authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-15 20:56:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-15 20:56:52-07:00
log984e7d6cc79df0a1dec4cc9ae37e899376a5f641
tree47dd9effd4306cc8f9dad277e08fe00267ac506a
parentf580c7fa4330a0c181226060d2e778285fa38dc0

first pass at linking on macos


7 files changed, 357 insertions(+), 31 deletions(-)

CMakeLists.txt+21
......@@ -144,6 +144,27 @@ set(ZIG_STD_SRC
144144 "${CMAKE_SOURCE_DIR}/std/math.zig"
145145)
146146
147
148set(ZIG_HOST_LINK_VERSION)
149if (APPLE)
150 set(LD_V_OUTPUT)
151 execute_process(
152 COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1"
153 RESULT_VARIABLE HAD_ERROR
154 OUTPUT_VARIABLE LD_V_OUTPUT
155 )
156 if (NOT HAD_ERROR)
157 if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*")
158 string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" ZIG_HOST_LINK_VERSION ${LD_V_OUTPUT})
159 elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*")
160 string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" ZIG_HOST_LINK_VERSION ${LD_V_OUTPUT})
161 endif()
162 else()
163 message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}")
164 endif()
165endif()
166
167
147168set(C_HEADERS_DEST "lib/zig/include")
148169set(ZIG_STD_DEST "lib/zig/std")
149170set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
src/all_types.hpp+4
......@@ -1130,6 +1130,10 @@ struct CodeGen {
11301130 bool windows_subsystem_windows;
11311131 bool windows_subsystem_console;
11321132 bool windows_linker_unicode;
1133 Buf *darwin_linker_version;
1134 Buf *mmacosx_version_min;
1135 Buf *mios_version_min;
1136 bool linker_rdynamic;
11331137
11341138 // The function definitions this module includes. There must be a corresponding
11351139 // fn_protos entry.
src/codegen.cpp+51
......@@ -22,6 +22,31 @@
2222#include <errno.h>
2323
2424
25static void init_darwin_native(CodeGen *g) {
26 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
27 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
28
29 // Allow conflicts among OSX and iOS, but choose the default platform.
30 if (osx_target && ios_target) {
31 if (g->zig_target.arch.arch == ZigLLVM_arm ||
32 g->zig_target.arch.arch == ZigLLVM_aarch64 ||
33 g->zig_target.arch.arch == ZigLLVM_thumb)
34 {
35 osx_target = nullptr;
36 } else {
37 ios_target = nullptr;
38 }
39 }
40
41 if (osx_target) {
42 g->mmacosx_version_min = buf_create_from_str(osx_target);
43 } else if (ios_target) {
44 g->mios_version_min = buf_create_from_str(ios_target);
45 } else {
46 zig_panic("unable to determine -mmacosx-version-min or -mios-version-min");
47 }
48}
49
2550CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
2651 CodeGen *g = allocate<CodeGen>(1);
2752 g->import_table.init(32);
......@@ -46,6 +71,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
4671 g->libc_static_lib_dir = buf_create_from_str("");
4772 g->libc_include_dir = buf_create_from_str("");
4873 g->linker_path = buf_create_from_str("");
74 g->darwin_linker_version = buf_create_from_str("");
4975 } else {
5076 // native compilation, we can rely on the configuration stuff
5177 g->is_native_target = true;
......@@ -56,6 +82,15 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
5682 g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);
5783 g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);
5884 g->linker_path = buf_create_from_str(ZIG_LD_PATH);
85 g->darwin_linker_version = buf_create_from_str(ZIG_HOST_LINK_VERSION);
86
87 if (g->zig_target.os == ZigLLVM_Darwin ||
88 g->zig_target.os == ZigLLVM_MacOSX ||
89 g->zig_target.os == ZigLLVM_IOS)
90 {
91 init_darwin_native(g);
92 }
93
5994 }
6095
6196 return g;
......@@ -131,6 +166,22 @@ void codegen_set_windows_unicode(CodeGen *g, bool municode) {
131166 g->windows_linker_unicode = municode;
132167}
133168
169void codegen_set_mlinker_version(CodeGen *g, Buf *darwin_linker_version) {
170 g->darwin_linker_version = darwin_linker_version;
171}
172
173void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min) {
174 g->mmacosx_version_min = mmacosx_version_min;
175}
176
177void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min) {
178 g->mios_version_min = mios_version_min;
179}
180
181void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
182 g->linker_rdynamic = rdynamic;
183}
184
134185static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
135186static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);
136187static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);
src/codegen.hpp+4
......@@ -34,6 +34,10 @@ void codegen_set_linker_path(CodeGen *g, Buf *linker_path);
3434void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
3535void codegen_set_windows_unicode(CodeGen *g, bool municode);
3636void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
37void codegen_set_mlinker_version(CodeGen *g, Buf *darwin_linker_version);
38void codegen_set_rdynamic(CodeGen *g, bool rdynamic);
39void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);
40void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min);
3741
3842void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);
3943
src/config.h.in+1
......@@ -13,6 +13,7 @@
1313#define ZIG_LIBC_STATIC_LIB_DIR "@ZIG_LIBC_STATIC_LIB_DIR@"
1414#define ZIG_LD_PATH "@ZIG_LD_PATH@"
1515#define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@"
16#define ZIG_HOST_LINK_VERSION "@ZIG_HOST_LINK_VERSION@"
1617
1718#cmakedefine ZIG_LLVM_OLD_CXX_ABI
1819
src/link.cpp+242-27
......@@ -50,6 +50,9 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
5050 codegen_set_verbose(child_gen, parent_gen->verbose);
5151 codegen_set_errmsg_color(child_gen, parent_gen->err_color);
5252
53 codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min);
54 codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min);
55
5356 Buf *full_path = buf_alloc();
5457 os_path_join(std_dir_path, source_basename, full_path);
5558 Buf source_code = BUF_INIT;
......@@ -391,38 +394,251 @@ static void construct_linker_job_mingw(LinkJob *lj) {
391394 }
392395}
393396
397
398// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
399// grouped values as integers. Numbers which are not provided are set to 0.
400// return true if the entire string was parsed (9.2), or all groups were
401// parsed (10.3.5extrastuff).
402static bool darwin_get_release_version(const char *str, int *major, int *minor, int *micro, bool *had_extra) {
403 *had_extra = false;
404
405 *major = 0;
406 *minor = 0;
407 *micro = 0;
408
409 if (*str == '\0')
410 return false;
411
412 char *end;
413 *major = strtol(str, &end, 10);
414 if (*str != '\0' && *end == '\0')
415 return true;
416 if (*end != '.')
417 return false;
418
419 str = end + 1;
420 *minor = strtol(str, &end, 10);
421 if (*str != '\0' && *end == '\0')
422 return true;
423 if (*end != '.')
424 return false;
425
426 str = end + 1;
427 *micro = strtol(str, &end, 10);
428 if (*str != '\0' && *end == '\0')
429 return true;
430 if (str == end)
431 return false;
432 *had_extra = true;
433 return true;
434}
435
436enum DarwinPlatformKind {
437 MacOS,
438 IPhoneOS,
439 IPhoneOSSimulator,
440};
441
442struct DarwinPlatform {
443 DarwinPlatformKind kind;
444 int major;
445 int minor;
446 int micro;
447};
448
449static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
450 CodeGen *g = lj->codegen;
451
452 if (g->mmacosx_version_min) {
453 platform->kind = MacOS;
454 } else if (g->mios_version_min) {
455 platform->kind = IPhoneOS;
456 } else {
457 zig_panic("unable to infer -macosx-version-min or -mios-version-min");
458 }
459
460 bool had_extra;
461 if (platform->kind == MacOS) {
462 if (!darwin_get_release_version(buf_ptr(g->mmacosx_version_min),
463 &platform->major, &platform->minor, &platform->micro, &had_extra) ||
464 had_extra || platform->major != 10 || platform->minor >= 100 || platform->micro >= 100)
465 {
466 zig_panic("invalid -mmacosx-version-min");
467 }
468 } else if (platform->kind == IPhoneOS) {
469 if (!darwin_get_release_version(buf_ptr(g->mios_version_min),
470 &platform->major, &platform->minor, &platform->micro, &had_extra) ||
471 had_extra || platform->major >= 10 || platform->minor >= 100 || platform->micro >= 100)
472 {
473 zig_panic("invalid -mios-version-min");
474 }
475 } else {
476 zig_unreachable();
477 }
478
479 if (platform->kind == IPhoneOS &&
480 (g->zig_target.arch.arch == ZigLLVM_x86 ||
481 g->zig_target.arch.arch == ZigLLVM_x86_64))
482 {
483 platform->kind = IPhoneOSSimulator;
484 }
485}
486
487static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) {
488 if (platform->major < major) {
489 return true;
490 } else if (platform->major > major) {
491 return false;
492 }
493 if (platform->minor < minor) {
494 return true;
495 }
496 return false;
497}
498
499static void construct_linker_job_darwin(LinkJob *lj) {
500 CodeGen *g = lj->codegen;
501
502 int ver_major;
503 int ver_minor;
504 int ver_micro;
505 bool had_extra;
506
507 if (!darwin_get_release_version(buf_ptr(g->darwin_linker_version), &ver_major, &ver_minor, &ver_micro,
508 &had_extra) || had_extra)
509 {
510 zig_panic("invalid linker version number");
511 }
512
513 // Newer linkers support -demangle. Pass it if supported and not disabled by
514 // the user.
515 if (ver_major >= 100) {
516 lj->args.append("-demangle");
517 }
518
519 if (g->linker_rdynamic && ver_major >= 137) {
520 lj->args.append("-export_dynamic");
521 }
522
523 bool is_lib = g->out_type == OutTypeLib;
524 bool shared = !g->is_static && is_lib;
525 if (g->is_static) {
526 lj->args.append("-static");
527 } else {
528 lj->args.append("-dynamic");
529 }
530
531 if (is_lib) {
532 zig_panic("TODO linker args on darwin for making a library");
533 }
534
535 DarwinPlatform platform;
536 get_darwin_platform(lj, &platform);
537 switch (platform.kind) {
538 case MacOS:
539 lj->args.append("-macosx_version_min");
540 break;
541 case IPhoneOS:
542 lj->args.append("-iphoneos_version_min");
543 break;
544 case IPhoneOSSimulator:
545 lj->args.append("-ios_simulator_version_min");
546 break;
547 }
548 lj->args.append(buf_ptr(buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro)));
549
550
551 if (g->out_type == OutTypeExe) {
552 if (g->is_static) {
553 lj->args.append("-no_pie");
554 } else {
555 lj->args.append("-pie");
556 }
557 }
558
559 lj->args.append("-o");
560 lj->args.append(buf_ptr(&lj->out_file));
561
562 if (lj->link_in_crt) {
563 if (shared) {
564 zig_panic("TODO");
565 } else if (g->is_static) {
566 lj->args.append("-lcrt0.o");
567 } else {
568 switch (platform.kind) {
569 case MacOS:
570 if (darwin_version_lt(&platform, 10, 5)) {
571 lj->args.append("-lcrt1.o");
572 } else if (darwin_version_lt(&platform, 10, 6)) {
573 lj->args.append("-lcrt1.10.5.o");
574 } else if (darwin_version_lt(&platform, 10, 8)) {
575 lj->args.append("-lcrt1.10.6.o");
576 }
577 break;
578 case IPhoneOS:
579 if (g->zig_target.arch.arch == ZigLLVM_aarch64) {
580 // iOS does not need any crt1 files for arm64
581 } else if (darwin_version_lt(&platform, 3, 1)) {
582 lj->args.append("-lcrt1.o");
583 } else if (darwin_version_lt(&platform, 6, 0)) {
584 lj->args.append("-lcrt1.3.1.o");
585 }
586 break;
587 case IPhoneOSSimulator:
588 // no crt1.o needed
589 break;
590 }
591 }
592 }
593
594 for (int i = 0; i < g->lib_dirs.length; i += 1) {
595 const char *lib_dir = g->lib_dirs.at(i);
596 lj->args.append("-L");
597 lj->args.append(lib_dir);
598 }
599
600 lj->args.append((const char *)buf_ptr(&lj->out_file_o));
601
602 for (int i = 0; i < g->link_libs.length; i += 1) {
603 Buf *link_lib = g->link_libs.at(i);
604 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));
605 lj->args.append(buf_ptr(arg));
606 }
607
608}
609
394610static void construct_linker_job(LinkJob *lj) {
395611 switch (lj->codegen->zig_target.os) {
396612 case ZigLLVM_UnknownOS:
397 zig_unreachable();
613 zig_unreachable();
398614 case ZigLLVM_Linux:
399 if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
615 if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
400616 zig_panic("TODO construct hexagon_TC linker job");
401 } else {
617 } else {
402618 return construct_linker_job_linux(lj);
403 }
619 }
404620 case ZigLLVM_CloudABI:
405 zig_panic("TODO construct CloudABI linker job");
621 zig_panic("TODO construct CloudABI linker job");
406622 case ZigLLVM_Darwin:
407623 case ZigLLVM_MacOSX:
408624 case ZigLLVM_IOS:
409 zig_panic("TODO construct DarwinClang linker job");
625 return construct_linker_job_darwin(lj);
410626 case ZigLLVM_DragonFly:
411 zig_panic("TODO construct DragonFly linker job");
627 zig_panic("TODO construct DragonFly linker job");
412628 case ZigLLVM_OpenBSD:
413 zig_panic("TODO construct OpenBSD linker job");
629 zig_panic("TODO construct OpenBSD linker job");
414630 case ZigLLVM_Bitrig:
415 zig_panic("TODO construct Bitrig linker job");
631 zig_panic("TODO construct Bitrig linker job");
416632 case ZigLLVM_NetBSD:
417 zig_panic("TODO construct NetBSD linker job");
633 zig_panic("TODO construct NetBSD linker job");
418634 case ZigLLVM_FreeBSD:
419 zig_panic("TODO construct FreeBSD linker job");
635 zig_panic("TODO construct FreeBSD linker job");
420636 case ZigLLVM_Minix:
421 zig_panic("TODO construct Minix linker job");
637 zig_panic("TODO construct Minix linker job");
422638 case ZigLLVM_NaCl:
423 zig_panic("TODO construct NaCl_TC linker job");
639 zig_panic("TODO construct NaCl_TC linker job");
424640 case ZigLLVM_Solaris:
425 zig_panic("TODO construct Solaris linker job");
641 zig_panic("TODO construct Solaris linker job");
426642 case ZigLLVM_Win32:
427643 switch (lj->codegen->zig_target.environ) {
428644 default:
......@@ -440,27 +656,27 @@ static void construct_linker_job(LinkJob *lj) {
440656 case ZigLLVM_MSVC:
441657 case ZigLLVM_UnknownEnvironment:
442658 zig_panic("TODO construct MSVC linker job");
443 }
659 }
444660 case ZigLLVM_CUDA:
445 zig_panic("TODO construct Cuda linker job");
661 zig_panic("TODO construct Cuda linker job");
446662 default:
447 // Of these targets, Hexagon is the only one that might have
448 // an OS of Linux, in which case it got handled above already.
449 if (lj->codegen->zig_target.arch.arch == ZigLLVM_tce) {
663 // Of these targets, Hexagon is the only one that might have
664 // an OS of Linux, in which case it got handled above already.
665 if (lj->codegen->zig_target.arch.arch == ZigLLVM_tce) {
450666 zig_panic("TODO construct TCE linker job");
451 } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
667 } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_hexagon) {
452668 zig_panic("TODO construct Hexagon_TC linker job");
453 } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_xcore) {
669 } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_xcore) {
454670 zig_panic("TODO construct XCore linker job");
455 } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_shave) {
671 } else if (lj->codegen->zig_target.arch.arch == ZigLLVM_shave) {
456672 zig_panic("TODO construct SHAVE linker job");
457 } else if (lj->codegen->zig_target.oformat == ZigLLVM_ELF) {
673 } else if (lj->codegen->zig_target.oformat == ZigLLVM_ELF) {
458674 zig_panic("TODO construct Generic_ELF linker job");
459 } else if (lj->codegen->zig_target.oformat == ZigLLVM_MachO) {
675 } else if (lj->codegen->zig_target.oformat == ZigLLVM_MachO) {
460676 zig_panic("TODO construct MachO linker job");
461 } else {
677 } else {
462678 zig_panic("TODO construct Generic_GCC linker job");
463 }
679 }
464680
465681 }
466682}
......@@ -535,7 +751,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
535751 }
536752
537753 lj.link_in_crt = (g->link_libc && g->out_type == OutTypeExe);
538 // invoke `ld`
539754 ensure_we_have_linker_path(g);
540755
541756 construct_linker_job(&lj);
src/main.cpp+34-4
......@@ -18,10 +18,10 @@
1818static int usage(const char *arg0) {
1919 fprintf(stderr, "Usage: %s [command] [options]\n"
2020 "Commands:\n"
21 " build create executable, object, or library from target\n"
22 " test create and run a test build\n"
21 " build [source] create executable, object, or library from source\n"
22 " test [source] create and run a test build\n"
23 " parseh [source] convert a c header file to zig extern declarations\n"
2324 " version print version number and exit\n"
24 " parseh convert a c header file to zig extern declarations\n"
2525 " targets list available compilation targets\n"
2626 "Options:\n"
2727 " --release build with optimizations on and debug protection off\n"
......@@ -33,7 +33,7 @@ static int usage(const char *arg0) {
3333 " --verbose turn on compiler debug output\n"
3434 " --color [auto|off|on] enable or disable colored error messages\n"
3535 " --libc-lib-dir [path] directory where libc crt1.o resides\n"
36 " --libc-static-lib-dir [path] directory where libc crtbeginT.o resides\n"
36 " --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n"
3737 " --libc-include-dir [path] directory where libc stdlib.h resides\n"
3838 " --dynamic-linker [path] set the path to ld.so\n"
3939 " --ld-path [path] set the path to the linker\n"
......@@ -46,6 +46,10 @@ static int usage(const char *arg0) {
4646 " -mwindows (windows only) --subsystem windows to the linker\n"
4747 " -mconsole (windows only) --subsystem console to the linker\n"
4848 " -municode (windows only) link with unicode\n"
49 " -mlinker-version [ver] (darwin only) override linker version\n"
50 " -rdynamic add all symbols to the dynamic symbol table\n"
51 " -mmacosx-version-min [ver] (darwin only) set Mac OS X deployment target\n"
52 " -mios-version-min [ver] (darwin only) set iOS deployment target\n"
4953 , arg0);
5054 return EXIT_FAILURE;
5155}
......@@ -119,6 +123,10 @@ int main(int argc, char **argv) {
119123 bool mwindows = false;
120124 bool mconsole = false;
121125 bool municode = false;
126 const char *mlinker_version = nullptr;
127 bool rdynamic = false;
128 const char *mmacosx_version_min = nullptr;
129 const char *mios_version_min = nullptr;
122130
123131 for (int i = 1; i < argc; i += 1) {
124132 char *arg = argv[i];
......@@ -138,6 +146,8 @@ int main(int argc, char **argv) {
138146 mconsole = true;
139147 } else if (strcmp(arg, "-municode") == 0) {
140148 municode = true;
149 } else if (strcmp(arg, "-rdynamic") == 0) {
150 rdynamic = true;
141151 } else if (i + 1 >= argc) {
142152 return usage(arg0);
143153 } else {
......@@ -192,6 +202,12 @@ int main(int argc, char **argv) {
192202 target_os = argv[i];
193203 } else if (strcmp(arg, "--target-environ") == 0) {
194204 target_environ = argv[i];
205 } else if (strcmp(arg, "-mlinker-version") == 0) {
206 mlinker_version = argv[i];
207 } else if (strcmp(arg, "-mmacosx-version-min") == 0) {
208 mmacosx_version_min = argv[i];
209 } else if (strcmp(arg, "-mios-version-min") == 0) {
210 mios_version_min = argv[i];
195211 } else {
196212 fprintf(stderr, "Invalid argument: %s\n", arg);
197213 return usage(arg0);
......@@ -327,6 +343,20 @@ int main(int argc, char **argv) {
327343
328344 codegen_set_windows_subsystem(g, mwindows, mconsole);
329345 codegen_set_windows_unicode(g, municode);
346 codegen_set_rdynamic(g, rdynamic);
347 if (mlinker_version) {
348 codegen_set_mlinker_version(g, buf_create_from_str(mlinker_version));
349 }
350 if (mmacosx_version_min && mios_version_min) {
351 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
352 return EXIT_FAILURE;
353 }
354 if (mmacosx_version_min) {
355 codegen_set_mmacosx_version_min(g, buf_create_from_str(mmacosx_version_min));
356 }
357 if (mios_version_min) {
358 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
359 }
330360
331361 if (cmd == CmdBuild) {
332362 codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);