authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-25 14:11:54-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-02-25 14:11:54-05:00
log6003b1ea7018fe6a7aa87622d1178e444e6d8abb
treef87768be86d630511e694ebd09173057c7b88a58
parente5d4862e145c38ffc1111ee578ddcafc1e35ad57
parent0d4db8828a9efc05b5c3622098a8337de0b62d1e
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2005 from ziglang/c-source

first class support for compiling C code

21 files changed, 496 insertions(+), 737 deletions(-)

example/mix_o_files/build.zig+3-3
...@@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;...@@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
3pub fn build(b: *Builder) void {3pub fn build(b: *Builder) void {
4 const obj = b.addObject("base64", "base64.zig");4 const obj = b.addObject("base64", "base64.zig");
55
6 const exe = b.addCExecutable("test");6 const exe = b.addExecutable("test", null);
7 exe.addCompileFlags([][]const u8{"-std=c99"});7 exe.addCSourceFile("test.c",[][]const u8{"-std=c99"});
8 exe.addSourceFile("test.c");
9 exe.addObject(obj);8 exe.addObject(obj);
9 exe.linkSystemLibrary("c");
1010
11 b.default_step.dependOn(&exe.step);11 b.default_step.dependOn(&exe.step);
1212
example/shared_library/build.zig+3-3
...@@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;...@@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
3pub fn build(b: *Builder) void {3pub fn build(b: *Builder) void {
4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
6 const exe = b.addCExecutable("test");6 const exe = b.addExecutable("test", null);
7 exe.addCompileFlags([][]const u8{"-std=c99"});7 exe.addCSourceFile("test.c", [][]const u8{"-std=c99"});
8 exe.addSourceFile("test.c");
9 exe.linkLibrary(lib);8 exe.linkLibrary(lib);
9 exe.linkSystemLibrary("c");
1010
11 b.default_step.dependOn(&exe.step);11 b.default_step.dependOn(&exe.step);
1212
src/all_types.hpp+8
...@@ -1611,6 +1611,11 @@ enum ValgrindSupport {...@@ -1611,6 +1611,11 @@ enum ValgrindSupport {
1611 ValgrindSupportEnabled,1611 ValgrindSupportEnabled,
1612};1612};
16131613
1614struct CFile {
1615 ZigList<const char *> args;
1616 const char *source_path;
1617};
1618
1614// When adding fields, check if they should be added to the hash computation in build_with_cache1619// When adding fields, check if they should be added to the hash computation in build_with_cache
1615struct CodeGen {1620struct CodeGen {
1616 //////////////////////////// Runtime State1621 //////////////////////////// Runtime State
...@@ -1738,6 +1743,7 @@ struct CodeGen {...@@ -1738,6 +1743,7 @@ struct CodeGen {
1738 Buf triple_str;1743 Buf triple_str;
1739 Buf global_asm;1744 Buf global_asm;
1740 Buf *out_h_path;1745 Buf *out_h_path;
1746 Buf *out_lib_path;
1741 Buf artifact_dir;1747 Buf artifact_dir;
1742 Buf output_file_path;1748 Buf output_file_path;
1743 Buf o_file_output_path;1749 Buf o_file_output_path;
...@@ -1788,6 +1794,7 @@ struct CodeGen {...@@ -1788,6 +1794,7 @@ struct CodeGen {
1788 bool verbose_ir;1794 bool verbose_ir;
1789 bool verbose_llvm_ir;1795 bool verbose_llvm_ir;
1790 bool verbose_cimport;1796 bool verbose_cimport;
1797 bool verbose_cc;
1791 bool error_during_imports;1798 bool error_during_imports;
1792 bool generate_error_name_table;1799 bool generate_error_name_table;
1793 bool enable_cache;1800 bool enable_cache;
...@@ -1805,6 +1812,7 @@ struct CodeGen {...@@ -1805,6 +1812,7 @@ struct CodeGen {
1805 ZigList<Buf *> forbidden_libs;1812 ZigList<Buf *> forbidden_libs;
1806 ZigList<Buf *> link_objects;1813 ZigList<Buf *> link_objects;
1807 ZigList<Buf *> assembly_files;1814 ZigList<Buf *> assembly_files;
1815 ZigList<CFile *> c_source_files;
1808 ZigList<const char *> lib_dirs;1816 ZigList<const char *> lib_dirs;
18091817
1810 ZigLibCInstallation *libc;1818 ZigLibCInstallation *libc;
src/cache_hash.cpp+34
...@@ -414,6 +414,39 @@ Error cache_add_file(CacheHash *ch, Buf *path) {...@@ -414,6 +414,39 @@ Error cache_add_file(CacheHash *ch, Buf *path) {
414 return cache_add_file_fetch(ch, resolved_path, nullptr);414 return cache_add_file_fetch(ch, resolved_path, nullptr);
415}415}
416416
417Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
418 Error err;
419 Buf *contents = buf_alloc();
420 if ((err = os_fetch_file_path(dep_file_path, contents, false))) {
421 if (verbose) {
422 fprintf(stderr, "unable to read .d file: %s\n", err_str(err));
423 }
424 return ErrorReadingDepFile;
425 }
426 SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
427 // skip first line
428 SplitIterator_next(&it);
429 for (;;) {
430 Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
431 if (!opt_line.is_some)
432 break;
433 if (opt_line.value.len == 0)
434 continue;
435 SplitIterator line_it = memSplit(opt_line.value, str(" \t"));
436 Slice<uint8_t> filename;
437 if (!SplitIterator_next(&line_it).unwrap(&filename))
438 continue;
439 Buf *filename_buf = buf_create_from_slice(filename);
440 if ((err = cache_add_file(ch, filename_buf))) {
441 if (verbose) {
442 fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
443 }
444 return err;
445 }
446 }
447 return ErrorNone;
448}
449
417static Error write_manifest_file(CacheHash *ch) {450static Error write_manifest_file(CacheHash *ch) {
418 Error err;451 Error err;
419 Buf contents = BUF_INIT;452 Buf contents = BUF_INIT;
...@@ -464,3 +497,4 @@ void cache_release(CacheHash *ch) {...@@ -464,3 +497,4 @@ void cache_release(CacheHash *ch) {
464497
465 os_file_close(ch->manifest_file);498 os_file_close(ch->manifest_file);
466}499}
500
src/cache_hash.hpp+2
...@@ -56,6 +56,8 @@ Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);...@@ -56,6 +56,8 @@ Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
56// If you did not get a cache hit, call this function for every file56// If you did not get a cache hit, call this function for every file
57// that is depended on, and then finish with cache_final.57// that is depended on, and then finish with cache_final.
58Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path);58Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path);
59// This opens a file created by -MD -MF args to Clang
60Error ATTRIBUTE_MUST_USE cache_add_dep_file(CacheHash *ch, Buf *path, bool verbose);
5961
60// This variant of cache_add_file returns the file contents.62// This variant of cache_add_file returns the file contents.
61// Also the file path argument must be already resolved.63// Also the file path argument must be already resolved.
src/codegen.cpp+169-11
...@@ -175,6 +175,10 @@ void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {...@@ -175,6 +175,10 @@ void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
175 g->out_h_path = h_path;175 g->out_h_path = h_path;
176}176}
177177
178void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path) {
179 g->out_lib_path = lib_path;
180}
181
178void codegen_set_output_path(CodeGen *g, Buf *path) {182void codegen_set_output_path(CodeGen *g, Buf *path) {
179 g->wanted_output_file_path = path;183 g->wanted_output_file_path = path;
180}184}
...@@ -7885,8 +7889,8 @@ static void detect_libc(CodeGen *g) {...@@ -7885,8 +7889,8 @@ static void detect_libc(CodeGen *g) {
7885 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));7889 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
7886 exit(1);7890 exit(1);
7887 }7891 }
7888 if (rename(buf_ptr(native_libc_tmp), buf_ptr(native_libc_txt)) == -1) {7892 if ((err = os_rename(native_libc_tmp, native_libc_txt))) {
7889 fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), strerror(errno));7893 fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), err_str(err));
7890 exit(1);7894 exit(1);
7891 }7895 }
7892 }7896 }
...@@ -8123,6 +8127,143 @@ static void gen_global_asm(CodeGen *g) {...@@ -8123,6 +8127,143 @@ static void gen_global_asm(CodeGen *g) {
8123 }8127 }
8124}8128}
81258129
8130static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
8131 Error err;
8132
8133 Buf *c_source_file = buf_create_from_str(c_file->source_path);
8134 Buf *c_source_basename = buf_alloc();
8135 os_path_split(c_source_file, nullptr, c_source_basename);
8136 Buf *out_obj_name = buf_sprintf("%s%s", buf_ptr(c_source_basename), target_o_file_ext(g->zig_target));
8137 Buf *out_obj_path = buf_alloc();
8138 os_path_join(&g->cache_dir, out_obj_name, out_obj_path);
8139 Buf *out_dep_name = buf_sprintf("%s.d", buf_ptr(c_source_file));
8140 Buf *out_dep_path = buf_alloc();
8141 os_path_join(&g->cache_dir, out_dep_name, out_dep_path);
8142
8143 Termination term;
8144 ZigList<const char *> args = {};
8145 args.append("cc");
8146
8147 if (g->enable_cache) {
8148 args.append("-MD");
8149 args.append("-MF");
8150 args.append(buf_ptr(out_dep_path));
8151 }
8152
8153 args.append("-isystem");
8154 args.append(buf_ptr(g->zig_c_headers_dir));
8155
8156 if (g->libc != nullptr) {
8157 args.append("-isystem");
8158 args.append(buf_ptr(&g->libc->include_dir));
8159 }
8160
8161 if (g->zig_target->is_native) {
8162 args.append("-march=native");
8163 } else {
8164 args.append("-target");
8165 args.append(buf_ptr(&g->triple_str));
8166 }
8167
8168 if (!g->strip_debug_symbols) {
8169 args.append("-g");
8170 }
8171 switch (g->build_mode) {
8172 case BuildModeDebug:
8173 if (g->libc_link_lib != nullptr) {
8174 args.append("-fstack-protector-strong");
8175 args.append("--param");
8176 args.append("ssp-buffer-size=4");
8177 } else {
8178 args.append("-fno-stack-protector");
8179 }
8180 break;
8181 case BuildModeSafeRelease:
8182 args.append("-O2");
8183 if (g->libc_link_lib != nullptr) {
8184 args.append("-D_FORTIFY_SOURCE=2");
8185 args.append("-fstack-protector-strong");
8186 args.append("--param");
8187 args.append("ssp-buffer-size=4");
8188 } else {
8189 args.append("-fno-stack-protector");
8190 }
8191 break;
8192 case BuildModeFastRelease:
8193 args.append("-O2");
8194 args.append("-fno-stack-protector");
8195 break;
8196 case BuildModeSmallRelease:
8197 args.append("-Os");
8198 args.append("-fno-stack-protector");
8199 break;
8200 }
8201
8202 args.append("-o");
8203 args.append(buf_ptr(out_obj_path));
8204
8205 args.append("-c");
8206 args.append(buf_ptr(c_source_file));
8207
8208 if (!g->disable_pic && target_supports_fpic(g->zig_target)) {
8209 args.append("-fPIC");
8210 }
8211
8212 for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
8213 args.append(g->clang_argv[arg_i]);
8214 }
8215
8216 for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) {
8217 args.append(c_file->args.at(arg_i));
8218 }
8219
8220 if (g->verbose_cc) {
8221 fprintf(stderr, "zig");
8222 for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {
8223 fprintf(stderr, " %s", args.at(arg_i));
8224 }
8225 fprintf(stderr, "\n");
8226 }
8227
8228 os_spawn_process(buf_ptr(self_exe_path), args, &term);
8229 if (term.how != TerminationIdClean || term.code != 0) {
8230 fprintf(stderr, "`zig cc` failed\n");
8231 exit(1);
8232 }
8233
8234 g->link_objects.append(out_obj_path);
8235
8236 if (g->enable_cache) {
8237 // add the files depended on to the cache system
8238 if ((err = cache_add_file(&g->cache_hash, c_source_file))) {
8239 fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(c_source_file), err_str(err));
8240 exit(1);
8241 }
8242 if ((err = cache_add_dep_file(&g->cache_hash, out_dep_path, true))) {
8243 fprintf(stderr, "failed to add C source dependencies to cache: %s\n", err_str(err));
8244 exit(1);
8245 }
8246 }
8247}
8248
8249static void gen_c_objects(CodeGen *g) {
8250 Error err;
8251
8252 if (g->c_source_files.length == 0)
8253 return;
8254
8255 Buf *self_exe_path = buf_alloc();
8256 if ((err = os_self_exe_path(self_exe_path))) {
8257 fprintf(stderr, "Unable to get self exe path: %s\n", err_str(err));
8258 exit(1);
8259 }
8260
8261 for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
8262 CFile *c_file = g->c_source_files.at(c_file_i);
8263 gen_c_object(g, self_exe_path, c_file);
8264 }
8265}
8266
8126void codegen_add_object(CodeGen *g, Buf *object_path) {8267void codegen_add_object(CodeGen *g, Buf *object_path) {
8127 g->link_objects.append(object_path);8268 g->link_objects.append(object_path);
8128}8269}
...@@ -8637,6 +8778,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -8637,6 +8778,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
8637 cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);8778 cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
8638 cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);8779 cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
8639 cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);8780 cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);
8781 for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
8782 CFile *c_file = g->c_source_files.at(c_file_i);
8783 cache_file(ch, buf_create_from_str(c_file->source_path));
8784 for (size_t opt_i = 0; opt_i < c_file->args.length; opt_i += 1) {
8785 cache_buf(ch, buf_create_from_str(c_file->args.at(opt_i)));
8786 }
8787 }
8640 cache_int(ch, g->emit_file_type);8788 cache_int(ch, g->emit_file_type);
8641 cache_int(ch, g->build_mode);8789 cache_int(ch, g->build_mode);
8642 cache_int(ch, g->out_type);8790 cache_int(ch, g->out_type);
...@@ -8788,6 +8936,7 @@ void codegen_build_and_link(CodeGen *g) {...@@ -8788,6 +8936,7 @@ void codegen_build_and_link(CodeGen *g) {
87888936
8789 gen_global_asm(g);8937 gen_global_asm(g);
8790 gen_root_source(g);8938 gen_root_source(g);
8939 gen_c_objects(g);
87918940
8792 if (g->enable_cache) {8941 if (g->enable_cache) {
8793 if ((err = cache_final(&g->cache_hash, &digest))) {8942 if ((err = cache_final(&g->cache_hash, &digest))) {
...@@ -8805,16 +8954,25 @@ void codegen_build_and_link(CodeGen *g) {...@@ -8805,16 +8954,25 @@ void codegen_build_and_link(CodeGen *g) {
8805 resolve_out_paths(g);8954 resolve_out_paths(g);
88068955
8807 codegen_add_time_event(g, "Code Generation");8956 codegen_add_time_event(g, "Code Generation");
8808 do_code_gen(g);8957 if (g->out_type == OutTypeObj && g->c_source_files.length == 1) {
8809 codegen_add_time_event(g, "LLVM Emit Output");8958 assert(g->link_objects.length == 1);
8810 zig_llvm_emit_output(g);8959 if ((err = os_rename(g->link_objects.pop(), &g->o_file_output_path))) {
8960 fprintf(stderr, "unable to move object to '%s': %s\n",
8961 buf_ptr(&g->o_file_output_path), err_str(err));
8962 exit(1);
8963 }
8964 } else {
8965 do_code_gen(g);
8966 codegen_add_time_event(g, "LLVM Emit Output");
8967 zig_llvm_emit_output(g);
88118968
8812 if (g->out_h_path != nullptr) {8969 if (g->out_h_path != nullptr) {
8813 codegen_add_time_event(g, "Generate .h");8970 codegen_add_time_event(g, "Generate .h");
8814 gen_h_file(g);8971 gen_h_file(g);
8815 }8972 }
8816 if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {8973 if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {
8817 codegen_link(g);8974 codegen_link(g);
8975 }
8818 }8976 }
8819 }8977 }
88208978
src/codegen.hpp+1
...@@ -41,6 +41,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);...@@ -41,6 +41,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);
41void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);41void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
42void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);42void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
43void codegen_set_output_h_path(CodeGen *g, Buf *h_path);43void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
44void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path);
44void codegen_set_output_path(CodeGen *g, Buf *path);45void codegen_set_output_path(CodeGen *g, Buf *path);
45void codegen_add_time_event(CodeGen *g, const char *name);46void codegen_add_time_event(CodeGen *g, const char *name);
46void codegen_print_timing_report(CodeGen *g, FILE *f);47void codegen_print_timing_report(CodeGen *g, FILE *f);
src/error.cpp+1
...@@ -36,6 +36,7 @@ const char *err_str(Error err) {...@@ -36,6 +36,7 @@ const char *err_str(Error err) {
36 case ErrorCacheUnavailable: return "cache unavailable";36 case ErrorCacheUnavailable: return "cache unavailable";
37 case ErrorPathTooLong: return "path too long";37 case ErrorPathTooLong: return "path too long";
38 case ErrorCCompilerCannotFindFile: return "C compiler cannot find file";38 case ErrorCCompilerCannotFindFile: return "C compiler cannot find file";
39 case ErrorReadingDepFile: return "failed to read .d file";
39 }40 }
40 return "(invalid error)";41 return "(invalid error)";
41}42}
src/error.hpp+1
...@@ -38,6 +38,7 @@ enum Error {...@@ -38,6 +38,7 @@ enum Error {
38 ErrorCacheUnavailable,38 ErrorCacheUnavailable,
39 ErrorPathTooLong,39 ErrorPathTooLong,
40 ErrorCCompilerCannotFindFile,40 ErrorCCompilerCannotFindFile,
41 ErrorReadingDepFile,
41};42};
4243
43const char *err_str(Error err);44const char *err_str(Error err);
src/ir.cpp-6
...@@ -18670,12 +18670,6 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc...@@ -18670,12 +18670,6 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc
18670}18670}
1867118671
18672static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {18672static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
18673 if (ira->codegen->enable_cache) {
18674 ir_add_error(ira, &instruction->base,
18675 buf_sprintf("TODO @cImport is incompatible with --cache on. The cache system currently is unable to detect subsequent changes in .h files."));
18676 return ira->codegen->invalid_instruction;
18677 }
18678
18679 AstNode *node = instruction->base.source_node;18673 AstNode *node = instruction->base.source_node;
18680 assert(node->type == NodeTypeFnCallExpr);18674 assert(node->type == NodeTypeFnCallExpr);
18681 AstNode *block_node = node->data.fn_call_expr.params.at(0);18675 AstNode *block_node = node->data.fn_call_expr.params.at(0);
src/link.cpp+1
...@@ -554,6 +554,7 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -554,6 +554,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
554 bool is_library = g->out_type == OutTypeLib;554 bool is_library = g->out_type == OutTypeLib;
555 switch (g->subsystem) {555 switch (g->subsystem) {
556 case TargetSubsystemAuto:556 case TargetSubsystemAuto:
557 add_nt_link_args(lj, is_library);
557 break;558 break;
558 case TargetSubsystemConsole:559 case TargetSubsystemConsole:
559 lj->args.append("/SUBSYSTEM:console");560 lj->args.append("/SUBSYSTEM:console");
src/main.cpp+73-18
...@@ -18,7 +18,7 @@...@@ -18,7 +18,7 @@
18#include <stdio.h>18#include <stdio.h>
1919
20static int print_error_usage(const char *arg0) {20static int print_error_usage(const char *arg0) {
21 fprintf(stderr, "See `%s help` for detailed usage information\n", arg0);21 fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0);
22 return EXIT_FAILURE;22 return EXIT_FAILURE;
23}23}
2424
...@@ -34,7 +34,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -34,7 +34,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
34 " builtin show the source code of that @import(\"builtin\")\n"34 " builtin show the source code of that @import(\"builtin\")\n"
35 " cc C compiler\n"35 " cc C compiler\n"
36 " fmt parse files and render in canonical zig format\n"36 " fmt parse files and render in canonical zig format\n"
37 " help show this usage information\n"
38 " id print the base64-encoded compiler id\n"37 " id print the base64-encoded compiler id\n"
39 " init-exe initialize a `zig build` application in the cwd\n"38 " init-exe initialize a `zig build` application in the cwd\n"
40 " init-lib initialize a `zig build` library in the cwd\n"39 " init-lib initialize a `zig build` library in the cwd\n"
...@@ -48,6 +47,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -48,6 +47,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
48 "\n"47 "\n"
49 "Compile Options:\n"48 "Compile Options:\n"
50 " --assembly [source] add assembly file to build\n"49 " --assembly [source] add assembly file to build\n"
50 " --c-source [options] [file] compile C source code\n"
51 " --cache-dir [path] override the cache directory\n"51 " --cache-dir [path] override the cache directory\n"
52 " --cache [auto|off|on] build in global cache, print out paths to stdout\n"52 " --cache [auto|off|on] build in global cache, print out paths to stdout\n"
53 " --color [auto|off|on] enable or disable colored error messages\n"53 " --color [auto|off|on] enable or disable colored error messages\n"
...@@ -60,6 +60,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -60,6 +60,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
60 " --name [name] override output name\n"60 " --name [name] override output name\n"
61 " --output [file] override destination path\n"61 " --output [file] override destination path\n"
62 " --output-h [file] generate header file\n"62 " --output-h [file] generate header file\n"
63 " --output-lib [file] override import library path\n"
63 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"64 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
64 " --pkg-end pop current pkg\n"65 " --pkg-end pop current pkg\n"
65 " --release-fast build with optimizations on and safety off\n"66 " --release-fast build with optimizations on and safety off\n"
...@@ -77,6 +78,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -77,6 +78,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
77 " --verbose-ir enable compiler debug output for Zig IR\n"78 " --verbose-ir enable compiler debug output for Zig IR\n"
78 " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"79 " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
79 " --verbose-cimport enable compiler debug output for C imports\n"80 " --verbose-cimport enable compiler debug output for C imports\n"
81 " --verbose-cc enable compiler debug output for C compilation\n"
80 " -dirafter [dir] same as -isystem but do it last\n"82 " -dirafter [dir] same as -isystem but do it last\n"
81 " -isystem [dir] add additional search path for other .h files\n"83 " -isystem [dir] add additional search path for other .h files\n"
82 " -mllvm [arg] forward an arg to LLVM's option processing\n"84 " -mllvm [arg] forward an arg to LLVM's option processing\n"
...@@ -181,7 +183,6 @@ enum Cmd {...@@ -181,7 +183,6 @@ enum Cmd {
181 CmdNone,183 CmdNone,
182 CmdBuild,184 CmdBuild,
183 CmdBuiltin,185 CmdBuiltin,
184 CmdHelp,
185 CmdRun,186 CmdRun,
186 CmdTargets,187 CmdTargets,
187 CmdTest,188 CmdTest,
...@@ -375,6 +376,7 @@ int main(int argc, char **argv) {...@@ -375,6 +376,7 @@ int main(int argc, char **argv) {
375 const char *in_file = nullptr;376 const char *in_file = nullptr;
376 const char *out_file = nullptr;377 const char *out_file = nullptr;
377 const char *out_file_h = nullptr;378 const char *out_file_h = nullptr;
379 const char *out_file_lib = nullptr;
378 bool strip = false;380 bool strip = false;
379 bool is_static = false;381 bool is_static = false;
380 OutType out_type = OutTypeUnknown;382 OutType out_type = OutTypeUnknown;
...@@ -385,6 +387,7 @@ int main(int argc, char **argv) {...@@ -385,6 +387,7 @@ int main(int argc, char **argv) {
385 bool verbose_ir = false;387 bool verbose_ir = false;
386 bool verbose_llvm_ir = false;388 bool verbose_llvm_ir = false;
387 bool verbose_cimport = false;389 bool verbose_cimport = false;
390 bool verbose_cc = false;
388 ErrColor color = ErrColorAuto;391 ErrColor color = ErrColorAuto;
389 CacheOpt enable_cache = CacheOptAuto;392 CacheOpt enable_cache = CacheOptAuto;
390 const char *libc_txt = nullptr;393 const char *libc_txt = nullptr;
...@@ -404,6 +407,7 @@ int main(int argc, char **argv) {...@@ -404,6 +407,7 @@ int main(int argc, char **argv) {
404 ZigList<const char *> rpath_list = {0};407 ZigList<const char *> rpath_list = {0};
405 bool each_lib_rpath = false;408 bool each_lib_rpath = false;
406 ZigList<const char *> objects = {0};409 ZigList<const char *> objects = {0};
410 ZigList<CFile *> c_source_files = {0};
407 ZigList<const char *> asm_files = {0};411 ZigList<const char *> asm_files = {0};
408 const char *test_filter = nullptr;412 const char *test_filter = nullptr;
409 const char *test_name_prefix = nullptr;413 const char *test_name_prefix = nullptr;
...@@ -512,6 +516,7 @@ int main(int argc, char **argv) {...@@ -512,6 +516,7 @@ int main(int argc, char **argv) {
512 " --verbose-ir Enable compiler debug output for Zig IR\n"516 " --verbose-ir Enable compiler debug output for Zig IR\n"
513 " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"517 " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
514 " --verbose-cimport Enable compiler debug output for C imports\n"518 " --verbose-cimport Enable compiler debug output for C imports\n"
519 " --verbose-cc Enable compiler debug output for C compilation\n"
515 "\n"520 "\n"
516 , zig_exe_path);521 , zig_exe_path);
517 return EXIT_SUCCESS;522 return EXIT_SUCCESS;
...@@ -521,7 +526,7 @@ int main(int argc, char **argv) {...@@ -521,7 +526,7 @@ int main(int argc, char **argv) {
521 "No 'build.zig' file found.\n"526 "No 'build.zig' file found.\n"
522 "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"527 "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"
523 "or build an executable directly with `zig build-exe $FILENAME.zig`.\n"528 "or build an executable directly with `zig build-exe $FILENAME.zig`.\n"
524 "See: `zig build --help` or `zig help` for more options.\n"529 "See: `zig build --help` or `zig --help` for more options.\n"
525 );530 );
526 return EXIT_FAILURE;531 return EXIT_FAILURE;
527 }532 }
...@@ -587,9 +592,9 @@ int main(int argc, char **argv) {...@@ -587,9 +592,9 @@ int main(int argc, char **argv) {
587 build_mode = BuildModeSmallRelease;592 build_mode = BuildModeSmallRelease;
588 } else if (strcmp(arg, "--help") == 0) {593 } else if (strcmp(arg, "--help") == 0) {
589 if (cmd == CmdLibC) {594 if (cmd == CmdLibC) {
590 return print_libc_usage(arg0, stderr, EXIT_FAILURE);595 return print_libc_usage(arg0, stdout, EXIT_SUCCESS);
591 } else {596 } else {
592 return print_full_usage(arg0, stderr, EXIT_FAILURE);597 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
593 }598 }
594 } else if (strcmp(arg, "--strip") == 0) {599 } else if (strcmp(arg, "--strip") == 0) {
595 strip = true;600 strip = true;
...@@ -607,6 +612,8 @@ int main(int argc, char **argv) {...@@ -607,6 +612,8 @@ int main(int argc, char **argv) {
607 verbose_llvm_ir = true;612 verbose_llvm_ir = true;
608 } else if (strcmp(arg, "--verbose-cimport") == 0) {613 } else if (strcmp(arg, "--verbose-cimport") == 0) {
609 verbose_cimport = true;614 verbose_cimport = true;
615 } else if (strcmp(arg, "--verbose-cc") == 0) {
616 verbose_cc = true;
610 } else if (strcmp(arg, "-rdynamic") == 0) {617 } else if (strcmp(arg, "-rdynamic") == 0) {
611 rdynamic = true;618 rdynamic = true;
612 } else if (strcmp(arg, "--each-lib-rpath") == 0) {619 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
...@@ -656,6 +663,8 @@ int main(int argc, char **argv) {...@@ -656,6 +663,8 @@ int main(int argc, char **argv) {
656 out_file = argv[i];663 out_file = argv[i];
657 } else if (strcmp(arg, "--output-h") == 0) {664 } else if (strcmp(arg, "--output-h") == 0) {
658 out_file_h = argv[i];665 out_file_h = argv[i];
666 } else if (strcmp(arg, "--output-lib") == 0) {
667 out_file_lib = argv[i];
659 } else if (strcmp(arg, "--color") == 0) {668 } else if (strcmp(arg, "--color") == 0) {
660 if (strcmp(argv[i], "auto") == 0) {669 if (strcmp(argv[i], "auto") == 0) {
661 color = ErrColorAuto;670 color = ErrColorAuto;
...@@ -714,6 +723,19 @@ int main(int argc, char **argv) {...@@ -714,6 +723,19 @@ int main(int argc, char **argv) {
714 forbidden_link_libs.append(argv[i]);723 forbidden_link_libs.append(argv[i]);
715 } else if (strcmp(arg, "--object") == 0) {724 } else if (strcmp(arg, "--object") == 0) {
716 objects.append(argv[i]);725 objects.append(argv[i]);
726 } else if (strcmp(arg, "--c-source") == 0) {
727 CFile *c_file = allocate<CFile>(1);
728 for (;;) {
729 if (argv[i][0] == '-') {
730 c_file->args.append(argv[i]);
731 i += 1;
732 continue;
733 } else {
734 c_file->source_path = argv[i];
735 c_source_files.append(c_file);
736 break;
737 }
738 }
717 } else if (strcmp(arg, "--assembly") == 0) {739 } else if (strcmp(arg, "--assembly") == 0) {
718 asm_files.append(argv[i]);740 asm_files.append(argv[i]);
719 } else if (strcmp(arg, "--cache-dir") == 0) {741 } else if (strcmp(arg, "--cache-dir") == 0) {
...@@ -792,8 +814,6 @@ int main(int argc, char **argv) {...@@ -792,8 +814,6 @@ int main(int argc, char **argv) {
792 } else if (strcmp(arg, "build-lib") == 0) {814 } else if (strcmp(arg, "build-lib") == 0) {
793 cmd = CmdBuild;815 cmd = CmdBuild;
794 out_type = OutTypeLib;816 out_type = OutTypeLib;
795 } else if (strcmp(arg, "help") == 0) {
796 cmd = CmdHelp;
797 } else if (strcmp(arg, "run") == 0) {817 } else if (strcmp(arg, "run") == 0) {
798 cmd = CmdRun;818 cmd = CmdRun;
799 out_type = OutTypeExe;819 out_type = OutTypeExe;
...@@ -835,7 +855,6 @@ int main(int argc, char **argv) {...@@ -835,7 +855,6 @@ int main(int argc, char **argv) {
835 }855 }
836 break;856 break;
837 case CmdBuiltin:857 case CmdBuiltin:
838 case CmdHelp:
839 case CmdVersion:858 case CmdVersion:
840 case CmdZen:859 case CmdZen:
841 case CmdTargets:860 case CmdTargets:
...@@ -910,15 +929,43 @@ int main(int argc, char **argv) {...@@ -910,15 +929,43 @@ int main(int argc, char **argv) {
910 case CmdTranslateC:929 case CmdTranslateC:
911 case CmdTest:930 case CmdTest:
912 {931 {
913 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {932 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 &&
914 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");933 c_source_files.length == 0)
934 {
935 fprintf(stderr,
936 "Expected at least one of these things:\n"
937 " * Zig root source file argument\n"
938 " * --object argument\n"
939 " * --assembly argument\n"
940 " * --c-source argument\n");
915 return print_error_usage(arg0);941 return print_error_usage(arg0);
916 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {942 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
917 fprintf(stderr, "Expected source file argument.\n");943 fprintf(stderr, "Expected source file argument.\n");
918 return print_error_usage(arg0);944 return print_error_usage(arg0);
919 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {945 } else if (cmd == CmdBuild && out_type == OutTypeObj) {
920 fprintf(stderr, "When building an object file, --object arguments are invalid.\n");946 if (objects.length != 0) {
921 return print_error_usage(arg0);947 fprintf(stderr,
948 "When building an object file, --object arguments are invalid.\n"
949 "Consider building a static library instead.\n");
950 return print_error_usage(arg0);
951 }
952 size_t zig_root_src_count = in_file ? 1 : 0;
953 if (zig_root_src_count + c_source_files.length > 1) {
954 fprintf(stderr,
955 "When building an object file, only one of these allowed:\n"
956 " * Zig root source file argument\n"
957 " * --c-source argument\n"
958 "Consider building a static library instead.\n");
959 return print_error_usage(arg0);
960 }
961 if (c_source_files.length != 0 && asm_files.length != 0) {
962 fprintf(stderr,
963 "When building an object file, only one of these allowed:\n"
964 " * --assembly argument\n"
965 " * --c-source argument\n"
966 "Consider building a static library instead.\n");
967 return print_error_usage(arg0);
968 }
922 }969 }
923970
924 assert(cmd != CmdBuild || out_type != OutTypeUnknown);971 assert(cmd != CmdBuild || out_type != OutTypeUnknown);
...@@ -945,6 +992,13 @@ int main(int argc, char **argv) {...@@ -945,6 +992,13 @@ int main(int argc, char **argv) {
945 }992 }
946 }993 }
947994
995 if (need_name && buf_out_name == nullptr && c_source_files.length == 1) {
996 Buf basename = BUF_INIT;
997 os_path_split(buf_create_from_str(c_source_files.at(0)->source_path), nullptr, &basename);
998 buf_out_name = buf_alloc();
999 os_path_extname(&basename, buf_out_name, nullptr);
1000 }
1001
948 if (need_name && buf_out_name == nullptr) {1002 if (need_name && buf_out_name == nullptr) {
949 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");1003 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
950 return print_error_usage(arg0);1004 return print_error_usage(arg0);
...@@ -996,6 +1050,7 @@ int main(int argc, char **argv) {...@@ -996,6 +1050,7 @@ int main(int argc, char **argv) {
996 g->verbose_ir = verbose_ir;1050 g->verbose_ir = verbose_ir;
997 g->verbose_llvm_ir = verbose_llvm_ir;1051 g->verbose_llvm_ir = verbose_llvm_ir;
998 g->verbose_cimport = verbose_cimport;1052 g->verbose_cimport = verbose_cimport;
1053 g->verbose_cc = verbose_cc;
999 codegen_set_errmsg_color(g, color);1054 codegen_set_errmsg_color(g, color);
1000 g->system_linker_hack = system_linker_hack;1055 g->system_linker_hack = system_linker_hack;
10011056
...@@ -1043,11 +1098,14 @@ int main(int argc, char **argv) {...@@ -1043,11 +1098,14 @@ int main(int argc, char **argv) {
1043 codegen_set_output_path(g, buf_create_from_str(out_file));1098 codegen_set_output_path(g, buf_create_from_str(out_file));
1044 if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))1099 if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))
1045 codegen_set_output_h_path(g, buf_create_from_str(out_file_h));1100 codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
1101 if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
1102 codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
10461103
10471104
1048 add_package(g, cur_pkg, g->root_package);1105 add_package(g, cur_pkg, g->root_package);
10491106
1050 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {1107 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
1108 g->c_source_files = c_source_files;
1051 for (size_t i = 0; i < objects.length; i += 1) {1109 for (size_t i = 0; i < objects.length; i += 1) {
1052 codegen_add_object(g, buf_create_from_str(objects.at(i)));1110 codegen_add_object(g, buf_create_from_str(objects.at(i)));
1053 }1111 }
...@@ -1147,8 +1205,6 @@ int main(int argc, char **argv) {...@@ -1147,8 +1205,6 @@ int main(int argc, char **argv) {
1147 zig_unreachable();1205 zig_unreachable();
1148 }1206 }
1149 }1207 }
1150 case CmdHelp:
1151 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
1152 case CmdVersion:1208 case CmdVersion:
1153 printf("%s\n", ZIG_VERSION_STRING);1209 printf("%s\n", ZIG_VERSION_STRING);
1154 return EXIT_SUCCESS;1210 return EXIT_SUCCESS;
...@@ -1158,7 +1214,6 @@ int main(int argc, char **argv) {...@@ -1158,7 +1214,6 @@ int main(int argc, char **argv) {
1158 case CmdTargets:1214 case CmdTargets:
1159 return print_target_list(stdout);1215 return print_target_list(stdout);
1160 case CmdNone:1216 case CmdNone:
1161 fprintf(stderr, "Zig programming language\n");1217 return print_full_usage(arg0, stderr, EXIT_FAILURE);
1162 return print_error_usage(arg0);
1163 }1218 }
1164}1219}
src/os.cpp+12
...@@ -1232,6 +1232,18 @@ static Error os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_p...@@ -1232,6 +1232,18 @@ static Error os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_p
1232}1232}
1233#endif1233#endif
12341234
1235Buf *os_tmp_filename(Buf *prefix, Buf *suffix) {
1236 Buf *result = buf_create_from_buf(prefix);
1237
1238 const char base64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1239 assert(array_length(base64) == 64 + 1);
1240 for (size_t i = 0; i < 12; i += 1) {
1241 buf_append_char(result, base64[rand() % 64]);
1242 }
1243 buf_append_buf(result, suffix);
1244 return result;
1245}
1246
1235#if defined(ZIG_OS_WINDOWS)1247#if defined(ZIG_OS_WINDOWS)
1236static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) {1248static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
1237 char tmp_dir[MAX_PATH + 1];1249 char tmp_dir[MAX_PATH + 1];
src/os.hpp+1
...@@ -121,6 +121,7 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);...@@ -121,6 +121,7 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);
121bool os_stderr_tty(void);121bool os_stderr_tty(void);
122void os_stderr_set_color(TermColor color);122void os_stderr_set_color(TermColor color);
123123
124Buf *os_tmp_filename(Buf *prefix, Buf *suffix);
124Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);125Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
125Error os_delete_file(Buf *path);126Error os_delete_file(Buf *path);
126127
src/target.cpp+6
...@@ -1049,3 +1049,9 @@ bool target_requires_libc(const ZigTarget *target) {...@@ -1049,3 +1049,9 @@ bool target_requires_libc(const ZigTarget *target) {
1049 // since this is the stable syscall interface.1049 // since this is the stable syscall interface.
1050 return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD);1050 return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD);
1051}1051}
1052
1053bool target_supports_fpic(const ZigTarget *target) {
1054 // This is not whether the target supports Position Independent Code, but whether the -fPIC
1055 // C compiler argument is valid.
1056 return target->os != OsWindows;
1057}
src/target.hpp+1
...@@ -141,5 +141,6 @@ bool target_allows_addr_zero(const ZigTarget *target);...@@ -141,5 +141,6 @@ bool target_allows_addr_zero(const ZigTarget *target);
141bool target_has_valgrind_support(const ZigTarget *target);141bool target_has_valgrind_support(const ZigTarget *target);
142bool target_is_darwin(const ZigTarget *target);142bool target_is_darwin(const ZigTarget *target);
143bool target_requires_libc(const ZigTarget *target);143bool target_requires_libc(const ZigTarget *target);
144bool target_supports_fpic(const ZigTarget *target);
144145
145#endif146#endif
src/translate_c.cpp+20
...@@ -4776,6 +4776,15 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const...@@ -4776,6 +4776,15 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
4776 clang_argv.append("-x");4776 clang_argv.append("-x");
4777 clang_argv.append("c");4777 clang_argv.append("c");
47784778
4779 Buf *out_dep_path = nullptr;
4780 if (codegen->enable_cache) {
4781 Buf *prefix = buf_sprintf("%s" OS_SEP, buf_ptr(&codegen->cache_dir));
4782 out_dep_path = os_tmp_filename(prefix, buf_create_from_str(".d"));
4783 clang_argv.append("-MD");
4784 clang_argv.append("-MF");
4785 clang_argv.append(buf_ptr(out_dep_path));
4786 }
4787
4779 if (c->codegen->zig_target->is_native) {4788 if (c->codegen->zig_target->is_native) {
4780 char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS");4789 char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS");
4781 if (ZIG_PARSEC_CFLAGS) {4790 if (ZIG_PARSEC_CFLAGS) {
...@@ -4912,6 +4921,17 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const...@@ -4912,6 +4921,17 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
4912 return ErrorCCompileErrors;4921 return ErrorCCompileErrors;
4913 }4922 }
49144923
4924 if (codegen->enable_cache) {
4925 Error err;
4926 assert(out_dep_path != nullptr);
4927 if ((err = cache_add_dep_file(&codegen->cache_hash, out_dep_path, codegen->verbose_cimport))) {
4928 if (codegen->verbose_cimport) {
4929 fprintf(stderr, "translate-c: aborting due to failed cache operation: %s\n", err_str(err));
4930 }
4931 return err;
4932 }
4933 }
4934
4915 c->ctx = ZigClangASTUnit_getASTContext(ast_unit);4935 c->ctx = ZigClangASTUnit_getASTContext(ast_unit);
4916 c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit);4936 c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit);
4917 c->root = trans_create_node(c, NodeTypeContainerDecl);4937 c->root = trans_create_node(c, NodeTypeContainerDecl);
std/buf_set.zig+4
...@@ -32,6 +32,10 @@ pub const BufSet = struct {...@@ -32,6 +32,10 @@ pub const BufSet = struct {
32 }32 }
33 }33 }
3434
35 pub fn exists(self: BufSet, key: []const u8) bool {
36 return self.hash_map.get(key) != null;
37 }
38
35 pub fn delete(self: *BufSet, key: []const u8) void {39 pub fn delete(self: *BufSet, key: []const u8) void {
36 const entry = self.hash_map.remove(key) orelse return;40 const entry = self.hash_map.remove(key) orelse return;
37 self.free(entry.key);41 self.free(entry.key);
std/build.zig+151-688
...@@ -31,6 +31,7 @@ pub const Builder = struct {...@@ -31,6 +31,7 @@ pub const Builder = struct {
31 verbose_tokenize: bool,31 verbose_tokenize: bool,
32 verbose_ast: bool,32 verbose_ast: bool,
33 verbose_link: bool,33 verbose_link: bool,
34 verbose_cc: bool,
34 verbose_ir: bool,35 verbose_ir: bool,
35 verbose_llvm_ir: bool,36 verbose_llvm_ir: bool,
36 verbose_cimport: bool,37 verbose_cimport: bool,
...@@ -99,6 +100,7 @@ pub const Builder = struct {...@@ -99,6 +100,7 @@ pub const Builder = struct {
99 .verbose_tokenize = false,100 .verbose_tokenize = false,
100 .verbose_ast = false,101 .verbose_ast = false,
101 .verbose_link = false,102 .verbose_link = false,
103 .verbose_cc = false,
102 .verbose_ir = false,104 .verbose_ir = false,
103 .verbose_llvm_ir = false,105 .verbose_llvm_ir = false,
104 .verbose_cimport = false,106 .verbose_cimport = false,
...@@ -157,7 +159,7 @@ pub const Builder = struct {...@@ -157,7 +159,7 @@ pub const Builder = struct {
157 return LibExeObjStep.createExecutable(self, name, root_src, true);159 return LibExeObjStep.createExecutable(self, name, root_src, true);
158 }160 }
159161
160 pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {162 pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
161 return LibExeObjStep.createObject(self, name, root_src);163 return LibExeObjStep.createObject(self, name, root_src);
162 }164 }
163165
...@@ -169,10 +171,8 @@ pub const Builder = struct {...@@ -169,10 +171,8 @@ pub const Builder = struct {
169 return LibExeObjStep.createStaticLibrary(self, name, root_src);171 return LibExeObjStep.createStaticLibrary(self, name, root_src);
170 }172 }
171173
172 pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {174 pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep {
173 const test_step = self.allocator.create(TestStep) catch unreachable;175 return LibExeObjStep.createTest(self, "test", root_src);
174 test_step.* = TestStep.init(self, root_src);
175 return test_step;
176 }176 }
177177
178 pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {178 pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
...@@ -181,22 +181,6 @@ pub const Builder = struct {...@@ -181,22 +181,6 @@ pub const Builder = struct {
181 return obj_step;181 return obj_step;
182 }182 }
183183
184 pub fn addCStaticLibrary(self: *Builder, name: []const u8) *LibExeObjStep {
185 return LibExeObjStep.createCStaticLibrary(self, name);
186 }
187
188 pub fn addCSharedLibrary(self: *Builder, name: []const u8, ver: Version) *LibExeObjStep {
189 return LibExeObjStep.createCSharedLibrary(self, name, ver);
190 }
191
192 pub fn addCExecutable(self: *Builder, name: []const u8) *LibExeObjStep {
193 return LibExeObjStep.createCExecutable(self, name);
194 }
195
196 pub fn addCObject(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
197 return LibExeObjStep.createCObject(self, name, src);
198 }
199
200 /// ::argv is copied.184 /// ::argv is copied.
201 pub fn addCommand(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {185 pub fn addCommand(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
202 return CommandStep.create(self, cwd, env_map, argv);186 return CommandStep.create(self, cwd, env_map, argv);
...@@ -663,14 +647,6 @@ pub const Builder = struct {...@@ -663,14 +647,6 @@ pub const Builder = struct {
663 return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable;647 return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable;
664 }648 }
665649
666 fn getCCExe(self: *Builder) []const u8 {
667 if (builtin.environ == builtin.Environ.msvc) {
668 return "cl.exe";
669 } else {
670 return os.getEnvVarOwned(self.allocator, "CC") catch |err| if (err == error.EnvironmentVariableNotFound) ([]const u8)("cc") else debug.panic("Unable to get environment variable: {}", err);
671 }
672 }
673
674 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {650 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
675 // TODO report error for ambiguous situations651 // TODO report error for ambiguous situations
676 const exe_extension = (Target{ .Native = {} }).exeFileExt();652 const exe_extension = (Target{ .Native = {} }).exeFileExt();
...@@ -825,6 +801,11 @@ const Pkg = struct {...@@ -825,6 +801,11 @@ const Pkg = struct {
825 path: []const u8,801 path: []const u8,
826};802};
827803
804const CSourceFile = struct {
805 source_path: []const u8,
806 args: []const []const u8,
807};
808
828pub const LibExeObjStep = struct {809pub const LibExeObjStep = struct {
829 step: Step,810 step: Step,
830 builder: *Builder,811 builder: *Builder,
...@@ -834,6 +815,7 @@ pub const LibExeObjStep = struct {...@@ -834,6 +815,7 @@ pub const LibExeObjStep = struct {
834 linker_script: ?[]const u8,815 linker_script: ?[]const u8,
835 out_filename: []const u8,816 out_filename: []const u8,
836 output_path: ?[]const u8,817 output_path: ?[]const u8,
818 output_lib_path: ?[]const u8,
837 static: bool,819 static: bool,
838 version: Version,820 version: Version,
839 object_files: ArrayList([]const u8),821 object_files: ArrayList([]const u8),
...@@ -844,32 +826,34 @@ pub const LibExeObjStep = struct {...@@ -844,32 +826,34 @@ pub const LibExeObjStep = struct {
844 strip: bool,826 strip: bool,
845 full_path_libs: ArrayList([]const u8),827 full_path_libs: ArrayList([]const u8),
846 need_flat_namespace_hack: bool,828 need_flat_namespace_hack: bool,
847 is_zig: bool,
848 cflags: ArrayList([]const u8),
849 include_dirs: ArrayList([]const u8),829 include_dirs: ArrayList([]const u8),
850 lib_paths: ArrayList([]const u8),830 lib_paths: ArrayList([]const u8),
851 disable_libc: bool,
852 frameworks: BufSet,831 frameworks: BufSet,
853 verbose_link: bool,832 verbose_link: bool,
833 verbose_cc: bool,
854 c_std: Builder.CStd,834 c_std: Builder.CStd,
835 override_std_dir: ?[]const u8,
836 exec_cmd_args: ?[]const ?[]const u8,
837 name_prefix: []const u8,
838 filter: ?[]const u8,
855839
856 // zig only stuff
857 root_src: ?[]const u8,840 root_src: ?[]const u8,
858 output_h_path: ?[]const u8,841 output_h_path: ?[]const u8,
859 out_h_filename: []const u8,842 out_h_filename: []const u8,
843 out_lib_filename: []const u8,
860 assembly_files: ArrayList([]const u8),844 assembly_files: ArrayList([]const u8),
861 packages: ArrayList(Pkg),845 packages: ArrayList(Pkg),
862 build_options_contents: std.Buffer,846 build_options_contents: std.Buffer,
863 system_linker_hack: bool,847 system_linker_hack: bool,
864848
865 // C only stuff849 c_source_files: ArrayList(*CSourceFile),
866 source_files: ArrayList([]const u8),
867 object_src: []const u8,850 object_src: []const u8,
868851
869 const Kind = enum {852 const Kind = enum {
870 Exe,853 Exe,
871 Lib,854 Lib,
872 Obj,855 Obj,
856 Test,
873 };857 };
874858
875 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {859 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {
...@@ -878,46 +862,27 @@ pub const LibExeObjStep = struct {...@@ -878,46 +862,27 @@ pub const LibExeObjStep = struct {
878 return self;862 return self;
879 }863 }
880864
881 pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: Version) *LibExeObjStep {
882 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
883 self.* = initC(builder, name, Kind.Lib, version, false);
884 return self;
885 }
886
887 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {865 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
888 const self = builder.allocator.create(LibExeObjStep) catch unreachable;866 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
889 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));867 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
890 return self;868 return self;
891 }869 }
892870
893 pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {871 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
894 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
895 self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
896 return self;
897 }
898
899 pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
900 const self = builder.allocator.create(LibExeObjStep) catch unreachable;872 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
901 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));873 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
902 return self;874 return self;
903 }875 }
904876
905 pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
906 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
907 self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
908 self.object_src = src;
909 return self;
910 }
911
912 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {877 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
913 const self = builder.allocator.create(LibExeObjStep) catch unreachable;878 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
914 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));879 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));
915 return self;880 return self;
916 }881 }
917882
918 pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {883 pub fn createTest(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
919 const self = builder.allocator.create(LibExeObjStep) catch unreachable;884 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
920 self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);885 self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, builder.version(0, 0, 0));
921 return self;886 return self;
922 }887 }
923888
...@@ -926,6 +891,7 @@ pub const LibExeObjStep = struct {...@@ -926,6 +891,7 @@ pub const LibExeObjStep = struct {
926 .strip = false,891 .strip = false,
927 .builder = builder,892 .builder = builder,
928 .verbose_link = false,893 .verbose_link = false,
894 .verbose_cc = false,
929 .build_mode = builtin.Mode.Debug,895 .build_mode = builtin.Mode.Debug,
930 .static = static,896 .static = static,
931 .kind = kind,897 .kind = kind,
...@@ -937,70 +903,30 @@ pub const LibExeObjStep = struct {...@@ -937,70 +903,30 @@ pub const LibExeObjStep = struct {
937 .frameworks = BufSet.init(builder.allocator),903 .frameworks = BufSet.init(builder.allocator),
938 .step = Step.init(name, builder.allocator, make),904 .step = Step.init(name, builder.allocator, make),
939 .output_path = null,905 .output_path = null,
906 .output_lib_path = null,
940 .output_h_path = null,907 .output_h_path = null,
941 .version = ver,908 .version = ver,
942 .out_filename = undefined,909 .out_filename = undefined,
943 .out_h_filename = builder.fmt("{}.h", name),910 .out_h_filename = builder.fmt("{}.h", name),
911 .out_lib_filename = undefined,
944 .major_only_filename = undefined,912 .major_only_filename = undefined,
945 .name_only_filename = undefined,913 .name_only_filename = undefined,
946 .object_files = ArrayList([]const u8).init(builder.allocator),914 .object_files = ArrayList([]const u8).init(builder.allocator),
947 .assembly_files = ArrayList([]const u8).init(builder.allocator),915 .assembly_files = ArrayList([]const u8).init(builder.allocator),
948 .packages = ArrayList(Pkg).init(builder.allocator),916 .packages = ArrayList(Pkg).init(builder.allocator),
949 .is_zig = true,
950 .full_path_libs = ArrayList([]const u8).init(builder.allocator),917 .full_path_libs = ArrayList([]const u8).init(builder.allocator),
951 .need_flat_namespace_hack = false,918 .need_flat_namespace_hack = false,
952 .cflags = ArrayList([]const u8).init(builder.allocator),919 .c_source_files = ArrayList(*CSourceFile).init(builder.allocator),
953 .source_files = undefined,
954 .include_dirs = ArrayList([]const u8).init(builder.allocator),920 .include_dirs = ArrayList([]const u8).init(builder.allocator),
955 .lib_paths = ArrayList([]const u8).init(builder.allocator),921 .lib_paths = ArrayList([]const u8).init(builder.allocator),
956 .object_src = undefined,922 .object_src = undefined,
957 .disable_libc = true,
958 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,923 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
959 .c_std = Builder.CStd.C99,924 .c_std = Builder.CStd.C99,
960 .system_linker_hack = false,925 .system_linker_hack = false,
961 };926 .override_std_dir = null,
962 self.computeOutFileNames();927 .exec_cmd_args = null,
963 return self;928 .name_prefix = "",
964 }929 .filter = null,
965
966 fn initC(builder: *Builder, name: []const u8, kind: Kind, version: Version, static: bool) LibExeObjStep {
967 var self = LibExeObjStep{
968 .builder = builder,
969 .name = name,
970 .kind = kind,
971 .version = version,
972 .static = static,
973 .target = Target.Native,
974 .cflags = ArrayList([]const u8).init(builder.allocator),
975 .source_files = ArrayList([]const u8).init(builder.allocator),
976 .object_files = ArrayList([]const u8).init(builder.allocator),
977 .step = Step.init(name, builder.allocator, make),
978 .link_libs = BufSet.init(builder.allocator),
979 .frameworks = BufSet.init(builder.allocator),
980 .full_path_libs = ArrayList([]const u8).init(builder.allocator),
981 .include_dirs = ArrayList([]const u8).init(builder.allocator),
982 .lib_paths = ArrayList([]const u8).init(builder.allocator),
983 .output_path = null,
984 .out_filename = undefined,
985 .major_only_filename = undefined,
986 .name_only_filename = undefined,
987 .object_src = undefined,
988 .build_mode = builtin.Mode.Debug,
989 .strip = false,
990 .need_flat_namespace_hack = false,
991 .disable_libc = false,
992 .is_zig = false,
993 .linker_script = null,
994 .c_std = Builder.CStd.C99,
995 .system_linker_hack = false,
996
997 .root_src = undefined,
998 .verbose_link = false,
999 .output_h_path = undefined,
1000 .out_h_filename = undefined,
1001 .assembly_files = undefined,
1002 .packages = undefined,
1003 .build_options_contents = undefined,
1004 };930 };
1005 self.computeOutFileNames();931 self.computeOutFileNames();
1006 return self;932 return self;
...@@ -1014,23 +940,37 @@ pub const LibExeObjStep = struct {...@@ -1014,23 +940,37 @@ pub const LibExeObjStep = struct {
1014 Kind.Exe => {940 Kind.Exe => {
1015 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());941 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
1016 },942 },
943 Kind.Test => {
944 self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());
945 },
1017 Kind.Lib => {946 Kind.Lib => {
1018 if (self.static) {947 if (self.static) {
1019 self.out_filename = self.builder.fmt("lib{}.a", self.name);948 switch (self.target.getOs()) {
949 builtin.Os.windows => {
950 self.out_filename = self.builder.fmt("{}.lib", self.name);
951 },
952 else => {
953 self.out_filename = self.builder.fmt("lib{}.a", self.name);
954 },
955 }
956 self.out_lib_filename = self.out_filename;
1020 } else {957 } else {
1021 switch (self.target.getOs()) {958 switch (self.target.getOs()) {
1022 builtin.Os.ios, builtin.Os.macosx => {959 builtin.Os.ios, builtin.Os.macosx => {
1023 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);960 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
1024 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);961 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
1025 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);962 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
963 self.out_lib_filename = self.out_filename;
1026 },964 },
1027 builtin.Os.windows => {965 builtin.Os.windows => {
1028 self.out_filename = self.builder.fmt("{}.dll", self.name);966 self.out_filename = self.builder.fmt("{}.dll", self.name);
967 self.out_lib_filename = self.builder.fmt("{}.lib", self.name);
1029 },968 },
1030 else => {969 else => {
1031 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);970 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
1032 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);971 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
1033 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);972 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
973 self.out_lib_filename = self.out_filename;
1034 },974 },
1035 }975 }
1036 }976 }
...@@ -1065,7 +1005,11 @@ pub const LibExeObjStep = struct {...@@ -1065,7 +1005,11 @@ pub const LibExeObjStep = struct {
10651005
1066 self.step.dependOn(&lib.step);1006 self.step.dependOn(&lib.step);
10671007
1068 self.full_path_libs.append(lib.getOutputPath()) catch unreachable;1008 if (lib.static or self.target.isWindows()) {
1009 self.object_files.append(lib.getOutputLibPath()) catch unreachable;
1010 } else {
1011 self.full_path_libs.append(lib.getOutputPath()) catch unreachable;
1012 }
10691013
1070 // TODO should be some kind of isolated directory that only has this header in it1014 // TODO should be some kind of isolated directory that only has this header in it
1071 self.include_dirs.append(self.builder.cache_root) catch unreachable;1015 self.include_dirs.append(self.builder.cache_root) catch unreachable;
...@@ -1081,24 +1025,44 @@ pub const LibExeObjStep = struct {...@@ -1081,24 +1025,44 @@ pub const LibExeObjStep = struct {
1081 }1025 }
10821026
1083 pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {1027 pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
1084 assert(self.kind != Kind.Obj);
1085 self.link_libs.put(name) catch unreachable;1028 self.link_libs.put(name) catch unreachable;
1086 }1029 }
10871030
1088 pub fn addSourceFile(self: *LibExeObjStep, file: []const u8) void {1031 pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
1089 assert(self.kind != Kind.Obj);1032 assert(self.kind == Kind.Test);
1090 assert(!self.is_zig);1033 self.name_prefix = text;
1091 self.source_files.append(file) catch unreachable;1034 }
1035
1036 pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void {
1037 assert(self.kind == Kind.Test);
1038 self.filter = text;
1039 }
1040
1041 pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, args: []const []const u8) void {
1042 const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
1043 c_source_file.* = CSourceFile{
1044 .source_path = file,
1045 .args = args,
1046 };
1047 self.c_source_files.append(c_source_file) catch unreachable;
1092 }1048 }
10931049
1094 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {1050 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
1095 self.verbose_link = value;1051 self.verbose_link = value;
1096 }1052 }
10971053
1054 pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void {
1055 self.verbose_cc = value;
1056 }
1057
1098 pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {1058 pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {
1099 self.build_mode = mode;1059 self.build_mode = mode;
1100 }1060 }
11011061
1062 pub fn overrideStdDir(self: *LibExeObjStep, dir_path: []const u8) void {
1063 self.override_std_dir = dir_path;
1064 }
1065
1102 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {1066 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
1103 self.output_path = file_path;1067 self.output_path = file_path;
11041068
...@@ -1115,6 +1079,22 @@ pub const LibExeObjStep = struct {...@@ -1115,6 +1079,22 @@ pub const LibExeObjStep = struct {
1115 ) catch unreachable;1079 ) catch unreachable;
1116 }1080 }
11171081
1082 pub fn setOutputLibPath(self: *LibExeObjStep, file_path: []const u8) void {
1083 assert(self.kind == Kind.Lib);
1084 if (self.static)
1085 return self.setOutputPath(file_path);
1086
1087 self.output_lib_path = file_path;
1088 }
1089
1090 pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {
1091 assert(self.kind == Kind.Lib);
1092 return if (self.output_lib_path) |output_lib_path| output_lib_path else os.path.join(
1093 self.builder.allocator,
1094 [][]const u8{ self.builder.cache_root, self.out_lib_filename },
1095 ) catch unreachable;
1096 }
1097
1118 pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {1098 pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
1119 self.output_h_path = file_path;1099 self.output_h_path = file_path;
11201100
...@@ -1149,17 +1129,15 @@ pub const LibExeObjStep = struct {...@@ -1149,17 +1129,15 @@ pub const LibExeObjStep = struct {
11491129
1150 self.object_files.append(obj.getOutputPath()) catch unreachable;1130 self.object_files.append(obj.getOutputPath()) catch unreachable;
11511131
1152 // TODO make this lazy instead of stateful
1153 if (!obj.disable_libc) {
1154 self.disable_libc = false;
1155 }
1156
1157 // TODO should be some kind of isolated directory that only has this header in it1132 // TODO should be some kind of isolated directory that only has this header in it
1158 self.include_dirs.append(self.builder.cache_root) catch unreachable;1133 self.include_dirs.append(self.builder.cache_root) catch unreachable;
1134
1135 if (obj.link_libs.exists("c")) {
1136 self.link_libs.put("c") catch unreachable;
1137 }
1159 }1138 }
11601139
1161 pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {1140 pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {
1162 assert(self.is_zig);
1163 const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream;1141 const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream;
1164 out.print("pub const {} = {};\n", name, value) catch unreachable;1142 out.print("pub const {} = {};\n", name, value) catch unreachable;
1165 }1143 }
...@@ -1173,23 +1151,15 @@ pub const LibExeObjStep = struct {...@@ -1173,23 +1151,15 @@ pub const LibExeObjStep = struct {
1173 }1151 }
11741152
1175 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {1153 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
1176 assert(self.is_zig);
1177
1178 self.packages.append(Pkg{1154 self.packages.append(Pkg{
1179 .name = name,1155 .name = name,
1180 .path = pkg_index_path,1156 .path = pkg_index_path,
1181 }) catch unreachable;1157 }) catch unreachable;
1182 }1158 }
11831159
1184 pub fn addCompileFlags(self: *LibExeObjStep, flags: []const []const u8) void {1160 pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
1185 for (flags) |flag| {1161 assert(self.kind == Kind.Test);
1186 self.cflags.append(flag) catch unreachable;1162 self.exec_cmd_args = args;
1187 }
1188 }
1189
1190 pub fn setNoStdLib(self: *LibExeObjStep, disable: bool) void {
1191 assert(!self.is_zig);
1192 self.disable_libc = disable;
1193 }1163 }
11941164
1195 pub fn enableSystemLinkerHack(self: *LibExeObjStep) void {1165 pub fn enableSystemLinkerHack(self: *LibExeObjStep) void {
...@@ -1198,15 +1168,11 @@ pub const LibExeObjStep = struct {...@@ -1198,15 +1168,11 @@ pub const LibExeObjStep = struct {
11981168
1199 fn make(step: *Step) !void {1169 fn make(step: *Step) !void {
1200 const self = @fieldParentPtr(LibExeObjStep, "step", step);1170 const self = @fieldParentPtr(LibExeObjStep, "step", step);
1201 return if (self.is_zig) self.makeZig() else self.makeC();
1202 }
1203
1204 fn makeZig(self: *LibExeObjStep) !void {
1205 const builder = self.builder;1171 const builder = self.builder;
12061172
1207 assert(self.is_zig);1173 if (self.root_src == null and self.object_files.len == 0 and
12081174 self.assembly_files.len == 0 and self.c_source_files.len == 0)
1209 if (self.root_src == null and self.object_files.len == 0 and self.assembly_files.len == 0) {1175 {
1210 warn("{}: linker needs 1 or more objects to link\n", self.step.name);1176 warn("{}: linker needs 1 or more objects to link\n", self.step.name);
1211 return error.NeedAnObject;1177 return error.NeedAnObject;
1212 }1178 }
...@@ -1220,6 +1186,7 @@ pub const LibExeObjStep = struct {...@@ -1220,6 +1186,7 @@ pub const LibExeObjStep = struct {
1220 Kind.Lib => "build-lib",1186 Kind.Lib => "build-lib",
1221 Kind.Exe => "build-exe",1187 Kind.Exe => "build-exe",
1222 Kind.Obj => "build-obj",1188 Kind.Obj => "build-obj",
1189 Kind.Test => "test",
1223 };1190 };
1224 zig_args.append(cmd) catch unreachable;1191 zig_args.append(cmd) catch unreachable;
12251192
...@@ -1227,6 +1194,14 @@ pub const LibExeObjStep = struct {...@@ -1227,6 +1194,14 @@ pub const LibExeObjStep = struct {
1227 zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;1194 zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;
1228 }1195 }
12291196
1197 for (self.c_source_files.toSliceConst()) |c_source_file| {
1198 try zig_args.append("--c-source");
1199 for (c_source_file.args) |arg| {
1200 try zig_args.append(arg);
1201 }
1202 try zig_args.append(self.builder.pathFromRoot(c_source_file.source_path));
1203 }
1204
1230 if (self.build_options_contents.len() > 0) {1205 if (self.build_options_contents.len() > 0) {
1231 const build_options_file = try os.path.join(1206 const build_options_file = try os.path.join(
1232 builder.allocator,1207 builder.allocator,
...@@ -1239,6 +1214,16 @@ pub const LibExeObjStep = struct {...@@ -1239,6 +1214,16 @@ pub const LibExeObjStep = struct {
1239 try zig_args.append("--pkg-end");1214 try zig_args.append("--pkg-end");
1240 }1215 }
12411216
1217 if (self.filter) |filter| {
1218 try zig_args.append("--test-filter");
1219 try zig_args.append(filter);
1220 }
1221
1222 if (self.name_prefix.len != 0) {
1223 try zig_args.append("--test-name-prefix");
1224 try zig_args.append(self.name_prefix);
1225 }
1226
1242 for (self.object_files.toSliceConst()) |object_file| {1227 for (self.object_files.toSliceConst()) |object_file| {
1243 zig_args.append("--object") catch unreachable;1228 zig_args.append("--object") catch unreachable;
1244 zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;1229 zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;
...@@ -1255,6 +1240,7 @@ pub const LibExeObjStep = struct {...@@ -1255,6 +1240,7 @@ pub const LibExeObjStep = struct {
1255 if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable;1240 if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable;
1256 if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable;1241 if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable;
1257 if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable;1242 if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable;
1243 if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable;
12581244
1259 if (self.strip) {1245 if (self.strip) {
1260 zig_args.append("--strip") catch unreachable;1246 zig_args.append("--strip") catch unreachable;
...@@ -1274,6 +1260,12 @@ pub const LibExeObjStep = struct {...@@ -1274,6 +1260,12 @@ pub const LibExeObjStep = struct {
1274 zig_args.append("--output") catch unreachable;1260 zig_args.append("--output") catch unreachable;
1275 zig_args.append(output_path) catch unreachable;1261 zig_args.append(output_path) catch unreachable;
12761262
1263 if (self.kind == Kind.Lib and !self.static) {
1264 const output_lib_path = builder.pathFromRoot(self.getOutputLibPath());
1265 zig_args.append("--output-lib") catch unreachable;
1266 zig_args.append(output_lib_path) catch unreachable;
1267 }
1268
1277 if (self.kind != Kind.Exe) {1269 if (self.kind != Kind.Exe) {
1278 const output_h_path = self.getOutputHPath();1270 const output_h_path = self.getOutputHPath();
1279 zig_args.append("--output-h") catch unreachable;1271 zig_args.append("--output-h") catch unreachable;
...@@ -1293,7 +1285,7 @@ pub const LibExeObjStep = struct {...@@ -1293,7 +1285,7 @@ pub const LibExeObjStep = struct {
1293 zig_args.append("--ver-patch") catch unreachable;1285 zig_args.append("--ver-patch") catch unreachable;
1294 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;1286 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
1295 }1287 }
1296 if (self.kind == Kind.Exe and self.static) {1288 if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {
1297 zig_args.append("--static") catch unreachable;1289 zig_args.append("--static") catch unreachable;
1298 }1290 }
12991291
...@@ -1325,11 +1317,16 @@ pub const LibExeObjStep = struct {...@@ -1325,11 +1317,16 @@ pub const LibExeObjStep = struct {
1325 }1317 }
1326 }1318 }
13271319
1328 if (!self.disable_libc) {1320 if (self.exec_cmd_args) |exec_cmd_args| {
1329 zig_args.append("--library") catch unreachable;1321 for (exec_cmd_args) |cmd_arg| {
1330 zig_args.append("c") catch unreachable;1322 if (cmd_arg) |arg| {
1323 try zig_args.append("--test-cmd");
1324 try zig_args.append(arg);
1325 } else {
1326 try zig_args.append("--test-cmd-bin");
1327 }
1328 }
1331 }1329 }
1332
1333 for (self.packages.toSliceConst()) |pkg| {1330 for (self.packages.toSliceConst()) |pkg| {
1334 zig_args.append("--pkg-begin") catch unreachable;1331 zig_args.append("--pkg-begin") catch unreachable;
1335 zig_args.append(pkg.name) catch unreachable;1332 zig_args.append(pkg.name) catch unreachable;
...@@ -1363,8 +1360,14 @@ pub const LibExeObjStep = struct {...@@ -1363,8 +1360,14 @@ pub const LibExeObjStep = struct {
1363 }1360 }
13641361
1365 for (self.full_path_libs.toSliceConst()) |full_path_lib| {1362 for (self.full_path_libs.toSliceConst()) |full_path_lib| {
1366 zig_args.append("--library") catch unreachable;1363 try zig_args.append("--library");
1367 zig_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;1364 try zig_args.append(builder.pathFromRoot(full_path_lib));
1365
1366 const full_path_lib_abs = builder.pathFromRoot(full_path_lib);
1367 if (os.path.dirname(full_path_lib_abs)) |dirname| {
1368 try zig_args.append("-rpath");
1369 try zig_args.append(dirname);
1370 }
1368 }1371 }
13691372
1370 if (self.target.isDarwin()) {1373 if (self.target.isDarwin()) {
...@@ -1379,558 +1382,16 @@ pub const LibExeObjStep = struct {...@@ -1379,558 +1382,16 @@ pub const LibExeObjStep = struct {
1379 try zig_args.append("--system-linker-hack");1382 try zig_args.append("--system-linker-hack");
1380 }1383 }
13811384
1382 try builder.spawnChild(zig_args.toSliceConst());
1383
1384 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
1385 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
1386 }
1387 }
1388
1389 fn appendCompileFlags(self: *LibExeObjStep, args: *ArrayList([]const u8)) void {
1390 if (!self.strip) {
1391 args.append("-g") catch unreachable;
1392 }
1393 switch (self.build_mode) {
1394 builtin.Mode.Debug => {
1395 if (self.disable_libc) {
1396 args.append("-fno-stack-protector") catch unreachable;
1397 } else {
1398 args.append("-fstack-protector-strong") catch unreachable;
1399 args.append("--param") catch unreachable;
1400 args.append("ssp-buffer-size=4") catch unreachable;
1401 }
1402 },
1403 builtin.Mode.ReleaseSafe => {
1404 args.append("-O2") catch unreachable;
1405 if (self.disable_libc) {
1406 args.append("-fno-stack-protector") catch unreachable;
1407 } else {
1408 args.append("-D_FORTIFY_SOURCE=2") catch unreachable;
1409 args.append("-fstack-protector-strong") catch unreachable;
1410 args.append("--param") catch unreachable;
1411 args.append("ssp-buffer-size=4") catch unreachable;
1412 }
1413 },
1414 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {
1415 args.append("-O2") catch unreachable;
1416 args.append("-fno-stack-protector") catch unreachable;
1417 },
1418 }
1419
1420 for (self.include_dirs.toSliceConst()) |dir| {
1421 args.append("-I") catch unreachable;
1422 args.append(self.builder.pathFromRoot(dir)) catch unreachable;
1423 }
1424
1425 for (self.cflags.toSliceConst()) |cflag| {
1426 args.append(cflag) catch unreachable;
1427 }
1428
1429 if (self.disable_libc) {
1430 args.append("-nostdlib") catch unreachable;
1431 }
1432 }
1433
1434 fn makeC(self: *LibExeObjStep) !void {
1435 const builder = self.builder;
1436
1437 const cc = builder.getCCExe();
1438
1439 assert(!self.is_zig);
1440
1441 var cc_args = ArrayList([]const u8).init(builder.allocator);
1442 defer cc_args.deinit();
1443
1444 cc_args.append(cc) catch unreachable;
1445
1446 const is_darwin = self.target.isDarwin();
1447
1448 const c_std_arg = switch (self.c_std) {
1449 Builder.CStd.C89 => "-std=c89",
1450 Builder.CStd.C99 => "-std=c99",
1451 Builder.CStd.C11 => "-std=c11",
1452 };
1453 try cc_args.append(c_std_arg);
1454
1455 switch (self.kind) {
1456 Kind.Obj => {
1457 cc_args.append("-c") catch unreachable;
1458 cc_args.append(builder.pathFromRoot(self.object_src)) catch unreachable;
1459
1460 const output_path = builder.pathFromRoot(self.getOutputPath());
1461 cc_args.append("-o") catch unreachable;
1462 cc_args.append(output_path) catch unreachable;
1463
1464 self.appendCompileFlags(&cc_args);
1465
1466 try builder.spawnChild(cc_args.toSliceConst());
1467 },
1468 Kind.Lib => {
1469 for (self.source_files.toSliceConst()) |source_file| {
1470 cc_args.resize(0) catch unreachable;
1471 cc_args.append(cc) catch unreachable;
1472
1473 if (!self.static) {
1474 cc_args.append("-fPIC") catch unreachable;
1475 }
1476
1477 const abs_source_file = builder.pathFromRoot(source_file);
1478 cc_args.append("-c") catch unreachable;
1479 cc_args.append(abs_source_file) catch unreachable;
1480
1481 const cache_o_src = os.path.join(
1482 builder.allocator,
1483 [][]const u8{ builder.cache_root, source_file },
1484 ) catch unreachable;
1485 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1486 try builder.makePath(cache_o_dir);
1487 }
1488 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
1489 cc_args.append("-o") catch unreachable;
1490 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
1491
1492 self.appendCompileFlags(&cc_args);
1493
1494 try builder.spawnChild(cc_args.toSliceConst());
1495
1496 self.object_files.append(cache_o_file) catch unreachable;
1497 }
1498
1499 if (self.static) {
1500 // ar
1501 cc_args.resize(0) catch unreachable;
1502 cc_args.append("ar") catch unreachable;
1503
1504 cc_args.append("qc") catch unreachable;
1505
1506 const output_path = builder.pathFromRoot(self.getOutputPath());
1507 cc_args.append(output_path) catch unreachable;
1508
1509 for (self.object_files.toSliceConst()) |object_file| {
1510 cc_args.append(builder.pathFromRoot(object_file)) catch unreachable;
1511 }
1512
1513 try builder.spawnChild(cc_args.toSliceConst());
1514
1515 // ranlib
1516 cc_args.resize(0) catch unreachable;
1517 cc_args.append("ranlib") catch unreachable;
1518 cc_args.append(output_path) catch unreachable;
1519
1520 try builder.spawnChild(cc_args.toSliceConst());
1521 } else {
1522 cc_args.resize(0) catch unreachable;
1523 cc_args.append(cc) catch unreachable;
1524
1525 if (is_darwin) {
1526 cc_args.append("-dynamiclib") catch unreachable;
1527
1528 cc_args.append("-Wl,-headerpad_max_install_names") catch unreachable;
1529
1530 cc_args.append("-compatibility_version") catch unreachable;
1531 cc_args.append(builder.fmt("{}.0.0", self.version.major)) catch unreachable;
1532
1533 cc_args.append("-current_version") catch unreachable;
1534 cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable;
1535
1536 const install_name = builder.pathFromRoot(os.path.join(
1537 builder.allocator,
1538 [][]const u8{ builder.cache_root, self.major_only_filename },
1539 ) catch unreachable);
1540 cc_args.append("-install_name") catch unreachable;
1541 cc_args.append(install_name) catch unreachable;
1542 } else {
1543 cc_args.append("-fPIC") catch unreachable;
1544 cc_args.append("-shared") catch unreachable;
1545
1546 const soname_arg = builder.fmt("-Wl,-soname,lib{}.so.{d}", self.name, self.version.major);
1547 defer builder.allocator.free(soname_arg);
1548 cc_args.append(soname_arg) catch unreachable;
1549 }
1550
1551 const output_path = builder.pathFromRoot(self.getOutputPath());
1552 cc_args.append("-o") catch unreachable;
1553 cc_args.append(output_path) catch unreachable;
1554
1555 for (self.object_files.toSliceConst()) |object_file| {
1556 cc_args.append(builder.pathFromRoot(object_file)) catch unreachable;
1557 }
1558
1559 if (!is_darwin) {
1560 const rpath_arg = builder.fmt("-Wl,-rpath,{}", try os.path.realAlloc(
1561 builder.allocator,
1562 builder.pathFromRoot(builder.cache_root),
1563 ));
1564 defer builder.allocator.free(rpath_arg);
1565 try cc_args.append(rpath_arg);
1566
1567 try cc_args.append("-rdynamic");
1568 }
1569
1570 for (self.full_path_libs.toSliceConst()) |full_path_lib| {
1571 cc_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;
1572 }
1573
1574 {
1575 var it = self.link_libs.iterator();
1576 while (it.next()) |entry| {
1577 cc_args.append(builder.fmt("-l{}", entry.key)) catch unreachable;
1578 }
1579 }
1580
1581 if (is_darwin and !self.static) {
1582 var it = self.frameworks.iterator();
1583 while (it.next()) |entry| {
1584 cc_args.append("-framework") catch unreachable;
1585 cc_args.append(entry.key) catch unreachable;
1586 }
1587 }
1588
1589 try builder.spawnChild(cc_args.toSliceConst());
1590
1591 if (self.target.wantSharedLibSymLinks()) {
1592 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
1593 }
1594 }
1595 },
1596 Kind.Exe => {
1597 for (self.source_files.toSliceConst()) |source_file| {
1598 cc_args.resize(0) catch unreachable;
1599 cc_args.append(cc) catch unreachable;
1600
1601 const abs_source_file = builder.pathFromRoot(source_file);
1602 cc_args.append("-c") catch unreachable;
1603 cc_args.append(abs_source_file) catch unreachable;
1604
1605 const cache_o_src = os.path.join(
1606 builder.allocator,
1607 [][]const u8{ builder.cache_root, source_file },
1608 ) catch unreachable;
1609 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1610 try builder.makePath(cache_o_dir);
1611 }
1612 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
1613 cc_args.append("-o") catch unreachable;
1614 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
1615
1616 for (self.cflags.toSliceConst()) |cflag| {
1617 cc_args.append(cflag) catch unreachable;
1618 }
1619
1620 for (self.include_dirs.toSliceConst()) |dir| {
1621 cc_args.append("-I") catch unreachable;
1622 cc_args.append(builder.pathFromRoot(dir)) catch unreachable;
1623 }
1624
1625 try builder.spawnChild(cc_args.toSliceConst());
1626
1627 self.object_files.append(cache_o_file) catch unreachable;
1628 }
1629
1630 cc_args.resize(0) catch unreachable;
1631 cc_args.append(cc) catch unreachable;
1632
1633 for (self.object_files.toSliceConst()) |object_file| {
1634 cc_args.append(builder.pathFromRoot(object_file)) catch unreachable;
1635 }
1636
1637 const output_path = builder.pathFromRoot(self.getOutputPath());
1638 cc_args.append("-o") catch unreachable;
1639 cc_args.append(output_path) catch unreachable;
1640
1641 const rpath_arg = builder.fmt("-Wl,-rpath,{}", try os.path.realAlloc(
1642 builder.allocator,
1643 builder.pathFromRoot(builder.cache_root),
1644 ));
1645 defer builder.allocator.free(rpath_arg);
1646 try cc_args.append(rpath_arg);
1647
1648 try cc_args.append("-rdynamic");
1649
1650 {
1651 var it = self.link_libs.iterator();
1652 while (it.next()) |entry| {
1653 cc_args.append(builder.fmt("-l{}", entry.key)) catch unreachable;
1654 }
1655 }
1656
1657 if (is_darwin) {
1658 if (self.need_flat_namespace_hack) {
1659 cc_args.append("-Wl,-flat_namespace") catch unreachable;
1660 }
1661 cc_args.append("-Wl,-search_paths_first") catch unreachable;
1662 }
1663
1664 for (self.full_path_libs.toSliceConst()) |full_path_lib| {
1665 cc_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;
1666 }
1667
1668 if (is_darwin) {
1669 var it = self.frameworks.iterator();
1670 while (it.next()) |entry| {
1671 cc_args.append("-framework") catch unreachable;
1672 cc_args.append(entry.key) catch unreachable;
1673 }
1674 }
1675
1676 try builder.spawnChild(cc_args.toSliceConst());
1677 },
1678 }
1679 }
1680};
1681
1682pub const TestStep = struct {
1683 step: Step,
1684 builder: *Builder,
1685 root_src: []const u8,
1686 build_mode: builtin.Mode,
1687 verbose: bool,
1688 link_libs: BufSet,
1689 name_prefix: []const u8,
1690 filter: ?[]const u8,
1691 target: Target,
1692 exec_cmd_args: ?[]const ?[]const u8,
1693 include_dirs: ArrayList([]const u8),
1694 lib_paths: ArrayList([]const u8),
1695 packages: ArrayList(Pkg),
1696 object_files: ArrayList([]const u8),
1697 output_path: ?[]const u8,
1698 system_linker_hack: bool,
1699 override_std_dir: ?[]const u8,
1700
1701 pub fn init(builder: *Builder, root_src: []const u8) TestStep {
1702 const step_name = builder.fmt("test {}", root_src);
1703 return TestStep{
1704 .step = Step.init(step_name, builder.allocator, make),
1705 .builder = builder,
1706 .root_src = root_src,
1707 .build_mode = builtin.Mode.Debug,
1708 .verbose = false,
1709 .name_prefix = "",
1710 .filter = null,
1711 .link_libs = BufSet.init(builder.allocator),
1712 .target = Target{ .Native = {} },
1713 .exec_cmd_args = null,
1714 .include_dirs = ArrayList([]const u8).init(builder.allocator),
1715 .lib_paths = ArrayList([]const u8).init(builder.allocator),
1716 .packages = ArrayList(Pkg).init(builder.allocator),
1717 .object_files = ArrayList([]const u8).init(builder.allocator),
1718 .output_path = null,
1719 .system_linker_hack = false,
1720 .override_std_dir = null,
1721 };
1722 }
1723
1724 pub fn addLibPath(self: *TestStep, path: []const u8) void {
1725 self.lib_paths.append(path) catch unreachable;
1726 }
1727
1728 pub fn addPackagePath(self: *TestStep, name: []const u8, pkg_index_path: []const u8) void {
1729 self.packages.append(Pkg{
1730 .name = name,
1731 .path = pkg_index_path,
1732 }) catch unreachable;
1733 }
1734
1735 pub fn setVerbose(self: *TestStep, value: bool) void {
1736 self.verbose = value;
1737 }
1738
1739 pub fn addIncludeDir(self: *TestStep, path: []const u8) void {
1740 self.include_dirs.append(path) catch unreachable;
1741 }
1742
1743 pub fn setBuildMode(self: *TestStep, mode: builtin.Mode) void {
1744 self.build_mode = mode;
1745 }
1746
1747 pub fn overrideStdDir(self: *TestStep, dir_path: []const u8) void {
1748 self.override_std_dir = dir_path;
1749 }
1750
1751 pub fn setOutputPath(self: *TestStep, file_path: []const u8) void {
1752 self.output_path = file_path;
1753
1754 // catch a common mistake
1755 if (mem.eql(u8, self.builder.pathFromRoot(file_path), self.builder.pathFromRoot("."))) {
1756 debug.panic("setOutputPath wants a file path, not a directory\n");
1757 }
1758 }
1759
1760 pub fn getOutputPath(self: *TestStep) []const u8 {
1761 if (self.output_path) |output_path| {
1762 return output_path;
1763 } else {
1764 const basename = self.builder.fmt("test{}", self.target.exeFileExt());
1765 return os.path.join(
1766 self.builder.allocator,
1767 [][]const u8{ self.builder.cache_root, basename },
1768 ) catch unreachable;
1769 }
1770 }
1771
1772 pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void {
1773 self.link_libs.put(name) catch unreachable;
1774 }
1775
1776 pub fn setNamePrefix(self: *TestStep, text: []const u8) void {
1777 self.name_prefix = text;
1778 }
1779
1780 pub fn setFilter(self: *TestStep, text: ?[]const u8) void {
1781 self.filter = text;
1782 }
1783
1784 pub fn addObject(self: *TestStep, obj: *LibExeObjStep) void {
1785 assert(obj.kind == LibExeObjStep.Kind.Obj);
1786
1787 self.step.dependOn(&obj.step);
1788
1789 self.object_files.append(obj.getOutputPath()) catch unreachable;
1790
1791 // TODO should be some kind of isolated directory that only has this header in it
1792 self.include_dirs.append(self.builder.cache_root) catch unreachable;
1793 }
1794
1795 pub fn addObjectFile(self: *TestStep, path: []const u8) void {
1796 self.object_files.append(path) catch unreachable;
1797 }
1798
1799 pub fn setTarget(self: *TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
1800 self.target = Target{
1801 .Cross = CrossTarget{
1802 .arch = target_arch,
1803 .os = target_os,
1804 .environ = target_environ,
1805 },
1806 };
1807 }
1808
1809 pub fn setExecCmd(self: *TestStep, args: []const ?[]const u8) void {
1810 self.exec_cmd_args = args;
1811 }
1812
1813 pub fn enableSystemLinkerHack(self: *TestStep) void {
1814 self.system_linker_hack = true;
1815 }
1816
1817 fn make(step: *Step) !void {
1818 const self = @fieldParentPtr(TestStep, "step", step);
1819 const builder = self.builder;
1820
1821 var zig_args = ArrayList([]const u8).init(builder.allocator);
1822 defer zig_args.deinit();
1823
1824 try zig_args.append(builder.zig_exe);
1825
1826 try zig_args.append("test");
1827 try zig_args.append(builder.pathFromRoot(self.root_src));
1828
1829 if (self.verbose) {
1830 try zig_args.append("--verbose");
1831 }
1832
1833 switch (self.build_mode) {
1834 builtin.Mode.Debug => {},
1835 builtin.Mode.ReleaseSafe => try zig_args.append("--release-safe"),
1836 builtin.Mode.ReleaseFast => try zig_args.append("--release-fast"),
1837 builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"),
1838 }
1839
1840 const output_path = builder.pathFromRoot(self.getOutputPath());
1841 try zig_args.append("--output");
1842 try zig_args.append(output_path);
1843
1844 switch (self.target) {
1845 Target.Native => {},
1846 Target.Cross => |cross_target| {
1847 try zig_args.append("--target-arch");
1848 try zig_args.append(@tagName(cross_target.arch));
1849
1850 try zig_args.append("--target-os");
1851 try zig_args.append(@tagName(cross_target.os));
1852
1853 try zig_args.append("--target-environ");
1854 try zig_args.append(@tagName(cross_target.environ));
1855 },
1856 }
1857
1858 if (self.filter) |filter| {
1859 try zig_args.append("--test-filter");
1860 try zig_args.append(filter);
1861 }
1862
1863 if (self.name_prefix.len != 0) {
1864 try zig_args.append("--test-name-prefix");
1865 try zig_args.append(self.name_prefix);
1866 }
1867
1868 for (self.object_files.toSliceConst()) |object_file| {
1869 try zig_args.append("--object");
1870 try zig_args.append(builder.pathFromRoot(object_file));
1871 }
1872
1873 {
1874 var it = self.link_libs.iterator();
1875 while (true) {
1876 const entry = it.next() orelse break;
1877 try zig_args.append("--library");
1878 try zig_args.append(entry.key);
1879 }
1880 }
1881
1882 if (self.exec_cmd_args) |exec_cmd_args| {
1883 for (exec_cmd_args) |cmd_arg| {
1884 if (cmd_arg) |arg| {
1885 try zig_args.append("--test-cmd");
1886 try zig_args.append(arg);
1887 } else {
1888 try zig_args.append("--test-cmd-bin");
1889 }
1890 }
1891 }
1892
1893 for (self.include_dirs.toSliceConst()) |include_path| {
1894 try zig_args.append("-isystem");
1895 try zig_args.append(builder.pathFromRoot(include_path));
1896 }
1897
1898 for (builder.include_paths.toSliceConst()) |include_path| {
1899 try zig_args.append("-isystem");
1900 try zig_args.append(builder.pathFromRoot(include_path));
1901 }
1902
1903 for (builder.rpaths.toSliceConst()) |rpath| {
1904 try zig_args.append("-rpath");
1905 try zig_args.append(rpath);
1906 }
1907
1908 for (self.lib_paths.toSliceConst()) |lib_path| {
1909 try zig_args.append("--library-path");
1910 try zig_args.append(lib_path);
1911 }
1912
1913 for (builder.lib_paths.toSliceConst()) |lib_path| {
1914 try zig_args.append("--library-path");
1915 try zig_args.append(lib_path);
1916 }
1917
1918 for (self.packages.toSliceConst()) |pkg| {
1919 zig_args.append("--pkg-begin") catch unreachable;
1920 zig_args.append(pkg.name) catch unreachable;
1921 zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable;
1922 zig_args.append("--pkg-end") catch unreachable;
1923 }
1924
1925 if (self.system_linker_hack) {
1926 try zig_args.append("--system-linker-hack");
1927 }
1928 if (self.override_std_dir) |dir| {1385 if (self.override_std_dir) |dir| {
1929 try zig_args.append("--override-std-dir");1386 try zig_args.append("--override-std-dir");
1930 try zig_args.append(builder.pathFromRoot(dir));1387 try zig_args.append(builder.pathFromRoot(dir));
1931 }1388 }
19321389
1933 try builder.spawnChild(zig_args.toSliceConst());1390 try builder.spawnChild(zig_args.toSliceConst());
1391
1392 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
1393 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
1394 }
1934 }1395 }
1935};1396};
19361397
...@@ -1976,6 +1437,7 @@ const InstallArtifactStep = struct {...@@ -1976,6 +1437,7 @@ const InstallArtifactStep = struct {
1976 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {1437 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
1977 const dest_dir = switch (artifact.kind) {1438 const dest_dir = switch (artifact.kind) {
1978 LibExeObjStep.Kind.Obj => unreachable,1439 LibExeObjStep.Kind.Obj => unreachable,
1440 LibExeObjStep.Kind.Test => unreachable,
1979 LibExeObjStep.Kind.Exe => builder.exe_dir,1441 LibExeObjStep.Kind.Exe => builder.exe_dir,
1980 LibExeObjStep.Kind.Lib => builder.lib_dir,1442 LibExeObjStep.Kind.Lib => builder.lib_dir,
1981 };1443 };
...@@ -2012,6 +1474,7 @@ const InstallArtifactStep = struct {...@@ -2012,6 +1474,7 @@ const InstallArtifactStep = struct {
2012 builtin.Os.windows => {},1474 builtin.Os.windows => {},
2013 else => switch (self.artifact.kind) {1475 else => switch (self.artifact.kind) {
2014 LibExeObjStep.Kind.Obj => unreachable,1476 LibExeObjStep.Kind.Obj => unreachable,
1477 LibExeObjStep.Kind.Test => unreachable,
2015 LibExeObjStep.Kind.Exe => u32(0o755),1478 LibExeObjStep.Kind.Exe => u32(0o755),
2016 LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755),1479 LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755),
2017 },1480 },
test/build_examples.zig+2-6
...@@ -7,12 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {...@@ -7,12 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
7 cases.addC("example/hello_world/hello_libc.zig");7 cases.addC("example/hello_world/hello_libc.zig");
8 cases.add("example/cat/main.zig");8 cases.add("example/cat/main.zig");
9 cases.add("example/guess_number/main.zig");9 cases.add("example/guess_number/main.zig");
10 if (!is_windows) {10 cases.addBuildFile("example/shared_library/build.zig");
11 // TODO get this test passing on windows11 cases.addBuildFile("example/mix_o_files/build.zig");
12 // See https://github.com/ziglang/zig/issues/538
13 cases.addBuildFile("example/shared_library/build.zig");
14 cases.addBuildFile("example/mix_o_files/build.zig");
15 }
16 if (builtin.os != builtin.Os.macosx) {12 if (builtin.os != builtin.Os.macosx) {
17 // TODO https://github.com/ziglang/zig/issues/112613 // TODO https://github.com/ziglang/zig/issues/1126
18 cases.addBuildFile("test/standalone/issue_339/build.zig");14 cases.addBuildFile("test/standalone/issue_339/build.zig");
test/stage1/c_abi/build.zig+3-2
...@@ -3,9 +3,10 @@ const Builder = @import("std").build.Builder;...@@ -3,9 +3,10 @@ const Builder = @import("std").build.Builder;
3pub fn build(b: *Builder) void {3pub fn build(b: *Builder) void {
4 const rel_opts = b.standardReleaseOptions();4 const rel_opts = b.standardReleaseOptions();
55
6 const c_obj = b.addCObject("cfuncs", "cfuncs.c");6 const c_obj = b.addObject("cfuncs", null);
7 c_obj.addCSourceFile("cfuncs.c", [][]const u8{"-std=c99"});
7 c_obj.setBuildMode(rel_opts);8 c_obj.setBuildMode(rel_opts);
8 c_obj.setNoStdLib(true);9 c_obj.linkSystemLibrary("c");
910
10 const main = b.addTest("main.zig");11 const main = b.addTest("main.zig");
11 main.setBuildMode(rel_opts);12 main.setBuildMode(rel_opts);