aboutsummaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-11-20 17:23:44 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-11-20 17:23:44 -0700
commit4e5a88b28882eda156a46ecc7f70887a7bc0b49b (patch)
tree1ccdc54fdb432ff72692e9f10f4f0640ef6869cd /src/main.zig
parenta699d678b2c81dcf333a4f4bb84676836849a618 (diff)
downloadzig-4e5a88b28882eda156a46ecc7f70887a7bc0b49b.tar.gz
zig-4e5a88b28882eda156a46ecc7f70887a7bc0b49b.zip
stage2: default dynamic libraries to be linked as needed
After this change, the default for dynamic libraries (`-l` or `--library`) is to only link them if they end up being actually used. With the Zig CLI, the new options `-needed-l` or `--needed-library` can be used to force link against a dynamic library. With `zig cc`, this behavior can be overridden with `-Wl,--no-as-needed` (and restored with `-Wl,--as-needed`). Closes #10164
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig58
1 files changed, 37 insertions, 21 deletions
diff --git a/src/main.zig b/src/main.zig
index f5ab7f7368..57193022e5 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -387,7 +387,9 @@ const usage_build_generic =
\\ -ffunction-sections Places each function in a separate section
\\
\\Link Options:
- \\ -l[lib], --library [lib] Link against system library
+ \\ -l[lib], --library [lib] Link against system library (only if actually used)
+ \\ -needed-l[lib], Link against system library (even if unused)
+ \\ --needed-library [lib]
\\ -L[d], --library-directory [d] Add a directory to the library search path
\\ -T[script], --script [script] Use a custom linker script
\\ --version-script [path] Provide a version .map file
@@ -655,7 +657,7 @@ fn buildOutputType(
var wasi_exec_model: ?std.builtin.WasiExecModel = null;
var enable_link_snapshots: bool = false;
- var system_libs = std.ArrayList([]const u8).init(gpa);
+ var system_libs = std.StringArrayHashMap(Compilation.SystemLib).init(gpa);
defer system_libs.deinit();
var wasi_emulated_libs = std.ArrayList(wasi_libc.CRTFile).init(gpa);
@@ -860,10 +862,14 @@ fn buildOutputType(
version_script = args[i];
} else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
- // We don't know whether this library is part of libc or libc++ until we resolve the target.
- // So we simply append to the list for now.
+ // We don't know whether this library is part of libc or libc++ until
+ // we resolve the target, so we simply append to the list for now.
i += 1;
- try system_libs.append(args[i]);
+ try system_libs.put(args[i], .{ .needed = false });
+ } else if (mem.eql(u8, arg, "--needed-library") or mem.eql(u8, arg, "-needed-l")) {
+ if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
+ i += 1;
+ try system_libs.put(args[i], .{ .needed = true });
} else if (mem.eql(u8, arg, "-D") or
mem.eql(u8, arg, "-isystem") or
mem.eql(u8, arg, "-I") or
@@ -1164,9 +1170,11 @@ fn buildOutputType(
} else if (mem.startsWith(u8, arg, "-F")) {
try framework_dirs.append(arg[2..]);
} else if (mem.startsWith(u8, arg, "-l")) {
- // We don't know whether this library is part of libc or libc++ until we resolve the target.
- // So we simply append to the list for now.
- try system_libs.append(arg[2..]);
+ // We don't know whether this library is part of libc or libc++ until
+ // we resolve the target, so we simply append to the list for now.
+ try system_libs.put(arg["-l".len..], .{ .needed = false });
+ } else if (mem.startsWith(u8, arg, "-needed-l")) {
+ try system_libs.put(arg["-needed-l".len..], .{ .needed = true });
} else if (mem.startsWith(u8, arg, "-D") or
mem.startsWith(u8, arg, "-I"))
{
@@ -1230,6 +1238,7 @@ fn buildOutputType(
var linker_args = std.ArrayList([]const u8).init(arena);
var it = ClangArgIterator.init(arena, all_args);
var emit_llvm = false;
+ var needed = false;
while (it.has_next) {
it.next() catch |err| {
fatal("unable to parse command line parameters: {s}", .{@errorName(err)});
@@ -1262,9 +1271,9 @@ fn buildOutputType(
},
.l => {
// -l
- // We don't know whether this library is part of libc or libc++ until we resolve the target.
- // So we simply append to the list for now.
- try system_libs.append(it.only_arg);
+ // We don't know whether this library is part of libc or libc++ until
+ // we resolve the target, so we simply append to the list for now.
+ try system_libs.put(it.only_arg, .{ .needed = needed });
},
.ignore => {},
.driver_punt => {
@@ -1302,8 +1311,13 @@ fn buildOutputType(
continue;
}
}
-
- try linker_args.append(linker_arg);
+ if (mem.eql(u8, linker_arg, "--as-needed")) {
+ needed = false;
+ } else if (mem.eql(u8, linker_arg, "--no-as-needed")) {
+ needed = true;
+ } else {
+ try linker_args.append(linker_arg);
+ }
}
},
.optimize => {
@@ -1725,21 +1739,22 @@ fn buildOutputType(
// existence via flags instead.
{
var i: usize = 0;
- while (i < system_libs.items.len) {
- const lib_name = system_libs.items[i];
+ while (i < system_libs.count()) {
+ const lib_name = system_libs.keys()[i];
+
if (target_util.is_libc_lib_name(target_info.target, lib_name)) {
link_libc = true;
- _ = system_libs.orderedRemove(i);
+ _ = system_libs.orderedRemove(lib_name);
continue;
}
if (target_util.is_libcpp_lib_name(target_info.target, lib_name)) {
link_libcpp = true;
- _ = system_libs.orderedRemove(i);
+ _ = system_libs.orderedRemove(lib_name);
continue;
}
if (mem.eql(u8, lib_name, "unwind")) {
link_libunwind = true;
- _ = system_libs.orderedRemove(i);
+ _ = system_libs.orderedRemove(lib_name);
continue;
}
if (std.fs.path.isAbsolute(lib_name)) {
@@ -1748,7 +1763,7 @@ fn buildOutputType(
if (target_info.target.os.tag == .wasi) {
if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {
try wasi_emulated_libs.append(crt_file);
- _ = system_libs.orderedRemove(i);
+ _ = system_libs.orderedRemove(lib_name);
continue;
}
}
@@ -1777,7 +1792,7 @@ fn buildOutputType(
const is_darwin_on_darwin = (comptime builtin.target.isDarwin()) and cross_target.isDarwin();
if (sysroot == null and (cross_target.isNativeOs() or is_darwin_on_darwin) and
- (system_libs.items.len != 0 or want_native_include_dirs))
+ (system_libs.count() != 0 or want_native_include_dirs))
{
const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| {
fatal("unable to detect native system paths: {s}", .{@errorName(err)});
@@ -2144,7 +2159,8 @@ fn buildOutputType(
.link_objects = link_objects.items,
.framework_dirs = framework_dirs.items,
.frameworks = frameworks.items,
- .system_libs = system_libs.items,
+ .system_lib_names = system_libs.keys(),
+ .system_lib_infos = system_libs.values(),
.wasi_emulated_libs = wasi_emulated_libs.items,
.link_libc = link_libc,
.link_libcpp = link_libcpp,