Commit 4b0ddb817b

Andrew Kelley <andrew@ziglang.org>
2020-03-22 01:32:48
zig cc: better support for the preprocessor option (-E)
1 parent 28ad78c
src/all_types.hpp
@@ -2003,6 +2003,7 @@ enum WantCSanitize {
 struct CFile {
     ZigList<const char *> args;
     const char *source_path;
+    const char *preprocessor_only_basename;
 };
 
 // When adding fields, check if they should be added to the hash computation in build_with_cache
@@ -2147,6 +2148,7 @@ struct CodeGen {
     // As an input parameter, mutually exclusive with enable_cache. But it gets
     // populated in codegen_build_and_link.
     Buf *output_dir;
+    Buf *c_artifact_dir;
     const char **libc_include_dir_list;
     size_t libc_include_dir_len;
 
src/codegen.cpp
@@ -9723,13 +9723,17 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
             buf_len(c_source_basename), 0);
 
     Buf *final_o_basename = buf_alloc();
-    // We special case when doing build-obj for just one C file
-    if (main_output_dir_is_just_one_c_object_pre(g)) {
-        buf_init_from_buf(final_o_basename, g->root_out_name);
+    if (c_file->preprocessor_only_basename == nullptr) {
+        // We special case when doing build-obj for just one C file
+        if (main_output_dir_is_just_one_c_object_pre(g)) {
+            buf_init_from_buf(final_o_basename, g->root_out_name);
+        } else {
+            os_path_extname(c_source_basename, final_o_basename, nullptr);
+        }
+        buf_append_str(final_o_basename, target_o_file_ext(g->zig_target));
     } else {
-        os_path_extname(c_source_basename, final_o_basename, nullptr);
+        buf_init_from_str(final_o_basename, c_file->preprocessor_only_basename);
     }
-    buf_append_str(final_o_basename, target_o_file_ext(g->zig_target));
 
     CacheHash *cache_hash;
     if ((err = create_c_object_cache(g, &cache_hash, true))) {
@@ -9780,13 +9784,18 @@ 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 {
+            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);
 
         args.append("-o");
         args.append(buf_ptr(out_obj_path));
 
-        args.append("-c");
         args.append(buf_ptr(c_source_file));
 
         for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) {
@@ -9841,6 +9850,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
         os_path_join(artifact_dir, final_o_basename, o_final_path);
     }
 
+    g->c_artifact_dir = artifact_dir;
     g->link_objects.append(o_final_path);
     g->caches_to_release.append(cache_hash);
 
src/main.cpp
@@ -453,6 +453,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;
 
     ZigList<const char *> llvm_argv = {0};
     llvm_argv.append("zig (LLVM option parsing)");
@@ -660,6 +661,9 @@ static int main0(int argc, char **argv) {
                     }
                     break;
                 }
+                case Stage2ClangArgPreprocess:
+                    only_preprocess = true;
+                    break;
             }
         }
         // Parse linker args
@@ -715,7 +719,28 @@ static int main0(int argc, char **argv) {
             have_libc = true;
             link_libs.append("c");
         }
