Skip to content

Commit

Permalink
[workspace] Build IPOPT from source on Ubuntu
Browse files Browse the repository at this point in the history
On Ubuntu, this is an upgrade from 3.11.9 to 3.14.12.

On Ubuntu, we can now remove ipopt from the prereqs setup and skip it during
wheel builds. It's licensed as EPL-2.0 so we can statically link it but we do
need to distribute a patch file with our changes. We also teach vendor_cxx
about gentler option for vendoring, where we only hide the symbols without
prefixing them with "drake_vendor".

On macOS, Homebrew usually tracks the newest upstream version so the urgency of
rebuilding from source is reduced. Building from source would still help with
linker issues, but since there is no MUMPS package in Homebrew the work to make
it happen is not yet worth the time investment.
  • Loading branch information
jwnimmer-tri committed May 10, 2023
1 parent 4d4949a commit cfe2244
Show file tree
Hide file tree
Showing 24 changed files with 853 additions and 63 deletions.
1 change: 0 additions & 1 deletion setup/ubuntu/binary_distribution/packages-focal.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
coinor-libclp1
coinor-libcoinutils3v5
coinor-libipopt1v5
default-jre
jupyter-notebook
libblas3
Expand Down
1 change: 0 additions & 1 deletion setup/ubuntu/binary_distribution/packages-jammy.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
coinor-libclp1
coinor-libcoinutils3v5
coinor-libipopt1v5
default-jre
jupyter-notebook
libblas-dev
Expand Down
1 change: 0 additions & 1 deletion setup/ubuntu/source_distribution/packages-focal.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
clang-format-12
coinor-libclp-dev
coinor-libcoinutils-dev
coinor-libipopt-dev
default-jdk
file
gfortran
Expand Down
1 change: 0 additions & 1 deletion setup/ubuntu/source_distribution/packages-jammy.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
clang-format-12
coinor-libclp-dev
coinor-libcoinutils-dev
coinor-libipopt-dev
default-jdk
file
gfortran
Expand Down
16 changes: 13 additions & 3 deletions tools/install/libdrake/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package(default_visibility = ["//visibility:private"])

load("@bazel_skylib//lib:selects.bzl", "selects")
load(
"@python//:version.bzl",
"PYTHON_SITE_PACKAGES_RELPATH",
Expand Down Expand Up @@ -137,14 +138,23 @@ cc_library(
}),
)

# Depend on IPOPT's shared library iff IPOPT is enabled.
# Depend on IPOPT's shared library iff IPOPT is enabled and we're on a platform
# that uses the host OS shared library.
selects.config_setting_group(
name = "ipopt_not_shared",
match_any = [
"//tools:no_ipopt",
"//tools/cc_toolchain:linux",
],
)

