diff --git a/src/all_types.hpp b/src/all_types.hpp index 91676d0c39b2..4bb76ff64f2a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1857,7 +1857,7 @@ struct CodeGen { BuildMode build_mode; OutType out_type; const ZigTarget *zig_target; - TargetSubsystem subsystem; + TargetSubsystem subsystem; // careful using this directly; see detect_subsystem ValgrindSupport valgrind_support; bool strip_debug_symbols; bool is_test_build; diff --git a/src/analyze.cpp b/src/analyze.cpp index 182bcc93a6fe..3769ae47c285 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2722,12 +2722,10 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi if (ccc) { if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { g->have_c_main = true; - g->subsystem = g->subsystem == TargetSubsystemAuto ? TargetSubsystemConsole : g->subsystem; } else if (buf_eql_str(symbol_name, "WinMain") && g->zig_target->os == OsWindows) { g->have_winmain = true; - g->subsystem = g->subsystem == TargetSubsystemAuto ? TargetSubsystemWindows : g->subsystem; } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && g->zig_target->os == OsWindows) { @@ -3966,7 +3964,6 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu if (is_pub) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; - g->subsystem = g->subsystem == TargetSubsystemAuto ? TargetSubsystemConsole : g->subsystem; } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } diff --git a/src/codegen.cpp b/src/codegen.cpp index 7d9e03baf4e5..fc9cdfc9b8b1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -100,6 +100,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget codegen_add_time_event(g, "Initialize"); + g->subsystem = TargetSubsystemAuto; g->libc = libc; g->zig_target = target; g->cache_dir = cache_dir; @@ -7417,6 +7418,21 @@ static const char *build_mode_to_str(BuildMode build_mode) { zig_unreachable(); } +static const char *subsystem_to_str(TargetSubsystem subsystem) { + switch (subsystem) { + case TargetSubsystemConsole: return "Console"; + case TargetSubsystemWindows: return "Windows"; + case TargetSubsystemPosix: return "Posix"; + case TargetSubsystemNative: return "Native"; + case TargetSubsystemEfiApplication: return "EfiApplication"; + case TargetSubsystemEfiBootServiceDriver: return "EfiBootServiceDriver"; + case TargetSubsystemEfiRom: return "EfiRom"; + case TargetSubsystemEfiRuntimeDriver: return "EfiRuntimeDriver"; + case TargetSubsystemAuto: zig_unreachable(); + } + zig_unreachable(); +} + static bool detect_dynamic_link(CodeGen *g) { if (g->is_dynamic) return true; @@ -7462,6 +7478,23 @@ static bool detect_stack_probing(CodeGen *g) { zig_unreachable(); } +// Returns TargetSubsystemAuto to mean "no subsystem" +TargetSubsystem detect_subsystem(CodeGen *g) { + if (g->subsystem != TargetSubsystemAuto) + return g->subsystem; + if (g->zig_target->os == OsWindows) { + if (g->have_dllmain_crt_startup || (g->out_type == OutTypeLib && g->is_dynamic)) + return TargetSubsystemAuto; + if (g->have_c_main || g->have_pub_main || g->is_test_build) + return TargetSubsystemConsole; + if (g->have_winmain || g->have_winmain_crt_startup) + return TargetSubsystemWindows; + } else if (g->zig_target->os == OsUefi) { + return TargetSubsystemEfiApplication; + } + return TargetSubsystemAuto; +} + static bool detect_single_threaded(CodeGen *g) { if (g->want_single_threaded) return true; @@ -7869,6 +7902,28 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { //assert(EndianBig == 0); //assert(EndianLittle == 1); } + { + buf_appendf(contents, + "pub const SubSystem = enum {\n" + " Console,\n" + " Windows,\n" + " Posix,\n" + " Native,\n" + " EfiApplication,\n" + " EfiBootServiceDriver,\n" + " EfiRom,\n" + " EfiRuntimeDriver,\n" + "};\n\n"); + + assert(TargetSubsystemConsole == 0); + assert(TargetSubsystemWindows == 1); + assert(TargetSubsystemPosix == 2); + assert(TargetSubsystemNative == 3); + assert(TargetSubsystemEfiApplication == 4); + assert(TargetSubsystemEfiBootServiceDriver == 5); + assert(TargetSubsystemEfiRom == 6); + assert(TargetSubsystemEfiRuntimeDriver == 7); + } { const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little"; buf_appendf(contents, "pub const endian = %s;\n", endian_str); @@ -7885,6 +7940,13 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { buf_appendf(contents, "pub const valgrind_support = %s;\n", bool_to_str(want_valgrind_support(g))); buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); + { + TargetSubsystem detected_subsystem = detect_subsystem(g); + if (detected_subsystem != TargetSubsystemAuto) { + buf_appendf(contents, "pub const subsystem = SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); + } + } + if (g->is_test_build) { buf_appendf(contents, "const TestFn = struct {\n" @@ -7928,6 +7990,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { cache_bool(&cache_hash, g->have_err_ret_tracing); cache_bool(&cache_hash, g->libc_link_lib != nullptr); cache_bool(&cache_hash, g->valgrind_support); + cache_int(&cache_hash, detect_subsystem(g)); Buf digest = BUF_INIT; buf_resize(&digest, 0); @@ -7995,10 +8058,6 @@ static void init(CodeGen *g) { g->is_single_threaded = true; } - if (g->is_test_build) { - g->subsystem = g->subsystem == TargetSubsystemAuto ? TargetSubsystemConsole : g->subsystem; - } - assert(g->root_out_name); g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name)); @@ -9352,7 +9411,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_int(ch, g->zig_target->vendor); cache_int(ch, g->zig_target->os); cache_int(ch, g->zig_target->abi); - cache_int(ch, g->subsystem); + cache_int(ch, detect_subsystem(g)); cache_bool(ch, g->strip_debug_symbols); cache_bool(ch, g->is_test_build); if (g->is_test_build) { diff --git a/src/codegen.hpp b/src/codegen.hpp index 47c0097e4baf..9a340d720507 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -56,4 +56,6 @@ void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_us Buf *codegen_generate_builtin_source(CodeGen *g); +TargetSubsystem detect_subsystem(CodeGen *g); + #endif diff --git a/src/link.cpp b/src/link.cpp index 4c3b3d476979..f94b1219f6b9 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -1225,7 +1225,7 @@ static void add_mingw_link_args(LinkJob *lj, bool is_library) { lj->args.append(get_libc_file(g->libc, "libmingwex.a")); lj->args.append(get_libc_file(g->libc, "libmsvcrt.a")); - if (g->subsystem == TargetSubsystemWindows) { + if (detect_subsystem(g) == TargetSubsystemWindows) { lj->args.append(get_libc_file(g->libc, "libgdi32.a")); lj->args.append(get_libc_file(g->libc, "libcomdlg32.a")); } @@ -1307,7 +1307,7 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } - switch (g->subsystem) { + switch (detect_subsystem(g)) { case TargetSubsystemAuto: if (g->zig_target->os == OsUefi) { add_uefi_link_args(lj); diff --git a/src/target.hpp b/src/target.hpp index f3cde902a09e..7fa99bcda8d1 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -62,7 +62,6 @@ enum SubArchList { }; enum TargetSubsystem { - TargetSubsystemAuto, // Zig should infer the subsystem TargetSubsystemConsole, TargetSubsystemWindows, TargetSubsystemPosix, @@ -71,6 +70,11 @@ enum TargetSubsystem { TargetSubsystemEfiBootServiceDriver, TargetSubsystemEfiRom, TargetSubsystemEfiRuntimeDriver, + + // This means Zig should infer the subsystem. + // It's last so that the indexes of other items can line up + // with the enum in builtin.zig. + TargetSubsystemAuto }; struct ZigTarget {