diff --git a/cc/toolchains/args/BUILD b/cc/toolchains/args/BUILD index 3fd023d..6545890 100644 --- a/cc/toolchains/args/BUILD +++ b/cc/toolchains/args/BUILD @@ -16,6 +16,7 @@ cc_feature( args = [ "//cc/toolchains/args/archiver_flags", "//cc/toolchains/args/force_pic_flags", + "//cc/toolchains/args/libraries_to_link", "//cc/toolchains/args/linker_param_file", "//cc/toolchains/args/runtime_library_search_directories", "//cc/toolchains/args/shared_flag", @@ -37,6 +38,5 @@ cc_feature( "//cc/toolchains/features/legacy:unfiltered_compile_flags", "//cc/toolchains/features/legacy:user_compile_flags", "//cc/toolchains/features/legacy:user_link_flags", - "//cc/toolchains/features/legacy:libraries_to_link", ], ) diff --git a/cc/toolchains/args/libraries_to_link/BUILD b/cc/toolchains/args/libraries_to_link/BUILD new file mode 100644 index 0000000..4bd1331 --- /dev/null +++ b/cc/toolchains/args/libraries_to_link/BUILD @@ -0,0 +1,175 @@ +load("//cc/toolchains:args.bzl", "cc_args") +load("//cc/toolchains:nested_args.bzl", "cc_nested_args") +load("//cc/toolchains/args/libraries_to_link/private:library_link_args.bzl", "library_link_args") + +package(default_visibility = ["//visibility:private"]) + +cc_args( + name = "libraries_to_link", + actions = [ + "//cc/toolchains/actions:cpp_link_executable", + "//cc/toolchains/actions:cpp_link_dynamic_library", + "//cc/toolchains/actions:cpp_link_nodeps_dynamic_library", + "//cc/toolchains/actions:lto_index_for_executable", + "//cc/toolchains/actions:lto_index_for_dynamic_library", + "//cc/toolchains/actions:lto_index_for_nodeps_dynamic_library", + ], + nested = [ + ":thinlto_param_file", + ":libraries_to_link_args", + ], + visibility = ["//visibility:public"], +) + +cc_nested_args( + name = "thinlto_param_file", + args = ["-Wl,@{param_file}"], + format = { + "param_file": "//cc/toolchains/variables:thinlto_param_file", + }, + requires_not_none = "//cc/toolchains/variables:thinlto_param_file", +) + +cc_nested_args( + name = "libraries_to_link_args", + nested = [":iterate_over_libraries_to_link"], + requires_not_none = "//cc/toolchains/variables:libraries_to_link", +) + +cc_nested_args( + name = "iterate_over_libraries_to_link", + iterate_over = "//cc/toolchains/variables:libraries_to_link", + nested = [ + ":optional_object_file_group_start", + ":single_library_args", + ":optional_object_file_group_end", + ], +) + +cc_nested_args( + name = "optional_object_file_group_start", + nested = [":start_lib_arg"], + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "object_file_group", +) + +cc_nested_args( + name = "start_lib_arg", + args = ["-Wl,--start-lib"], + requires_false = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", +) + +cc_nested_args( + name = "optional_object_file_group_end", + nested = [":end_lib_arg"], + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "object_file_group", +) + +cc_nested_args( + name = "end_lib_arg", + args = ["-Wl,--end-lib"], + requires_false = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", +) + +cc_nested_args( + name = "single_library_args", + nested = select({ + "@platforms//os:macos": [], + "//conditions:default": [":optional_whole_archive_start"], + }) + [ + ":optional_object_file_group", + ":optional_object_file", + ":optional_interface_library", + ":optional_static_library", + ":optional_dynamic_library", + ] + select({ + # maOS has a minor nuance where it uses the path to the library instead of `-l:{library_name}`. + "@platforms//os:macos": [":macos_optional_versioned_dynamic_library"], + "//conditions:default": [":generic_optional_versioned_dynamic_library"], + }) + select({ + "@platforms//os:macos": [], + "//conditions:default": [":optional_whole_archive_end"], + }), +) + +cc_nested_args( + name = "optional_whole_archive_start", + nested = [":whole_archive_start_arg"], + requires_true = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", +) + +cc_nested_args( + name = "whole_archive_start_arg", + args = ["-Wl,-whole-archive"], + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "static_library", +) + +cc_nested_args( + name = "optional_whole_archive_end", + nested = [":whole_archive_end_arg"], + requires_true = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", +) + +cc_nested_args( + name = "whole_archive_end_arg", + args = ["-Wl,-no-whole-archive"], + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "static_library", +) + +library_link_args( + name = "optional_object_file_group", + from_variable = "//cc/toolchains/variables:libraries_to_link.object_files", + iterate_over_variable = True, + library_type = "object_file_group", +) + +library_link_args( + name = "optional_object_file", + from_variable = "//cc/toolchains/variables:libraries_to_link.name", + library_type = "object_file", +) + +library_link_args( + name = "optional_interface_library", + from_variable = "//cc/toolchains/variables:libraries_to_link.name", + library_type = "interface_library", +) + +library_link_args( + name = "optional_static_library", + from_variable = "//cc/toolchains/variables:libraries_to_link.name", + library_type = "static_library", +) + +cc_nested_args( + name = "optional_dynamic_library", + args = ["-l{library}"], + format = { + "library": "//cc/toolchains/variables:libraries_to_link.name", + }, + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "dynamic_library", +) + +cc_nested_args( + name = "generic_optional_versioned_dynamic_library", + args = ["-l:{library_name}"], + format = { + "library_name": "//cc/toolchains/variables:libraries_to_link.name", + }, + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "versioned_dynamic_library", +) + +cc_nested_args( + name = "macos_optional_versioned_dynamic_library", + args = ["{library_path}"], + format = { + "library_path": "//cc/toolchains/variables:libraries_to_link.path", + }, + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "versioned_dynamic_library", +) diff --git a/cc/toolchains/args/libraries_to_link/private/BUILD b/cc/toolchains/args/libraries_to_link/private/BUILD new file mode 100644 index 0000000..ecb36c3 --- /dev/null +++ b/cc/toolchains/args/libraries_to_link/private/BUILD @@ -0,0 +1 @@ +package(default_visibility = ["//visibility:private"]) diff --git a/cc/toolchains/args/libraries_to_link/private/library_link_args.bzl b/cc/toolchains/args/libraries_to_link/private/library_link_args.bzl new file mode 100644 index 0000000..8b0e409 --- /dev/null +++ b/cc/toolchains/args/libraries_to_link/private/library_link_args.bzl @@ -0,0 +1,104 @@ +# Copyright 2024 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Helper macros for declaring library link arguments.""" + +load("//cc/toolchains:nested_args.bzl", "cc_nested_args") + +def macos_force_load_library_args(name, variable): + """A helper for declaring -force_load argument expansion for a library. + + This creates an argument expansion that will expand to -Wl,-force_load, + if the library should be linked as a whole archive. + + Args: + name: The name of the rule. + variable: The variable to expand. + """ + cc_nested_args( + name = name, + nested = [ + ":{}_force_load_library".format(name), + ":{}_no_force_load_library".format(name), + ], + ) + cc_nested_args( + name = name + "_no_force_load_library", + requires_false = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", + args = ["{library}"], + format = { + "library": variable, + }, + ) + cc_nested_args( + name = name + "_force_load_library", + requires_true = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", + args = ["-Wl,-force_load,{library}"], + format = { + "library": variable, + }, + ) + +def library_link_args(name, library_type, from_variable, iterate_over_variable = False): + """A helper for declaring a library to link. + + For most platforms, this expands something akin to the following: + + cc_nested_args( + name = "foo", + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = "interface_library", + iterate_over = None, + args = ["{library}"], + format = { + "library": //cc/toolchains/variables:libraries_to_link.name, + }, + ) + + For macos, this expands to a more complex cc_nested_args structure that + handles the -force_load flag. + + Args: + name: The name of the rule. + library_type: The type of the library. + from_variable: The variable to expand. + iterate_over_variable: Whether to iterate over the variable. + """ + native.alias( + name = name, + actual = select({ + "@platforms//os:macos": ":macos_{}".format(name), + "//conditions:default": ":generic_{}".format(name), + }), + ) + cc_nested_args( + name = "generic_{}".format(name), + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = library_type, + iterate_over = from_variable if iterate_over_variable else None, + args = ["{library}"], + format = { + "library": from_variable, + }, + ) + cc_nested_args( + name = "macos_{}".format(name), + requires_equal = "//cc/toolchains/variables:libraries_to_link.type", + requires_equal_value = library_type, + iterate_over = from_variable if iterate_over_variable else None, + nested = [":{}_maybe_force_load".format(name)], + ) + macos_force_load_library_args( + name = "{}_maybe_force_load".format(name), + variable = from_variable, + ) diff --git a/cc/toolchains/features/legacy/BUILD b/cc/toolchains/features/legacy/BUILD index cb6e918..af68df4 100644 --- a/cc/toolchains/features/legacy/BUILD +++ b/cc/toolchains/features/legacy/BUILD @@ -136,6 +136,7 @@ cc_external_feature( cc_external_feature( name = "libraries_to_link", + deprecation = "Use //cc/toolchains/args/libraries_to_link instead", feature_name = "libraries_to_link", overridable = True, ) diff --git a/tests/rule_based_toolchain/legacy_features_as_args/BUILD b/tests/rule_based_toolchain/legacy_features_as_args/BUILD index 65ef22a..1083f7a 100644 --- a/tests/rule_based_toolchain/legacy_features_as_args/BUILD +++ b/tests/rule_based_toolchain/legacy_features_as_args/BUILD @@ -27,6 +27,15 @@ compare_feature_implementation( }), ) +compare_feature_implementation( + name = "libraries_to_link_test", + actual_implementation = "//cc/toolchains/args/libraries_to_link", + expected = select({ + "@platforms//os:macos": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/macos/libraries_to_link.textproto", + "//conditions:default": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/unix/libraries_to_link.textproto", + }), +) + compare_feature_implementation( name = "linker_param_file_test", actual_implementation = "//cc/toolchains/args/linker_param_file", diff --git a/tests/rule_based_toolchain/legacy_features_as_args/goldens/macos/libraries_to_link.textproto b/tests/rule_based_toolchain/legacy_features_as_args/goldens/macos/libraries_to_link.textproto new file mode 100644 index 0000000..7144d7f --- /dev/null +++ b/tests/rule_based_toolchain/legacy_features_as_args/goldens/macos/libraries_to_link.textproto @@ -0,0 +1,123 @@ +enabled: false +flag_sets { + actions: "c++-link-dynamic-library" + actions: "c++-link-executable" + actions: "c++-link-nodeps-dynamic-library" + actions: "lto-index-for-dynamic-library" + actions: "lto-index-for-executable" + actions: "lto-index-for-nodeps-dynamic-library" + flag_groups { + flag_groups { + expand_if_available: "thinlto_param_file" + flags: "-Wl,@%{thinlto_param_file}" + } + flag_groups { + expand_if_available: "libraries_to_link" + flag_groups { + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file_group" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "-Wl,--start-lib" + } + } + flag_groups { + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file_group" + } + flag_groups { + flag_groups { + expand_if_true: "libraries_to_link.is_whole_archive" + flags: "-Wl,-force_load,%{libraries_to_link.object_files}" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "%{libraries_to_link.object_files}" + } + } + iterate_over: "libraries_to_link.object_files" + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file" + } + flag_groups { + flag_groups { + expand_if_true: "libraries_to_link.is_whole_archive" + flags: "-Wl,-force_load,%{libraries_to_link.name}" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "%{libraries_to_link.name}" + } + } + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "interface_library" + } + flag_groups { + flag_groups { + expand_if_true: "libraries_to_link.is_whole_archive" + flags: "-Wl,-force_load,%{libraries_to_link.name}" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "%{libraries_to_link.name}" + } + } + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "static_library" + } + flag_groups { + flag_groups { + expand_if_true: "libraries_to_link.is_whole_archive" + flags: "-Wl,-force_load,%{libraries_to_link.name}" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "%{libraries_to_link.name}" + } + } + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "dynamic_library" + } + flags: "-l%{libraries_to_link.name}" + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "versioned_dynamic_library" + } + flags: "%{libraries_to_link.path}" + } + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file_group" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "-Wl,--end-lib" + } + } + iterate_over: "libraries_to_link" + } + } + } +} +name: "libraries_to_link_test" diff --git a/tests/rule_based_toolchain/legacy_features_as_args/goldens/unix/libraries_to_link.textproto b/tests/rule_based_toolchain/legacy_features_as_args/goldens/unix/libraries_to_link.textproto new file mode 100644 index 0000000..80f0562 --- /dev/null +++ b/tests/rule_based_toolchain/legacy_features_as_args/goldens/unix/libraries_to_link.textproto @@ -0,0 +1,107 @@ +enabled: false +flag_sets { + actions: "c++-link-dynamic-library" + actions: "c++-link-executable" + actions: "c++-link-nodeps-dynamic-library" + actions: "lto-index-for-dynamic-library" + actions: "lto-index-for-executable" + actions: "lto-index-for-nodeps-dynamic-library" + flag_groups { + flag_groups { + expand_if_available: "thinlto_param_file" + flags: "-Wl,@%{thinlto_param_file}" + } + flag_groups { + expand_if_available: "libraries_to_link" + flag_groups { + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file_group" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "-Wl,--start-lib" + } + } + flag_groups { + flag_groups { + expand_if_true: "libraries_to_link.is_whole_archive" + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "static_library" + } + flags: "-Wl,-whole-archive" + } + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file_group" + } + flags: "%{libraries_to_link.object_files}" + iterate_over: "libraries_to_link.object_files" + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file" + } + flags: "%{libraries_to_link.name}" + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "interface_library" + } + flags: "%{libraries_to_link.name}" + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "static_library" + } + flags: "%{libraries_to_link.name}" + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "dynamic_library" + } + flags: "-l%{libraries_to_link.name}" + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "versioned_dynamic_library" + } + flags: "-l:%{libraries_to_link.name}" + } + flag_groups { + expand_if_true: "libraries_to_link.is_whole_archive" + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "static_library" + } + flags: "-Wl,-no-whole-archive" + } + } + } + flag_groups { + expand_if_equal { + name: "libraries_to_link.type" + value: "object_file_group" + } + flag_groups { + expand_if_false: "libraries_to_link.is_whole_archive" + flags: "-Wl,--end-lib" + } + } + iterate_over: "libraries_to_link" + } + } + } +} +name: "libraries_to_link_test"