diff --git a/main.c b/main.c index a16eae5..13a2e16 100644 --- a/main.c +++ b/main.c @@ -5,7 +5,10 @@ static bool opt_cc1; static bool opt_hash_hash_hash; static char *opt_o; -static char *input_path; +static char *base_file; +static char *output_file; + +static StringArray input_paths; static StringArray tmpfiles; static void usage(int status) { @@ -13,7 +16,18 @@ static void usage(int status) { exit(status); } +static bool take_arg(char *arg) { + return !strcmp(arg, "-o"); +} + static void parse_args(int argc, char **argv) { + // Make sure that all command line options that take an argument + // have an argument. + for (int i = 1; i < argc; i++) + if (take_arg(argv[i])) + if (!argv[++i]) + usage(1); + for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-###")) { opt_hash_hash_hash = true; @@ -29,9 +43,7 @@ static void parse_args(int argc, char **argv) { usage(0); if (!strcmp(argv[i], "-o")) { - if (!argv[++i]) - usage(1); - opt_o = argv[i]; + opt_o = argv[++i]; continue; } @@ -45,13 +57,23 @@ static void parse_args(int argc, char **argv) { continue; } + if (!strcmp(argv[i], "-cc1-input")) { + base_file = argv[++i]; + continue; + } + + if (!strcmp(argv[i], "-cc1-output")) { + output_file = argv[++i]; + continue; + } + if (argv[i][0] == '-' && argv[i][1] != '\0') error("unknown argument: %s", argv[i]); - input_path = argv[i]; + strarray_push(&input_paths, argv[i]); } - if (!input_path) + if (input_paths.len == 0) error("no input files"); } @@ -118,11 +140,13 @@ static void run_cc1(int argc, char **argv, char *input, char *output) { memcpy(args, argv, argc * sizeof(char *)); args[argc++] = "-cc1"; - if (input) + if (input) { + args[argc++] = "-cc1-input"; args[argc++] = input; + } if (output) { - args[argc++] = "-o"; + args[argc++] = "-cc1-output"; args[argc++] = output; } @@ -131,12 +155,12 @@ static void run_cc1(int argc, char **argv, char *input, char *output) { static void cc1(void) { // Tokenize and parse. - Token *tok = tokenize_file(input_path); + Token *tok = tokenize_file(base_file); Obj *prog = parse(tok); // Traverse the AST to emit assembly. - FILE *out = open_file(opt_o); - fprintf(out, ".file 1 \"%s\"\n", input_path); + FILE *out = open_file(output_file); + fprintf(out, ".file 1 \"%s\"\n", base_file); codegen(prog, out); } @@ -154,23 +178,31 @@ int main(int argc, char **argv) { return 0; } - char *output; - if (opt_o) - output = opt_o; - else if (opt_S) - output = replace_extn(input_path, ".s"); - else - output = replace_extn(input_path, ".o"); + if (input_paths.len > 1 && opt_o) + error("cannot specify '-o' with multiple files"); - // If -S is given, assembly text is the final output. - if (opt_S) { - run_cc1(argc, argv, input_path, output); - return 0; + for (int i = 0; i < input_paths.len; i++) { + char *input = input_paths.data[i]; + + char *output; + if (opt_o) + output = opt_o; + else if (opt_S) + output = replace_extn(input, ".s"); + else + output = replace_extn(input, ".o"); + + // If -S is given, assembly text is the final output. + if (opt_S) { + run_cc1(argc, argv, input, output); + continue; + } + + // Otherwise, run the assembler to assemble our output. + char *tmpfile = create_tmpfile(); + run_cc1(argc, argv, input, tmpfile); + assemble(tmpfile, output); } - // Otherwise, run the assembler to assemble our output. - char *tmpfile = create_tmpfile(); - run_cc1(argc, argv, input_path, tmpfile); - assemble(tmpfile, output); return 0; } diff --git a/test/driver.sh b/test/driver.sh index d30c46d..ad1c629 100755 --- a/test/driver.sh +++ b/test/driver.sh @@ -39,4 +39,19 @@ check 'default output file' [ -f $tmp/out.s ] check 'default output file' +# Multiple input files +rm -f $tmp/foo.o $tmp/bar.o +echo 'int x;' > $tmp/foo.c +echo 'int y;' > $tmp/bar.c +(cd $tmp; $OLDPWD/$chibicc $tmp/foo.c $tmp/bar.c) +[ -f $tmp/foo.o ] && [ -f $tmp/bar.o ] +check 'multiple input files' + +rm -f $tmp/foo.s $tmp/bar.s +echo 'int x;' > $tmp/foo.c +echo 'int y;' > $tmp/bar.c +(cd $tmp; $OLDPWD/$chibicc -S $tmp/foo.c $tmp/bar.c) +[ -f $tmp/foo.s ] && [ -f $tmp/bar.s ] +check 'multiple input files' + echo OK