Merge pull request #2005 from ziglang/c-source

first class support for compiling C code
master
Andrew Kelley 2019-02-25 14:11:54 -05:00 committed by GitHub
commit 6003b1ea70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 496 additions and 737 deletions

View File

@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void { pub fn build(b: *Builder) void {
const obj = b.addObject("base64", "base64.zig"); const obj = b.addObject("base64", "base64.zig");
const exe = b.addCExecutable("test"); const exe = b.addExecutable("test", null);
exe.addCompileFlags([][]const u8{"-std=c99"}); exe.addCSourceFile("test.c",[][]const u8{"-std=c99"});
exe.addSourceFile("test.c");
exe.addObject(obj); exe.addObject(obj);
exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step); b.default_step.dependOn(&exe.step);

View File

@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void { pub fn build(b: *Builder) void {
const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
const exe = b.addCExecutable("test"); const exe = b.addExecutable("test", null);
exe.addCompileFlags([][]const u8{"-std=c99"}); exe.addCSourceFile("test.c", [][]const u8{"-std=c99"});
exe.addSourceFile("test.c");
exe.linkLibrary(lib); exe.linkLibrary(lib);
exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step); b.default_step.dependOn(&exe.step);

View File

@ -1611,6 +1611,11 @@ enum ValgrindSupport {
ValgrindSupportEnabled, ValgrindSupportEnabled,
}; };
struct CFile {
ZigList<const char *> args;
const char *source_path;
};
// When adding fields, check if they should be added to the hash computation in build_with_cache // When adding fields, check if they should be added to the hash computation in build_with_cache
struct CodeGen { struct CodeGen {
//////////////////////////// Runtime State //////////////////////////// Runtime State
@ -1738,6 +1743,7 @@ struct CodeGen {
Buf triple_str; Buf triple_str;
Buf global_asm; Buf global_asm;
Buf *out_h_path; Buf *out_h_path;
Buf *out_lib_path;
Buf artifact_dir; Buf artifact_dir;
Buf output_file_path; Buf output_file_path;
Buf o_file_output_path; Buf o_file_output_path;
@ -1788,6 +1794,7 @@ struct CodeGen {
bool verbose_ir; bool verbose_ir;
bool verbose_llvm_ir; bool verbose_llvm_ir;
bool verbose_cimport; bool verbose_cimport;
bool verbose_cc;
bool error_during_imports; bool error_during_imports;
bool generate_error_name_table; bool generate_error_name_table;
bool enable_cache; bool enable_cache;
@ -1805,6 +1812,7 @@ struct CodeGen {
ZigList<Buf *> forbidden_libs; ZigList<Buf *> forbidden_libs;
ZigList<Buf *> link_objects; ZigList<Buf *> link_objects;
ZigList<Buf *> assembly_files; ZigList<Buf *> assembly_files;
ZigList<CFile *> c_source_files;
ZigList<const char *> lib_dirs; ZigList<const char *> lib_dirs;
ZigLibCInstallation *libc; ZigLibCInstallation *libc;

View File

@ -414,6 +414,39 @@ Error cache_add_file(CacheHash *ch, Buf *path) {
return cache_add_file_fetch(ch, resolved_path, nullptr); return cache_add_file_fetch(ch, resolved_path, nullptr);
} }
Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
Error err;
Buf *contents = buf_alloc();
if ((err = os_fetch_file_path(dep_file_path, contents, false))) {
if (verbose) {
fprintf(stderr, "unable to read .d file: %s\n", err_str(err));
}
return ErrorReadingDepFile;
}
SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
// skip first line
SplitIterator_next(&it);
for (;;) {
Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
if (!opt_line.is_some)
break;
if (opt_line.value.len == 0)
continue;
SplitIterator line_it = memSplit(opt_line.value, str(" \t"));
Slice<uint8_t> filename;
if (!SplitIterator_next(&line_it).unwrap(&filename))
continue;
Buf *filename_buf = buf_create_from_slice(filename);
if ((err = cache_add_file(ch, filename_buf))) {
if (verbose) {
fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
}
return err;
}
}
return ErrorNone;
}
static Error write_manifest_file(CacheHash *ch) { static Error write_manifest_file(CacheHash *ch) {
Error err; Error err;
Buf contents = BUF_INIT; Buf contents = BUF_INIT;
@ -464,3 +497,4 @@ void cache_release(CacheHash *ch) {
os_file_close(ch->manifest_file); os_file_close(ch->manifest_file);
} }

View File

@ -56,6 +56,8 @@ Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
// If you did not get a cache hit, call this function for every file // If you did not get a cache hit, call this function for every file
// that is depended on, and then finish with cache_final. // that is depended on, and then finish with cache_final.
Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path); Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path);
// This opens a file created by -MD -MF args to Clang
Error ATTRIBUTE_MUST_USE cache_add_dep_file(CacheHash *ch, Buf *path, bool verbose);
// This variant of cache_add_file returns the file contents. // This variant of cache_add_file returns the file contents.
// Also the file path argument must be already resolved. // Also the file path argument must be already resolved.

View File

@ -175,6 +175,10 @@ void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
g->out_h_path = h_path; g->out_h_path = h_path;
} }
void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path) {
g->out_lib_path = lib_path;
}
void codegen_set_output_path(CodeGen *g, Buf *path) { void codegen_set_output_path(CodeGen *g, Buf *path) {
g->wanted_output_file_path = path; g->wanted_output_file_path = path;
} }
@ -7885,8 +7889,8 @@ static void detect_libc(CodeGen *g) {
fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
exit(1); exit(1);
} }
if (rename(buf_ptr(native_libc_tmp), buf_ptr(native_libc_txt)) == -1) { if ((err = os_rename(native_libc_tmp, native_libc_txt))) {
fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), strerror(errno)); fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), err_str(err));
exit(1); exit(1);
} }
} }
@ -8123,6 +8127,143 @@ static void gen_global_asm(CodeGen *g) {
} }
} }
static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
Error err;
Buf *c_source_file = buf_create_from_str(c_file->source_path);
Buf *c_source_basename = buf_alloc();
os_path_split(c_source_file, nullptr, c_source_basename);
Buf *out_obj_name = buf_sprintf("%s%s", buf_ptr(c_source_basename), target_o_file_ext(g->zig_target));
Buf *out_obj_path = buf_alloc();
os_path_join(&g->cache_dir, out_obj_name, out_obj_path);
Buf *out_dep_name = buf_sprintf("%s.d", buf_ptr(c_source_file));
Buf *out_dep_path = buf_alloc();
os_path_join(&g->cache_dir, out_dep_name, out_dep_path);
Termination term;
ZigList<const char *> args = {};
args.append("cc");
if (g->enable_cache) {
args.append("-MD");
args.append("-MF");
args.append(buf_ptr(out_dep_path));
}
args.append("-isystem");
args.append(buf_ptr(g->zig_c_headers_dir));
if (g->libc != nullptr) {
args.append("-isystem");
args.append(buf_ptr(&g->libc->include_dir));
}
if (g->zig_target->is_native) {
args.append("-march=native");
} else {
args.append("-target");
args.append(buf_ptr(&g->triple_str));
}
if (!g->strip_debug_symbols) {
args.append("-g");
}
switch (g->build_mode) {
case BuildModeDebug:
if (g->libc_link_lib != nullptr) {
args.append("-fstack-protector-strong");
args.append("--param");
args.append("ssp-buffer-size=4");
} else {
args.append("-fno-stack-protector");
}
break;
case BuildModeSafeRelease:
args.append("-O2");
if (g->libc_link_lib != nullptr) {
args.append("-D_FORTIFY_SOURCE=2");
args.append("-fstack-protector-strong");
args.append("--param");
args.append("ssp-buffer-size=4");
} else {
args.append("-fno-stack-protector");
}
break;
case BuildModeFastRelease:
args.append("-O2");
args.append("-fno-stack-protector");
break;
case BuildModeSmallRelease:
args.append("-Os");
args.append("-fno-stack-protector");
break;
}
args.append("-o");
args.append(buf_ptr(out_obj_path));
args.append("-c");
args.append(buf_ptr(c_source_file));
if (!g->disable_pic && target_supports_fpic(g->zig_target)) {
args.append("-fPIC");
}
for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
args.append(g->clang_argv[arg_i]);
}
for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) {
args.append(c_file->args.at(arg_i));
}
if (g->verbose_cc) {
fprintf(stderr, "zig");
for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {
fprintf(stderr, " %s", args.at(arg_i));
}
fprintf(stderr, "\n");
}
os_spawn_process(buf_ptr(self_exe_path), args, &term);
if (term.how != TerminationIdClean || term.code != 0) {
fprintf(stderr, "`zig cc` failed\n");
exit(1);
}
g->link_objects.append(out_obj_path);
if (g->enable_cache) {
// add the files depended on to the cache system
if ((err = cache_add_file(&g->cache_hash, c_source_file))) {
fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(c_source_file), err_str(err));
exit(1);
}
if ((err = cache_add_dep_file(&g->cache_hash, out_dep_path, true))) {
fprintf(stderr, "failed to add C source dependencies to cache: %s\n", err_str(err));
exit(1);
}
}
}
static void gen_c_objects(CodeGen *g) {
Error err;
if (g->c_source_files.length == 0)
return;
Buf *self_exe_path = buf_alloc();
if ((err = os_self_exe_path(self_exe_path))) {
fprintf(stderr, "Unable to get self exe path: %s\n", err_str(err));
exit(1);
}
for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
CFile *c_file = g->c_source_files.at(c_file_i);
gen_c_object(g, self_exe_path, c_file);
}
}
void codegen_add_object(CodeGen *g, Buf *object_path) { void codegen_add_object(CodeGen *g, Buf *object_path) {
g->link_objects.append(object_path); g->link_objects.append(object_path);
} }
@ -8637,6 +8778,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length); cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
cache_list_of_file(ch, g->link_objects.items, g->link_objects.length); cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length); cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);
for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
CFile *c_file = g->c_source_files.at(c_file_i);
cache_file(ch, buf_create_from_str(c_file->source_path));
for (size_t opt_i = 0; opt_i < c_file->args.length; opt_i += 1) {
cache_buf(ch, buf_create_from_str(c_file->args.at(opt_i)));
}
}
cache_int(ch, g->emit_file_type); cache_int(ch, g->emit_file_type);
cache_int(ch, g->build_mode); cache_int(ch, g->build_mode);
cache_int(ch, g->out_type); cache_int(ch, g->out_type);
@ -8788,6 +8936,7 @@ void codegen_build_and_link(CodeGen *g) {
gen_global_asm(g); gen_global_asm(g);
gen_root_source(g); gen_root_source(g);
gen_c_objects(g);
if (g->enable_cache) { if (g->enable_cache) {
if ((err = cache_final(&g->cache_hash, &digest))) { if ((err = cache_final(&g->cache_hash, &digest))) {
@ -8805,6 +8954,14 @@ void codegen_build_and_link(CodeGen *g) {
resolve_out_paths(g); resolve_out_paths(g);
codegen_add_time_event(g, "Code Generation"); codegen_add_time_event(g, "Code Generation");
if (g->out_type == OutTypeObj && g->c_source_files.length == 1) {
assert(g->link_objects.length == 1);
if ((err = os_rename(g->link_objects.pop(), &g->o_file_output_path))) {
fprintf(stderr, "unable to move object to '%s': %s\n",
buf_ptr(&g->o_file_output_path), err_str(err));
exit(1);
}
} else {
do_code_gen(g); do_code_gen(g);
codegen_add_time_event(g, "LLVM Emit Output"); codegen_add_time_event(g, "LLVM Emit Output");
zig_llvm_emit_output(g); zig_llvm_emit_output(g);
@ -8817,6 +8974,7 @@ void codegen_build_and_link(CodeGen *g) {
codegen_link(g); codegen_link(g);
} }
} }
}
if (g->enable_cache) { if (g->enable_cache) {
cache_release(&g->cache_hash); cache_release(&g->cache_hash);

View File

@ -41,6 +41,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch); void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
void codegen_set_output_h_path(CodeGen *g, Buf *h_path); void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path);
void codegen_set_output_path(CodeGen *g, Buf *path); void codegen_set_output_path(CodeGen *g, Buf *path);
void codegen_add_time_event(CodeGen *g, const char *name); void codegen_add_time_event(CodeGen *g, const char *name);
void codegen_print_timing_report(CodeGen *g, FILE *f); void codegen_print_timing_report(CodeGen *g, FILE *f);

View File

@ -36,6 +36,7 @@ const char *err_str(Error err) {
case ErrorCacheUnavailable: return "cache unavailable"; case ErrorCacheUnavailable: return "cache unavailable";
case ErrorPathTooLong: return "path too long"; case ErrorPathTooLong: return "path too long";
case ErrorCCompilerCannotFindFile: return "C compiler cannot find file"; case ErrorCCompilerCannotFindFile: return "C compiler cannot find file";
case ErrorReadingDepFile: return "failed to read .d file";
} }
return "(invalid error)"; return "(invalid error)";
} }