cc_library(
name = "ipopt_deps",
deps = select({
deps = selects.with_or({
"//conditions:default": [
"@ipopt",
],
"//tools:no_ipopt": [],
":ipopt_not_shared": [],
}),
)

Expand Down
5 changes: 5 additions & 0 deletions tools/wheel/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
load("@drake//tools/skylark:drake_py.bzl", "drake_py_binary")
load("//tools/lint:lint.bzl", "add_lint_tests")

exports_files(
glob(["**"]),
visibility = ["//tools:__subpackages__"],
)

py_library(
name = "module_py",
srcs = ["__init__.py"],
Expand Down
18 changes: 10 additions & 8 deletions tools/wheel/image/dependencies/projects.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,22 @@ set(clp_md5 "f7c25af22d2f03398cbbdf38c8b4f6fd")
set(clp_dlname "clp-${clp_version}.tar.gz")
list(APPEND ALL_PROJECTS clp)

# ipopt (requires mumps)
if(APPLE)
set(mumps_version 5.4.1) # Latest available in Ubuntu.
set(mumps_url
"http://archive.ubuntu.com/ubuntu/pool/universe/m/mumps/mumps_${mumps_version}.orig.tar.gz"
"http://archive.ubuntu.com/ubuntu/pool/universe/m/mumps/mumps_${mumps_version}.orig.tar.gz"
"http://mumps.enseeiht.fr/MUMPS_${mumps_version}.tar.gz"
)
set(mumps_md5 "93be789bf9c6c341a78c16038da3241b")
set(mumps_dlname "mumps-${mumps_version}.tar.gz")
list(APPEND ALL_PROJECTS mumps)
endif()

# ipopt
set(ipopt_version 3.11.9)
set(ipopt_url "https://github.com/coin-or/Ipopt/archive/refs/tags/releases/${ipopt_version}.tar.gz")
set(ipopt_md5 "55275c202072ad30db25d2b723ef9b7a")
set(ipopt_dlname "ipopt-${ipopt_version}.tar.gz")
list(APPEND ALL_PROJECTS ipopt)
# This must match the version in tools/workspace/ipopt_internal_fromsource.
# The matching is automatically enforced by a linter script.
set(ipopt_version 3.14.12)
set(ipopt_url "https://github.com/coin-or/Ipopt/archive/refs/tags/releases/${ipopt_version}.tar.gz")
set(ipopt_md5 "b2bcb362be4c10eccde02829d3025faa")
set(ipopt_dlname "ipopt-${ipopt_version}.tar.gz")
list(APPEND ALL_PROJECTS ipopt)
endif()
24 changes: 7 additions & 17 deletions tools/wheel/image/dependencies/projects/ipopt.cmake
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
if(APPLE)
set(ipopt_extra_dependencies mumps)
set(ipopt_mumps_configure_args
--with-mumps-lib=-ldmumps\ -lmumps_common\ -lpord\ -lmpiseq
--with-mumps-incdir=${CMAKE_INSTALL_PREFIX}/include
CPPFLAGS=-I${CMAKE_INSTALL_PREFIX}/include/mumps_seq
)
else()
set(ipopt_extra_dependencies)
set(ipopt_mumps_configure_args
--with-mumps-lib=-ldmumps_seq
--with-mumps-incdir=/usr/include
CPPFLAGS=-I/usr/include/mumps_seq
)
if(NOT APPLE)
message(FATAL_ERROR "mumps should only be built on macOS")
endif()

ExternalProject_Add(ipopt
URL ${ipopt_url}
URL_MD5 ${ipopt_md5}
DOWNLOAD_NAME ${ipopt_dlname}
DEPENDS lapack ${ipopt_extra_dependencies}
DEPENDS lapack mumps
${COMMON_EP_ARGS}
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND ./configure
Expand All @@ -28,11 +16,13 @@ ExternalProject_Add(ipopt
CFLAGS=-fPIC
CXXFLAGS=-fPIC
LDFLAGS=-L${CMAKE_INSTALL_PREFIX}/lib
${ipopt_mumps_configure_args}
--with-mumps-lflags=-ldmumps\ -lmpiseq\ -lmumps_common\ -lpord
--with-mumps-cflags=-I${CMAKE_INSTALL_PREFIX}/include
CPPFLAGS=-I${CMAKE_INSTALL_PREFIX}/include/mumps_seq
BUILD_COMMAND make
INSTALL_COMMAND make install
)

extract_license(ipopt
Ipopt/LICENSE
LICENSE
)
2 changes: 2 additions & 0 deletions tools/workspace/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ drake_py_binary(
"@fcl_internal//:__pkg__",
"@gz_math_internal//:__pkg__",
"@gz_utils_internal//:__pkg__",
"@ipopt_internal_fromsource//:__pkg__",
"@msgpack_internal//:__pkg__",
"@nlopt_internal//:__pkg__",
"@qhull_internal//:__pkg__",
Expand Down Expand Up @@ -85,6 +86,7 @@ _DRAKE_EXTERNAL_PACKAGE_INSTALLS = ["@%s//:install" % p for p in [
"fmt",
"gz_math_internal",
"gz_utils_internal",
"ipopt",
"lcm",
"meshcat",
"msgpack_internal",
Expand Down
9 changes: 9 additions & 0 deletions tools/workspace/default.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ load("@drake//tools/workspace/gz_math_internal:repository.bzl", "gz_math_interna
load("@drake//tools/workspace/gz_utils_internal:repository.bzl", "gz_utils_internal_repository") # noqa
load("@drake//tools/workspace/intel_realsense_ros_internal:repository.bzl", "intel_realsense_ros_internal_repository") # noqa
load("@drake//tools/workspace/ipopt:repository.bzl", "ipopt_repository")
load("@drake//tools/workspace/ipopt_internal_fromsource:repository.bzl", "ipopt_internal_fromsource_repository") # noqa
load("@drake//tools/workspace/ipopt_internal_pkgconfig:repository.bzl", "ipopt_internal_pkgconfig_repository") # noqa
load("@drake//tools/workspace/lapack:repository.bzl", "lapack_repository")
load("@drake//tools/workspace/lcm:repository.bzl", "lcm_repository")
load("@drake//tools/workspace/libblas:repository.bzl", "libblas_repository")
Expand All @@ -51,6 +53,7 @@ load("@drake//tools/workspace/libtiff:repository.bzl", "libtiff_repository")
load("@drake//tools/workspace/meshcat:repository.bzl", "meshcat_repository")
load("@drake//tools/workspace/mosek:repository.bzl", "mosek_repository")
load("@drake//tools/workspace/msgpack_internal:repository.bzl", "msgpack_internal_repository") # noqa
load("@drake//tools/workspace/mumps_internal:repository.bzl", "mumps_internal_repository") # noqa
load("@drake//tools/workspace/mypy_extensions_internal:repository.bzl", "mypy_extensions_internal_repository") # noqa
load("@drake//tools/workspace/mypy_internal:repository.bzl", "mypy_internal_repository") # noqa
load("@drake//tools/workspace/nanoflann_internal:repository.bzl", "nanoflann_internal_repository") # noqa
Expand Down Expand Up @@ -182,6 +185,10 @@ def add_default_repositories(excludes = [], mirrors = DEFAULT_MIRRORS):
intel_realsense_ros_internal_repository(name = "intel_realsense_ros_internal", mirrors = mirrors) # noqa
if "ipopt" not in excludes:
ipopt_repository(name = "ipopt")
if "ipopt_internal_fromsource" not in excludes:
ipopt_internal_fromsource_repository(name = "ipopt_internal_fromsource", mirrors = mirrors) # noqa
if "ipopt_internal_pkgconfig" not in excludes:
ipopt_internal_pkgconfig_repository(name = "ipopt_internal_pkgconfig")
if "lapack" not in excludes:
lapack_repository(name = "lapack")
if "lcm" not in excludes:
Expand Down Expand Up @@ -210,6 +217,8 @@ def add_default_repositories(excludes = [], mirrors = DEFAULT_MIRRORS):
mosek_repository(name = "mosek")
if "msgpack_internal" not in excludes:
msgpack_internal_repository(name = "msgpack_internal", mirrors = mirrors) # noqa
if "mumps_internal" not in excludes:
mumps_internal_repository(name = "mumps_internal")
if "mypy_extensions_internal" not in excludes:
mypy_extensions_internal_repository(name = "mypy_extensions_internal", mirrors = mirrors) # noqa
if "mypy_internal" not in excludes:
Expand Down
3 changes: 0 additions & 3 deletions tools/workspace/ipopt/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# This file exists to make our directory into a Bazel package, so that our
# neighboring *.bzl file can be loaded elsewhere.

load("//tools/lint:lint.bzl", "add_lint_tests")

add_lint_tests()
33 changes: 14 additions & 19 deletions tools/workspace/ipopt/repository.bzl
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
load(
"@drake//tools/workspace:pkg_config.bzl",
"pkg_config_repository",
)
load("@drake//tools/workspace:os.bzl", "os_specific_alias_repository")

def ipopt_repository(
name,
licenses = [
"reciprocal", # CPL-1.0
"unencumbered", # Public-Domain
],
modname = "ipopt",
pkg_config_paths = [],
homebrew_subdir = "opt/ipopt/lib/pkgconfig",
**kwargs):
pkg_config_repository(
# How we build IPOPT depends on which platform we're on.
def ipopt_repository(name):
os_specific_alias_repository(
name = name,
licenses = licenses,
modname = modname,
pkg_config_paths = pkg_config_paths,
**kwargs
mapping = {
"macOS default": [
"ipopt=@ipopt_internal_pkgconfig//:ipopt_internal_pkgconfig",
"install=@ipopt_internal_pkgconfig//:install",
],
"Ubuntu default": [
"ipopt=@ipopt_internal_fromsource//:ipopt",
"install=@ipopt_internal_fromsource//:install",
],
},
)
15 changes: 15 additions & 0 deletions tools/workspace/ipopt_internal_fromsource/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load("@drake//tools/skylark:drake_py.bzl", "drake_py_unittest")
load("//tools/lint:lint.bzl", "add_lint_tests")

drake_py_unittest(
name = "lint_test",
data = [
":package.BUILD.bazel",
"//tools/wheel:image/dependencies/projects.cmake",
"@ipopt_internal_fromsource//:drake_repository_metadata.json",
"@ipopt_internal_fromsource//:src/Makefile.am",
],
tags = ["lint"],
)

add_lint_tests()
Loading

0 comments on commit cfe2244

Please sign in to comment.