From 4b0ddb817bb5d4effd8cd2dd0844ac278e35e1d5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 21 Mar 2020 20:32:48 -0400 Subject: [PATCH] zig cc: better support for the preprocessor option (-E) --- src-self-hosted/clang_options_data.zig | 8 ++-- src-self-hosted/stage2.zig | 1 + src/all_types.hpp | 2 + src/codegen.cpp | 22 +++++++--- src/main.cpp | 60 ++++++++++++++++++++++++-- src/os.cpp | 24 +++++++++++ src/os.hpp | 1 + src/stage2.h | 1 + tools/update_clang_options.zig | 10 ++++- 9 files changed, 115 insertions(+), 14 deletions(-) diff --git a/src-self-hosted/clang_options_data.zig b/src-self-hosted/clang_options_data.zig index bfd26c6de..b1796dce7 100644 --- a/src-self-hosted/clang_options_data.zig +++ b/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, diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 45fa2ec3e..030e9694e 100644 --- a/src-self-hosted/stage2.zig +++ b/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 { diff --git a/src/all_types.hpp b/src/all_types.hpp index b1450f08d..aed03d478 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2003,6 +2003,7 @@ enum WantCSanitize { struct CFile { ZigList 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; diff --git a/src/codegen.cpp b/src/codegen.cpp index 7729172c2..7b481f7c2 100644 --- a/src/codegen.cpp +++ b/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); diff --git a/src/main.cpp b/src/main.cpp index d64b8dcdb..071b365d2 100644 --- a/src/main.cpp +++ b/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 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(); + 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, '/', '\\'); diff --git a/src/os.cpp b/src/os.cpp index f65a578e1..351b61cd6 100644 --- a/src/os.cpp +++ b/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; diff --git a/src/os.hpp b/src/os.hpp index 116861e8b..e73e5e3aa 100644 --- a/src/os.hpp +++ b/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); diff --git a/src/stage2.h b/src/stage2.h index 5f233f9fc..15c4c604c 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -333,6 +333,7 @@ enum Stage2ClangArg { Stage2ClangArgShared, Stage2ClangArgRDynamic, Stage2ClangArgWL, + Stage2ClangArgPreprocess, }; // ABI warning diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index b4cec5afd..ccd444313 100644 --- a/tools/update_clang_options.zig +++ b/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{};