View File

@ -38,6 +38,7 @@ enum Error {
ErrorCacheUnavailable, ErrorCacheUnavailable,
ErrorPathTooLong, ErrorPathTooLong,
ErrorCCompilerCannotFindFile, ErrorCCompilerCannotFindFile,
ErrorReadingDepFile,
}; };
const char *err_str(Error err); const char *err_str(Error err);

View File

@ -18670,12 +18670,6 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc
} }
static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) { static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
if (ira->codegen->enable_cache) {
ir_add_error(ira, &instruction->base,
buf_sprintf("TODO @cImport is incompatible with --cache on. The cache system currently is unable to detect subsequent changes in .h files."));
return ira->codegen->invalid_instruction;
}
AstNode *node = instruction->base.source_node; AstNode *node = instruction->base.source_node;
assert(node->type == NodeTypeFnCallExpr); assert(node->type == NodeTypeFnCallExpr);
AstNode *block_node = node->data.fn_call_expr.params.at(0); AstNode *block_node = node->data.fn_call_expr.params.at(0);

View File

@ -554,6 +554,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
bool is_library = g->out_type == OutTypeLib; bool is_library = g->out_type == OutTypeLib;
switch (g->subsystem) { switch (g->subsystem) {
case TargetSubsystemAuto: case TargetSubsystemAuto:
add_nt_link_args(lj, is_library);
break; break;
case TargetSubsystemConsole: case TargetSubsystemConsole:
lj->args.append("/SUBSYSTEM:console"); lj->args.append("/SUBSYSTEM:console");

View File

@ -18,7 +18,7 @@
#include <stdio.h> #include <stdio.h>
static int print_error_usage(const char *arg0) { static int print_error_usage(const char *arg0) {
fprintf(stderr, "See `%s help` for detailed usage information\n", arg0); fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -34,7 +34,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" builtin show the source code of that @import(\"builtin\")\n" " builtin show the source code of that @import(\"builtin\")\n"
" cc C compiler\n" " cc C compiler\n"
" fmt parse files and render in canonical zig format\n" " fmt parse files and render in canonical zig format\n"
" help show this usage information\n"
" id print the base64-encoded compiler id\n" " id print the base64-encoded compiler id\n"
" init-exe initialize a `zig build` application in the cwd\n" " init-exe initialize a `zig build` application in the cwd\n"
" init-lib initialize a `zig build` library in the cwd\n" " 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) {
"\n" "\n"
"Compile Options:\n" "Compile Options:\n"
" --assembly [source] add assembly file to build\n" " --assembly [source] add assembly file to build\n"
" --c-source [options] [file] compile C source code\n"
" --cache-dir [path] override the cache directory\n" " --cache-dir [path] override the cache directory\n"
" --cache [auto|off|on] build in global cache, print out paths to stdout\n" " --cache [auto|off|on] build in global cache, print out paths to stdout\n"
" --color [auto|off|on] enable or disable colored error messages\n" " --color [auto|off|on] enable or disable colored error messages\n"
@ -60,6 +60,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" --name [name] override output name\n" " --name [name] override output name\n"
" --output [file] override destination path\n" " --output [file] override destination path\n"
" --output-h [file] generate header file\n" " --output-h [file] generate header file\n"
" --output-lib [file] override import library path\n"
" --pkg-begin [name] [path] make pkg available to import and push current pkg\n" " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
" --pkg-end pop current pkg\n" " --pkg-end pop current pkg\n"
" --release-fast build with optimizations on and safety off\n" " --release-fast build with optimizations on and safety off\n"
@ -77,6 +78,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" --verbose-ir enable compiler debug output for Zig IR\n" " --verbose-ir enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir enable compiler debug output for LLVM IR\n" " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
" --verbose-cimport enable compiler debug output for C imports\n" " --verbose-cimport enable compiler debug output for C imports\n"
" --verbose-cc enable compiler debug output for C compilation\n"
" -dirafter [dir] same as -isystem but do it last\n" " -dirafter [dir] same as -isystem but do it last\n"
" -isystem [dir] add additional search path for other .h files\n" " -isystem [dir] add additional search path for other .h files\n"
" -mllvm [arg] forward an arg to LLVM's option processing\n" " -mllvm [arg] forward an arg to LLVM's option processing\n"
@ -181,7 +183,6 @@ enum Cmd {
CmdNone, CmdNone,
CmdBuild, CmdBuild,
CmdBuiltin, CmdBuiltin,
CmdHelp,
CmdRun, CmdRun,
CmdTargets, CmdTargets,
CmdTest, CmdTest,
@ -375,6 +376,7 @@ int main(int argc, char **argv) {
const char *in_file = nullptr; const char *in_file = nullptr;
const char *out_file = nullptr; const char *out_file = nullptr;
const char *out_file_h = nullptr; const char *out_file_h = nullptr;
const char *out_file_lib = nullptr;
bool strip = false; bool strip = false;
bool is_static = false; bool is_static = false;
OutType out_type = OutTypeUnknown; OutType out_type = OutTypeUnknown;
@ -385,6 +387,7 @@ int main(int argc, char **argv) {
bool verbose_ir = false; bool verbose_ir = false;
bool verbose_llvm_ir = false; bool verbose_llvm_ir = false;
bool verbose_cimport = false; bool verbose_cimport = false;
bool verbose_cc = false;
ErrColor color = ErrColorAuto; ErrColor color = ErrColorAuto;
CacheOpt enable_cache = CacheOptAuto; CacheOpt enable_cache = CacheOptAuto;
const char *libc_txt = nullptr; const char *libc_txt = nullptr;
@ -404,6 +407,7 @@ int main(int argc, char **argv) {
ZigList<const char *> rpath_list = {0}; ZigList<const char *> rpath_list = {0};
bool each_lib_rpath = false; bool each_lib_rpath = false;
ZigList<const char *> objects = {0}; ZigList<const char *> objects = {0};
ZigList<CFile *> c_source_files = {0};
ZigList<const char *> asm_files = {0}; ZigList<const char *> asm_files = {0};
const char *test_filter = nullptr; const char *test_filter = nullptr;
const char *test_name_prefix = nullptr; const char *test_name_prefix = nullptr;
@ -512,6 +516,7 @@ int main(int argc, char **argv) {
" --verbose-ir Enable compiler debug output for Zig IR\n" " --verbose-ir Enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir Enable compiler debug output for LLVM IR\n" " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
" --verbose-cimport Enable compiler debug output for C imports\n" " --verbose-cimport Enable compiler debug output for C imports\n"
" --verbose-cc Enable compiler debug output for C compilation\n"
"\n" "\n"
, zig_exe_path); , zig_exe_path);
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -521,7 +526,7 @@ int main(int argc, char **argv) {
"No 'build.zig' file found.\n" "No 'build.zig' file found.\n"
"Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n" "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"
"or build an executable directly with `zig build-exe $FILENAME.zig`.\n" "or build an executable directly with `zig build-exe $FILENAME.zig`.\n"
"See: `zig build --help` or `zig help` for more options.\n" "See: `zig build --help` or `zig --help` for more options.\n"
); );
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -587,9 +592,9 @@ int main(int argc, char **argv) {
build_mode = BuildModeSmallRelease; build_mode = BuildModeSmallRelease;
} else if (strcmp(arg, "--help") == 0) { } else if (strcmp(arg, "--help") == 0) {
if (cmd == CmdLibC) { if (cmd == CmdLibC) {
return print_libc_usage(arg0, stderr, EXIT_FAILURE); return print_libc_usage(arg0, stdout, EXIT_SUCCESS);
} else { } else {
return print_full_usage(arg0, stderr, EXIT_FAILURE); return print_full_usage(arg0, stdout, EXIT_SUCCESS);
} }
} else if (strcmp(arg, "--strip") == 0) { } else if (strcmp(arg, "--strip") == 0) {
strip = true; strip = true;
@ -607,6 +612,8 @@ int main(int argc, char **argv) {
verbose_llvm_ir = true; verbose_llvm_ir = true;
} else if (strcmp(arg, "--verbose-cimport") == 0) { } else if (strcmp(arg, "--verbose-cimport") == 0) {
verbose_cimport = true; verbose_cimport = true;
} else if (strcmp(arg, "--verbose-cc") == 0) {
verbose_cc = true;
} else if (strcmp(arg, "-rdynamic") == 0) { } else if (strcmp(arg, "-rdynamic") == 0) {
rdynamic = true; rdynamic = true;
} else if (strcmp(arg, "--each-lib-rpath") == 0) { } else if (strcmp(arg, "--each-lib-rpath") == 0) {
@ -656,6 +663,8 @@ int main(int argc, char **argv) {
out_file = argv[i]; out_file = argv[i];
} else if (strcmp(arg, "--output-h") == 0) { } else if (strcmp(arg, "--output-h") == 0) {
out_file_h = argv[i]; out_file_h = argv[i];
} else if (strcmp(arg, "--output-lib") == 0) {
out_file_lib = argv[i];
} else if (strcmp(arg, "--color") == 0) { } else if (strcmp(arg, "--color") == 0) {
if (strcmp(argv[i], "auto") == 0) { if (strcmp(argv[i], "auto") == 0) {
color = ErrColorAuto; color = ErrColorAuto;
@ -714,6 +723,19 @@ int main(int argc, char **argv) {
forbidden_link_libs.append(argv[i]); forbidden_link_libs.append(argv[i]);
} else if (strcmp(arg, "--object") == 0) { } else if (strcmp(arg, "--object") == 0) {
objects.append(argv[i]); objects.append(argv[i]);
} else if (strcmp(arg, "--c-source") == 0) {
CFile *c_file = allocate<CFile>(1);
for (;;) {
if (argv[i][0] == '-') {
c_file->args.append(argv[i]);
i += 1;
continue;
} else {
c_file->source_path = argv[i];
c_source_files.append(c_file);
break;
}
}
} else if (strcmp(arg, "--assembly") == 0) { } else if (strcmp(arg, "--assembly") == 0) {
asm_files.append(argv[i]); asm_files.append(argv[i]);
} else if (strcmp(arg, "--cache-dir") == 0) { } else if (strcmp(arg, "--cache-dir") == 0) {
@ -792,8 +814,6 @@ int main(int argc, char **argv) {
} else if (strcmp(arg, "build-lib") == 0) { } else if (strcmp(arg, "build-lib") == 0) {
cmd = CmdBuild; cmd = CmdBuild;
out_type = OutTypeLib; out_type = OutTypeLib;
} else if (strcmp(arg, "help") == 0) {
cmd = CmdHelp;
} else if (strcmp(arg, "run") == 0) { } else if (strcmp(arg, "run") == 0) {
cmd = CmdRun; cmd = CmdRun;
out_type = OutTypeExe; out_type = OutTypeExe;
@ -835,7 +855,6 @@ int main(int argc, char **argv) {
} }
break; break;
case CmdBuiltin: case CmdBuiltin:
case CmdHelp:
case CmdVersion: case CmdVersion:
case CmdZen: case CmdZen:
case CmdTargets: case CmdTargets:
@ -910,16 +929,44 @@ int main(int argc, char **argv) {
case CmdTranslateC: case CmdTranslateC:
case CmdTest: case CmdTest:
{ {
if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 &&
fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); c_source_files.length == 0)
{
fprintf(stderr,
"Expected at least one of these things:\n"
" * Zig root source file argument\n"
" * --object argument\n"
" * --assembly argument\n"
" * --c-source argument\n");
return print_error_usage(arg0); return print_error_usage(arg0);
} else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) { } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
fprintf(stderr, "Expected source file argument.\n"); fprintf(stderr, "Expected source file argument.\n");
return print_error_usage(arg0); return print_error_usage(arg0);
} else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { } else if (cmd == CmdBuild && out_type == OutTypeObj) {
fprintf(stderr, "When building an object file, --object arguments are invalid.\n"); if (objects.length != 0) {
fprintf(stderr,
"When building an object file, --object arguments are invalid.\n"
"Consider building a static library instead.\n");
return print_error_usage(arg0); return print_error_usage(arg0);
} }
size_t zig_root_src_count = in_file ? 1 : 0;
if (zig_root_src_count + c_source_files.length > 1) {
fprintf(stderr,
"When building an object file, only one of these allowed:\n"
" * Zig root source file argument\n"
" * --c-source argument\n"
"Consider building a static library instead.\n");
return print_error_usage(arg0);
}
if (c_source_files.length != 0 && asm_files.length != 0) {
fprintf(stderr,
"When building an object file, only one of these allowed:\n"
" * --assembly argument\n"
" * --c-source argument\n"
"Consider building a static library instead.\n");
return print_error_usage(arg0);
}
}
assert(cmd != CmdBuild || out_type != OutTypeUnknown); assert(cmd != CmdBuild || out_type != OutTypeUnknown);
@ -945,6 +992,13 @@ int main(int argc, char **argv) {
} }
} }
if (need_name && buf_out_name == nullptr && c_source_files.length == 1) {
Buf basename = BUF_INIT;
os_path_split(buf_create_from_str(c_source_files.at(0)->source_path), nullptr, &basename);
buf_out_name = buf_alloc();
os_path_extname(&basename, buf_out_name, nullptr);
}
if (need_name && buf_out_name == nullptr) { if (need_name && buf_out_name == nullptr) {
fprintf(stderr, "--name [name] not provided and unable to infer\n\n"); fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
return print_error_usage(arg0); return print_error_usage(arg0);
@ -996,6 +1050,7 @@ int main(int argc, char **argv) {
g->verbose_ir = verbose_ir; g->verbose_ir = verbose_ir;
g->verbose_llvm_ir = verbose_llvm_ir; g->verbose_llvm_ir = verbose_llvm_ir;
g->verbose_cimport = verbose_cimport; g->verbose_cimport = verbose_cimport;
g->verbose_cc = verbose_cc;
codegen_set_errmsg_color(g, color); codegen_set_errmsg_color(g, color);
g->system_linker_hack = system_linker_hack; g->system_linker_hack = system_linker_hack;
@ -1043,11 +1098,14 @@ int main(int argc, char **argv) {
codegen_set_output_path(g, buf_create_from_str(out_file)); codegen_set_output_path(g, buf_create_from_str(out_file));
if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib)) if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))
codegen_set_output_h_path(g, buf_create_from_str(out_file_h)); codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
add_package(g, cur_pkg, g->root_package); add_package(g, cur_pkg, g->root_package);
if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) { if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
g->c_source_files = c_source_files;
for (size_t i = 0; i < objects.length; i += 1) { for (size_t i = 0; i < objects.length; i += 1) {
codegen_add_object(g, buf_create_from_str(objects.at(i))); codegen_add_object(g, buf_create_from_str(objects.at(i)));
} }
@ -1147,8 +1205,6 @@ int main(int argc, char **argv) {
zig_unreachable(); zig_unreachable();
} }
} }
case CmdHelp:
return print_full_usage(arg0, stdout, EXIT_SUCCESS);
case CmdVersion: case CmdVersion:
printf("%s\n", ZIG_VERSION_STRING); printf("%s\n", ZIG_VERSION_STRING);
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -1158,7 +1214,6 @@ int main(int argc, char **argv) {
case CmdTargets: case CmdTargets:
return print_target_list(stdout); return print_target_list(stdout);
case CmdNone: case CmdNone:
fprintf(stderr, "Zig programming language\n"); return print_full_usage(arg0, stderr, EXIT_FAILURE);
return print_error_usage(arg0);
} }
} }

View File

@ -1232,6 +1232,18 @@ static Error os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_p
} }
#endif #endif
Buf *os_tmp_filename(Buf *prefix, Buf *suffix) {
Buf *result = buf_create_from_buf(prefix);
const char base64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
assert(array_length(base64) == 64 + 1);
for (size_t i = 0; i < 12; i += 1) {
buf_append_char(result, base64[rand() % 64]);
}
buf_append_buf(result, suffix);
return result;
}
#if defined(ZIG_OS_WINDOWS) #if defined(ZIG_OS_WINDOWS)
static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) { static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
char tmp_dir[MAX_PATH + 1]; char tmp_dir[MAX_PATH + 1];

View File

@ -121,6 +121,7 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);
bool os_stderr_tty(void); bool os_stderr_tty(void);
void os_stderr_set_color(TermColor color); void os_stderr_set_color(TermColor color);
Buf *os_tmp_filename(Buf *prefix, Buf *suffix);
Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path); Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
Error os_delete_file(Buf *path); Error os_delete_file(Buf *path);

