Commit 783f73c7e3

Andrew Kelley <andrew@ziglang.org>
2020-04-01 22:01:06
zig cc properly handles -S flag and .ll, .bc extensions
1 parent 6695fa4
src/all_types.hpp
@@ -54,6 +54,16 @@ struct ResultLocCast;
 struct ResultLocReturn;
 struct IrExecutableGen;
 
+enum FileExt {
+    FileExtUnknown,
+    FileExtAsm,
+    FileExtC,
+    FileExtCpp,
+    FileExtHeader,
+    FileExtLLVMIr,
+    FileExtLLVMBitCode,
+};
+
 enum PtrLen {
     PtrLenUnknown,
     PtrLenSingle,
src/analyze.hpp
@@ -257,14 +257,8 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose
 LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type);
 ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type);
 
-enum CSourceKind {
-    CSourceKindAsm,
-    CSourceKindC,
-    CSourceKindCpp,
-};
-
 void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_path, bool translate_c,
-        CSourceKind source_kind);
+        FileExt source_kind);
 
 void src_assert(bool ok, AstNode *source_node);
 bool is_container(ZigType *type_entry);
src/buffer.hpp
@@ -178,10 +178,7 @@ static inline bool buf_starts_with_str(Buf *buf, const char *str) {
 }
 
 static inline bool buf_ends_with_mem(Buf *buf, const char *mem, size_t mem_len) {
-    if (buf_len(buf) < mem_len) {
-        return false;
-    }
-    return memcmp(buf_ptr(buf) + buf_len(buf) - mem_len, mem, mem_len) == 0;
+    return mem_ends_with_mem(buf_ptr(buf), buf_len(buf), mem, mem_len);
 }
 
 static inline bool buf_ends_with_str(Buf *buf, const char *str) {
src/codegen.cpp
@@ -9170,20 +9170,13 @@ static void detect_libc(CodeGen *g) {
 
 // does not add the "cc" arg
 void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_path,
-        bool translate_c, CSourceKind source_kind)
+        bool translate_c, FileExt source_kind)
 {
     if (translate_c) {
         args.append("-x");
         args.append("c");
     }
 
-    if (source_kind != CSourceKindAsm && out_dep_path != nullptr) {
-        args.append("-MD");
-        args.append("-MV");
-        args.append("-MF");
-        args.append(out_dep_path);
-    }
-
     args.append("-nostdinc");
     args.append("-fno-spell-checking");
 
@@ -9191,14 +9184,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
         args.append("-ffunction-sections");
     }
 
