Commit 5314641e11

Andrew Kelley <andrew@ziglang.org>
2020-04-02 23:29:22
zig cc: support more linker args
1 parent c1778bd
src/all_types.hpp
@@ -2015,6 +2015,12 @@ enum WantCSanitize {
     WantCSanitizeEnabled,
 };
 
+enum OptionalBool {
+    OptionalBoolNull,
+    OptionalBoolFalse,
+    OptionalBoolTrue,
+};
+
 struct CFile {
     ZigList<const char *> args;
     const char *source_path;
@@ -2260,6 +2266,8 @@ struct CodeGen {
     TargetSubsystem subsystem; // careful using this directly; see detect_subsystem
     ValgrindSupport valgrind_support;
     CodeModel code_model;
+    OptionalBool linker_gc_sections;
+    OptionalBool linker_allow_shlib_undefined;
     bool strip_debug_symbols;
     bool is_test_build;
     bool is_single_threaded;
@@ -2280,6 +2288,8 @@ struct CodeGen {
     bool emit_asm;
     bool emit_llvm_ir;
     bool test_is_evented;
+    bool linker_z_nodelete;
+    bool linker_z_defs;
 
     Buf *root_out_name;
     Buf *test_filter;
@@ -2288,6 +2298,7 @@ struct CodeGen {
     Buf *zig_std_dir;
     Buf *version_script_path;
     Buf *override_soname;
+    Buf *linker_optimization;
 
     const char **llvm_argv;
     size_t llvm_argv_len;
src/codegen.cpp
@@ -10558,6 +10558,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
     }
     cache_buf_opt(ch, g->version_script_path);
     cache_buf_opt(ch, g->override_soname);
+    cache_buf_opt(ch, g->linker_optimization);
+    cache_int(ch, g->linker_gc_sections);
+    cache_int(ch, g->linker_allow_shlib_undefined);
+    cache_bool(ch, g->linker_z_nodelete);
+    cache_bool(ch, g->linker_z_defs);
 
     // gen_c_objects appends objects to g->link_objects which we want to include in the hash
     gen_c_objects(g);
src/link.cpp
@@ -1769,8 +1769,17 @@ static void construct_linker_job_elf(LinkJob *lj) {
         lj->args.append(g->linker_script);
     }
 
-    if (g->out_type != OutTypeObj) {
-        lj->args.append("--gc-sections");
+    switch (g->linker_gc_sections) {
+        case OptionalBoolNull:
+            if (g->out_type != OutTypeObj) {
+                lj->args.append("--gc-sections");
+            }
+            break;
+        case OptionalBoolTrue:
+            lj->args.append("--gc-sections");
+            break;
+        case OptionalBoolFalse:
+            break;
     }
 
     if (g->link_eh_frame_hdr) {
@@ -1781,6 +1790,19 @@ static void construct_linker_job_elf(LinkJob *lj) {
         lj->args.append("--export-dynamic");
     }
 
+    if (g->linker_optimization != nullptr) {
+        lj->args.append(buf_ptr(g->linker_optimization));
+    }
+
+    if (g->linker_z_nodelete) {
+        lj->args.append("-z");
+        lj->args.append("nodelete");
+    }
+    if (g->linker_z_defs) {
+        lj->args.append("-z");
+        lj->args.append("defs");
+    }
+
     lj->args.append("-m");
     lj->args.append(getLDMOption(g->zig_target));
 
@@ -1971,8 +1993,17 @@ static void construct_linker_job_elf(LinkJob *lj) {
         }
     }
 
-    if (!g->zig_target->is_native_os) {
-        lj->args.append("--allow-shlib-undefined");
+    switch (g->linker_allow_shlib_undefined) {
+        case OptionalBoolNull:
+            if (!g->zig_target->is_native_os) {
+                lj->args.append("--allow-shlib-undefined");
+            }
+            break;
+        case OptionalBoolFalse:
+            break;
+        case OptionalBoolTrue:
+            lj->args.append("--allow-shlib-undefined");
+            break;
     }
 }
 
@@ -2536,10 +2567,34 @@ static void construct_linker_job_macho(LinkJob *lj) {
     //lj->args.append("-error-limit=0");
     lj->args.append("-demangle");
 
+    switch (g->linker_gc_sections) {
+        case OptionalBoolNull:
+            // TODO why do we not follow the same logic of elf here?
+            break;
+        case OptionalBoolTrue:
+            lj->args.append("--gc-sections");
+            break;
+        case OptionalBoolFalse:
+            break;
+    }
+
     if (g->linker_rdynamic) {
         lj->args.append("-export_dynamic");
     }
 
+    if (g->linker_optimization != nullptr) {
+        lj->args.append(buf_ptr(g->linker_optimization));
+    }
+
+    if (g->linker_z_nodelete) {
+        lj->args.append("-z");
+        lj->args.append("nodelete");
+    }
+    if (g->linker_z_defs) {
+        lj->args.append("-z");
+        lj->args.append("defs");
+    }
+
     bool is_lib = g->out_type == OutTypeLib;
     bool is_dyn_lib = g->is_dynamic && is_lib;
     if (is_lib && !g->is_dynamic) {
@@ -2654,9 +2709,20 @@ static void construct_linker_job_macho(LinkJob *lj) {
         // and change between versions.
         // so we always link against libSystem
         lj->args.append("-lSystem");
-    } else {
-        lj->args.append("-undefined");
-        lj->args.append("dynamic_lookup");
+    }
+    switch (g->linker_allow_shlib_undefined) {
+        case OptionalBoolNull:
+            if (!g->zig_target->is_native_os) {
+                lj->args.append("-undefined");
+                lj->args.append("dynamic_lookup");
+            }
+            break;
+        case OptionalBoolFalse:
+            break;
+        case OptionalBoolTrue:
+            lj->args.append("-undefined");
+            lj->args.append("dynamic_lookup");
+            break;
     }
 
     for (size_t i = 0; i < g->framework_dirs.length; i += 1) {
src/main.cpp
@@ -459,6 +459,11 @@ static int main0(int argc, char **argv) {
     bool ensure_libc_on_non_freestanding = false;
     bool ensure_libcpp_on_non_freestanding = false;
     bool disable_c_depfile = false;
+    Buf *linker_optimization = nullptr;
+    OptionalBool linker_gc_sections = OptionalBoolNull;
+    OptionalBool linker_allow_shlib_undefined = OptionalBoolNull;
+    bool linker_z_nodelete = false;
+    bool linker_z_defs = false;
 
     ZigList<const char *> llvm_argv = {0};
     llvm_argv.append("zig (LLVM option parsing)");
@@ -822,6 +827,30 @@ static int main0(int argc, char **argv) {
                     return EXIT_FAILURE;
                 }
                 version_script = linker_args.at(i);
+            } else if (buf_starts_with_str(arg, "-O")) {
+                linker_optimization = arg;
+            } else if (buf_eql_str(arg, "--gc-sections")) {
+                linker_gc_sections = OptionalBoolTrue;
+            } else if (buf_eql_str(arg, "--no-gc-sections")) {
+                linker_gc_sections = OptionalBoolFalse;
+            } else if (buf_eql_str(arg, "--allow-shlib-undefined")) {
+                linker_allow_shlib_undefined = OptionalBoolTrue;
+            } else if (buf_eql_str(arg, "--no-allow-shlib-undefined")) {
+                linker_allow_shlib_undefined = OptionalBoolFalse;
+            } else if (buf_eql_str(arg, "-z")) {
+                i += 1;
+                if (i >= linker_args.length) {
+                    fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
+                    return EXIT_FAILURE;
+                }
+                Buf *z_arg = linker_args.at(i);
+                if (buf_eql_str(z_arg, "nodelete")) {
+                    linker_z_nodelete = true;
+                } else if (buf_eql_str(z_arg, "defs")) {
+                    linker_z_defs = true;
+                } else {
+                    fprintf(stderr, "warning: unsupported linker arg: -z %s\n", buf_ptr(z_arg));
+                }
             } else {
                 fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg));
             }
@@ -1542,6 +1571,12 @@ static int main0(int argc, char **argv) {
             g->code_model = code_model;
             g->disable_c_depfile = disable_c_depfile;
 
+            g->linker_optimization = linker_optimization;
+            g->linker_gc_sections = linker_gc_sections;
+            g->linker_allow_shlib_undefined = linker_allow_shlib_undefined;
+            g->linker_z_nodelete = linker_z_nodelete;
+            g->linker_z_defs = linker_z_defs;
+
             if (override_soname) {
                 g->override_soname = buf_create_from_str(override_soname);
             }