Skip to content

Commit

Permalink
Add support for -- on clang/clang-cl command-line
Browse files Browse the repository at this point in the history
Fixes #1498
  • Loading branch information
glandium committed Nov 23, 2023
1 parent 68d0409 commit c9db859
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 33 deletions.
23 changes: 22 additions & 1 deletion src/compiler/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ where
{
arguments: I,
arg_info: S,
seen_double_dashes: Option<bool>,
phantom: PhantomData<T>,
}

Expand All @@ -592,9 +593,15 @@ where
ArgsIter {
arguments,
arg_info,
seen_double_dashes: None,
phantom: PhantomData,
}
}

pub fn with_double_dashes(mut self) -> Self {
self.seen_double_dashes = Some(false);
self
}
}

impl<I, T, S> Iterator for ArgsIter<I, T, S>
Expand All @@ -607,6 +614,14 @@ where

fn next(&mut self) -> Option<Self::Item> {
if let Some(arg) = self.arguments.next() {
if let Some(seen_double_dashes) = &mut self.seen_double_dashes {
if !*seen_double_dashes && arg == "--" {
*seen_double_dashes = true;
}
if *seen_double_dashes {
return Some(Ok(Argument::Raw(arg.clone())));
}
}
let s = arg.to_string_lossy();
let arguments = &mut self.arguments;
Some(match self.arg_info.search(&s[..]) {
Expand Down Expand Up @@ -957,8 +972,11 @@ mod tests {
"-plop",
"-quxbar", // -quxbar is not -qux with a value of bar
"-qux=value",
"--",
"non_flag",
"-flag-after-double-dashes",
];
let iter = ArgsIter::new(args.iter().map(OsString::from), &ARGS[..]);
let iter = ArgsIter::new(args.iter().map(OsString::from), &ARGS[..]).with_double_dashes();
let expected = vec![
arg!(UnknownFlag("-nomatch")),
arg!(WithValue("-foo", ArgData::Foo("value"), Separated)),
Expand All @@ -979,6 +997,9 @@ mod tests {
ArgData::Qux("value"),
CanBeSeparated('=')
)),
arg!(Raw("--")),
arg!(Raw("non_flag")),
arg!(Raw("-flag-after-double-dashes")),
];
match diff_with(iter, expected, |a, b| {
assert_eq!(a.as_ref().unwrap(), b);
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ pub struct ArtifactDescriptor {
pub struct ParsedArguments {
/// The input source file.
pub input: PathBuf,
/// Whether to prepend the input with `--`
pub double_dash_input: bool,
/// The type of language used in the input source file.
pub language: Language,
/// The flag required to compile for the given language
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/diab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ where

CompilerArguments::Ok(ParsedArguments {
input: input.into(),
double_dash_input: false,
language,
compilation_flag,
depfile: None,
Expand Down Expand Up @@ -744,6 +745,7 @@ mod test {
let f = TestFixture::new();
let parsed_args = ParsedArguments {
input: "foo.c".into(),
double_dash_input: false,
language: Language::C,
compilation_flag: "-c".into(),
depfile: None,
Expand Down
158 changes: 149 additions & 9 deletions src/compiler/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ where
{
let mut output_arg = None;
let mut input_arg = None;
let mut double_dash_input = false;
let mut dep_target = None;
let mut dep_flag = OsString::from("-MT");
let mut common_args = vec![];
Expand Down Expand Up @@ -290,7 +291,11 @@ where

let mut too_hard_for_preprocessor_cache_mode = false;

for arg in ArgsIter::new(it, arg_info) {
let mut args_iter = ArgsIter::new(it, arg_info);
if kind == CCompilerKind::Clang {
args_iter = args_iter.with_double_dashes();
}
for arg in args_iter {
let arg = try_or_cannot_cache!(arg, "argument parse");
// Check if the value part of this argument begins with '@'. If so, we either
// failed to expand it, or it was a concatenated argument - either way, bail.
Expand Down Expand Up @@ -392,6 +397,11 @@ where
}
Some(XClang(s)) => xclangs.push(s.clone()),
None => match arg {
Argument::Raw(ref val) if val == "--" => {
if input_arg.is_none() {
double_dash_input = true;
}
}
Argument::Raw(ref val) => {
if input_arg.is_some() {
multiple_input = true;
Expand Down Expand Up @@ -605,6 +615,7 @@ where

CompilerArguments::Ok(ParsedArguments {
input: input.into(),
double_dash_input,
language,
compilation_flag,
depfile: None,
Expand Down Expand Up @@ -703,11 +714,14 @@ fn preprocess_cmd<T>(
arch_args_to_use = &parsed_args.arch_args;
}

cmd.arg(&parsed_args.input)
.args(&parsed_args.preprocessor_args)
cmd.args(&parsed_args.preprocessor_args)
.args(&parsed_args.dependency_args)
.args(&parsed_args.common_args)
.args(arch_args_to_use)
.args(arch_args_to_use);
if parsed_args.double_dash_input {
cmd.arg("--");
}
cmd.arg(&parsed_args.input)
.env_clear()
.envs(env_vars.iter().map(|(k, v)| (k, v)))
.current_dir(cwd);
Expand Down Expand Up @@ -780,14 +794,17 @@ pub fn generate_compile_commands(
}
arguments.extend(vec![
parsed_args.compilation_flag.clone(),
parsed_args.input.clone().into(),
"-o".into(),
out_file.into(),
]);
arguments.extend(parsed_args.preprocessor_args.clone());
arguments.extend(parsed_args.unhashed_args.clone());
arguments.extend(parsed_args.common_args.clone());
arguments.extend(parsed_args.arch_args.clone());
if parsed_args.double_dash_input {
arguments.push("--".into());
}
arguments.push(parsed_args.input.clone().into());
let command = CompileCommand {
executable: executable.to_owned(),
arguments,
Expand Down Expand Up @@ -941,6 +958,20 @@ mod test {
parse_arguments(&args, ".".as_ref(), &ARGS[..], plusplus, CCompilerKind::Gcc)
}

fn parse_arguments_clang(
arguments: Vec<String>,
plusplus: bool,
) -> CompilerArguments<ParsedArguments> {
let args = arguments.iter().map(OsString::from).collect::<Vec<_>>();
parse_arguments(
&args,
".".as_ref(),
&ARGS[..],
plusplus,
CCompilerKind::Clang,
)
}

#[test]
fn test_parse_arguments_simple() {
let args = stringvec!["-c", "foo.c", "-o", "foo.o"];
Expand Down Expand Up @@ -1336,6 +1367,65 @@ mod test {
assert!(!msvc_show_includes);
}

#[test]
fn test_parse_arguments_double_dash() {
let args = stringvec!["-c", "-o", "foo.o", "--", "foo.c"];
let ParsedArguments {
input,
double_dash_input,
common_args,
..
} = match parse_arguments_(args.clone(), false) {
CompilerArguments::Ok(args) => args,
o => panic!("Got unexpected parse result: {:?}", o),
};
assert_eq!(Some("foo.c"), input.to_str());
// GCC doesn't support double dashes. If we got one, we'll pass them
// through to GCC for it to error out.
assert_eq!(double_dash_input, false);
assert_eq!(ovec!["--"], common_args);

let ParsedArguments {
input,
double_dash_input,
common_args,
..
} = match parse_arguments_clang(args, false) {
CompilerArguments::Ok(args) => args,
o => panic!("Got unexpected parse result: {:?}", o),
};
assert_eq!(Some("foo.c"), input.to_str());
assert_eq!(double_dash_input, true);
assert!(common_args.is_empty());

let args = stringvec!["-c", "-o", "foo.o", "foo.c", "--"];
let ParsedArguments {
input,
double_dash_input,
common_args,
..
} = match parse_arguments_clang(args, false) {
CompilerArguments::Ok(args) => args,
o => panic!("Got unexpected parse result: {:?}", o),
};
assert_eq!(Some("foo.c"), input.to_str());
// Double dash after input file is ignored.
assert_eq!(double_dash_input, false);
assert!(common_args.is_empty());

let args = stringvec!["-c", "-o", "foo.o", "foo.c", "--", "bar.c"];
assert_eq!(
CompilerArguments::CannotCache("multiple input files", Some("[\"bar.c\"]".to_string())),
parse_arguments_clang(args, false)
);

let args = stringvec!["-c", "-o", "foo.o", "foo.c", "--", "-fPIC"];
assert_eq!(
CompilerArguments::CannotCache("multiple input files", Some("[\"-fPIC\"]".to_string())),
parse_arguments_clang(args, false)
);
}

#[test]
fn test_parse_arguments_explicit_dep_target() {
let args =
Expand Down Expand Up @@ -1503,9 +1593,9 @@ mod test {
"c++",
"-E",
"-fdirectives-only",
"foo.cc",
"-D__arm64__=1",
"-D__i386__=1"
"-D__i386__=1",
"foo.cc"
];
assert_eq!(cmd.args, expected_args);
});
Expand Down Expand Up @@ -1538,13 +1628,38 @@ mod test {
"c++",
"-E",
"-fdirectives-only",
"foo.cc",
"-arch",
"arm64"
"arm64",
"foo.cc"
];
assert_eq!(cmd.args, expected_args);
}

#[test]
fn test_preprocess_double_dash_input() {
let args = stringvec!["-c", "-o", "foo.o", "--", "foo.c"];
let parsed_args = match parse_arguments_clang(args, false) {
CompilerArguments::Ok(args) => args,
o => panic!("Got unexpected parse result: {:?}", o),
};
let mut cmd = MockCommand {
child: None,
args: vec![],
};
preprocess_cmd(
&mut cmd,
&parsed_args,
Path::new(""),
&[],
true,
CCompilerKind::Clang,
true,
vec![],
);
let expected_args = ovec!["-x", "c", "-E", "-frewrite-includes", "--", "foo.c"];
assert_eq!(cmd.args, expected_args);
}

#[test]
fn pedantic_default() {
let args = stringvec!["-pedantic", "-c", "foo.cc"];
Expand Down Expand Up @@ -1888,6 +2003,7 @@ mod test {
let f = TestFixture::new();
let parsed_args = ParsedArguments {
input: "foo.c".into(),
double_dash_input: false,
language: Language::C,
compilation_flag: "-c".into(),
depfile: None,
Expand Down Expand Up @@ -1936,6 +2052,30 @@ mod test {
assert_eq!(0, creator.lock().unwrap().children.len());
}

#[test]
fn test_compile_double_dash_input() {
let args = stringvec!["-c", "-o", "foo.o", "--", "foo.c"];
let parsed_args = match parse_arguments_clang(args, false) {
CompilerArguments::Ok(args) => args,
o => panic!("Got unexpected parse result: {:?}", o),
};
let f = TestFixture::new();
let compiler = &f.bins[0];
let mut path_transformer = dist::PathTransformer::default();
let (command, _, _) = generate_compile_commands(
&mut path_transformer,
compiler,
&parsed_args,
f.tempdir.path(),
&[],
CCompilerKind::Clang,
false,
)
.unwrap();
let expected_args = ovec!["-x", "c", "-c", "-o", "foo.o", "--", "foo.c"];
assert_eq!(command.arguments, expected_args);
}

#[test]
fn test_parse_arguments_plusplus() {
let args = stringvec!["-c", "foo.c", "-o", "foo.o"];
Expand Down
Loading

0 comments on commit c9db859

Please sign in to comment.