Skip to content

Commit

Permalink
[workspace] Build NLopt from source
Browse files Browse the repository at this point in the history
Compared to the Ubuntu and macOS packages, this removes the LGPL'd
"luksan" solver from the build, which means we can link the library
statically (and eventually, hidden). This might mean that NLopt is
no longer able to solve certain kinds of programs, but that is a
fair trade-off given all of the problems caused by LGPL linking.

The package.BUILD.bazel is modeled on nlopt.BUILD.bazel in a10ebb7.

Deprecate the now-unused current (host OS) nlopt external.
  • Loading branch information
jwnimmer-tri committed May 30, 2022
1 parent d1c7a67 commit 520cf77
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 16 deletions.
2 changes: 1 addition & 1 deletion solvers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,7 @@ drake_cc_variant_library(
],
deps_enabled = [
"//math:autodiff",
"@nlopt",
"@nlopt_internal//:nlopt",
],
)

Expand Down
13 changes: 0 additions & 13 deletions tools/install/libdrake/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ cc_library(
name = "dreal_deps",
deps = select({
"//conditions:default": [
"@nlopt",
"@ibex",
],
"//tools:no_dreal": [],
Expand Down Expand Up @@ -162,17 +161,6 @@ cc_library(
}),
)

# Depend on NLOPT's shared library iff NLOPT is enabled.
cc_library(
name = "nlopt_deps",
deps = select({
"//conditions:default": [
"@nlopt",
],
"//tools:no_nlopt": [],
}),
)

# Depend on the subset of VTK's shared libraries that Drake uses.
cc_library(
name = "vtk_deps",
Expand Down Expand Up @@ -239,7 +227,6 @@ cc_library(
":gurobi_deps",
":ipopt_deps",
":mosek_deps",
":nlopt_deps",
":vtk_deps",
":x11_deps",
"//common:drake_marker_shared_library",
Expand Down
2 changes: 0 additions & 2 deletions tools/wheel/image/packages-focal
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ zip
libgl1-mesa-dev
libglib2.0-dev
libjchart2d-java
libnlopt-dev
libnlopt-cxx-dev
libxt-dev
# Build dependencies (OpenCL).
opencl-headers
Expand Down
1 change: 1 addition & 0 deletions tools/workspace/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ drake_py_binary(
name = "vendor_cxx",
srcs = ["vendor_cxx.py"],
visibility = [
"@nlopt_internal//:__pkg__",
"@yaml_cpp_internal//:__pkg__",
],
deps = [":module_py"],
Expand Down
5 changes: 5 additions & 0 deletions tools/workspace/default.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ load("@drake//tools/workspace/mosek:repository.bzl", "mosek_repository")
load("@drake//tools/workspace/msgpack:repository.bzl", "msgpack_repository")
load("@drake//tools/workspace/net_sf_jchart2d:repository.bzl", "net_sf_jchart2d_repository") # noqa
load("@drake//tools/workspace/nlopt:repository.bzl", "nlopt_repository")
load("@drake//tools/workspace/nlopt_internal:repository.bzl", "nlopt_internal_repository") # noqa
load("@drake//tools/workspace/openblas:repository.bzl", "openblas_repository")
load("@drake//tools/workspace/opencl:repository.bzl", "opencl_repository")
load("@drake//tools/workspace/opengl:repository.bzl", "opengl_repository")
Expand Down Expand Up @@ -225,7 +226,11 @@ def add_default_repositories(excludes = [], mirrors = DEFAULT_MIRRORS):
if "net_sf_jchart2d" not in excludes:
net_sf_jchart2d_repository(name = "net_sf_jchart2d", mirrors = mirrors)
if "nlopt" not in excludes:
# The @nlopt external is being removed from Drake on 2020-09-01.
# TODO(jwnimmer-tri) When removing @nlopt, also update install_prereqs.
nlopt_repository(name = "nlopt")
if "nlopt_internal" not in excludes:
nlopt_internal_repository(name = "nlopt_internal", mirrors = mirrors)
if "openblas" not in excludes:
openblas_repository(name = "openblas")
if "opencl" not in excludes:
Expand Down
3 changes: 3 additions & 0 deletions tools/workspace/dreal/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ def dreal_repository(
patches = [
"@drake//tools/workspace/dreal:ibex_2.8.6.patch",
],
repo_mapping = {
"@nlopt": "@nlopt_internal",
},
)
1 change: 1 addition & 0 deletions tools/workspace/nlopt/package-macos.BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ cc_library(
"-lnlopt",
],
visibility = ["//visibility:public"],
deprecation = "DRAKE DEPRECATED: The @nlopt external is being removed from Drake on or after 2020-09-01. Downstream projects should add it to their own WORKSPACE if needed.", # noqa
)
1 change: 1 addition & 0 deletions tools/workspace/nlopt/package-ubuntu-20.04.BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ cc_library(
"-lnlopt_cxx",
],
visibility = ["//visibility:public"],
deprecation = "DRAKE DEPRECATED: The @nlopt external is being removed from Drake on or after 2020-09-01. Downstream projects should add it to their own WORKSPACE if needed.", # noqa
)
45 changes: 45 additions & 0 deletions tools/workspace/nlopt_internal/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- python -*-

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

exports_files(
["patches/gen_enums.patch"],
visibility = ["@nlopt_internal//:__pkg__"],
)

# Creates api/nlopt.hpp using NLopt upstream's codegen so that we can
# cross-check it versus our Drake-local patch file.
genrule(
name = "cmake_genrule",
srcs = [
"@nlopt_internal//:cmake/generate-cpp.cmake",
"@nlopt_internal//:src/api/nlopt-in.hpp",
"@nlopt_internal//:src/api/nlopt.h",
],
outs = ["test/nlopt-upstream.hpp"],
cmd = " ".join([
"cmake",
"-DAPI_SOURCE_DIR=$$(dirname $(execpath @nlopt_internal//:src/api/nlopt.h))", # noqa
"-P $(execpath @nlopt_internal//:cmake/generate-cpp.cmake)",
"&&",
"mv nlopt.hpp $@",
]),
tags = [
"manual",
"nolint",
],
)

drake_py_unittest(
name = "enum_test",
data = [
":test/nlopt-upstream.hpp",
"@nlopt_internal//:src/api/nlopt.hpp",
],
deps = [
"@bazel_tools//tools/python/runfiles",
],
)

add_lint_tests()
221 changes: 221 additions & 0 deletions tools/workspace/nlopt_internal/package.BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# -*- python -*-

load(
"@drake//tools/workspace:cmake_configure_file.bzl",
"cmake_configure_file",
)
load(
"@drake//tools/install:install.bzl",
"install",
)
load(
"@drake//tools/workspace:check_lists_consistency.bzl",
"check_lists_consistency",
)
load(
"@drake//tools/workspace:vendor_cxx.bzl",
"cc_library_vendored",
)

package(default_visibility = ["//visibility:private"])

# Chooses the nlopt preprocessor substitutions that we want to use from Bazel.
cmake_configure_file(
name = "config",
src = "nlopt_config.h.in",
out = "src/nlopt_config.h",
cmakelists = ["CMakeLists.txt"],
defines = [
# Yes, we are going to build the C++ bindings.
"NLOPT_CXX=1",
# C11 standard spelling.
"THREADLOCAL=_Thread_local",
# Say "yes" to some useful things.
"HAVE_COPYSIGN=1",
"HAVE_FPCLASSIFY=1",
"HAVE_ISINF=1",
"HAVE_ISNAN=1",
"HAVE_LIBM=1",
"HAVE_QSORT_R=1",
"HAVE_STDINT_H=1",
"HAVE_UINT32_T=1",
# These end up being unused; empty-string is a fail-fast value.
"SIZEOF_UNSIGNED_INT=",
"SIZEOF_UNSIGNED_LONG=",
],
)

# Creates api/nlopt.hpp based on api/nlopt-in.hpp.
genrule(
name = "nlopt_hpp_genrule",
srcs = [
"src/api/nlopt-in.hpp",
"@drake//tools/workspace/nlopt_internal:patches/gen_enums.patch",
],
outs = ["src/api/nlopt.hpp"],
cmd = " ".join([
"cp $(execpath src/api/nlopt-in.hpp) $@",
"&&",
"patch $@ $(execpath @drake//tools/workspace/nlopt_internal:patches/gen_enums.patch)", # noqa
]),
visibility = ["@drake//tools/workspace/nlopt_internal:__pkg__"],
)

# Provides upstream's inputs for nlopt.hpp for use by Drake's unit tests.
exports_files(
[
"cmake/generate-cpp.cmake",
"src/api/nlopt-in.hpp",
"src/api/nlopt.h",
],
visibility = ["@//tools/workspace/nlopt_internal:__pkg__"],
)

_SRCS = [
# This comes from a genrule above.
"src/nlopt_config.h",
# This list exactly matches CMakeLists.txt NLOPT_SOURCES, except that
# we have removed all of the "src/algs/luksan/**" sources (LGPL).
"src/algs/direct/DIRect.c",
"src/algs/direct/direct_wrap.c",
"src/algs/direct/DIRserial.c",
"src/algs/direct/DIRsubrout.c",
"src/algs/direct/direct-internal.h",
"src/algs/direct/direct.h",
"src/algs/cdirect/cdirect.c",
"src/algs/cdirect/hybrid.c",
"src/algs/cdirect/cdirect.h",
"src/algs/praxis/praxis.c",
"src/algs/praxis/praxis.h",
"src/algs/crs/crs.c",
"src/algs/crs/crs.h",
"src/algs/mlsl/mlsl.c",
"src/algs/mlsl/mlsl.h",
"src/algs/mma/mma.c",
"src/algs/mma/mma.h",
"src/algs/mma/ccsa_quadratic.c",
"src/algs/cobyla/cobyla.c",
"src/algs/cobyla/cobyla.h",
"src/algs/newuoa/newuoa.c",
"src/algs/newuoa/newuoa.h",
"src/algs/neldermead/nldrmd.c",
"src/algs/neldermead/neldermead.h",
"src/algs/neldermead/sbplx.c",
"src/algs/auglag/auglag.c",
"src/algs/auglag/auglag.h",
"src/algs/bobyqa/bobyqa.c",
"src/algs/bobyqa/bobyqa.h",
"src/algs/isres/isres.c",
"src/algs/isres/isres.h",
"src/algs/slsqp/slsqp.c",
"src/algs/slsqp/slsqp.h",
"src/algs/esch/esch.c",
"src/algs/esch/esch.h",
"src/api/general.c",
"src/api/options.c",
"src/api/optimize.c",
"src/api/deprecated.c",
"src/api/nlopt-internal.h",
"src/api/f77api.c",
"src/api/f77funcs.h",
"src/api/f77funcs_.h",
"src/util/mt19937ar.c",
"src/util/sobolseq.c",
"src/util/soboldata.h",
"src/util/timer.c",
"src/util/stop.c",
"src/util/nlopt-util.h",
"src/util/redblack.c",
"src/util/redblack.h",
"src/util/qsort_r.c",
"src/util/rescale.c",
# This list exactly matches CMakeLists.txt extras for NLOPT_CXX.
"src/algs/stogo/global.cc",
"src/algs/stogo/linalg.cc",
"src/algs/stogo/local.cc",
"src/algs/stogo/stogo.cc",
"src/algs/stogo/tools.cc",
"src/algs/stogo/global.h",
"src/algs/stogo/linalg.h",
"src/algs/stogo/local.h",
"src/algs/stogo/stogo_config.h",
"src/algs/stogo/stogo.h",
"src/algs/stogo/tools.h",
# This list exactly matches CMakeLists.txt extras for NLOPT_CXX11.
"src/algs/ags/data_types.hpp",
"src/algs/ags/evolvent.hpp",
"src/algs/ags/evolvent.cc",
"src/algs/ags/solver.hpp",
"src/algs/ags/solver.cc",
"src/algs/ags/local_optimizer.hpp",
"src/algs/ags/local_optimizer.cc",
"src/algs/ags/ags.h",
"src/algs/ags/ags.cc",
]

_HDRS = [
"src/api/nlopt.h",
# This comes from a genrule above.
"src/api/nlopt.hpp",
]

# Fail-fast in case upstream adds/removes files as part of an upgrade.
check_lists_consistency(
files = _HDRS + _SRCS,
glob_include = [
"src/**/*.h",
"src/**/*.c",
"src/**/*.hpp",
"src/**/*.cc",
],
glob_exclude = [
# This is a main() function, not a library source.
"src/algs/stogo/prog.cc",
# This is used as a genrule input only, not a library source.
"src/api/nlopt-in.hpp",
# These are disabled upstream by default.
"src/algs/cquad/**",
"src/algs/direct/DIRparallel.c",
"src/algs/subplex/**",
# This is in Drake specifically due to LGPL.
"src/algs/luksan/**",
# Drake don't use the octave bindings.
"src/octave/**",
# These are unit testing files, not library sources.
"**/*test*",
"**/*tst*",
"src/algs/stogo/rosen.h",
"src/util/nlopt-getopt.*",
],
)

_INCLUDES = ["src"] + depset([
x.rsplit("/", 1)[0]
for x in _SRCS
]).to_list()

# TODO(jwnimmer-tri) Use cc_library_vendored.
cc_library(
name = "nlopt",
srcs = _SRCS,
hdrs = _HDRS,
copts = ["-w"],
includes = _INCLUDES,
linkstatic = True,
visibility = ["//visibility:public"],
)

install(
name = "install",
targets = [":nlopt"],
docs = [
"src/AUTHORS",
"src/NEWS",
] + glob([
"src/**/COPYING",
"src/**/COPYRIGHT",
], exclude = [
"**/luksan/**",
]),
visibility = ["//visibility:public"],
)
Loading

0 comments on commit 520cf77

Please sign in to comment.