View File

@ -1049,3 +1049,9 @@ bool target_requires_libc(const ZigTarget *target) {
// since this is the stable syscall interface. // since this is the stable syscall interface.
return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD); return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD);
} }
bool target_supports_fpic(const ZigTarget *target) {
// This is not whether the target supports Position Independent Code, but whether the -fPIC
// C compiler argument is valid.
return target->os != OsWindows;
}

View File

@ -141,5 +141,6 @@ bool target_allows_addr_zero(const ZigTarget *target);
bool target_has_valgrind_support(const ZigTarget *target); bool target_has_valgrind_support(const ZigTarget *target);
bool target_is_darwin(const ZigTarget *target); bool target_is_darwin(const ZigTarget *target);
bool target_requires_libc(const ZigTarget *target); bool target_requires_libc(const ZigTarget *target);
bool target_supports_fpic(const ZigTarget *target);
#endif #endif

View File

@ -4776,6 +4776,15 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
clang_argv.append("-x"); clang_argv.append("-x");
clang_argv.append("c"); clang_argv.append("c");
Buf *out_dep_path = nullptr;
if (codegen->enable_cache) {
Buf *prefix = buf_sprintf("%s" OS_SEP, buf_ptr(&codegen->cache_dir));
out_dep_path = os_tmp_filename(prefix, buf_create_from_str(".d"));
clang_argv.append("-MD");
clang_argv.append("-MF");
clang_argv.append(buf_ptr(out_dep_path));
}
if (c->codegen->zig_target->is_native) { if (c->codegen->zig_target->is_native) {
char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS"); char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS");
if (ZIG_PARSEC_CFLAGS) { if (ZIG_PARSEC_CFLAGS) {
@ -4912,6 +4921,17 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
return ErrorCCompileErrors; return ErrorCCompileErrors;
} }
if (codegen->enable_cache) {
Error err;
assert(out_dep_path != nullptr);
if ((err = cache_add_dep_file(&codegen->cache_hash, out_dep_path, codegen->verbose_cimport))) {
if (codegen->verbose_cimport) {
fprintf(stderr, "translate-c: aborting due to failed cache operation: %s\n", err_str(err));
}
return err;
}
}
c->ctx = ZigClangASTUnit_getASTContext(ast_unit); c->ctx = ZigClangASTUnit_getASTContext(ast_unit);
c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit); c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit);
c->root = trans_create_node(c, NodeTypeContainerDecl); c->root = trans_create_node(c, NodeTypeContainerDecl);