-        if (!c_arg) {
+        if (only_preprocess) {
+            cmd = CmdBuild;
+            out_type = OutTypeObj;
+            emit_bin = false;
+            // Transfer "objects" into c_source_files
+            for (size_t i = 0; i < objects.length; i += 1) {
+                CFile *c_file = heap::c_allocator.create<CFile>();
+                c_file->source_path = objects.at(i);
+                c_source_files.append(c_file);
+            }
+            for (size_t i = 0; i < c_source_files.length; i += 1) {
+                Buf *src_path;
+                if (emit_bin_override_path != nullptr) {
+                    src_path = buf_create_from_str(emit_bin_override_path);
+                } else {
+                    src_path = buf_create_from_str(c_source_files.at(i)->source_path);
+                }
+                Buf basename = BUF_INIT;
+                os_path_split(src_path, nullptr, &basename);
+                c_source_files.at(i)->preprocessor_only_basename = buf_ptr(&basename);
+            }
+        } else if (!c_arg) {
             cmd = CmdBuild;
             if (is_shared_lib) {
                 out_type = OutTypeLib;
@@ -1464,12 +1489,41 @@ static int main0(int argc, char **argv) {
                     return term.code;
                 } else if (cmd == CmdBuild) {
                     if (emit_bin_override_path != nullptr) {
+#if defined(ZIG_OS_WINDOWS)
+                        buf_replace(g->output_dir, '/', '\\');
+#endif
                         Buf *dest_path = buf_create_from_str(emit_bin_override_path);
-                        if ((err = os_update_file(&g->bin_file_output_path, dest_path))) {
-                            fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->bin_file_output_path),
+                        Buf *source_path;
+                        if (only_preprocess) {
+                            source_path = buf_alloc();
+                            Buf *pp_only_basename = buf_create_from_str(
+                                    c_source_files.at(0)->preprocessor_only_basename);
+                            os_path_join(g->output_dir, pp_only_basename, source_path);
+
+                        } else {
+                            source_path = &g->bin_file_output_path;
+                        }
+                        if ((err = os_update_file(source_path, dest_path))) {
+                            fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(source_path),
                                     buf_ptr(dest_path), err_str(err));
                             return main_exit(root_progress_node, EXIT_FAILURE);
                         }
+                    } else if (only_preprocess) {
+#if defined(ZIG_OS_WINDOWS)
+                        buf_replace(g->c_artifact_dir, '/', '\\');
+#endif
+                        // dump the preprocessed output to stdout
+                        for (size_t i = 0; i < c_source_files.length; i += 1) {
+                            Buf *source_path = buf_alloc();
+                            Buf *pp_only_basename = buf_create_from_str(
+                                    c_source_files.at(i)->preprocessor_only_basename);
+                            os_path_join(g->c_artifact_dir, pp_only_basename, source_path);
+                            if ((err = os_dump_file(source_path, stdout))) {
+                                fprintf(stderr, "unable to read %s: %s\n", buf_ptr(source_path),
+                                        err_str(err));
+                                return main_exit(root_progress_node, EXIT_FAILURE);
+                            }
+                        }
                     } else if (g->enable_cache) {
 #if defined(ZIG_OS_WINDOWS)
                         buf_replace(&g->bin_file_output_path, '/', '\\');
src/os.cpp
@@ -1051,6 +1051,30 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) {
     }
 }
 
+Error os_dump_file(Buf *src_path, FILE *dest_file) {
+    Error err;
+
+    FILE *src_f = fopen(buf_ptr(src_path), "rb");
+    if (!src_f) {
+        int err = errno;
+        if (err == ENOENT) {
+            return ErrorFileNotFound;
+        } else if (err == EACCES || err == EPERM) {
+            return ErrorAccess;
+        } else {
+            return ErrorFileSystem;
+        }
+    }
+    copy_open_files(src_f, dest_file);
+    if ((err = copy_open_files(src_f, dest_file))) {
+        fclose(src_f);
+        return err;
+    }
+
+    fclose(src_f);
+    return ErrorNone;
+}
+
 #if defined(ZIG_OS_WINDOWS)
 static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) {
     mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
src/os.hpp
@@ -129,6 +129,7 @@ void os_file_close(OsFile *file);
 Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents);
 Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path);
 Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path);
+Error ATTRIBUTE_MUST_USE os_dump_file(Buf *src_path, FILE *dest_file);
 
 Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents);
 Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents);
src/stage2.h
@@ -333,6 +333,7 @@ enum Stage2ClangArg {
     Stage2ClangArgShared,
     Stage2ClangArgRDynamic,
     Stage2ClangArgWL,
+    Stage2ClangArgPreprocess,
 };
 
 // ABI warning
src-self-hosted/clang_options_data.zig
@@ -7,7 +7,7 @@ flagpd1("CC"),
 .{
     .name = "E",
     .syntax = .flag,
-    .zig_equivalent = .driver_punt,
+    .zig_equivalent = .preprocess,
     .pd1 = true,
     .pd2 = false,
     .psl = false,
@@ -133,7 +133,7 @@ flagpd1("###"),
 .{
     .name = "E",
     .syntax = .flag,
-    .zig_equivalent = .driver_punt,
+    .zig_equivalent = .preprocess,
     .pd1 = true,
     .pd2 = false,
     .psl = true,
@@ -1421,7 +1421,7 @@ flagpd1("###"),
 .{
     .name = "assemble",
     .syntax = .flag,
-    .zig_equivalent = .other,
+    .zig_equivalent = .driver_punt,
     .pd1 = false,
     .pd2 = true,
     .psl = false,
@@ -1749,7 +1749,7 @@ flagpd1("###"),
 .{
     .name = "preprocess",
     .syntax = .flag,
-    .zig_equivalent = .other,
+    .zig_equivalent = .preprocess,
     .pd1 = false,
     .pd2 = true,
     .psl = false,
src-self-hosted/stage2.zig
@@ -1247,6 +1247,7 @@ pub const ClangArgIterator = extern struct {
         shared,
         rdynamic,
         wl,
+        preprocess,
     };
 
     fn init(argv: []const [*:0]const u8) ClangArgIterator {
tools/update_clang_options.zig
@@ -76,12 +76,20 @@ const known_options = [_]KnownOpt{
     },
     .{
         .name = "E",
-        .ident = "driver_punt",
+        .ident = "preprocess",
+    },
+    .{
+        .name = "preprocess",
+        .ident = "preprocess",
     },
     .{
         .name = "S",
         .ident = "driver_punt",
     },
+    .{
+        .name = "assemble",
+        .ident = "driver_punt",
+    },
 };
 
 const blacklisted_options = [_][]const u8{};