@@ -47,6 +47,11 @@ pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
47
47
48
48
pub const base_tag : File.Tag = File .Tag .macho ;
49
49
50
+ pub const SearchStrategy = enum {
51
+ paths_first ,
52
+ dylibs_first ,
53
+ };
54
+
50
55
base : File ,
51
56
52
57
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
@@ -536,7 +541,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
536
541
// We are about to obtain this lock, so here we give other processes a chance first.
537
542
self .base .releaseLock ();
538
543
539
- comptime assert (Compilation .link_hash_implementation_version == 4 );
544
+ comptime assert (Compilation .link_hash_implementation_version == 5 );
540
545
541
546
for (self .base .options .objects ) | obj | {
542
547
_ = try man .addFile (obj .path , null );
@@ -550,6 +555,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
550
555
// installation sources because they are always a product of the compiler version + target information.
551
556
man .hash .add (stack_size );
552
557
man .hash .addOptional (self .base .options .pagezero_size );
558
+ man .hash .addOptional (self .base .options .search_strategy );
553
559
man .hash .addListOfBytes (self .base .options .lib_dirs );
554
560
man .hash .addListOfBytes (self .base .options .framework_dirs );
555
561
man .hash .addListOfBytes (self .base .options .frameworks );
@@ -784,18 +790,43 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
784
790
}
785
791
786
792
var libs = std .ArrayList ([]const u8 ).init (arena );
787
- for (search_lib_names .items ) | lib_name | {
788
- // Assume ld64 default: -search_paths_first
789
- // Look in each directory for a dylib (stub first), and then for archive
790
- // TODO implement alternative: -search_dylibs_first
791
- for (&[_ ][]const u8 { ".tbd" , ".dylib" , ".a" }) | ext | {
792
- if (try resolveLib (arena , lib_dirs .items , lib_name , ext )) | full_path | {
793
- try libs .append (full_path );
794
- break ;
795
- }
796
- } else {
797
- log .warn ("library not found for '-l{s}'" , .{lib_name });
798
- lib_not_found = true ;
793
+
794
+ // Assume ld64 default -search_paths_first if no strategy specified.
795
+ const search_strategy = self .base .options .search_strategy orelse .paths_first ;
796
+ outer : for (search_lib_names .items ) | lib_name | {
797
+ switch (search_strategy ) {
798
+ .paths_first = > {
799
+ // Look in each directory for a dylib (stub first), and then for archive
800
+ for (lib_dirs .items ) | dir | {
801
+ for (&[_ ][]const u8 { ".tbd" , ".dylib" , ".a" }) | ext | {
802
+ if (try resolveLib (arena , dir , lib_name , ext )) | full_path | {
803
+ try libs .append (full_path );
804
+ continue :outer ;
805
+ }
806
+ }
807
+ } else {
808
+ log .warn ("library not found for '-l{s}'" , .{lib_name });
809
+ lib_not_found = true ;
810
+ }
811
+ },
812
+ .dylibs_first = > {
813
+ // First, look for a dylib in each search dir
814
+ for (lib_dirs .items ) | dir | {
815
+ for (&[_ ][]const u8 { ".tbd" , ".dylib" }) | ext | {
816
+ if (try resolveLib (arena , dir , lib_name , ext )) | full_path | {
817
+ try libs .append (full_path );
818
+ continue :outer ;
819
+ }
820
+ }
821
+ } else for (lib_dirs .items ) | dir | {
822
+ if (try resolveLib (arena , dir , lib_name , ".a" )) | full_path | {
823
+ try libs .append (full_path );
824
+ } else {
825
+ log .warn ("library not found for '-l{s}'" , .{lib_name });
826
+ lib_not_found = true ;
827
+ }
828
+ }
829
+ },
799
830
}
800
831
}
801
832
@@ -811,19 +842,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
811
842
if (self .base .options .sysroot != null ) blk : {
812
843
// Try stub file first. If we hit it, then we're done as the stub file
813
844
// re-exports every single symbol definition.
814
- if (try resolveLib (arena , lib_dirs .items , "System" , ".tbd" )) | full_path | {
815
- try libs .append (full_path );
816
- libsystem_available = true ;
817
- break :blk ;
845
+ for (lib_dirs .items ) | dir | {
846
+ if (try resolveLib (arena , dir , "System" , ".tbd" )) | full_path | {
847
+ try libs .append (full_path );
848
+ libsystem_available = true ;
849
+ break :blk ;
850
+ }
818
851
}
819
852
// If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
820
853
// doesn't export libc.dylib which we'll need to resolve subsequently also.
821
- if (try resolveLib (arena , lib_dirs .items , "System" , ".dylib" )) | libsystem_path | {
822
- if (try resolveLib (arena , lib_dirs .items , "c" , ".dylib" )) | libc_path | {
823
- try libs .append (libsystem_path );
824
- try libs .append (libc_path );
825
- libsystem_available = true ;
826
- break :blk ;
854
+ for (lib_dirs .items ) | dir | {
855
+ if (try resolveLib (arena , dir , "System" , ".dylib" )) | libsystem_path | {
856
+ if (try resolveLib (arena , dir , "c" , ".dylib" )) | libc_path | {
857
+ try libs .append (libsystem_path );
858
+ try libs .append (libc_path );
859
+ libsystem_available = true ;
860
+ break :blk ;
861
+ }
827
862
}
828
863
}
829
864
}
@@ -847,11 +882,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
847
882
}
848
883
}
849
884
850
- for (self .base .options .frameworks ) | framework | {
851
- for (&[_ ][]const u8 { ".tbd" , ".dylib" , "" }) | ext | {
852
- if (try resolveFramework (arena , framework_dirs .items , framework , ext )) | full_path | {
853
- try libs .append (full_path );
854
- break ;
885
+ outer : for (self .base .options .frameworks ) | framework | {
886
+ for (framework_dirs .items ) | dir | {
887
+ for (&[_ ][]const u8 { ".tbd" , ".dylib" , "" }) | ext | {
888
+ if (try resolveFramework (arena , dir , framework , ext )) | full_path | {
889
+ try libs .append (full_path );
890
+ continue :outer ;
891
+ }
855
892
}
856
893
} else {
857
894
log .warn ("framework not found for '-framework {s}'" , .{framework });
@@ -934,20 +971,44 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
934
971
try argv .append (try std .fmt .allocPrint (arena , "0x{x}" , .{pagezero_size }));
935
972
}
936
973
974
+ if (self .base .options .search_strategy ) | strat | switch (strat ) {
975
+ .paths_first = > try argv .append ("-search_paths_first" ),
976
+ .dylibs_first = > try argv .append ("-search_dylibs_first" ),
977
+ };
978
+
937
979
if (self .base .options .entry ) | entry | {
938
980
try argv .append ("-e" );
939
981
try argv .append (entry );
940
982
}
941
983
942
- try argv .appendSlice (positionals .items );
984
+ for (self .base .options .objects ) | obj | {
985
+ try argv .append (obj .path );
986
+ }
987
+
988
+ for (comp .c_object_table .keys ()) | key | {
989
+ try argv .append (key .status .success .object_path );
990
+ }
991
+
992
+ if (module_obj_path ) | p | {
993
+ try argv .append (p );
994
+ }
995
+
996
+ if (comp .compiler_rt_lib ) | lib | {
997
+ try argv .append (lib .full_object_path );
998
+ }
999
+
1000
+ if (self .base .options .link_libcpp ) {
1001
+ try argv .append (comp .libcxxabi_static_lib .? .full_object_path );
1002
+ try argv .append (comp .libcxx_static_lib .? .full_object_path );
1003
+ }
943
1004
944
1005
try argv .append ("-o" );
945
1006
try argv .append (full_out_path );
946
1007
947
1008
try argv .append ("-lSystem" );
948
1009
try argv .append ("-lc" );
949
1010
950
- for (search_lib_names . items ) | l_name | {
1011
+ for (self . base . options . system_libs . keys () ) | l_name | {
951
1012
try argv .append (try std .fmt .allocPrint (arena , "-l{s}" , .{l_name }));
952
1013
}
953
1014
@@ -1183,51 +1244,41 @@ fn resolveSearchDir(
1183
1244
1184
1245
fn resolveLib (
1185
1246
arena : Allocator ,
1186
- search_dirs : [] const []const u8 ,
1247
+ search_dir : []const u8 ,
1187
1248
name : []const u8 ,
1188
1249
ext : []const u8 ,
1189
1250
) ! ? []const u8 {
1190
1251
const search_name = try std .fmt .allocPrint (arena , "lib{s}{s}" , .{ name , ext });
1252
+ const full_path = try fs .path .join (arena , &[_ ][]const u8 { search_dir , search_name });
1191
1253
1192
- for (search_dirs ) | dir | {
1193
- const full_path = try fs .path .join (arena , &[_ ][]const u8 { dir , search_name });
1194
-
1195
- // Check if the file exists.
1196
- const tmp = fs .cwd ().openFile (full_path , .{}) catch | err | switch (err ) {
1197
- error .FileNotFound = > continue ,
1198
- else = > | e | return e ,
1199
- };
1200
- defer tmp .close ();
1201
-
1202
- return full_path ;
1203
- }
1254
+ // Check if the file exists.
1255
+ const tmp = fs .cwd ().openFile (full_path , .{}) catch | err | switch (err ) {
1256
+ error .FileNotFound = > return null ,
1257
+ else = > | e | return e ,
1258
+ };
1259
+ defer tmp .close ();
1204
1260
1205
- return null ;
1261
+ return full_path ;
1206
1262
}
1207
1263
1208
1264
fn resolveFramework (
1209
1265
arena : Allocator ,
1210
- search_dirs : [] const []const u8 ,
1266
+ search_dir : []const u8 ,
1211
1267
name : []const u8 ,
1212
1268
ext : []const u8 ,
1213
1269
) ! ? []const u8 {
1214
1270
const search_name = try std .fmt .allocPrint (arena , "{s}{s}" , .{ name , ext });
1215
1271
const prefix_path = try std .fmt .allocPrint (arena , "{s}.framework" , .{name });
1272
+ const full_path = try fs .path .join (arena , &[_ ][]const u8 { search_dir , prefix_path , search_name });
1216
1273
1217
- for (search_dirs ) | dir | {
1218
- const full_path = try fs .path .join (arena , &[_ ][]const u8 { dir , prefix_path , search_name });
1219
-
1220
- // Check if the file exists.
1221
- const tmp = fs .cwd ().openFile (full_path , .{}) catch | err | switch (err ) {
1222
- error .FileNotFound = > continue ,
1223
- else = > | e | return e ,
1224
- };
1225
- defer tmp .close ();
1226
-
1227
- return full_path ;
1228
- }
1274
+ // Check if the file exists.
1275
+ const tmp = fs .cwd ().openFile (full_path , .{}) catch | err | switch (err ) {
1276
+ error .FileNotFound = > return null ,
1277
+ else = > | e | return e ,
1278
+ };
1279
+ defer tmp .close ();
1229
1280
1230
- return null ;
1281
+ return full_path ;
1231
1282
}
1232
1283
1233
1284
fn parseObject (self : * MachO , path : []const u8 ) ! bool {
0 commit comments