@@ -121,12 +121,23 @@ pub fn build(b: *Builder) !void {
121
121
test_step .dependOn (docs_step );
122
122
}
123
123
124
- fn dependOnLib (lib_exe_obj : var , dep : LibraryDep ) void {
124
+ fn dependOnLib (b : * Builder , lib_exe_obj : var , dep : LibraryDep ) void {
125
125
for (dep .libdirs .toSliceConst ()) | lib_dir | {
126
126
lib_exe_obj .addLibPath (lib_dir );
127
127
}
128
+ const lib_dir = os .path .join (b .allocator , dep .prefix , "lib" ) catch unreachable ;
128
129
for (dep .system_libs .toSliceConst ()) | lib | {
129
- lib_exe_obj .linkSystemLibrary (lib );
130
+ const static_bare_name = if (mem .eql (u8 , lib , "curses" ))
131
+ ([]const u8 )("libncurses.a" )
132
+ else
133
+ b .fmt ("lib{}.a" , lib );
134
+ const static_lib_name = os .path .join (b .allocator , lib_dir , static_bare_name ) catch unreachable ;
135
+ const have_static = fileExists (static_lib_name ) catch unreachable ;
136
+ if (have_static ) {
137
+ lib_exe_obj .addObjectFile (static_lib_name );
138
+ } else {
139
+ lib_exe_obj .linkSystemLibrary (lib );
140
+ }
130
141
}
131
142
for (dep .libs .toSliceConst ()) | lib | {
132
143
lib_exe_obj .addObjectFile (lib );
@@ -136,34 +147,49 @@ fn dependOnLib(lib_exe_obj: var, dep: LibraryDep) void {
136
147
}
137
148
}
138
149
150
+ fn fileExists (filename : []const u8 ) ! bool {
151
+ os .File .access (filename ) catch | err | switch (err ) {
152
+ error .PermissionDenied ,
153
+ error .FileNotFound ,
154
+ = > return false ,
155
+ else = > return err ,
156
+ };
157
+ return true ;
158
+ }
159
+
139
160
fn addCppLib (b : * Builder , lib_exe_obj : var , cmake_binary_dir : []const u8 , lib_name : []const u8 ) void {
140
161
const lib_prefix = if (lib_exe_obj .target .isWindows ()) "" else "lib" ;
141
162
lib_exe_obj .addObjectFile (os .path .join (b .allocator , cmake_binary_dir , "zig_cpp" , b .fmt ("{}{}{}" , lib_prefix , lib_name , lib_exe_obj .target .libFileExt ())) catch unreachable );
142
163
}
143
164
144
165
const LibraryDep = struct .{
166
+ prefix : []const u8 ,
145
167
libdirs : ArrayList ([]const u8 ),
146
168
libs : ArrayList ([]const u8 ),
147
169
system_libs : ArrayList ([]const u8 ),
148
170
includes : ArrayList ([]const u8 ),
149
171
};
150
172
151
173
fn findLLVM (b : * Builder , llvm_config_exe : []const u8 ) ! LibraryDep {
152
- const libs_output = try b .exec ([][]const u8 .{
153
- llvm_config_exe ,
154
- "--libs" ,
155
- "--system-libs" ,
156
- });
157
- const includes_output = try b .exec ([][]const u8 .{
158
- llvm_config_exe ,
159
- "--includedir" ,
160
- });
161
- const libdir_output = try b .exec ([][]const u8 .{
162
- llvm_config_exe ,
163
- "--libdir" ,
164
- });
174
+ const shared_mode = try b .exec ([][]const u8 .{ llvm_config_exe , "--shared-mode" });
175
+ const is_static = mem .startsWith (u8 , shared_mode , "static" );
176
+ const libs_output = if (is_static )
177
+ try b .exec ([][]const u8 .{
178
+ llvm_config_exe ,
179
+ "--libfiles" ,
180
+ "--system-libs" ,
181
+ })
182
+ else
183
+ try b .exec ([][]const u8 .{
184
+ llvm_config_exe ,
185
+ "--libs" ,
186
+ });
187
+ const includes_output = try b .exec ([][]const u8 .{ llvm_config_exe , "--includedir" });
188
+ const libdir_output = try b .exec ([][]const u8 .{ llvm_config_exe , "--libdir" });
189
+ const prefix_output = try b .exec ([][]const u8 .{ llvm_config_exe , "--prefix" });
165
190
166
191
var result = LibraryDep. {
192
+ .prefix = mem .split (prefix_output , " \r \n " ).next ().? ,
167
193
.libs = ArrayList ([]const u8 ).init (b .allocator ),
168
194
.system_libs = ArrayList ([]const u8 ).init (b .allocator ),
169
195
.includes = ArrayList ([]const u8 ).init (b .allocator ),
@@ -244,10 +270,6 @@ fn nextValue(index: *usize, build_info: []const u8) []const u8 {
244
270
}
245
271
246
272
fn configureStage2 (b : * Builder , exe : var , ctx : Context ) ! void {
247
- // This is for finding /lib/libz.a on alpine linux.
248
- // TODO turn this into -Dextra-lib-path=/lib option
249
- exe .addLibPath ("/lib" );
250
-
251
273
exe .setNoRoSegment (ctx .no_rosegment );
252
274
253
275
exe .addIncludeDir ("src" );
@@ -265,39 +287,63 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
265
287
addCppLib (b , exe , ctx .cmake_binary_dir , "embedded_lld_coff" );
266
288
addCppLib (b , exe , ctx .cmake_binary_dir , "embedded_lld_lib" );
267
289
}
268
- dependOnLib (exe , ctx .llvm );
290
+ dependOnLib (b , exe , ctx .llvm );
269
291
270
292
if (exe .target .getOs () == builtin .Os .linux ) {
271
- const libstdcxx_path_padded = try b .exec ([][]const u8 .{
272
- ctx .cxx_compiler ,
273
- "-print-file-name=libstdc++.a" ,
274
- });
275
- const libstdcxx_path = mem .split (libstdcxx_path_padded , "\r \n " ).next ().? ;
276
- if (mem .eql (u8 , libstdcxx_path , "libstdc++.a" )) {
277
- warn (
278
- \\Unable to determine path to libstdc++.a
279
- \\On Fedora, install libstdc++-static and try again.
280
- \\
281
- );
282
- return error .RequiredLibraryNotFound ;
283
- }
284
- exe .addObjectFile (libstdcxx_path );
293
+ try addCxxKnownPath (b , ctx , exe , "libstdc++.a" ,
294
+ \\Unable to determine path to libstdc++.a
295
+ \\On Fedora, install libstdc++-static and try again.
296
+ \\
297
+ );
285
298
286
299
exe .linkSystemLibrary ("pthread" );
287
300
} else if (exe .target .isDarwin ()) {
288
- exe .linkSystemLibrary ("c++" );
301
+ if (addCxxKnownPath (b , ctx , exe , "libgcc_eh.a" , "" )) {
302
+ // Compiler is GCC.
303
+ try addCxxKnownPath (b , ctx , exe , "libstdc++.a" , null );
304
+ exe .linkSystemLibrary ("pthread" );
305
+ // TODO LLD cannot perform this link.
306
+ // See https://github.com/ziglang/zig/issues/1535
307
+ exe .enableSystemLinkerHack ();
308
+ } else | err | switch (err ) {
309
+ error .RequiredLibraryNotFound = > {
310
+ // System compiler, not gcc.
311
+ exe .linkSystemLibrary ("c++" );
312
+ },
313
+ else = > return err ,
314
+ }
289
315
}
290
316
291
317
if (ctx .dia_guids_lib .len != 0 ) {
292
318
exe .addObjectFile (ctx .dia_guids_lib );
293
319
}
294
320
295
- if (exe .target .getOs () != builtin .Os .windows ) {
296
- exe .linkSystemLibrary ("xml2" );
297
- }
298
321
exe .linkSystemLibrary ("c" );
299
322
}
300
323
324
+ fn addCxxKnownPath (
325
+ b : * Builder ,
326
+ ctx : Context ,
327
+ exe : var ,
328
+ objname : []const u8 ,
329
+ errtxt : ? []const u8 ,
330
+ ) ! void {
331
+ const path_padded = try b .exec ([][]const u8 .{
332
+ ctx .cxx_compiler ,
333
+ b .fmt ("-print-file-name={}" , objname ),
334
+ });
335
+ const path_unpadded = mem .split (path_padded , "\r \n " ).next ().? ;
336
+ if (mem .eql (u8 , path_unpadded , objname )) {
337
+ if (errtxt ) | msg | {
338
+ warn ("{}" , msg );
339
+ } else {
340
+ warn ("Unable to determine path to {}\n " , objname );
341
+ }
342
+ return error .RequiredLibraryNotFound ;
343
+ }
344
+ exe .addObjectFile (path_unpadded );
345
+ }
346
+
301
347
const Context = struct .{
302
348
cmake_binary_dir : []const u8 ,
303
349
cxx_compiler : []const u8 ,
0 commit comments