Skip to content

Split concatenated compiler flags into separate flag+path arguments#220

Open
JSGette wants to merge 2 commits into
f0rmiga:mainfrom
JSGette:jsgette/split-flag-path-args-upstream
Open

Split concatenated compiler flags into separate flag+path arguments#220
JSGette wants to merge 2 commits into
f0rmiga:mainfrom
JSGette:jsgette/split-flag-path-args-upstream

Conversation

@JSGette
Copy link
Copy Markdown

@JSGette JSGette commented Apr 2, 2026

Problem

Flags like -isystem, -I, -B, and -L are currently emitted as single concatenated strings in defs.bzl:

"-isystem{}".format(include)   # produces "-isystem/path/to/include"
"-B%workspace%/bin"             # produces "-Bexternal/.../bin"

While GCC accepts both -isystemPATH and -isystem PATH, the concatenated form is incompatible with downstream tools that post-process compiler flags by matching individual arguments.

Specifically, rules_rust's cargo_build_script has path-rewriting logic (_pwd_flags) that prefixes execroot-relative paths with ${pwd}/ so that Cargo build scripts — which run from a different working directory — can resolve them. This logic only recognizes the space-separated form (-isystem, path) and silently skips the concatenated form (-isystempath).

Symptom

When building Rust crates that compile C code via cc-rs (e.g. zstd-sys, aws-lc-sys), the build script's GCC invocation fails with:

fatal error: limits.h: No such file or directory

because -isystemexternal/gcc_toolchain_.../include is passed as-is, and the build script's CWD is not the Bazel execroot, so the relative path doesn't resolve.

Reproduction

  1. Use gcc_toolchain to provide a GCC toolchain.
  2. Have a Rust crate that depends on a -sys crate using cc-rs to compile C code (e.g. zstd-sys via async-compression, or aws-lc-sys via rustls).
  3. Build with rules_rust — the cargo_build_script action for the -sys crate will fail because the compiler cannot find standard headers.

The root cause is that rules_rust's _pwd_flags_isystem and _pwd_flags_bindir functions iterate over flag arguments looking for standalone -isystem or -B entries and then prefix the next argument with ${pwd}/. When the flag and path are concatenated into a single argument, these functions never match.

Fix

Split all flag+path pairs into two separate list elements:

# Before
"-isystem{}".format(include)
"-B%workspace%/bin"

# After
"-isystem", include
"-B", "%workspace%/bin"

This is a no-op for GCC (both forms are semantically identical) but enables correct path rewriting by rules_rust and any other tool that inspects flags as discrete arguments.

The same change is applied consistently to extra_cflags, extra_cxxflags, extra_fflags, extra_ldflags, and extra_asmflags.

Currently, flags like -isystem, -I, -B, and -L are emitted as single
concatenated strings (e.g. "-isystem/path/to/include", "-B/path/to/bin").
While GCC accepts both forms, this concatenated style is incompatible with
tools that post-process compiler flags by pattern-matching individual
arguments.

Specifically, rules_rust's cargo_build_script has logic (_pwd_flags) to
rewrite execroot-relative paths so that Cargo build scripts (which run
from a different working directory) can locate headers and libraries.
This logic only recognizes the space-separated form ("-isystem", "/path")
and silently skips the concatenated form ("-isystem/path"), causing
build failures when Rust crates with C dependencies (e.g. zstd-sys,
aws-lc-sys via cc-rs) cannot find standard headers like limits.h.

Split all flag+path pairs into two separate list elements. This is a
no-op for GCC (both forms are equivalent) but enables correct path
rewriting by downstream tooling.
Copy link
Copy Markdown
Owner

@f0rmiga f0rmiga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JSGette Unfortunately, this breaks libtool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants