authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-25 11:37:54-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-25 11:45:00-05:00
loge76ce2c1d0d3988359267fd3030a81a52ec99f3f
tree04e2c5c67961d5d54ba9d31b2e1601837b84a9df
parente5d4862e145c38ffc1111ee578ddcafc1e35ad57
signaturelock-open Commit is signed but in an unrecognized format.

first class support for compiling C code

New CLI parameter: --c-source [options] [file] It even works with `--cache on` when there are transitive dependencies. Instead of `builder.addCExecutable`, use `builder.addExecutable` and pass `null` for the root source file. Then use `builder.addCSourceFile`, which takes the path to the C code, and a list of C compiler args. Be sure to linkSystemLibrary("c") if you want libc headers to be available. Merge TestStep into LibExeObjStep. That was long overdue.

8 files changed, 379 insertions(+), 723 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+7
...@@ -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
...@@ -1788,6 +1793,7 @@ struct CodeGen {...@@ -1788,6 +1793,7 @@ struct CodeGen {
1788 bool verbose_ir;1793 bool verbose_ir;
1789 bool verbose_llvm_ir;1794 bool verbose_llvm_ir;
1790 bool verbose_cimport;1795 bool verbose_cimport;
1796 bool verbose_cc;
1791 bool error_during_imports;1797 bool error_during_imports;
1792 bool generate_error_name_table;1798 bool generate_error_name_table;
1793 bool enable_cache;1799 bool enable_cache;
...@@ -1805,6 +1811,7 @@ struct CodeGen {...@@ -1805,6 +1811,7 @@ struct CodeGen {
1805 ZigList<Buf *> forbidden_libs;1811 ZigList<Buf *> forbidden_libs;
1806 ZigList<Buf *> link_objects;1812 ZigList<Buf *> link_objects;
1807 ZigList<Buf *> assembly_files;1813 ZigList<Buf *> assembly_files;
1814 ZigList<CFile *> c_source_files;
1808 ZigList<const char *> lib_dirs;1815 ZigList<const char *> lib_dirs;
18091816
1810 ZigLibCInstallation *libc;1817 ZigLibCInstallation *libc;
src/codegen.cpp+184-11
...@@ -7885,8 +7885,8 @@ static void detect_libc(CodeGen *g) {...@@ -7885,8 +7885,8 @@ static void detect_libc(CodeGen *g) {
7885 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));7885 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
7886 exit(1);7886 exit(1);
7887 }7887 }
7888 if (rename(buf_ptr(native_libc_tmp), buf_ptr(native_libc_txt)) == -1) {7888 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));7889 fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), err_str(err));
7890 exit(1);7890 exit(1);
7891 }7891 }
7892 }7892 }
...@@ -8123,6 +8123,162 @@ static void gen_global_asm(CodeGen *g) {...@@ -8123,6 +8123,162 @@ static void gen_global_asm(CodeGen *g) {
8123 }8123 }
8124}8124}
81258125
8126static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
8127 Error err;
8128
8129 Buf *c_source_file = buf_create_from_str(c_file->source_path);
8130 Buf *c_source_basename = buf_alloc();
8131 os_path_split(c_source_file, nullptr, c_source_basename);
8132 Buf *out_obj_name = buf_sprintf("%s%s", buf_ptr(c_source_basename), target_o_file_ext(g->zig_target));
8133 Buf *out_obj_path = buf_alloc();
8134 os_path_join(&g->cache_dir, out_obj_name, out_obj_path);
8135 Buf *out_dep_name = buf_sprintf("%s.d", buf_ptr(c_source_file));
8136 Buf *out_dep_path = buf_alloc();
8137 os_path_join(&g->cache_dir, out_dep_name, out_dep_path);
8138
8139 Termination term;
8140 ZigList<const char *> args = {};
8141 args.append("cc");
8142
8143 if (g->enable_cache) {
8144 args.append("-MD");
8145 args.append("-MF");
8146 args.append(buf_ptr(out_dep_path));
8147 }
8148
8149 args.append("-isystem");
8150 args.append(buf_ptr(g->zig_c_headers_dir));
8151
8152 if (g->libc != nullptr) {
8153 args.append("-isystem");
8154 args.append(buf_ptr(&g->libc->include_dir));
8155 }
8156
8157 if (g->zig_target->is_native) {
8158 args.append("-march=native");
8159 } else {
8160 args.append("-target");
8161 args.append(buf_ptr(&g->triple_str));
8162 }
8163
8164 if (!g->strip_debug_symbols) {
8165 args.append("-g");
8166 }
8167 switch (g->build_mode) {
8168 case BuildModeDebug:
8169 if (g->libc_link_lib != nullptr) {
8170 args.append("-fstack-protector-strong");
8171 args.append("--param");
8172 args.append("ssp-buffer-size=4");
8173 } else {
8174 args.append("-fno-stack-protector");
8175 }
8176 break;
8177 case BuildModeSafeRelease:
8178 args.append("-O2");
8179 if (g->libc_link_lib != nullptr) {
8180 args.append("-D_FORTIFY_SOURCE=2");
8181 args.append("-fstack-protector-strong");
8182 args.append("--param");
8183 args.append("ssp-buffer-size=4");
8184 } else {
8185 args.append("-fno-stack-protector");
8186 }
8187 break;
8188 case BuildModeFastRelease:
8189 args.append("-O2");
8190 args.append("-fno-stack-protector");
8191 break;
8192 case BuildModeSmallRelease:
8193 args.append("-Os");
8194 args.append("-fno-stack-protector");
8195 break;
8196 }
8197
8198 args.append("-o");
8199 args.append(buf_ptr(out_obj_path));
8200
8201 args.append("-c");
8202 args.append(buf_ptr(c_source_file));
8203
8204 if (!g->disable_pic) {
8205 args.append("-fPIC");
8206 }
8207
8208 for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
8209 args.append(g->clang_argv[arg_i]);
8210 }
8211
8212 for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) {
8213 args.append(c_file->args.at(arg_i));
8214 }
8215
8216 if (g->verbose_cc) {
8217 for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {
8218 fprintf(stderr, "%s ", args.at(arg_i));
8219 }
8220 fprintf(stderr, "\n");
8221 }
8222
8223 os_spawn_process(buf_ptr(self_exe_path), args, &term);
8224 if (term.how != TerminationIdClean || term.code != 0) {
8225 fprintf(stderr, "`zig cc` failed\n");
8226 exit(1);
8227 }
8228
8229 g->link_objects.append(out_obj_path);
8230
8231 // add the files depended on to the cache system
8232 if (g->enable_cache) {
8233 Buf *contents = buf_alloc();
8234 if ((err = os_fetch_file_path(out_dep_path, contents, false))) {
8235 fprintf(stderr, "unable to read .d file: %s\n", err_str(err));
8236 exit(1);
8237 }
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 SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
8243 // skip first line
8244 SplitIterator_next(&it);
8245 for (;;) {
8246 Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
8247 if (!opt_line.is_some)
8248 break;
8249 if (opt_line.value.len == 0)
8250 continue;
8251 SplitIterator line_it = memSplit(opt_line.value, str(" \t"));
8252 Slice<uint8_t> filename;
8253 if (!SplitIterator_next(&line_it).unwrap(&filename))
8254 continue;
8255 Buf *filename_buf = buf_create_from_slice(filename);
8256 if ((err = cache_add_file(&g->cache_hash, filename_buf))) {
8257 fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(c_source_file), err_str(err));
8258 exit(1);
8259 }
8260 }
8261 }
8262}
8263
8264static void gen_c_objects(CodeGen *g) {
8265 Error err;
8266
8267 if (g->c_source_files.length == 0)
8268 return;
8269
8270 Buf *self_exe_path = buf_alloc();
8271 if ((err = os_self_exe_path(self_exe_path))) {
8272 fprintf(stderr, "Unable to get self exe path: %s\n", err_str(err));
8273 exit(1);
8274 }
8275
8276 for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
8277 CFile *c_file = g->c_source_files.at(c_file_i);
8278 gen_c_object(g, self_exe_path, c_file);
8279 }
8280}
8281
8126void codegen_add_object(CodeGen *g, Buf *object_path) {8282void codegen_add_object(CodeGen *g, Buf *object_path) {
8127 g->link_objects.append(object_path);8283 g->link_objects.append(object_path);
8128}8284}
...@@ -8637,6 +8793,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -8637,6 +8793,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);8793 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);8794 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);8795 cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);
8796 for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
8797 CFile *c_file = g->c_source_files.at(c_file_i);
8798 cache_file(ch, buf_create_from_str(c_file->source_path));
8799 for (size_t opt_i = 0; opt_i < c_file->args.length; opt_i += 1) {
8800 cache_buf(ch, buf_create_from_str(c_file->args.at(opt_i)));
8801 }
8802 }
8640 cache_int(ch, g->emit_file_type);8803 cache_int(ch, g->emit_file_type);
8641 cache_int(ch, g->build_mode);8804 cache_int(ch, g->build_mode);
8642 cache_int(ch, g->out_type);8805 cache_int(ch, g->out_type);
...@@ -8788,6 +8951,7 @@ void codegen_build_and_link(CodeGen *g) {...@@ -8788,6 +8951,7 @@ void codegen_build_and_link(CodeGen *g) {
87888951
8789 gen_global_asm(g);8952 gen_global_asm(g);
8790 gen_root_source(g);8953 gen_root_source(g);
8954 gen_c_objects(g);
87918955
8792 if (g->enable_cache) {8956 if (g->enable_cache) {
8793 if ((err = cache_final(&g->cache_hash, &digest))) {8957 if ((err = cache_final(&g->cache_hash, &digest))) {
...@@ -8805,16 +8969,25 @@ void codegen_build_and_link(CodeGen *g) {...@@ -8805,16 +8969,25 @@ void codegen_build_and_link(CodeGen *g) {
8805 resolve_out_paths(g);8969 resolve_out_paths(g);
88068970
8807 codegen_add_time_event(g, "Code Generation");8971 codegen_add_time_event(g, "Code Generation");
8808 do_code_gen(g);8972 if (g->out_type == OutTypeObj && g->c_source_files.length == 1) {
8809 codegen_add_time_event(g, "LLVM Emit Output");8973 assert(g->link_objects.length == 1);
8810 zig_llvm_emit_output(g);8974 if ((err = os_rename(g->link_objects.pop(), &g->o_file_output_path))) {
8975 fprintf(stderr, "unable to move object to '%s': %s\n",
8976 buf_ptr(&g->o_file_output_path), err_str(err));
8977 exit(1);
8978 }
8979 } else {
8980 do_code_gen(g);
8981 codegen_add_time_event(g, "LLVM Emit Output");
8982 zig_llvm_emit_output(g);
88118983
8812 if (g->out_h_path != nullptr) {8984 if (g->out_h_path != nullptr) {
8813 codegen_add_time_event(g, "Generate .h");8985 codegen_add_time_event(g, "Generate .h");
8814 gen_h_file(g);8986 gen_h_file(g);
8815 }8987 }
8816 if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {8988 if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {
8817 codegen_link(g);8989 codegen_link(g);
8990 }
8818 }8991 }
8819 }8992 }
88208993
src/main.cpp+67-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"
...@@ -77,6 +77,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -77,6 +77,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"77 " --verbose-ir enable compiler debug output for Zig IR\n"
78 " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"78 " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
79 " --verbose-cimport enable compiler debug output for C imports\n"79 " --verbose-cimport enable compiler debug output for C imports\n"
80 " --verbose-cc enable compiler debug output for C compilation\n"
80 " -dirafter [dir] same as -isystem but do it last\n"81 " -dirafter [dir] same as -isystem but do it last\n"
81 " -isystem [dir] add additional search path for other .h files\n"82 " -isystem [dir] add additional search path for other .h files\n"
82 " -mllvm [arg] forward an arg to LLVM's option processing\n"83 " -mllvm [arg] forward an arg to LLVM's option processing\n"
...@@ -181,7 +182,6 @@ enum Cmd {...@@ -181,7 +182,6 @@ enum Cmd {
181 CmdNone,182 CmdNone,
182 CmdBuild,183 CmdBuild,
183 CmdBuiltin,184 CmdBuiltin,
184 CmdHelp,
185 CmdRun,185 CmdRun,
186 CmdTargets,186 CmdTargets,
187 CmdTest,187 CmdTest,
...@@ -385,6 +385,7 @@ int main(int argc, char **argv) {...@@ -385,6 +385,7 @@ int main(int argc, char **argv) {
385 bool verbose_ir = false;385 bool verbose_ir = false;
386 bool verbose_llvm_ir = false;386 bool verbose_llvm_ir = false;
387 bool verbose_cimport = false;387 bool verbose_cimport = false;
388 bool verbose_cc = false;
388 ErrColor color = ErrColorAuto;389 ErrColor color = ErrColorAuto;
389 CacheOpt enable_cache = CacheOptAuto;390 CacheOpt enable_cache = CacheOptAuto;
390 const char *libc_txt = nullptr;391 const char *libc_txt = nullptr;
...@@ -404,6 +405,7 @@ int main(int argc, char **argv) {...@@ -404,6 +405,7 @@ int main(int argc, char **argv) {
404 ZigList<const char *> rpath_list = {0};405 ZigList<const char *> rpath_list = {0};
405 bool each_lib_rpath = false;406 bool each_lib_rpath = false;
406 ZigList<const char *> objects = {0};407 ZigList<const char *> objects = {0};
408 ZigList<CFile *> c_source_files = {0};
407 ZigList<const char *> asm_files = {0};409 ZigList<const char *> asm_files = {0};
408 const char *test_filter = nullptr;410 const char *test_filter = nullptr;
409 const char *test_name_prefix = nullptr;411 const char *test_name_prefix = nullptr;
...@@ -512,6 +514,7 @@ int main(int argc, char **argv) {...@@ -512,6 +514,7 @@ int main(int argc, char **argv) {
512 " --verbose-ir Enable compiler debug output for Zig IR\n"514 " --verbose-ir Enable compiler debug output for Zig IR\n"
513 " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"515 " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
514 " --verbose-cimport Enable compiler debug output for C imports\n"516 " --verbose-cimport Enable compiler debug output for C imports\n"
517 " --verbose-cc Enable compiler debug output for C compilation\n"
515 "\n"518 "\n"
516 , zig_exe_path);519 , zig_exe_path);
517 return EXIT_SUCCESS;520 return EXIT_SUCCESS;
...@@ -521,7 +524,7 @@ int main(int argc, char **argv) {...@@ -521,7 +524,7 @@ int main(int argc, char **argv) {
521 "No 'build.zig' file found.\n"524 "No 'build.zig' file found.\n"
522 "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"525 "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"526 "or build an executable directly with `zig build-exe $FILENAME.zig`.\n"
524 "See: `zig build --help` or `zig help` for more options.\n"527 "See: `zig build --help` or `zig --help` for more options.\n"
525 );528 );
526 return EXIT_FAILURE;529 return EXIT_FAILURE;
527 }530 }
...@@ -587,9 +590,9 @@ int main(int argc, char **argv) {...@@ -587,9 +590,9 @@ int main(int argc, char **argv) {
587 build_mode = BuildModeSmallRelease;590 build_mode = BuildModeSmallRelease;
588 } else if (strcmp(arg, "--help") == 0) {591 } else if (strcmp(arg, "--help") == 0) {
589 if (cmd == CmdLibC) {592 if (cmd == CmdLibC) {
590 return print_libc_usage(arg0, stderr, EXIT_FAILURE);593 return print_libc_usage(arg0, stdout, EXIT_SUCCESS);
591 } else {594 } else {
592 return print_full_usage(arg0, stderr, EXIT_FAILURE);595 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
593 }596 }
594 } else if (strcmp(arg, "--strip") == 0) {597 } else if (strcmp(arg, "--strip") == 0) {
595 strip = true;598 strip = true;
...@@ -607,6 +610,8 @@ int main(int argc, char **argv) {...@@ -607,6 +610,8 @@ int main(int argc, char **argv) {
607 verbose_llvm_ir = true;610 verbose_llvm_ir = true;
608 } else if (strcmp(arg, "--verbose-cimport") == 0) {611 } else if (strcmp(arg, "--verbose-cimport") == 0) {
609 verbose_cimport = true;612 verbose_cimport = true;
613 } else if (strcmp(arg, "--verbose-cc") == 0) {
614 verbose_cc = true;
610 } else if (strcmp(arg, "-rdynamic") == 0) {615 } else if (strcmp(arg, "-rdynamic") == 0) {
611 rdynamic = true;616 rdynamic = true;
612 } else if (strcmp(arg, "--each-lib-rpath") == 0) {617 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
...@@ -714,6 +719,19 @@ int main(int argc, char **argv) {...@@ -714,6 +719,19 @@ int main(int argc, char **argv) {
714 forbidden_link_libs.append(argv[i]);719 forbidden_link_libs.append(argv[i]);
715 } else if (strcmp(arg, "--object") == 0) {720 } else if (strcmp(arg, "--object") == 0) {
716 objects.append(argv[i]);721 objects.append(argv[i]);
722 } else if (strcmp(arg, "--c-source") == 0) {
723 CFile *c_file = allocate<CFile>(1);
724 for (;;) {
725 if (argv[i][0] == '-') {
726 c_file->args.append(argv[i]);
727 i += 1;
728 continue;
729 } else {
730 c_file->source_path = argv[i];
731 c_source_files.append(c_file);
732 break;
733 }
734 }
717 } else if (strcmp(arg, "--assembly") == 0) {735 } else if (strcmp(arg, "--assembly") == 0) {
718 asm_files.append(argv[i]);736 asm_files.append(argv[i]);
719 } else if (strcmp(arg, "--cache-dir") == 0) {737 } else if (strcmp(arg, "--cache-dir") == 0) {
...@@ -792,8 +810,6 @@ int main(int argc, char **argv) {...@@ -792,8 +810,6 @@ int main(int argc, char **argv) {
792 } else if (strcmp(arg, "build-lib") == 0) {810 } else if (strcmp(arg, "build-lib") == 0) {
793 cmd = CmdBuild;811 cmd = CmdBuild;
794 out_type = OutTypeLib;812 out_type = OutTypeLib;
795 } else if (strcmp(arg, "help") == 0) {
796 cmd = CmdHelp;
797 } else if (strcmp(arg, "run") == 0) {813 } else if (strcmp(arg, "run") == 0) {
798 cmd = CmdRun;814 cmd = CmdRun;
799 out_type = OutTypeExe;815 out_type = OutTypeExe;
...@@ -835,7 +851,6 @@ int main(int argc, char **argv) {...@@ -835,7 +851,6 @@ int main(int argc, char **argv) {
835 }851 }
836 break;852 break;
837 case CmdBuiltin:853 case CmdBuiltin:
838 case CmdHelp:
839 case CmdVersion:854 case CmdVersion:
840 case CmdZen:855 case CmdZen:
841 case CmdTargets:856 case CmdTargets:
...@@ -910,15 +925,43 @@ int main(int argc, char **argv) {...@@ -910,15 +925,43 @@ int main(int argc, char **argv) {
910 case CmdTranslateC:925 case CmdTranslateC:
911 case CmdTest:926 case CmdTest:
912 {927 {
913 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {928 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");929 c_source_files.length == 0)
930 {
931 fprintf(stderr,
932 "Expected at least one of these things:\n"
933 " * Zig root source file argument\n"
934 " * --object argument\n"
935 " * --assembly argument\n"
936 " * --c-source argument\n");
915 return print_error_usage(arg0);937 return print_error_usage(arg0);
916 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {938 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
917 fprintf(stderr, "Expected source file argument.\n");939 fprintf(stderr, "Expected source file argument.\n");
918 return print_error_usage(arg0);940 return print_error_usage(arg0);
919 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {941 } else if (cmd == CmdBuild && out_type == OutTypeObj) {
920 fprintf(stderr, "When building an object file, --object arguments are invalid.\n");942 if (objects.length != 0) {
921 return print_error_usage(arg0);943 fprintf(stderr,
944 "When building an object file, --object arguments are invalid.\n"
945 "Consider building a static library instead.\n");
946 return print_error_usage(arg0);
947 }
948 size_t zig_root_src_count = in_file ? 1 : 0;
949 if (zig_root_src_count + c_source_files.length > 1) {
950 fprintf(stderr,
951 "When building an object file, only one of these allowed:\n"
952 " * Zig root source file argument\n"
953 " * --c-source argument\n"
954 "Consider building a static library instead.\n");
955 return print_error_usage(arg0);
956 }
957 if (c_source_files.length != 0 && asm_files.length != 0) {
958 fprintf(stderr,
959 "When building an object file, only one of these allowed:\n"
960 " * --assembly argument\n"
961 " * --c-source argument\n"
962 "Consider building a static library instead.\n");
963 return print_error_usage(arg0);
964 }
922 }965 }
923966
924 assert(cmd != CmdBuild || out_type != OutTypeUnknown);967 assert(cmd != CmdBuild || out_type != OutTypeUnknown);
...@@ -945,6 +988,13 @@ int main(int argc, char **argv) {...@@ -945,6 +988,13 @@ int main(int argc, char **argv) {
945 }988 }
946 }989 }
947990
991 if (need_name && buf_out_name == nullptr && c_source_files.length == 1) {
992 Buf basename = BUF_INIT;
993 os_path_split(buf_create_from_str(c_source_files.at(0)->source_path), nullptr, &basename);
994 buf_out_name = buf_alloc();
995 os_path_extname(&basename, buf_out_name, nullptr);
996 }
997
948 if (need_name && buf_out_name == nullptr) {998 if (need_name && buf_out_name == nullptr) {
949 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");999 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
950 return print_error_usage(arg0);1000 return print_error_usage(arg0);
...@@ -996,6 +1046,7 @@ int main(int argc, char **argv) {...@@ -996,6 +1046,7 @@ int main(int argc, char **argv) {
996 g->verbose_ir = verbose_ir;1046 g->verbose_ir = verbose_ir;
997 g->verbose_llvm_ir = verbose_llvm_ir;1047 g->verbose_llvm_ir = verbose_llvm_ir;
998 g->verbose_cimport = verbose_cimport;1048 g->verbose_cimport = verbose_cimport;
1049 g->verbose_cc = verbose_cc;
999 codegen_set_errmsg_color(g, color);1050 codegen_set_errmsg_color(g, color);
1000 g->system_linker_hack = system_linker_hack;1051 g->system_linker_hack = system_linker_hack;
10011052
...@@ -1048,6 +1099,7 @@ int main(int argc, char **argv) {...@@ -1048,6 +1099,7 @@ int main(int argc, char **argv) {
1048 add_package(g, cur_pkg, g->root_package);1099 add_package(g, cur_pkg, g->root_package);
10491100
1050 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {1101 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
1102 g->c_source_files = c_source_files;
1051 for (size_t i = 0; i < objects.length; i += 1) {1103 for (size_t i = 0; i < objects.length; i += 1) {
1052 codegen_add_object(g, buf_create_from_str(objects.at(i)));1104 codegen_add_object(g, buf_create_from_str(objects.at(i)));
1053 }1105 }
...@@ -1147,8 +1199,6 @@ int main(int argc, char **argv) {...@@ -1147,8 +1199,6 @@ int main(int argc, char **argv) {
1147 zig_unreachable();1199 zig_unreachable();
1148 }1200 }
1149 }1201 }
1150 case CmdHelp:
1151 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
1152 case CmdVersion:1202 case CmdVersion:
1153 printf("%s\n", ZIG_VERSION_STRING);1203 printf("%s\n", ZIG_VERSION_STRING);
1154 return EXIT_SUCCESS;1204 return EXIT_SUCCESS;
...@@ -1158,7 +1208,6 @@ int main(int argc, char **argv) {...@@ -1158,7 +1208,6 @@ int main(int argc, char **argv) {
1158 case CmdTargets:1208 case CmdTargets:
1159 return print_target_list(stdout);1209 return print_target_list(stdout);
1160 case CmdNone:1210 case CmdNone:
1161 fprintf(stderr, "Zig programming language\n");1211 return print_full_usage(arg0, stderr, EXIT_FAILURE);
1162 return print_error_usage(arg0);
1163 }1212 }
1164}1213}
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+108-686
...@@ -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,
...@@ -844,16 +825,17 @@ pub const LibExeObjStep = struct {...@@ -844,16 +825,17 @@ pub const LibExeObjStep = struct {
844 strip: bool,825 strip: bool,
845 full_path_libs: ArrayList([]const u8),826 full_path_libs: ArrayList([]const u8),
846 need_flat_namespace_hack: bool,827 need_flat_namespace_hack: bool,
847 is_zig: bool,
848 cflags: ArrayList([]const u8),
849 include_dirs: ArrayList([]const u8),828 include_dirs: ArrayList([]const u8),
850 lib_paths: ArrayList([]const u8),829 lib_paths: ArrayList([]const u8),
851 disable_libc: bool,
852 frameworks: BufSet,830 frameworks: BufSet,
853 verbose_link: bool,831 verbose_link: bool,
832 verbose_cc: bool,
854 c_std: Builder.CStd,833 c_std: Builder.CStd,
834 override_std_dir: ?[]const u8,
835 exec_cmd_args: ?[]const ?[]const u8,
836 name_prefix: []const u8,
837 filter: ?[]const u8,
855838
856 // zig only stuff
857 root_src: ?[]const u8,839 root_src: ?[]const u8,
858 output_h_path: ?[]const u8,840 output_h_path: ?[]const u8,
859 out_h_filename: []const u8,841 out_h_filename: []const u8,
...@@ -862,14 +844,14 @@ pub const LibExeObjStep = struct {...@@ -862,14 +844,14 @@ pub const LibExeObjStep = struct {
862 build_options_contents: std.Buffer,844 build_options_contents: std.Buffer,
863 system_linker_hack: bool,845 system_linker_hack: bool,
864846
865 // C only stuff847 c_source_files: ArrayList(*CSourceFile),
866 source_files: ArrayList([]const u8),
867 object_src: []const u8,848 object_src: []const u8,
868849
869 const Kind = enum {850 const Kind = enum {
870 Exe,851 Exe,
871 Lib,852 Lib,
872 Obj,853 Obj,
854 Test,
873 };855 };
874856
875 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {857 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {
...@@ -878,46 +860,27 @@ pub const LibExeObjStep = struct {...@@ -878,46 +860,27 @@ pub const LibExeObjStep = struct {
878 return self;860 return self;
879 }861 }
880862
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 {863 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
888 const self = builder.allocator.create(LibExeObjStep) catch unreachable;864 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
889 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));865 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
890 return self;866 return self;
891 }867 }
892868
893 pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {869 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;870 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
901 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));871 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
902 return self;872 return self;
903 }873 }
904874
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 {875 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
913 const self = builder.allocator.create(LibExeObjStep) catch unreachable;876 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
914 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));877 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));
915 return self;878 return self;
916 }879 }
917880
918 pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {881 pub fn createTest(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
919 const self = builder.allocator.create(LibExeObjStep) catch unreachable;882 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
920 self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);883 self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, builder.version(0, 0, 0));
921 return self;884 return self;
922 }885 }
923886
...@@ -926,6 +889,7 @@ pub const LibExeObjStep = struct {...@@ -926,6 +889,7 @@ pub const LibExeObjStep = struct {
926 .strip = false,889 .strip = false,
927 .builder = builder,890 .builder = builder,
928 .verbose_link = false,891 .verbose_link = false,
892 .verbose_cc = false,
929 .build_mode = builtin.Mode.Debug,893 .build_mode = builtin.Mode.Debug,
930 .static = static,894 .static = static,
931 .kind = kind,895 .kind = kind,
...@@ -946,61 +910,19 @@ pub const LibExeObjStep = struct {...@@ -946,61 +910,19 @@ pub const LibExeObjStep = struct {
946 .object_files = ArrayList([]const u8).init(builder.allocator),910 .object_files = ArrayList([]const u8).init(builder.allocator),
947 .assembly_files = ArrayList([]const u8).init(builder.allocator),911 .assembly_files = ArrayList([]const u8).init(builder.allocator),
948 .packages = ArrayList(Pkg).init(builder.allocator),912 .packages = ArrayList(Pkg).init(builder.allocator),
949 .is_zig = true,
950 .full_path_libs = ArrayList([]const u8).init(builder.allocator),913 .full_path_libs = ArrayList([]const u8).init(builder.allocator),
951 .need_flat_namespace_hack = false,914 .need_flat_namespace_hack = false,
952 .cflags = ArrayList([]const u8).init(builder.allocator),915 .c_source_files = ArrayList(*CSourceFile).init(builder.allocator),
953 .source_files = undefined,
954 .include_dirs = ArrayList([]const u8).init(builder.allocator),916 .include_dirs = ArrayList([]const u8).init(builder.allocator),
955 .lib_paths = ArrayList([]const u8).init(builder.allocator),917 .lib_paths = ArrayList([]const u8).init(builder.allocator),
956 .object_src = undefined,918 .object_src = undefined,
957 .disable_libc = true,
958 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,919 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
959 .c_std = Builder.CStd.C99,920 .c_std = Builder.CStd.C99,
960 .system_linker_hack = false,921 .system_linker_hack = false,
961 };922 .override_std_dir = null,
962 self.computeOutFileNames();923 .exec_cmd_args = null,
963 return self;924 .name_prefix = "",
964 }925 .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 };926 };
1005 self.computeOutFileNames();927 self.computeOutFileNames();
1006 return self;928 return self;
...@@ -1014,6 +936,9 @@ pub const LibExeObjStep = struct {...@@ -1014,6 +936,9 @@ pub const LibExeObjStep = struct {
1014 Kind.Exe => {936 Kind.Exe => {
1015 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());937 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
1016 },938 },
939 Kind.Test => {
940 self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());
941 },
1017 Kind.Lib => {942 Kind.Lib => {
1018 if (self.static) {943 if (self.static) {
1019 self.out_filename = self.builder.fmt("lib{}.a", self.name);944 self.out_filename = self.builder.fmt("lib{}.a", self.name);
...@@ -1081,24 +1006,44 @@ pub const LibExeObjStep = struct {...@@ -1081,24 +1006,44 @@ pub const LibExeObjStep = struct {
1081 }1006 }
10821007
1083 pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {1008 pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
1084 assert(self.kind != Kind.Obj);
1085 self.link_libs.put(name) catch unreachable;1009 self.link_libs.put(name) catch unreachable;
1086 }1010 }
10871011
1088 pub fn addSourceFile(self: *LibExeObjStep, file: []const u8) void {1012 pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
1089 assert(self.kind != Kind.Obj);1013 assert(self.kind == Kind.Test);
1090 assert(!self.is_zig);1014 self.name_prefix = text;
1091 self.source_files.append(file) catch unreachable;1015 }
1016
1017 pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void {
1018 assert(self.kind == Kind.Test);
1019 self.filter = text;
1020 }
1021
1022 pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, args: []const []const u8) void {
1023 const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
1024 c_source_file.* = CSourceFile{
1025 .source_path = file,
1026 .args = args,
1027 };
1028 self.c_source_files.append(c_source_file) catch unreachable;
1092 }1029 }
10931030
1094 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {1031 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
1095 self.verbose_link = value;1032 self.verbose_link = value;
1096 }1033 }
10971034
1035 pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void {
1036 self.verbose_cc = value;
1037 }
1038
1098 pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {1039 pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {
1099 self.build_mode = mode;1040 self.build_mode = mode;
1100 }1041 }
11011042
1043 pub fn overrideStdDir(self: *LibExeObjStep, dir_path: []const u8) void {
1044 self.override_std_dir = dir_path;
1045 }
1046
1102 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {1047 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
1103 self.output_path = file_path;1048 self.output_path = file_path;
11041049
...@@ -1149,17 +1094,15 @@ pub const LibExeObjStep = struct {...@@ -1149,17 +1094,15 @@ pub const LibExeObjStep = struct {
11491094
1150 self.object_files.append(obj.getOutputPath()) catch unreachable;1095 self.object_files.append(obj.getOutputPath()) catch unreachable;
11511096
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 it1097 // 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;1098 self.include_dirs.append(self.builder.cache_root) catch unreachable;
1099
1100 if (obj.link_libs.exists("c")) {
1101 self.link_libs.put("c") catch unreachable;
1102 }
1159 }1103 }
11601104
1161 pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {1105 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;1106 const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream;
1164 out.print("pub const {} = {};\n", name, value) catch unreachable;1107 out.print("pub const {} = {};\n", name, value) catch unreachable;
1165 }1108 }
...@@ -1173,23 +1116,15 @@ pub const LibExeObjStep = struct {...@@ -1173,23 +1116,15 @@ pub const LibExeObjStep = struct {
1173 }1116 }
11741117
1175 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {1118 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{1119 self.packages.append(Pkg{
1179 .name = name,1120 .name = name,
1180 .path = pkg_index_path,1121 .path = pkg_index_path,
1181 }) catch unreachable;1122 }) catch unreachable;
1182 }1123 }
11831124
1184 pub fn addCompileFlags(self: *LibExeObjStep, flags: []const []const u8) void {1125 pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
1185 for (flags) |flag| {1126 assert(self.kind == Kind.Test);
1186 self.cflags.append(flag) catch unreachable;1127 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 }1128 }
11941129
1195 pub fn enableSystemLinkerHack(self: *LibExeObjStep) void {1130 pub fn enableSystemLinkerHack(self: *LibExeObjStep) void {
...@@ -1198,15 +1133,11 @@ pub const LibExeObjStep = struct {...@@ -1198,15 +1133,11 @@ pub const LibExeObjStep = struct {
11981133
1199 fn make(step: *Step) !void {1134 fn make(step: *Step) !void {
1200 const self = @fieldParentPtr(LibExeObjStep, "step", step);1135 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;1136 const builder = self.builder;
12061137
1207 assert(self.is_zig);1138 if (self.root_src == null and self.object_files.len == 0 and
12081139 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) {1140 {
1210 warn("{}: linker needs 1 or more objects to link\n", self.step.name);1141 warn("{}: linker needs 1 or more objects to link\n", self.step.name);
1211 return error.NeedAnObject;1142 return error.NeedAnObject;
1212 }1143 }
...@@ -1220,6 +1151,7 @@ pub const LibExeObjStep = struct {...@@ -1220,6 +1151,7 @@ pub const LibExeObjStep = struct {
1220 Kind.Lib => "build-lib",1151 Kind.Lib => "build-lib",
1221 Kind.Exe => "build-exe",1152 Kind.Exe => "build-exe",
1222 Kind.Obj => "build-obj",1153 Kind.Obj => "build-obj",
1154 Kind.Test => "test",
1223 };1155 };
1224 zig_args.append(cmd) catch unreachable;1156 zig_args.append(cmd) catch unreachable;
12251157
...@@ -1227,6 +1159,14 @@ pub const LibExeObjStep = struct {...@@ -1227,6 +1159,14 @@ pub const LibExeObjStep = struct {
1227 zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;1159 zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;
1228 }1160 }
12291161
1162 for (self.c_source_files.toSliceConst()) |c_source_file| {
1163 try zig_args.append("--c-source");
1164 for (c_source_file.args) |arg| {
1165 try zig_args.append(arg);
1166 }
1167 try zig_args.append(self.builder.pathFromRoot(c_source_file.source_path));
1168 }
1169
1230 if (self.build_options_contents.len() > 0) {1170 if (self.build_options_contents.len() > 0) {
1231 const build_options_file = try os.path.join(1171 const build_options_file = try os.path.join(
1232 builder.allocator,1172 builder.allocator,
...@@ -1239,6 +1179,16 @@ pub const LibExeObjStep = struct {...@@ -1239,6 +1179,16 @@ pub const LibExeObjStep = struct {
1239 try zig_args.append("--pkg-end");1179 try zig_args.append("--pkg-end");
1240 }1180 }
12411181
1182 if (self.filter) |filter| {
1183 try zig_args.append("--test-filter");
1184 try zig_args.append(filter);
1185 }
1186
1187 if (self.name_prefix.len != 0) {
1188 try zig_args.append("--test-name-prefix");
1189 try zig_args.append(self.name_prefix);
1190 }
1191
1242 for (self.object_files.toSliceConst()) |object_file| {1192 for (self.object_files.toSliceConst()) |object_file| {
1243 zig_args.append("--object") catch unreachable;1193 zig_args.append("--object") catch unreachable;
1244 zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;1194 zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;
...@@ -1255,6 +1205,7 @@ pub const LibExeObjStep = struct {...@@ -1255,6 +1205,7 @@ pub const LibExeObjStep = struct {
1255 if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable;1205 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;1206 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;1207 if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable;
1208 if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable;
12581209
1259 if (self.strip) {1210 if (self.strip) {
1260 zig_args.append("--strip") catch unreachable;1211 zig_args.append("--strip") catch unreachable;
...@@ -1293,7 +1244,7 @@ pub const LibExeObjStep = struct {...@@ -1293,7 +1244,7 @@ pub const LibExeObjStep = struct {
1293 zig_args.append("--ver-patch") catch unreachable;1244 zig_args.append("--ver-patch") catch unreachable;
1294 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;1245 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
1295 }1246 }
1296 if (self.kind == Kind.Exe and self.static) {1247 if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {
1297 zig_args.append("--static") catch unreachable;1248 zig_args.append("--static") catch unreachable;
1298 }1249 }
12991250
...@@ -1325,11 +1276,16 @@ pub const LibExeObjStep = struct {...@@ -1325,11 +1276,16 @@ pub const LibExeObjStep = struct {
1325 }1276 }
1326 }1277 }
13271278
1328 if (!self.disable_libc) {1279 if (self.exec_cmd_args) |exec_cmd_args| {
1329 zig_args.append("--library") catch unreachable;1280 for (exec_cmd_args) |cmd_arg| {
1330 zig_args.append("c") catch unreachable;1281 if (cmd_arg) |arg| {
1282 try zig_args.append("--test-cmd");
1283 try zig_args.append(arg);
1284 } else {
1285 try zig_args.append("--test-cmd-bin");
1286 }
1287 }
1331 }1288 }
1332
1333 for (self.packages.toSliceConst()) |pkg| {1289 for (self.packages.toSliceConst()) |pkg| {
1334 zig_args.append("--pkg-begin") catch unreachable;1290 zig_args.append("--pkg-begin") catch unreachable;
1335 zig_args.append(pkg.name) catch unreachable;1291 zig_args.append(pkg.name) catch unreachable;
...@@ -1363,8 +1319,14 @@ pub const LibExeObjStep = struct {...@@ -1363,8 +1319,14 @@ pub const LibExeObjStep = struct {
1363 }1319 }
13641320
1365 for (self.full_path_libs.toSliceConst()) |full_path_lib| {1321 for (self.full_path_libs.toSliceConst()) |full_path_lib| {
1366 zig_args.append("--library") catch unreachable;1322 try zig_args.append("--library");
1367 zig_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;1323 try zig_args.append(builder.pathFromRoot(full_path_lib));
1324
1325 const full_path_lib_abs = builder.pathFromRoot(full_path_lib);
1326 if (os.path.dirname(full_path_lib_abs)) |dirname| {
1327 try zig_args.append("-rpath");
1328 try zig_args.append(dirname);
1329 }
1368 }1330 }
13691331
1370 if (self.target.isDarwin()) {1332 if (self.target.isDarwin()) {
...@@ -1379,558 +1341,16 @@ pub const LibExeObjStep = struct {...@@ -1379,558 +1341,16 @@ pub const LibExeObjStep = struct {
1379 try zig_args.append("--system-linker-hack");1341 try zig_args.append("--system-linker-hack");
1380 }1342 }
13811343
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| {1344 if (self.override_std_dir) |dir| {
1929 try zig_args.append("--override-std-dir");1345 try zig_args.append("--override-std-dir");
1930 try zig_args.append(builder.pathFromRoot(dir));1346 try zig_args.append(builder.pathFromRoot(dir));
1931 }1347 }
19321348
1933 try builder.spawnChild(zig_args.toSliceConst());1349 try builder.spawnChild(zig_args.toSliceConst());
1350
1351 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
1352 try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
1353 }
1934 }1354 }
1935};1355};
19361356
...@@ -1976,6 +1396,7 @@ const InstallArtifactStep = struct {...@@ -1976,6 +1396,7 @@ const InstallArtifactStep = struct {
1976 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {1396 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
1977 const dest_dir = switch (artifact.kind) {1397 const dest_dir = switch (artifact.kind) {
1978 LibExeObjStep.Kind.Obj => unreachable,1398 LibExeObjStep.Kind.Obj => unreachable,
1399 LibExeObjStep.Kind.Test => unreachable,
1979 LibExeObjStep.Kind.Exe => builder.exe_dir,1400 LibExeObjStep.Kind.Exe => builder.exe_dir,
1980 LibExeObjStep.Kind.Lib => builder.lib_dir,1401 LibExeObjStep.Kind.Lib => builder.lib_dir,
1981 };1402 };
...@@ -2012,6 +1433,7 @@ const InstallArtifactStep = struct {...@@ -2012,6 +1433,7 @@ const InstallArtifactStep = struct {
2012 builtin.Os.windows => {},1433 builtin.Os.windows => {},
2013 else => switch (self.artifact.kind) {1434 else => switch (self.artifact.kind) {
2014 LibExeObjStep.Kind.Obj => unreachable,1435 LibExeObjStep.Kind.Obj => unreachable,
1436 LibExeObjStep.Kind.Test => unreachable,
2015 LibExeObjStep.Kind.Exe => u32(0o755),1437 LibExeObjStep.Kind.Exe => u32(0o755),
2016 LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755),1438 LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755),
2017 },1439 },
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);