View File

@ -32,6 +32,10 @@ pub const BufSet = struct {
} }
} }
pub fn exists(self: BufSet, key: []const u8) bool {
return self.hash_map.get(key) != null;
}
pub fn delete(self: *BufSet, key: []const u8) void { pub fn delete(self: *BufSet, key: []const u8) void {
const entry = self.hash_map.remove(key) orelse return; const entry = self.hash_map.remove(key) orelse return;
self.free(entry.key); self.free(entry.key);

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
cases.addC("example/hello_world/hello_libc.zig"); cases.addC("example/hello_world/hello_libc.zig");
cases.add("example/cat/main.zig"); cases.add("example/cat/main.zig");
cases.add("example/guess_number/main.zig"); cases.add("example/guess_number/main.zig");
if (!is_windows) {
// TODO get this test passing on windows
// See https://github.com/ziglang/zig/issues/538
cases.addBuildFile("example/shared_library/build.zig"); cases.addBuildFile("example/shared_library/build.zig");
cases.addBuildFile("example/mix_o_files/build.zig"); cases.addBuildFile("example/mix_o_files/build.zig");
}
if (builtin.os != builtin.Os.macosx) { if (builtin.os != builtin.Os.macosx) {
// TODO https://github.com/ziglang/zig/issues/1126 // TODO https://github.com/ziglang/zig/issues/1126
cases.addBuildFile("test/standalone/issue_339/build.zig"); cases.addBuildFile("test/standalone/issue_339/build.zig");

View File

@ -3,9 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void { pub fn build(b: *Builder) void {
const rel_opts = b.standardReleaseOptions(); const rel_opts = b.standardReleaseOptions();
const c_obj = b.addCObject("cfuncs", "cfuncs.c"); const c_obj = b.addObject("cfuncs", null);
c_obj.addCSourceFile("cfuncs.c", [][]const u8{"-std=c99"});
c_obj.setBuildMode(rel_opts); c_obj.setBuildMode(rel_opts);
c_obj.setNoStdLib(true); c_obj.linkSystemLibrary("c");
const main = b.addTest("main.zig"); const main = b.addTest("main.zig");
main.setBuildMode(rel_opts); main.setBuildMode(rel_opts);