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
signaturebadge-question-mark 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;
33pub fn build(b: *Builder) void {
44 const obj = b.addObject("base64", "base64.zig");
55
6 const exe = b.addCExecutable("test");
7 exe.addCompileFlags([][]const u8{"-std=c99"});
8 exe.addSourceFile("test.c");
6 const exe = b.addExecutable("test", null);
7 exe.addCSourceFile("test.c",[][]const u8{"-std=c99"});
98 exe.addObject(obj);
9 exe.linkSystemLibrary("c");
1010
1111 b.default_step.dependOn(&exe.step);
1212
example/shared_library/build.zig+3-3
......@@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
33pub fn build(b: *Builder) void {
44 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
6 const exe = b.addCExecutable("test");
7 exe.addCompileFlags([][]const u8{"-std=c99"});
8 exe.addSourceFile("test.c");
6 const exe = b.addExecutable("test", null);
7 exe.addCSourceFile("test.c", [][]const u8{"-std=c99"});
98 exe.linkLibrary(lib);
9 exe.linkSystemLibrary("c");
1010
1111 b.default_step.dependOn(&exe.step);
1212
src/all_types.hpp+8
......@@ -1611,6 +1611,11 @@ enum ValgrindSupport {
16111611 ValgrindSupportEnabled,
16121612};
16131613
1614struct CFile {
1615 ZigList<const char *> args;
1616 const char *source_path;
1617};
1618
16141619// When adding fields, check if they should be added to the hash computation in build_with_cache
16151620struct CodeGen {
16161621 //////////////////////////// Runtime State
......@@ -1738,6 +1743,7 @@ struct CodeGen {
17381743 Buf triple_str;
17391744 Buf global_asm;
17401745 Buf *out_h_path;
1746 Buf *out_lib_path;
17411747 Buf artifact_dir;
17421748 Buf output_file_path;
17431749 Buf o_file_output_path;
......@@ -1788,6 +1794,7 @@ struct CodeGen {
17881794 bool verbose_ir;
17891795 bool verbose_llvm_ir;
17901796 bool verbose_cimport;
1797 bool verbose_cc;
17911798 bool error_during_imports;
17921799 bool generate_error_name_table;
17931800 bool enable_cache;
......@@ -1805,6 +1812,7 @@ struct CodeGen {
18051812 ZigList<Buf *> forbidden_libs;
18061813 ZigList<Buf *> link_objects;
18071814 ZigList<Buf *> assembly_files;
1815 ZigList<CFile *> c_source_files;
18081816 ZigList<const char *> lib_dirs;
18091817
18101818 ZigLibCInstallation *libc;
src/cache_hash.cpp+34
......@@ -414,6 +414,39 @@ Error cache_add_file(CacheHash *ch, Buf *path) {
414414 return cache_add_file_fetch(ch, resolved_path, nullptr);
415415}
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
417450static Error write_manifest_file(CacheHash *ch) {
418451 Error err;
419452 Buf contents = BUF_INIT;
......@@ -464,3 +497,4 @@ void cache_release(CacheHash *ch) {
464497
465498 os_file_close(ch->manifest_file);
466499}
500
src/cache_hash.hpp+2
......@@ -56,6 +56,8 @@ Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
5656// If you did not get a cache hit, call this function for every file
5757// that is depended on, and then finish with cache_final.
5858Error 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
6062// This variant of cache_add_file returns the file contents.
6163// 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) {
175175 g->out_h_path = h_path;
176176}
177177
178void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path) {
179 g->out_lib_path = lib_path;
180}
181
178182void codegen_set_output_path(CodeGen *g, Buf *path) {
179183 g->wanted_output_file_path = path;
180184}
......@@ -7885,8 +7889,8 @@ static void detect_libc(CodeGen *g) {
78857889 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
78867890 exit(1);
78877891 }
7888 if (rename(buf_ptr(native_libc_tmp), buf_ptr(native_libc_txt)) == -1) {
7889 fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), strerror(errno));
7892 if ((err = os_rename(native_libc_tmp, native_libc_txt))) {
7893 fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), err_str(err));
78907894 exit(1);
78917895 }
78927896 }
......@@ -8123,6 +8127,143 @@ static void gen_global_asm(CodeGen *g) {
81238127 }
81248128}
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
81268267void codegen_add_object(CodeGen *g, Buf *object_path) {
81278268 g->link_objects.append(object_path);
81288269}
......@@ -8637,6 +8778,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
86378778 cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
86388779 cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
86398780 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 }
86408788 cache_int(ch, g->emit_file_type);
86418789 cache_int(ch, g->build_mode);
86428790 cache_int(ch, g->out_type);
......@@ -8788,6 +8936,7 @@ void codegen_build_and_link(CodeGen *g) {
87888936
87898937 gen_global_asm(g);
87908938 gen_root_source(g);
8939 gen_c_objects(g);
87918940
87928941 if (g->enable_cache) {
87938942 if ((err = cache_final(&g->cache_hash, &digest))) {
......@@ -8805,16 +8954,25 @@ void codegen_build_and_link(CodeGen *g) {
88058954 resolve_out_paths(g);
88068955
88078956 codegen_add_time_event(g, "Code Generation");
8808 do_code_gen(g);
8809 codegen_add_time_event(g, "LLVM Emit Output");
8810 zig_llvm_emit_output(g);
8957 if (g->out_type == OutTypeObj && g->c_source_files.length == 1) {
8958 assert(g->link_objects.length == 1);
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) {
8813 codegen_add_time_event(g, "Generate .h");
8814 gen_h_file(g);
8815 }
8816 if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {
8817 codegen_link(g);
8969 if (g->out_h_path != nullptr) {
8970 codegen_add_time_event(g, "Generate .h");
8971 gen_h_file(g);
8972 }
8973 if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {
8974 codegen_link(g);
8975 }
88188976 }
88198977 }
88208978
src/codegen.hpp+1
......@@ -41,6 +41,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);
4141void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
4242void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
4343void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
44void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path);
4445void codegen_set_output_path(CodeGen *g, Buf *path);
4546void codegen_add_time_event(CodeGen *g, const char *name);
4647void codegen_print_timing_report(CodeGen *g, FILE *f);
src/error.cpp+1
......@@ -36,6 +36,7 @@ const char *err_str(Error err) {
3636 case ErrorCacheUnavailable: return "cache unavailable";
3737 case ErrorPathTooLong: return "path too long";
3838 case ErrorCCompilerCannotFindFile: return "C compiler cannot find file";
39 case ErrorReadingDepFile: return "failed to read .d file";
3940 }
4041 return "(invalid error)";
4142}
src/error.hpp+1
......@@ -38,6 +38,7 @@ enum Error {
3838 ErrorCacheUnavailable,
3939 ErrorPathTooLong,
4040 ErrorCCompilerCannotFindFile,
41 ErrorReadingDepFile,
4142};
4243
4344const char *err_str(Error err);
src/ir.cpp-6
......@@ -18670,12 +18670,6 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc
1867018670}
1867118671
1867218672static 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
1867918673 AstNode *node = instruction->base.source_node;
1868018674 assert(node->type == NodeTypeFnCallExpr);
1868118675 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) {
554554 bool is_library = g->out_type == OutTypeLib;
555555 switch (g->subsystem) {
556556 case TargetSubsystemAuto:
557 add_nt_link_args(lj, is_library);
557558 break;
558559 case TargetSubsystemConsole:
559560 lj->args.append("/SUBSYSTEM:console");
src/main.cpp+73-18
......@@ -18,7 +18,7 @@
1818#include <stdio.h>
1919
2020static 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);
2222 return EXIT_FAILURE;
2323}
2424
......@@ -34,7 +34,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
3434 " builtin show the source code of that @import(\"builtin\")\n"
3535 " cc C compiler\n"
3636 " fmt parse files and render in canonical zig format\n"
37 " help show this usage information\n"
3837 " id print the base64-encoded compiler id\n"
3938 " init-exe initialize a `zig build` application in the cwd\n"
4039 " 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) {
4847 "\n"
4948 "Compile Options:\n"
5049 " --assembly [source] add assembly file to build\n"
50 " --c-source [options] [file] compile C source code\n"
5151 " --cache-dir [path] override the cache directory\n"
5252 " --cache [auto|off|on] build in global cache, print out paths to stdout\n"
5353 " --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) {
6060 " --name [name] override output name\n"
6161 " --output [file] override destination path\n"
6262 " --output-h [file] generate header file\n"
63 " --output-lib [file] override import library path\n"
6364 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
6465 " --pkg-end pop current pkg\n"
6566 " --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) {
7778 " --verbose-ir enable compiler debug output for Zig IR\n"
7879 " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
7980 " --verbose-cimport enable compiler debug output for C imports\n"
81 " --verbose-cc enable compiler debug output for C compilation\n"
8082 " -dirafter [dir] same as -isystem but do it last\n"
8183 " -isystem [dir] add additional search path for other .h files\n"
8284 " -mllvm [arg] forward an arg to LLVM's option processing\n"
......@@ -181,7 +183,6 @@ enum Cmd {
181183 CmdNone,
182184 CmdBuild,
183185 CmdBuiltin,
184 CmdHelp,
185186 CmdRun,
186187 CmdTargets,
187188 CmdTest,
......@@ -375,6 +376,7 @@ int main(int argc, char **argv) {
375376 const char *in_file = nullptr;
376377 const char *out_file = nullptr;
377378 const char *out_file_h = nullptr;
379 const char *out_file_lib = nullptr;
378380 bool strip = false;
379381 bool is_static = false;
380382 OutType out_type = OutTypeUnknown;
......@@ -385,6 +387,7 @@ int main(int argc, char **argv) {
385387 bool verbose_ir = false;
386388 bool verbose_llvm_ir = false;
387389 bool verbose_cimport = false;
390 bool verbose_cc = false;
388391 ErrColor color = ErrColorAuto;
389392 CacheOpt enable_cache = CacheOptAuto;
390393 const char *libc_txt = nullptr;
......@@ -404,6 +407,7 @@ int main(int argc, char **argv) {
404407 ZigList<const char *> rpath_list = {0};
405408 bool each_lib_rpath = false;
406409 ZigList<const char *> objects = {0};
410 ZigList<CFile *> c_source_files = {0};
407411 ZigList<const char *> asm_files = {0};
408412 const char *test_filter = nullptr;
409413 const char *test_name_prefix = nullptr;
......@@ -512,6 +516,7 @@ int main(int argc, char **argv) {
512516 " --verbose-ir Enable compiler debug output for Zig IR\n"
513517 " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
514518 " --verbose-cimport Enable compiler debug output for C imports\n"
519 " --verbose-cc Enable compiler debug output for C compilation\n"
515520 "\n"
516521 , zig_exe_path);
517522 return EXIT_SUCCESS;
......@@ -521,7 +526,7 @@ int main(int argc, char **argv) {
521526 "No 'build.zig' file found.\n"
522527 "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"
523528 "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"
525530 );
526531 return EXIT_FAILURE;
527532 }
......@@ -587,9 +592,9 @@ int main(int argc, char **argv) {
587592 build_mode = BuildModeSmallRelease;
588593 } else if (strcmp(arg, "--help") == 0) {
589594 if (cmd == CmdLibC) {
590 return print_libc_usage(arg0, stderr, EXIT_FAILURE);
595 return print_libc_usage(arg0, stdout, EXIT_SUCCESS);
591596 } else {
592 return print_full_usage(arg0, stderr, EXIT_FAILURE);
597 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
593598 }
594599 } else if (strcmp(arg, "--strip") == 0) {
595600 strip = true;
......@@ -607,6 +612,8 @@ int main(int argc, char **argv) {
607612 verbose_llvm_ir = true;
608613 } else if (strcmp(arg, "--verbose-cimport") == 0) {
609614 verbose_cimport = true;
615 } else if (strcmp(arg, "--verbose-cc") == 0) {
616 verbose_cc = true;
610617 } else if (strcmp(arg, "-rdynamic") == 0) {
611618 rdynamic = true;
612619 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
......@@ -656,6 +663,8 @@ int main(int argc, char **argv) {
656663 out_file = argv[i];
657664 } else if (strcmp(arg, "--output-h") == 0) {
658665 out_file_h = argv[i];
666 } else if (strcmp(arg, "--output-lib") == 0) {
667 out_file_lib = argv[i];
659668 } else if (strcmp(arg, "--color") == 0) {
660669 if (strcmp(argv[i], "auto") == 0) {
661670 color = ErrColorAuto;
......@@ -714,6 +723,19 @@ int main(int argc, char **argv) {
714723 forbidden_link_libs.append(argv[i]);
715724 } else if (strcmp(arg, "--object") == 0) {
716725 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 }
717739 } else if (strcmp(arg, "--assembly") == 0) {
718740 asm_files.append(argv[i]);
719741 } else if (strcmp(arg, "--cache-dir") == 0) {
......@@ -792,8 +814,6 @@ int main(int argc, char **argv) {
792814 } else if (strcmp(arg, "build-lib") == 0) {
793815 cmd = CmdBuild;
794816 out_type = OutTypeLib;
795 } else if (strcmp(arg, "help") == 0) {
796 cmd = CmdHelp;
797817 } else if (strcmp(arg, "run") == 0) {
798818 cmd = CmdRun;
799819 out_type = OutTypeExe;
......@@ -835,7 +855,6 @@ int main(int argc, char **argv) {
835855 }
836856 break;
837857 case CmdBuiltin:
838 case CmdHelp:
839858 case CmdVersion:
840859 case CmdZen:
841860 case CmdTargets:
......@@ -910,15 +929,43 @@ int main(int argc, char **argv) {
910929 case CmdTranslateC:
911930 case CmdTest:
912931 {
913 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");
932 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 &&
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");
915941 return print_error_usage(arg0);
916942 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
917943 fprintf(stderr, "Expected source file argument.\n");
918944 return print_error_usage(arg0);
919 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
920 fprintf(stderr, "When building an object file, --object arguments are invalid.\n");
921 return print_error_usage(arg0);
945 } else if (cmd == CmdBuild && out_type == OutTypeObj) {
946 if (objects.length != 0) {
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 }
922969 }
923970
924971 assert(cmd != CmdBuild || out_type != OutTypeUnknown);
......@@ -945,6 +992,13 @@ int main(int argc, char **argv) {
945992 }
946993 }
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
9481002 if (need_name && buf_out_name == nullptr) {
9491003 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
9501004 return print_error_usage(arg0);
......@@ -996,6 +1050,7 @@ int main(int argc, char **argv) {
9961050 g->verbose_ir = verbose_ir;
9971051 g->verbose_llvm_ir = verbose_llvm_ir;
9981052 g->verbose_cimport = verbose_cimport;
1053 g->verbose_cc = verbose_cc;
9991054 codegen_set_errmsg_color(g, color);
10001055 g->system_linker_hack = system_linker_hack;
10011056
......@@ -1043,11 +1098,14 @@ int main(int argc, char **argv) {
10431098 codegen_set_output_path(g, buf_create_from_str(out_file));
10441099 if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))
10451100 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
10481105 add_package(g, cur_pkg, g->root_package);
10491106
10501107 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
1108 g->c_source_files = c_source_files;
10511109 for (size_t i = 0; i < objects.length; i += 1) {
10521110 codegen_add_object(g, buf_create_from_str(objects.at(i)));
10531111 }
......@@ -1147,8 +1205,6 @@ int main(int argc, char **argv) {
11471205 zig_unreachable();
11481206 }
11491207 }
1150 case CmdHelp:
1151 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
11521208 case CmdVersion:
11531209 printf("%s\n", ZIG_VERSION_STRING);
11541210 return EXIT_SUCCESS;
......@@ -1158,7 +1214,6 @@ int main(int argc, char **argv) {
11581214 case CmdTargets:
11591215 return print_target_list(stdout);
11601216 case CmdNone:
1161 fprintf(stderr, "Zig programming language\n");
1162 return print_error_usage(arg0);
1217 return print_full_usage(arg0, stderr, EXIT_FAILURE);
11631218 }
11641219}
src/os.cpp+12
......@@ -1232,6 +1232,18 @@ static Error os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_p
12321232}
12331233#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
12351247#if defined(ZIG_OS_WINDOWS)
12361248static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
12371249 char tmp_dir[MAX_PATH + 1];
src/os.hpp+1
......@@ -121,6 +121,7 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);
121121bool os_stderr_tty(void);
122122void os_stderr_set_color(TermColor color);
123123
124Buf *os_tmp_filename(Buf *prefix, Buf *suffix);
124125Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
125126Error os_delete_file(Buf *path);
126127
src/target.cpp+6
......@@ -1049,3 +1049,9 @@ bool target_requires_libc(const ZigTarget *target) {
10491049 // since this is the stable syscall interface.
10501050 return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD);
10511051}
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);
141141bool target_has_valgrind_support(const ZigTarget *target);
142142bool target_is_darwin(const ZigTarget *target);
143143bool target_requires_libc(const ZigTarget *target);
144bool target_supports_fpic(const ZigTarget *target);
144145
145146#endif
src/translate_c.cpp+20
......@@ -4776,6 +4776,15 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
47764776 clang_argv.append("-x");
47774777 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
47794788 if (c->codegen->zig_target->is_native) {
47804789 char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS");
47814790 if (ZIG_PARSEC_CFLAGS) {
......@@ -4912,6 +4921,17 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
49124921 return ErrorCCompileErrors;
49134922 }
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
49154935 c->ctx = ZigClangASTUnit_getASTContext(ast_unit);
49164936 c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit);
49174937 c->root = trans_create_node(c, NodeTypeContainerDecl);
std/buf_set.zig+4
......@@ -32,6 +32,10 @@ pub const BufSet = struct {
3232 }
3333 }
3434
35 pub fn exists(self: BufSet, key: []const u8) bool {
36 return self.hash_map.get(key) != null;
37 }
38
3539 pub fn delete(self: *BufSet, key: []const u8) void {
3640 const entry = self.hash_map.remove(key) orelse return;
3741 self.free(entry.key);
std/build.zig+151-688
......@@ -31,6 +31,7 @@ pub const Builder = struct {
3131 verbose_tokenize: bool,
3232 verbose_ast: bool,
3333 verbose_link: bool,
34 verbose_cc: bool,
3435 verbose_ir: bool,
3536 verbose_llvm_ir: bool,
3637 verbose_cimport: bool,
......@@ -99,6 +100,7 @@ pub const Builder = struct {
99100 .verbose_tokenize = false,
100101 .verbose_ast = false,
101102 .verbose_link = false,
103 .verbose_cc = false,
102104 .verbose_ir = false,
103105 .verbose_llvm_ir = false,
104106 .verbose_cimport = false,
......@@ -157,7 +159,7 @@ pub const Builder = struct {
157159 return LibExeObjStep.createExecutable(self, name, root_src, true);
158160 }
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 {
161163 return LibExeObjStep.createObject(self, name, root_src);
162164 }
163165
......@@ -169,10 +171,8 @@ pub const Builder = struct {
169171 return LibExeObjStep.createStaticLibrary(self, name, root_src);
170172 }
171173
172 pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {
173 const test_step = self.allocator.create(TestStep) catch unreachable;
174 test_step.* = TestStep.init(self, root_src);
175 return test_step;
174 pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep {
175 return LibExeObjStep.createTest(self, "test", root_src);
176176 }
177177
178178 pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
......@@ -181,22 +181,6 @@ pub const Builder = struct {
181181 return obj_step;
182182 }
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
200184 /// ::argv is copied.
201185 pub fn addCommand(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
202186 return CommandStep.create(self, cwd, env_map, argv);
......@@ -663,14 +647,6 @@ pub const Builder = struct {
663647 return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable;
664648 }
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
674650 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
675651 // TODO report error for ambiguous situations
676652 const exe_extension = (Target{ .Native = {} }).exeFileExt();
......@@ -825,6 +801,11 @@ const Pkg = struct {
825801 path: []const u8,
826802};
827803
804const CSourceFile = struct {
805 source_path: []const u8,
806 args: []const []const u8,
807};
808
828809pub const LibExeObjStep = struct {
829810 step: Step,
830811 builder: *Builder,
......@@ -834,6 +815,7 @@ pub const LibExeObjStep = struct {
834815 linker_script: ?[]const u8,
835816 out_filename: []const u8,
836817 output_path: ?[]const u8,
818 output_lib_path: ?[]const u8,
837819 static: bool,
838820 version: Version,
839821 object_files: ArrayList([]const u8),
......@@ -844,32 +826,34 @@ pub const LibExeObjStep = struct {
844826 strip: bool,
845827 full_path_libs: ArrayList([]const u8),
846828 need_flat_namespace_hack: bool,
847 is_zig: bool,
848 cflags: ArrayList([]const u8),
849829 include_dirs: ArrayList([]const u8),
850830 lib_paths: ArrayList([]const u8),
851 disable_libc: bool,
852831 frameworks: BufSet,
853832 verbose_link: bool,
833 verbose_cc: bool,
854834 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
857840 root_src: ?[]const u8,
858841 output_h_path: ?[]const u8,
859842 out_h_filename: []const u8,
843 out_lib_filename: []const u8,
860844 assembly_files: ArrayList([]const u8),
861845 packages: ArrayList(Pkg),
862846 build_options_contents: std.Buffer,
863847 system_linker_hack: bool,
864848
865 // C only stuff
866 source_files: ArrayList([]const u8),
849 c_source_files: ArrayList(*CSourceFile),
867850 object_src: []const u8,
868851
869852 const Kind = enum {
870853 Exe,
871854 Lib,
872855 Obj,
856 Test,
873857 };
874858
875859 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {
......@@ -878,46 +862,27 @@ pub const LibExeObjStep = struct {
878862 return self;
879863 }
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
887865 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
888866 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
889867 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
890868 return self;
891869 }
892870
893 pub fn createCStaticLibrary(builder: *Builder, name: []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 {
871 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
900872 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
901873 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
902874 return self;
903875 }
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
912877 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
913878 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
914879 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));
915880 return self;
916881 }
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 {
919884 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));
921886 return self;
922887 }
923888
......@@ -926,6 +891,7 @@ pub const LibExeObjStep = struct {
926891 .strip = false,
927892 .builder = builder,
928893 .verbose_link = false,
894 .verbose_cc = false,
929895 .build_mode = builtin.Mode.Debug,
930896 .static = static,
931897 .kind = kind,
......@@ -937,70 +903,30 @@ pub const LibExeObjStep = struct {
937903 .frameworks = BufSet.init(builder.allocator),
938904 .step = Step.init(name, builder.allocator, make),
939905 .output_path = null,
906 .output_lib_path = null,
940907 .output_h_path = null,
941908 .version = ver,
942909 .out_filename = undefined,
943910 .out_h_filename = builder.fmt("{}.h", name),
911 .out_lib_filename = undefined,
944912 .major_only_filename = undefined,
945913 .name_only_filename = undefined,
946914 .object_files = ArrayList([]const u8).init(builder.allocator),
947915 .assembly_files = ArrayList([]const u8).init(builder.allocator),
948916 .packages = ArrayList(Pkg).init(builder.allocator),
949 .is_zig = true,
950917 .full_path_libs = ArrayList([]const u8).init(builder.allocator),
951918 .need_flat_namespace_hack = false,
952 .cflags = ArrayList([]const u8).init(builder.allocator),
953 .source_files = undefined,
919 .c_source_files = ArrayList(*CSourceFile).init(builder.allocator),
954920 .include_dirs = ArrayList([]const u8).init(builder.allocator),
955921 .lib_paths = ArrayList([]const u8).init(builder.allocator),
956922 .object_src = undefined,
957 .disable_libc = true,
958923 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
959924 .c_std = Builder.CStd.C99,
960925 .system_linker_hack = false,
961 };
962 self.computeOutFileNames();
963 return self;
964 }
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,
926 .override_std_dir = null,
927 .exec_cmd_args = null,
928 .name_prefix = "",
929 .filter = null,
1004930 };
1005931 self.computeOutFileNames();
1006932 return self;
......@@ -1014,23 +940,37 @@ pub const LibExeObjStep = struct {
1014940 Kind.Exe => {
1015941 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
1016942 },
943 Kind.Test => {
944 self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());
945 },
1017946 Kind.Lib => {
1018947 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;
1020957 } else {
1021958 switch (self.target.getOs()) {
1022959 builtin.Os.ios, builtin.Os.macosx => {
1023960 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
1024961 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
1025962 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
963 self.out_lib_filename = self.out_filename;
1026964 },
1027965 builtin.Os.windows => {
1028966 self.out_filename = self.builder.fmt("{}.dll", self.name);
967 self.out_lib_filename = self.builder.fmt("{}.lib", self.name);
1029968 },
1030969 else => {
1031970 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
1032971 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
1033972 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
973 self.out_lib_filename = self.out_filename;
1034974 },
1035975 }
1036976 }
......@@ -1065,7 +1005,11 @@ pub const LibExeObjStep = struct {
10651005
10661006 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
10701014 // TODO should be some kind of isolated directory that only has this header in it
10711015 self.include_dirs.append(self.builder.cache_root) catch unreachable;
......@@ -1081,24 +1025,44 @@ pub const LibExeObjStep = struct {
10811025 }
10821026
10831027 pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
1084 assert(self.kind != Kind.Obj);
10851028 self.link_libs.put(name) catch unreachable;
10861029 }
10871030
1088 pub fn addSourceFile(self: *LibExeObjStep, file: []const u8) void {
1089 assert(self.kind != Kind.Obj);
1090 assert(!self.is_zig);
1091 self.source_files.append(file) catch unreachable;
1031 pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
1032 assert(self.kind == Kind.Test);
1033 self.name_prefix = text;
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;
10921048 }
10931049
10941050 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
10951051 self.verbose_link = value;
10961052 }
10971053
1054 pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void {
1055 self.verbose_cc = value;
1056 }
1057
10981058 pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {
10991059 self.build_mode = mode;
11001060 }
11011061
1062 pub fn overrideStdDir(self: *LibExeObjStep, dir_path: []const u8) void {
1063 self.override_std_dir = dir_path;
1064 }
1065
11021066 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
11031067 self.output_path = file_path;
11041068
......@@ -1115,6 +1079,22 @@ pub const LibExeObjStep = struct {
11151079 ) catch unreachable;
11161080 }
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
11181098 pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
11191099 self.output_h_path = file_path;
11201100
......@@ -1149,17 +1129,15 @@ pub const LibExeObjStep = struct {
11491129
11501130 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
11571132 // TODO should be some kind of isolated directory that only has this header in it
11581133 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 }
11591138 }
11601139
11611140 pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {
1162 assert(self.is_zig);
11631141 const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream;
11641142 out.print("pub const {} = {};\n", name, value) catch unreachable;
11651143 }
......@@ -1173,23 +1151,15 @@ pub const LibExeObjStep = struct {
11731151 }
11741152
11751153 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
1176 assert(self.is_zig);
1177
11781154 self.packages.append(Pkg{
11791155 .name = name,
11801156 .path = pkg_index_path,
11811157 }) catch unreachable;
11821158 }
11831159
1184 pub fn addCompileFlags(self: *LibExeObjStep, flags: []const []const u8) void {
1185 for (flags) |flag| {
1186 self.cflags.append(flag) catch unreachable;
1187 }
1188 }
1189
1190 pub fn setNoStdLib(self: *LibExeObjStep, disable: bool) void {
1191 assert(!self.is_zig);
1192 self.disable_libc = disable;
1160 pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
1161 assert(self.kind == Kind.Test);
1162 self.exec_cmd_args = args;
11931163 }
11941164
11951165 pub fn enableSystemLinkerHack(self: *LibExeObjStep) void {
......@@ -1198,15 +1168,11 @@ pub const LibExeObjStep = struct {
11981168
11991169 fn make(step: *Step) !void {
12001170 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 {
12051171 const builder = self.builder;
12061172
1207 assert(self.is_zig);
1208
1209 if (self.root_src == null and self.object_files.len == 0 and self.assembly_files.len == 0) {
1173 if (self.root_src == null and self.object_files.len == 0 and
1174 self.assembly_files.len == 0 and self.c_source_files.len == 0)
1175 {
12101176 warn("{}: linker needs 1 or more objects to link\n", self.step.name);
12111177 return error.NeedAnObject;
12121178 }
......@@ -1220,6 +1186,7 @@ pub const LibExeObjStep = struct {
12201186 Kind.Lib => "build-lib",
12211187 Kind.Exe => "build-exe",
12221188 Kind.Obj => "build-obj",
1189 Kind.Test => "test",
12231190 };
12241191 zig_args.append(cmd) catch unreachable;
12251192
......@@ -1227,6 +1194,14 @@ pub const LibExeObjStep = struct {
12271194 zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;
12281195 }
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
12301205 if (self.build_options_contents.len() > 0) {
12311206 const build_options_file = try os.path.join(
12321207 builder.allocator,
......@@ -1239,6 +1214,16 @@ pub const LibExeObjStep = struct {
12391214 try zig_args.append("--pkg-end");
12401215 }
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
12421227 for (self.object_files.toSliceConst()) |object_file| {
12431228 zig_args.append("--object") catch unreachable;
12441229 zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;
......@@ -1255,6 +1240,7 @@ pub const LibExeObjStep = struct {
12551240 if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable;
12561241 if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable;
12571242 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
12591245 if (self.strip) {
12601246 zig_args.append("--strip") catch unreachable;
......@@ -1274,6 +1260,12 @@ pub const LibExeObjStep = struct {
12741260 zig_args.append("--output") catch unreachable;
12751261 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
12771269 if (self.kind != Kind.Exe) {
12781270 const output_h_path = self.getOutputHPath();
12791271 zig_args.append("--output-h") catch unreachable;
......@@ -1293,7 +1285,7 @@ pub const LibExeObjStep = struct {
12931285 zig_args.append("--ver-patch") catch unreachable;
12941286 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
12951287 }
1296 if (self.kind == Kind.Exe and self.static) {
1288 if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {
12971289 zig_args.append("--static") catch unreachable;
12981290 }
12991291
......@@ -1325,11 +1317,16 @@ pub const LibExeObjStep = struct {
13251317 }
13261318 }
13271319
1328 if (!self.disable_libc) {
1329 zig_args.append("--library") catch unreachable;
1330 zig_args.append("c") catch unreachable;
1320 if (self.exec_cmd_args) |exec_cmd_args| {
1321 for (exec_cmd_args) |cmd_arg| {
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 }
13311329 }
1332
13331330 for (self.packages.toSliceConst()) |pkg| {
13341331 zig_args.append("--pkg-begin") catch unreachable;
13351332 zig_args.append(pkg.name) catch unreachable;
......@@ -1363,8 +1360,14 @@ pub const LibExeObjStep = struct {
13631360 }
13641361
13651362 for (self.full_path_libs.toSliceConst()) |full_path_lib| {
1366 zig_args.append("--library") catch unreachable;
1367 zig_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;
1363 try zig_args.append("--library");
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 }
13681371 }
13691372
13701373 if (self.target.isDarwin()) {
......@@ -1379,558 +1382,16 @@ pub const LibExeObjStep = struct {
13791382 try zig_args.append("--system-linker-hack");
13801383 }
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 }
19281385 if (self.override_std_dir) |dir| {
19291386 try zig_args.append("--override-std-dir");
19301387 try zig_args.append(builder.pathFromRoot(dir));
19311388 }
19321389
19331390 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 }
19341395 }
19351396};
19361397
......@@ -1976,6 +1437,7 @@ const InstallArtifactStep = struct {
19761437 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
19771438 const dest_dir = switch (artifact.kind) {
19781439 LibExeObjStep.Kind.Obj => unreachable,
1440 LibExeObjStep.Kind.Test => unreachable,
19791441 LibExeObjStep.Kind.Exe => builder.exe_dir,
19801442 LibExeObjStep.Kind.Lib => builder.lib_dir,
19811443 };
......@@ -2012,6 +1474,7 @@ const InstallArtifactStep = struct {
20121474 builtin.Os.windows => {},
20131475 else => switch (self.artifact.kind) {
20141476 LibExeObjStep.Kind.Obj => unreachable,
1477 LibExeObjStep.Kind.Test => unreachable,
20151478 LibExeObjStep.Kind.Exe => u32(0o755),
20161479 LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755),
20171480 },
test/build_examples.zig+2-6
......@@ -7,12 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
77 cases.addC("example/hello_world/hello_libc.zig");
88 cases.add("example/cat/main.zig");
99 cases.add("example/guess_number/main.zig");
10 if (!is_windows) {
11 // TODO get this test passing on windows
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 }
10 cases.addBuildFile("example/shared_library/build.zig");
11 cases.addBuildFile("example/mix_o_files/build.zig");
1612 if (builtin.os != builtin.Os.macosx) {
1713 // TODO https://github.com/ziglang/zig/issues/1126
1814 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;
33pub fn build(b: *Builder) void {
44 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"});
78 c_obj.setBuildMode(rel_opts);
8 c_obj.setNoStdLib(true);
9 c_obj.linkSystemLibrary("c");
910
1011 const main = b.addTest("main.zig");
1112 main.setBuildMode(rel_opts);