-    if (translate_c) {
-        if (source_kind != CSourceKindAsm) {
-            // this gives us access to preprocessing entities, presumably at
-            // the cost of performance
-            args.append("-Xclang");
-            args.append("-detailed-preprocessing-record");
-        }
-    } else {
+    if (!translate_c) {
         switch (g->err_color) {
             case ErrColorAuto:
                 break;
@@ -9232,24 +9218,25 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
         args.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
     }
 
-    // According to Rich Felker libc headers are supposed to go before C language headers.
-    // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
-    // and other compiler specific items.
-    args.append("-isystem");
-    args.append(buf_ptr(g->zig_c_headers_dir));
-
-    for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {
-        const char *include_dir = g->libc_include_dir_list[i];
-        args.append("-isystem");
-        args.append(include_dir);
-    }
-
     args.append("-target");
     args.append(buf_ptr(&g->llvm_triple_str));
 
     switch (source_kind) {
-        case CSourceKindC:
-        case CSourceKindCpp:
+        case FileExtC:
+        case FileExtCpp:
+        case FileExtHeader:
+            // According to Rich Felker libc headers are supposed to go before C language headers.
+            // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
+            // and other compiler specific items.
+            args.append("-isystem");
+            args.append(buf_ptr(g->zig_c_headers_dir));
+
+            for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {
+                const char *include_dir = g->libc_include_dir_list[i];
+                args.append("-isystem");
+                args.append(include_dir);
+            }
+
             if (g->zig_target->llvm_cpu_name != nullptr) {
                 args.append("-Xclang");
                 args.append("-target-cpu");
@@ -9262,8 +9249,23 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
                 args.append("-Xclang");
                 args.append(g->zig_target->llvm_cpu_features);
             }
+            if (translate_c) {
+                // this gives us access to preprocessing entities, presumably at
+                // the cost of performance
+                args.append("-Xclang");
+                args.append("-detailed-preprocessing-record");
+            }
+            if (out_dep_path != nullptr) {
+                args.append("-MD");
+                args.append("-MV");
+                args.append("-MF");
+                args.append(out_dep_path);
+            }
             break;
-        case CSourceKindAsm:
+        case FileExtAsm:
+        case FileExtLLVMIr:
+        case FileExtLLVMBitCode:
+        case FileExtUnknown:
             break;
     }
     for (size_t i = 0; i < g->zig_target->llvm_cpu_features_asm_len; i += 1) {
@@ -9413,7 +9415,7 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
     }
 
     ZigList<const char *> clang_argv = {0};
-    add_cc_args(g, clang_argv, out_dep_path_cstr, true, CSourceKindC);
+    add_cc_args(g, clang_argv, out_dep_path_cstr, true, FileExtC);
 
     clang_argv.append(buf_ptr(full_path));
 
@@ -9751,15 +9753,6 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
     Buf *c_source_basename = buf_alloc();
     os_path_split(c_source_file, nullptr, c_source_basename);
 
-    CSourceKind c_source_kind;
-    if (buf_ends_with_str(c_source_basename, ".s") ||
-        buf_ends_with_str(c_source_basename, ".S"))
-    {
-        c_source_kind = CSourceKindAsm;
-    } else {
-        c_source_kind = CSourceKindC;
-    }
-
     Stage2ProgressNode *child_prog_node = stage2_progress_start(g->sub_progress_node, buf_ptr(c_source_basename),
             buf_len(c_source_basename), 0);
 
@@ -9825,14 +9818,13 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
         args.append(buf_ptr(self_exe_path));
         args.append("clang");
 
-        if (c_file->preprocessor_only_basename != nullptr) {
-            args.append("-E");
-        } else {
+        if (c_file->preprocessor_only_basename == nullptr) {
             args.append("-c");
         }
 
         Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path));
-        add_cc_args(g, args, buf_ptr(out_dep_path), false, c_source_kind);
+        FileExt ext = classify_file_ext(buf_ptr(c_source_basename), buf_len(c_source_basename));
+        add_cc_args(g, args, buf_ptr(out_dep_path), false, ext);
 
         args.append("-o");
         args.append(buf_ptr(out_obj_path));
src/compiler.cpp
@@ -164,3 +164,25 @@ Buf *get_global_cache_dir(void) {
     buf_deinit(&app_data_dir);
     return &saved_global_cache_dir;
 }
+
+FileExt classify_file_ext(const char *filename_ptr, size_t filename_len) {
+    if (mem_ends_with_str(filename_ptr, filename_len, ".c")) {
+        return FileExtC;
+    } else if (mem_ends_with_str(filename_ptr, filename_len, ".C") ||
+        mem_ends_with_str(filename_ptr, filename_len, ".cc") ||
+        mem_ends_with_str(filename_ptr, filename_len, ".cpp") ||
+        mem_ends_with_str(filename_ptr, filename_len, ".cxx"))
+    {
+        return FileExtCpp;
+    } else if (mem_ends_with_str(filename_ptr, filename_len, ".ll")) {
+        return FileExtLLVMIr;
+    } else if (mem_ends_with_str(filename_ptr, filename_len, ".bc")) {
+        return FileExtLLVMBitCode;
+    } else if (mem_ends_with_str(filename_ptr, filename_len, ".s") ||
+        mem_ends_with_str(filename_ptr, filename_len, ".S"))
+    {
+        return FileExtAsm;
+    }
+    // TODO look for .so, .so.X, .so.X.Y, .so.X.Y.Z
+    return FileExtUnknown;
+}
src/compiler.hpp
@@ -8,8 +8,7 @@
 #ifndef ZIG_COMPILER_HPP
 #define ZIG_COMPILER_HPP
 
-#include "buffer.hpp"
-#include "error.hpp"
+#include "all_types.hpp"
 
 Error get_compiler_id(Buf **result);
 
@@ -19,4 +18,7 @@ Buf *get_zig_std_dir(Buf *zig_lib_dir);
 
 Buf *get_global_cache_dir(void);
 
+
+FileExt classify_file_ext(const char *filename_ptr, size_t filename_len);
+
 #endif
src/ir.cpp
@@ -25171,7 +25171,7 @@ static IrInstGen *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstSrcCImpo
 
         ZigList<const char *> clang_argv = {0};
 
-        add_cc_args(ira->codegen, clang_argv, buf_ptr(tmp_dep_file), true, CSourceKindC);
+        add_cc_args(ira->codegen, clang_argv, buf_ptr(tmp_dep_file), true, FileExtC);
 
         clang_argv.append(buf_ptr(&tmp_c_file_path));
 
src/main.cpp
@@ -455,7 +455,7 @@ static int main0(int argc, char **argv) {
     const char *mcpu = nullptr;
     CodeModel code_model = CodeModelDefault;
     const char *override_soname = nullptr;
-    bool only_preprocess = false;
+    bool only_pp_or_asm = false;
     bool ensure_libc_on_non_freestanding = false;
     bool ensure_libcpp_on_non_freestanding = false;
 
@@ -615,20 +615,22 @@ static int main0(int argc, char **argv) {
                     }
                     break;
                 case Stage2ClangArgPositional: {
-                    Buf *arg_buf = buf_create_from_str(it.only_arg);
-                    if (buf_ends_with_str(arg_buf, ".c") ||
-                        buf_ends_with_str(arg_buf, ".C") ||
-                        buf_ends_with_str(arg_buf, ".cc") ||
-                        buf_ends_with_str(arg_buf, ".cpp") ||
-                        buf_ends_with_str(arg_buf, ".cxx") ||
-                        buf_ends_with_str(arg_buf, ".s") ||
-                        buf_ends_with_str(arg_buf, ".S"))
-                    {
-                        CFile *c_file = heap::c_allocator.create<CFile>();
-                        c_file->source_path = it.only_arg;
-                        c_source_files.append(c_file);
-                    } else {
-                        objects.append(it.only_arg);
+                    FileExt file_ext = classify_file_ext(it.only_arg, strlen(it.only_arg));
+                    switch (file_ext) {
+                        case FileExtAsm:
+                        case FileExtC:
+                        case FileExtCpp:
+                        case FileExtLLVMIr:
+                        case FileExtLLVMBitCode:
+                        case FileExtHeader: {
+                            CFile *c_file = heap::c_allocator.create<CFile>();
+                            c_file->source_path = it.only_arg;
+                            c_source_files.append(c_file);
+                            break;
+                        }
+                        case FileExtUnknown:
+                            objects.append(it.only_arg);
+                            break;
                     }
                     break;
                 }
@@ -674,8 +676,12 @@ static int main0(int argc, char **argv) {
                     }
                     break;
                 }
-                case Stage2ClangArgPreprocess:
-                    only_preprocess = true;
+                case Stage2ClangArgPreprocessOrAsm:
+                    // this handles both -E and -S
+                    only_pp_or_asm = true;
+                    for (size_t i = 0; i < it.other_args_len; i += 1) {
+                        clang_argv.append(it.other_args_ptr[i]);
+                    }
                     break;
                 case Stage2ClangArgOptimize:
                     // alright what release mode do they want?
@@ -799,7 +805,7 @@ static int main0(int argc, char **argv) {
             build_mode = BuildModeSafeRelease;
         }
 
-        if (only_preprocess) {
+        if (only_pp_or_asm) {
             cmd = CmdBuild;
             out_type = OutTypeObj;
             emit_bin = false;
@@ -1597,7 +1603,7 @@ static int main0(int argc, char **argv) {
 #endif
                         Buf *dest_path = buf_create_from_str(emit_bin_override_path);
                         Buf *source_path;
-                        if (only_preprocess) {
+                        if (only_pp_or_asm) {
                             source_path = buf_alloc();
                             Buf *pp_only_basename = buf_create_from_str(
                                     c_source_files.at(0)->preprocessor_only_basename);
@@ -1611,7 +1617,7 @@ static int main0(int argc, char **argv) {
                                     buf_ptr(dest_path), err_str(err));
                             return main_exit(root_progress_node, EXIT_FAILURE);
                         }
-                    } else if (only_preprocess) {
+                    } else if (only_pp_or_asm) {
 #if defined(ZIG_OS_WINDOWS)
                         buf_replace(g->c_artifact_dir, '/', '\\');
 #endif
src/stage2.h
@@ -339,7 +339,7 @@ enum Stage2ClangArg {
     Stage2ClangArgShared,
     Stage2ClangArgRDynamic,
     Stage2ClangArgWL,
-    Stage2ClangArgPreprocess,
+    Stage2ClangArgPreprocessOrAsm,
     Stage2ClangArgOptimize,
     Stage2ClangArgDebug,
     Stage2ClangArgSanitize,
src/util.hpp
@@ -100,6 +100,15 @@ static inline bool is_power_of_2(uint64_t x) {
     return x != 0 && ((x & (~x + 1)) == x);
 }
 
+static inline bool mem_ends_with_mem(const char *mem, size_t mem_len, const char *end, size_t end_len) {
+    if (mem_len < end_len) return false;
+    return memcmp(mem + mem_len - end_len, end, end_len) == 0;
+}
+
+static inline bool mem_ends_with_str(const char *mem, size_t mem_len, const char *str) {
+    return mem_ends_with_mem(mem, mem_len, str, strlen(str));
+}
+
 static inline uint64_t round_to_next_power_of_2(uint64_t x) {
     --x;
     x |= x >> 1;
src-self-hosted/clang_options_data.zig
@@ -7,7 +7,7 @@ flagpd1("CC"),
 .{
     .name = "E",
     .syntax = .flag,
-    .zig_equivalent = .preprocess,
+    .zig_equivalent = .pp_or_asm,
     .pd1 = true,
     .pd2 = false,
     .psl = false,
@@ -53,7 +53,7 @@ flagpd1("Qy"),
 .{
     .name = "S",
     .syntax = .flag,
-    .zig_equivalent = .driver_punt,
+    .zig_equivalent = .pp_or_asm,
     .pd1 = true,
     .pd2 = false,
     .psl = false,
@@ -154,7 +154,7 @@ sepd1("Zlinker-input"),
 .{
     .name = "E",
     .syntax = .flag,
-    .zig_equivalent = .preprocess,
+    .zig_equivalent = .pp_or_asm,
     .pd1 = true,
     .pd2 = false,
     .psl = true,
@@ -1442,7 +1442,7 @@ sepd1("Zlinker-input"),
 .{
     .name = "assemble",
     .syntax = .flag,
-    .zig_equivalent = .driver_punt,
+    .zig_equivalent = .pp_or_asm,
     .pd1 = false,
     .pd2 = true,
     .psl = false,
@@ -1770,7 +1770,7 @@ sepd1("Zlinker-input"),
 .{
     .name = "preprocess",
     .syntax = .flag,
-    .zig_equivalent = .preprocess,
+    .zig_equivalent = .pp_or_asm,
     .pd1 = false,
     .pd2 = true,
     .psl = false,
src-self-hosted/stage2.zig
@@ -1280,7 +1280,7 @@ pub const ClangArgIterator = extern struct {
         shared,
         rdynamic,
         wl,
-        preprocess,
+        pp_or_asm,
         optimize,
         debug,
         sanitize,
tools/update_clang_options.zig
@@ -96,19 +96,19 @@ const known_options = [_]KnownOpt{
     },
     .{
         .name = "E",
-        .ident = "preprocess",
+        .ident = "pp_or_asm",
     },
     .{
         .name = "preprocess",
-        .ident = "preprocess",
+        .ident = "pp_or_asm",
     },
     .{
         .name = "S",
-        .ident = "driver_punt",
+        .ident = "pp_or_asm",
     },
     .{
         .name = "assemble",
-        .ident = "driver_punt",
+        .ident = "pp_or_asm",
     },
     .{
         .name = "O1",