From 47a9f25e55fec3bf12fa0950aac920bb9b715f20 Mon Sep 17 00:00:00 2001 From: Jeremy Nimmer Date: Mon, 4 Mar 2024 07:59:04 -0800 Subject: [PATCH] [workspace] Remove determine_os logic Centralize choice of C++20 to be project-wide, instead of OS-specific. Simplify CMakeLists to use whatever OS codename it finds for the bazel customizations, with only warnings (not errors) when none is found. Overall, these changes remove some barriers to building Drake on non-Ubuntu linuxen. --- CMakeLists.txt | 65 +++------ doc/_pages/from_source.md | 4 +- tools/bazel.rc | 4 + tools/macos.bazelrc | 4 - tools/ubuntu-jammy.bazelrc | 4 - tools/ubuntu-noble.bazelrc | 4 - tools/workspace/fmt/repository.bzl | 7 +- tools/workspace/os.bzl | 200 +------------------------- tools/workspace/pkg_config.bzl | 11 +- tools/workspace/spdlog/repository.bzl | 12 +- 10 files changed, 41 insertions(+), 274 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52983b7e30ed..5208d4e9af9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,56 +52,29 @@ if(APPLE) endif() list(APPEND BAZELRC_IMPORTS "tools/macos-arch-${MACOS_ARCH}.bazelrc") else() - find_program(LSB_RELEASE_EXECUTABLE NAMES lsb_release) - - if(NOT LSB_RELEASE_EXECUTABLE) - message(FATAL_ERROR "Could NOT find the lsb_release executable") - endif() + list(APPEND BAZELRC_IMPORTS "tools/ubuntu.bazelrc") + find_program(LSB_RELEASE_EXECUTABLE NAMES lsb_release) mark_as_advanced(LSB_RELEASE_EXECUTABLE) - - execute_process(COMMAND "${LSB_RELEASE_EXECUTABLE}" --id --short - RESULT_VARIABLE LSB_RELEASE_ID_SHORT_RESULT_VARIABLE - OUTPUT_VARIABLE LSB_RELEASE_ID_SHORT_OUTPUT_VARIABLE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(LSB_RELEASE_ID_SHORT_RESULT_VARIABLE EQUAL 0) - set(UNIX_DISTRIBUTION_ID "${LSB_RELEASE_ID_SHORT_OUTPUT_VARIABLE}") - endif() - - if(NOT UNIX_DISTRIBUTION_ID STREQUAL Ubuntu) - message(WARNING - "Distribution ${UNIX_DISTRIBUTION_ID} is NOT supported" - ) - endif() - - string(TOLOWER "${UNIX_DISTRIBUTION_ID}" UNIX_DISTRIBUTION_ID) - - execute_process(COMMAND "${LSB_RELEASE_EXECUTABLE}" --codename --short - RESULT_VARIABLE LSB_RELEASE_CODENAME_SHORT_RESULT_VARIABLE - OUTPUT_VARIABLE LSB_RELEASE_CODENAME_SHORT_OUTPUT_VARIABLE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(LSB_RELEASE_CODENAME_SHORT_RESULT_VARIABLE EQUAL 0) - set(UNIX_DISTRIBUTION_CODENAME - "${LSB_RELEASE_CODENAME_SHORT_OUTPUT_VARIABLE}" - ) - endif() - - # The supported releases should match those listed in both - # doc/_pages/from_source.md and tools/workspace/os.bzl. - if(NOT UNIX_DISTRIBUTION_CODENAME MATCHES "^(jammy|noble)$") - message(FATAL_ERROR - "Release ${UNIX_DISTRIBUTION_CODENAME} is NOT supported. Please use " - "Ubuntu 22.04 (Jammy) or Ubuntu 24.04 (Noble)." + if(NOT LSB_RELEASE_EXECUTABLE) + message(WARNING "Could NOT find the lsb_release executable") + else() + execute_process(COMMAND "${LSB_RELEASE_EXECUTABLE}" --codename --short + RESULT_VARIABLE LSB_RELEASE_CODENAME_SHORT_RESULT_VARIABLE + OUTPUT_VARIABLE UNIX_DISTRIBUTION_CODENAME + OUTPUT_STRIP_TRAILING_WHITESPACE ) + if(NOT LSB_RELEASE_CODENAME_SHORT_RESULT_VARIABLE EQUAL 0) + message(WARNING "Could NOT run the lsb_release executable") + else() + set(MAYBE_RC "tools/ubuntu-${UNIX_DISTRIBUTION_CODENAME}.bazelrc") + if(NOT EXISTS "${PROJECT_SOURCE_DIR}/${MAYBE_RC}") + message(WARNING "Could NOT find config file ${MAYBE_RC}") + else() + list(APPEND BAZELRC_IMPORTS "${MAYBE_RC}") + endif() + endif() endif() - - list(APPEND BAZELRC_IMPORTS "tools/ubuntu.bazelrc") - list(APPEND BAZELRC_IMPORTS - "tools/ubuntu-${UNIX_DISTRIBUTION_CODENAME}.bazelrc") endif() # The version passed to find_package(Bazel) should match the diff --git a/doc/_pages/from_source.md b/doc/_pages/from_source.md index fd259776fc8a..cc68fa718f70 100644 --- a/doc/_pages/from_source.md +++ b/doc/_pages/from_source.md @@ -7,8 +7,8 @@ title: Source Installation The following table shows the configurations and platforms that Drake officially supports: - + diff --git a/tools/bazel.rc b/tools/bazel.rc index e563ba0406b9..6d30300dca80 100644 --- a/tools/bazel.rc +++ b/tools/bazel.rc @@ -8,6 +8,10 @@ build -c opt build --strip=never build --strict_system_includes +# Use C++20 by default. +build --cxxopt=-std=c++20 +build --host_cxxopt=-std=c++20 + # Default test options. build --test_output=errors build --test_summary=terse diff --git a/tools/macos.bazelrc b/tools/macos.bazelrc index c378d979e124..f82da01fdc84 100644 --- a/tools/macos.bazelrc +++ b/tools/macos.bazelrc @@ -1,9 +1,5 @@ # Common options for macOS, no matter the arch (x86 or arm). -# Use C++20 by default. -build --cxxopt=-std=c++20 -build --host_cxxopt=-std=c++20 - # Suppress numerous "'_FORTIFY_SOURCE' macro redefined" warnings when using # sanitizers. build:asan --copt=-Wno-macro-redefined diff --git a/tools/ubuntu-jammy.bazelrc b/tools/ubuntu-jammy.bazelrc index ab3e8a4464aa..ecb5ca704f60 100644 --- a/tools/ubuntu-jammy.bazelrc +++ b/tools/ubuntu-jammy.bazelrc @@ -1,7 +1,3 @@ -# Use C++20 by default. -build --cxxopt=-std=c++20 -build --host_cxxopt=-std=c++20 - # Options for explicitly using Clang. common:clang --repo_env=CC=clang-14 common:clang --repo_env=CXX=clang++-14 diff --git a/tools/ubuntu-noble.bazelrc b/tools/ubuntu-noble.bazelrc index ab3e8a4464aa..ecb5ca704f60 100644 --- a/tools/ubuntu-noble.bazelrc +++ b/tools/ubuntu-noble.bazelrc @@ -1,7 +1,3 @@ -# Use C++20 by default. -build --cxxopt=-std=c++20 -build --host_cxxopt=-std=c++20 - # Options for explicitly using Clang. common:clang --repo_env=CC=clang-14 common:clang --repo_env=CXX=clang++-14 diff --git a/tools/workspace/fmt/repository.bzl b/tools/workspace/fmt/repository.bzl index e11b10d35dad..e13542ec0c8f 100644 --- a/tools/workspace/fmt/repository.bzl +++ b/tools/workspace/fmt/repository.bzl @@ -1,12 +1,9 @@ -load("//tools/workspace:os.bzl", "determine_os") +load("//tools/workspace:os.bzl", "is_wheel_build") load("//tools/workspace:github.bzl", "setup_github_repository") load("//tools/workspace:pkg_config.bzl", "setup_pkg_config_repository") def _impl(repo_ctx): - os_result = determine_os(repo_ctx) - if os_result.error != None: - fail(os_result.error) - if os_result.is_manylinux or os_result.is_macos_wheel: + if is_wheel_build(repo_ctx): # Compile from downloaded github sources. error = setup_github_repository(repo_ctx).error else: diff --git a/tools/workspace/os.bzl b/tools/workspace/os.bzl index 673b31904096..0c162166730e 100644 --- a/tools/workspace/os.bzl +++ b/tools/workspace/os.bzl @@ -47,204 +47,12 @@ def exec_using_which(repository_ctx, command): # Success. return struct(stdout = result.stdout, error = None) -def _make_result( - error = None, - macos_release = None, - ubuntu_release = None, - is_wheel = False, - homebrew_prefix = None, - macos_arch_result = None): - """Return a fully-populated struct result for determine_os, below.""" - is_macos = (macos_release != None) and not is_wheel - is_macos_wheel = (macos_release != None) and is_wheel - is_ubuntu = (ubuntu_release != None) and not is_wheel - is_manylinux = (ubuntu_release != None) and is_wheel - if is_macos: - target = "macos" - elif is_macos_wheel: - target = "macos_wheel" - elif is_ubuntu: - target = "ubuntu" - elif is_manylinux: - target = "manylinux" - else: - target = None - return struct( - error = error, - target = target, - is_macos = is_macos, - is_macos_wheel = is_macos_wheel, - is_ubuntu = is_ubuntu, - is_manylinux = is_manylinux, - ubuntu_release = ubuntu_release, - macos_release = macos_release, - homebrew_prefix = homebrew_prefix, - macos_arch_result = macos_arch_result, - ) - -def _determine_linux(repository_ctx): - """Handle determine_os on Linux.""" - - # 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", "") - is_manylinux = False - if len(drake_os) > 0: - if drake_os == "manylinux": - is_manylinux = True - else: - return _make_result(error = "{}{} DRAKE_OS={}".format( - error_prologue, - "unknown value for environment variable", - drake_os, - )) - - # Get distro name. - lsb = exec_using_which(repository_ctx, ["lsb_release", "-si"]) - if lsb.error != None: - return _make_result(error = error_prologue + lsb.error) - distro = lsb.stdout.strip() - - # Some Ubuntu derivatives reply with their specific name in `-i` mode but - # declare Ubuntu compatibility in /etc. Check for that as a fallback. - if distro != "Ubuntu": - result = repository_ctx.execute([ - "/bin/sh", - "-c", - ". /etc/lsb-release; echo $DISTRIB_ID", - ]) - if result.return_code == 0: - maybe_distro = result.stdout.strip() - if maybe_distro == "Ubuntu": - distro = maybe_distro - - if distro == "Ubuntu": - lsb = exec_using_which(repository_ctx, ["lsb_release", "-sr"]) - if lsb.error != None: - return _make_result(error = error_prologue + lsb.error) - ubuntu_release = lsb.stdout.strip() - - # Match supported Ubuntu release(s). These should match those listed in - # both doc/_pages/from_source.md and the root CMakeLists.txt. - if ubuntu_release in ["22.04", "24.04"]: - return _make_result( - ubuntu_release = ubuntu_release, - is_wheel = is_manylinux, - ) - - # Nothing matched. - return _make_result( - error = (error_prologue + - "unsupported '%s' release '%s'" % - (distro, ubuntu_release)), - ) - - # Nothing matched. - return _make_result( - error = error_prologue + "unsupported distribution '%s'" % distro, - ) - -def _determine_macos(repository_ctx): - """Handle determine_os on macOS.""" - - # 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", - "-productVersion", - ]) - if sw_vers.error != None: - return _make_result(error = error_prologue + sw_vers.error) - - # Match supported macOS release(s). - (macos_release,) = sw_vers.stdout.strip().split(".")[:1] - if macos_release not in ["12", "13", "14"]: - print("WARNING: unsupported macOS '%s'" % macos_release) - - # Check which arch we should be using. - arch_result = exec_using_which(repository_ctx, ["/usr/bin/arch"]) - macos_arch_result = arch_result.stdout.strip() - if macos_arch_result == "arm64": - homebrew_prefix = "/opt/homebrew" - else: - homebrew_prefix = "/usr/local" - - return _make_result( - macos_release = macos_release, - is_wheel = is_macos_wheel, - homebrew_prefix = homebrew_prefix, - macos_arch_result = macos_arch_result, - ) - -def determine_os(repository_ctx): +def is_wheel_build(repository_ctx): """ - DO NOT USE THIS IN NEW CODE. We are working to remove this from Drake. - - A repository_rule helper function that determines which of the supported - build environments (OS versions or wheel environments) we should target. - - We support four options, which are mutually exclusive and collectively - exhaustive: "macos" or "macos_wheel" or "ubuntu" or "manylinux". - - The "manylinux" target indicates this build will be packaged into a Python - wheel that conforms to a "manylinux" standard such as manylinux_2_31; see - https://github.com/pypa/manylinux. Currently we compile this in an Ubuntu - container using only the most basic host packages from Ubuntu (libc, - libstdc++, etc.). In this case, the value of is_ubuntu will be False, but - ubuntu_release will still be provided. - - 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. - - 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 - - - target: str "macos" or "macos_wheel" or "ubuntu" or "manylinux" - - is_macos: True iff targeting a macOS non-wheel build - - is_macos_wheel: True iff targeting a macOS wheel build - - is_ubuntu: True iff targeting an Ubuntu non-wheel build - - is_manylinux: True iff targeting a Linux wheel build - - - ubuntu_release: str like "22.04" (set any time the build - platform is Ubuntu, even for builds targeting "manylinux") - - 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") + Returns true iff this build is a Python wheel flavor. """ - - os_name = repository_ctx.os.name - if os_name == "mac os x": - return _determine_macos(repository_ctx) - elif os_name == "linux": - return _determine_linux(repository_ctx) - else: - return _make_result(error = "unknown or unsupported OS '%s'" % os_name) + drake_os = repository_ctx.os.environ.get("DRAKE_OS", "") + return drake_os in ["manylinux", "macos_wheel"] def os_specific_alias(repository_ctx, mapping): """ diff --git a/tools/workspace/pkg_config.bzl b/tools/workspace/pkg_config.bzl index edc4f5e2fa97..4cb6e039a6bb 100644 --- a/tools/workspace/pkg_config.bzl +++ b/tools/workspace/pkg_config.bzl @@ -1,5 +1,5 @@ load("//tools/workspace:execute.bzl", "path", "which") -load("//tools/workspace:os.bzl", "determine_os") +load("//tools/workspace:os.bzl", "is_wheel_build") _DEFAULT_TEMPLATE = Label("@drake//tools/workspace:pkg_config.BUILD.tpl") @@ -50,9 +50,12 @@ def setup_pkg_config_repository(repository_ctx): [], )) - os_result = determine_os(repository_ctx) - - if os_result.is_manylinux or os_result.is_macos_wheel: + if is_wheel_build(repository_ctx): + # TODO(jwnimmer-tri) Ultimately, we want the wheel build to use Bazel + # to compile all dependencies. At the moment, however, some are built + # using CMake files at drake/tools/wheel/image/dependencies. To find + # the libraries installed by those builds, we need to add some custom + # paths when calling pkg-config. pkg_config_paths.insert(0, "/opt/drake-dependencies/share/pkgconfig") pkg_config_paths.insert(0, "/opt/drake-dependencies/lib/pkgconfig") diff --git a/tools/workspace/spdlog/repository.bzl b/tools/workspace/spdlog/repository.bzl index e5db5b44aa56..99de74032771 100644 --- a/tools/workspace/spdlog/repository.bzl +++ b/tools/workspace/spdlog/repository.bzl @@ -1,15 +1,9 @@ -load("//tools/workspace:os.bzl", "determine_os") -load( - "//tools/workspace:github.bzl", - "setup_github_repository", -) +load("//tools/workspace:os.bzl", "is_wheel_build") +load("//tools/workspace:github.bzl", "setup_github_repository") load("//tools/workspace:pkg_config.bzl", "setup_pkg_config_repository") def _impl(repo_ctx): - os_result = determine_os(repo_ctx) - if os_result.error != None: - fail(os_result.error) - if os_result.is_manylinux or os_result.is_macos_wheel: + if is_wheel_build(repo_ctx): # Compile it from downloaded github sources. error = setup_github_repository(repo_ctx).error else: