diff --git a/src/all_types.hpp b/src/all_types.hpp index 80f17afdd4..8386050cae 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1362,6 +1362,7 @@ struct CodeGen { bool strip_debug_symbols; bool want_h_file; bool have_pub_main; + bool have_c_main; bool have_pub_panic; bool link_libc; Buf *libc_lib_dir; diff --git a/src/analyze.cpp b/src/analyze.cpp index c3e2522ab4..af910cd590 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2911,7 +2911,12 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } + } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "main") && + g->link_libc) + { + g->have_c_main = true; } + } } diff --git a/src/codegen.cpp b/src/codegen.cpp index d5f1cfe4f6..3061c82766 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4726,7 +4726,9 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou assert(g->root_out_name); assert(g->out_type != OutTypeUnknown); - if (!g->is_test_build && g->have_pub_main && (g->out_type == OutTypeObj || g->out_type == OutTypeExe)) { + if (!g->is_test_build && g->zig_target.os != ZigLLVM_UnknownOS && !g->have_c_main && + ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) + { g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); } if (!g->omit_zigrt) { diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 3b014869f9..d2a7703144 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -12,8 +12,8 @@ const exit = std.os.posix.exit; var argc_ptr: &usize = undefined; export nakedcc fn _start() -> noreturn { - @setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal); if (!want_start_symbol) { + @setGlobalLinkage(_start, GlobalLinkage.Internal); unreachable; } @@ -48,8 +48,8 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { } export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { - @setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal); if (!want_main_symbol) { + @setGlobalLinkage(main, GlobalLinkage.Internal); unreachable; } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index e7b041ee3f..aad51dbe1f 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -161,6 +161,38 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source return test_case; } +static TestCase *add_compile_fail_case_exe(const char *case_name, const char *source, size_t count, ...) { + va_list ap; + va_start(ap, count); + + TestCase *test_case = allocate(1); + test_case->case_name = case_name; + test_case->source_files.resize(1); + test_case->source_files.at(0).relative_path = tmp_source_path; + test_case->source_files.at(0).source_code = source; + + for (size_t i = 0; i < count; i += 1) { + const char *arg = va_arg(ap, const char *); + test_case->compile_errors.append(arg); + } + + test_case->compiler_args.append("build_exe"); + test_case->compiler_args.append(tmp_source_path); + + test_case->compiler_args.append("--name"); + test_case->compiler_args.append("test"); + + test_case->compiler_args.append("--output"); + test_case->compiler_args.append(tmp_exe_path); + + test_case->compiler_args.append("--release"); + test_case->compiler_args.append("--strip"); + + test_cases.append(test_case); + + return test_case; +} + static void add_debug_safety_case(const char *case_name, const char *source) { TestCase *test_case = allocate(1); test_case->is_debug_safety = true; @@ -220,6 +252,11 @@ static TestCase *add_example_compile_extra(const char *root_source_file, bool li test_case->compiler_args.append("build_exe"); test_case->compiler_args.append(buf_ptr(buf_sprintf("../%s", root_source_file))); + if (libc) { + test_case->compiler_args.append("--library"); + test_case->compiler_args.append("c"); + } + test_cases.append(test_case); return test_case; @@ -1952,6 +1989,16 @@ comptime { const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a); } )SOURCE", 1, ".tmp_source.zig:9:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'"); + + add_compile_fail_case_exe("missing main fn in executable", R"SOURCE( + )SOURCE", 1, "error: no member named 'main' in '"); + + add_compile_fail_case_exe("private main fn", R"SOURCE( +fn main() {} + )SOURCE", 2, + "error: 'main' is private", + ".tmp_source.zig:2:1: note: declared here"); + } //////////////////////////////////////////////////////////////////////////////