From cff836322598dd980f6b4be2b3983654f0642ac8 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 18 Sep 2026 18:11:20 +0200 Subject: [PATCH 1/6] feat: add dSYM outputs to C++-linked Zig targets --- zig/private/common/zig_build.bzl | 29 +++- zig/private/providers/zig_module_info.bzl | 16 ++- zig/private/providers/zig_settings_info.bzl | 5 +- zig/tests/BUILD.bazel | 3 + zig/tests/dsym_test.bzl | 138 ++++++++++++++++++++ zig/tests/strip_debug_symbols/BUILD.bazel | 7 + 6 files changed, 187 insertions(+), 11 deletions(-) create mode 100644 zig/tests/dsym_test.bzl diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index 0b618779..0adb8c29 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -277,6 +277,16 @@ def zig_build_impl(ctx, *, kind): use_cc_common_link = settings.use_cc_common_link use_test_obj = kind == "zig_test" and use_cc_common_link and semver.gte(zigtoolchaininfo.zig_version, "0.16.0") + cc_toolchain = None + feature_configuration = None + generate_dsym_file = False + if use_cc_common_link and kind != "zig_static_library": + cc_toolchain, feature_configuration = find_cc_toolchain(ctx, mandatory = True) + generate_dsym_file = cc_common.is_enabled( + feature_configuration = feature_configuration, + feature_name = "generate_dsym_file", + ) + providers = [] exported_library_to_link = None direct_data = [] @@ -317,7 +327,7 @@ def zig_build_impl(ctx, *, kind): elif ctx.attr.compiler_runtime == "exclude": args.add("-fno-compiler-rt") - if ctx.attr.strip_debug_symbols and not settings.strip: + if ctx.attr.strip_debug_symbols and not settings.strip and not generate_dsym_file: args.add("-fstrip") zig_lib_dir( @@ -361,6 +371,15 @@ def zig_build_impl(ctx, *, kind): bin_output = ctx.actions.declare_file(bin_output_name) solib_parents = [""] + cc_link_kwargs = {} + if generate_dsym_file: + dsym_file = ctx.actions.declare_directory(ctx.label.name + ".dSYM", sibling = bin_output) + cc_link_kwargs = { + "additional_outputs": [dsym_file], + "variables_extension": {"dsym_path": dsym_file.path}, + } + output_groups["dsyms"] = depset([dsym_file]) + if kind == "zig_test" and ctx.attr.test_runner: args.add("--test-runner", ctx.file.test_runner) direct_inputs.append(ctx.file.test_runner) @@ -437,6 +456,7 @@ def zig_build_impl(ctx, *, kind): zig_settings( settings = settings, args = global_args, + strip = not generate_dsym_file, ) zig_target_platform( @@ -483,6 +503,7 @@ def zig_build_impl(ctx, *, kind): root_module = root_module, args = args, c_module = c_module, + strip = not generate_dsym_file, ) transitive_inputs.append(root_module.transitive_inputs) @@ -547,7 +568,6 @@ def zig_build_impl(ctx, *, kind): **zig_build_kwargs ) - cc_toolchain, feature_configuration = find_cc_toolchain(ctx, mandatory = True) library_to_link = cc_common.create_library_to_link( actions = ctx.actions, feature_configuration = feature_configuration, @@ -571,6 +591,7 @@ def zig_build_impl(ctx, *, kind): main_output = bin_output, linking_contexts = [linking_context, root_module.cc_info.linking_context], user_link_flags = linkopts, + **cc_link_kwargs ) else: args.add(bin_output, format = "-femit-bin=%s") @@ -638,7 +659,6 @@ def zig_build_impl(ctx, *, kind): **zig_build_kwargs ) - cc_toolchain, feature_configuration = find_cc_toolchain(ctx, mandatory = True) library_to_link = cc_common.create_library_to_link( actions = ctx.actions, feature_configuration = feature_configuration, @@ -662,6 +682,7 @@ def zig_build_impl(ctx, *, kind): main_output = bin_output, linking_contexts = [linking_context, root_module.cc_info.linking_context], user_link_flags = linkopts, + **cc_link_kwargs ) else: args.add(bin_output, format = "-femit-bin=%s") @@ -713,7 +734,6 @@ def zig_build_impl(ctx, *, kind): **zig_build_kwargs ) - cc_toolchain, feature_configuration = find_cc_toolchain(ctx, mandatory = True) library_to_link = cc_common.create_library_to_link( actions = ctx.actions, feature_configuration = feature_configuration, @@ -738,6 +758,7 @@ def zig_build_impl(ctx, *, kind): main_output = bin_output, linking_contexts = [linking_context, root_module.cc_info.linking_context], user_link_flags = linkopts, + **cc_link_kwargs ) exported_library_to_link = link_outputs.library_to_link diff --git a/zig/private/providers/zig_module_info.bzl b/zig/private/providers/zig_module_info.bzl index db9510a5..001ec074 100644 --- a/zig/private/providers/zig_module_info.bzl +++ b/zig/private/providers/zig_module_info.bzl @@ -95,19 +95,25 @@ def _render_per_module_args(module): return args -def zig_module_specifications(*, root_module, args, c_module = None): +def _render_per_module_args_without_strip(module): + return [arg for arg in _render_per_module_args(module) if arg != "-fstrip"] + +def zig_module_specifications(*, root_module, args, c_module = None, strip = True): """Collect inputs and flags to build Zig modules. Args: root_module: ZigModuleInfo; The root module for which to render args. args: Args; mutable, Append the needed Zig compiler flags to this object. c_module: ZigModuleInfo or None; If not None, the global C translation module to depend on. + strip: bool; Whether to append strip flags from module options. """ + render_per_module_args = _render_per_module_args if strip else _render_per_module_args_without_strip + # The first module is the main module. - args.add_all([root_module.module_context], map_each = _render_per_module_args) - args.add_all(root_module.transitive_module_contexts, map_each = _render_per_module_args) + args.add_all([root_module.module_context], map_each = render_per_module_args) + args.add_all(root_module.transitive_module_contexts, map_each = render_per_module_args) if c_module: - args.add_all([c_module.module_context], map_each = _render_per_module_args) - args.add_all(c_module.transitive_module_contexts, map_each = _render_per_module_args) + args.add_all([c_module.module_context], map_each = render_per_module_args) + args.add_all(c_module.transitive_module_contexts, map_each = render_per_module_args) diff --git a/zig/private/providers/zig_settings_info.bzl b/zig/private/providers/zig_settings_info.bzl index aed0fb03..d51aad99 100644 --- a/zig/private/providers/zig_settings_info.bzl +++ b/zig/private/providers/zig_settings_info.bzl @@ -17,11 +17,12 @@ ZigSettingsInfo = provider( fields = FIELDS, ) -def zig_settings(*, settings, args): +def zig_settings(*, settings, args, strip = True): """Set flags for the given Zig build settings. Args: settings: ZigSettingsInfo, The active Zig build settings. args: Args; mutable, Append the needed Zig compiler flags to this object. + strip: bool; Whether to append the configured strip flag. """ - args.add_all(settings.args) + args.add_all(settings.args if strip else [arg for arg in settings.args if arg != "-fstrip"]) diff --git a/zig/tests/BUILD.bazel b/zig/tests/BUILD.bazel index 48078ccc..b0a5b430 100644 --- a/zig/tests/BUILD.bazel +++ b/zig/tests/BUILD.bazel @@ -2,6 +2,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load(":bzlmod_zig_test.bzl", "bzlmod_zig_test_suite") load(":cache_test.bzl", "cache_test_suite") load(":config_test.bzl", "config_test_suite") +load(":dsym_test.bzl", "dsym_test_suite") load(":emit_attr_test.bzl", "emit_attr_test_suite") load(":mode_test.bzl", "mode_test_suite") load(":module_info_test.bzl", "module_info_test_suite") @@ -26,6 +27,8 @@ cache_test_suite(name = "cache_test") config_test_suite(name = "config_test") +dsym_test_suite(name = "dsym_test") + emit_attr_test_suite(name = "emit_attr_test") use_cc_common_link_test_suite(name = "use_cc_common_link_test") diff --git a/zig/tests/dsym_test.bzl b/zig/tests/dsym_test.bzl new file mode 100644 index 00000000..0c686bbf --- /dev/null +++ b/zig/tests/dsym_test.bzl @@ -0,0 +1,138 @@ +"""Analysis tests for dSYM outputs from cc_common.link.""" + +load("@bazel_features//:features.bzl", "bazel_features") +load("@bazel_skylib//lib:partial.bzl", "partial") +load("@bazel_skylib//lib:sets.bzl", "sets") +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest") +load( + ":util.bzl", + "assert_find_action", + "assert_flag_set", + "assert_flag_unset", + "canonical_label", +) + +_APPLE_GENERATE_DSYM = "//command_line_option:apple_generate_dsym" +_EXTRA_TOOLCHAINS = "//command_line_option:extra_toolchains" +_STRIP = "//command_line_option:strip" +_TARGET_PLATFORM = "//command_line_option:platforms" +_SETTINGS_USE_CC_COMMON_LINK = canonical_label("@//zig/settings:use_cc_common_link") + +_PLATFORM_ZIG_ONLY_X86_64_LINUX = canonical_label("@//zig/tests/platforms:zig-only-x86_64-linux") +_TOOLCHAIN_UNCONSTRAINED_DEFAULT_TEST = canonical_label("@//zig/tests/platforms:unconstrained_default_test_toolchain") +_TOOLCHAIN_ZIG_ONLY_X86_64_LINUX = canonical_label("@//zig/tests/platforms:zig-only-x86_64-linux_toolchain") + +def _dsyms_enabled_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + output_groups = target[OutputGroupInfo] + + asserts.true(env, hasattr(output_groups, "dsyms"), "dSYMs should be exposed when the C++ toolchain enables generate_dsym_file.") + dsyms = output_groups.dsyms.to_list() if hasattr(output_groups, "dsyms") else [] + asserts.equals(env, 1, len(dsyms), "Exactly one dSYM should be exposed.") + if dsyms: + dsym = dsyms[0] + asserts.true(env, dsym.is_directory, "The dSYM should be a directory artifact.") + asserts.equals(env, target.label.name + ".dSYM", dsym.basename) + + link = assert_find_action(env, "CppLink") + asserts.true(env, sets.contains(sets.make(link.outputs.to_list()), dsym), "The CppLink action should produce the dSYM.") + + link_variables = link.argv + getattr(link, "env", {}).values() + asserts.true( + env, + any([dsym.path in value for value in link_variables]), + "The CppLink command line or environment should contain the dSYM path.", + ) + + for action in analysistest.target_actions(env): + if action.mnemonic in ["ZigBuildLib", "ZigBuildTest"]: + assert_flag_unset(env, "-fstrip", action.argv) + + return analysistest.end(env) + +_dsyms_enabled_test = analysistest.make( + _dsyms_enabled_test_impl, + config_settings = { + _APPLE_GENERATE_DSYM: True, + _SETTINGS_USE_CC_COMMON_LINK: True, + _STRIP: "always", + }, +) + +_dsyms_enabled_without_bazel_strip_test = analysistest.make( + _dsyms_enabled_test_impl, + config_settings = { + _APPLE_GENERATE_DSYM: True, + _SETTINGS_USE_CC_COMMON_LINK: True, + _STRIP: "never", + }, +) + +def _dsyms_disabled_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + output_groups = target[OutputGroupInfo] + + asserts.false(env, hasattr(output_groups, "dsyms"), "dSYMs should not be exposed when generate_dsym_file is disabled.") + assert_find_action(env, "CppLink") + assert_flag_set(env, "-fstrip", assert_find_action(env, "ZigBuildLib").argv) + + return analysistest.end(env) + +_dsyms_disabled_test = analysistest.make( + _dsyms_disabled_test_impl, + config_settings = { + _APPLE_GENERATE_DSYM: False, + _SETTINGS_USE_CC_COMMON_LINK: True, + _STRIP: "always", + }, +) + +def _dsyms_without_cc_toolchain_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + output_groups = target[OutputGroupInfo] + + asserts.false(env, hasattr(output_groups, "dsyms"), "A Zig-only target should not expose a dSYM that no action can create.") + assert_find_action(env, "ZigBuildExe") + asserts.false( + env, + any([action.mnemonic == "CppLink" for action in analysistest.target_actions(env)]), + "A Zig-only target should not create a CppLink action.", + ) + + return analysistest.end(env) + +def _zig_only_config(generate_dsym): + return { + _APPLE_GENERATE_DSYM: generate_dsym, + _EXTRA_TOOLCHAINS: ",".join([ + _TOOLCHAIN_ZIG_ONLY_X86_64_LINUX, + ] + ([_TOOLCHAIN_UNCONSTRAINED_DEFAULT_TEST] if bazel_features.toolchains.has_default_test_toolchain_type else [])), + _SETTINGS_USE_CC_COMMON_LINK: False, + _TARGET_PLATFORM: _PLATFORM_ZIG_ONLY_X86_64_LINUX, + } + +_dsyms_without_cc_toolchain_requested_test = analysistest.make( + _dsyms_without_cc_toolchain_test_impl, + config_settings = _zig_only_config(True), +) + +_dsyms_without_cc_toolchain_unrequested_test = analysistest.make( + _dsyms_without_cc_toolchain_test_impl, + config_settings = _zig_only_config(False), +) + +def dsym_test_suite(name): + unittest.suite( + name, + partial.make(_dsyms_enabled_test, name = "dsym_binary_enabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), + partial.make(_dsyms_enabled_test, name = "dsym_shared_library_enabled_test", target_under_test = "//zig/tests/simple-shared-library:shared", size = "small"), + partial.make(_dsyms_enabled_test, name = "dsym_test_enabled_test", target_under_test = "//zig/tests/simple-test:test", size = "small"), + partial.make(_dsyms_enabled_without_bazel_strip_test, name = "dsym_strip_attr_test", target_under_test = "//zig/tests/strip_debug_symbols:binary-strip", size = "small"), + partial.make(_dsyms_enabled_without_bazel_strip_test, name = "dsym_zigopt_strip_test", target_under_test = "//zig/tests/strip_debug_symbols:binary-zigopt-strip", size = "small"), + partial.make(_dsyms_disabled_test, name = "dsym_binary_disabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), + partial.make(_dsyms_without_cc_toolchain_requested_test, name = "dsym_zig_only_requested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), + partial.make(_dsyms_without_cc_toolchain_unrequested_test, name = "dsym_zig_only_unrequested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), + ) diff --git a/zig/tests/strip_debug_symbols/BUILD.bazel b/zig/tests/strip_debug_symbols/BUILD.bazel index 36cfed0e..dddf66e9 100644 --- a/zig/tests/strip_debug_symbols/BUILD.bazel +++ b/zig/tests/strip_debug_symbols/BUILD.bazel @@ -18,6 +18,13 @@ zig_binary( visibility = ["//zig/tests:__pkg__"], ) +zig_binary( + name = "binary-zigopt-strip", + main = "main.zig", + visibility = ["//zig/tests:__pkg__"], + zigopts = ["-fstrip"], +) + zig_shared_library( name = "library-shared-strip", main = "main.zig", From efb30d68b5eb7e0b1e9381e798ffe9a0fafcfd11 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 18 Sep 2026 18:24:35 +0200 Subject: [PATCH 2/6] refactor: localize dSYM strip handling --- zig/private/common/zig_build.bzl | 25 +++++++++++++++------ zig/private/providers/zig_module_info.bzl | 16 +++++-------- zig/private/providers/zig_settings_info.bzl | 5 ++--- zig/tests/dsym_test.bzl | 11 --------- zig/tests/strip_debug_symbols/BUILD.bazel | 7 ------ 5 files changed, 25 insertions(+), 39 deletions(-) diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index 0adb8c29..11efed13 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -246,6 +246,16 @@ def _executable_extension(os): def _object_extension(os): return ".obj" if os == "windows" else ".o" +def _without_bazel_strip(settings): + args = [] + strip_removed = False + for arg in settings.args: + if settings.strip and not strip_removed and arg == "-fstrip": + strip_removed = True + else: + args.append(arg) + return args + def zig_build_impl(ctx, *, kind): """Common implementation for Zig build rules. @@ -327,7 +337,7 @@ def zig_build_impl(ctx, *, kind): elif ctx.attr.compiler_runtime == "exclude": args.add("-fno-compiler-rt") - if ctx.attr.strip_debug_symbols and not settings.strip and not generate_dsym_file: + if ctx.attr.strip_debug_symbols and not settings.strip: args.add("-fstrip") zig_lib_dir( @@ -453,11 +463,13 @@ def zig_build_impl(ctx, *, kind): import_names = import_names, ) - zig_settings( - settings = settings, - args = global_args, - strip = not generate_dsym_file, - ) + if generate_dsym_file: + global_args.add_all(_without_bazel_strip(settings)) + else: + zig_settings( + settings = settings, + args = global_args, + ) zig_target_platform( target = zigtargetinfo, @@ -503,7 +515,6 @@ def zig_build_impl(ctx, *, kind): root_module = root_module, args = args, c_module = c_module, - strip = not generate_dsym_file, ) transitive_inputs.append(root_module.transitive_inputs) diff --git a/zig/private/providers/zig_module_info.bzl b/zig/private/providers/zig_module_info.bzl index 001ec074..db9510a5 100644 --- a/zig/private/providers/zig_module_info.bzl +++ b/zig/private/providers/zig_module_info.bzl @@ -95,25 +95,19 @@ def _render_per_module_args(module): return args -def _render_per_module_args_without_strip(module): - return [arg for arg in _render_per_module_args(module) if arg != "-fstrip"] - -def zig_module_specifications(*, root_module, args, c_module = None, strip = True): +def zig_module_specifications(*, root_module, args, c_module = None): """Collect inputs and flags to build Zig modules. Args: root_module: ZigModuleInfo; The root module for which to render args. args: Args; mutable, Append the needed Zig compiler flags to this object. c_module: ZigModuleInfo or None; If not None, the global C translation module to depend on. - strip: bool; Whether to append strip flags from module options. """ - render_per_module_args = _render_per_module_args if strip else _render_per_module_args_without_strip - # The first module is the main module. - args.add_all([root_module.module_context], map_each = render_per_module_args) - args.add_all(root_module.transitive_module_contexts, map_each = render_per_module_args) + args.add_all([root_module.module_context], map_each = _render_per_module_args) + args.add_all(root_module.transitive_module_contexts, map_each = _render_per_module_args) if c_module: - args.add_all([c_module.module_context], map_each = render_per_module_args) - args.add_all(c_module.transitive_module_contexts, map_each = render_per_module_args) + args.add_all([c_module.module_context], map_each = _render_per_module_args) + args.add_all(c_module.transitive_module_contexts, map_each = _render_per_module_args) diff --git a/zig/private/providers/zig_settings_info.bzl b/zig/private/providers/zig_settings_info.bzl index d51aad99..aed0fb03 100644 --- a/zig/private/providers/zig_settings_info.bzl +++ b/zig/private/providers/zig_settings_info.bzl @@ -17,12 +17,11 @@ ZigSettingsInfo = provider( fields = FIELDS, ) -def zig_settings(*, settings, args, strip = True): +def zig_settings(*, settings, args): """Set flags for the given Zig build settings. Args: settings: ZigSettingsInfo, The active Zig build settings. args: Args; mutable, Append the needed Zig compiler flags to this object. - strip: bool; Whether to append the configured strip flag. """ - args.add_all(settings.args if strip else [arg for arg in settings.args if arg != "-fstrip"]) + args.add_all(settings.args) diff --git a/zig/tests/dsym_test.bzl b/zig/tests/dsym_test.bzl index 0c686bbf..ac7c3783 100644 --- a/zig/tests/dsym_test.bzl +++ b/zig/tests/dsym_test.bzl @@ -60,15 +60,6 @@ _dsyms_enabled_test = analysistest.make( }, ) -_dsyms_enabled_without_bazel_strip_test = analysistest.make( - _dsyms_enabled_test_impl, - config_settings = { - _APPLE_GENERATE_DSYM: True, - _SETTINGS_USE_CC_COMMON_LINK: True, - _STRIP: "never", - }, -) - def _dsyms_disabled_test_impl(ctx): env = analysistest.begin(ctx) target = analysistest.target_under_test(env) @@ -130,8 +121,6 @@ def dsym_test_suite(name): partial.make(_dsyms_enabled_test, name = "dsym_binary_enabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_enabled_test, name = "dsym_shared_library_enabled_test", target_under_test = "//zig/tests/simple-shared-library:shared", size = "small"), partial.make(_dsyms_enabled_test, name = "dsym_test_enabled_test", target_under_test = "//zig/tests/simple-test:test", size = "small"), - partial.make(_dsyms_enabled_without_bazel_strip_test, name = "dsym_strip_attr_test", target_under_test = "//zig/tests/strip_debug_symbols:binary-strip", size = "small"), - partial.make(_dsyms_enabled_without_bazel_strip_test, name = "dsym_zigopt_strip_test", target_under_test = "//zig/tests/strip_debug_symbols:binary-zigopt-strip", size = "small"), partial.make(_dsyms_disabled_test, name = "dsym_binary_disabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_without_cc_toolchain_requested_test, name = "dsym_zig_only_requested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_without_cc_toolchain_unrequested_test, name = "dsym_zig_only_unrequested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), diff --git a/zig/tests/strip_debug_symbols/BUILD.bazel b/zig/tests/strip_debug_symbols/BUILD.bazel index dddf66e9..36cfed0e 100644 --- a/zig/tests/strip_debug_symbols/BUILD.bazel +++ b/zig/tests/strip_debug_symbols/BUILD.bazel @@ -18,13 +18,6 @@ zig_binary( visibility = ["//zig/tests:__pkg__"], ) -zig_binary( - name = "binary-zigopt-strip", - main = "main.zig", - visibility = ["//zig/tests:__pkg__"], - zigopts = ["-fstrip"], -) - zig_shared_library( name = "library-shared-strip", main = "main.zig", From 475e0e8290a3317cd64123fc60d31e455a452922 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 18 Sep 2026 19:21:03 +0200 Subject: [PATCH 3/6] refactor: keep strip filtering in Zig settings --- zig/private/common/zig_build.bzl | 22 +++++---------------- zig/private/providers/zig_settings_info.bzl | 16 +++++++++++++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index 11efed13..e5625aa6 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -246,16 +246,6 @@ def _executable_extension(os): def _object_extension(os): return ".obj" if os == "windows" else ".o" -def _without_bazel_strip(settings): - args = [] - strip_removed = False - for arg in settings.args: - if settings.strip and not strip_removed and arg == "-fstrip": - strip_removed = True - else: - args.append(arg) - return args - def zig_build_impl(ctx, *, kind): """Common implementation for Zig build rules. @@ -463,13 +453,11 @@ def zig_build_impl(ctx, *, kind): import_names = import_names, ) - if generate_dsym_file: - global_args.add_all(_without_bazel_strip(settings)) - else: - zig_settings( - settings = settings, - args = global_args, - ) + zig_settings( + settings = settings, + args = global_args, + strip = not generate_dsym_file, + ) zig_target_platform( target = zigtargetinfo, diff --git a/zig/private/providers/zig_settings_info.bzl b/zig/private/providers/zig_settings_info.bzl index aed0fb03..0f6039d8 100644 --- a/zig/private/providers/zig_settings_info.bzl +++ b/zig/private/providers/zig_settings_info.bzl @@ -17,11 +17,23 @@ ZigSettingsInfo = provider( fields = FIELDS, ) -def zig_settings(*, settings, args): +def zig_settings(*, settings, args, strip = True): """Set flags for the given Zig build settings. Args: settings: ZigSettingsInfo, The active Zig build settings. args: Args; mutable, Append the needed Zig compiler flags to this object. + strip: bool; Whether to append the Bazel-derived strip flag. Explicit zigopts are preserved. """ - args.add_all(settings.args) + if strip or not settings.strip: + args.add_all(settings.args) + return + + settings_args = [] + strip_removed = False + for arg in settings.args: + if not strip_removed and arg == "-fstrip": + strip_removed = True + else: + settings_args.append(arg) + args.add_all(settings_args) From 07878c70677e3b449c9d463242d17d63b2a681e2 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 18 Sep 2026 19:35:49 +0200 Subject: [PATCH 4/6] test: gate dSYM analysis tests to macOS --- zig/tests/dsym_test.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zig/tests/dsym_test.bzl b/zig/tests/dsym_test.bzl index ac7c3783..35b3182c 100644 --- a/zig/tests/dsym_test.bzl +++ b/zig/tests/dsym_test.bzl @@ -118,9 +118,9 @@ _dsyms_without_cc_toolchain_unrequested_test = analysistest.make( def dsym_test_suite(name): unittest.suite( name, - partial.make(_dsyms_enabled_test, name = "dsym_binary_enabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), - partial.make(_dsyms_enabled_test, name = "dsym_shared_library_enabled_test", target_under_test = "//zig/tests/simple-shared-library:shared", size = "small"), - partial.make(_dsyms_enabled_test, name = "dsym_test_enabled_test", target_under_test = "//zig/tests/simple-test:test", size = "small"), + partial.make(_dsyms_enabled_test, name = "dsym_binary_enabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small", target_compatible_with = ["@platforms//os:macos"]), + partial.make(_dsyms_enabled_test, name = "dsym_shared_library_enabled_test", target_under_test = "//zig/tests/simple-shared-library:shared", size = "small", target_compatible_with = ["@platforms//os:macos"]), + partial.make(_dsyms_enabled_test, name = "dsym_test_enabled_test", target_under_test = "//zig/tests/simple-test:test", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_disabled_test, name = "dsym_binary_disabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_without_cc_toolchain_requested_test, name = "dsym_zig_only_requested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_without_cc_toolchain_unrequested_test, name = "dsym_zig_only_unrequested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), From 54c20006b151b37ff9ac95bacd63ccff85d80760 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 18 Sep 2026 20:12:53 +0200 Subject: [PATCH 5/6] refactor: model strip as a structured setting --- zig/private/common/zig_build.bzl | 7 +++-- zig/private/providers/zig_settings_info.bzl | 19 ++++-------- zig/private/settings.bzl | 3 -- zig/tests/dsym_test.bzl | 32 +++++++++++++++++++++ zig/tests/rules_test.bzl | 5 +--- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index e5625aa6..48b02144 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -327,8 +327,11 @@ def zig_build_impl(ctx, *, kind): elif ctx.attr.compiler_runtime == "exclude": args.add("-fno-compiler-rt") - if ctx.attr.strip_debug_symbols and not settings.strip: - args.add("-fstrip") + if ctx.attr.strip_debug_symbols: + if generate_dsym_file: + fail("'strip_debug_symbols' cannot be enabled when generating a dSYM; use Bazel's '--strip' option to strip the linked binary after dSYM generation") + if not settings.strip: + args.add("-fstrip") zig_lib_dir( zigtoolchaininfo = zigtoolchaininfo, diff --git a/zig/private/providers/zig_settings_info.bzl b/zig/private/providers/zig_settings_info.bzl index 0f6039d8..6d80fe73 100644 --- a/zig/private/providers/zig_settings_info.bzl +++ b/zig/private/providers/zig_settings_info.bzl @@ -9,7 +9,7 @@ FIELDS = { "use_cc_common_link": "Whether to use cc_common.link to link zig binaries, tests and shared libraries.", "threaded": "The Zig multi- or single-threaded setting.", "strip": "Whether Zig compile actions should remove debug symbols.", - "args": "The collected compiler arguments for all active settings.", + "args": "The collected compiler arguments excluding the Bazel-derived strip flag.", } ZigSettingsInfo = provider( @@ -23,17 +23,8 @@ def zig_settings(*, settings, args, strip = True): Args: settings: ZigSettingsInfo, The active Zig build settings. args: Args; mutable, Append the needed Zig compiler flags to this object. - strip: bool; Whether to append the Bazel-derived strip flag. Explicit zigopts are preserved. + strip: bool; Whether to append the Bazel-derived strip flag. """ - if strip or not settings.strip: - args.add_all(settings.args) - return - - settings_args = [] - strip_removed = False - for arg in settings.args: - if not strip_removed and arg == "-fstrip": - strip_removed = True - else: - settings_args.append(arg) - args.add_all(settings_args) + if strip and settings.strip: + args.add("-fstrip") + args.add_all(settings.args) diff --git a/zig/private/settings.bzl b/zig/private/settings.bzl index 00bd3b42..2a7a6a63 100644 --- a/zig/private/settings.bzl +++ b/zig/private/settings.bzl @@ -137,9 +137,6 @@ def _settings_impl(ctx): use_cc_common_link = ctx.attr.host_use_cc_common_link[BuildSettingInfo].value if is_exec_configuration else ctx.attr.use_cc_common_link[BuildSettingInfo].value strip = _resolve_strip(ctx, ctx.attr._bazel_strip[BazelStripInfo].strip) - if strip: - args.append("-fstrip") - args.extend(ctx.attr.host_zigopt[BuildSettingInfo].value if is_exec_configuration else ctx.attr.zigopt[BuildSettingInfo].value) settings_info = ZigSettingsInfo( diff --git a/zig/tests/dsym_test.bzl b/zig/tests/dsym_test.bzl index 35b3182c..ad56aec2 100644 --- a/zig/tests/dsym_test.bzl +++ b/zig/tests/dsym_test.bzl @@ -17,6 +17,7 @@ _EXTRA_TOOLCHAINS = "//command_line_option:extra_toolchains" _STRIP = "//command_line_option:strip" _TARGET_PLATFORM = "//command_line_option:platforms" _SETTINGS_USE_CC_COMMON_LINK = canonical_label("@//zig/settings:use_cc_common_link") +_SETTINGS_ZIGOPT = canonical_label("@//zig/settings:zigopt") _PLATFORM_ZIG_ONLY_X86_64_LINUX = canonical_label("@//zig/tests/platforms:zig-only-x86_64-linux") _TOOLCHAIN_UNCONSTRAINED_DEFAULT_TEST = canonical_label("@//zig/tests/platforms:unconstrained_default_test_toolchain") @@ -60,6 +61,35 @@ _dsyms_enabled_test = analysistest.make( }, ) +def _dsyms_explicit_fstrip_test_impl(ctx): + env = analysistest.begin(ctx) + assert_flag_set(env, "-fstrip", assert_find_action(env, "ZigBuildLib").argv) + return analysistest.end(env) + +_dsyms_explicit_fstrip_test = analysistest.make( + _dsyms_explicit_fstrip_test_impl, + config_settings = { + _APPLE_GENERATE_DSYM: True, + _SETTINGS_USE_CC_COMMON_LINK: True, + _SETTINGS_ZIGOPT: ["-fstrip"], + _STRIP: "always", + }, +) + +def _dsyms_strip_debug_symbols_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "'strip_debug_symbols' cannot be enabled when generating a dSYM") + return analysistest.end(env) + +_dsyms_strip_debug_symbols_test = analysistest.make( + _dsyms_strip_debug_symbols_test_impl, + config_settings = { + _APPLE_GENERATE_DSYM: True, + _SETTINGS_USE_CC_COMMON_LINK: True, + }, + expect_failure = True, +) + def _dsyms_disabled_test_impl(ctx): env = analysistest.begin(ctx) target = analysistest.target_under_test(env) @@ -121,6 +151,8 @@ def dsym_test_suite(name): partial.make(_dsyms_enabled_test, name = "dsym_binary_enabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_enabled_test, name = "dsym_shared_library_enabled_test", target_under_test = "//zig/tests/simple-shared-library:shared", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_enabled_test, name = "dsym_test_enabled_test", target_under_test = "//zig/tests/simple-test:test", size = "small", target_compatible_with = ["@platforms//os:macos"]), + partial.make(_dsyms_explicit_fstrip_test, name = "dsym_explicit_fstrip_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small", target_compatible_with = ["@platforms//os:macos"]), + partial.make(_dsyms_strip_debug_symbols_test, name = "dsym_strip_debug_symbols_test", target_under_test = "//zig/tests/strip_debug_symbols:binary-strip", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_disabled_test, name = "dsym_binary_disabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_without_cc_toolchain_requested_test, name = "dsym_zig_only_requested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_without_cc_toolchain_unrequested_test, name = "dsym_zig_only_unrequested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), diff --git a/zig/tests/rules_test.bzl b/zig/tests/rules_test.bzl index 4dfd5d8c..11e0283e 100644 --- a/zig/tests/rules_test.bzl +++ b/zig/tests/rules_test.bzl @@ -467,10 +467,7 @@ def _define_bazel_strip_settings_test(*, strip, compilation_mode, expected_strip settings = analysistest.target_under_test(env)[ZigSettingsInfo] asserts.equals(env, expected_strip, settings.strip) - if expected_strip: - assert_flag_set(env, "-fstrip", settings.args) - else: - assert_flag_unset(env, "-fstrip", settings.args) + assert_flag_unset(env, "-fstrip", settings.args) return analysistest.end(env) From 86eebc5b9e7f2c823fd7a2b49f475c91b1d2b15d Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 18 Sep 2026 20:28:56 +0200 Subject: [PATCH 6/6] refactor: leave dSYM strip coordination to users --- zig/private/common/zig_build.bzl | 3 +-- zig/private/providers/zig_settings_info.bzl | 7 ++----- zig/private/settings.bzl | 3 +++ zig/tests/dsym_test.bzl | 19 +------------------ zig/tests/rules_test.bzl | 5 ++++- 5 files changed, 11 insertions(+), 26 deletions(-) diff --git a/zig/private/common/zig_build.bzl b/zig/private/common/zig_build.bzl index 48b02144..c5750ed5 100644 --- a/zig/private/common/zig_build.bzl +++ b/zig/private/common/zig_build.bzl @@ -329,7 +329,7 @@ def zig_build_impl(ctx, *, kind): if ctx.attr.strip_debug_symbols: if generate_dsym_file: - fail("'strip_debug_symbols' cannot be enabled when generating a dSYM; use Bazel's '--strip' option to strip the linked binary after dSYM generation") + fail("'strip_debug_symbols' cannot be enabled when generating a dSYM") if not settings.strip: args.add("-fstrip") @@ -459,7 +459,6 @@ def zig_build_impl(ctx, *, kind): zig_settings( settings = settings, args = global_args, - strip = not generate_dsym_file, ) zig_target_platform( diff --git a/zig/private/providers/zig_settings_info.bzl b/zig/private/providers/zig_settings_info.bzl index 6d80fe73..aed0fb03 100644 --- a/zig/private/providers/zig_settings_info.bzl +++ b/zig/private/providers/zig_settings_info.bzl @@ -9,7 +9,7 @@ FIELDS = { "use_cc_common_link": "Whether to use cc_common.link to link zig binaries, tests and shared libraries.", "threaded": "The Zig multi- or single-threaded setting.", "strip": "Whether Zig compile actions should remove debug symbols.", - "args": "The collected compiler arguments excluding the Bazel-derived strip flag.", + "args": "The collected compiler arguments for all active settings.", } ZigSettingsInfo = provider( @@ -17,14 +17,11 @@ ZigSettingsInfo = provider( fields = FIELDS, ) -def zig_settings(*, settings, args, strip = True): +def zig_settings(*, settings, args): """Set flags for the given Zig build settings. Args: settings: ZigSettingsInfo, The active Zig build settings. args: Args; mutable, Append the needed Zig compiler flags to this object. - strip: bool; Whether to append the Bazel-derived strip flag. """ - if strip and settings.strip: - args.add("-fstrip") args.add_all(settings.args) diff --git a/zig/private/settings.bzl b/zig/private/settings.bzl index 2a7a6a63..00bd3b42 100644 --- a/zig/private/settings.bzl +++ b/zig/private/settings.bzl @@ -137,6 +137,9 @@ def _settings_impl(ctx): use_cc_common_link = ctx.attr.host_use_cc_common_link[BuildSettingInfo].value if is_exec_configuration else ctx.attr.use_cc_common_link[BuildSettingInfo].value strip = _resolve_strip(ctx, ctx.attr._bazel_strip[BazelStripInfo].strip) + if strip: + args.append("-fstrip") + args.extend(ctx.attr.host_zigopt[BuildSettingInfo].value if is_exec_configuration else ctx.attr.zigopt[BuildSettingInfo].value) settings_info = ZigSettingsInfo( diff --git a/zig/tests/dsym_test.bzl b/zig/tests/dsym_test.bzl index ad56aec2..ffce021b 100644 --- a/zig/tests/dsym_test.bzl +++ b/zig/tests/dsym_test.bzl @@ -17,7 +17,6 @@ _EXTRA_TOOLCHAINS = "//command_line_option:extra_toolchains" _STRIP = "//command_line_option:strip" _TARGET_PLATFORM = "//command_line_option:platforms" _SETTINGS_USE_CC_COMMON_LINK = canonical_label("@//zig/settings:use_cc_common_link") -_SETTINGS_ZIGOPT = canonical_label("@//zig/settings:zigopt") _PLATFORM_ZIG_ONLY_X86_64_LINUX = canonical_label("@//zig/tests/platforms:zig-only-x86_64-linux") _TOOLCHAIN_UNCONSTRAINED_DEFAULT_TEST = canonical_label("@//zig/tests/platforms:unconstrained_default_test_toolchain") @@ -57,22 +56,7 @@ _dsyms_enabled_test = analysistest.make( config_settings = { _APPLE_GENERATE_DSYM: True, _SETTINGS_USE_CC_COMMON_LINK: True, - _STRIP: "always", - }, -) - -def _dsyms_explicit_fstrip_test_impl(ctx): - env = analysistest.begin(ctx) - assert_flag_set(env, "-fstrip", assert_find_action(env, "ZigBuildLib").argv) - return analysistest.end(env) - -_dsyms_explicit_fstrip_test = analysistest.make( - _dsyms_explicit_fstrip_test_impl, - config_settings = { - _APPLE_GENERATE_DSYM: True, - _SETTINGS_USE_CC_COMMON_LINK: True, - _SETTINGS_ZIGOPT: ["-fstrip"], - _STRIP: "always", + _STRIP: "never", }, ) @@ -151,7 +135,6 @@ def dsym_test_suite(name): partial.make(_dsyms_enabled_test, name = "dsym_binary_enabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_enabled_test, name = "dsym_shared_library_enabled_test", target_under_test = "//zig/tests/simple-shared-library:shared", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_enabled_test, name = "dsym_test_enabled_test", target_under_test = "//zig/tests/simple-test:test", size = "small", target_compatible_with = ["@platforms//os:macos"]), - partial.make(_dsyms_explicit_fstrip_test, name = "dsym_explicit_fstrip_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_strip_debug_symbols_test, name = "dsym_strip_debug_symbols_test", target_under_test = "//zig/tests/strip_debug_symbols:binary-strip", size = "small", target_compatible_with = ["@platforms//os:macos"]), partial.make(_dsyms_disabled_test, name = "dsym_binary_disabled_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), partial.make(_dsyms_without_cc_toolchain_requested_test, name = "dsym_zig_only_requested_test", target_under_test = "//zig/tests/simple-binary:binary", size = "small"), diff --git a/zig/tests/rules_test.bzl b/zig/tests/rules_test.bzl index 11e0283e..4dfd5d8c 100644 --- a/zig/tests/rules_test.bzl +++ b/zig/tests/rules_test.bzl @@ -467,7 +467,10 @@ def _define_bazel_strip_settings_test(*, strip, compilation_mode, expected_strip settings = analysistest.target_under_test(env)[ZigSettingsInfo] asserts.equals(env, expected_strip, settings.strip) - assert_flag_unset(env, "-fstrip", settings.args) + if expected_strip: + assert_flag_set(env, "-fstrip", settings.args) + else: + assert_flag_unset(env, "-fstrip", settings.args) return analysistest.end(env)