diff --git a/cc/common/cc_helper_internal.bzl b/cc/common/cc_helper_internal.bzl index 735e050f2..33cdca6b2 100644 --- a/cc/common/cc_helper_internal.bzl +++ b/cc/common/cc_helper_internal.bzl @@ -40,6 +40,15 @@ def wrap_with_check_private_api(symbol): return callback +def create_solib_symlink(actions, library, symlink_path): + """Declares a shareable symlink to a dynamic library.""" + symlink = actions.declare_shareable_artifact(symlink_path) + actions.symlink( + output = symlink, + target_file = library, + ) + return symlink + CPP_SOURCE_TYPE_HEADER = "HEADER" CPP_SOURCE_TYPE_SOURCE = "SOURCE" CPP_SOURCE_TYPE_CLIF_INPUT_PROTO = "CLIF_INPUT_PROTO" diff --git a/cc/private/cc_common.bzl b/cc/private/cc_common.bzl index 8db674306..312c3f033 100644 --- a/cc/private/cc_common.bzl +++ b/cc/private/cc_common.bzl @@ -17,6 +17,7 @@ load( "//cc/common:cc_helper_internal.bzl", _CREATE_COMPILE_ACTION_API_ALLOWLISTED_PACKAGES = "CREATE_COMPILE_ACTION_API_ALLOWLISTED_PACKAGES", _PRIVATE_STARLARKIFICATION_ALLOWLIST = "PRIVATE_STARLARKIFICATION_ALLOWLIST", + _create_solib_symlink = "create_solib_symlink", ) load("//cc/private:cc_info.bzl", "CcNativeLibraryInfo", "create_compilation_context", "create_debug_context", "create_linking_context", "create_module_map", "merge_cc_infos", "merge_compilation_contexts", "merge_debug_context", "merge_linking_contexts") load("//cc/private:cc_internal.bzl", _cc_internal = "cc_internal") @@ -712,11 +713,11 @@ def _cc_toolchain_features(*, toolchain_config_info, tools_directory): def _solib_symlink_action(*, ctx, artifact, solib_directory, runtime_solib_dir_base): _cc_internal.check_private_api(allowlist = _PRIVATE_STARLARKIFICATION_ALLOWLIST) - return _cc_internal.solib_symlink_action( - ctx = ctx, - artifact = artifact, - solib_directory = solib_directory, - runtime_solib_dir_base = runtime_solib_dir_base, + symlink_directory = runtime_solib_dir_base if runtime_solib_dir_base != None else solib_directory + return _create_solib_symlink( + ctx.actions, + artifact, + symlink_directory + "/" + artifact.basename, ) def _cc_toolchain_variables(*, vars): diff --git a/cc/private/link/create_library_to_link.bzl b/cc/private/link/create_library_to_link.bzl index 79e356665..a59080ed1 100644 --- a/cc/private/link/create_library_to_link.bzl +++ b/cc/private/link/create_library_to_link.bzl @@ -16,7 +16,7 @@ The cc_common.create_library_to_link function. """ load("@bazel_skylib//lib:paths.bzl", "paths") -load("//cc/common:cc_helper_internal.bzl", "is_versioned_shared_library", "path_contains_up_level_references") +load("//cc/common:cc_helper_internal.bzl", "create_solib_symlink", "is_versioned_shared_library", "path_contains_up_level_references") load("//cc/private:cc_internal.bzl", _cc_internal = "cc_internal") load("//cc/private/compile:lto_compilation_context.bzl", _EMPTY_LTO = "EMPTY_LTO_COMPILATION_CONTEXT") load("//cc/private/link:lto_backends.bzl", "create_shared_non_lto_artifacts") @@ -211,7 +211,11 @@ def create_library_to_link( if dynamic_library_symlink_path: if dynamic_library.short_path.startswith("_solib_"): fail("dynamic_library must not be a symbolic link in the solib directory. Got '%s'" % dynamic_library.short_path) - dynamic_library = _cc_internal.dynamic_library_symlink2(actions, dynamic_library, cc_toolchain._solib_dir, dynamic_library_symlink_path) + dynamic_library = create_solib_symlink( + actions, + dynamic_library, + cc_toolchain._solib_dir + "/" + dynamic_library_symlink_path, + ) else: dynamic_library = _cc_internal.dynamic_library_symlink(actions, dynamic_library, cc_toolchain._solib_dir, True, True) @@ -226,7 +230,11 @@ def create_library_to_link( if interface_library_symlink_path: if interface_library.short_path.startswith("_solib_"): fail("dynamic_library must not be a symbolic link in the solib directory. Got '%s'" % dynamic_library.short_path) - interface_library = _cc_internal.dynamic_library_symlink2(actions, interface_library, cc_toolchain._solib_dir, interface_library_symlink_path) + interface_library = create_solib_symlink( + actions, + interface_library, + cc_toolchain._solib_dir + "/" + interface_library_symlink_path, + ) else: interface_library = _cc_internal.dynamic_library_symlink(actions, interface_library, cc_toolchain._solib_dir, True, True) diff --git a/tests/cc/common/cc_common_test.bzl b/tests/cc/common/cc_common_test.bzl index 678097a8c..0a8dfca03 100644 --- a/tests/cc/common/cc_common_test.bzl +++ b/tests/cc/common/cc_common_test.bzl @@ -5,6 +5,8 @@ load("@rules_testing//lib:analysis_test.bzl", "test_suite") load("@rules_testing//lib:truth.bzl", "matching") load("@rules_testing//lib:util.bzl", "TestingAspectInfo", "util") load("//cc:cc_library.bzl", "cc_library") +load("//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_ATTRS", "find_cpp_toolchain", "use_cc_toolchain") +load("//cc/common:cc_common.bzl", "cc_common") load("//cc/common:cc_info.bzl", "CcInfo") load("//tests/cc/testutil:cc_analysis_test.bzl", "cc_analysis_test") load("//tests/cc/testutil:cc_info_subject.bzl", "cc_info_subject") @@ -482,6 +484,68 @@ def _test_alwayslink_yields_lo_impl(env, target): files = [f.basename for f in target[DefaultInfo].files.to_list()] env.expect.that_collection(files).contains("libalways_link.lo") +def _solib_symlinks_impl(ctx): + cc_toolchain = find_cpp_toolchain(ctx) + feature_configuration = cc_common.configure_features( + ctx = ctx, + cc_toolchain = cc_toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + library = ctx.actions.declare_file("liboriginal.so") + ctx.actions.write(library, "") + library_to_link = cc_common.create_library_to_link( + actions = ctx.actions, + cc_toolchain = cc_toolchain, + dynamic_library = library, + dynamic_library_symlink_path = "custom/libalias.so", + feature_configuration = feature_configuration, + ) + runtime_symlink = cc_common.solib_symlink_action( + ctx = ctx, + artifact = library, + solib_directory = "unused_solib_directory", + runtime_solib_dir_base = "runtime_solib", + ) + return [DefaultInfo(files = depset([library_to_link.dynamic_library, runtime_symlink]))] + +_solib_symlinks = rule( + implementation = _solib_symlinks_impl, + attrs = CC_TOOLCHAIN_ATTRS, + fragments = ["cpp"], + toolchains = use_cc_toolchain(), +) + +def _test_solib_symlinks(name): + util.helper_target( + _solib_symlinks, + name = name + "/target", + ) + cc_analysis_test( + name = name, + impl = _test_solib_symlinks_impl, + target = name + "/target", + ) + +def _test_solib_symlinks_impl(env, target): + symlink_outputs = target[DefaultInfo].files.to_list() + explicit = [output for output in symlink_outputs if output.basename == "libalias.so"][0] + runtime = [output for output in symlink_outputs if output.basename == "liboriginal.so"][0] + + explicit_path = env.expect.that_str(explicit.short_path) + explicit_path.contains("_solib_") + explicit_path.ends_with("/custom/libalias.so") + env.expect.that_str(runtime.short_path).ends_with("runtime_solib/liboriginal.so") + + symlinks = [action for action in target[TestingAspectInfo].actions if action.mnemonic == "Symlink"] + env.expect.that_collection(symlinks).has_size(2) + env.expect.that_collection([output for action in symlinks for output in action.outputs.to_list()]).contains_exactly([ + explicit, + runtime, + ]) + for action in symlinks: + env.expect.that_collection([input.basename for input in action.inputs.to_list()]).contains_exactly(["liboriginal.so"]) + def cc_common_tests(name): tests = [ _test_same_cc_file_twice, @@ -505,6 +569,7 @@ def cc_common_tests(name): _test_strip_include_prefix_no_virtual_includes_when_enabled, _test_strip_include_prefix_with_include_prefix_uses_virtual_includes, _test_strip_include_prefix_error_not_under_prefix, + _test_solib_symlinks, ]) test_suite( name = name,