Commit 22f464a8c3

Andrew Kelley <andrew@ziglang.org>
2022-02-16 01:32:20
zig cc: handle `-l :FILE` syntax
This "feature" of gcc/clang means to treat this as a positional link object, but using the library search directories as a prefix. We solve this problem in the CLI layer, using a separate map for the data since it is an uncommon case. Closes #10851
1 parent 092b019
Changed files (1)
src/main.zig
@@ -712,6 +712,14 @@ fn buildOutputType(
     var link_objects = std.ArrayList(Compilation.LinkObject).init(gpa);
     defer link_objects.deinit();
 
+    // This map is a flag per link_objects item, used to represent the
+    // `-l :file.so` syntax from gcc/clang.
+    // This is only exposed from the `zig cc` interface. It means that the `path`
+    // field from the corresponding `link_objects` element is a suffix, and is
+    // to be tried against each library path as a prefix until an existing file is found.
+    // This map remains empty for the main CLI.
+    var link_objects_lib_search_paths: std.AutoHashMapUnmanaged(u32, void) = .{};
+
     var framework_dirs = std.ArrayList([]const u8).init(gpa);
     defer framework_dirs.deinit();
 
@@ -1338,7 +1346,16 @@ 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.
-                        if (force_static_libs) {
+                        if (mem.startsWith(u8, it.only_arg, ":")) {
+                            // This "feature" of gcc/clang means to treat this as a positional
+                            // link object, but using the library search directories as a prefix.
+                            try link_objects.append(.{
+                                .path = it.only_arg[1..],
+                                .must_link = must_link,
+                            });
+                            const index = @intCast(u32, link_objects.items.len - 1);
+                            try link_objects_lib_search_paths.put(arena, index, {});
+                        } else if (force_static_libs) {
                             try static_libs.append(it.only_arg);
                         } else {
                             try system_libs.put(it.only_arg, .{ .needed = needed });
@@ -2137,6 +2154,30 @@ fn buildOutputType(
         }
     }
 
+    // Resolve `-l :file.so` syntax from `zig cc`. We use a separate map for this data
+    // since this is an uncommon case.
+    {
+        var it = link_objects_lib_search_paths.iterator();
+        while (it.next()) |item| {
+            const link_object_i = item.key_ptr.*;
+            const suffix = link_objects.items[link_object_i].path;
+
+            for (lib_dirs.items) |lib_dir_path| {
+                const test_path = try fs.path.join(arena, &.{ lib_dir_path, suffix });
+                fs.cwd().access(test_path, .{}) catch |err| switch (err) {
+                    error.FileNotFound => continue,
+                    else => |e| fatal("unable to search for library '{s}': {s}", .{
+                        test_path, @errorName(e),
+                    }),
+                };
+                link_objects.items[link_object_i].path = test_path;
+                break;
+            } else {
+                fatal("library '{s}' not found", .{suffix});
+            }
+        }
+    }
+
     const object_format: std.Target.ObjectFormat = blk: {
         const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat();
         if (mem.eql(u8, ofmt, "elf")) {