Skip to content

Commit

Permalink
Implement macos_wheel platform (RobotLocomotion#17301)
Browse files Browse the repository at this point in the history
* Implement macos_wheel platform

Add support for the recently added "macos_wheel" target/platform.
Add ability to override the platform on macOS, which finishes
implementing the "macos_wheel" target/platform that was recently
introduced. Implement support for the same. This should, with a proper
environment, allow Drake to be built in a mode that can be used to
produce a wheel.

(Scripts to actually perform such a build, and particularly to establish
the aforementioned "proper environment", will be added in subsequent
commits.)

Also, explicitly add the pkg-config paths to Bazel's search paths to
allow us to find dependencies built for wheels. This is required as we
cannot inject these into /usr/local on macOS, as we would in the Ubuntu
Docker containers.
  • Loading branch information
mwoehlke-kitware authored May 31, 2022
1 parent 7d5edd2 commit 1ffa6f9
Show file tree
Hide file tree
Showing 16 changed files with 76 additions and 41 deletions.
3 changes: 0 additions & 3 deletions tools/wheel/image/build-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,4 @@ cmake -G Ninja \

ninja

ln -s /opt/drake-dependencies/lib/pkgconfig /usr/local/lib
ln -s /opt/drake-dependencies/share/pkgconfig /usr/local/share

ln -s /opt/drake-dependencies/bin/patchelf /usr/local/bin/patchelf
2 changes: 1 addition & 1 deletion tools/workspace/boost/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def _impl(repository_ctx):
os_result = determine_os(repository_ctx)
if os_result.error != None:
fail(os_result.error)
elif os_result.is_macos:
elif os_result.is_macos or os_result.is_macos_wheel:
prefix = "{}/opt/boost".format(os_result.homebrew_prefix)
elif os_result.is_ubuntu or os_result.is_manylinux:
prefix = "/usr"
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/double_conversion/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def _impl(repository_ctx):
"/usr/include/double-conversion",
"include/double-conversion",
)
elif os_result.is_manylinux:
elif os_result.is_manylinux or os_result.is_macos_wheel:
libdir = "/opt/drake-dependencies/lib"
repository_ctx.symlink(
"/opt/drake-dependencies/include/double-conversion",
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/fmt/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ 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:
elif os_result.is_manylinux or os_result.is_macos_wheel:
# Compile from downloaded github sources.
error = setup_github_repository(repo_ctx).error
elif os_result.ubuntu_release == "20.04":
Expand Down
4 changes: 2 additions & 2 deletions tools/workspace/gfortran/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ def _gfortran_impl(repo_ctx):
os_result = determine_os(repo_ctx)
if os_result.error != None:
fail(os_result.error)
if os_result.is_macos:
if os_result.is_macos or os_result.is_macos_wheel:
suffix = ".dylib"
else:
suffix = ".so"
libgfortran = "libgfortran{}".format(suffix)
libgfortran_path = _find_library(repo_ctx, compiler, libgfortran)

# The cc_library linking is different on Ubuntu vs macOS.
if os_result.is_macos:
if os_result.is_macos or os_result.is_macos_wheel:
srcs = []
linkopts = [
"-L{}".format(repo_ctx.path(libgfortran_path).dirname),
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 @@ -16,7 +16,7 @@ def _impl(repository_ctx):
"{}/opt/jpeg/include".format(os_result.homebrew_prefix),
"include",
)
elif os_result.is_manylinux:
elif os_result.is_manylinux or os_result.is_macos_wheel:
libdir = "/opt/drake-dependencies/lib"
for hdr in noarch_hdrs + ["jconfig.h"]:
repository_ctx.symlink(
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/nlopt/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def _impl(repository_ctx):
if os_result.error != None:
fail(os_result.error)

if os_result.is_macos:
if os_result.is_macos or os_result.is_macos_wheel:
build_flavor = "macos"
repository_ctx.symlink(
"{}/opt/nlopt/include/nlopt.h".format(os_result.homebrew_prefix),
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/openblas/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_macos:
if os_result.is_macos or os_result.is_macos_wheel:
error = setup_pkg_config_repository(repo_ctx).error
if error != None:
fail(error)
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 @@ -8,7 +8,7 @@ def _impl(repository_ctx):
if os_result.error != None:
fail(os_result.error)

if os_result.is_macos:
if os_result.is_macos or os_result.is_macos_wheel:
repository_ctx.symlink(
Label("@drake//tools/workspace/opengl:package-macos.BUILD.bazel"),
"BUILD.bazel",
Expand Down
31 changes: 23 additions & 8 deletions tools/workspace/os.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
"""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:
To opt-in to the "manylinux" or "macos_wheel" build variants, set the
environment variable (e.g.) `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.
command line. (Replace "manylinux" with "macos_wheel" as appropriate.)
"""

load("@drake//tools/workspace:execute.bzl", "which")
Expand Down Expand Up @@ -140,6 +140,19 @@ def _determine_macos(repository_ctx):
# Shared error message text across different failure cases.
error_prologue = "could not determine macOS version: "

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

# Run sw_vers to determine macOS version.
sw_vers = exec_using_which(repository_ctx, [
"sw_vers",
Expand All @@ -166,6 +179,7 @@ def _determine_macos(repository_ctx):
return _make_result(
macos_release = macos_release,
homebrew_prefix = homebrew_prefix,
is_wheel = is_macos_wheel,
)

# Nothing matched.
Expand All @@ -188,7 +202,8 @@ def determine_os(repository_ctx):
libstdc++, etc.). In this case, the value of is_ubuntu will be False, but
ubuntu_release will still be provided.
TODO(jwnimmer-tri) The is_macos_wheel option isn't detected / active yet.
The "macos_wheel" target indicates this build will be packaged into a
Python wheel.
In case of an error, the "error" attribute of the struct will be set, and
all of the other fields will be None or False.
Expand All @@ -211,8 +226,8 @@ def determine_os(repository_ctx):
- macos_release: str like "11" or "12" (set any time the build platform
is macOS, even for builds targeting "macos_wheel")
- homebrew_prefix: str "/usr/local" or "/opt/homebrew" (set any time
the build platform is macOS, even for builds targeting
"macos_wheel")
the build platform is macOS, even for builds targeting
"macos_wheel")
"""

os_name = repository_ctx.os.name
Expand Down
31 changes: 19 additions & 12 deletions tools/workspace/pkg_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,25 @@ def setup_pkg_config_repository(repository_ctx):
[],
))

# Find the desired homebrew search path, if any.
homebrew_prefix = determine_os(repository_ctx).homebrew_prefix
homebrew_subdir = getattr(
repository_ctx.attr,
"homebrew_subdir",
"",
)
if homebrew_prefix and homebrew_subdir:
pkg_config_paths.insert(0, "{}/{}".format(
homebrew_prefix,
homebrew_subdir,
))
os_result = determine_os(repository_ctx)

if os_result.is_macos or os_result.is_macos_wheel:
# Find the desired homebrew search path, if any.
homebrew_prefix = os_result.homebrew_prefix
homebrew_subdir = getattr(
repository_ctx.attr,
"homebrew_subdir",
"",
)
if homebrew_prefix and homebrew_subdir:
pkg_config_paths.insert(0, "{}/{}".format(
homebrew_prefix,
homebrew_subdir,
))

if os_result.is_manylinux or os_result.is_macos_wheel:
pkg_config_paths.insert(0, "/opt/drake-dependencies/share/pkgconfig")
pkg_config_paths.insert(0, "/opt/drake-dependencies/lib/pkgconfig")

# Check if we can find the required *.pc file of any version.
result = _run_pkg_config(repository_ctx, args, pkg_config_paths)
Expand Down
3 changes: 2 additions & 1 deletion tools/workspace/python/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ load("@drake//tools/workspace:os.bzl", "determine_os")
_VERSION_SUPPORT_MATRIX = {
"ubuntu:20.04": ["3.8"],
"macos": ["3.9"],
"macos_wheel": ["3.9"],
"manylinux": ["3.8", "3.9"],
}

Expand All @@ -69,7 +70,7 @@ def repository_python_info(repository_ctx):
os_key += ":" + os_result.ubuntu_release
versions_supported = _VERSION_SUPPORT_MATRIX[os_key]

if os_result.is_macos:
if os_result.is_macos or os_result.is_macos_wheel:
# This value must match the interpreter_path in
# @drake//tools/py_toolchain:macos_py3_runtime
python = repository_ctx.attr.macos_interpreter_path
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/snopt/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def _impl(repo_ctx):
Label("@drake//tools/workspace/snopt:fortran-ubuntu.bzl"),
"fortran.bzl",
)
elif os_result.is_macos:
elif os_result.is_macos or os_result.is_macos_wheel:
repo_ctx.symlink(
Label("@drake//tools/workspace/snopt:fortran-macos.bzl"),
"fortran.bzl",
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/spdlog/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ 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:
elif os_result.is_manylinux or os_result.is_macos_wheel:
# Compile it from downloaded github sources.
error = setup_github_repository(repo_ctx).error
else:
Expand Down
2 changes: 1 addition & 1 deletion tools/workspace/suitesparse/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def _impl(repo_ctx):
libdir = "{}/opt/suite-sparse/lib".format(
os_result.homebrew_prefix,
)
elif os_result.is_manylinux:
elif os_result.is_manylinux or os_result.is_macos_wheel:
# TODO(jwnimmer-tri) Ideally, we wouldn't be hard-coding paths when
# using manylinux.
include = "/opt/drake-dependencies/include"
Expand Down
25 changes: 20 additions & 5 deletions tools/workspace/vtk/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _vtk_cc_library(
elif os_result.is_ubuntu:
if not header_only:
srcs = ["lib/lib{}-{}.so.1".format(name, VTK_MAJOR_MINOR_VERSION)]
elif os_result.is_manylinux:
elif os_result.is_manylinux or os_result.is_macos_wheel:
if not header_only:
# TODO(jwnimmer-tri) Ideally, we wouldn't be hard-coding paths when
# using manylinux.
Expand Down Expand Up @@ -136,7 +136,7 @@ def _impl(repository_ctx):
sha256 = sha256,
type = "tar.gz",
)
elif os_result.is_manylinux:
elif os_result.is_manylinux or os_result.is_macos_wheel:
repository_ctx.symlink("/opt/vtk/include", "include")
else:
fail("Operating system is NOT supported {}".format(os_result))
Expand All @@ -157,7 +157,7 @@ licenses([
file_content += _vtk_cc_library(os_result, "vtkfmt")

# NOTE: see /tools/wheel/image/vtk-args, this is to avoid packaging glew.
if os_result.is_manylinux:
if os_result.is_manylinux or os_result.is_macos_wheel:
file_content += _vtk_cc_library(os_result, "vtkglew")

file_content += _vtk_cc_library(os_result, "vtkkissfft")
Expand Down Expand Up @@ -835,15 +835,24 @@ licenses([
"vtkGenericRenderWindowInteractor.h",
"vtkRenderingUIModule.h",
]
if not os_result.is_macos:
if not os_result.is_macos and not os_result.is_macos_wheel:
vtk_rendering_ui_hdrs.append("vtkXRenderWindowInteractor.h")

if os_result.is_macos_wheel:
# Normally this would be a private dependency, but no such thing when
# VTK is built static.
vtk_ui_linkopts = ["-framework Cocoa"]
else:
vtk_ui_linkopts = []

file_content += _vtk_cc_library(
os_result,
"vtkRenderingUI",
hdrs = vtk_rendering_ui_hdrs,
deps = [
":vtkRenderingCore",
],
linkopts = vtk_ui_linkopts,
)

# Indirect dependency: omit headers.
Expand All @@ -869,12 +878,18 @@ licenses([
"vtkShader.h",
"vtkShaderProgram.h",
]
if not os_result.is_macos:
if not os_result.is_macos and not os_result.is_macos_wheel:
vtk_rendering_opengl2_hdrs.append("vtkXOpenGLRenderWindow.h")

if os_result.is_manylinux:
vtk_glew_library = ":vtkglew"

# Normally these would be private dependencies, but no such thing when
# VTK is built static.
vtk_opengl_linkopts = ["-lX11", "-lXt", "-lGLX"]
elif os_result.is_macos_wheel:
vtk_glew_library = ":vtkglew"
vtk_opengl_linkopts = []
else:
vtk_glew_library = "@glew"
vtk_opengl_linkopts = []
Expand Down

0 comments on commit 1ffa6f9

Please sign in to comment.