@@ -844,6 +844,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
844
844
try argv .append (arg );
845
845
}
846
846
847
+ for (self .lib_dirs ) | lib_dir | {
848
+ const arg = try std .fmt .allocPrint (arena , "-L{s}" , .{lib_dir });
849
+ try argv .append (arg );
850
+ }
851
+
847
852
for (self .frameworks ) | framework | {
848
853
const name = std .fs .path .stem (framework .path );
849
854
const arg = if (framework .needed )
@@ -855,6 +860,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
855
860
try argv .append (arg );
856
861
}
857
862
863
+ for (self .framework_dirs ) | f_dir | {
864
+ try argv .append ("-F" );
865
+ try argv .append (f_dir );
866
+ }
867
+
858
868
if (self .base .isDynLib () and self .base .allow_shlib_undefined ) {
859
869
try argv .append ("-undefined" );
860
870
try argv .append ("dynamic_lookup" );
@@ -887,11 +897,11 @@ pub fn resolveLibSystem(
887
897
if (self .sdk_layout ) | sdk_layout | switch (sdk_layout ) {
888
898
.sdk = > {
889
899
const dir = try fs .path .join (arena , &[_ ][]const u8 { comp .sysroot .? , "usr" , "lib" });
890
- if (try accessLibPath (arena , & test_path , & checked_paths , dir , "libSystem " )) break :success ;
900
+ if (try accessLibPath (arena , & test_path , & checked_paths , dir , "System " )) break :success ;
891
901
},
892
902
.vendored = > {
893
903
const dir = try comp .zig_lib_directory .join (arena , &[_ ][]const u8 { "libc" , "darwin" });
894
- if (try accessLibPath (arena , & test_path , & checked_paths , dir , "libSystem " )) break :success ;
904
+ if (try accessLibPath (arena , & test_path , & checked_paths , dir , "System " )) break :success ;
895
905
},
896
906
};
897
907
@@ -906,51 +916,6 @@ pub fn resolveLibSystem(
906
916
});
907
917
}
908
918
909
- fn accessLibPath (
910
- gpa : Allocator ,
911
- test_path : * std .ArrayList (u8 ),
912
- checked_paths : * std .ArrayList ([]const u8 ),
913
- search_dir : []const u8 ,
914
- lib_name : []const u8 ,
915
- ) ! bool {
916
- const sep = fs .path .sep_str ;
917
-
918
- tbd : {
919
- test_path .clearRetainingCapacity ();
920
- try test_path .writer ().print ("{s}" ++ sep ++ "{s}.tbd" , .{ search_dir , lib_name });
921
- try checked_paths .append (try gpa .dupe (u8 , test_path .items ));
922
- fs .cwd ().access (test_path .items , .{}) catch | err | switch (err ) {
923
- error .FileNotFound = > break :tbd ,
924
- else = > | e | return e ,
925
- };
926
- return true ;
927
- }
928
-
929
- dylib : {
930
- test_path .clearRetainingCapacity ();
931
- try test_path .writer ().print ("{s}" ++ sep ++ "{s}.dylib" , .{ search_dir , lib_name });
932
- try checked_paths .append (try gpa .dupe (u8 , test_path .items ));
933
- fs .cwd ().access (test_path .items , .{}) catch | err | switch (err ) {
934
- error .FileNotFound = > break :dylib ,
935
- else = > | e | return e ,
936
- };
937
- return true ;
938
- }
939
-
940
- noextension : {
941
- test_path .clearRetainingCapacity ();
942
- try test_path .writer ().print ("{s}" ++ sep ++ "{s}" , .{ search_dir , lib_name });
943
- try checked_paths .append (try gpa .dupe (u8 , test_path .items ));
944
- fs .cwd ().access (test_path .items , .{}) catch | err | switch (err ) {
945
- error .FileNotFound = > break :noextension ,
946
- else = > | e | return e ,
947
- };
948
- return true ;
949
- }
950
-
951
- return false ;
952
- }
953
-
954
919
const ParseError = error {
955
920
MalformedObject ,
956
921
MalformedArchive ,
@@ -1163,37 +1128,55 @@ fn isHoisted(self: *MachO, install_name: []const u8) bool {
1163
1128
return false ;
1164
1129
}
1165
1130
1166
- fn accessPath (path : []const u8 ) ! bool {
1167
- std .fs .cwd ().access (path , .{}) catch | err | switch (err ) {
1168
- error .FileNotFound = > return false ,
1169
- else = > | e | return e ,
1170
- };
1171
- return true ;
1172
- }
1131
+ fn accessLibPath (
1132
+ arena : Allocator ,
1133
+ test_path : * std .ArrayList (u8 ),
1134
+ checked_paths : * std .ArrayList ([]const u8 ),
1135
+ search_dir : []const u8 ,
1136
+ name : []const u8 ,
1137
+ ) ! bool {
1138
+ const sep = fs .path .sep_str ;
1173
1139
1174
- fn resolveLib (arena : Allocator , search_dirs : []const []const u8 , name : []const u8 ) ! ? []const u8 {
1175
- const path = try std .fmt .allocPrint (arena , "lib{s}" , .{name });
1176
- for (search_dirs ) | dir | {
1177
- for (&[_ ][]const u8 { ".tbd" , ".dylib" }) | ext | {
1178
- const with_ext = try std .fmt .allocPrint (arena , "{s}{s}" , .{ path , ext });
1179
- const full_path = try std .fs .path .join (arena , &[_ ][]const u8 { dir , with_ext });
1180
- if (try accessPath (full_path )) return full_path ;
1181
- }
1140
+ for (&[_ ][]const u8 { ".tbd" , ".dylib" , "" }) | ext | {
1141
+ test_path .clearRetainingCapacity ();
1142
+ try test_path .writer ().print ("{s}" ++ sep ++ "lib{s}{s}" , .{ search_dir , name , ext });
1143
+ try checked_paths .append (try arena .dupe (u8 , test_path .items ));
1144
+ std .fs .cwd ().access (test_path .items , .{}) catch | err | switch (err ) {
1145
+ error .FileNotFound = > continue ,
1146
+ else = > | e | return e ,
1147
+ };
1148
+ return true ;
1182
1149
}
1183
- return null ;
1150
+
1151
+ return false ;
1184
1152
}
1185
1153
1186
- fn resolveFramework (arena : Allocator , search_dirs : []const []const u8 , name : []const u8 ) ! ? []const u8 {
1187
- const prefix = try std .fmt .allocPrint (arena , "{s}.framework" , .{name });
1188
- const path = try std .fs .path .join (arena , &[_ ][]const u8 { prefix , name });
1189
- for (search_dirs ) | dir | {
1190
- for (&[_ ][]const u8 { ".tbd" , ".dylib" }) | ext | {
1191
- const with_ext = try std .fmt .allocPrint (arena , "{s}{s}" , .{ path , ext });
1192
- const full_path = try std .fs .path .join (arena , &[_ ][]const u8 { dir , with_ext });
1193
- if (try accessPath (full_path )) return full_path ;
1194
- }
1154
+ fn accessFrameworkPath (
1155
+ arena : Allocator ,
1156
+ test_path : * std .ArrayList (u8 ),
1157
+ checked_paths : * std .ArrayList ([]const u8 ),
1158
+ search_dir : []const u8 ,
1159
+ name : []const u8 ,
1160
+ ) ! bool {
1161
+ const sep = fs .path .sep_str ;
1162
+
1163
+ for (&[_ ][]const u8 { ".tbd" , ".dylib" , "" }) | ext | {
1164
+ test_path .clearRetainingCapacity ();
1165
+ try test_path .writer ().print ("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}" , .{
1166
+ search_dir ,
1167
+ name ,
1168
+ name ,
1169
+ ext ,
1170
+ });
1171
+ try checked_paths .append (try arena .dupe (u8 , test_path .items ));
1172
+ std .fs .cwd ().access (test_path .items , .{}) catch | err | switch (err ) {
1173
+ error .FileNotFound = > continue ,
1174
+ else = > | e | return e ,
1175
+ };
1176
+ return true ;
1195
1177
}
1196
- return null ;
1178
+
1179
+ return false ;
1197
1180
}
1198
1181
1199
1182
fn parseDependentDylibs (self : * MachO ) ! void {
@@ -1204,8 +1187,9 @@ fn parseDependentDylibs(self: *MachO) !void {
1204
1187
const lib_dirs = self .lib_dirs ;
1205
1188
const framework_dirs = self .framework_dirs ;
1206
1189
1207
- var arena = std .heap .ArenaAllocator .init (gpa );
1208
- defer arena .deinit ();
1190
+ var arena_alloc = std .heap .ArenaAllocator .init (gpa );
1191
+ defer arena_alloc .deinit ();
1192
+ const arena = arena_alloc .allocator ();
1209
1193
1210
1194
// TODO handle duplicate dylibs - it is not uncommon to have the same dylib loaded multiple times
1211
1195
// in which case we should track that and return File.Index immediately instead re-parsing paths.
@@ -1215,7 +1199,7 @@ fn parseDependentDylibs(self: *MachO) !void {
1215
1199
while (index < self .dylibs .items .len ) : (index += 1 ) {
1216
1200
const dylib_index = self .dylibs .items [index ];
1217
1201
1218
- var dependents = std .ArrayList (File .Index ).init (gpa );
1202
+ var dependents = std .ArrayList (struct { id : Dylib.Id , file : File .Index } ).init (gpa );
1219
1203
defer dependents .deinit ();
1220
1204
try dependents .ensureTotalCapacityPrecise (self .getFile (dylib_index ).? .dylib .dependents .items .len );
1221
1205
@@ -1228,43 +1212,52 @@ fn parseDependentDylibs(self: *MachO) !void {
1228
1212
// 3. If name is a relative path, substitute @rpath, @loader_path, @executable_path with
1229
1213
// dependees list of rpaths, and search there.
1230
1214
// 4. Finally, just search the provided relative path directly in CWD.
1215
+ var test_path = std .ArrayList (u8 ).init (arena );
1216
+ var checked_paths = std .ArrayList ([]const u8 ).init (arena );
1217
+
1231
1218
const full_path = full_path : {
1232
- fail : {
1219
+ {
1233
1220
const stem = std .fs .path .stem (id .name );
1234
- const framework_name = try std .fmt .allocPrint (gpa , "{s}.framework" ++ std .fs .path .sep_str ++ "{s}" , .{
1235
- stem ,
1236
- stem ,
1237
- });
1238
- defer gpa .free (framework_name );
1239
1221
1240
- if ( mem . endsWith ( u8 , id . name , framework_name )) {
1241
- // Framework
1242
- const full_path = ( try resolveFramework ( arena . allocator (), framework_dirs , stem )) orelse break : fail ;
1243
- break :full_path full_path ;
1222
+ // Framework
1223
+ for ( framework_dirs ) | dir | {
1224
+ test_path . clearRetainingCapacity () ;
1225
+ if ( try accessFrameworkPath ( arena , & test_path , & checked_paths , dir , stem )) break :full_path test_path . items ;
1244
1226
}
1245
1227
1246
1228
// Library
1247
1229
const lib_name = eatPrefix (stem , "lib" ) orelse stem ;
1248
- const full_path = (try resolveLib (arena .allocator (), lib_dirs , lib_name )) orelse break :fail ;
1249
- break :full_path full_path ;
1230
+ for (lib_dirs ) | dir | {
1231
+ test_path .clearRetainingCapacity ();
1232
+ if (try accessLibPath (arena , & test_path , & checked_paths , dir , lib_name )) break :full_path test_path .items ;
1233
+ }
1250
1234
}
1251
1235
1252
1236
if (std .fs .path .isAbsolute (id .name )) {
1253
- const path = if (self .base .comp .sysroot ) | root |
1254
- try std .fs .path .join (arena .allocator (), &.{ root , id .name })
1255
- else
1256
- id .name ;
1257
- for (&[_ ][]const u8 { "" , ".tbd" , ".dylib" }) | ext | {
1258
- const full_path = try std .fmt .allocPrint (arena .allocator (), "{s}{s}" , .{ path , ext });
1259
- if (try accessPath (full_path )) break :full_path full_path ;
1237
+ const existing_ext = std .fs .path .extension (id .name );
1238
+ const path = if (existing_ext .len > 0 ) id .name [0 .. id .name .len - existing_ext .len ] else id .name ;
1239
+ for (&[_ ][]const u8 { ".tbd" , ".dylib" , "" }) | ext | {
1240
+ test_path .clearRetainingCapacity ();
1241
+ if (self .base .comp .sysroot ) | root | {
1242
+ try test_path .writer ().print ("{s}" ++ std .fs .path .sep_str ++ "{s}{s}" , .{ root , path , ext });
1243
+ } else {
1244
+ try test_path .writer ().print ("{s}{s}" , .{ path , ext });
1245
+ }
1246
+ try checked_paths .append (try arena .dupe (u8 , test_path .items ));
1247
+ std .fs .cwd ().access (test_path .items , .{}) catch | err | switch (err ) {
1248
+ error .FileNotFound = > continue ,
1249
+ else = > | e | return e ,
1250
+ };
1251
+ break :full_path test_path .items ;
1260
1252
}
1261
1253
}
1262
1254
1263
1255
if (eatPrefix (id .name , "@rpath/" )) | path | {
1264
1256
const dylib = self .getFile (dylib_index ).? .dylib ;
1265
1257
for (self .getFile (dylib .umbrella ).? .dylib .rpaths .keys ()) | rpath | {
1266
1258
const prefix = eatPrefix (rpath , "@loader_path/" ) orelse rpath ;
1267
- const rel_path = try std .fs .path .join (arena .allocator (), &.{ prefix , path });
1259
+ const rel_path = try std .fs .path .join (arena , &.{ prefix , path });
1260
+ try checked_paths .append (rel_path );
1268
1261
var buffer : [std .fs .MAX_PATH_BYTES ]u8 = undefined ;
1269
1262
const full_path = std .fs .realpath (rel_path , & buffer ) catch continue ;
1270
1263
break :full_path full_path ;
@@ -1277,12 +1270,21 @@ fn parseDependentDylibs(self: *MachO) !void {
1277
1270
return error .Unhandled ;
1278
1271
}
1279
1272
1273
+ try checked_paths .append (try arena .dupe (u8 , id .name ));
1280
1274
var buffer : [std .fs .MAX_PATH_BYTES ]u8 = undefined ;
1281
- const full_path = std .fs .realpath (id .name , & buffer ) catch {
1282
- dependents .appendAssumeCapacity (0 );
1275
+ if (std .fs .realpath (id .name , & buffer )) | full_path | {
1276
+ break :full_path full_path ;
1277
+ } else | _ | {
1278
+ try self .reportMissingDependencyError (
1279
+ self .getFile (dylib_index ).? .dylib .getUmbrella (self ).index ,
1280
+ id .name ,
1281
+ checked_paths .items ,
1282
+ "unable to resolve dependency" ,
1283
+ .{},
1284
+ );
1285
+ has_errors = true ;
1283
1286
continue ;
1284
- };
1285
- break :full_path full_path ;
1287
+ }
1286
1288
};
1287
1289
const lib = SystemLib {
1288
1290
.path = full_path ,
@@ -1304,11 +1306,13 @@ fn parseDependentDylibs(self: *MachO) !void {
1304
1306
break :file_index file_index ;
1305
1307
}
1306
1308
};
1307
- dependents .appendAssumeCapacity (file_index );
1309
+ dependents .appendAssumeCapacity (.{ . id = id , . file = file_index } );
1308
1310
}
1309
1311
1310
1312
const dylib = self .getFile (dylib_index ).? .dylib ;
1311
- for (dylib .dependents .items , dependents .items ) | id , file_index | {
1313
+ for (dependents .items ) | entry | {
1314
+ const id = entry .id ;
1315
+ const file_index = entry .file ;
1312
1316
if (self .getFile (file_index )) | file | {
1313
1317
const dep_dylib = file .dylib ;
1314
1318
dep_dylib .hoisted = self .isHoisted (id .name );
@@ -3857,18 +3861,33 @@ fn reportMissingLibraryError(
3857
3861
}
3858
3862
}
3859
3863
3864
+ fn reportMissingDependencyError (
3865
+ self : * MachO ,
3866
+ parent : File.Index ,
3867
+ path : []const u8 ,
3868
+ checked_paths : []const []const u8 ,
3869
+ comptime format : []const u8 ,
3870
+ args : anytype ,
3871
+ ) error {OutOfMemory }! void {
3872
+ var err = try self .addErrorWithNotes (2 + checked_paths .len );
3873
+ try err .addMsg (self , format , args );
3874
+ try err .addNote (self , "while resolving {s}" , .{path });
3875
+ try err .addNote (self , "a dependency of {}" , .{self .getFile (parent ).? .fmtPath ()});
3876
+ for (checked_paths ) | p | {
3877
+ try err .addNote (self , "tried {s}" , .{p });
3878
+ }
3879
+ }
3880
+
3860
3881
fn reportDependencyError (
3861
3882
self : * MachO ,
3862
3883
parent : File.Index ,
3863
- path : ? []const u8 ,
3884
+ path : []const u8 ,
3864
3885
comptime format : []const u8 ,
3865
3886
args : anytype ,
3866
3887
) error {OutOfMemory }! void {
3867
3888
var err = try self .addErrorWithNotes (2 );
3868
3889
try err .addMsg (self , format , args );
3869
- if (path ) | p | {
3870
- try err .addNote (self , "while parsing {s}" , .{p });
3871
- }
3890
+ try err .addNote (self , "while parsing {s}" , .{path });
3872
3891
try err .addNote (self , "a dependency of {}" , .{self .getFile (parent ).? .fmtPath ()});
3873
3892
}
3874
3893
0 commit comments