Commit eec825cea2

Andrew Kelley <andrew@ziglang.org>
2021-11-27 00:26:19
zig cc: support -Bdynamic and -Bstatic parameters
Related: #10050
1 parent b196dd1
Changed files (2)
src/link/Elf.zig
@@ -1553,7 +1553,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
             defer test_path.deinit();
             for (self.base.options.lib_dirs) |lib_dir_path| {
                 for (self.base.options.system_libs.keys()) |link_lib| {
-                    test_path.shrinkRetainingCapacity(0);
+                    test_path.clearRetainingCapacity();
                     const sep = fs.path.sep_str;
                     try test_path.writer().print("{s}" ++ sep ++ "lib{s}.so", .{
                         lib_dir_path, link_lib,
src/main.zig
@@ -668,6 +668,9 @@ fn buildOutputType(
     var system_libs = std.StringArrayHashMap(Compilation.SystemLib).init(gpa);
     defer system_libs.deinit();
 
+    var static_libs = std.ArrayList([]const u8).init(gpa);
+    defer static_libs.deinit();
+
     var wasi_emulated_libs = std.ArrayList(wasi_libc.CRTFile).init(gpa);
     defer wasi_emulated_libs.deinit();
 
@@ -1253,6 +1256,7 @@ fn buildOutputType(
             var it = ClangArgIterator.init(arena, all_args);
             var emit_llvm = false;
             var needed = false;
+            var force_static_libs = false;
             while (it.has_next) {
                 it.next() catch |err| {
                     fatal("unable to parse command line parameters: {s}", .{@errorName(err)});
@@ -1287,7 +1291,11 @@ fn buildOutputType(
                         // -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.put(it.only_arg, .{ .needed = needed });
+                        if (force_static_libs) {
+                            try static_libs.append(it.only_arg);
+                        } else {
+                            try system_libs.put(it.only_arg, .{ .needed = needed });
+                        }
                     },
                     .ignore => {},
                     .driver_punt => {
@@ -1333,6 +1341,17 @@ fn buildOutputType(
                                 needed = false;
                             } else if (mem.eql(u8, linker_arg, "--no-as-needed")) {
                                 needed = true;
+                            } else if (mem.eql(u8, linker_arg, "-Bdynamic") or
+                                mem.eql(u8, linker_arg, "-dy") or
+                                mem.eql(u8, linker_arg, "-call_shared"))
+                            {
+                                force_static_libs = false;
+                            } else if (mem.eql(u8, linker_arg, "-Bstatic") or
+                                mem.eql(u8, linker_arg, "-dn") or
+                                mem.eql(u8, linker_arg, "-non_shared") or
+                                mem.eql(u8, linker_arg, "-static"))
+                            {
+                                force_static_libs = true;
                             } else {
                                 try linker_args.append(linker_arg);
                             }
@@ -1893,6 +1912,48 @@ fn buildOutputType(
         }
     }
 
+    {
+        // Resolve static libraries into full paths.
+        const sep = fs.path.sep_str;
+
+        var test_path = std.ArrayList(u8).init(gpa);
+        defer test_path.deinit();
+
+        for (static_libs.items) |static_lib| {
+            for (lib_dirs.items) |lib_dir_path| {
+                test_path.clearRetainingCapacity();
+                try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{
+                    lib_dir_path,
+                    target_info.target.libPrefix(),
+                    static_lib,
+                    target_info.target.staticLibSuffix(),
+                });
+                fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
+                    error.FileNotFound => continue,
+                    else => |e| fatal("unable to search for static library '{s}': {s}", .{
+                        test_path.items, @errorName(e),
+                    }),
+                };
+                try link_objects.append(try arena.dupe(u8, test_path.items));
+                break;
+            } else {
+                var search_paths = std.ArrayList(u8).init(arena);
+                for (lib_dirs.items) |lib_dir_path| {
+                    try search_paths.writer().print("\n {s}" ++ sep ++ "{s}{s}{s}", .{
+                        lib_dir_path,
+                        target_info.target.libPrefix(),
+                        static_lib,
+                        target_info.target.staticLibSuffix(),
+                    });
+                }
+                try search_paths.appendSlice("\n suggestion: use full paths to static libraries on the command line rather than using -l and -L arguments");
+                fatal("static library '{s}' not found. search paths: {s}", .{
+                    static_lib, search_paths.items,
+                });
+            }
+        }
+    }
+
     const object_format: std.Target.ObjectFormat = blk: {
         const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat();
         if (mem.eql(u8, ofmt, "elf")) {