Skip to content

Commit

Permalink
[workspace] Begin adding support for a "manylinux" OS variant (#15667)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthew Woehlke <[email protected]>
  • Loading branch information
jwnimmer-tri and mwoehlke-kitware authored Sep 15, 2021
1 parent 1ebb8c4 commit e637144
Show file tree
Hide file tree
Showing 22 changed files with 175 additions and 32 deletions.
10 changes: 7 additions & 3 deletions tools/skylark/drake_cc_per_os.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
# @drake_detected_os is somewhat brittle and might present challenges
# for users exploring novel platforms.

# TODO(jwnimmer-tri) For the moment, these functions are named "ubuntu",
# but also are armed on "manylinux". We should probably rework the names
# and/or documentation to be more clear on this point.

load(
"@drake//tools/skylark:drake_cc.bzl",
"drake_cc_googletest",
Expand All @@ -25,7 +29,7 @@ def drake_cc_googletest_ubuntu_only(
Because this test is not cross-platform, the visibility defaults to
private.
"""
if DISTRIBUTION == "ubuntu":
if DISTRIBUTION in ["ubuntu", "manylinux"]:
drake_cc_googletest(
name = name,
visibility = visibility,
Expand All @@ -43,7 +47,7 @@ def drake_cc_library_ubuntu_only(
Because this library is not cross-platform, the visibility defaults to
private and the headers are excluded from the installation.
"""
if DISTRIBUTION == "ubuntu":
if DISTRIBUTION in ["ubuntu", "manylinux"]:
drake_cc_library(
name = name,
hdrs = hdrs,
Expand All @@ -61,5 +65,5 @@ def drake_cc_package_library_per_os(
"""
if DISTRIBUTION == "macos":
drake_cc_package_library(deps = macos_deps, **kwargs)
elif DISTRIBUTION == "ubuntu":
elif DISTRIBUTION in ["ubuntu", "manylinux"]:
drake_cc_package_library(deps = ubuntu_deps, **kwargs)
1 change: 1 addition & 0 deletions tools/workspace/blas/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ def blas_repository(name):
mapping = {
"macOS default": ["blas=@openblas"],
"Ubuntu default": ["blas=@libblas"],
"manylinux": ["blas=@libblas"],
},
)
34 changes: 17 additions & 17 deletions tools/workspace/buildifier/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,29 @@ load(
)

def _impl(repository_ctx):
# Enumerate the possible binaries.
# Enumerate the possible binaries. Note that the buildifier binaries are
# fully statically linked, so the particular distribution doesn't matter,
# only the kernel.
version = "4.0.1"
mac_urls = [
darwin_urls = [
x.format(version = version, filename = "buildifier-darwin-amd64")
for x in repository_ctx.attr.mirrors.get("buildifier")
]
mac_sha256 = "f4d0ede5af04b32671b9a086ae061df8f621f48ea139b01b3715bfa068219e4a" # noqa
ubuntu_urls = [
darwin_sha256 = "f4d0ede5af04b32671b9a086ae061df8f621f48ea139b01b3715bfa068219e4a" # noqa
linux_urls = [
x.format(version = version, filename = "buildifier-linux-amd64")
for x in repository_ctx.attr.mirrors.get("buildifier")
]
ubuntu_sha256 = "069a03fc1fa46135e3f71e075696e09389344710ccee798b2722c50a2d92d55a" # noqa
linux_sha256 = "069a03fc1fa46135e3f71e075696e09389344710ccee798b2722c50a2d92d55a" # noqa

# Choose which binary to use on the current OS.
# Choose which binary to use.
os_result = determine_os(repository_ctx)
if os_result.error != None:
fail(os_result.error)
if os_result.is_macos:
urls = mac_urls
sha256 = mac_sha256
elif os_result.is_ubuntu:
urls = ubuntu_urls
sha256 = ubuntu_sha256
urls = darwin_urls
sha256 = darwin_sha256
elif os_result.is_ubuntu or os_result.is_manylinux:
urls = linux_urls
sha256 = linux_sha256
else:
fail("Operating system is NOT supported {}".format(os_result))

Expand All @@ -73,12 +73,12 @@ def _impl(repository_ctx):
version = version,
downloads = [
{
"urls": mac_urls,
"sha256": mac_sha256,
"urls": darwin_urls,
"sha256": darwin_sha256,
},
{
"urls": ubuntu_urls,
"sha256": ubuntu_sha256,
"urls": linux_urls,
"sha256": linux_sha256,
},
],
)
Expand Down
2 changes: 2 additions & 0 deletions tools/workspace/double_conversion/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def _impl(repository_ctx):
"/usr/include/double-conversion",
"include/double-conversion",
)
elif os_result.is_manylinux:
build_flavor = "ubuntu"
else:
fail("Operating system is NOT supported {}".format(os_result))

Expand Down
19 changes: 19 additions & 0 deletions tools/workspace/drake_visualizer/package-stub.BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- python -*-

load("@drake//tools/skylark:py.bzl", "py_library")
load("@drake//tools/install:install.bzl", "install")

py_library(
name = "drake_visualizer_python_deps",
visibility = ["//visibility:public"],
)

filegroup(
name = "drake_visualizer",
visibility = ["//visibility:public"],
)

install(
name = "install",
visibility = ["//visibility:public"],
)
6 changes: 6 additions & 0 deletions tools/workspace/drake_visualizer/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def _impl(repository_ctx):
archive = "dv-0.1.0-406-g4c3e570a-python-3.8.2-qt-5.12.8-vtk-8.2.0-focal-x86_64-1.tar.gz" # noqa
sha256 = "282438d7fabd72dddc8a9f5b3b7481b6b6ea53e4355f79f5bda1dae6e258d6be" # noqa
python_version = "3.8"
elif os_result.is_manylinux:
repository_ctx.symlink(
Label("@drake//tools/workspace/drake_visualizer:package-stub.BUILD.bazel"), # noqa
"BUILD.bazel",
)
return
else:
fail("Operating system is NOT supported {}".format(os_result))

Expand Down
3 changes: 3 additions & 0 deletions tools/workspace/fmt/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ def _impl(repo_ctx):
if os_result.is_macos:
# On macOS, we use fmt from homebrew via pkg-config.
error = setup_pkg_config_repository(repo_ctx).error
elif os_result.is_manylinux:
# Compile from downloaded github sources.
error = setup_github_repository(repo_ctx).error
elif os_result.ubuntu_release == "18.04":
# On Ubuntu 18.04, the host-provided spdlog is way too old so we can't
# use its bundled fmt, and there is no other fmt package available, so
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/glx/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def _impl(repository_ctx):
if os_result.is_macos:
# On macOS, no targets should depend on @glx.
build_flavor = "macos"
elif os_result.is_ubuntu:
elif os_result.is_ubuntu or os_result.is_manylinux:
build_flavor = "ubuntu"
hdrs = [
"GL/glx.h",
Expand Down
4 changes: 3 additions & 1 deletion tools/workspace/gurobi/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def _gurobi_impl(repo_ctx):
# Gurobi must be installed into its standard location.
gurobi_home = "/Library/gurobi902/mac64"
repo_ctx.symlink(gurobi_home, "gurobi-distro")
build_flavor = "macos"
else:
# The default directory for the downloaded gurobi is
# /opt/gurobi902/linux64. If the user does not use the default
Expand All @@ -26,12 +27,13 @@ def _gurobi_impl(repo_ctx):
gurobi_home or "/opt/gurobi902/linux64",
"gurobi-distro",
)
build_flavor = "ubuntu"

# Emit the generated BUILD.bazel file.
repo_ctx.template(
"BUILD.bazel",
Label("@drake//tools/workspace/gurobi:" +
"package-{}.BUILD.bazel.in".format(os_result.distribution)),
"package-{}.BUILD.bazel.in".format(build_flavor)),
substitutions = {
"{gurobi_home}": gurobi_home,
},
Expand Down
1 change: 1 addition & 0 deletions tools/workspace/lapack/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ def lapack_repository(name):
mapping = {
"macOS default": ["lapack=@openblas"],
"Ubuntu default": ["lapack=@liblapack"],
"manylinux": ["lapack=@liblapack"],
},
)
2 changes: 1 addition & 1 deletion tools/workspace/libblas/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def _impl(repo_ctx):
os_result = determine_os(repo_ctx)
if os_result.error != None:
fail(os_result.error)
if os_result.is_ubuntu:
if os_result.is_ubuntu or os_result.is_manylinux:
error = setup_pkg_config_repository(repo_ctx).error
if error != None:
fail(error)
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/libjpeg/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def _impl(repository_ctx):
if os_result.is_macos:
build_flavor = "macos"
repository_ctx.symlink("/usr/local/opt/jpeg/include", "include")
elif os_result.is_ubuntu:
elif os_result.is_ubuntu or os_result.is_manylinux:
build_flavor = "ubuntu"
for hdr in ["jerror.h", "jmorecfg.h", "jpegint.h", "jpeglib.h"]:
repository_ctx.symlink(
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/liblapack/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def _impl(repo_ctx):
os_result = determine_os(repo_ctx)
if os_result.error != None:
fail(os_result.error)
if os_result.is_ubuntu:
if os_result.is_ubuntu or os_result.is_manylinux:
error = setup_pkg_config_repository(repo_ctx).error
if error != None:
fail(error)
Expand Down
16 changes: 16 additions & 0 deletions tools/workspace/nlopt/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ def _impl(repository_ctx):
build_flavor = "ubuntu-{}".format(os_result.ubuntu_release)
repository_ctx.symlink("/usr/include/nlopt.h", "include/nlopt.h")
repository_ctx.symlink("/usr/include/nlopt.hpp", "include/nlopt.hpp")
elif os_result.is_manylinux:
# Although we expect that "manylinux" is based on Ubuntu 18.04, the
# "flavor" here relates to what spelling of the linkopts we want to be
# using. As drake-dependencies is currently formulated, the linkopts
# from the ubuntu-18.04.BUILD.bazel are satisfactory.
build_flavor = "ubuntu-18.04"
repository_ctx.symlink(
# TODO(jwnimmer-tri) Ideally, we wouldn't be hard-coding paths when
# using manylinux.
"/opt/drake-dependencies/include/nlopt.h",
"include/nlopt.h",
)
repository_ctx.symlink(
"/opt/drake-dependencies/include/nlopt.hpp",
"include/nlopt.hpp",
)
else:
fail("Operating system is NOT supported {}".format(os_result))

Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/opengl/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def _impl(repository_ctx):
Label("@drake//tools/workspace/opengl:package-macos.BUILD.bazel"),
"BUILD.bazel",
)
elif os_result.is_ubuntu:
elif os_result.is_ubuntu or os_result.is_manylinux:
hdrs = [
"GL/gl.h",
"GL/glcorearb.h",
Expand Down
42 changes: 40 additions & 2 deletions tools/workspace/os.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@

"""A collection of OS-related utilities intended for use in repository rules,
i.e., rules used by WORKSPACE files, not BUILD files.
To opt-in to the "manylinux" build variant, set the environment variable
`DRAKE_OS=manylinux` before running the build. The most precise way to do
this is to add a `user.bazelrc` file to the root of the Drake source tree
with the following content:
common --repo_env=DRAKE_OS=manylinux
Alternatively, you may pass `--repo_env=DRAKE_OS=manylinux` on the bazel
command line.
"""

load("@drake//tools/workspace:execute.bzl", "which")
Expand Down Expand Up @@ -43,19 +53,23 @@ def exec_using_which(repository_ctx, command):
def _make_result(
error = None,
ubuntu_release = None,
macos_release = None):
macos_release = None,
is_manylinux = False):
"""Return a fully-populated struct result for determine_os, below."""
if ubuntu_release != None:
distribution = "ubuntu"
elif macos_release != None:
distribution = "macos"
elif is_manylinux:
distribution = "manylinux"
else:
distribution = None
return struct(
error = error,
distribution = distribution,
is_macos = (macos_release != None),
is_ubuntu = (ubuntu_release != None),
is_manylinux = is_manylinux,
ubuntu_release = ubuntu_release,
macos_release = macos_release,
)
Expand All @@ -66,6 +80,17 @@ def _determine_linux(repository_ctx):
# Shared error message text across different failure cases.
error_prologue = "could not determine Linux distribution: "

# Allow the user to override the OS selection.
drake_os = repository_ctx.os.environ.get("DRAKE_OS", "")
if len(drake_os) > 0:
if drake_os == "manylinux":
return _make_result(is_manylinux = True)
return _make_result(error = "{}{} DRAKE_OS={}".format(
error_prologue,
"unknown value for environment variable",
drake_os,
))

# Run sed to determine Linux NAME and VERSION_ID.
sed = exec_using_which(repository_ctx, [
"sed",
Expand Down Expand Up @@ -125,18 +150,27 @@ def determine_os(repository_ctx):
A repository_rule helper function that determines which of the supported OS
versions we are targeting.
Note that even if the operating system hosting the build is Ubuntu, the
target OS might be "manylinux", which means that we only use the most basic
host packages from Ubuntu (libc, libstdc++, etc.). In that case, the
value of is_ubuntu will be False.
Argument:
repository_ctx: The context passed to the repository_rule calling this.
Result:
a struct, with attributes:
- error: str iff any error occurred, else None
- distribution: str either "ubuntu" or "macos" if no error
- distribution: str either "ubuntu" or "macos" or "manylinux" iff no
error occurred, else None
- is_macos: True iff on a supported macOS release, else False
- macos_release: str like "10.15" or "11" iff on a supported macOS,
else None
- is_ubuntu: True iff on a supported Ubuntu version, else False
- ubuntu_release: str like "18.04" iff on a supported ubuntu, else None
- is_manylinux: True iff this build will be packaged into a Python
wheel that confirms to a "manylinux" standard such as
manylinux_2_27; see https://github.com/pypa/manylinux.
"""

os_name = repository_ctx.os.name
Expand Down Expand Up @@ -181,6 +215,10 @@ def os_specific_alias(repository_ctx, mapping):
"macOS default",
"default",
]
elif os_result.is_manylinux:
keys = [
"manylinux",
]
found_items = None
for key in keys:
if key in mapping:
Expand Down
5 changes: 4 additions & 1 deletion tools/workspace/python/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ _VERSION_SUPPORT_MATRIX = {
"ubuntu:18.04": ["3.6"],
"ubuntu:20.04": ["3.8"],
"macos": ["3.9"],
"manylinux": ["3.6"],
}

def repository_python_info(repository_ctx):
Expand All @@ -64,8 +65,10 @@ def repository_python_info(repository_ctx):
fail(os_result.error)
if os_result.is_macos:
os_key = os_result.distribution
else:
elif os_result.is_ubuntu:
os_key = os_result.distribution + ":" + os_result.ubuntu_release
else:
os_key = "manylinux"
versions_supported = _VERSION_SUPPORT_MATRIX[os_key]

if os_result.is_macos:
Expand Down
3 changes: 3 additions & 0 deletions tools/workspace/spdlog/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ def _impl(repo_ctx):
if os_result.is_macos:
# On macOS, we use spdlog from homebrew via pkg-config.
error = setup_pkg_config_repository(repo_ctx).error
elif os_result.is_manylinux:
# Compile it from downloaded github sources.
error = setup_github_repository(repo_ctx).error
elif os_result.ubuntu_release == "18.04":
# On Ubuntu 18.04, the host-provided spdlog is way too old. Instead,
# we'll recompile it from downloaded github sources.
Expand Down
5 changes: 5 additions & 0 deletions tools/workspace/suitesparse/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ def _impl(repo_ctx):
elif os_result.is_macos:
include = "/usr/local/opt/suite-sparse/include"
lib = "/usr/local/opt/suite-sparse/lib"
elif os_result.is_manylinux:
# TODO(jwnimmer-tri) Ideally, we wouldn't be hard-coding paths when
# using manylinux.
include = "/opt/drake-dependencies/include"
lib = "/opt/drake-dependencies/lib"
else:
fail("Unknown OS")

Expand Down
Loading

0 comments on commit e637144

Please sign in to comment.