diff --git a/main.c b/main.c index 27bcadf..398108b 100644 --- a/main.c +++ b/main.c @@ -1,8 +1,11 @@ #include "chibicc.h" +typedef enum { FILE_NONE, FILE_C, FILE_ASM, FILE_OBJ } FileType; + StringArray include_paths; bool opt_fcommon = true; +static FileType opt_x; static StringArray opt_include; static bool opt_E; static bool opt_S; @@ -23,7 +26,7 @@ static void usage(int status) { } static bool take_arg(char *arg) { - char *x[] = {"-o", "-I", "-idirafter", "-include"}; + char *x[] = {"-o", "-I", "-idirafter", "-include", "-x"}; for (int i = 0; i < sizeof(x) / sizeof(*x); i++) if (!strcmp(arg, x[i])) @@ -50,6 +53,16 @@ static void define(char *str) { define_macro(str, "1"); } +static FileType parse_opt_x(char *s) { + if (!strcmp(s, "c")) + return FILE_C; + if (!strcmp(s, "assembler")) + return FILE_ASM; + if (!strcmp(s, "none")) + return FILE_NONE; + error(": unknown argument for -x: %s", s); +} + static void parse_args(int argc, char **argv) { // Make sure that all command line options that take an argument // have an argument. @@ -139,6 +152,16 @@ static void parse_args(int argc, char **argv) { continue; } + if (!strcmp(argv[i], "-x")) { + opt_x = parse_opt_x(argv[++i]); + continue; + } + + if (!strncmp(argv[i], "-x", 2)) { + opt_x = parse_opt_x(argv[i] + 2); + continue; + } + if (!strcmp(argv[i], "-cc1-input")) { base_file = argv[++i]; continue; @@ -434,6 +457,21 @@ static void run_linker(StringArray *inputs, char *output) { run_subprocess(arr.data); } +static FileType get_file_type(char *filename) { + if (endswith(filename, ".o")) + return FILE_OBJ; + + if (opt_x != FILE_NONE) + return opt_x; + + if (endswith(filename, ".c")) + return FILE_C; + if (endswith(filename, ".s")) + return FILE_ASM; + + error(": unknown file extension: %s", filename); +} + int main(int argc, char **argv) { atexit(cleanup); init_macros(); @@ -461,22 +499,22 @@ int main(int argc, char **argv) { else output = replace_extn(input, ".o"); + FileType type = get_file_type(input); + // Handle .o - if (endswith(input, ".o")) { + if (type == FILE_OBJ) { strarray_push(&ld_args, input); continue; } // Handle .s - if (endswith(input, ".s")) { + if (type == FILE_ASM) { if (!opt_S) assemble(input, output); continue; } - // Handle .c - if (!endswith(input, ".c") && strcmp(input, "-")) - error("unknown file extension: %s", input); + assert(type == FILE_C); // Just preprocess if (opt_E) { diff --git a/test/driver.sh b/test/driver.sh index 2fdf08a..3f31b4f 100755 --- a/test/driver.sh +++ b/test/driver.sh @@ -25,7 +25,7 @@ $chibicc --help 2>&1 | grep -q chibicc check --help # -S -echo 'int main() {}' | $chibicc -S -o - - | grep -q 'main:' +echo 'int main() {}' | $chibicc -S -o- -xc - | grep -q 'main:' check -S # Default output file @@ -56,7 +56,7 @@ check 'multiple input files' # Run linker rm -f $tmp/foo -echo 'int main() { return 0; }' | $chibicc -o $tmp/foo - +echo 'int main() { return 0; }' | $chibicc -o $tmp/foo -xc -xc - $tmp/foo check linker @@ -77,30 +77,30 @@ check a.out # -E echo foo > $tmp/out -echo "#include \"$tmp/out\"" | $chibicc -E - | grep -q foo +echo "#include \"$tmp/out\"" | $chibicc -E -xc - | grep -q foo check -E echo foo > $tmp/out1 -echo "#include \"$tmp/out1\"" | $chibicc -E -o $tmp/out2 - +echo "#include \"$tmp/out1\"" | $chibicc -E -o $tmp/out2 -xc - cat $tmp/out2 | grep -q foo check '-E and -o' # -I mkdir $tmp/dir echo foo > $tmp/dir/i-option-test -echo "#include \"i-option-test\"" | $chibicc -I$tmp/dir -E - | grep -q foo +echo "#include \"i-option-test\"" | $chibicc -I$tmp/dir -E -xc - | grep -q foo check -I # -D -echo foo | $chibicc -Dfoo -E - | grep -q 1 +echo foo | $chibicc -Dfoo -E -xc - | grep -q 1 check -D # -D -echo foo | $chibicc -Dfoo=bar -E - | grep -q bar +echo foo | $chibicc -Dfoo=bar -E -xc - | grep -q bar check -D # -U -echo foo | $chibicc -Dfoo=bar -Ufoo -E - | grep -q foo +echo foo | $chibicc -Dfoo=bar -Ufoo -E -xc - | grep -q foo check -U # ignored options @@ -110,7 +110,7 @@ $chibicc -c -O -Wall -g -std=c11 -ffreestanding -fno-builtin \ check 'ignored options' # BOM marker -printf '\xef\xbb\xbfxyz\n' | $chibicc -E -o- - | grep -q '^xyz' +printf '\xef\xbb\xbfxyz\n' | $chibicc -E -o- -xc - | grep -q '^xyz' check 'BOM marker' # Inline functions @@ -125,67 +125,77 @@ echo 'int foo(); int main() { foo(); }' > $tmp/inline2.c $chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c check inline -echo 'static inline void f1() {}' | $chibicc -o- -S - | grep -v -q f1: +echo 'static inline void f1() {}' | $chibicc -o- -S -xc - | grep -v -q f1: check inline -echo 'static inline void f1() {} void foo() { f1(); }' | $chibicc -o- -S - | grep -q f1: +echo 'static inline void f1() {} void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1: check inline -echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -q f1: +echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1: check inline -echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -v -q f2: +echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -v -q f2: check inline -echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f1: +echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f1: check inline -echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f2: +echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f2: check inline -echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S - | grep -v -q f1: +echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S -xc - | grep -v -q f1: check inline -echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S - | grep -v -q f2: +echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S -xc - | grep -v -q f2: check inline -echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -q f1: +echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1: check inline -echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -q f2: +echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f2: check inline -echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f1: +echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f1: check inline -echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f2: +echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f2: check inline # -idirafter mkdir -p $tmp/dir1 $tmp/dir2 echo foo > $tmp/dir1/idirafter echo bar > $tmp/dir2/idirafter -echo "#include \"idirafter\"" | $chibicc -I$tmp/dir1 -I$tmp/dir2 -E - | grep -q foo +echo "#include \"idirafter\"" | $chibicc -I$tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q foo check -idirafter -echo "#include \"idirafter\"" | $chibicc -idirafter $tmp/dir1 -I$tmp/dir2 -E - | grep -q bar +echo "#include \"idirafter\"" | $chibicc -idirafter $tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q bar check -idirafter # -fcommon -echo 'int foo;' | $chibicc -S -o- - | grep -q '\.comm foo' +echo 'int foo;' | $chibicc -S -o- -xc - | grep -q '\.comm foo' check '-fcommon (default)' -echo 'int foo;' | $chibicc -fcommon -S -o- - | grep -q '\.comm foo' +echo 'int foo;' | $chibicc -fcommon -S -o- -xc - | grep -q '\.comm foo' check '-fcommon' # -fno-common -echo 'int foo;' | $chibicc -fno-common -S -o- - | grep -q '^foo:' +echo 'int foo;' | $chibicc -fno-common -S -o- -xc - | grep -q '^foo:' check '-fno-common' # -include echo foo > $tmp/out.h -echo bar | $chibicc -include $tmp/out.h -E -o- - | grep -q -z 'foo.*bar' +echo bar | $chibicc -include $tmp/out.h -E -o- -xc - | grep -q -z 'foo.*bar' check -include -echo NULL | $chibicc -Iinclude -include stdio.h -E -o- - | grep -q 0 +echo NULL | $chibicc -Iinclude -include stdio.h -E -o- -xc - | grep -q 0 check -include +# -x +echo 'int x;' | $chibicc -c -xc -o $tmp/foo.o - +check -xc +echo 'x:' | $chibicc -c -x assembler -o $tmp/foo.o - +check '-x assembler' + +echo 'int x;' > $tmp/foo.c +$chibicc -c -x assembler -x none -o $tmp/foo.o $tmp/foo.c +check '-x none' + echo OK