@@ -842,8 +842,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
842
842
Compilation .dump_argv (argv .items );
843
843
}
844
844
845
- try self .parseInputFiles (positionals .items , self .base .options .sysroot );
846
- try self .parseLibs (libs .items , self .base .options .sysroot );
845
+ var dependent_libs = std .fifo .LinearFifo (Dylib .Id , .Dynamic ).init (self .base .allocator );
846
+ defer dependent_libs .deinit ();
847
+ try self .parseInputFiles (positionals .items , self .base .options .sysroot , & dependent_libs );
848
+ try self .parseLibs (libs .items , self .base .options .sysroot , & dependent_libs );
849
+ try self .parseDependentLibs (self .base .options .sysroot , & dependent_libs );
847
850
}
848
851
849
852
if (self .bss_section_index ) | idx | {
@@ -1161,7 +1164,8 @@ const ParseDylibError = error{
1161
1164
} || fs .File .OpenError || std .os .PReadError || Dylib .Id .ParseError ;
1162
1165
1163
1166
const DylibCreateOpts = struct {
1164
- syslibroot : ? []const u8 = null ,
1167
+ syslibroot : ? []const u8 ,
1168
+ dependent_libs : * std .fifo .LinearFifo (Dylib.Id , .Dynamic ),
1165
1169
id : ? Dylib.Id = null ,
1166
1170
is_dependent : bool = false ,
1167
1171
};
@@ -1181,7 +1185,7 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy
1181
1185
.file = file ,
1182
1186
};
1183
1187
1184
- dylib .parse (self .base .allocator , self .base .options .target ) catch | err | switch (err ) {
1188
+ dylib .parse (self .base .allocator , self .base .options .target , opts . dependent_libs ) catch | err | switch (err ) {
1185
1189
error .EndOfStream , error .NotDylib = > {
1186
1190
try file .seekTo (0 );
1187
1191
@@ -1191,7 +1195,7 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy
1191
1195
};
1192
1196
defer lib_stub .deinit ();
1193
1197
1194
- try dylib .parseFromStub (self .base .allocator , self .base .options .target , lib_stub );
1198
+ try dylib .parseFromStub (self .base .allocator , self .base .options .target , lib_stub , opts . dependent_libs );
1195
1199
},
1196
1200
else = > | e | return e ,
1197
1201
};
@@ -1218,14 +1222,10 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy
1218
1222
try self .referenced_dylibs .putNoClobber (self .base .allocator , dylib_id , {});
1219
1223
}
1220
1224
1221
- // TODO this should not be performed if the user specifies `-flat_namespace` flag.
1222
- // See ld64 manpages.
1223
- try dylib .parseDependentLibs (self , opts .syslibroot );
1224
-
1225
1225
return true ;
1226
1226
}
1227
1227
1228
- fn parseInputFiles (self : * MachO , files : []const []const u8 , syslibroot : ? []const u8 ) ! void {
1228
+ fn parseInputFiles (self : * MachO , files : []const []const u8 , syslibroot : ? []const u8 , dependent_libs : anytype ) ! void {
1229
1229
for (files ) | file_name | {
1230
1230
const full_path = full_path : {
1231
1231
var buffer : [fs .MAX_PATH_BYTES ]u8 = undefined ;
@@ -1239,24 +1239,70 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
1239
1239
if (try self .parseArchive (full_path )) continue ;
1240
1240
if (try self .parseDylib (full_path , .{
1241
1241
.syslibroot = syslibroot ,
1242
+ .dependent_libs = dependent_libs ,
1242
1243
})) continue ;
1243
1244
1244
1245
log .warn ("unknown filetype for positional input file: '{s}'" , .{file_name });
1245
1246
}
1246
1247
}
1247
1248
1248
- fn parseLibs (self : * MachO , libs : []const []const u8 , syslibroot : ? []const u8 ) ! void {
1249
+ fn parseLibs (self : * MachO , libs : []const []const u8 , syslibroot : ? []const u8 , dependent_libs : anytype ) ! void {
1249
1250
for (libs ) | lib | {
1250
1251
log .debug ("parsing lib path '{s}'" , .{lib });
1251
1252
if (try self .parseDylib (lib , .{
1252
1253
.syslibroot = syslibroot ,
1254
+ .dependent_libs = dependent_libs ,
1253
1255
})) continue ;
1254
1256
if (try self .parseArchive (lib )) continue ;
1255
1257
1256
1258
log .warn ("unknown filetype for a library: '{s}'" , .{lib });
1257
1259
}
1258
1260
}
1259
1261
1262
+ fn parseDependentLibs (self : * MachO , syslibroot : ? []const u8 , dependent_libs : anytype ) ! void {
1263
+ // At this point, we can now parse dependents of dylibs preserving the inclusion order of:
1264
+ // 1) anything on the linker line is parsed first
1265
+ // 2) afterwards, we parse dependents of the included dylibs
1266
+ // TODO this should not be performed if the user specifies `-flat_namespace` flag.
1267
+ // See ld64 manpages.
1268
+ var arena_alloc = std .heap .ArenaAllocator .init (self .base .allocator );
1269
+ const arena = & arena_alloc .allocator ;
1270
+ defer arena_alloc .deinit ();
1271
+
1272
+ while (dependent_libs .readItem ()) | * id | {
1273
+ defer id .deinit (self .base .allocator );
1274
+
1275
+ if (self .dylibs_map .contains (id .name )) continue ;
1276
+
1277
+ const has_ext = blk : {
1278
+ const basename = fs .path .basename (id .name );
1279
+ break :blk mem .lastIndexOfScalar (u8 , basename , '.' ) != null ;
1280
+ };
1281
+ const extension = if (has_ext ) fs .path .extension (id .name ) else "" ;
1282
+ const without_ext = if (has_ext ) blk : {
1283
+ const index = mem .lastIndexOfScalar (u8 , id .name , '.' ) orelse unreachable ;
1284
+ break :blk id .name [0.. index ];
1285
+ } else id .name ;
1286
+
1287
+ for (&[_ ][]const u8 { extension , ".tbd" }) | ext | {
1288
+ const with_ext = try std .fmt .allocPrint (arena , "{s}{s}" , .{ without_ext , ext });
1289
+ const full_path = if (syslibroot ) | root | try fs .path .join (arena , &.{ root , with_ext }) else with_ext ;
1290
+
1291
+ log .debug ("trying dependency at fully resolved path {s}" , .{full_path });
1292
+
1293
+ const did_parse_successfully = try self .parseDylib (full_path , .{
1294
+ .id = id .* ,
1295
+ .syslibroot = syslibroot ,
1296
+ .is_dependent = true ,
1297
+ .dependent_libs = dependent_libs ,
1298
+ });
1299
+ if (did_parse_successfully ) break ;
1300
+ } else {
1301
+ log .warn ("unable to resolve dependency {s}" , .{id .name });
1302
+ }
1303
+ }
1304
+ }
1305
+
1260
1306
pub const MatchingSection = struct {
1261
1307
seg : u16 ,
1262
1308
sect : u16 ,
@@ -3992,12 +4038,16 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3992
4038
self .base .options .emit .? .sub_path ,
3993
4039
});
3994
4040
defer self .base .allocator .free (install_name );
4041
+ const current_version = self .base .options .version orelse
4042
+ std.builtin.Version { .major = 1 , .minor = 0 , .patch = 0 };
4043
+ const compat_version = self .base .options .compatibility_version orelse
4044
+ std.builtin.Version { .major = 1 , .minor = 0 , .patch = 0 };
3995
4045
var dylib_cmd = try commands .createLoadDylibCommand (
3996
4046
self .base .allocator ,
3997
4047
install_name ,
3998
4048
2 ,
3999
- 0x10000 , // TODO forward user-provided versions
4000
- 0x10000 ,
4049
+ current_version . major << 16 | current_version . minor << 8 | current_version . patch ,
4050
+ compat_version . major << 16 | compat_version . minor << 8 | compat_version . patch ,
4001
4051
);
4002
4052
errdefer dylib_cmd .deinit (self .base .allocator );
4003
4053
dylib_cmd .inner .cmd = macho .LC_ID_DYLIB ;
0 commit comments