Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[build] Support bzlmod for building and installing #22271

Merged
merged 1 commit into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
/build/
/cmake-build-*/

# Bazel build artifacts (symlinks)
# Bazel build artifacts
/bazel-*
/MODULE.bazel.lock

# Platform artifacts generated by `install_prereqs`
/gen/
Expand Down
25 changes: 23 additions & 2 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ exports_files([
"package.xml",
])

exports_files(
[
"MODULE.bazel",
"WORKSPACE",
"WORKSPACE.bzlmod",
],
visibility = ["//tools/workspace:__pkg__"],
)

# A legacy hack module to disambiguate the 'drake' module when Drake is being
# used as a non-bzlmod external. We should remove this when we drop support for
# WORKSPACE (i.e., Bazel >= 9).
Expand Down Expand Up @@ -84,12 +93,24 @@ filegroup(

_INSTALL_TEST_COMMANDS = "install_test_commands"

# These are the (only) files from our root directory which are installed. Note
# that even though the "data_dest" and "doc_dest" seem to be redundant with the
# default value for those attributes, that is not the case with bzlmod (where
# the default repository is named "_main" not "drake").
install(
name = "install",
install_tests_script = _INSTALL_TEST_COMMANDS,
name = "install_files",
data = ["package.xml"],
data_dest = "share/drake",
docs = ["LICENSE.TXT"],
doc_dest = "share/doc/drake",
visibility = ["//visibility:private"],
)

install(
name = "install",
install_tests_script = _INSTALL_TEST_COMMANDS,
deps = [
":install_files",
"//bindings/pydrake:install",
"//common:install",
"//examples:install",
Expand Down
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,10 @@ endforeach()
# however, that the macOS wheel builds also need to know this path, so if it
# ever changes, tools/wheel/macos/build-wheel.sh will also need to be updated.
configure_file(cmake/bazel.rc.in drake_build_cwd/.bazelrc @ONLY)
configure_file(cmake/WORKSPACE.in drake_build_cwd/WORKSPACE.bazel @ONLY)
configure_file(cmake/WORKSPACE.bzlmod.in drake_build_cwd/WORKSPACE.bzlmod @ONLY)
file(CREATE_LINK "${PROJECT_SOURCE_DIR}/.bazeliskrc" drake_build_cwd/.bazeliskrc SYMBOLIC)
file(CREATE_LINK "${PROJECT_SOURCE_DIR}/MODULE.bazel" drake_build_cwd/MODULE.bazel SYMBOLIC)
file(CREATE_LINK "${PROJECT_SOURCE_DIR}/WORKSPACE" drake_build_cwd/WORKSPACE SYMBOLIC)

find_package(Git)

Expand Down
29 changes: 29 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This file marks a workspace root for the Bazel build system.
# See `https://bazel.build/`.

# This file lists Drake's external dependencies as known to bzlmod.
#
# When bzlmod is disabled, this file is NOT used. Instead, only WORKSPACE is
# used.
#
# When bzlmod is enabled, this file + WORKSPACE.bzlmod are both used, and
# WORKSPACE is ignored.

module(name = "drake")

bazel_dep(name = "bazel_skylib", version = "1.7.1")
bazel_dep(name = "rules_cc", version = "0.0.17")
bazel_dep(name = "rules_java", version = "8.6.1")
bazel_dep(name = "rules_license", version = "1.0.0")
bazel_dep(name = "rules_python", version = "0.40.0")

cc_configure = use_extension(
"@rules_cc//cc:extensions.bzl",
"cc_configure_extension",
)
use_repo(cc_configure, "local_config_cc")

# TODO(#20731) Move all of our dependencies from WORKSPACE.bzlmod into this
# file, so that downstream projects can consume Drake exclusively via bzlmod
# (and so that we can delete our WORKSPACE files prior to Bazel 9 which drops
# suppose for it).
7 changes: 6 additions & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# This file marks a workspace root for the Bazel build system.
# See `https://bazel.build/`.
#
# When bzlmod is disabled, only this file is used. The related files
# MODULE.bazel and WORKSPACE.bzlmod are NOT used.
#
# When bzlmod is enabled, this file is ignored.

workspace(name = "drake")

load("//tools/workspace:default.bzl", "add_default_workspace")

add_default_workspace()
add_default_workspace(bzlmod = False)

load("@build_bazel_apple_support//crosstool:setup.bzl", "apple_cc_configure")

Expand Down
38 changes: 38 additions & 0 deletions WORKSPACE.bzlmod
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# -*- bazel -*-
#
# This file lists Drake's external dependencies as known to bzlmod.
#
# When bzlmod is disabled, this file is NOT used. Instead, only WORKSPACE is
# used.
#
# When bzlmod is enabled, this file + MODULE.bazel are both used, and WORKSPACE
# is ignored.

workspace(name = "drake")

load("//tools/workspace:default.bzl", "add_default_workspace")

add_default_workspace(bzlmod = True)

load("@build_bazel_apple_support//crosstool:setup.bzl", "apple_cc_configure")

apple_cc_configure()

# Add some special heuristic logic for using CLion with Drake.
load("//tools/clion:repository.bzl", "drake_clion_environment")

drake_clion_environment()

load("@bazel_skylib//lib:versions.bzl", "versions")

# This needs to be in WORKSPACE or a repository rule for native.bazel_version
# to actually be defined. The minimum_bazel_version value should match the
# version passed to the find_package(Bazel) call in the root CMakeLists.txt.
versions.check(minimum_bazel_version = "7.1")

# The cargo_universe programs are only used by Drake's new_release tooling, not
# by any compilation rules. As such, we can put it directly into the WORKSPACE
# instead of into our `//tools/workspace:default.bzl` repositories.
load("@rules_rust//crate_universe:repositories.bzl", "crate_universe_dependencies") # noqa

crate_universe_dependencies(bootstrap = True)
1 change: 1 addition & 0 deletions cmake/WORKSPACE.in → cmake/WORKSPACE.bzlmod.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ _BAZEL_WORKSPACE_EXCLUDES = split_cmake_list("@BAZEL_WORKSPACE_EXCLUDES@")
# For anything not already overridden, use Drake's default externals.
add_default_workspace(
repository_excludes = ["python"] + _BAZEL_WORKSPACE_EXCLUDES,
bzlmod = True,
)

load("@build_bazel_apple_support//crosstool:setup.bzl", "apple_cc_configure")
Expand Down
5 changes: 5 additions & 0 deletions cmake/bazel.rc.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ startup --output_base="@BAZEL_OUTPUT_BASE@"
# Inherit Drake's default options.
@BAZELRC_IMPORT@

# By default Drake (currently) opts-out of bzlmod, but for CMake builds we want
# to enable it as a mechanism for covering our bzlmod changes in CI, and also
# to be forward-looking since bzlmod is all Bazel >= 9 will support.
common --enable_bzlmod=true

# Environment variables to be used in repository rules (if any).
common @BAZEL_REPO_ENV@

Expand Down
2 changes: 2 additions & 0 deletions tools/bazel.rc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Don't use bzlmod yet.
# TODO(jwnimmer-tri) When we enable bzlmod by default here, we should nix the
# redundant setting drake/cmake/bazel.rc.in at the same time.
common --enable_workspace=true
common --enable_bzlmod=false

Expand Down
4 changes: 2 additions & 2 deletions tools/lint/bazel_lint.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ def bazel_lint(
name = name,
files = native.glob(
[
"*.bazel",
"*.bzl",
"*.bzlmod",
"*.BUILD",
"*.BUILD.bazel",
"BUILD",
"BUILD.bazel",
"WORKSPACE",
],
exclude = exclude,
Expand Down
15 changes: 15 additions & 0 deletions tools/py_toolchain/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
load("@python//:version.bzl", "PYTHON_BIN_PATH")
load("@rules_python//python:defs.bzl", "py_runtime", "py_runtime_pair")
load(
"@rules_python//python:py_exec_tools_toolchain.bzl",
"py_exec_tools_toolchain",
)
load("//tools/lint:lint.bzl", "add_lint_tests")

py_runtime(
Expand All @@ -19,4 +23,15 @@ toolchain(
toolchain_type = "@rules_python//python:toolchain_type",
)

py_exec_tools_toolchain(
name = "exec_tools",
precompiler = "@rules_python//tools/precompiler:precompiler",
)

toolchain(
name = "exec_tools_toolchain",
toolchain = ":exec_tools",
toolchain_type = "@rules_python//python:exec_tools_toolchain_type",
)

add_lint_tests()
6 changes: 6 additions & 0 deletions tools/skylark/drake_py.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ def drake_py_binary(
srcs = srcs,
main = main,
deps = deps,
# We use the same srcs for both the py_binary and the py_test so we
# must disable pre-compilation during the py_test target; otherwise
# both targets would declare an identical set of `*.pyc` output
# files from their build actions and bazel would error out because
# of the malformed BUILD file.
precompile = "disabled",
isolate = isolate,
args = test_rule_args,
data = data + test_rule_data,
Expand Down
20 changes: 20 additions & 0 deletions tools/workspace/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ drake_py_test(
deps = [":module_py"],
)

drake_py_test(
name = "workspace_bzlmod_sync_test",
srcs = ["workspace_bzlmod_sync_test.py"],
allow_import_unittest = True,
data = [
":default.bzl",
"//:MODULE.bazel",
"//:WORKSPACE",
"//:WORKSPACE.bzlmod",
"//tools/workspace/bazel_skylib:repository.bzl",
"//tools/workspace/rules_cc:repository.bzl",
"//tools/workspace/rules_license:repository.bzl",
],
tags = ["lint"],
deps = [
":module_py",
"@rules_python//python/runfiles",
],
)

drake_py_binary(
name = "cmake_configure_file",
srcs = ["cmake_configure_file.py"],
Expand Down
9 changes: 6 additions & 3 deletions tools/workspace/bazel_skylib/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# 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")

# Required for workspace_bzlmod_sync_test.py.
exports_files(
["repository.bzl"],
visibility = ["//tools/workspace:__pkg__"],
)

add_lint_tests()
4 changes: 4 additions & 0 deletions tools/workspace/bazel_skylib/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ def bazel_skylib_repository(name, mirrors = None):
github_archive(
name = name,
repository = "bazelbuild/bazel-skylib",
upgrade_advice = """
When updating, you must also manually propagate to the new version
number into the MODULE.bazel file (at the top level of Drake).
""",
commit = "1.7.1",
sha256 = "e3fea03ff75a9821e84199466799ba560dbaebb299c655b5307f4df1e5970696", # noqa
mirrors = mirrors,
Expand Down
11 changes: 6 additions & 5 deletions tools/workspace/cc/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ Argument:

load("//tools/workspace:execute.bzl", "execute_or_fail")

# We can probe whether bzlmod is enabled by checking if labels use one or two
# leading '@' charaters. (The label doesn't need to be valid.)
BZLMOD_ENABLED = "@@" in str(Label("//:foo"))

def _check_compiler_version(compiler_id, actual_version, supported_version):
"""
Check if the compiler is of a supported version and report an error if not.
Expand Down Expand Up @@ -91,8 +87,13 @@ def _impl(repository_ctx):
else:
cc_environment = {}

# For Bazel 7.x sometimes we need a weird spelling of @local_config_cc.
# We can probably remove this once our minimum supported Bazel is >= 8.
local_config_cc = "@local_config_cc"
if BZLMOD_ENABLED:
if all([
native.bazel_version.startswith("7."),
"@@" in str(Label("//:foo")),
]):
local_config_cc = "@bazel_tools~cc_configure_extension~local_config_cc"
executable = repository_ctx.path("identify_compiler")
execute_or_fail(repository_ctx, [
Expand Down
Loading