authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-13 09:48:39-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-13 09:48:39-07:00
logf2d433a19375734d744656c1c231525aab6ee59f
tree8eb0335aa1fdccf1c051c880c32d38c5bf251fce
parent2896266a038cde4b64743534df7ccdd3f5b9347f
parentcea8645423604b758208d94ff4d404a0fbae51f8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15708 from xxxbxxx/build-link

build: avoid repeating objects when linking a static library

4 files changed, 174 insertions(+), 1 deletions(-)

lib/std/Build/Step/Compile.zig+2-1
...@@ -2192,7 +2192,8 @@ const TransitiveDeps = struct {...@@ -2192,7 +2192,8 @@ const TransitiveDeps = struct {
2192 if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)2192 if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)
2193 continue;2193 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)
2196 try td.link_objects.append(other_link_object);2197 try td.link_objects.append(other_link_object);
21972198
2198 try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());2199 try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());
test/link.zig+4
...@@ -20,6 +20,10 @@ pub const cases = [_]Case{...@@ -20,6 +20,10 @@ pub const cases = [_]Case{
20 .build_root = "test/link/interdependent_static_c_libs",20 .build_root = "test/link/interdependent_static_c_libs",
21 .import = @import("link/interdependent_static_c_libs/build.zig"),21 .import = @import("link/interdependent_static_c_libs/build.zig"),
22 },22 },
23 .{
24 .build_root = "test/link/static_libs_from_object_files",
25 .import = @import("link/static_libs_from_object_files/build.zig"),
26 },
23 .{27 .{
24 .build_root = "test/link/glibc_compat",28 .build_root = "test/link/glibc_compat",
25 .import = @import("link/glibc_compat/build.zig"),29 .import = @import("link/glibc_compat/build.zig"),
test/link/static_libs_from_object_files/build.zig created+148
...@@ -0,0 +1,148 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4const Build = std.Build;
5const FileSource = Build.FileSource;
6const Step = Build.Step;
7const Run = Step.Run;
8const WriteFile = Step.WriteFile;
9
10pub 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
50fn 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}
test/link/static_libs_from_object_files/main.zig created+20
...@@ -0,0 +1,20 @@
1const std = @import("std");
2
3extern fn foo_last() i32;
4extern fn bar_last() i32;
5
6export const one_0: i32 = 1;
7
8export fn foo_0() i32 {
9 return 1234;
10}
11export fn bar_0() i32 {
12 return 5678;
13}
14
15pub 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}