authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-29 13:16:41-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-04-29 13:16:41-04:00
logd3c88a8949851c4ea9bdfd38dfb0e93196f602ea
tree0a90fe0822c7f8a60d2a3a3ef73d689f5cd1bee8
parent9902b604cb01072d4599035b59724731cf03fdbc
parent6057513cc753905a592e4810e6eb79ffb397cf73
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2139 from emekoi/lib-on-mingw

implement linking to libc on mingw

3 files changed, 184 insertions(+), 88 deletions(-)

src/libc_installation.cpp+29-5
......@@ -14,6 +14,7 @@ static const char *zig_libc_keys[] = {
1414 "include_dir",
1515 "sys_include_dir",
1616 "crt_dir",
17 "static_crt_dir",
1718 "msvc_lib_dir",
1819 "kernel32_lib_dir",
1920};
......@@ -34,6 +35,7 @@ static void zig_libc_init_empty(ZigLibCInstallation *libc) {
3435 buf_init_from_str(&libc->include_dir, "");
3536 buf_init_from_str(&libc->sys_include_dir, "");
3637 buf_init_from_str(&libc->crt_dir, "");
38 buf_init_from_str(&libc->static_crt_dir, "");
3739 buf_init_from_str(&libc->msvc_lib_dir, "");
3840 buf_init_from_str(&libc->kernel32_lib_dir, "");
3941}
......@@ -74,8 +76,9 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget
7476 match = match || zig_libc_match_key(name, value, found_keys, 0, &libc->include_dir);
7577 match = match || zig_libc_match_key(name, value, found_keys, 1, &libc->sys_include_dir);
7678 match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir);
77 match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->msvc_lib_dir);
78 match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->kernel32_lib_dir);
79 match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->static_crt_dir);
80 match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->msvc_lib_dir);
81 match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->kernel32_lib_dir);
7982 }
8083
8184 for (size_t i = 0; i < zig_libc_keys_len; i += 1) {
......@@ -110,6 +113,15 @@ Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget
110113 }
111114 }
112115
116 if (buf_len(&libc->static_crt_dir) == 0) {
117 if (target->os == OsWindows && target_abi_is_gnu(target->abi)) {
118 if (verbose) {
119 fprintf(stderr, "static_crt_dir may not be empty for %s\n", target_os_name(target->os));
120 }
121 return ErrorSemanticAnalyzeFail;
122 }
123 }
124
113125 if (buf_len(&libc->msvc_lib_dir) == 0) {
114126 if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) {
115127 if (verbose) {
......@@ -310,6 +322,10 @@ static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool
310322}
311323#endif
312324
325static Error zig_libc_find_native_static_crt_dir_posix(ZigLibCInstallation *self, bool verbose) {
326 return zig_libc_cc_print_file_name("crtbegin.o", &self->static_crt_dir, true, verbose);
327}
328
313329#if defined(ZIG_OS_WINDOWS)
314330static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
315331 Error err;
......@@ -322,7 +338,7 @@ static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self,
322338 return ErrorNone;
323339}
324340
325static Error zig_libc_find_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
341static Error zig_libc_find_native_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
326342 bool verbose)
327343{
328344 Error err;
......@@ -398,11 +414,16 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file) {
398414 "# On POSIX it's the directory that includes `sys/errno.h`.\n"
399415 "sys_include_dir=%s\n"
400416 "\n"
401 "# The directory that contains `crt1.o`.\n"
417 "# The directory that contains `crt1.o` or `crt2.o`.\n"
402418 "# On POSIX, can be found with `cc -print-file-name=crt1.o`.\n"
403419 "# Not needed when targeting MacOS.\n"
404420 "crt_dir=%s\n"
405421 "\n"
422 "# The directory that contains `crtbegin.o`.\n"
423 "# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.\n"
424 "# Not needed when targeting MacOS.\n"
425 "static_crt_dir=%s\n"
426 "\n"
406427 "# The directory that contains `vcruntime.lib`.\n"
407428 "# Only needed when targeting MSVC on Windows.\n"
408429 "msvc_lib_dir=%s\n"
......@@ -415,6 +436,7 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file) {
415436 buf_ptr(&self->include_dir),
416437 buf_ptr(&self->sys_include_dir),
417438 buf_ptr(&self->crt_dir),
439 buf_ptr(&self->static_crt_dir),
418440 buf_ptr(&self->msvc_lib_dir),
419441 buf_ptr(&self->kernel32_lib_dir)
420442 );
......@@ -431,6 +453,8 @@ Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) {
431453 return err;
432454 if ((err = zig_libc_find_native_crt_dir_posix(self, verbose)))
433455 return err;
456 if ((err = zig_libc_find_native_static_crt_dir_posix(self, verbose)))
457 return err;
434458 return ErrorNone;
435459 } else {
436460 ZigWindowsSDK *sdk;
......@@ -444,7 +468,7 @@ Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) {
444468 return err;
445469 if ((err = zig_libc_find_native_include_dir_windows(self, sdk, verbose)))
446470 return err;
447 if ((err = zig_libc_find_crt_dir_windows(self, sdk, &native_target, verbose)))
471 if ((err = zig_libc_find_native_crt_dir_windows(self, sdk, &native_target, verbose)))
448472 return err;
449473 return ErrorNone;
450474 case ZigFindWindowsSdkErrorOutOfMemory:
src/libc_installation.hpp+1-2
......@@ -19,6 +19,7 @@ struct ZigLibCInstallation {
1919 Buf include_dir;
2020 Buf sys_include_dir;
2121 Buf crt_dir;
22 Buf static_crt_dir;
2223 Buf msvc_lib_dir;
2324 Buf kernel32_lib_dir;
2425};
......@@ -29,8 +30,6 @@ void zig_libc_render(ZigLibCInstallation *self, FILE *file);
2930
3031Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose);
3132
32#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_WINDOWS)
3333Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose);
34#endif
3534
3635#endif
src/link.cpp+154-81
......@@ -1137,53 +1137,121 @@ static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, si
11371137}
11381138
11391139static void add_uefi_link_args(LinkJob *lj) {
1140 lj->args.append("/BASE:0");
1141 lj->args.append("/ENTRY:EfiMain");
1142 lj->args.append("/OPT:REF");
1143 lj->args.append("/SAFESEH:NO");
1144 lj->args.append("/MERGE:.rdata=.data");
1145 lj->args.append("/ALIGN:32");
1146 lj->args.append("/NODEFAULTLIB");
1147 lj->args.append("/SECTION:.xdata,D");
1140 lj->args.append("-BASE:0");
1141 lj->args.append("-ENTRY:EfiMain");
1142 lj->args.append("-OPT:REF");
1143 lj->args.append("-SAFESEH:NO");
1144 lj->args.append("-MERGE:.rdata=.data");
1145 lj->args.append("-ALIGN:32");
1146 lj->args.append("-NODEFAULTLIB");
1147 lj->args.append("-SECTION:.xdata,D");
11481148}
11491149
1150static void add_nt_link_args(LinkJob *lj, bool is_library) {
1150static void add_msvc_link_args(LinkJob *lj, bool is_library) {
11511151 CodeGen *g = lj->codegen;
11521152
1153 if (lj->link_in_crt) {
1154 // TODO: https://github.com/ziglang/zig/issues/2064
1155 bool is_dynamic = true; // g->is_dynamic;
1156 const char *lib_str = is_dynamic ? "" : "lib";
1157 const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : "";
1158
1159 if (!is_dynamic) {
1160 Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str);
1161 lj->args.append(buf_ptr(cmt_lib_name));
1162 } else {
1163 Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str);
1164 lj->args.append(buf_ptr(msvcrt_lib_name));
1165 }
1153 // TODO: https://github.com/ziglang/zig/issues/2064
1154 bool is_dynamic = true; // g->is_dynamic;
1155 const char *lib_str = is_dynamic ? "" : "lib";
1156 const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : "";
1157
1158 if (!is_dynamic) {
1159 Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str);
1160 lj->args.append(buf_ptr(cmt_lib_name));
1161 } else {
1162 Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str);
1163 lj->args.append(buf_ptr(msvcrt_lib_name));
1164 }
1165
1166 Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str);
1167 lj->args.append(buf_ptr(vcruntime_lib_name));
1168
1169 Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str);
1170 lj->args.append(buf_ptr(crt_lib_name));
1171
1172 //Visual C++ 2015 Conformance Changes
1173 //https://msdn.microsoft.com/en-us/library/bb531344.aspx
1174 lj->args.append("legacy_stdio_definitions.lib");
1175
1176 // msvcrt depends on kernel32 and ntdll
1177 lj->args.append("kernel32.lib");
1178 lj->args.append("ntdll.lib");
1179}
11661180
1167 Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str);
1168 lj->args.append(buf_ptr(vcruntime_lib_name));
1181static const char *get_libc_file(ZigLibCInstallation *lib, const char *file) {
1182 Buf *out_buf = buf_alloc();
1183 os_path_join(&lib->crt_dir, buf_create_from_str(file), out_buf);
1184 return buf_ptr(out_buf);
1185}
1186
1187static const char *get_libc_static_file(ZigLibCInstallation *lib, const char *file) {
1188 Buf *out_buf = buf_alloc();
1189 os_path_join(&lib->static_crt_dir, buf_create_from_str(file), out_buf);
1190 return buf_ptr(out_buf);
1191}
11691192
1170 Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str);
1171 lj->args.append(buf_ptr(crt_lib_name));
1193static void add_mingw_link_args(LinkJob *lj, bool is_library) {
1194 CodeGen *g = lj->codegen;
11721195
1173 //Visual C++ 2015 Conformance Changes
1174 //https://msdn.microsoft.com/en-us/library/bb531344.aspx
1175 lj->args.append("legacy_stdio_definitions.lib");
1196 bool is_dll = g->out_type == OutTypeLib && g->is_dynamic;
11761197
1177 // msvcrt depends on kernel32 and ntdll
1178 lj->args.append("kernel32.lib");
1179 lj->args.append("ntdll.lib");
1198 if (g->zig_target->arch == ZigLLVM_x86) {
1199 lj->args.append("-ALTERNATENAME:__image_base__=___ImageBase");
11801200 } else {
1181 lj->args.append("/NODEFAULTLIB");
1201 lj->args.append("-ALTERNATENAME:__image_base__=__ImageBase");
1202 }
1203
1204 if (is_dll) {
1205 lj->args.append(get_libc_file(g->libc, "dllcrt2.o"));
1206 } else {
1207 lj->args.append(get_libc_file(g->libc, "crt2.o"));
1208 }
1209
1210 lj->args.append(get_libc_static_file(g->libc, "crtbegin.o"));
1211
1212 lj->args.append(get_libc_file(g->libc, "libmingw32.a"));
1213
1214 if (is_dll) {
1215 lj->args.append(get_libc_static_file(g->libc, "libgcc_s.a"));
1216 lj->args.append(get_libc_static_file(g->libc, "libgcc.a"));
1217 } else {
1218 lj->args.append(get_libc_static_file(g->libc, "libgcc.a"));
1219 lj->args.append(get_libc_static_file(g->libc, "libgcc_eh.a"));
1220 }
1221
1222 lj->args.append(get_libc_static_file(g->libc, "libssp.a"));
1223 lj->args.append(get_libc_file(g->libc, "libmoldname.a"));
1224 lj->args.append(get_libc_file(g->libc, "libmingwex.a"));
1225 lj->args.append(get_libc_file(g->libc, "libmsvcrt.a"));
1226
1227 if (g->subsystem == TargetSubsystemWindows) {
1228 lj->args.append(get_libc_file(g->libc, "libgdi32.a"));
1229 lj->args.append(get_libc_file(g->libc, "libcomdlg32.a"));
1230 }
1231
1232 lj->args.append(get_libc_file(g->libc, "libadvapi32.a"));
1233 lj->args.append(get_libc_file(g->libc, "libadvapi32.a"));
1234 lj->args.append(get_libc_file(g->libc, "libshell32.a"));
1235 lj->args.append(get_libc_file(g->libc, "libuser32.a"));
1236 lj->args.append(get_libc_file(g->libc, "libkernel32.a"));
1237
1238 lj->args.append(get_libc_static_file(g->libc, "crtend.o"));
1239}
1240
1241static void add_win_link_args(LinkJob *lj, bool is_library) {
1242 if (lj->link_in_crt) {
1243 if (target_abi_is_gnu(lj->codegen->zig_target->abi)) {
1244 add_mingw_link_args(lj, is_library);
1245 } else {
1246 add_msvc_link_args(lj, is_library);
1247 }
1248 } else {
1249 lj->args.append("-NODEFAULTLIB");
11821250 if (!is_library) {
1183 if (g->have_winmain) {
1184 lj->args.append("/ENTRY:WinMain");
1251 if (lj->codegen->have_winmain) {
1252 lj->args.append("-ENTRY:WinMain");
11851253 } else {
1186 lj->args.append("/ENTRY:WinMainCRTStartup");
1254 lj->args.append("-ENTRY:WinMainCRTStartup");
11871255 }
11881256 }
11891257 }
......@@ -1193,87 +1261,93 @@ static void construct_linker_job_coff(LinkJob *lj) {
11931261 Error err;
11941262 CodeGen *g = lj->codegen;
11951263
1196 lj->args.append("/ERRORLIMIT:0");
1264 lj->args.append("-ERRORLIMIT:0");
11971265
1198 lj->args.append("/NOLOGO");
1266 lj->args.append("-NOLOGO");
11991267
12001268 if (!g->strip_debug_symbols) {
1201 lj->args.append("/DEBUG");
1269 lj->args.append("-DEBUG");
12021270 }
12031271
12041272 if (g->out_type == OutTypeExe) {
12051273 // TODO compile time stack upper bound detection
1206 lj->args.append("/STACK:16777216");
1274 lj->args.append("-STACK:16777216");
12071275 }
12081276
12091277 coff_append_machine_arg(g, &lj->args);
12101278
12111279 bool is_library = g->out_type == OutTypeLib;
1280 if (is_library && g->is_dynamic) {
1281 lj->args.append("-DLL");
1282 }
1283
1284 lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
1285
1286 if (g->libc_link_lib != nullptr) {
1287 assert(g->libc != nullptr);
1288
1289 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir))));
1290
1291 if (target_abi_is_gnu(g->zig_target->abi)) {
1292 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->sys_include_dir))));
1293 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->include_dir))));
1294 } else {
1295 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir))));
1296 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir))));
1297 }
1298 }
1299
1300 for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
1301 const char *lib_dir = g->lib_dirs.at(i);
1302 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));
1303 }
1304
1305 for (size_t i = 0; i < g->link_objects.length; i += 1) {
1306 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
1307 }
1308
12121309 switch (g->subsystem) {
12131310 case TargetSubsystemAuto:
12141311 if (g->zig_target->os == OsUefi) {
12151312 add_uefi_link_args(lj);
12161313 } else {
1217 add_nt_link_args(lj, is_library);
1314 add_win_link_args(lj, is_library);
12181315 }
12191316 break;
12201317 case TargetSubsystemConsole:
1221 lj->args.append("/SUBSYSTEM:console");
1222 add_nt_link_args(lj, is_library);
1318 lj->args.append("-SUBSYSTEM:console");
1319 add_win_link_args(lj, is_library);
12231320 break;
12241321 case TargetSubsystemEfiApplication:
1225 lj->args.append("/SUBSYSTEM:efi_application");
1322 lj->args.append("-SUBSYSTEM:efi_application");
12261323 add_uefi_link_args(lj);
12271324 break;
12281325 case TargetSubsystemEfiBootServiceDriver:
1229 lj->args.append("/SUBSYSTEM:efi_boot_service_driver");
1326 lj->args.append("-SUBSYSTEM:efi_boot_service_driver");
12301327 add_uefi_link_args(lj);
12311328 break;
12321329 case TargetSubsystemEfiRom:
1233 lj->args.append("/SUBSYSTEM:efi_rom");
1330 lj->args.append("-SUBSYSTEM:efi_rom");
12341331 add_uefi_link_args(lj);
12351332 break;
12361333 case TargetSubsystemEfiRuntimeDriver:
1237 lj->args.append("/SUBSYSTEM:efi_runtime_driver");
1334 lj->args.append("-SUBSYSTEM:efi_runtime_driver");
12381335 add_uefi_link_args(lj);
12391336 break;
12401337 case TargetSubsystemNative:
1241 lj->args.append("/SUBSYSTEM:native");
1242 add_nt_link_args(lj, is_library);
1338 lj->args.append("-SUBSYSTEM:native");
1339 add_win_link_args(lj, is_library);
12431340 break;
12441341 case TargetSubsystemPosix:
1245 lj->args.append("/SUBSYSTEM:posix");
1246 add_nt_link_args(lj, is_library);
1342 lj->args.append("-SUBSYSTEM:posix");
1343 add_win_link_args(lj, is_library);
12471344 break;
12481345 case TargetSubsystemWindows:
1249 lj->args.append("/SUBSYSTEM:windows");
1250 add_nt_link_args(lj, is_library);
1346 lj->args.append("-SUBSYSTEM:windows");
1347 add_win_link_args(lj, is_library);
12511348 break;
12521349 }
12531350
1254 lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
1255
1256 if (g->libc_link_lib != nullptr) {
1257 assert(g->libc != nullptr);
1258
1259 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir))));
1260 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir))));
1261 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir))));
1262 }
1263
1264 if (is_library && g->is_dynamic) {
1265 lj->args.append("-DLL");
1266 }
1267
1268 for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
1269 const char *lib_dir = g->lib_dirs.at(i);
1270 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));
1271 }
1272
1273 for (size_t i = 0; i < g->link_objects.length; i += 1) {
1274 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
1275 }
1276
12771351 if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) {
12781352 if (g->libc_link_lib == nullptr && !g->is_dummy_so) {
12791353 Buf *builtin_a_path = build_a(g, "builtin");
......@@ -1293,11 +1367,10 @@ static void construct_linker_job_coff(LinkJob *lj) {
12931367 continue;
12941368 }
12951369 if (link_lib->provided_explicitly) {
1296 if (lj->codegen->zig_target->abi == ZigLLVM_GNU) {
1297 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
1298 lj->args.append(buf_ptr(arg));
1299 }
1300 else {
1370 if (target_abi_is_gnu(lj->codegen->zig_target->abi)) {
1371 Buf *lib_name = buf_sprintf("lib%s.a", buf_ptr(link_lib->name));
1372 lj->args.append(buf_ptr(lib_name));
1373 } else {
13011374 lj->args.append(buf_ptr(link_lib->name));
13021375 }
13031376 } else {