Skip to content

Commit 38f05d4

Browse files
dimenusandrewrk
authored andcommittedNov 1, 2017
WIN32: Linking with the CRT at runtime. (#570)
Disclaimer: Forgive me if my format sucks, I've never submitted a PR before! Fixes: #517 I added a few things to allow zig to link with the CRT properly both statically and dynamically. In Visual Studio 2017, Microsoft changed how the c-runtime is factored again. With this change, they also added a COM interface to allow you to query the respective Visual Studio instance for two of them. This does that and also falls back on a registry query for 2015 support. If you're using a Visual Studio instance older than 2015, you'll have to use the existing options available with the zig compiler. Changes are listed below along with a general description of the changes. all_types.cpp: The separate variables for msvc/kern32 have been removed and all win32 libc directory paths have been combined into a ZigList since we're querying more than two directories and differentiating one from another doesn't matter to lld. analyze.cpp: The existing functions were extended to support querying libc libs & libc headers at runtime. codegen.cpp/hpp: Microsoft uses the new 'Universal C Runtime' name now. Doesn't matter from a functionality standpoint. I left the compiler switches as is to not introduce any breaking changes. link.cpp: We're linking 4 libs and generating another in order to support the UCRT. Dynamic: msvcrt/d, vcruntime/d, ucrt/d, legacy_stdio_definitions.lib Static: libcmt/d, libvcruntime/d libucrt/d, legacy_stdio_definitions.lib main.cpp: Update function call names. os.cpp/hpp: COM/Registry interface for querying Windows UCRT/SDK. Sources: [Windows CRT](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features) [VS 2015 Breaking Changes](https://msdn.microsoft.com/en-us/library/bb531344.aspx)
1 parent b35689b commit 38f05d4

11 files changed

+1316
-86
lines changed
 

‎src/all_types.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct IrInstruction;
3535
struct IrInstructionCast;
3636
struct IrBasicBlock;
3737
struct ScopeDecls;
38+
struct ZigWindowsSDK;
3839

3940
struct IrGotoItem {
4041
AstNode *source_node;
@@ -1461,17 +1462,17 @@ struct CodeGen {
14611462
bool have_winmain_crt_startup;
14621463
bool have_dllmain_crt_startup;
14631464
bool have_pub_panic;
1465+
ZigList<Buf*> libc_lib_dirs_list;
14641466
Buf *libc_lib_dir;
14651467
Buf *libc_static_lib_dir;
14661468
Buf *libc_include_dir;
1467-
Buf *msvc_lib_dir;
1468-
Buf *kernel32_lib_dir;
14691469
Buf *zig_lib_dir;
14701470
Buf *zig_std_dir;
14711471
Buf *zig_c_headers_dir;
14721472
Buf *zig_std_special_dir;
14731473
Buf *dynamic_linker;
14741474
Buf *ar_path;
1475+
ZigWindowsSDK *win_sdk;
14751476
Buf triple_str;
14761477
BuildMode build_mode;
14771478
bool is_test_build;

‎src/analyze.cpp

+39-47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/*
22
* Copyright (c) 2015 Andrew Kelley
33
*
44
* This file is part of zig, which is MIT licensed.
@@ -3371,65 +3371,57 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
33713371
}
33723372

33733373
void find_libc_include_path(CodeGen *g) {
3374+
#ifdef ZIG_OS_WINDOWS
33743375
if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {
3376+
if (g->win_sdk == nullptr) {
3377+
if (os_find_windows_sdk(&g->win_sdk)) {
3378+
zig_panic("Unable to determine Windows SDK path.");
3379+
}
3380+
}
3381+
3382+
if (g->zig_target.os == ZigLLVM_Win32) {
3383+
if (os_get_win32_ucrt_include_path(g->win_sdk, g->libc_include_dir)) {
3384+
zig_panic("Unable to determine libc include path.");
3385+
}
3386+
}
3387+
}
3388+
return;
3389+
#endif
3390+
// TODO find libc at runtime for other operating systems
3391+
if(!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {
33753392
zig_panic("Unable to determine libc include path.");
33763393
}
33773394
}
33783395

33793396
void find_libc_lib_path(CodeGen *g) {
33803397
#ifdef ZIG_OS_WINDOWS
3381-
if (!g->msvc_lib_dir && g->zig_target.os == ZigLLVM_Win32) {
3382-
Buf *msvc_lib_dir;
3383-
if (g->zig_target.arch.arch == ZigLLVM_arm) {
3384-
msvc_lib_dir = buf_create_from_str("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\lib\\arm");
3385-
} else if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
3386-
msvc_lib_dir = buf_create_from_str("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\lib\\amd64");
3387-
} else if (g->zig_target.arch.arch == ZigLLVM_x86) {
3388-
msvc_lib_dir = buf_create_from_str("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\lib");
3389-
} else {
3390-
zig_panic("unable to determine msvc lib path");
3391-
}
3392-
Buf *test_path = buf_alloc();
3393-
os_path_join(msvc_lib_dir, buf_create_from_str("vcruntime.lib"), test_path);
3394-
bool result;
3395-
int err;
3396-
if ((err = os_file_exists(test_path, &result))) {
3397-
result = false;
3398-
}
3399-
if (result) {
3400-
g->msvc_lib_dir = msvc_lib_dir;
3401-
} else {
3402-
zig_panic("Unable to determine msvc lib path.");
3398+
if (g->zig_target.os == ZigLLVM_Win32) {
3399+
if (g->win_sdk == nullptr) {
3400+
if (os_find_windows_sdk(&g->win_sdk)) {
3401+
zig_panic("Unable to determine Windows SDK path.");
3402+
}
34033403
}
3404-
}
34053404

3406-
if (!g->kernel32_lib_dir && g->zig_target.os == ZigLLVM_Win32) {
3407-
Buf *kernel32_lib_dir;
3408-
if (g->zig_target.arch.arch == ZigLLVM_arm) {
3409-
kernel32_lib_dir = buf_create_from_str(
3410-
"C:\\Program Files (x86)\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\arm");
3411-
} else if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
3412-
kernel32_lib_dir = buf_create_from_str(
3413-
"C:\\Program Files (x86)\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\x64");
3414-
} else if (g->zig_target.arch.arch == ZigLLVM_x86) {
3415-
kernel32_lib_dir = buf_create_from_str(
3416-
"C:\\Program Files (x86)\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\x86");
3417-
} else {
3418-
zig_panic("unable to determine kernel32 lib path");
3405+
Buf* vc_lib_dir = buf_alloc();
3406+
if (os_get_win32_vcruntime_path(vc_lib_dir, g->zig_target.arch.arch)) {
3407+
zig_panic("Unable to determine vcruntime path.");
34193408
}
3420-
Buf *test_path = buf_alloc();
3421-
os_path_join(kernel32_lib_dir, buf_create_from_str("kernel32.lib"), test_path);
3422-
bool result;
3423-
int err;
3424-
if ((err = os_file_exists(test_path, &result))) {
3425-
result = false;
3409+
3410+
Buf* ucrt_lib_path = buf_alloc();
3411+
if (os_get_win32_ucrt_lib_path(g->win_sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
3412+
zig_panic("Unable to determine ucrt path.");
34263413
}
3427-
if (result) {
3428-
g->kernel32_lib_dir = kernel32_lib_dir;
3429-
} else {
3430-
zig_panic("Unable to determine kernel32 lib path.");
3414+
3415+
Buf* kern_lib_path = buf_alloc();
3416+
if (os_get_win32_kern32_path(g->win_sdk, kern_lib_path, g->zig_target.arch.arch)) {
3417+
zig_panic("Unable to determine kernel32 path.");
34313418
}
3419+
3420+
g->libc_lib_dirs_list.append(vc_lib_dir);
3421+
g->libc_lib_dirs_list.append(ucrt_lib_path);
3422+
g->libc_lib_dirs_list.append(kern_lib_path);
34323423
}
3424+
return;
34333425
#endif
34343426

34353427
// later we can handle this better by reporting an error via the normal mechanism

‎src/codegen.cpp

+9-16
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
8585
g->external_prototypes.init(8);
8686
g->is_test_build = false;
8787
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
88-
8988
buf_resize(&g->global_asm, 0);
9089

9190
// reserve index 0 to indicate no error
@@ -106,31 +105,25 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
106105
g->zig_std_special_dir = buf_alloc();
107106
os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir);
108107

109-
110108
if (target) {
111109
// cross compiling, so we can't rely on all the configured stuff since
112110
// that's for native compilation
113111
g->zig_target = *target;
114112
resolve_target_object_format(&g->zig_target);
115-
116113
g->dynamic_linker = buf_create_from_str("");
117114
g->libc_lib_dir = buf_create_from_str("");
118115
g->libc_static_lib_dir = buf_create_from_str("");
119116
g->libc_include_dir = buf_create_from_str("");
120-
g->msvc_lib_dir = nullptr;
121-
g->kernel32_lib_dir = nullptr;
122117
g->each_lib_rpath = false;
123118
} else {
124119
// native compilation, we can rely on the configuration stuff
125120
g->is_native_target = true;
126121
get_native_target(&g->zig_target);
127-
128122
g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER);
129123
g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);
130124
g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);
131125
g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);
132-
g->msvc_lib_dir = nullptr; // find it at runtime
133-
g->kernel32_lib_dir = nullptr; // find it at runtime
126+
134127
#ifdef ZIG_EACH_LIB_RPATH
135128
g->each_lib_rpath = true;
136129
#endif
@@ -228,14 +221,6 @@ void codegen_set_libc_include_dir(CodeGen *g, Buf *libc_include_dir) {
228221
g->libc_include_dir = libc_include_dir;
229222
}
230223

231-
void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir) {
232-
g->msvc_lib_dir = msvc_lib_dir;
233-
}
234-
235-
void codegen_set_kernel32_lib_dir(CodeGen *g, Buf *kernel32_lib_dir) {
236-
g->kernel32_lib_dir = kernel32_lib_dir;
237-
}
238-
239224
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker) {
240225
g->dynamic_linker = dynamic_linker;
241226
}
@@ -244,6 +229,14 @@ void codegen_add_lib_dir(CodeGen *g, const char *dir) {
244229
g->lib_dirs.append(dir);
245230
}
246231

232+
void codegen_set_ucrt_lib_dir(CodeGen *g, Buf *ucrt_lib_dir) {
233+
g->libc_lib_dirs_list.append(ucrt_lib_dir);
234+
}
235+
236+
void codegen_set_kernel32_lib_dir(CodeGen *g, Buf *kernel32_lib_dir) {
237+
g->libc_lib_dirs_list.append(kernel32_lib_dir);
238+
}
239+
247240
void codegen_add_rpath(CodeGen *g, const char *name) {
248241
g->rpath_list.append(buf_create_from_str(name));
249242
}

‎src/codegen.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
3030
void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir);
3131
void codegen_set_libc_static_lib_dir(CodeGen *g, Buf *libc_static_lib_dir);
3232
void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir);
33-
void codegen_set_msvc_lib_dir(CodeGen *codegen, Buf *msvc_lib_dir);
33+
void codegen_set_ucrt_lib_dir(CodeGen *g, Buf *ucrt_lib_dir);
3434
void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
3535
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
3636
void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);

‎src/link.cpp

+16-7
Original file line numberDiff line numberDiff line change
@@ -402,26 +402,35 @@ static void construct_linker_job_coff(LinkJob *lj) {
402402
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&lj->out_file))));
403403

404404
if (g->libc_link_lib != nullptr) {
405-
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
406-
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
407-
408-
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
409-
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
405+
if (g->libc_link_lib != nullptr) {
406+
for (uint32_t i = 0; i < g->libc_lib_dirs_list.length; ++i) {
407+
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dirs_list.items[i]))));
408+
}
409+
}
410410
}
411411

412412
if (lj->link_in_crt) {
413413
const char *lib_str = g->is_static ? "lib" : "";
414414
const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : "";
415415

416-
Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str);
417-
lj->args.append(buf_ptr(cmt_lib_name));
416+
if (g->is_static) {
417+
Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str);
418+
lj->args.append(buf_ptr(cmt_lib_name));
419+
}
420+
else {
421+
Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str);
422+
lj->args.append(buf_ptr(msvcrt_lib_name));
423+
}
418424

419425
Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str);
420426
lj->args.append(buf_ptr(vcruntime_lib_name));
421427

422428
Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str);
423429
lj->args.append(buf_ptr(crt_lib_name));
424430

431+
//Visual C++ 2015 Conformance Changes
432+
//https://msdn.microsoft.com/en-us/library/bb531344.aspx
433+
lj->args.append("legacy_stdio_definitions.lib");
425434

426435
//if (shared || dll) {
427436
// lj->args.append(get_libc_file(g, "dllcrt2.o"));

‎src/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ int main(int argc, char **argv) {
758758
if (libc_include_dir)
759759
codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir));
760760
if (msvc_lib_dir)
761-
codegen_set_msvc_lib_dir(g, buf_create_from_str(msvc_lib_dir));
761+
codegen_set_ucrt_lib_dir(g, buf_create_from_str(msvc_lib_dir));
762762
if (kernel32_lib_dir)
763763
codegen_set_kernel32_lib_dir(g, buf_create_from_str(kernel32_lib_dir));
764764
if (dynamic_linker)

0 commit comments

Comments
 (0)
Please sign in to comment.