From 22e0fc5bcbd4815b3d0efdd309c50cf7a9ceb2f6 Mon Sep 17 00:00:00 2001 From: Adam Jacob Date: Mon, 1 Apr 2024 17:17:55 -0700 Subject: [PATCH] feat(ci): enable release and debug builds This PR enables release and debug builds for buck2. By default, we will always do debug builds (or, more accurately, whatever the rustc compiler thinks the defaults should be). If you want to build for release or debug explicitly, you can do that with: ``` $ buck2 build @//mode/release //bin/sdf:sdf ``` And the result will be compiled with release optimizations. You can also use `@//mode/debug` if you want. Those files are just ways of DRY-ing up the configuration options - you could also pass them directly on the command line. We can add as many configuration options as we want, and as many toolchain configurations as we want, by extending the options in the `//config` tree, adding a new toolchain statement, and extending the select statement for the `:rust` alias. --- .buckconfig | 5 +- config/BUCK | 3 + mode/debug | 1 + mode/release | 1 + .../build_context_srcs_from_deps.bxl | 3 + prelude-si/platforms/BUCK | 88 +++++++++++++++++++ prelude-si/platforms/defs.bzl | 66 ++++++++++++++ toolchains/BUCK | 27 +++++- toolchains/toolchain.bzl | 17 ++++ 9 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 config/BUCK create mode 100644 mode/debug create mode 100644 mode/release create mode 100644 prelude-si/platforms/BUCK create mode 100644 prelude-si/platforms/defs.bzl create mode 100644 toolchains/toolchain.bzl diff --git a/.buckconfig b/.buckconfig index 193def011e..fdff03c4de 100644 --- a/.buckconfig +++ b/.buckconfig @@ -14,8 +14,9 @@ fbsource = none [parser] target_platform_detector_spec = \ - target:root//...->prelude//platforms:default \ - target:prelude-si//...->prelude//platforms:default + target:root//...->prelude-si//platforms:default \ + target:prelude-si//...->prelude-si//platforms:default \ + target:toolchains//...->prelude-si//platforms:default \ [project] ignore = \ diff --git a/config/BUCK b/config/BUCK new file mode 100644 index 0000000000..64a64f5698 --- /dev/null +++ b/config/BUCK @@ -0,0 +1,3 @@ +constraint_setting(name = "rust_build_mode", visibility = ["PUBLIC"]) +constraint_value(name = "build_debug", constraint_setting = ":rust_build_mode", visibility = ["PUBLIC"]) +constraint_value(name = "build_release", constraint_setting = ":rust_build_mode", visibility = ["PUBLIC"]) diff --git a/mode/debug b/mode/debug new file mode 100644 index 0000000000..60a0e9c345 --- /dev/null +++ b/mode/debug @@ -0,0 +1 @@ +--config=rustc.mode=build_debug diff --git a/mode/release b/mode/release new file mode 100644 index 0000000000..406d29f412 --- /dev/null +++ b/mode/release @@ -0,0 +1 @@ +--config=rustc.mode=build_release diff --git a/prelude-si/build_context/build_context_srcs_from_deps.bxl b/prelude-si/build_context/build_context_srcs_from_deps.bxl index 109dfdd117..419a774bfd 100644 --- a/prelude-si/build_context/build_context_srcs_from_deps.bxl +++ b/prelude-si/build_context/build_context_srcs_from_deps.bxl @@ -27,6 +27,9 @@ def _build_context_srcs_from_deps_impl(ctx): # Add candidate path entries for the Buck2 prelude directories (we want *all* these files) raw_paths.append("prelude") raw_paths.append("prelude-si") + raw_paths.append("config") + raw_paths.append("mode") + raw_paths.append("toolchains") # While not officially in a prelude, there are macros that Reindeer used to create the Rust # third-party targets, so we will include this directory as well. diff --git a/prelude-si/platforms/BUCK b/prelude-si/platforms/BUCK new file mode 100644 index 0000000000..238dab2f43 --- /dev/null +++ b/prelude-si/platforms/BUCK @@ -0,0 +1,88 @@ +# The custom platform for SI. This is taken from the prelude, but includes our customizations for +# rust build flags. +# +# Essentially, we should be adding any custom configuration into root//config, and then plumbing it +# through the execution_platform defined below. +# +# To actually add new configuration, you'll extend the relevant python function to output the +# correct configuration info, and then you can use it in a select() statement at will. + +load(":defs.bzl", "execution_platform", "host_configuration") + +prelude = native + +_rust_build_mode = read_root_config("rustc", "mode", "build_debug") +_rust_build_mode_constraint = "root//config:" + _rust_build_mode + +execution_platform( + name = "default", + cpu_configuration = host_configuration.cpu, + os_configuration = host_configuration.os, + rust_build_mode = _rust_build_mode_constraint, + use_windows_path_separators = host_info().os.is_windows, +) + +prelude.constraint_setting( + name = "runs_remote", +) + +prelude.constraint_value( + name = "may_run_remote", + constraint_setting = ":runs_remote", + visibility = ["PUBLIC"], +) + +prelude.constraint_setting( + name = "runs_local", + visibility = ["PUBLIC"], +) + +prelude.constraint_value( + name = "may_run_local", + constraint_setting = ":runs_local", + visibility = ["PUBLIC"], +) + +prelude.constraint_setting( + name = "runs_only", +) + +prelude.constraint_value( + name = "runs_only_local", + constraint_setting = ":runs_only", + visibility = ["PUBLIC"], +) + +prelude.constraint_value( + name = "runs_only_remote", + constraint_setting = ":runs_only", + visibility = ["PUBLIC"], +) + +prelude.constraint_setting( + name = "fat_platform_marker", +) + +prelude.constraint_value( + name = "fat_platform_enabled", + constraint_setting = ":fat_platform_marker", + visibility = ["PUBLIC"], +) + +# This is mostly here for a rule type to add a dependency on it to mark all +# instances of that rule type as incompatible with a fat platform. Ideally, +# toolchains could affect the target compatibility of their users directly but +# toolchains are currently all exec deps and so cannot do that. We'd like +# buck2 to support a form of dep that inherited its users execution platform +# so that toolchains could basically get visibility and affect both target and +# execution configuration, but that's not implemented yet. +export_file( + name = "fat_platform_incompatible", + # @oss-disable: src = "TARGETS.v2", + src = "BUCK", # @oss-enable + target_compatible_with = select({ + ":fat_platform_enabled": ["config//:none"], + "DEFAULT": [], + }), + visibility = ["PUBLIC"], +) diff --git a/prelude-si/platforms/defs.bzl b/prelude-si/platforms/defs.bzl new file mode 100644 index 0000000000..7e940ee00c --- /dev/null +++ b/prelude-si/platforms/defs.bzl @@ -0,0 +1,66 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under both the MIT license found in the +# LICENSE-MIT file in the root directory of this source tree and the Apache +# License, Version 2.0 found in the LICENSE-APACHE file in the root directory +# of this source tree. + +def _execution_platform_impl(ctx: AnalysisContext) -> list[Provider]: + constraints = dict() + constraints.update(ctx.attrs.cpu_configuration[ConfigurationInfo].constraints) + constraints.update(ctx.attrs.os_configuration[ConfigurationInfo].constraints) + constraints.update(ctx.attrs.rust_build_mode[ConfigurationInfo].constraints) + cfg = ConfigurationInfo(constraints = constraints, values = {}) + + name = ctx.label.raw_target() + platform = ExecutionPlatformInfo( + label = name, + configuration = cfg, + executor_config = CommandExecutorConfig( + local_enabled = True, + remote_enabled = False, + use_windows_path_separators = ctx.attrs.use_windows_path_separators, + ), + ) + + return [ + DefaultInfo(), + platform, + PlatformInfo(label = str(name), configuration = cfg), + ExecutionPlatformRegistrationInfo(platforms = [platform]), + ] + +execution_platform = rule( + impl = _execution_platform_impl, + attrs = { + "cpu_configuration": attrs.dep(providers = [ConfigurationInfo]), + "os_configuration": attrs.dep(providers = [ConfigurationInfo]), + "rust_build_mode": attrs.dep(providers = [ConfigurationInfo]), + "use_windows_path_separators": attrs.bool(), + }, +) + +def _host_cpu_configuration() -> str: + arch = host_info().arch + if arch.is_aarch64: + return "prelude//cpu:arm64" + elif arch.is_arm: + return "prelude//cpu:arm32" + elif arch.is_i386: + return "prelude//cpu:x86_32" + else: + return "prelude//cpu:x86_64" + +def _host_os_configuration() -> str: + os = host_info().os + if os.is_macos: + return "prelude//os:macos" + elif os.is_windows: + return "prelude//os:windows" + else: + return "prelude//os:linux" + +host_configuration = struct( + cpu = _host_cpu_configuration(), + os = _host_os_configuration(), +) diff --git a/toolchains/BUCK b/toolchains/BUCK index 8676e92625..ddc0486d00 100644 --- a/toolchains/BUCK +++ b/toolchains/BUCK @@ -1,3 +1,4 @@ +load(":toolchain.bzl", "toolchain_alias") load("@prelude//toolchains:cxx.bzl", "system_cxx_toolchain") load("@prelude//toolchains:genrule.bzl", "system_genrule_toolchain") load( @@ -45,9 +46,33 @@ system_python_bootstrap_toolchain( ) system_rust_toolchain( - name = "rust", + name = "rust_release", + default_edition = "2021", + clippy_toml = "root//:clippy.toml", + visibility = ["PUBLIC"], + rustc_flags = [ + "-Copt-level=3", + "-Cdebuginfo=none", + "-Cdebug-assertions=false", + "-Coverflow-checks=false", + "-Clto=false", + "-Ccodegen-units=16" + ] +) + +system_rust_toolchain( + name = "rust_debug", default_edition = "2021", clippy_toml = "root//:clippy.toml", + visibility = ["PUBLIC"] +) + +toolchain_alias( + name = "rust", + actual = select({ + "root//config:build_debug": ":rust_debug", + "root//config:build_release": ":rust_release", + }), visibility = ["PUBLIC"], ) diff --git a/toolchains/toolchain.bzl b/toolchains/toolchain.bzl new file mode 100644 index 0000000000..9485c19a79 --- /dev/null +++ b/toolchains/toolchain.bzl @@ -0,0 +1,17 @@ +def _toolchain_alias_impl(ctx: AnalysisContext) -> list[Provider]: + return ctx.attrs.actual.providers + +toolchain_alias = rule( + doc=""" +toolchain_alias acts like alias but for toolchain rules. +The toolchain_alias itself is a toolchain rule and the `actual` argument is +expected to be a toolchain_rule as well. + """, + attrs={ + "actual": attrs.toolchain_dep( + doc="The actual toolchain that is being aliased. This should be a toolchain rule." + ) + }, + impl=_toolchain_alias_impl, + is_toolchain_rule=True, +)