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;
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+7
......@@ -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
......@@ -1788,6 +1793,7 @@ struct CodeGen {
17881793 bool verbose_ir;
17891794 bool verbose_llvm_ir;
17901795 bool verbose_cimport;
1796 bool verbose_cc;
17911797 bool error_during_imports;
17921798 bool generate_error_name_table;
17931799 bool enable_cache;
......@@ -1805,6 +1811,7 @@ struct CodeGen {
18051811 ZigList<Buf *> forbidden_libs;
18061812 ZigList<Buf *> link_objects;
18071813 ZigList<Buf *> assembly_files;
1814 ZigList<CFile *> c_source_files;
18081815 ZigList<const char *> lib_dirs;
18091816
18101817 ZigLibCInstallation *libc;
src/codegen.cpp+184-11
......@@ -7885,8 +7885,8 @@ static void detect_libc(CodeGen *g) {
78857885 fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
78867886 exit(1);
78877887 }
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));
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), err_str(err));
78907890 exit(1);
78917891 }
78927892 }
......@@ -8123,6 +8123,162 @@ static void gen_global_asm(CodeGen *g) {
81238123 }
81248124}
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
81268282void codegen_add_object(CodeGen *g, Buf *object_path) {
81278283 g->link_objects.append(object_path);
81288284}
......@@ -8637,6 +8793,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
86378793 cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
86388794 cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
86398795 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 }
86408803 cache_int(ch, g->emit_file_type);
86418804 cache_int(ch, g->build_mode);
86428805 cache_int(ch, g->out_type);
......@@ -8788,6 +8951,7 @@ void codegen_build_and_link(CodeGen *g) {
87888951
87898952 gen_global_asm(g);
87908953 gen_root_source(g);
8954 gen_c_objects(g);
87918955
87928956 if (g->enable_cache) {
87938957 if ((err = cache_final(&g->cache_hash, &digest))) {
......@@ -8805,16 +8969,25 @@ void codegen_build_and_link(CodeGen *g) {
88058969 resolve_out_paths(g);
88068970
88078971 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);
8972 if (g->out_type == OutTypeObj && g->c_source_files.length == 1) {
8973 assert(g->link_objects.length == 1);
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) {
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);
8984 if (g->out_h_path != nullptr) {
8985 codegen_add_time_event(g, "Generate .h");
8986 gen_h_file(g);
8987 }
8988 if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {
8989 codegen_link(g);
8990 }
88188991 }
88198992 }
88208993
src/main.cpp+67-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"
......@@ -77,6 +77,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
7777 " --verbose-ir enable compiler debug output for Zig IR\n"
7878 " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
7979 " --verbose-cimport enable compiler debug output for C imports\n"
80 " --verbose-cc enable compiler debug output for C compilation\n"
8081 " -dirafter [dir] same as -isystem but do it last\n"
8182 " -isystem [dir] add additional search path for other .h files\n"
8283 " -mllvm [arg] forward an arg to LLVM's option processing\n"
......@@ -181,7 +182,6 @@ enum Cmd {
181182 CmdNone,
182183 CmdBuild,
183184 CmdBuiltin,
184 CmdHelp,
185185 CmdRun,
186186 CmdTargets,
187187 CmdTest,
......@@ -385,6 +385,7 @@ int main(int argc, char **argv) {
385385 bool verbose_ir = false;
386386 bool verbose_llvm_ir = false;
387387 bool verbose_cimport = false;
388 bool verbose_cc = false;
388389 ErrColor color = ErrColorAuto;
389390 CacheOpt enable_cache = CacheOptAuto;
390391 const char *libc_txt = nullptr;
......@@ -404,6 +405,7 @@ int main(int argc, char **argv) {
404405 ZigList<const char *> rpath_list = {0};
405406 bool each_lib_rpath = false;
406407 ZigList<const char *> objects = {0};
408 ZigList<CFile *> c_source_files = {0};
407409 ZigList<const char *> asm_files = {0};
408410 const char *test_filter = nullptr;
409411 const char *test_name_prefix = nullptr;
......@@ -512,6 +514,7 @@ int main(int argc, char **argv) {
512514 " --verbose-ir Enable compiler debug output for Zig IR\n"
513515 " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
514516 " --verbose-cimport Enable compiler debug output for C imports\n"
517 " --verbose-cc Enable compiler debug output for C compilation\n"
515518 "\n"
516519 , zig_exe_path);
517520 return EXIT_SUCCESS;
......@@ -521,7 +524,7 @@ int main(int argc, char **argv) {
521524 "No 'build.zig' file found.\n"
522525 "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"
523526 "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"
525528 );
526529 return EXIT_FAILURE;
527530 }
......@@ -587,9 +590,9 @@ int main(int argc, char **argv) {
587590 build_mode = BuildModeSmallRelease;
588591 } else if (strcmp(arg, "--help") == 0) {
589592 if (cmd == CmdLibC) {
590 return print_libc_usage(arg0, stderr, EXIT_FAILURE);
593 return print_libc_usage(arg0, stdout, EXIT_SUCCESS);
591594 } else {
592 return print_full_usage(arg0, stderr, EXIT_FAILURE);
595 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
593596 }
594597 } else if (strcmp(arg, "--strip") == 0) {
595598 strip = true;
......@@ -607,6 +610,8 @@ int main(int argc, char **argv) {
607610 verbose_llvm_ir = true;
608611 } else if (strcmp(arg, "--verbose-cimport") == 0) {
609612 verbose_cimport = true;
613 } else if (strcmp(arg, "--verbose-cc") == 0) {
614 verbose_cc = true;
610615 } else if (strcmp(arg, "-rdynamic") == 0) {
611616 rdynamic = true;
612617 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
......@@ -714,6 +719,19 @@ int main(int argc, char **argv) {
714719 forbidden_link_libs.append(argv[i]);
715720 } else if (strcmp(arg, "--object") == 0) {
716721 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 }
717735 } else if (strcmp(arg, "--assembly") == 0) {
718736 asm_files.append(argv[i]);
719737 } else if (strcmp(arg, "--cache-dir") == 0) {
......@@ -792,8 +810,6 @@ int main(int argc, char **argv) {
792810 } else if (strcmp(arg, "build-lib") == 0) {
793811 cmd = CmdBuild;
794812 out_type = OutTypeLib;
795 } else if (strcmp(arg, "help") == 0) {
796 cmd = CmdHelp;
797813 } else if (strcmp(arg, "run") == 0) {
798814 cmd = CmdRun;
799815 out_type = OutTypeExe;
......@@ -835,7 +851,6 @@ int main(int argc, char **argv) {
835851 }
836852 break;
837853 case CmdBuiltin:
838 case CmdHelp:
839854 case CmdVersion:
840855 case CmdZen:
841856 case CmdTargets:
......@@ -910,15 +925,43 @@ int main(int argc, char **argv) {
910925 case CmdTranslateC:
911926 case CmdTest:
912927 {
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");
928 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 &&
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");
915937 return print_error_usage(arg0);
916938 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
917939 fprintf(stderr, "Expected source file argument.\n");
918940 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);
941 } else if (cmd == CmdBuild && out_type == OutTypeObj) {
942 if (objects.length != 0) {
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 }
922965 }
923966
924967 assert(cmd != CmdBuild || out_type != OutTypeUnknown);
......@@ -945,6 +988,13 @@ int main(int argc, char **argv) {
945988 }
946989 }
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
948998 if (need_name && buf_out_name == nullptr) {
949999 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
9501000 return print_error_usage(arg0);
......@@ -996,6 +1046,7 @@ int main(int argc, char **argv) {
9961046 g->verbose_ir = verbose_ir;
9971047 g->verbose_llvm_ir = verbose_llvm_ir;
9981048 g->verbose_cimport = verbose_cimport;
1049 g->verbose_cc = verbose_cc;
9991050 codegen_set_errmsg_color(g, color);
10001051 g->system_linker_hack = system_linker_hack;
10011052
......@@ -1048,6 +1099,7 @@ int main(int argc, char **argv) {
10481099 add_package(g, cur_pkg, g->root_package);
10491100
10501101 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
1102 g->c_source_files = c_source_files;
10511103 for (size_t i = 0; i < objects.length; i += 1) {
10521104 codegen_add_object(g, buf_create_from_str(objects.at(i)));
10531105 }
......@@ -1147,8 +1199,6 @@ int main(int argc, char **argv) {
11471199 zig_unreachable();
11481200 }
11491201 }
1150 case CmdHelp:
1151 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
11521202 case CmdVersion:
11531203 printf("%s\n", ZIG_VERSION_STRING);
11541204 return EXIT_SUCCESS;
......@@ -1158,7 +1208,6 @@ int main(int argc, char **argv) {
11581208 case CmdTargets:
11591209 return print_target_list(stdout);
11601210 case CmdNone:
1161 fprintf(stderr, "Zig programming language\n");
1162 return print_error_usage(arg0);
1211 return print_full_usage(arg0, stderr, EXIT_FAILURE);
11631212 }
11641213}
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+108-686
......@@ -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,
......@@ -844,16 +825,17 @@ pub const LibExeObjStep = struct {
844825 strip: bool,
845826 full_path_libs: ArrayList([]const u8),
846827 need_flat_namespace_hack: bool,
847 is_zig: bool,
848 cflags: ArrayList([]const u8),
849828 include_dirs: ArrayList([]const u8),
850829 lib_paths: ArrayList([]const u8),
851 disable_libc: bool,
852830 frameworks: BufSet,
853831 verbose_link: bool,
832 verbose_cc: bool,
854833 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
857839 root_src: ?[]const u8,
858840 output_h_path: ?[]const u8,
859841 out_h_filename: []const u8,
......@@ -862,14 +844,14 @@ pub const LibExeObjStep = struct {
862844 build_options_contents: std.Buffer,
863845 system_linker_hack: bool,
864846
865 // C only stuff
866 source_files: ArrayList([]const u8),
847 c_source_files: ArrayList(*CSourceFile),
867848 object_src: []const u8,
868849
869850 const Kind = enum {
870851 Exe,
871852 Lib,
872853 Obj,
854 Test,
873855 };
874856
875857 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {
......@@ -878,46 +860,27 @@ pub const LibExeObjStep = struct {
878860 return self;
879861 }
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
887863 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
888864 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
889865 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
890866 return self;
891867 }
892868
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 {
869 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
900870 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
901871 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
902872 return self;
903873 }
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
912875 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
913876 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
914877 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));
915878 return self;
916879 }
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 {
919882 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));
921884 return self;
922885 }
923886
......@@ -926,6 +889,7 @@ pub const LibExeObjStep = struct {
926889 .strip = false,
927890 .builder = builder,
928891 .verbose_link = false,
892 .verbose_cc = false,
929893 .build_mode = builtin.Mode.Debug,
930894 .static = static,
931895 .kind = kind,
......@@ -946,61 +910,19 @@ pub const LibExeObjStep = struct {
946910 .object_files = ArrayList([]const u8).init(builder.allocator),
947911 .assembly_files = ArrayList([]const u8).init(builder.allocator),
948912 .packages = ArrayList(Pkg).init(builder.allocator),
949 .is_zig = true,
950913 .full_path_libs = ArrayList([]const u8).init(builder.allocator),
951914 .need_flat_namespace_hack = false,
952 .cflags = ArrayList([]const u8).init(builder.allocator),
953 .source_files = undefined,
915 .c_source_files = ArrayList(*CSourceFile).init(builder.allocator),
954916 .include_dirs = ArrayList([]const u8).init(builder.allocator),
955917 .lib_paths = ArrayList([]const u8).init(builder.allocator),
956918 .object_src = undefined,
957 .disable_libc = true,
958919 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
959920 .c_std = Builder.CStd.C99,
960921 .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,
922 .override_std_dir = null,
923 .exec_cmd_args = null,
924 .name_prefix = "",
925 .filter = null,
1004926 };
1005927 self.computeOutFileNames();
1006928 return self;
......@@ -1014,6 +936,9 @@ pub const LibExeObjStep = struct {
1014936 Kind.Exe => {
1015937 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
1016938 },
939 Kind.Test => {
940 self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());
941 },
1017942 Kind.Lib => {
1018943 if (self.static) {
1019944 self.out_filename = self.builder.fmt("lib{}.a", self.name);
......@@ -1081,24 +1006,44 @@ pub const LibExeObjStep = struct {
10811006 }
10821007
10831008 pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
1084 assert(self.kind != Kind.Obj);
10851009 self.link_libs.put(name) catch unreachable;
10861010 }
10871011
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;
1012 pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
1013 assert(self.kind == Kind.Test);
1014 self.name_prefix = text;
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;
10921029 }
10931030
10941031 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
10951032 self.verbose_link = value;
10961033 }
10971034
1035 pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void {
1036 self.verbose_cc = value;
1037 }
1038
10981039 pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {
10991040 self.build_mode = mode;
11001041 }
11011042
1043 pub fn overrideStdDir(self: *LibExeObjStep, dir_path: []const u8) void {
1044 self.override_std_dir = dir_path;
1045 }
1046
11021047 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
11031048 self.output_path = file_path;
11041049
......@@ -1149,17 +1094,15 @@ pub const LibExeObjStep = struct {
11491094
11501095 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
11571097 // TODO should be some kind of isolated directory that only has this header in it
11581098 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 }
11591103 }
11601104
11611105 pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {
1162 assert(self.is_zig);
11631106 const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream;
11641107 out.print("pub const {} = {};\n", name, value) catch unreachable;
11651108 }
......@@ -1173,23 +1116,15 @@ pub const LibExeObjStep = struct {
11731116 }
11741117
11751118 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
1176 assert(self.is_zig);
1177
11781119 self.packages.append(Pkg{
11791120 .name = name,
11801121 .path = pkg_index_path,
11811122 }) catch unreachable;
11821123 }
11831124
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;
1125 pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
1126 assert(self.kind == Kind.Test);
1127 self.exec_cmd_args = args;
11931128 }
11941129
11951130 pub fn enableSystemLinkerHack(self: *LibExeObjStep) void {
......@@ -1198,15 +1133,11 @@ pub const LibExeObjStep = struct {
11981133
11991134 fn make(step: *Step) !void {
12001135 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 {
12051136 const builder = self.builder;
12061137
1207 assert(self.is_zig);
1208
1209 if (self.root_src == null and self.object_files.len == 0 and self.assembly_files.len == 0) {
1138 if (self.root_src == null and self.object_files.len == 0 and
1139 self.assembly_files.len == 0 and self.c_source_files.len == 0)
1140 {
12101141 warn("{}: linker needs 1 or more objects to link\n", self.step.name);
12111142 return error.NeedAnObject;
12121143 }
......@@ -1220,6 +1151,7 @@ pub const LibExeObjStep = struct {
12201151 Kind.Lib => "build-lib",
12211152 Kind.Exe => "build-exe",
12221153 Kind.Obj => "build-obj",
1154 Kind.Test => "test",
12231155 };
12241156 zig_args.append(cmd) catch unreachable;
12251157
......@@ -1227,6 +1159,14 @@ pub const LibExeObjStep = struct {
12271159 zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;
12281160 }
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
12301170 if (self.build_options_contents.len() > 0) {
12311171 const build_options_file = try os.path.join(
12321172 builder.allocator,
......@@ -1239,6 +1179,16 @@ pub const LibExeObjStep = struct {
12391179 try zig_args.append("--pkg-end");
12401180 }
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
12421192 for (self.object_files.toSliceConst()) |object_file| {
12431193 zig_args.append("--object") catch unreachable;
12441194 zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;
......@@ -1255,6 +1205,7 @@ pub const LibExeObjStep = struct {
12551205 if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable;
12561206 if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable;
12571207 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
12591210 if (self.strip) {
12601211 zig_args.append("--strip") catch unreachable;
......@@ -1293,7 +1244,7 @@ pub const LibExeObjStep = struct {
12931244 zig_args.append("--ver-patch") catch unreachable;
12941245 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
12951246 }
1296 if (self.kind == Kind.Exe and self.static) {
1247 if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {
12971248 zig_args.append("--static") catch unreachable;
12981249 }
12991250
......@@ -1325,11 +1276,16 @@ pub const LibExeObjStep = struct {
13251276 }
13261277 }
13271278
1328 if (!self.disable_libc) {
1329 zig_args.append("--library") catch unreachable;
1330 zig_args.append("c") catch unreachable;
1279 if (self.exec_cmd_args) |exec_cmd_args| {
1280 for (exec_cmd_args) |cmd_arg| {
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 }
13311288 }
1332
13331289 for (self.packages.toSliceConst()) |pkg| {
13341290 zig_args.append("--pkg-begin") catch unreachable;
13351291 zig_args.append(pkg.name) catch unreachable;
......@@ -1363,8 +1319,14 @@ pub const LibExeObjStep = struct {
13631319 }
13641320
13651321 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;
1322 try zig_args.append("--library");
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 }
13681330 }
13691331
13701332 if (self.target.isDarwin()) {
......@@ -1379,558 +1341,16 @@ pub const LibExeObjStep = struct {
13791341 try zig_args.append("--system-linker-hack");
13801342 }
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 }
19281344 if (self.override_std_dir) |dir| {
19291345 try zig_args.append("--override-std-dir");
19301346 try zig_args.append(builder.pathFromRoot(dir));
19311347 }
19321348
19331349 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 }
19341354 }
19351355};
19361356
......@@ -1976,6 +1396,7 @@ const InstallArtifactStep = struct {
19761396 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
19771397 const dest_dir = switch (artifact.kind) {
19781398 LibExeObjStep.Kind.Obj => unreachable,
1399 LibExeObjStep.Kind.Test => unreachable,
19791400 LibExeObjStep.Kind.Exe => builder.exe_dir,
19801401 LibExeObjStep.Kind.Lib => builder.lib_dir,
19811402 };
......@@ -2012,6 +1433,7 @@ const InstallArtifactStep = struct {
20121433 builtin.Os.windows => {},
20131434 else => switch (self.artifact.kind) {
20141435 LibExeObjStep.Kind.Obj => unreachable,
1436 LibExeObjStep.Kind.Test => unreachable,
20151437 LibExeObjStep.Kind.Exe => u32(0o755),
20161438 LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755),
20171439 },
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);