Skip to content

Commit f2d433a

Browse files
authored
Merge pull request #15708 from xxxbxxx/build-link
build: avoid repeating objects when linking a static library
2 parents 2896266 + cea8645 commit f2d433a

File tree

4 files changed

+174
-1
lines changed

4 files changed

+174
-1
lines changed

lib/std/Build/Step/Compile.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2192,7 +2192,8 @@ const TransitiveDeps = struct {
21922192
if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)
21932193
continue;
21942194

2195-
if (!dyn)
2195+
const included_in_lib = (other.kind == .lib and inner_other.kind == .obj);
2196+
if (!dyn and !included_in_lib)
21962197
try td.link_objects.append(other_link_object);
21972198

21982199
try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());

test/link.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ pub const cases = [_]Case{
2020
.build_root = "test/link/interdependent_static_c_libs",
2121
.import = @import("link/interdependent_static_c_libs/build.zig"),
2222
},
23+
.{
24+
.build_root = "test/link/static_libs_from_object_files",
25+
.import = @import("link/static_libs_from_object_files/build.zig"),
26+
},
2327
.{
2428
.build_root = "test/link/glibc_compat",
2529
.import = @import("link/glibc_compat/build.zig"),
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
const std = @import("std");
2+
const builtin = @import("builtin");
3+
4+
const Build = std.Build;
5+
const FileSource = Build.FileSource;
6+
const Step = Build.Step;
7+
const Run = Step.Run;
8+
const WriteFile = Step.WriteFile;
9+
10+
pub fn build(b: *Build) void {
11+
const nb_files = b.option(u32, "nb_files", "Number of c files to generate.") orelse 10;
12+
13+
const test_step = b.step("test", "Test it");
14+
b.default_step = test_step;
15+
16+
// generate c files
17+
const files = b.allocator.alloc(std.Build.FileSource, nb_files) catch unreachable;
18+
defer b.allocator.free(files);
19+
{
20+
for (files[0 .. nb_files - 1], 1..nb_files) |*file, i| {
21+
const wf = WriteFile.create(b);
22+
file.* = wf.add(b.fmt("src_{}.c", .{i}), b.fmt(
23+
\\extern int foo_0();
24+
\\extern int bar_{}();
25+
\\extern int one_{};
26+
\\int one_{} = 1;
27+
\\int foo_{}() {{ return one_{} + foo_0(); }}
28+
\\int bar_{}() {{ return bar_{}(); }}
29+
, .{ i - 1, i - 1, i, i, i - 1, i, i - 1 }));
30+
}
31+
32+
{
33+
const wf = WriteFile.create(b);
34+
files[nb_files - 1] = wf.add("src_last.c", b.fmt(
35+
\\extern int foo_0();
36+
\\extern int bar_{}();
37+
\\extern int one_{};
38+
\\int foo_last() {{ return one_{} + foo_0(); }}
39+
\\int bar_last() {{ return bar_{}(); }}
40+
, .{ nb_files - 1, nb_files - 1, nb_files - 1, nb_files - 1 }));
41+
}
42+
}
43+
44+
add(b, test_step, files, .Debug);
45+
add(b, test_step, files, .ReleaseSafe);
46+
add(b, test_step, files, .ReleaseSmall);
47+
add(b, test_step, files, .ReleaseFast);
48+
}
49+
50+
fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimize: std.builtin.OptimizeMode) void {
51+
const flags = [_][]const u8{
52+
"-Wall",
53+
"-std=c11",
54+
};
55+
56+
// all files at once
57+
{
58+
const exe = b.addExecutable(.{
59+
.name = "test1",
60+
.root_source_file = .{ .path = "main.zig" },
61+
.optimize = optimize,
62+
.target = .{},
63+
});
64+
65+
for (files) |file| {
66+
exe.addCSourceFileSource(.{ .source = file, .args = &flags });
67+
}
68+
69+
const run_cmd = b.addRunArtifact(exe);
70+
run_cmd.skip_foreign_checks = true;
71+
run_cmd.expectExitCode(0);
72+
73+
test_step.dependOn(&run_cmd.step);
74+
}
75+
76+
// using static librairies
77+
{
78+
const lib_a = b.addStaticLibrary(.{
79+
.name = "test2_a",
80+
.target = .{},
81+
.optimize = optimize,
82+
});
83+
const lib_b = b.addStaticLibrary(.{
84+
.name = "test2_b",
85+
.target = .{},
86+
.optimize = optimize,
87+
});
88+
89+
for (files, 1..) |file, i| {
90+
const lib = if (i & 1 == 0) lib_a else lib_b;
91+
lib.addCSourceFileSource(.{ .source = file, .args = &flags });
92+
}
93+
94+
const exe = b.addExecutable(.{
95+
.name = "test2",
96+
.root_source_file = .{ .path = "main.zig" },
97+
.optimize = optimize,
98+
});
99+
exe.linkLibrary(lib_a);
100+
exe.linkLibrary(lib_b);
101+
102+
const run_cmd = b.addRunArtifact(exe);
103+
run_cmd.skip_foreign_checks = true;
104+
run_cmd.expectExitCode(0);
105+
106+
test_step.dependOn(&run_cmd.step);
107+
}
108+
109+
// using static librairies and object files
110+
{
111+
const lib_a = b.addStaticLibrary(.{
112+
.name = "test3_a",
113+
.target = .{},
114+
.optimize = optimize,
115+
});
116+
const lib_b = b.addStaticLibrary(.{
117+
.name = "test3_b",
118+
.target = .{},
119+
.optimize = optimize,
120+
});
121+
122+
for (files, 1..) |file, i| {
123+
const obj = b.addObject(.{
124+
.name = b.fmt("obj_{}", .{i}),
125+
.target = .{},
126+
.optimize = optimize,
127+
});
128+
obj.addCSourceFileSource(.{ .source = file, .args = &flags });
129+
130+
const lib = if (i & 1 == 0) lib_a else lib_b;
131+
lib.addObject(obj);
132+
}
133+
134+
const exe = b.addExecutable(.{
135+
.name = "test3",
136+
.root_source_file = .{ .path = "main.zig" },
137+
.optimize = optimize,
138+
});
139+
exe.linkLibrary(lib_a);
140+
exe.linkLibrary(lib_b);
141+
142+
const run_cmd = b.addRunArtifact(exe);
143+
run_cmd.skip_foreign_checks = true;
144+
run_cmd.expectExitCode(0);
145+
146+
test_step.dependOn(&run_cmd.step);
147+
}
148+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const std = @import("std");
2+
3+
extern fn foo_last() i32;
4+
extern fn bar_last() i32;
5+
6+
export const one_0: i32 = 1;
7+
8+
export fn foo_0() i32 {
9+
return 1234;
10+
}
11+
export fn bar_0() i32 {
12+
return 5678;
13+
}
14+
15+
pub fn main() anyerror!void {
16+
const foo_expected: i32 = 1 + 1234;
17+
const bar_expected: i32 = 5678;
18+
try std.testing.expectEqual(foo_expected, foo_last());
19+
try std.testing.expectEqual(bar_expected, bar_last());
20+
}

0 commit comments

Comments
 (0)