From ca38751f959cde85cc79fd0429ce8918df75997b Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 28 Aug 2026 15:48:12 +0200 Subject: [PATCH 1/3] Rust: Enable LTO for the extractor --- misc/bazel/rust.bzl | 26 +++++++++++++++++++++++++- rust/extractor/BUILD.bazel | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/misc/bazel/rust.bzl b/misc/bazel/rust.bzl index 97afee4ba1c1..9142776318cc 100644 --- a/misc/bazel/rust.bzl +++ b/misc/bazel/rust.bzl @@ -1,17 +1,41 @@ load("@rules_rust//rust:defs.bzl", "rust_binary") load("@semmle_code//buildutils-internal:glibc_symbols_check.bzl", "glibc_symbols_check") load("@semmle_code//buildutils-internal:lipo.bzl", "universal_binary") +load("@semmle_code//buildutils-internal:transitions.bzl", "forward_binary_from_transition", "get_transition_attrs") + +def _full_lto_transition_impl(_settings, _attr): + return {"@rules_rust//rust/settings:lto": "fat"} + +_full_lto_transition = transition( + implementation = _full_lto_transition_impl, + inputs = [], + outputs = ["@rules_rust//rust/settings:lto"], +) + +_full_lto_binary = rule( + implementation = forward_binary_from_transition, + attrs = get_transition_attrs(_full_lto_transition), +) def codeql_rust_binary( name, + full_lto = False, target_compatible_with = None, visibility = None, symbols_test = True, **kwargs): rust_label_name = "single_arch/" + name + binary_dep = ":" + rust_label_name + if full_lto: + lto_label_name = "full_lto/" + name + _full_lto_binary( + name = lto_label_name, + dep = binary_dep, + ) + binary_dep = ":" + lto_label_name universal_binary( name = name, - dep = ":" + rust_label_name, + dep = binary_dep, target_compatible_with = target_compatible_with, visibility = visibility, ) diff --git a/rust/extractor/BUILD.bazel b/rust/extractor/BUILD.bazel index 52b551f6335d..d3ae10fe39e8 100644 --- a/rust/extractor/BUILD.bazel +++ b/rust/extractor/BUILD.bazel @@ -11,6 +11,7 @@ codeql_rust_binary( "src/qltest_cargo.mustache", "src/nightly-toolchain/rust-toolchain.toml", ], + full_lto = True, proc_macro_deps = all_crate_deps( proc_macro = True, ) + [ From 693c0f3bfe76104684dd31d9a72f16b9ab2a3cab Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Sat, 29 Aug 2026 09:10:55 +0200 Subject: [PATCH 2/3] Fix full LTO in standalone and Linux builds Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a52f212e-fee3-4245-a5fc-e5be4cdf2cdf --- misc/bazel/rust.bzl | 5 +++- misc/bazel/transitions.bzl | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 misc/bazel/transitions.bzl diff --git a/misc/bazel/rust.bzl b/misc/bazel/rust.bzl index 9142776318cc..7f83f09bc085 100644 --- a/misc/bazel/rust.bzl +++ b/misc/bazel/rust.bzl @@ -1,7 +1,7 @@ load("@rules_rust//rust:defs.bzl", "rust_binary") load("@semmle_code//buildutils-internal:glibc_symbols_check.bzl", "glibc_symbols_check") load("@semmle_code//buildutils-internal:lipo.bzl", "universal_binary") -load("@semmle_code//buildutils-internal:transitions.bzl", "forward_binary_from_transition", "get_transition_attrs") +load("//misc/bazel:transitions.bzl", "forward_binary_from_transition", "get_transition_attrs") def _full_lto_transition_impl(_settings, _attr): return {"@rules_rust//rust/settings:lto": "fat"} @@ -27,6 +27,9 @@ def codeql_rust_binary( rust_label_name = "single_arch/" + name binary_dep = ":" + rust_label_name if full_lto: + # rustc must consume the LLVM bitcode because the C++ linker may use an + # incompatible LLVM version. + kwargs["experimental_use_cc_common_link"] = 0 lto_label_name = "full_lto/" + name _full_lto_binary( name = lto_label_name, diff --git a/misc/bazel/transitions.bzl b/misc/bazel/transitions.bzl new file mode 100644 index 000000000000..bc94ccdf4a03 --- /dev/null +++ b/misc/bazel/transitions.bzl @@ -0,0 +1,47 @@ +load("@bazel_skylib//lib:paths.bzl", "paths") + +def forward_binary_from_transition(ctx): + binary = ctx.attr.dep[0] + default_info = binary[DefaultInfo] + original_executable = default_info.files_to_run.executable + if not original_executable: + fail("Cannot transition a target that is not executable") + + (_, extension) = paths.split_extension(original_executable.basename) + new_executable = ctx.actions.declare_file(ctx.label.name + extension) + inputs = [original_executable] + command = "cp %s %s" % (original_executable.path, new_executable.path) + + providers = [] + if OutputGroupInfo in binary: + pdb_file = getattr(binary[OutputGroupInfo], "pdb_file", None) + if pdb_file: + (pdb_file,) = pdb_file.to_list() + linked_pdb_file = ctx.actions.declare_file(ctx.label.name + ".pdb") + ctx.actions.symlink(target_file = pdb_file, output = linked_pdb_file) + inputs.append(linked_pdb_file) + providers.append(binary[OutputGroupInfo]) + + ctx.actions.run_shell( + inputs = inputs, + outputs = [new_executable], + command = command, + ) + files = depset(direct = [new_executable]) + runfiles = default_info.default_runfiles.merge(ctx.runfiles([new_executable])) + providers.append( + DefaultInfo( + files = files, + runfiles = runfiles, + executable = new_executable, + ), + ) + return providers + +def get_transition_attrs(transition_rule): + return { + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + "dep": attr.label(mandatory = True, cfg = transition_rule), + } From 46a767ac159fcea0c5c8e929e8012317436b3142 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 31 Aug 2026 09:17:41 +0200 Subject: [PATCH 3/3] Reuse shared transition helpers Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a52f212e-fee3-4245-a5fc-e5be4cdf2cdf --- misc/bazel/rust.bzl | 2 +- .../buildutils-internal/transitions.bzl | 21 +++++++++ misc/bazel/transitions.bzl | 47 ------------------- 3 files changed, 22 insertions(+), 48 deletions(-) create mode 100644 misc/bazel/semmle_code_stub/buildutils-internal/transitions.bzl delete mode 100644 misc/bazel/transitions.bzl diff --git a/misc/bazel/rust.bzl b/misc/bazel/rust.bzl index 7f83f09bc085..f9d41d1079bb 100644 --- a/misc/bazel/rust.bzl +++ b/misc/bazel/rust.bzl @@ -1,7 +1,7 @@ load("@rules_rust//rust:defs.bzl", "rust_binary") load("@semmle_code//buildutils-internal:glibc_symbols_check.bzl", "glibc_symbols_check") load("@semmle_code//buildutils-internal:lipo.bzl", "universal_binary") -load("//misc/bazel:transitions.bzl", "forward_binary_from_transition", "get_transition_attrs") +load("@semmle_code//buildutils-internal:transitions.bzl", "forward_binary_from_transition", "get_transition_attrs") def _full_lto_transition_impl(_settings, _attr): return {"@rules_rust//rust/settings:lto": "fat"} diff --git a/misc/bazel/semmle_code_stub/buildutils-internal/transitions.bzl b/misc/bazel/semmle_code_stub/buildutils-internal/transitions.bzl new file mode 100644 index 000000000000..60bca5e5d179 --- /dev/null +++ b/misc/bazel/semmle_code_stub/buildutils-internal/transitions.bzl @@ -0,0 +1,21 @@ +def forward_binary_from_transition(ctx): + default_info = ctx.attr.dep[0][DefaultInfo] + original_executable = default_info.files_to_run.executable + executable = ctx.actions.declare_file(ctx.label.name) + ctx.actions.symlink( + output = executable, + target_file = original_executable, + is_executable = True, + ) + return [DefaultInfo( + executable = executable, + runfiles = default_info.default_runfiles, + )] + +def get_transition_attrs(transition_rule): + return { + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + "dep": attr.label(mandatory = True, cfg = transition_rule), + } diff --git a/misc/bazel/transitions.bzl b/misc/bazel/transitions.bzl deleted file mode 100644 index bc94ccdf4a03..000000000000 --- a/misc/bazel/transitions.bzl +++ /dev/null @@ -1,47 +0,0 @@ -load("@bazel_skylib//lib:paths.bzl", "paths") - -def forward_binary_from_transition(ctx): - binary = ctx.attr.dep[0] - default_info = binary[DefaultInfo] - original_executable = default_info.files_to_run.executable - if not original_executable: - fail("Cannot transition a target that is not executable") - - (_, extension) = paths.split_extension(original_executable.basename) - new_executable = ctx.actions.declare_file(ctx.label.name + extension) - inputs = [original_executable] - command = "cp %s %s" % (original_executable.path, new_executable.path) - - providers = [] - if OutputGroupInfo in binary: - pdb_file = getattr(binary[OutputGroupInfo], "pdb_file", None) - if pdb_file: - (pdb_file,) = pdb_file.to_list() - linked_pdb_file = ctx.actions.declare_file(ctx.label.name + ".pdb") - ctx.actions.symlink(target_file = pdb_file, output = linked_pdb_file) - inputs.append(linked_pdb_file) - providers.append(binary[OutputGroupInfo]) - - ctx.actions.run_shell( - inputs = inputs, - outputs = [new_executable], - command = command, - ) - files = depset(direct = [new_executable]) - runfiles = default_info.default_runfiles.merge(ctx.runfiles([new_executable])) - providers.append( - DefaultInfo( - files = files, - runfiles = runfiles, - executable = new_executable, - ), - ) - return providers - -def get_transition_attrs(transition_rule): - return { - "_allowlist_function_transition": attr.label( - default = "@bazel_tools//tools/allowlists/function_transition_allowlist", - ), - "dep": attr.label(mandatory = True, cfg = transition_rule), - }