diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-02-25 11:37:54 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-02-25 11:45:00 -0500 |
| commit | e76ce2c1d0d3988359267fd3030a81a52ec99f3f (patch) | |
| tree | 04e2c5c67961d5d54ba9d31b2e1601837b84a9df /src/codegen.cpp | |
| parent | e5d4862e145c38ffc1111ee578ddcafc1e35ad57 (diff) | |
| download | zig-e76ce2c1d0d3988359267fd3030a81a52ec99f3f.tar.gz zig-e76ce2c1d0d3988359267fd3030a81a52ec99f3f.zip | |
first class support for compiling C code
New CLI parameter: --c-source [options] [file]
It even works with `--cache on` when there are transitive dependencies.
Instead of `builder.addCExecutable`, use `builder.addExecutable` and pass
`null` for the root source file. Then use `builder.addCSourceFile`,
which takes the path to the C code, and a list of C compiler args.
Be sure to linkSystemLibrary("c") if you want libc headers to be
available.
Merge TestStep into LibExeObjStep. That was long overdue.
Diffstat (limited to 'src/codegen.cpp')
| -rw-r--r-- | src/codegen.cpp | 195 |
1 files changed, 184 insertions, 11 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 54da63e9f9..f14749bb28 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7885,8 +7885,8 @@ static void detect_libc(CodeGen *g) { fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); exit(1); } - if (rename(buf_ptr(native_libc_tmp), buf_ptr(native_libc_txt)) == -1) { - fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), strerror(errno)); + if ((err = os_rename(native_libc_tmp, native_libc_txt))) { + fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), err_str(err)); exit(1); } } @@ -8123,6 +8123,162 @@ static void gen_global_asm(CodeGen *g) { } } +static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { + Error err; + + Buf *c_source_file = buf_create_from_str(c_file->source_path); + Buf *c_source_basename = buf_alloc(); + os_path_split(c_source_file, nullptr, c_source_basename); + Buf *out_obj_name = buf_sprintf("%s%s", buf_ptr(c_source_basename), target_o_file_ext(g->zig_target)); + Buf *out_obj_path = buf_alloc(); + os_path_join(&g->cache_dir, out_obj_name, out_obj_path); + Buf *out_dep_name = buf_sprintf("%s.d", buf_ptr(c_source_file)); + Buf *out_dep_path = buf_alloc(); + os_path_join(&g->cache_dir, out_dep_name, out_dep_path); + + Termination term; + ZigList<const char *> args = {}; + args.append("cc"); + + if (g->enable_cache) { + args.append("-MD"); + args.append("-MF"); + args.append(buf_ptr(out_dep_path)); + } + + args.append("-isystem"); + args.append(buf_ptr(g->zig_c_headers_dir)); + + if (g->libc != nullptr) { + args.append("-isystem"); + args.append(buf_ptr(&g->libc->include_dir)); + } + + if (g->zig_target->is_native) { + args.append("-march=native"); + } else { + args.append("-target"); + args.append(buf_ptr(&g->triple_str)); + } + + if (!g->strip_debug_symbols) { + args.append("-g"); + } + switch (g->build_mode) { + case BuildModeDebug: + if (g->libc_link_lib != nullptr) { + args.append("-fstack-protector-strong"); + args.append("--param"); + args.append("ssp-buffer-size=4"); + } else { + args.append("-fno-stack-protector"); + } + break; + case BuildModeSafeRelease: + args.append("-O2"); + if (g->libc_link_lib != nullptr) { + args.append("-D_FORTIFY_SOURCE=2"); + args.append("-fstack-protector-strong"); + args.append("--param"); + args.append("ssp-buffer-size=4"); + } else { + args.append("-fno-stack-protector"); + } + break; + case BuildModeFastRelease: + args.append("-O2"); + args.append("-fno-stack-protector"); + break; + case BuildModeSmallRelease: + args.append("-Os"); + args.append("-fno-stack-protector"); + break; + } + + args.append("-o"); + args.append(buf_ptr(out_obj_path)); + + args.append("-c"); + args.append(buf_ptr(c_source_file)); + + if (!g->disable_pic) { + args.append("-fPIC"); + } + + for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { + args.append(g->clang_argv[arg_i]); + } + + for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) { + args.append(c_file->args.at(arg_i)); + } + + if (g->verbose_cc) { + for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) { + fprintf(stderr, "%s ", args.at(arg_i)); + } + fprintf(stderr, "\n"); + } + + os_spawn_process(buf_ptr(self_exe_path), args, &term); + if (term.how != TerminationIdClean || term.code != 0) { + fprintf(stderr, "`zig cc` failed\n"); + exit(1); + } + + g->link_objects.append(out_obj_path); + + // add the files depended on to the cache system + if (g->enable_cache) { + Buf *contents = buf_alloc(); + if ((err = os_fetch_file_path(out_dep_path, contents, false))) { + fprintf(stderr, "unable to read .d file: %s\n", err_str(err)); + exit(1); + } + if ((err = cache_add_file(&g->cache_hash, c_source_file))) { + fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(c_source_file), err_str(err)); + exit(1); + } + SplitIterator it = memSplit(buf_to_slice(contents), str("\n")); + // skip first line + SplitIterator_next(&it); + for (;;) { + Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it); + if (!opt_line.is_some) + break; + if (opt_line.value.len == 0) + continue; + SplitIterator line_it = memSplit(opt_line.value, str(" \t")); + Slice<uint8_t> filename; + if (!SplitIterator_next(&line_it).unwrap(&filename)) + continue; + Buf *filename_buf = buf_create_from_slice(filename); + if ((err = cache_add_file(&g->cache_hash, filename_buf))) { + fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(c_source_file), err_str(err)); + exit(1); + } + } + } +} + +static void gen_c_objects(CodeGen *g) { + Error err; + + if (g->c_source_files.length == 0) + return; + + Buf *self_exe_path = buf_alloc(); + if ((err = os_self_exe_path(self_exe_path))) { + fprintf(stderr, "Unable to get self exe path: %s\n", err_str(err)); + exit(1); + } + + for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) { + CFile *c_file = g->c_source_files.at(c_file_i); + gen_c_object(g, self_exe_path, c_file); + } +} + void codegen_add_object(CodeGen *g, Buf *object_path) { g->link_objects.append(object_path); } @@ -8637,6 +8793,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length); cache_list_of_file(ch, g->link_objects.items, g->link_objects.length); cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length); + for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) { + CFile *c_file = g->c_source_files.at(c_file_i); + cache_file(ch, buf_create_from_str(c_file->source_path)); + for (size_t opt_i = 0; opt_i < c_file->args.length; opt_i += 1) { + cache_buf(ch, buf_create_from_str(c_file->args.at(opt_i))); + } + } cache_int(ch, g->emit_file_type); cache_int(ch, g->build_mode); cache_int(ch, g->out_type); @@ -8788,6 +8951,7 @@ void codegen_build_and_link(CodeGen *g) { gen_global_asm(g); gen_root_source(g); + gen_c_objects(g); if (g->enable_cache) { if ((err = cache_final(&g->cache_hash, &digest))) { @@ -8805,16 +8969,25 @@ void codegen_build_and_link(CodeGen *g) { resolve_out_paths(g); codegen_add_time_event(g, "Code Generation"); - do_code_gen(g); - codegen_add_time_event(g, "LLVM Emit Output"); - zig_llvm_emit_output(g); + if (g->out_type == OutTypeObj && g->c_source_files.length == 1) { + assert(g->link_objects.length == 1); + if ((err = os_rename(g->link_objects.pop(), &g->o_file_output_path))) { + fprintf(stderr, "unable to move object to '%s': %s\n", + buf_ptr(&g->o_file_output_path), err_str(err)); + exit(1); + } + } else { + do_code_gen(g); + codegen_add_time_event(g, "LLVM Emit Output"); + zig_llvm_emit_output(g); - if (g->out_h_path != nullptr) { - codegen_add_time_event(g, "Generate .h"); - gen_h_file(g); - } - if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) { - codegen_link(g); + if (g->out_h_path != nullptr) { + codegen_add_time_event(g, "Generate .h"); + gen_h_file(g); + } + if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) { + codegen_link(g); + } } } |
