authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-31 13:44:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-31 15:09:35-07:00
log16cdd1297ebfac534615eaeb8439a4e1de71837c
treeb70dae5d7206c02f7cf19167de1d4ef6604f3dca
parent77544683ddd5f4d577ecc9c92a2b52a276aed2a6

rename std.Build.LibExeObjStep to std.Build.CompileStep

This matches the nomenclature internally: a Compilation is the main type that represents a single invokation of the compiler.

26 files changed, 2130 insertions(+), 2121 deletions(-)

build.zig+6-6
...@@ -516,7 +516,7 @@ fn addCompilerStep(...@@ -516,7 +516,7 @@ fn addCompilerStep(
516 b: *std.Build,516 b: *std.Build,
517 optimize: std.builtin.OptimizeMode,517 optimize: std.builtin.OptimizeMode,
518 target: std.zig.CrossTarget,518 target: std.zig.CrossTarget,
519) *std.Build.LibExeObjStep {519) *std.Build.CompileStep {
520 const exe = b.addExecutable(.{520 const exe = b.addExecutable(.{
521 .name = "zig",521 .name = "zig",
522 .root_source_file = .{ .path = "src/main.zig" },522 .root_source_file = .{ .path = "src/main.zig" },
...@@ -544,7 +544,7 @@ const exe_cflags = [_][]const u8{...@@ -544,7 +544,7 @@ const exe_cflags = [_][]const u8{
544fn addCmakeCfgOptionsToExe(544fn addCmakeCfgOptionsToExe(
545 b: *std.Build,545 b: *std.Build,
546 cfg: CMakeConfig,546 cfg: CMakeConfig,
547 exe: *std.Build.LibExeObjStep,547 exe: *std.Build.CompileStep,
548 use_zig_libcxx: bool,548 use_zig_libcxx: bool,
549) !void {549) !void {
550 if (exe.target.isDarwin()) {550 if (exe.target.isDarwin()) {
...@@ -623,7 +623,7 @@ fn addCmakeCfgOptionsToExe(...@@ -623,7 +623,7 @@ fn addCmakeCfgOptionsToExe(
623 }623 }
624}624}
625625
626fn addStaticLlvmOptionsToExe(exe: *std.Build.LibExeObjStep) !void {626fn addStaticLlvmOptionsToExe(exe: *std.Build.CompileStep) !void {
627 // Adds the Zig C++ sources which both stage1 and stage2 need.627 // Adds the Zig C++ sources which both stage1 and stage2 need.
628 //628 //
629 // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling629 // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
...@@ -662,7 +662,7 @@ fn addStaticLlvmOptionsToExe(exe: *std.Build.LibExeObjStep) !void {...@@ -662,7 +662,7 @@ fn addStaticLlvmOptionsToExe(exe: *std.Build.LibExeObjStep) !void {
662fn addCxxKnownPath(662fn addCxxKnownPath(
663 b: *std.Build,663 b: *std.Build,
664 ctx: CMakeConfig,664 ctx: CMakeConfig,
665 exe: *std.Build.LibExeObjStep,665 exe: *std.Build.CompileStep,
666 objname: []const u8,666 objname: []const u8,
667 errtxt: ?[]const u8,667 errtxt: ?[]const u8,
668 need_cpp_includes: bool,668 need_cpp_includes: bool,
...@@ -695,7 +695,7 @@ fn addCxxKnownPath(...@@ -695,7 +695,7 @@ fn addCxxKnownPath(
695 }695 }
696}696}
697697
698fn addCMakeLibraryList(exe: *std.Build.LibExeObjStep, list: []const u8) void {698fn addCMakeLibraryList(exe: *std.Build.CompileStep, list: []const u8) void {
699 var it = mem.tokenize(u8, list, ";");699 var it = mem.tokenize(u8, list, ";");
700 while (it.next()) |lib| {700 while (it.next()) |lib| {
701 if (mem.startsWith(u8, lib, "-l")) {701 if (mem.startsWith(u8, lib, "-l")) {
...@@ -709,7 +709,7 @@ fn addCMakeLibraryList(exe: *std.Build.LibExeObjStep, list: []const u8) void {...@@ -709,7 +709,7 @@ fn addCMakeLibraryList(exe: *std.Build.LibExeObjStep, list: []const u8) void {
709}709}
710710
711const CMakeConfig = struct {711const CMakeConfig = struct {
712 llvm_linkage: std.Build.LibExeObjStep.Linkage,712 llvm_linkage: std.Build.CompileStep.Linkage,
713 cmake_binary_dir: []const u8,713 cmake_binary_dir: []const u8,
714 cmake_prefix_path: []const u8,714 cmake_prefix_path: []const u8,
715 cmake_static_library_prefix: []const u8,715 cmake_static_library_prefix: []const u8,
lib/std/Build.zig+26-23
...@@ -19,6 +19,9 @@ const NativeTargetInfo = std.zig.system.NativeTargetInfo;...@@ -19,6 +19,9 @@ const NativeTargetInfo = std.zig.system.NativeTargetInfo;
19const Sha256 = std.crypto.hash.sha2.Sha256;19const Sha256 = std.crypto.hash.sha2.Sha256;
20const Build = @This();20const Build = @This();
2121
22///// deprecated: use `CompileStep` instead.
23//pub const LibExeObjStep = CompileStep;
24
22pub const Step = @import("Build/Step.zig");25pub const Step = @import("Build/Step.zig");
23pub const CheckFileStep = @import("Build/CheckFileStep.zig");26pub const CheckFileStep = @import("Build/CheckFileStep.zig");
24pub const CheckObjectStep = @import("Build/CheckObjectStep.zig");27pub const CheckObjectStep = @import("Build/CheckObjectStep.zig");
...@@ -29,7 +32,7 @@ pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");...@@ -29,7 +32,7 @@ pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");
29pub const InstallDirStep = @import("Build/InstallDirStep.zig");32pub const InstallDirStep = @import("Build/InstallDirStep.zig");
30pub const InstallFileStep = @import("Build/InstallFileStep.zig");33pub const InstallFileStep = @import("Build/InstallFileStep.zig");
31pub const InstallRawStep = @import("Build/InstallRawStep.zig");34pub const InstallRawStep = @import("Build/InstallRawStep.zig");
32pub const LibExeObjStep = @import("Build/LibExeObjStep.zig");35pub const CompileStep = @import("Build/CompileStep.zig");
33pub const LogStep = @import("Build/LogStep.zig");36pub const LogStep = @import("Build/LogStep.zig");
34pub const OptionsStep = @import("Build/OptionsStep.zig");37pub const OptionsStep = @import("Build/OptionsStep.zig");
35pub const RemoveDirStep = @import("Build/RemoveDirStep.zig");38pub const RemoveDirStep = @import("Build/RemoveDirStep.zig");
...@@ -423,11 +426,11 @@ pub const ExecutableOptions = struct {...@@ -423,11 +426,11 @@ pub const ExecutableOptions = struct {
423 version: ?std.builtin.Version = null,426 version: ?std.builtin.Version = null,
424 target: CrossTarget = .{},427 target: CrossTarget = .{},
425 optimize: std.builtin.Mode = .Debug,428 optimize: std.builtin.Mode = .Debug,
426 linkage: ?LibExeObjStep.Linkage = null,429 linkage: ?CompileStep.Linkage = null,
427};430};
428431
429pub fn addExecutable(b: *Build, options: ExecutableOptions) *LibExeObjStep {432pub fn addExecutable(b: *Build, options: ExecutableOptions) *CompileStep {
430 return LibExeObjStep.create(b, .{433 return CompileStep.create(b, .{
431 .name = options.name,434 .name = options.name,
432 .root_source_file = options.root_source_file,435 .root_source_file = options.root_source_file,
433 .version = options.version,436 .version = options.version,
...@@ -445,8 +448,8 @@ pub const ObjectOptions = struct {...@@ -445,8 +448,8 @@ pub const ObjectOptions = struct {
445 optimize: std.builtin.Mode,448 optimize: std.builtin.Mode,
446};449};
447450
448pub fn addObject(b: *Build, options: ObjectOptions) *LibExeObjStep {451pub fn addObject(b: *Build, options: ObjectOptions) *CompileStep {
449 return LibExeObjStep.create(b, .{452 return CompileStep.create(b, .{
450 .name = options.name,453 .name = options.name,
451 .root_source_file = options.root_source_file,454 .root_source_file = options.root_source_file,
452 .target = options.target,455 .target = options.target,
...@@ -463,8 +466,8 @@ pub const SharedLibraryOptions = struct {...@@ -463,8 +466,8 @@ pub const SharedLibraryOptions = struct {
463 optimize: std.builtin.Mode,466 optimize: std.builtin.Mode,
464};467};
465468
466pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *LibExeObjStep {469pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *CompileStep {
467 return LibExeObjStep.create(b, .{470 return CompileStep.create(b, .{
468 .name = options.name,471 .name = options.name,
469 .root_source_file = options.root_source_file,472 .root_source_file = options.root_source_file,
470 .kind = .lib,473 .kind = .lib,
...@@ -483,8 +486,8 @@ pub const StaticLibraryOptions = struct {...@@ -483,8 +486,8 @@ pub const StaticLibraryOptions = struct {
483 version: ?std.builtin.Version = null,486 version: ?std.builtin.Version = null,
484};487};
485488
486pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *LibExeObjStep {489pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *CompileStep {
487 return LibExeObjStep.create(b, .{490 return CompileStep.create(b, .{
488 .name = options.name,491 .name = options.name,
489 .root_source_file = options.root_source_file,492 .root_source_file = options.root_source_file,
490 .kind = .lib,493 .kind = .lib,
...@@ -497,15 +500,15 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *LibExeObjStep...@@ -497,15 +500,15 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *LibExeObjStep
497500
498pub const TestOptions = struct {501pub const TestOptions = struct {
499 name: []const u8 = "test",502 name: []const u8 = "test",
500 kind: LibExeObjStep.Kind = .@"test",503 kind: CompileStep.Kind = .@"test",
501 root_source_file: FileSource,504 root_source_file: FileSource,
502 target: CrossTarget = .{},505 target: CrossTarget = .{},
503 optimize: std.builtin.Mode = .Debug,506 optimize: std.builtin.Mode = .Debug,
504 version: ?std.builtin.Version = null,507 version: ?std.builtin.Version = null,
505};508};
506509
507pub fn addTest(b: *Build, options: TestOptions) *LibExeObjStep {510pub fn addTest(b: *Build, options: TestOptions) *CompileStep {
508 return LibExeObjStep.create(b, .{511 return CompileStep.create(b, .{
509 .name = options.name,512 .name = options.name,
510 .kind = options.kind,513 .kind = options.kind,
511 .root_source_file = options.root_source_file,514 .root_source_file = options.root_source_file,
...@@ -521,8 +524,8 @@ pub const AssemblyOptions = struct {...@@ -521,8 +524,8 @@ pub const AssemblyOptions = struct {
521 optimize: std.builtin.Mode,524 optimize: std.builtin.Mode,
522};525};
523526
524pub fn addAssembly(b: *Build, options: AssemblyOptions) *LibExeObjStep {527pub fn addAssembly(b: *Build, options: AssemblyOptions) *CompileStep {
525 const obj_step = LibExeObjStep.create(b, .{528 const obj_step = CompileStep.create(b, .{
526 .name = options.name,529 .name = options.name,
527 .root_source_file = null,530 .root_source_file = null,
528 .target = options.target,531 .target = options.target,
...@@ -536,7 +539,7 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *LibExeObjStep {...@@ -536,7 +539,7 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *LibExeObjStep {
536/// executable. More command line arguments can be added with `addArg`,539/// executable. More command line arguments can be added with `addArg`,
537/// `addArgs`, and `addArtifactArg`.540/// `addArgs`, and `addArtifactArg`.
538/// Be careful using this function, as it introduces a system dependency.541/// Be careful using this function, as it introduces a system dependency.
539/// To run an executable built with zig build, see `LibExeObjStep.run`.542/// To run an executable built with zig build, see `CompileStep.run`.
540pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep {543pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep {
541 assert(argv.len >= 1);544 assert(argv.len >= 1);
542 const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]}));545 const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]}));
...@@ -1167,11 +1170,11 @@ pub fn makePath(self: *Build, path: []const u8) !void {...@@ -1167,11 +1170,11 @@ pub fn makePath(self: *Build, path: []const u8) !void {
1167 };1170 };
1168}1171}
11691172
1170pub fn installArtifact(self: *Build, artifact: *LibExeObjStep) void {1173pub fn installArtifact(self: *Build, artifact: *CompileStep) void {
1171 self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);1174 self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
1172}1175}
11731176
1174pub fn addInstallArtifact(self: *Build, artifact: *LibExeObjStep) *InstallArtifactStep {1177pub fn addInstallArtifact(self: *Build, artifact: *CompileStep) *InstallArtifactStep {
1175 return InstallArtifactStep.create(self, artifact);1178 return InstallArtifactStep.create(self, artifact);
1176}1179}
11771180
...@@ -1195,7 +1198,7 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const...@@ -1195,7 +1198,7 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const
1195}1198}
11961199
1197/// Output format (BIN vs Intel HEX) determined by filename1200/// Output format (BIN vs Intel HEX) determined by filename
1198pub fn installRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {1201pub fn installRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
1199 const raw = self.addInstallRaw(artifact, dest_filename, options);1202 const raw = self.addInstallRaw(artifact, dest_filename, options);
1200 self.getInstallStep().dependOn(&raw.step);1203 self.getInstallStep().dependOn(&raw.step);
1201 return raw;1204 return raw;
...@@ -1220,7 +1223,7 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co...@@ -1220,7 +1223,7 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co
1220 return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);1223 return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);
1221}1224}
12221225
1223pub fn addInstallRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {1226pub fn addInstallRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
1224 return InstallRawStep.create(self, artifact, dest_filename, options);1227 return InstallRawStep.create(self, artifact, dest_filename, options);
1225}1228}
12261229
...@@ -1456,8 +1459,8 @@ pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8)...@@ -1456,8 +1459,8 @@ pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8)
1456pub const Dependency = struct {1459pub const Dependency = struct {
1457 builder: *Build,1460 builder: *Build,
14581461
1459 pub fn artifact(d: *Dependency, name: []const u8) *LibExeObjStep {1462 pub fn artifact(d: *Dependency, name: []const u8) *CompileStep {
1460 var found: ?*LibExeObjStep = null;1463 var found: ?*CompileStep = null;
1461 for (d.builder.install_tls.step.dependencies.items) |dep_step| {1464 for (d.builder.install_tls.step.dependencies.items) |dep_step| {
1462 const inst = dep_step.cast(InstallArtifactStep) orelse continue;1465 const inst = dep_step.cast(InstallArtifactStep) orelse continue;
1463 if (mem.eql(u8, inst.artifact.name, name)) {1466 if (mem.eql(u8, inst.artifact.name, name)) {
...@@ -1767,7 +1770,7 @@ test {...@@ -1767,7 +1770,7 @@ test {
1767 _ = InstallDirStep;1770 _ = InstallDirStep;
1768 _ = InstallFileStep;1771 _ = InstallFileStep;
1769 _ = InstallRawStep;1772 _ = InstallRawStep;
1770 _ = LibExeObjStep;1773 _ = CompileStep;
1771 _ = LogStep;1774 _ = LogStep;
1772 _ = OptionsStep;1775 _ = OptionsStep;
1773 _ = RemoveDirStep;1776 _ = RemoveDirStep;
lib/std/Build/CheckObjectStep.zig+1-1
...@@ -42,7 +42,7 @@ pub fn runAndCompare(self: *CheckObjectStep) *EmulatableRunStep {...@@ -42,7 +42,7 @@ pub fn runAndCompare(self: *CheckObjectStep) *EmulatableRunStep {
42 const dependencies_len = self.step.dependencies.items.len;42 const dependencies_len = self.step.dependencies.items.len;
43 assert(dependencies_len > 0);43 assert(dependencies_len > 0);
44 const exe_step = self.step.dependencies.items[dependencies_len - 1];44 const exe_step = self.step.dependencies.items[dependencies_len - 1];
45 const exe = exe_step.cast(std.Build.LibExeObjStep).?;45 const exe = exe_step.cast(std.Build.CompileStep).?;
46 const emulatable_step = EmulatableRunStep.create(self.builder, "EmulatableRun", exe);46 const emulatable_step = EmulatableRunStep.create(self.builder, "EmulatableRun", exe);
47 emulatable_step.step.dependOn(&self.step);47 emulatable_step.step.dependOn(&self.step);
48 return emulatable_step;48 return emulatable_step;
lib/std/Build/CompileStep.zig created+2045
...@@ -0,0 +1,2045 @@
1const builtin = @import("builtin");
2const std = @import("../std.zig");
3const mem = std.mem;
4const log = std.log;
5const fs = std.fs;
6const assert = std.debug.assert;
7const panic = std.debug.panic;
8const ArrayList = std.ArrayList;
9const StringHashMap = std.StringHashMap;
10const Sha256 = std.crypto.hash.sha2.Sha256;
11const Allocator = mem.Allocator;
12const Step = std.Build.Step;
13const CrossTarget = std.zig.CrossTarget;
14const NativeTargetInfo = std.zig.system.NativeTargetInfo;
15const FileSource = std.Build.FileSource;
16const PkgConfigPkg = std.Build.PkgConfigPkg;
17const PkgConfigError = std.Build.PkgConfigError;
18const ExecError = std.Build.ExecError;
19const Pkg = std.Build.Pkg;
20const VcpkgRoot = std.Build.VcpkgRoot;
21const InstallDir = std.Build.InstallDir;
22const InstallArtifactStep = std.Build.InstallArtifactStep;
23const GeneratedFile = std.Build.GeneratedFile;
24const InstallRawStep = std.Build.InstallRawStep;
25const EmulatableRunStep = std.Build.EmulatableRunStep;
26const CheckObjectStep = std.Build.CheckObjectStep;
27const RunStep = std.Build.RunStep;
28const OptionsStep = std.Build.OptionsStep;
29const ConfigHeaderStep = std.Build.ConfigHeaderStep;
30const CompileStep = @This();
31
32pub const base_id: Step.Id = .compile;
33
34step: Step,
35builder: *std.Build,
36name: []const u8,
37target: CrossTarget,
38target_info: NativeTargetInfo,
39optimize: std.builtin.Mode,
40linker_script: ?FileSource = null,
41version_script: ?[]const u8 = null,
42out_filename: []const u8,
43linkage: ?Linkage = null,
44version: ?std.builtin.Version,
45kind: Kind,
46major_only_filename: ?[]const u8,
47name_only_filename: ?[]const u8,
48strip: ?bool,
49unwind_tables: ?bool,
50// keep in sync with src/link.zig:CompressDebugSections
51compress_debug_sections: enum { none, zlib } = .none,
52lib_paths: ArrayList([]const u8),
53rpaths: ArrayList([]const u8),
54framework_dirs: ArrayList([]const u8),
55frameworks: StringHashMap(FrameworkLinkInfo),
56verbose_link: bool,
57verbose_cc: bool,
58emit_analysis: EmitOption = .default,
59emit_asm: EmitOption = .default,
60emit_bin: EmitOption = .default,
61emit_docs: EmitOption = .default,
62emit_implib: EmitOption = .default,
63emit_llvm_bc: EmitOption = .default,
64emit_llvm_ir: EmitOption = .default,
65// Lots of things depend on emit_h having a consistent path,
66// so it is not an EmitOption for now.
67emit_h: bool = false,
68bundle_compiler_rt: ?bool = null,
69single_threaded: ?bool = null,
70stack_protector: ?bool = null,
71disable_stack_probing: bool,
72disable_sanitize_c: bool,
73sanitize_thread: bool,
74rdynamic: bool,
75import_memory: bool = false,
76/// For WebAssembly targets, this will allow for undefined symbols to
77/// be imported from the host environment.
78import_symbols: bool = false,
79import_table: bool = false,
80export_table: bool = false,
81initial_memory: ?u64 = null,
82max_memory: ?u64 = null,
83shared_memory: bool = false,
84global_base: ?u64 = null,
85c_std: std.Build.CStd,
86override_lib_dir: ?[]const u8,
87main_pkg_path: ?[]const u8,
88exec_cmd_args: ?[]const ?[]const u8,
89name_prefix: []const u8,
90filter: ?[]const u8,
91test_evented_io: bool = false,
92test_runner: ?[]const u8,
93code_model: std.builtin.CodeModel = .default,
94wasi_exec_model: ?std.builtin.WasiExecModel = null,
95/// Symbols to be exported when compiling to wasm
96export_symbol_names: []const []const u8 = &.{},
97
98root_src: ?FileSource,
99out_h_filename: []const u8,
100out_lib_filename: []const u8,
101out_pdb_filename: []const u8,
102packages: ArrayList(Pkg),
103
104object_src: []const u8,
105
106link_objects: ArrayList(LinkObject),
107include_dirs: ArrayList(IncludeDir),
108c_macros: ArrayList([]const u8),
109installed_headers: ArrayList(*Step),
110output_dir: ?[]const u8,
111is_linking_libc: bool = false,
112is_linking_libcpp: bool = false,
113vcpkg_bin_path: ?[]const u8 = null,
114
115/// This may be set in order to override the default install directory
116override_dest_dir: ?InstallDir,
117installed_path: ?[]const u8,
118install_step: ?*InstallArtifactStep,
119
120/// Base address for an executable image.
121image_base: ?u64 = null,
122
123libc_file: ?FileSource = null,
124
125valgrind_support: ?bool = null,
126each_lib_rpath: ?bool = null,
127/// On ELF targets, this will emit a link section called ".note.gnu.build-id"
128/// which can be used to coordinate a stripped binary with its debug symbols.
129/// As an example, the bloaty project refuses to work unless its inputs have
130/// build ids, in order to prevent accidental mismatches.
131/// The default is to not include this section because it slows down linking.
132build_id: ?bool = null,
133
134/// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF
135/// file.
136link_eh_frame_hdr: bool = false,
137link_emit_relocs: bool = false,
138
139/// Place every function in its own section so that unused ones may be
140/// safely garbage-collected during the linking phase.
141link_function_sections: bool = false,
142
143/// Remove functions and data that are unreachable by the entry point or
144/// exported symbols.
145link_gc_sections: ?bool = null,
146
147linker_allow_shlib_undefined: ?bool = null,
148
149/// Permit read-only relocations in read-only segments. Disallowed by default.
150link_z_notext: bool = false,
151
152/// Force all relocations to be read-only after processing.
153link_z_relro: bool = true,
154
155/// Allow relocations to be lazily processed after load.
156link_z_lazy: bool = false,
157
158/// Common page size
159link_z_common_page_size: ?u64 = null,
160
161/// Maximum page size
162link_z_max_page_size: ?u64 = null,
163
164/// (Darwin) Install name for the dylib
165install_name: ?[]const u8 = null,
166
167/// (Darwin) Path to entitlements file
168entitlements: ?[]const u8 = null,
169
170/// (Darwin) Size of the pagezero segment.
171pagezero_size: ?u64 = null,
172
173/// (Darwin) Search strategy for searching system libraries. Either `paths_first` or `dylibs_first`.
174/// The former lowers to `-search_paths_first` linker option, while the latter to `-search_dylibs_first`
175/// option.
176/// By default, if no option is specified, the linker assumes `paths_first` as the default
177/// search strategy.
178search_strategy: ?enum { paths_first, dylibs_first } = null,
179
180/// (Darwin) Set size of the padding between the end of load commands
181/// and start of `__TEXT,__text` section.
182headerpad_size: ?u32 = null,
183
184/// (Darwin) Automatically Set size of the padding between the end of load commands
185/// and start of `__TEXT,__text` section to a value fitting all paths expanded to MAXPATHLEN.
186headerpad_max_install_names: bool = false,
187
188/// (Darwin) Remove dylibs that are unreachable by the entry point or exported symbols.
189dead_strip_dylibs: bool = false,
190
191/// Position Independent Code
192force_pic: ?bool = null,
193
194/// Position Independent Executable
195pie: ?bool = null,
196
197red_zone: ?bool = null,
198
199omit_frame_pointer: ?bool = null,
200dll_export_fns: ?bool = null,
201
202subsystem: ?std.Target.SubSystem = null,
203
204entry_symbol_name: ?[]const u8 = null,
205
206/// Overrides the default stack size
207stack_size: ?u64 = null,
208
209want_lto: ?bool = null,
210use_llvm: ?bool = null,
211use_lld: ?bool = null,
212
213output_path_source: GeneratedFile,
214output_lib_path_source: GeneratedFile,
215output_h_path_source: GeneratedFile,
216output_pdb_path_source: GeneratedFile,
217
218pub const CSourceFiles = struct {
219 files: []const []const u8,
220 flags: []const []const u8,
221};
222
223pub const CSourceFile = struct {
224 source: FileSource,
225 args: []const []const u8,
226
227 pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile {
228 return .{
229 .source = self.source.dupe(b),
230 .args = b.dupeStrings(self.args),
231 };
232 }
233};
234
235pub const LinkObject = union(enum) {
236 static_path: FileSource,
237 other_step: *CompileStep,
238 system_lib: SystemLib,
239 assembly_file: FileSource,
240 c_source_file: *CSourceFile,
241 c_source_files: *CSourceFiles,
242};
243
244pub const SystemLib = struct {
245 name: []const u8,
246 needed: bool,
247 weak: bool,
248 use_pkg_config: enum {
249 /// Don't use pkg-config, just pass -lfoo where foo is name.
250 no,
251 /// Try to get information on how to link the library from pkg-config.
252 /// If that fails, fall back to passing -lfoo where foo is name.
253 yes,
254 /// Try to get information on how to link the library from pkg-config.
255 /// If that fails, error out.
256 force,
257 },
258};
259
260const FrameworkLinkInfo = struct {
261 needed: bool = false,
262 weak: bool = false,
263};
264
265pub const IncludeDir = union(enum) {
266 raw_path: []const u8,
267 raw_path_system: []const u8,
268 other_step: *CompileStep,
269 config_header_step: *ConfigHeaderStep,
270};
271
272pub const Options = struct {
273 name: []const u8,
274 root_source_file: ?FileSource = null,
275 target: CrossTarget,
276 optimize: std.builtin.Mode,
277 kind: Kind,
278 linkage: ?Linkage = null,
279 version: ?std.builtin.Version = null,
280};
281
282pub const Kind = enum {
283 exe,
284 lib,
285 obj,
286 @"test",
287 test_exe,
288};
289
290pub const Linkage = enum { dynamic, static };
291
292pub const EmitOption = union(enum) {
293 default: void,
294 no_emit: void,
295 emit: void,
296 emit_to: []const u8,
297
298 fn getArg(self: @This(), b: *std.Build, arg_name: []const u8) ?[]const u8 {
299 return switch (self) {
300 .no_emit => b.fmt("-fno-{s}", .{arg_name}),
301 .default => null,
302 .emit => b.fmt("-f{s}", .{arg_name}),
303 .emit_to => |path| b.fmt("-f{s}={s}", .{ arg_name, path }),
304 };
305 }
306};
307
308pub fn create(builder: *std.Build, options: Options) *CompileStep {
309 const name = builder.dupe(options.name);
310 const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(builder) else null;
311 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
312 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
313 }
314
315 const self = builder.allocator.create(CompileStep) catch unreachable;
316 self.* = CompileStep{
317 .strip = null,
318 .unwind_tables = null,
319 .builder = builder,
320 .verbose_link = false,
321 .verbose_cc = false,
322 .optimize = options.optimize,
323 .target = options.target,
324 .linkage = options.linkage,
325 .kind = options.kind,
326 .root_src = root_src,
327 .name = name,
328 .frameworks = StringHashMap(FrameworkLinkInfo).init(builder.allocator),
329 .step = Step.init(base_id, name, builder.allocator, make),
330 .version = options.version,
331 .out_filename = undefined,
332 .out_h_filename = builder.fmt("{s}.h", .{name}),
333 .out_lib_filename = undefined,
334 .out_pdb_filename = builder.fmt("{s}.pdb", .{name}),
335 .major_only_filename = null,
336 .name_only_filename = null,
337 .packages = ArrayList(Pkg).init(builder.allocator),
338 .include_dirs = ArrayList(IncludeDir).init(builder.allocator),
339 .link_objects = ArrayList(LinkObject).init(builder.allocator),
340 .c_macros = ArrayList([]const u8).init(builder.allocator),
341 .lib_paths = ArrayList([]const u8).init(builder.allocator),
342 .rpaths = ArrayList([]const u8).init(builder.allocator),
343 .framework_dirs = ArrayList([]const u8).init(builder.allocator),
344 .installed_headers = ArrayList(*Step).init(builder.allocator),
345 .object_src = undefined,
346 .c_std = std.Build.CStd.C99,
347 .override_lib_dir = null,
348 .main_pkg_path = null,
349 .exec_cmd_args = null,
350 .name_prefix = "",
351 .filter = null,
352 .test_runner = null,
353 .disable_stack_probing = false,
354 .disable_sanitize_c = false,
355 .sanitize_thread = false,
356 .rdynamic = false,
357 .output_dir = null,
358 .override_dest_dir = null,
359 .installed_path = null,
360 .install_step = null,
361
362 .output_path_source = GeneratedFile{ .step = &self.step },
363 .output_lib_path_source = GeneratedFile{ .step = &self.step },
364 .output_h_path_source = GeneratedFile{ .step = &self.step },
365 .output_pdb_path_source = GeneratedFile{ .step = &self.step },
366
367 .target_info = NativeTargetInfo.detect(self.target) catch unreachable,
368 };
369 self.computeOutFileNames();
370 if (root_src) |rs| rs.addStepDependencies(&self.step);
371 return self;
372}
373
374fn computeOutFileNames(self: *CompileStep) void {
375 const target = self.target_info.target;
376
377 self.out_filename = std.zig.binNameAlloc(self.builder.allocator, .{
378 .root_name = self.name,
379 .target = target,
380 .output_mode = switch (self.kind) {
381 .lib => .Lib,
382 .obj => .Obj,
383 .exe, .@"test", .test_exe => .Exe,
384 },
385 .link_mode = if (self.linkage) |some| @as(std.builtin.LinkMode, switch (some) {
386 .dynamic => .Dynamic,
387 .static => .Static,
388 }) else null,
389 .version = self.version,
390 }) catch unreachable;
391
392 if (self.kind == .lib) {
393 if (self.linkage != null and self.linkage.? == .static) {
394 self.out_lib_filename = self.out_filename;
395 } else if (self.version) |version| {
396 if (target.isDarwin()) {
397 self.major_only_filename = self.builder.fmt("lib{s}.{d}.dylib", .{
398 self.name,
399 version.major,
400 });
401 self.name_only_filename = self.builder.fmt("lib{s}.dylib", .{self.name});
402 self.out_lib_filename = self.out_filename;
403 } else if (target.os.tag == .windows) {
404 self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
405 } else {
406 self.major_only_filename = self.builder.fmt("lib{s}.so.{d}", .{ self.name, version.major });
407 self.name_only_filename = self.builder.fmt("lib{s}.so", .{self.name});
408 self.out_lib_filename = self.out_filename;
409 }
410 } else {
411 if (target.isDarwin()) {
412 self.out_lib_filename = self.out_filename;
413 } else if (target.os.tag == .windows) {
414 self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
415 } else {
416 self.out_lib_filename = self.out_filename;
417 }
418 }
419 if (self.output_dir != null) {
420 self.output_lib_path_source.path = self.builder.pathJoin(
421 &.{ self.output_dir.?, self.out_lib_filename },
422 );
423 }
424 }
425}
426
427pub fn setOutputDir(self: *CompileStep, dir: []const u8) void {
428 self.output_dir = self.builder.dupePath(dir);
429}
430
431pub fn install(self: *CompileStep) void {
432 self.builder.installArtifact(self);
433}
434
435pub fn installRaw(self: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
436 return self.builder.installRaw(self, dest_filename, options);
437}
438
439pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {
440 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);
441 a.builder.getInstallStep().dependOn(&install_file.step);
442 a.installed_headers.append(&install_file.step) catch unreachable;
443}
444
445pub fn installHeadersDirectory(
446 a: *CompileStep,
447 src_dir_path: []const u8,
448 dest_rel_path: []const u8,
449) void {
450 return installHeadersDirectoryOptions(a, .{
451 .source_dir = src_dir_path,
452 .install_dir = .header,
453 .install_subdir = dest_rel_path,
454 });
455}
456
457pub fn installHeadersDirectoryOptions(
458 a: *CompileStep,
459 options: std.Build.InstallDirStep.Options,
460) void {
461 const install_dir = a.builder.addInstallDirectory(options);
462 a.builder.getInstallStep().dependOn(&install_dir.step);
463 a.installed_headers.append(&install_dir.step) catch unreachable;
464}
465
466pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {
467 assert(l.kind == .lib);
468 const install_step = a.builder.getInstallStep();
469 // Copy each element from installed_headers, modifying the builder
470 // to be the new parent's builder.
471 for (l.installed_headers.items) |step| {
472 const step_copy = switch (step.id) {
473 inline .install_file, .install_dir => |id| blk: {
474 const T = id.Type();
475 const ptr = a.builder.allocator.create(T) catch unreachable;
476 ptr.* = step.cast(T).?.*;
477 ptr.override_source_builder = ptr.builder;
478 ptr.builder = a.builder;
479 break :blk &ptr.step;
480 },
481 else => unreachable,
482 };
483 a.installed_headers.append(step_copy) catch unreachable;
484 install_step.dependOn(step_copy);
485 }
486 a.installed_headers.appendSlice(l.installed_headers.items) catch unreachable;
487}
488
489/// Creates a `RunStep` with an executable built with `addExecutable`.
490/// Add command line arguments with `addArg`.
491pub fn run(exe: *CompileStep) *RunStep {
492 assert(exe.kind == .exe or exe.kind == .test_exe);
493
494 // It doesn't have to be native. We catch that if you actually try to run it.
495 // Consider that this is declarative; the run step may not be run unless a user
496 // option is supplied.
497 const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}));
498 run_step.addArtifactArg(exe);
499
500 if (exe.kind == .test_exe) {
501 run_step.addArg(exe.builder.zig_exe);
502 }
503
504 if (exe.vcpkg_bin_path) |path| {
505 run_step.addPathDir(path);
506 }
507
508 return run_step;
509}
510
511/// Creates an `EmulatableRunStep` with an executable built with `addExecutable`.
512/// Allows running foreign binaries through emulation platforms such as Qemu or Rosetta.
513/// When a binary cannot be ran through emulation or the option is disabled, a warning
514/// will be printed and the binary will *NOT* be ran.
515pub fn runEmulatable(exe: *CompileStep) *EmulatableRunStep {
516 assert(exe.kind == .exe or exe.kind == .test_exe);
517
518 const run_step = EmulatableRunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}), exe);
519 if (exe.vcpkg_bin_path) |path| {
520 RunStep.addPathDirInternal(&run_step.step, exe.builder, path);
521 }
522 return run_step;
523}
524
525pub fn checkObject(self: *CompileStep, obj_format: std.Target.ObjectFormat) *CheckObjectStep {
526 return CheckObjectStep.create(self.builder, self.getOutputSource(), obj_format);
527}
528
529pub fn setLinkerScriptPath(self: *CompileStep, source: FileSource) void {
530 self.linker_script = source.dupe(self.builder);
531 source.addStepDependencies(&self.step);
532}
533
534pub fn linkFramework(self: *CompileStep, framework_name: []const u8) void {
535 self.frameworks.put(self.builder.dupe(framework_name), .{}) catch unreachable;
536}
537
538pub fn linkFrameworkNeeded(self: *CompileStep, framework_name: []const u8) void {
539 self.frameworks.put(self.builder.dupe(framework_name), .{
540 .needed = true,
541 }) catch unreachable;
542}
543
544pub fn linkFrameworkWeak(self: *CompileStep, framework_name: []const u8) void {
545 self.frameworks.put(self.builder.dupe(framework_name), .{
546 .weak = true,
547 }) catch unreachable;
548}
549
550/// Returns whether the library, executable, or object depends on a particular system library.
551pub fn dependsOnSystemLibrary(self: CompileStep, name: []const u8) bool {
552 if (isLibCLibrary(name)) {
553 return self.is_linking_libc;
554 }
555 if (isLibCppLibrary(name)) {
556 return self.is_linking_libcpp;
557 }
558 for (self.link_objects.items) |link_object| {
559 switch (link_object) {
560 .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
561 else => continue,
562 }
563 }
564 return false;
565}
566
567pub fn linkLibrary(self: *CompileStep, lib: *CompileStep) void {
568 assert(lib.kind == .lib);
569 self.linkLibraryOrObject(lib);
570}
571
572pub fn isDynamicLibrary(self: *CompileStep) bool {
573 return self.kind == .lib and self.linkage == Linkage.dynamic;
574}
575
576pub fn isStaticLibrary(self: *CompileStep) bool {
577 return self.kind == .lib and self.linkage != Linkage.dynamic;
578}
579
580pub fn producesPdbFile(self: *CompileStep) bool {
581 if (!self.target.isWindows() and !self.target.isUefi()) return false;
582 if (self.target.getObjectFormat() == .c) return false;
583 if (self.strip == true) return false;
584 return self.isDynamicLibrary() or self.kind == .exe or self.kind == .test_exe;
585}
586
587pub fn linkLibC(self: *CompileStep) void {
588 self.is_linking_libc = true;
589}
590
591pub fn linkLibCpp(self: *CompileStep) void {
592 self.is_linking_libcpp = true;
593}
594
595/// If the value is omitted, it is set to 1.
596/// `name` and `value` need not live longer than the function call.
597pub fn defineCMacro(self: *CompileStep, name: []const u8, value: ?[]const u8) void {
598 const macro = std.Build.constructCMacro(self.builder.allocator, name, value);
599 self.c_macros.append(macro) catch unreachable;
600}
601
602/// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1.
603pub fn defineCMacroRaw(self: *CompileStep, name_and_value: []const u8) void {
604 self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable;
605}
606
607/// This one has no integration with anything, it just puts -lname on the command line.
608/// Prefer to use `linkSystemLibrary` instead.
609pub fn linkSystemLibraryName(self: *CompileStep, name: []const u8) void {
610 self.link_objects.append(.{
611 .system_lib = .{
612 .name = self.builder.dupe(name),
613 .needed = false,
614 .weak = false,
615 .use_pkg_config = .no,
616 },
617 }) catch unreachable;
618}
619
620/// This one has no integration with anything, it just puts -needed-lname on the command line.
621/// Prefer to use `linkSystemLibraryNeeded` instead.
622pub fn linkSystemLibraryNeededName(self: *CompileStep, name: []const u8) void {
623 self.link_objects.append(.{
624 .system_lib = .{
625 .name = self.builder.dupe(name),
626 .needed = true,
627 .weak = false,
628 .use_pkg_config = .no,
629 },
630 }) catch unreachable;
631}
632
633/// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the
634/// command line. Prefer to use `linkSystemLibraryWeak` instead.
635pub fn linkSystemLibraryWeakName(self: *CompileStep, name: []const u8) void {
636 self.link_objects.append(.{
637 .system_lib = .{
638 .name = self.builder.dupe(name),
639 .needed = false,
640 .weak = true,
641 .use_pkg_config = .no,
642 },
643 }) catch unreachable;
644}
645
646/// This links against a system library, exclusively using pkg-config to find the library.
647/// Prefer to use `linkSystemLibrary` instead.
648pub fn linkSystemLibraryPkgConfigOnly(self: *CompileStep, lib_name: []const u8) void {
649 self.link_objects.append(.{
650 .system_lib = .{
651 .name = self.builder.dupe(lib_name),
652 .needed = false,
653 .weak = false,
654 .use_pkg_config = .force,
655 },
656 }) catch unreachable;
657}
658
659/// This links against a system library, exclusively using pkg-config to find the library.
660/// Prefer to use `linkSystemLibraryNeeded` instead.
661pub fn linkSystemLibraryNeededPkgConfigOnly(self: *CompileStep, lib_name: []const u8) void {
662 self.link_objects.append(.{
663 .system_lib = .{
664 .name = self.builder.dupe(lib_name),
665 .needed = true,
666 .weak = false,
667 .use_pkg_config = .force,
668 },
669 }) catch unreachable;
670}
671
672/// Run pkg-config for the given library name and parse the output, returning the arguments
673/// that should be passed to zig to link the given library.
674pub fn runPkgConfig(self: *CompileStep, lib_name: []const u8) ![]const []const u8 {
675 const pkg_name = match: {
676 // First we have to map the library name to pkg config name. Unfortunately,
677 // there are several examples where this is not straightforward:
678 // -lSDL2 -> pkg-config sdl2
679 // -lgdk-3 -> pkg-config gdk-3.0
680 // -latk-1.0 -> pkg-config atk
681 const pkgs = try getPkgConfigList(self.builder);
682
683 // Exact match means instant winner.
684 for (pkgs) |pkg| {
685 if (mem.eql(u8, pkg.name, lib_name)) {
686 break :match pkg.name;
687 }
688 }
689
690 // Next we'll try ignoring case.
691 for (pkgs) |pkg| {
692 if (std.ascii.eqlIgnoreCase(pkg.name, lib_name)) {
693 break :match pkg.name;
694 }
695 }
696
697 // Now try appending ".0".
698 for (pkgs) |pkg| {
699 if (std.ascii.indexOfIgnoreCase(pkg.name, lib_name)) |pos| {
700 if (pos != 0) continue;
701 if (mem.eql(u8, pkg.name[lib_name.len..], ".0")) {
702 break :match pkg.name;
703 }
704 }
705 }
706
707 // Trimming "-1.0".
708 if (mem.endsWith(u8, lib_name, "-1.0")) {
709 const trimmed_lib_name = lib_name[0 .. lib_name.len - "-1.0".len];
710 for (pkgs) |pkg| {
711 if (std.ascii.eqlIgnoreCase(pkg.name, trimmed_lib_name)) {
712 break :match pkg.name;
713 }
714 }
715 }
716
717 return error.PackageNotFound;
718 };
719
720 var code: u8 = undefined;
721 const stdout = if (self.builder.execAllowFail(&[_][]const u8{
722 "pkg-config",
723 pkg_name,
724 "--cflags",
725 "--libs",
726 }, &code, .Ignore)) |stdout| stdout else |err| switch (err) {
727 error.ProcessTerminated => return error.PkgConfigCrashed,
728 error.ExecNotSupported => return error.PkgConfigFailed,
729 error.ExitCodeFailure => return error.PkgConfigFailed,
730 error.FileNotFound => return error.PkgConfigNotInstalled,
731 error.ChildExecFailed => return error.PkgConfigFailed,
732 else => return err,
733 };
734
735 var zig_args = ArrayList([]const u8).init(self.builder.allocator);
736 defer zig_args.deinit();
737
738 var it = mem.tokenize(u8, stdout, " \r\n\t");
739 while (it.next()) |tok| {
740 if (mem.eql(u8, tok, "-I")) {
741 const dir = it.next() orelse return error.PkgConfigInvalidOutput;
742 try zig_args.appendSlice(&[_][]const u8{ "-I", dir });
743 } else if (mem.startsWith(u8, tok, "-I")) {
744 try zig_args.append(tok);
745 } else if (mem.eql(u8, tok, "-L")) {
746 const dir = it.next() orelse return error.PkgConfigInvalidOutput;
747 try zig_args.appendSlice(&[_][]const u8{ "-L", dir });
748 } else if (mem.startsWith(u8, tok, "-L")) {
749 try zig_args.append(tok);
750 } else if (mem.eql(u8, tok, "-l")) {
751 const lib = it.next() orelse return error.PkgConfigInvalidOutput;
752 try zig_args.appendSlice(&[_][]const u8{ "-l", lib });
753 } else if (mem.startsWith(u8, tok, "-l")) {
754 try zig_args.append(tok);
755 } else if (mem.eql(u8, tok, "-D")) {
756 const macro = it.next() orelse return error.PkgConfigInvalidOutput;
757 try zig_args.appendSlice(&[_][]const u8{ "-D", macro });
758 } else if (mem.startsWith(u8, tok, "-D")) {
759 try zig_args.append(tok);
760 } else if (self.builder.verbose) {
761 log.warn("Ignoring pkg-config flag '{s}'", .{tok});
762 }
763 }
764
765 return zig_args.toOwnedSlice();
766}
767
768pub fn linkSystemLibrary(self: *CompileStep, name: []const u8) void {
769 self.linkSystemLibraryInner(name, .{});
770}
771
772pub fn linkSystemLibraryNeeded(self: *CompileStep, name: []const u8) void {
773 self.linkSystemLibraryInner(name, .{ .needed = true });
774}
775
776pub fn linkSystemLibraryWeak(self: *CompileStep, name: []const u8) void {
777 self.linkSystemLibraryInner(name, .{ .weak = true });
778}
779
780fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct {
781 needed: bool = false,
782 weak: bool = false,
783}) void {
784 if (isLibCLibrary(name)) {
785 self.linkLibC();
786 return;
787 }
788 if (isLibCppLibrary(name)) {
789 self.linkLibCpp();
790 return;
791 }
792
793 self.link_objects.append(.{
794 .system_lib = .{
795 .name = self.builder.dupe(name),
796 .needed = opts.needed,
797 .weak = opts.weak,
798 .use_pkg_config = .yes,
799 },
800 }) catch unreachable;
801}
802
803pub fn setNamePrefix(self: *CompileStep, text: []const u8) void {
804 assert(self.kind == .@"test" or self.kind == .test_exe);
805 self.name_prefix = self.builder.dupe(text);
806}
807
808pub fn setFilter(self: *CompileStep, text: ?[]const u8) void {
809 assert(self.kind == .@"test" or self.kind == .test_exe);
810 self.filter = if (text) |t| self.builder.dupe(t) else null;
811}
812
813pub fn setTestRunner(self: *CompileStep, path: ?[]const u8) void {
814 assert(self.kind == .@"test" or self.kind == .test_exe);
815 self.test_runner = if (path) |p| self.builder.dupePath(p) else null;
816}
817
818/// Handy when you have many C/C++ source files and want them all to have the same flags.
819pub fn addCSourceFiles(self: *CompileStep, files: []const []const u8, flags: []const []const u8) void {
820 const c_source_files = self.builder.allocator.create(CSourceFiles) catch unreachable;
821
822 const files_copy = self.builder.dupeStrings(files);
823 const flags_copy = self.builder.dupeStrings(flags);
824
825 c_source_files.* = .{
826 .files = files_copy,
827 .flags = flags_copy,
828 };
829 self.link_objects.append(.{ .c_source_files = c_source_files }) catch unreachable;
830}
831
832pub fn addCSourceFile(self: *CompileStep, file: []const u8, flags: []const []const u8) void {
833 self.addCSourceFileSource(.{
834 .args = flags,
835 .source = .{ .path = file },
836 });
837}
838
839pub fn addCSourceFileSource(self: *CompileStep, source: CSourceFile) void {
840 const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
841 c_source_file.* = source.dupe(self.builder);
842 self.link_objects.append(.{ .c_source_file = c_source_file }) catch unreachable;
843 source.source.addStepDependencies(&self.step);
844}
845
846pub fn setVerboseLink(self: *CompileStep, value: bool) void {
847 self.verbose_link = value;
848}
849
850pub fn setVerboseCC(self: *CompileStep, value: bool) void {
851 self.verbose_cc = value;
852}
853
854pub fn overrideZigLibDir(self: *CompileStep, dir_path: []const u8) void {
855 self.override_lib_dir = self.builder.dupePath(dir_path);
856}
857
858pub fn setMainPkgPath(self: *CompileStep, dir_path: []const u8) void {
859 self.main_pkg_path = self.builder.dupePath(dir_path);
860}
861
862pub fn setLibCFile(self: *CompileStep, libc_file: ?FileSource) void {
863 self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null;
864}
865
866/// Returns the generated executable, library or object file.
867/// To run an executable built with zig build, use `run`, or create an install step and invoke it.
868pub fn getOutputSource(self: *CompileStep) FileSource {
869 return FileSource{ .generated = &self.output_path_source };
870}
871
872/// Returns the generated import library. This function can only be called for libraries.
873pub fn getOutputLibSource(self: *CompileStep) FileSource {
874 assert(self.kind == .lib);
875 return FileSource{ .generated = &self.output_lib_path_source };
876}
877
878/// Returns the generated header file.
879/// This function can only be called for libraries or object files which have `emit_h` set.
880pub fn getOutputHSource(self: *CompileStep) FileSource {
881 assert(self.kind != .exe and self.kind != .test_exe and self.kind != .@"test");
882 assert(self.emit_h);
883 return FileSource{ .generated = &self.output_h_path_source };
884}
885
886/// Returns the generated PDB file. This function can only be called for Windows and UEFI.
887pub fn getOutputPdbSource(self: *CompileStep) FileSource {
888 // TODO: Is this right? Isn't PDB for *any* PE/COFF file?
889 assert(self.target.isWindows() or self.target.isUefi());
890 return FileSource{ .generated = &self.output_pdb_path_source };
891}
892
893pub fn addAssemblyFile(self: *CompileStep, path: []const u8) void {
894 self.link_objects.append(.{
895 .assembly_file = .{ .path = self.builder.dupe(path) },
896 }) catch unreachable;
897}
898
899pub fn addAssemblyFileSource(self: *CompileStep, source: FileSource) void {
900 const source_duped = source.dupe(self.builder);
901 self.link_objects.append(.{ .assembly_file = source_duped }) catch unreachable;
902 source_duped.addStepDependencies(&self.step);
903}
904
905pub fn addObjectFile(self: *CompileStep, source_file: []const u8) void {
906 self.addObjectFileSource(.{ .path = source_file });
907}
908
909pub fn addObjectFileSource(self: *CompileStep, source: FileSource) void {
910 self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch unreachable;
911 source.addStepDependencies(&self.step);
912}
913
914pub fn addObject(self: *CompileStep, obj: *CompileStep) void {
915 assert(obj.kind == .obj);
916 self.linkLibraryOrObject(obj);
917}
918
919pub const addSystemIncludeDir = @compileError("deprecated; use addSystemIncludePath");
920pub const addIncludeDir = @compileError("deprecated; use addIncludePath");
921pub const addLibPath = @compileError("deprecated, use addLibraryPath");
922pub const addFrameworkDir = @compileError("deprecated, use addFrameworkPath");
923
924pub fn addSystemIncludePath(self: *CompileStep, path: []const u8) void {
925 self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable;
926}
927
928pub fn addIncludePath(self: *CompileStep, path: []const u8) void {
929 self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch unreachable;
930}
931
932pub fn addConfigHeader(self: *CompileStep, config_header: *ConfigHeaderStep) void {
933 self.step.dependOn(&config_header.step);
934 self.include_dirs.append(.{ .config_header_step = config_header }) catch @panic("OOM");
935}
936
937pub fn addLibraryPath(self: *CompileStep, path: []const u8) void {
938 self.lib_paths.append(self.builder.dupe(path)) catch unreachable;
939}
940
941pub fn addRPath(self: *CompileStep, path: []const u8) void {
942 self.rpaths.append(self.builder.dupe(path)) catch unreachable;
943}
944
945pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void {
946 self.framework_dirs.append(self.builder.dupe(dir_path)) catch unreachable;
947}
948
949pub fn addPackage(self: *CompileStep, package: Pkg) void {
950 self.packages.append(self.builder.dupePkg(package)) catch unreachable;
951 self.addRecursiveBuildDeps(package);
952}
953
954pub fn addOptions(self: *CompileStep, package_name: []const u8, options: *OptionsStep) void {
955 self.addPackage(options.getPackage(package_name));
956}
957
958fn addRecursiveBuildDeps(self: *CompileStep, package: Pkg) void {
959 package.source.addStepDependencies(&self.step);
960 if (package.dependencies) |deps| {
961 for (deps) |dep| {
962 self.addRecursiveBuildDeps(dep);
963 }
964 }
965}
966
967pub fn addPackagePath(self: *CompileStep, name: []const u8, pkg_index_path: []const u8) void {
968 self.addPackage(Pkg{
969 .name = self.builder.dupe(name),
970 .source = .{ .path = self.builder.dupe(pkg_index_path) },
971 });
972}
973
974/// If Vcpkg was found on the system, it will be added to include and lib
975/// paths for the specified target.
976pub fn addVcpkgPaths(self: *CompileStep, linkage: CompileStep.Linkage) !void {
977 // Ideally in the Unattempted case we would call the function recursively
978 // after findVcpkgRoot and have only one switch statement, but the compiler
979 // cannot resolve the error set.
980 switch (self.builder.vcpkg_root) {
981 .unattempted => {
982 self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root|
983 VcpkgRoot{ .found = root }
984 else
985 .not_found;
986 },
987 .not_found => return error.VcpkgNotFound,
988 .found => {},
989 }
990
991 switch (self.builder.vcpkg_root) {
992 .unattempted => unreachable,
993 .not_found => return error.VcpkgNotFound,
994 .found => |root| {
995 const allocator = self.builder.allocator;
996 const triplet = try self.target.vcpkgTriplet(allocator, if (linkage == .static) .Static else .Dynamic);
997 defer self.builder.allocator.free(triplet);
998
999 const include_path = self.builder.pathJoin(&.{ root, "installed", triplet, "include" });
1000 errdefer allocator.free(include_path);
1001 try self.include_dirs.append(IncludeDir{ .raw_path = include_path });
1002
1003 const lib_path = self.builder.pathJoin(&.{ root, "installed", triplet, "lib" });
1004 try self.lib_paths.append(lib_path);
1005
1006 self.vcpkg_bin_path = self.builder.pathJoin(&.{ root, "installed", triplet, "bin" });
1007 },
1008 }
1009}
1010
1011pub fn setExecCmd(self: *CompileStep, args: []const ?[]const u8) void {
1012 assert(self.kind == .@"test");
1013 const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable;
1014 for (args) |arg, i| {
1015 duped_args[i] = if (arg) |a| self.builder.dupe(a) else null;
1016 }
1017 self.exec_cmd_args = duped_args;
1018}
1019
1020fn linkLibraryOrObject(self: *CompileStep, other: *CompileStep) void {
1021 self.step.dependOn(&other.step);
1022 self.link_objects.append(.{ .other_step = other }) catch unreachable;
1023 self.include_dirs.append(.{ .other_step = other }) catch unreachable;
1024}
1025
1026fn makePackageCmd(self: *CompileStep, pkg: Pkg, zig_args: *ArrayList([]const u8)) error{OutOfMemory}!void {
1027 const builder = self.builder;
1028
1029 try zig_args.append("--pkg-begin");
1030 try zig_args.append(pkg.name);
1031 try zig_args.append(builder.pathFromRoot(pkg.source.getPath(self.builder)));
1032
1033 if (pkg.dependencies) |dependencies| {
1034 for (dependencies) |sub_pkg| {
1035 try self.makePackageCmd(sub_pkg, zig_args);
1036 }
1037 }
1038
1039 try zig_args.append("--pkg-end");
1040}
1041
1042fn make(step: *Step) !void {
1043 const self = @fieldParentPtr(CompileStep, "step", step);
1044 const builder = self.builder;
1045
1046 if (self.root_src == null and self.link_objects.items.len == 0) {
1047 log.err("{s}: linker needs 1 or more objects to link", .{self.step.name});
1048 return error.NeedAnObject;
1049 }
1050
1051 var zig_args = ArrayList([]const u8).init(builder.allocator);
1052 defer zig_args.deinit();
1053
1054 zig_args.append(builder.zig_exe) catch unreachable;
1055
1056 const cmd = switch (self.kind) {
1057 .lib => "build-lib",
1058 .exe => "build-exe",
1059 .obj => "build-obj",
1060 .@"test" => "test",
1061 .test_exe => "test",
1062 };
1063 zig_args.append(cmd) catch unreachable;
1064
1065 if (builder.color != .auto) {
1066 try zig_args.append("--color");
1067 try zig_args.append(@tagName(builder.color));
1068 }
1069
1070 if (builder.reference_trace) |some| {
1071 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-freference-trace={d}", .{some}));
1072 }
1073
1074 try addFlag(&zig_args, "LLVM", self.use_llvm);
1075 try addFlag(&zig_args, "LLD", self.use_lld);
1076
1077 if (self.target.ofmt) |ofmt| {
1078 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
1079 }
1080
1081 if (self.entry_symbol_name) |entry| {
1082 try zig_args.append("--entry");
1083 try zig_args.append(entry);
1084 }
1085
1086 if (self.stack_size) |stack_size| {
1087 try zig_args.append("--stack");
1088 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "{}", .{stack_size}));
1089 }
1090
1091 if (self.root_src) |root_src| try zig_args.append(root_src.getPath(builder));
1092
1093 // We will add link objects from transitive dependencies, but we want to keep
1094 // all link objects in the same order provided.
1095 // This array is used to keep self.link_objects immutable.
1096 var transitive_deps: TransitiveDeps = .{
1097 .link_objects = ArrayList(LinkObject).init(builder.allocator),
1098 .seen_system_libs = StringHashMap(void).init(builder.allocator),
1099 .seen_steps = std.AutoHashMap(*const Step, void).init(builder.allocator),
1100 .is_linking_libcpp = self.is_linking_libcpp,
1101 .is_linking_libc = self.is_linking_libc,
1102 .frameworks = &self.frameworks,
1103 };
1104
1105 try transitive_deps.seen_steps.put(&self.step, {});
1106 try transitive_deps.add(self.link_objects.items);
1107
1108 var prev_has_extra_flags = false;
1109
1110 for (transitive_deps.link_objects.items) |link_object| {
1111 switch (link_object) {
1112 .static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
1113
1114 .other_step => |other| switch (other.kind) {
1115 .exe => @panic("Cannot link with an executable build artifact"),
1116 .test_exe => @panic("Cannot link with an executable build artifact"),
1117 .@"test" => @panic("Cannot link with a test"),
1118 .obj => {
1119 try zig_args.append(other.getOutputSource().getPath(builder));
1120 },
1121 .lib => l: {
1122 if (self.isStaticLibrary() and other.isStaticLibrary()) {
1123 // Avoid putting a static library inside a static library.
1124 break :l;
1125 }
1126
1127 const full_path_lib = other.getOutputLibSource().getPath(builder);
1128 try zig_args.append(full_path_lib);
1129
1130 if (other.linkage == Linkage.dynamic and !self.target.isWindows()) {
1131 if (fs.path.dirname(full_path_lib)) |dirname| {
1132 try zig_args.append("-rpath");
1133 try zig_args.append(dirname);
1134 }
1135 }
1136 },
1137 },
1138
1139 .system_lib => |system_lib| {
1140 const prefix: []const u8 = prefix: {
1141 if (system_lib.needed) break :prefix "-needed-l";
1142 if (system_lib.weak) {
1143 if (self.target.isDarwin()) break :prefix "-weak-l";
1144 log.warn("Weak library import used for a non-darwin target, this will be converted to normally library import `-lname`", .{});
1145 }
1146 break :prefix "-l";
1147 };
1148 switch (system_lib.use_pkg_config) {
1149 .no => try zig_args.append(builder.fmt("{s}{s}", .{ prefix, system_lib.name })),
1150 .yes, .force => {
1151 if (self.runPkgConfig(system_lib.name)) |args| {
1152 try zig_args.appendSlice(args);
1153 } else |err| switch (err) {
1154 error.PkgConfigInvalidOutput,
1155 error.PkgConfigCrashed,
1156 error.PkgConfigFailed,
1157 error.PkgConfigNotInstalled,
1158 error.PackageNotFound,
1159 => switch (system_lib.use_pkg_config) {
1160 .yes => {
1161 // pkg-config failed, so fall back to linking the library
1162 // by name directly.
1163 try zig_args.append(builder.fmt("{s}{s}", .{
1164 prefix,
1165 system_lib.name,
1166 }));
1167 },
1168 .force => {
1169 panic("pkg-config failed for library {s}", .{system_lib.name});
1170 },
1171 .no => unreachable,
1172 },
1173
1174 else => |e| return e,
1175 }
1176 },
1177 }
1178 },
1179
1180 .assembly_file => |asm_file| {
1181 if (prev_has_extra_flags) {
1182 try zig_args.append("-extra-cflags");
1183 try zig_args.append("--");
1184 prev_has_extra_flags = false;
1185 }
1186 try zig_args.append(asm_file.getPath(builder));
1187 },
1188
1189 .c_source_file => |c_source_file| {
1190 if (c_source_file.args.len == 0) {
1191 if (prev_has_extra_flags) {
1192 try zig_args.append("-cflags");
1193 try zig_args.append("--");
1194 prev_has_extra_flags = false;
1195 }
1196 } else {
1197 try zig_args.append("-cflags");
1198 for (c_source_file.args) |arg| {
1199 try zig_args.append(arg);
1200 }
1201 try zig_args.append("--");
1202 }
1203 try zig_args.append(c_source_file.source.getPath(builder));
1204 },
1205
1206 .c_source_files => |c_source_files| {
1207 if (c_source_files.flags.len == 0) {
1208 if (prev_has_extra_flags) {
1209 try zig_args.append("-cflags");
1210 try zig_args.append("--");
1211 prev_has_extra_flags = false;
1212 }
1213 } else {
1214 try zig_args.append("-cflags");
1215 for (c_source_files.flags) |flag| {
1216 try zig_args.append(flag);
1217 }
1218 try zig_args.append("--");
1219 }
1220 for (c_source_files.files) |file| {
1221 try zig_args.append(builder.pathFromRoot(file));
1222 }
1223 },
1224 }
1225 }
1226
1227 if (transitive_deps.is_linking_libcpp) {
1228 try zig_args.append("-lc++");
1229 }
1230
1231 if (transitive_deps.is_linking_libc) {
1232 try zig_args.append("-lc");
1233 }
1234
1235 if (self.image_base) |image_base| {
1236 try zig_args.append("--image-base");
1237 try zig_args.append(builder.fmt("0x{x}", .{image_base}));
1238 }
1239
1240 if (self.filter) |filter| {
1241 try zig_args.append("--test-filter");
1242 try zig_args.append(filter);
1243 }
1244
1245 if (self.test_evented_io) {
1246 try zig_args.append("--test-evented-io");
1247 }
1248
1249 if (self.name_prefix.len != 0) {
1250 try zig_args.append("--test-name-prefix");
1251 try zig_args.append(self.name_prefix);
1252 }
1253
1254 if (self.test_runner) |test_runner| {
1255 try zig_args.append("--test-runner");
1256 try zig_args.append(builder.pathFromRoot(test_runner));
1257 }
1258
1259 for (builder.debug_log_scopes) |log_scope| {
1260 try zig_args.append("--debug-log");
1261 try zig_args.append(log_scope);
1262 }
1263
1264 if (builder.debug_compile_errors) {
1265 try zig_args.append("--debug-compile-errors");
1266 }
1267
1268 if (builder.verbose_cimport) zig_args.append("--verbose-cimport") catch unreachable;
1269 if (builder.verbose_air) zig_args.append("--verbose-air") catch unreachable;
1270 if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable;
1271 if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable;
1272 if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable;
1273 if (builder.verbose_llvm_cpu_features) zig_args.append("--verbose-llvm-cpu-features") catch unreachable;
1274
1275 if (self.emit_analysis.getArg(builder, "emit-analysis")) |arg| try zig_args.append(arg);
1276 if (self.emit_asm.getArg(builder, "emit-asm")) |arg| try zig_args.append(arg);
1277 if (self.emit_bin.getArg(builder, "emit-bin")) |arg| try zig_args.append(arg);
1278 if (self.emit_docs.getArg(builder, "emit-docs")) |arg| try zig_args.append(arg);
1279 if (self.emit_implib.getArg(builder, "emit-implib")) |arg| try zig_args.append(arg);
1280 if (self.emit_llvm_bc.getArg(builder, "emit-llvm-bc")) |arg| try zig_args.append(arg);
1281 if (self.emit_llvm_ir.getArg(builder, "emit-llvm-ir")) |arg| try zig_args.append(arg);
1282
1283 if (self.emit_h) try zig_args.append("-femit-h");
1284
1285 try addFlag(&zig_args, "strip", self.strip);
1286 try addFlag(&zig_args, "unwind-tables", self.unwind_tables);
1287
1288 switch (self.compress_debug_sections) {
1289 .none => {},
1290 .zlib => try zig_args.append("--compress-debug-sections=zlib"),
1291 }
1292
1293 if (self.link_eh_frame_hdr) {
1294 try zig_args.append("--eh-frame-hdr");
1295 }
1296 if (self.link_emit_relocs) {
1297 try zig_args.append("--emit-relocs");
1298 }
1299 if (self.link_function_sections) {
1300 try zig_args.append("-ffunction-sections");
1301 }
1302 if (self.link_gc_sections) |x| {
1303 try zig_args.append(if (x) "--gc-sections" else "--no-gc-sections");
1304 }
1305 if (self.linker_allow_shlib_undefined) |x| {
1306 try zig_args.append(if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined");
1307 }
1308 if (self.link_z_notext) {
1309 try zig_args.append("-z");
1310 try zig_args.append("notext");
1311 }
1312 if (!self.link_z_relro) {
1313 try zig_args.append("-z");
1314 try zig_args.append("norelro");
1315 }
1316 if (self.link_z_lazy) {
1317 try zig_args.append("-z");
1318 try zig_args.append("lazy");
1319 }
1320 if (self.link_z_common_page_size) |size| {
1321 try zig_args.append("-z");
1322 try zig_args.append(builder.fmt("common-page-size={d}", .{size}));
1323 }
1324 if (self.link_z_max_page_size) |size| {
1325 try zig_args.append("-z");
1326 try zig_args.append(builder.fmt("max-page-size={d}", .{size}));
1327 }
1328
1329 if (self.libc_file) |libc_file| {
1330 try zig_args.append("--libc");
1331 try zig_args.append(libc_file.getPath(builder));
1332 } else if (builder.libc_file) |libc_file| {
1333 try zig_args.append("--libc");
1334 try zig_args.append(libc_file);
1335 }
1336
1337 switch (self.optimize) {
1338 .Debug => {}, // Skip since it's the default.
1339 else => zig_args.append(builder.fmt("-O{s}", .{@tagName(self.optimize)})) catch unreachable,
1340 }
1341
1342 try zig_args.append("--cache-dir");
1343 try zig_args.append(builder.pathFromRoot(builder.cache_root));
1344
1345 try zig_args.append("--global-cache-dir");
1346 try zig_args.append(builder.pathFromRoot(builder.global_cache_root));
1347
1348 zig_args.append("--name") catch unreachable;
1349 zig_args.append(self.name) catch unreachable;
1350
1351 if (self.linkage) |some| switch (some) {
1352 .dynamic => try zig_args.append("-dynamic"),
1353 .static => try zig_args.append("-static"),
1354 };
1355 if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic) {
1356 if (self.version) |version| {
1357 zig_args.append("--version") catch unreachable;
1358 zig_args.append(builder.fmt("{}", .{version})) catch unreachable;
1359 }
1360
1361 if (self.target.isDarwin()) {
1362 const install_name = self.install_name orelse builder.fmt("@rpath/{s}{s}{s}", .{
1363 self.target.libPrefix(),
1364 self.name,
1365 self.target.dynamicLibSuffix(),
1366 });
1367 try zig_args.append("-install_name");
1368 try zig_args.append(install_name);
1369 }
1370 }
1371
1372 if (self.entitlements) |entitlements| {
1373 try zig_args.appendSlice(&[_][]const u8{ "--entitlements", entitlements });
1374 }
1375 if (self.pagezero_size) |pagezero_size| {
1376 const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{pagezero_size});
1377 try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });
1378 }
1379 if (self.search_strategy) |strat| switch (strat) {
1380 .paths_first => try zig_args.append("-search_paths_first"),
1381 .dylibs_first => try zig_args.append("-search_dylibs_first"),
1382 };
1383 if (self.headerpad_size) |headerpad_size| {
1384 const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{headerpad_size});
1385 try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size });
1386 }
1387 if (self.headerpad_max_install_names) {
1388 try zig_args.append("-headerpad_max_install_names");
1389 }
1390 if (self.dead_strip_dylibs) {
1391 try zig_args.append("-dead_strip_dylibs");
1392 }
1393
1394 try addFlag(&zig_args, "compiler-rt", self.bundle_compiler_rt);
1395 try addFlag(&zig_args, "single-threaded", self.single_threaded);
1396 if (self.disable_stack_probing) {
1397 try zig_args.append("-fno-stack-check");
1398 }
1399 try addFlag(&zig_args, "stack-protector", self.stack_protector);
1400 if (self.red_zone) |red_zone| {
1401 if (red_zone) {
1402 try zig_args.append("-mred-zone");
1403 } else {
1404 try zig_args.append("-mno-red-zone");
1405 }
1406 }
1407 try addFlag(&zig_args, "omit-frame-pointer", self.omit_frame_pointer);
1408 try addFlag(&zig_args, "dll-export-fns", self.dll_export_fns);
1409
1410 if (self.disable_sanitize_c) {
1411 try zig_args.append("-fno-sanitize-c");
1412 }
1413 if (self.sanitize_thread) {
1414 try zig_args.append("-fsanitize-thread");
1415 }
1416 if (self.rdynamic) {
1417 try zig_args.append("-rdynamic");
1418 }
1419 if (self.import_memory) {
1420 try zig_args.append("--import-memory");
1421 }
1422 if (self.import_symbols) {
1423 try zig_args.append("--import-symbols");
1424 }
1425 if (self.import_table) {
1426 try zig_args.append("--import-table");
1427 }
1428 if (self.export_table) {
1429 try zig_args.append("--export-table");
1430 }
1431 if (self.initial_memory) |initial_memory| {
1432 try zig_args.append(builder.fmt("--initial-memory={d}", .{initial_memory}));
1433 }
1434 if (self.max_memory) |max_memory| {
1435 try zig_args.append(builder.fmt("--max-memory={d}", .{max_memory}));
1436 }
1437 if (self.shared_memory) {
1438 try zig_args.append("--shared-memory");
1439 }
1440 if (self.global_base) |global_base| {
1441 try zig_args.append(builder.fmt("--global-base={d}", .{global_base}));
1442 }
1443
1444 if (self.code_model != .default) {
1445 try zig_args.append("-mcmodel");
1446 try zig_args.append(@tagName(self.code_model));
1447 }
1448 if (self.wasi_exec_model) |model| {
1449 try zig_args.append(builder.fmt("-mexec-model={s}", .{@tagName(model)}));
1450 }
1451 for (self.export_symbol_names) |symbol_name| {
1452 try zig_args.append(builder.fmt("--export={s}", .{symbol_name}));
1453 }
1454
1455 if (!self.target.isNative()) {
1456 try zig_args.appendSlice(&.{
1457 "-target", try self.target.zigTriple(builder.allocator),
1458 "-mcpu", try std.Build.serializeCpu(builder.allocator, self.target.getCpu()),
1459 });
1460
1461 if (self.target.dynamic_linker.get()) |dynamic_linker| {
1462 try zig_args.append("--dynamic-linker");
1463 try zig_args.append(dynamic_linker);
1464 }
1465 }
1466
1467 if (self.linker_script) |linker_script| {
1468 try zig_args.append("--script");
1469 try zig_args.append(linker_script.getPath(builder));
1470 }
1471
1472 if (self.version_script) |version_script| {
1473 try zig_args.append("--version-script");
1474 try zig_args.append(builder.pathFromRoot(version_script));
1475 }
1476
1477 if (self.kind == .@"test") {
1478 if (self.exec_cmd_args) |exec_cmd_args| {
1479 for (exec_cmd_args) |cmd_arg| {
1480 if (cmd_arg) |arg| {
1481 try zig_args.append("--test-cmd");
1482 try zig_args.append(arg);
1483 } else {
1484 try zig_args.append("--test-cmd-bin");
1485 }
1486 }
1487 } else {
1488 const need_cross_glibc = self.target.isGnuLibC() and transitive_deps.is_linking_libc;
1489
1490 switch (builder.host.getExternalExecutor(self.target_info, .{
1491 .qemu_fixes_dl = need_cross_glibc and builder.glibc_runtimes_dir != null,
1492 .link_libc = transitive_deps.is_linking_libc,
1493 })) {
1494 .native => {},
1495 .bad_dl, .bad_os_or_cpu => {
1496 try zig_args.append("--test-no-exec");
1497 },
1498 .rosetta => if (builder.enable_rosetta) {
1499 try zig_args.append("--test-cmd-bin");
1500 } else {
1501 try zig_args.append("--test-no-exec");
1502 },
1503 .qemu => |bin_name| ok: {
1504 if (builder.enable_qemu) qemu: {
1505 const glibc_dir_arg = if (need_cross_glibc)
1506 builder.glibc_runtimes_dir orelse break :qemu
1507 else
1508 null;
1509 try zig_args.append("--test-cmd");
1510 try zig_args.append(bin_name);
1511 if (glibc_dir_arg) |dir| {
1512 // TODO look into making this a call to `linuxTriple`. This
1513 // needs the directory to be called "i686" rather than
1514 // "x86" which is why we do it manually here.
1515 const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}";
1516 const cpu_arch = self.target.getCpuArch();
1517 const os_tag = self.target.getOsTag();
1518 const abi = self.target.getAbi();
1519 const cpu_arch_name: []const u8 = if (cpu_arch == .x86)
1520 "i686"
1521 else
1522 @tagName(cpu_arch);
1523 const full_dir = try std.fmt.allocPrint(builder.allocator, fmt_str, .{
1524 dir, cpu_arch_name, @tagName(os_tag), @tagName(abi),
1525 });
1526
1527 try zig_args.append("--test-cmd");
1528 try zig_args.append("-L");
1529 try zig_args.append("--test-cmd");
1530 try zig_args.append(full_dir);
1531 }
1532 try zig_args.append("--test-cmd-bin");
1533 break :ok;
1534 }
1535 try zig_args.append("--test-no-exec");
1536 },
1537 .wine => |bin_name| if (builder.enable_wine) {
1538 try zig_args.append("--test-cmd");
1539 try zig_args.append(bin_name);
1540 try zig_args.append("--test-cmd-bin");
1541 } else {
1542 try zig_args.append("--test-no-exec");
1543 },
1544 .wasmtime => |bin_name| if (builder.enable_wasmtime) {
1545 try zig_args.append("--test-cmd");
1546 try zig_args.append(bin_name);
1547 try zig_args.append("--test-cmd");
1548 try zig_args.append("--dir=.");
1549 try zig_args.append("--test-cmd-bin");
1550 } else {
1551 try zig_args.append("--test-no-exec");
1552 },
1553 .darling => |bin_name| if (builder.enable_darling) {
1554 try zig_args.append("--test-cmd");
1555 try zig_args.append(bin_name);
1556 try zig_args.append("--test-cmd-bin");
1557 } else {
1558 try zig_args.append("--test-no-exec");
1559 },
1560 }
1561 }
1562 } else if (self.kind == .test_exe) {
1563 try zig_args.append("--test-no-exec");
1564 }
1565
1566 for (self.packages.items) |pkg| {
1567 try self.makePackageCmd(pkg, &zig_args);
1568 }
1569
1570 for (self.include_dirs.items) |include_dir| {
1571 switch (include_dir) {
1572 .raw_path => |include_path| {
1573 try zig_args.append("-I");
1574 try zig_args.append(builder.pathFromRoot(include_path));
1575 },
1576 .raw_path_system => |include_path| {
1577 if (builder.sysroot != null) {
1578 try zig_args.append("-iwithsysroot");
1579 } else {
1580 try zig_args.append("-isystem");
1581 }
1582
1583 const resolved_include_path = builder.pathFromRoot(include_path);
1584
1585 const common_include_path = if (builtin.os.tag == .windows and builder.sysroot != null and fs.path.isAbsolute(resolved_include_path)) blk: {
1586 // We need to check for disk designator and strip it out from dir path so
1587 // that zig/clang can concat resolved_include_path with sysroot.
1588 const disk_designator = fs.path.diskDesignatorWindows(resolved_include_path);
1589
1590 if (mem.indexOf(u8, resolved_include_path, disk_designator)) |where| {
1591 break :blk resolved_include_path[where + disk_designator.len ..];
1592 }
1593
1594 break :blk resolved_include_path;
1595 } else resolved_include_path;
1596
1597 try zig_args.append(common_include_path);
1598 },
1599 .other_step => |other| {
1600 if (other.emit_h) {
1601 const h_path = other.getOutputHSource().getPath(builder);
1602 try zig_args.append("-isystem");
1603 try zig_args.append(fs.path.dirname(h_path).?);
1604 }
1605 if (other.installed_headers.items.len > 0) {
1606 for (other.installed_headers.items) |install_step| {
1607 try install_step.make();
1608 }
1609 try zig_args.append("-I");
1610 try zig_args.append(builder.pathJoin(&.{
1611 other.builder.install_prefix, "include",
1612 }));
1613 }
1614 },
1615 .config_header_step => |config_header| {
1616 try zig_args.append("-I");
1617 try zig_args.append(config_header.output_dir);
1618 },
1619 }
1620 }
1621
1622 for (self.lib_paths.items) |lib_path| {
1623 try zig_args.append("-L");
1624 try zig_args.append(lib_path);
1625 }
1626
1627 for (self.rpaths.items) |rpath| {
1628 try zig_args.append("-rpath");
1629 try zig_args.append(rpath);
1630 }
1631
1632 for (self.c_macros.items) |c_macro| {
1633 try zig_args.append("-D");
1634 try zig_args.append(c_macro);
1635 }
1636
1637 if (self.target.isDarwin()) {
1638 for (self.framework_dirs.items) |dir| {
1639 if (builder.sysroot != null) {
1640 try zig_args.append("-iframeworkwithsysroot");
1641 } else {
1642 try zig_args.append("-iframework");
1643 }
1644 try zig_args.append(dir);
1645 try zig_args.append("-F");
1646 try zig_args.append(dir);
1647 }
1648
1649 var it = self.frameworks.iterator();
1650 while (it.next()) |entry| {
1651 const name = entry.key_ptr.*;
1652 const info = entry.value_ptr.*;
1653 if (info.needed) {
1654 zig_args.append("-needed_framework") catch unreachable;
1655 } else if (info.weak) {
1656 zig_args.append("-weak_framework") catch unreachable;
1657 } else {
1658 zig_args.append("-framework") catch unreachable;
1659 }
1660 zig_args.append(name) catch unreachable;
1661 }
1662 } else {
1663 if (self.framework_dirs.items.len > 0) {
1664 log.info("Framework directories have been added for a non-darwin target, this will have no affect on the build", .{});
1665 }
1666
1667 if (self.frameworks.count() > 0) {
1668 log.info("Frameworks have been added for a non-darwin target, this will have no affect on the build", .{});
1669 }
1670 }
1671
1672 if (builder.sysroot) |sysroot| {
1673 try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });
1674 }
1675
1676 for (builder.search_prefixes.items) |search_prefix| {
1677 try zig_args.append("-L");
1678 try zig_args.append(builder.pathJoin(&.{
1679 search_prefix, "lib",
1680 }));
1681 try zig_args.append("-I");
1682 try zig_args.append(builder.pathJoin(&.{
1683 search_prefix, "include",
1684 }));
1685 }
1686
1687 try addFlag(&zig_args, "valgrind", self.valgrind_support);
1688 try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
1689 try addFlag(&zig_args, "build-id", self.build_id);
1690
1691 if (self.override_lib_dir) |dir| {
1692 try zig_args.append("--zig-lib-dir");
1693 try zig_args.append(builder.pathFromRoot(dir));
1694 } else if (builder.override_lib_dir) |dir| {
1695 try zig_args.append("--zig-lib-dir");
1696 try zig_args.append(builder.pathFromRoot(dir));
1697 }
1698
1699 if (self.main_pkg_path) |dir| {
1700 try zig_args.append("--main-pkg-path");
1701 try zig_args.append(builder.pathFromRoot(dir));
1702 }
1703
1704 try addFlag(&zig_args, "PIC", self.force_pic);
1705 try addFlag(&zig_args, "PIE", self.pie);
1706 try addFlag(&zig_args, "lto", self.want_lto);
1707
1708 if (self.subsystem) |subsystem| {
1709 try zig_args.append("--subsystem");
1710 try zig_args.append(switch (subsystem) {
1711 .Console => "console",
1712 .Windows => "windows",
1713 .Posix => "posix",
1714 .Native => "native",
1715 .EfiApplication => "efi_application",
1716 .EfiBootServiceDriver => "efi_boot_service_driver",
1717 .EfiRom => "efi_rom",
1718 .EfiRuntimeDriver => "efi_runtime_driver",
1719 });
1720 }
1721
1722 try zig_args.append("--enable-cache");
1723
1724 // Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux
1725 // 2,097,152. If our args exceed 30 KiB, we instead write them to a "response file" and
1726 // pass that to zig, e.g. via 'zig build-lib @args.rsp'
1727 // See @file syntax here: https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html
1728 var args_length: usize = 0;
1729 for (zig_args.items) |arg| {
1730 args_length += arg.len + 1; // +1 to account for null terminator
1731 }
1732 if (args_length >= 30 * 1024) {
1733 const args_dir = try fs.path.join(
1734 builder.allocator,
1735 &[_][]const u8{ builder.pathFromRoot("zig-cache"), "args" },
1736 );
1737 try std.fs.cwd().makePath(args_dir);
1738
1739 var args_arena = std.heap.ArenaAllocator.init(builder.allocator);
1740 defer args_arena.deinit();
1741
1742 const args_to_escape = zig_args.items[2..];
1743 var escaped_args = try ArrayList([]const u8).initCapacity(args_arena.allocator(), args_to_escape.len);
1744
1745 arg_blk: for (args_to_escape) |arg| {
1746 for (arg) |c, arg_idx| {
1747 if (c == '\\' or c == '"') {
1748 // Slow path for arguments that need to be escaped. We'll need to allocate and copy
1749 var escaped = try ArrayList(u8).initCapacity(args_arena.allocator(), arg.len + 1);
1750 const writer = escaped.writer();
1751 writer.writeAll(arg[0..arg_idx]) catch unreachable;
1752 for (arg[arg_idx..]) |to_escape| {
1753 if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\');
1754 try writer.writeByte(to_escape);
1755 }
1756 escaped_args.appendAssumeCapacity(escaped.items);
1757 continue :arg_blk;
1758 }
1759 }
1760 escaped_args.appendAssumeCapacity(arg); // no escaping needed so just use original argument
1761 }
1762
1763 // Write the args to zig-cache/args/<SHA256 hash of args> to avoid conflicts with
1764 // other zig build commands running in parallel.
1765 const partially_quoted = try std.mem.join(builder.allocator, "\" \"", escaped_args.items);
1766 const args = try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "\"", partially_quoted, "\"" });
1767
1768 var args_hash: [Sha256.digest_length]u8 = undefined;
1769 Sha256.hash(args, &args_hash, .{});
1770 var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined;
1771 _ = try std.fmt.bufPrint(
1772 &args_hex_hash,
1773 "{s}",
1774 .{std.fmt.fmtSliceHexLower(&args_hash)},
1775 );
1776
1777 const args_file = try fs.path.join(builder.allocator, &[_][]const u8{ args_dir, args_hex_hash[0..] });
1778 try std.fs.cwd().writeFile(args_file, args);
1779
1780 zig_args.shrinkRetainingCapacity(2);
1781 try zig_args.append(try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "@", args_file }));
1782 }
1783
1784 const output_dir_nl = try builder.execFromStep(zig_args.items, &self.step);
1785 const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n");
1786
1787 if (self.output_dir) |output_dir| {
1788 var src_dir = try std.fs.cwd().openIterableDir(build_output_dir, .{});
1789 defer src_dir.close();
1790
1791 // Create the output directory if it doesn't exist.
1792 try std.fs.cwd().makePath(output_dir);
1793
1794 var dest_dir = try std.fs.cwd().openDir(output_dir, .{});
1795 defer dest_dir.close();
1796
1797 var it = src_dir.iterate();
1798 while (try it.next()) |entry| {
1799 // The compiler can put these files into the same directory, but we don't
1800 // want to copy them over.
1801 if (mem.eql(u8, entry.name, "llvm-ar.id") or
1802 mem.eql(u8, entry.name, "libs.txt") or
1803 mem.eql(u8, entry.name, "builtin.zig") or
1804 mem.eql(u8, entry.name, "zld.id") or
1805 mem.eql(u8, entry.name, "lld.id")) continue;
1806
1807 _ = try src_dir.dir.updateFile(entry.name, dest_dir, entry.name, .{});
1808 }
1809 } else {
1810 self.output_dir = build_output_dir;
1811 }
1812
1813 // This will ensure all output filenames will now have the output_dir available!
1814 self.computeOutFileNames();
1815
1816 // Update generated files
1817 if (self.output_dir != null) {
1818 self.output_path_source.path = builder.pathJoin(
1819 &.{ self.output_dir.?, self.out_filename },
1820 );
1821
1822 if (self.emit_h) {
1823 self.output_h_path_source.path = builder.pathJoin(
1824 &.{ self.output_dir.?, self.out_h_filename },
1825 );
1826 }
1827
1828 if (self.target.isWindows() or self.target.isUefi()) {
1829 self.output_pdb_path_source.path = builder.pathJoin(
1830 &.{ self.output_dir.?, self.out_pdb_filename },
1831 );
1832 }
1833 }
1834
1835 if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) {
1836 try doAtomicSymLinks(builder.allocator, self.getOutputSource().getPath(builder), self.major_only_filename.?, self.name_only_filename.?);
1837 }
1838}
1839
1840fn isLibCLibrary(name: []const u8) bool {
1841 const libc_libraries = [_][]const u8{ "c", "m", "dl", "rt", "pthread" };
1842 for (libc_libraries) |libc_lib_name| {
1843 if (mem.eql(u8, name, libc_lib_name))
1844 return true;
1845 }
1846 return false;
1847}
1848
1849fn isLibCppLibrary(name: []const u8) bool {
1850 const libcpp_libraries = [_][]const u8{ "c++", "stdc++" };
1851 for (libcpp_libraries) |libcpp_lib_name| {
1852 if (mem.eql(u8, name, libcpp_lib_name))
1853 return true;
1854 }
1855 return false;
1856}
1857
1858/// Returned slice must be freed by the caller.
1859fn findVcpkgRoot(allocator: Allocator) !?[]const u8 {
1860 const appdata_path = try fs.getAppDataDir(allocator, "vcpkg");
1861 defer allocator.free(appdata_path);
1862
1863 const path_file = try fs.path.join(allocator, &[_][]const u8{ appdata_path, "vcpkg.path.txt" });
1864 defer allocator.free(path_file);
1865
1866 const file = fs.cwd().openFile(path_file, .{}) catch return null;
1867 defer file.close();
1868
1869 const size = @intCast(usize, try file.getEndPos());
1870 const vcpkg_path = try allocator.alloc(u8, size);
1871 const size_read = try file.read(vcpkg_path);
1872 std.debug.assert(size == size_read);
1873
1874 return vcpkg_path;
1875}
1876
1877pub fn doAtomicSymLinks(allocator: Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
1878 const out_dir = fs.path.dirname(output_path) orelse ".";
1879 const out_basename = fs.path.basename(output_path);
1880 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1881 const major_only_path = fs.path.join(
1882 allocator,
1883 &[_][]const u8{ out_dir, filename_major_only },
1884 ) catch unreachable;
1885 fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
1886 log.err("Unable to symlink {s} -> {s}", .{ major_only_path, out_basename });
1887 return err;
1888 };
1889 // sym link for libfoo.so to libfoo.so.1
1890 const name_only_path = fs.path.join(
1891 allocator,
1892 &[_][]const u8{ out_dir, filename_name_only },
1893 ) catch unreachable;
1894 fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
1895 log.err("Unable to symlink {s} -> {s}", .{ name_only_path, filename_major_only });
1896 return err;
1897 };
1898}
1899
1900fn execPkgConfigList(self: *std.Build, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg {
1901 const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore);
1902 var list = ArrayList(PkgConfigPkg).init(self.allocator);
1903 errdefer list.deinit();
1904 var line_it = mem.tokenize(u8, stdout, "\r\n");
1905 while (line_it.next()) |line| {
1906 if (mem.trim(u8, line, " \t").len == 0) continue;
1907 var tok_it = mem.tokenize(u8, line, " \t");
1908 try list.append(PkgConfigPkg{
1909 .name = tok_it.next() orelse return error.PkgConfigInvalidOutput,
1910 .desc = tok_it.rest(),
1911 });
1912 }
1913 return list.toOwnedSlice();
1914}
1915
1916fn getPkgConfigList(self: *std.Build) ![]const PkgConfigPkg {
1917 if (self.pkg_config_pkg_list) |res| {
1918 return res;
1919 }
1920 var code: u8 = undefined;
1921 if (execPkgConfigList(self, &code)) |list| {
1922 self.pkg_config_pkg_list = list;
1923 return list;
1924 } else |err| {
1925 const result = switch (err) {
1926 error.ProcessTerminated => error.PkgConfigCrashed,
1927 error.ExecNotSupported => error.PkgConfigFailed,
1928 error.ExitCodeFailure => error.PkgConfigFailed,
1929 error.FileNotFound => error.PkgConfigNotInstalled,
1930 error.InvalidName => error.PkgConfigNotInstalled,
1931 error.PkgConfigInvalidOutput => error.PkgConfigInvalidOutput,
1932 error.ChildExecFailed => error.PkgConfigFailed,
1933 else => return err,
1934 };
1935 self.pkg_config_pkg_list = result;
1936 return result;
1937 }
1938}
1939
1940test "addPackage" {
1941 if (builtin.os.tag == .wasi) return error.SkipZigTest;
1942
1943 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
1944 defer arena.deinit();
1945
1946 const host = try NativeTargetInfo.detect(.{});
1947
1948 var builder = try std.Build.create(
1949 arena.allocator(),
1950 "test",
1951 "test",
1952 "test",
1953 "test",
1954 host,
1955 );
1956 defer builder.destroy();
1957
1958 const pkg_dep = Pkg{
1959 .name = "pkg_dep",
1960 .source = .{ .path = "/not/a/pkg_dep.zig" },
1961 };
1962 const pkg_top = Pkg{
1963 .name = "pkg_dep",
1964 .source = .{ .path = "/not/a/pkg_top.zig" },
1965 .dependencies = &[_]Pkg{pkg_dep},
1966 };
1967
1968 var exe = builder.addExecutable("not_an_executable", "/not/an/executable.zig");
1969 exe.addPackage(pkg_top);
1970
1971 try std.testing.expectEqual(@as(usize, 1), exe.packages.items.len);
1972
1973 const dupe = exe.packages.items[0];
1974 try std.testing.expectEqualStrings(pkg_top.name, dupe.name);
1975}
1976
1977fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool) !void {
1978 const cond = opt orelse return;
1979 try args.ensureUnusedCapacity(1);
1980 if (cond) {
1981 args.appendAssumeCapacity("-f" ++ name);
1982 } else {
1983 args.appendAssumeCapacity("-fno-" ++ name);
1984 }
1985}
1986
1987const TransitiveDeps = struct {
1988 link_objects: ArrayList(LinkObject),
1989 seen_system_libs: StringHashMap(void),
1990 seen_steps: std.AutoHashMap(*const Step, void),
1991 is_linking_libcpp: bool,
1992 is_linking_libc: bool,
1993 frameworks: *StringHashMap(FrameworkLinkInfo),
1994
1995 fn add(td: *TransitiveDeps, link_objects: []const LinkObject) !void {
1996 try td.link_objects.ensureUnusedCapacity(link_objects.len);
1997
1998 for (link_objects) |link_object| {
1999 try td.link_objects.append(link_object);
2000 switch (link_object) {
2001 .other_step => |other| try addInner(td, other, other.isDynamicLibrary()),
2002 else => {},
2003 }
2004 }
2005 }
2006
2007 fn addInner(td: *TransitiveDeps, other: *CompileStep, dyn: bool) !void {
2008 // Inherit dependency on libc and libc++
2009 td.is_linking_libcpp = td.is_linking_libcpp or other.is_linking_libcpp;
2010 td.is_linking_libc = td.is_linking_libc or other.is_linking_libc;
2011
2012 // Inherit dependencies on darwin frameworks
2013 if (!dyn) {
2014 var it = other.frameworks.iterator();
2015 while (it.next()) |framework| {
2016 try td.frameworks.put(framework.key_ptr.*, framework.value_ptr.*);
2017 }
2018 }
2019
2020 // Inherit dependencies on system libraries and static libraries.
2021 for (other.link_objects.items) |other_link_object| {
2022 switch (other_link_object) {
2023 .system_lib => |system_lib| {
2024 if ((try td.seen_system_libs.fetchPut(system_lib.name, {})) != null)
2025 continue;
2026
2027 if (dyn)
2028 continue;
2029
2030 try td.link_objects.append(other_link_object);
2031 },
2032 .other_step => |inner_other| {
2033 if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)
2034 continue;
2035
2036 if (!dyn)
2037 try td.link_objects.append(other_link_object);
2038
2039 try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());
2040 },
2041 else => continue,
2042 }
2043 }
2044 }
2045};
lib/std/Build/EmulatableRunStep.zig+3-3
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
66
7const std = @import("../std.zig");7const std = @import("../std.zig");
8const Step = std.Build.Step;8const Step = std.Build.Step;
9const LibExeObjStep = std.Build.LibExeObjStep;9const CompileStep = std.Build.CompileStep;
10const RunStep = std.Build.RunStep;10const RunStep = std.Build.RunStep;
1111
12const fs = std.fs;12const fs = std.fs;
...@@ -23,7 +23,7 @@ step: Step,...@@ -23,7 +23,7 @@ step: Step,
23builder: *std.Build,23builder: *std.Build,
2424
25/// The artifact (executable) to be run by this step25/// The artifact (executable) to be run by this step
26exe: *LibExeObjStep,26exe: *CompileStep,
2727
28/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution28/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution
29expected_exit_code: ?u8 = 0,29expected_exit_code: ?u8 = 0,
...@@ -45,7 +45,7 @@ hide_foreign_binaries_warning: bool,...@@ -45,7 +45,7 @@ hide_foreign_binaries_warning: bool,
45/// binary through emulation when any of the emulation options such as `enable_rosetta` are set to true.45/// binary through emulation when any of the emulation options such as `enable_rosetta` are set to true.
46/// When set to false, and the binary is foreign, running the executable is skipped.46/// When set to false, and the binary is foreign, running the executable is skipped.
47/// Asserts given artifact is an executable.47/// Asserts given artifact is an executable.
48pub fn create(builder: *std.Build, name: []const u8, artifact: *LibExeObjStep) *EmulatableRunStep {48pub fn create(builder: *std.Build, name: []const u8, artifact: *CompileStep) *EmulatableRunStep {
49 std.debug.assert(artifact.kind == .exe or artifact.kind == .test_exe);49 std.debug.assert(artifact.kind == .exe or artifact.kind == .test_exe);
50 const self = builder.allocator.create(EmulatableRunStep) catch unreachable;50 const self = builder.allocator.create(EmulatableRunStep) catch unreachable;
5151
lib/std/Build/InstallArtifactStep.zig+4-4
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const Step = std.Build.Step;2const Step = std.Build.Step;
3const LibExeObjStep = std.Build.LibExeObjStep;3const CompileStep = std.Build.CompileStep;
4const InstallDir = std.Build.InstallDir;4const InstallDir = std.Build.InstallDir;
5const InstallArtifactStep = @This();5const InstallArtifactStep = @This();
66
...@@ -8,12 +8,12 @@ pub const base_id = .install_artifact;...@@ -8,12 +8,12 @@ pub const base_id = .install_artifact;
88
9step: Step,9step: Step,
10builder: *std.Build,10builder: *std.Build,
11artifact: *LibExeObjStep,11artifact: *CompileStep,
12dest_dir: InstallDir,12dest_dir: InstallDir,
13pdb_dir: ?InstallDir,13pdb_dir: ?InstallDir,
14h_dir: ?InstallDir,14h_dir: ?InstallDir,
1515
16pub fn create(builder: *std.Build, artifact: *LibExeObjStep) *InstallArtifactStep {16pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep {
17 if (artifact.install_step) |s| return s;17 if (artifact.install_step) |s| return s;
1818
19 const self = builder.allocator.create(InstallArtifactStep) catch unreachable;19 const self = builder.allocator.create(InstallArtifactStep) catch unreachable;
...@@ -67,7 +67,7 @@ fn make(step: *Step) !void {...@@ -67,7 +67,7 @@ fn make(step: *Step) !void {
67 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);67 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
68 try builder.updateFile(self.artifact.getOutputSource().getPath(builder), full_dest_path);68 try builder.updateFile(self.artifact.getOutputSource().getPath(builder), full_dest_path);
69 if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) {69 if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) {
70 try LibExeObjStep.doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);70 try CompileStep.doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);
71 }71 }
72 if (self.artifact.isDynamicLibrary() and self.artifact.target.isWindows() and self.artifact.emit_implib != .no_emit) {72 if (self.artifact.isDynamicLibrary() and self.artifact.target.isWindows() and self.artifact.emit_implib != .no_emit) {
73 const full_implib_path = builder.getInstallPath(self.dest_dir, self.artifact.out_lib_filename);73 const full_implib_path = builder.getInstallPath(self.dest_dir, self.artifact.out_lib_filename);
lib/std/Build/InstallRawStep.zig+3-3
...@@ -9,7 +9,7 @@ const ArenaAllocator = std.heap.ArenaAllocator;...@@ -9,7 +9,7 @@ const ArenaAllocator = std.heap.ArenaAllocator;
9const ArrayListUnmanaged = std.ArrayListUnmanaged;9const ArrayListUnmanaged = std.ArrayListUnmanaged;
10const File = std.fs.File;10const File = std.fs.File;
11const InstallDir = std.Build.InstallDir;11const InstallDir = std.Build.InstallDir;
12const LibExeObjStep = std.Build.LibExeObjStep;12const CompileStep = std.Build.CompileStep;
13const Step = std.Build.Step;13const Step = std.Build.Step;
14const elf = std.elf;14const elf = std.elf;
15const fs = std.fs;15const fs = std.fs;
...@@ -25,7 +25,7 @@ pub const RawFormat = enum {...@@ -25,7 +25,7 @@ pub const RawFormat = enum {
2525
26step: Step,26step: Step,
27builder: *std.Build,27builder: *std.Build,
28artifact: *LibExeObjStep,28artifact: *CompileStep,
29dest_dir: InstallDir,29dest_dir: InstallDir,
30dest_filename: []const u8,30dest_filename: []const u8,
31options: CreateOptions,31options: CreateOptions,
...@@ -40,7 +40,7 @@ pub const CreateOptions = struct {...@@ -40,7 +40,7 @@ pub const CreateOptions = struct {
4040
41pub fn create(41pub fn create(
42 builder: *std.Build,42 builder: *std.Build,
43 artifact: *LibExeObjStep,43 artifact: *CompileStep,
44 dest_filename: []const u8,44 dest_filename: []const u8,
45 options: CreateOptions,45 options: CreateOptions,
46) *InstallRawStep {46) *InstallRawStep {
lib/std/Build/LibExeObjStep.zig deleted-2045
...@@ -1,2045 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("../std.zig");
3const mem = std.mem;
4const log = std.log;
5const fs = std.fs;
6const assert = std.debug.assert;
7const panic = std.debug.panic;
8const ArrayList = std.ArrayList;
9const StringHashMap = std.StringHashMap;
10const Sha256 = std.crypto.hash.sha2.Sha256;
11const Allocator = mem.Allocator;
12const Step = std.Build.Step;
13const CrossTarget = std.zig.CrossTarget;
14const NativeTargetInfo = std.zig.system.NativeTargetInfo;
15const FileSource = std.Build.FileSource;
16const PkgConfigPkg = std.Build.PkgConfigPkg;
17const PkgConfigError = std.Build.PkgConfigError;
18const ExecError = std.Build.ExecError;
19const Pkg = std.Build.Pkg;
20const VcpkgRoot = std.Build.VcpkgRoot;
21const InstallDir = std.Build.InstallDir;
22const InstallArtifactStep = std.Build.InstallArtifactStep;
23const GeneratedFile = std.Build.GeneratedFile;
24const InstallRawStep = std.Build.InstallRawStep;
25const EmulatableRunStep = std.Build.EmulatableRunStep;
26const CheckObjectStep = std.Build.CheckObjectStep;
27const RunStep = std.Build.RunStep;
28const OptionsStep = std.Build.OptionsStep;
29const ConfigHeaderStep = std.Build.ConfigHeaderStep;
30const LibExeObjStep = @This();
31
32pub const base_id = .lib_exe_obj;
33
34step: Step,
35builder: *std.Build,
36name: []const u8,
37target: CrossTarget,
38target_info: NativeTargetInfo,
39optimize: std.builtin.Mode,
40linker_script: ?FileSource = null,
41version_script: ?[]const u8 = null,
42out_filename: []const u8,
43linkage: ?Linkage = null,
44version: ?std.builtin.Version,
45kind: Kind,
46major_only_filename: ?[]const u8,
47name_only_filename: ?[]const u8,
48strip: ?bool,
49unwind_tables: ?bool,
50// keep in sync with src/link.zig:CompressDebugSections
51compress_debug_sections: enum { none, zlib } = .none,
52lib_paths: ArrayList([]const u8),
53rpaths: ArrayList([]const u8),
54framework_dirs: ArrayList([]const u8),
55frameworks: StringHashMap(FrameworkLinkInfo),
56verbose_link: bool,
57verbose_cc: bool,
58emit_analysis: EmitOption = .default,
59emit_asm: EmitOption = .default,
60emit_bin: EmitOption = .default,
61emit_docs: EmitOption = .default,
62emit_implib: EmitOption = .default,
63emit_llvm_bc: EmitOption = .default,
64emit_llvm_ir: EmitOption = .default,
65// Lots of things depend on emit_h having a consistent path,
66// so it is not an EmitOption for now.
67emit_h: bool = false,
68bundle_compiler_rt: ?bool = null,
69single_threaded: ?bool = null,
70stack_protector: ?bool = null,
71disable_stack_probing: bool,
72disable_sanitize_c: bool,
73sanitize_thread: bool,
74rdynamic: bool,
75import_memory: bool = false,
76/// For WebAssembly targets, this will allow for undefined symbols to
77/// be imported from the host environment.
78import_symbols: bool = false,
79import_table: bool = false,
80export_table: bool = false,
81initial_memory: ?u64 = null,
82max_memory: ?u64 = null,
83shared_memory: bool = false,
84global_base: ?u64 = null,
85c_std: std.Build.CStd,
86override_lib_dir: ?[]const u8,
87main_pkg_path: ?[]const u8,
88exec_cmd_args: ?[]const ?[]const u8,
89name_prefix: []const u8,
90filter: ?[]const u8,
91test_evented_io: bool = false,
92test_runner: ?[]const u8,
93code_model: std.builtin.CodeModel = .default,
94wasi_exec_model: ?std.builtin.WasiExecModel = null,
95/// Symbols to be exported when compiling to wasm
96export_symbol_names: []const []const u8 = &.{},
97
98root_src: ?FileSource,
99out_h_filename: []const u8,
100out_lib_filename: []const u8,
101out_pdb_filename: []const u8,
102packages: ArrayList(Pkg),
103
104object_src: []const u8,
105
106link_objects: ArrayList(LinkObject),
107include_dirs: ArrayList(IncludeDir),
108c_macros: ArrayList([]const u8),
109installed_headers: ArrayList(*Step),
110output_dir: ?[]const u8,
111is_linking_libc: bool = false,
112is_linking_libcpp: bool = false,
113vcpkg_bin_path: ?[]const u8 = null,
114
115/// This may be set in order to override the default install directory
116override_dest_dir: ?InstallDir,
117installed_path: ?[]const u8,
118install_step: ?*InstallArtifactStep,
119
120/// Base address for an executable image.
121image_base: ?u64 = null,
122
123libc_file: ?FileSource = null,
124
125valgrind_support: ?bool = null,
126each_lib_rpath: ?bool = null,
127/// On ELF targets, this will emit a link section called ".note.gnu.build-id"
128/// which can be used to coordinate a stripped binary with its debug symbols.
129/// As an example, the bloaty project refuses to work unless its inputs have
130/// build ids, in order to prevent accidental mismatches.
131/// The default is to not include this section because it slows down linking.
132build_id: ?bool = null,
133
134/// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF
135/// file.
136link_eh_frame_hdr: bool = false,
137link_emit_relocs: bool = false,
138
139/// Place every function in its own section so that unused ones may be
140/// safely garbage-collected during the linking phase.
141link_function_sections: bool = false,
142
143/// Remove functions and data that are unreachable by the entry point or
144/// exported symbols.
145link_gc_sections: ?bool = null,
146
147linker_allow_shlib_undefined: ?bool = null,
148
149/// Permit read-only relocations in read-only segments. Disallowed by default.
150link_z_notext: bool = false,
151
152/// Force all relocations to be read-only after processing.
153link_z_relro: bool = true,
154
155/// Allow relocations to be lazily processed after load.
156link_z_lazy: bool = false,
157
158/// Common page size
159link_z_common_page_size: ?u64 = null,
160
161/// Maximum page size
162link_z_max_page_size: ?u64 = null,
163
164/// (Darwin) Install name for the dylib
165install_name: ?[]const u8 = null,
166
167/// (Darwin) Path to entitlements file
168entitlements: ?[]const u8 = null,
169
170/// (Darwin) Size of the pagezero segment.
171pagezero_size: ?u64 = null,
172
173/// (Darwin) Search strategy for searching system libraries. Either `paths_first` or `dylibs_first`.
174/// The former lowers to `-search_paths_first` linker option, while the latter to `-search_dylibs_first`
175/// option.
176/// By default, if no option is specified, the linker assumes `paths_first` as the default
177/// search strategy.
178search_strategy: ?enum { paths_first, dylibs_first } = null,
179
180/// (Darwin) Set size of the padding between the end of load commands
181/// and start of `__TEXT,__text` section.
182headerpad_size: ?u32 = null,
183
184/// (Darwin) Automatically Set size of the padding between the end of load commands
185/// and start of `__TEXT,__text` section to a value fitting all paths expanded to MAXPATHLEN.
186headerpad_max_install_names: bool = false,
187
188/// (Darwin) Remove dylibs that are unreachable by the entry point or exported symbols.
189dead_strip_dylibs: bool = false,
190
191/// Position Independent Code
192force_pic: ?bool = null,
193
194/// Position Independent Executable
195pie: ?bool = null,
196
197red_zone: ?bool = null,
198
199omit_frame_pointer: ?bool = null,
200dll_export_fns: ?bool = null,
201
202subsystem: ?std.Target.SubSystem = null,
203
204entry_symbol_name: ?[]const u8 = null,
205
206/// Overrides the default stack size
207stack_size: ?u64 = null,
208
209want_lto: ?bool = null,
210use_llvm: ?bool = null,
211use_lld: ?bool = null,
212
213output_path_source: GeneratedFile,
214output_lib_path_source: GeneratedFile,
215output_h_path_source: GeneratedFile,
216output_pdb_path_source: GeneratedFile,
217
218pub const CSourceFiles = struct {
219 files: []const []const u8,
220 flags: []const []const u8,
221};
222
223pub const CSourceFile = struct {
224 source: FileSource,
225 args: []const []const u8,
226
227 pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile {
228 return .{
229 .source = self.source.dupe(b),
230 .args = b.dupeStrings(self.args),
231 };
232 }
233};
234
235pub const LinkObject = union(enum) {
236 static_path: FileSource,
237 other_step: *LibExeObjStep,
238 system_lib: SystemLib,
239 assembly_file: FileSource,
240 c_source_file: *CSourceFile,
241 c_source_files: *CSourceFiles,
242};
243
244pub const SystemLib = struct {
245 name: []const u8,
246 needed: bool,
247 weak: bool,
248 use_pkg_config: enum {
249 /// Don't use pkg-config, just pass -lfoo where foo is name.
250 no,
251 /// Try to get information on how to link the library from pkg-config.
252 /// If that fails, fall back to passing -lfoo where foo is name.
253 yes,
254 /// Try to get information on how to link the library from pkg-config.
255 /// If that fails, error out.
256 force,
257 },
258};
259
260const FrameworkLinkInfo = struct {
261 needed: bool = false,
262 weak: bool = false,
263};
264
265pub const IncludeDir = union(enum) {
266 raw_path: []const u8,
267 raw_path_system: []const u8,
268 other_step: *LibExeObjStep,
269 config_header_step: *ConfigHeaderStep,
270};
271
272pub const Options = struct {
273 name: []const u8,
274 root_source_file: ?FileSource = null,
275 target: CrossTarget,
276 optimize: std.builtin.Mode,
277 kind: Kind,
278 linkage: ?Linkage = null,
279 version: ?std.builtin.Version = null,
280};
281
282pub const Kind = enum {
283 exe,
284 lib,
285 obj,
286 @"test",
287 test_exe,
288};
289
290pub const Linkage = enum { dynamic, static };
291
292pub const EmitOption = union(enum) {
293 default: void,
294 no_emit: void,
295 emit: void,
296 emit_to: []const u8,
297
298 fn getArg(self: @This(), b: *std.Build, arg_name: []const u8) ?[]const u8 {
299 return switch (self) {
300 .no_emit => b.fmt("-fno-{s}", .{arg_name}),
301 .default => null,
302 .emit => b.fmt("-f{s}", .{arg_name}),
303 .emit_to => |path| b.fmt("-f{s}={s}", .{ arg_name, path }),
304 };
305 }
306};
307
308pub fn create(builder: *std.Build, options: Options) *LibExeObjStep {
309 const name = builder.dupe(options.name);
310 const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(builder) else null;
311 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
312 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
313 }
314
315 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
316 self.* = LibExeObjStep{
317 .strip = null,
318 .unwind_tables = null,
319 .builder = builder,
320 .verbose_link = false,
321 .verbose_cc = false,
322 .optimize = options.optimize,
323 .target = options.target,
324 .linkage = options.linkage,
325 .kind = options.kind,
326 .root_src = root_src,
327 .name = name,
328 .frameworks = StringHashMap(FrameworkLinkInfo).init(builder.allocator),
329 .step = Step.init(base_id, name, builder.allocator, make),
330 .version = options.version,
331 .out_filename = undefined,
332 .out_h_filename = builder.fmt("{s}.h", .{name}),
333 .out_lib_filename = undefined,
334 .out_pdb_filename = builder.fmt("{s}.pdb", .{name}),
335 .major_only_filename = null,
336 .name_only_filename = null,
337 .packages = ArrayList(Pkg).init(builder.allocator),
338 .include_dirs = ArrayList(IncludeDir).init(builder.allocator),
339 .link_objects = ArrayList(LinkObject).init(builder.allocator),
340 .c_macros = ArrayList([]const u8).init(builder.allocator),
341 .lib_paths = ArrayList([]const u8).init(builder.allocator),
342 .rpaths = ArrayList([]const u8).init(builder.allocator),
343 .framework_dirs = ArrayList([]const u8).init(builder.allocator),
344 .installed_headers = ArrayList(*Step).init(builder.allocator),
345 .object_src = undefined,
346 .c_std = std.Build.CStd.C99,
347 .override_lib_dir = null,
348 .main_pkg_path = null,
349 .exec_cmd_args = null,
350 .name_prefix = "",
351 .filter = null,
352 .test_runner = null,
353 .disable_stack_probing = false,
354 .disable_sanitize_c = false,
355 .sanitize_thread = false,
356 .rdynamic = false,
357 .output_dir = null,
358 .override_dest_dir = null,
359 .installed_path = null,
360 .install_step = null,
361
362 .output_path_source = GeneratedFile{ .step = &self.step },
363 .output_lib_path_source = GeneratedFile{ .step = &self.step },
364 .output_h_path_source = GeneratedFile{ .step = &self.step },
365 .output_pdb_path_source = GeneratedFile{ .step = &self.step },
366
367 .target_info = NativeTargetInfo.detect(self.target) catch unreachable,
368 };
369 self.computeOutFileNames();
370 if (root_src) |rs| rs.addStepDependencies(&self.step);
371 return self;
372}
373
374fn computeOutFileNames(self: *LibExeObjStep) void {
375 const target = self.target_info.target;
376
377 self.out_filename = std.zig.binNameAlloc(self.builder.allocator, .{
378 .root_name = self.name,
379 .target = target,
380 .output_mode = switch (self.kind) {
381 .lib => .Lib,
382 .obj => .Obj,
383 .exe, .@"test", .test_exe => .Exe,
384 },
385 .link_mode = if (self.linkage) |some| @as(std.builtin.LinkMode, switch (some) {
386 .dynamic => .Dynamic,
387 .static => .Static,
388 }) else null,
389 .version = self.version,
390 }) catch unreachable;
391
392 if (self.kind == .lib) {
393 if (self.linkage != null and self.linkage.? == .static) {
394 self.out_lib_filename = self.out_filename;
395 } else if (self.version) |version| {
396 if (target.isDarwin()) {
397 self.major_only_filename = self.builder.fmt("lib{s}.{d}.dylib", .{
398 self.name,
399 version.major,
400 });
401 self.name_only_filename = self.builder.fmt("lib{s}.dylib", .{self.name});
402 self.out_lib_filename = self.out_filename;
403 } else if (target.os.tag == .windows) {
404 self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
405 } else {
406 self.major_only_filename = self.builder.fmt("lib{s}.so.{d}", .{ self.name, version.major });
407 self.name_only_filename = self.builder.fmt("lib{s}.so", .{self.name});
408 self.out_lib_filename = self.out_filename;
409 }
410 } else {
411 if (target.isDarwin()) {
412 self.out_lib_filename = self.out_filename;
413 } else if (target.os.tag == .windows) {
414 self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
415 } else {
416 self.out_lib_filename = self.out_filename;
417 }
418 }
419 if (self.output_dir != null) {
420 self.output_lib_path_source.path = self.builder.pathJoin(
421 &.{ self.output_dir.?, self.out_lib_filename },
422 );
423 }
424 }
425}
426
427pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
428 self.output_dir = self.builder.dupePath(dir);
429}
430
431pub fn install(self: *LibExeObjStep) void {
432 self.builder.installArtifact(self);
433}
434
435pub fn installRaw(self: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
436 return self.builder.installRaw(self, dest_filename, options);
437}
438
439pub fn installHeader(a: *LibExeObjStep, src_path: []const u8, dest_rel_path: []const u8) void {
440 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);
441 a.builder.getInstallStep().dependOn(&install_file.step);
442 a.installed_headers.append(&install_file.step) catch unreachable;
443}
444
445pub fn installHeadersDirectory(
446 a: *LibExeObjStep,
447 src_dir_path: []const u8,
448 dest_rel_path: []const u8,
449) void {
450 return installHeadersDirectoryOptions(a, .{
451 .source_dir = src_dir_path,
452 .install_dir = .header,
453 .install_subdir = dest_rel_path,
454 });
455}
456
457pub fn installHeadersDirectoryOptions(
458 a: *LibExeObjStep,
459 options: std.Build.InstallDirStep.Options,
460) void {
461 const install_dir = a.builder.addInstallDirectory(options);
462 a.builder.getInstallStep().dependOn(&install_dir.step);
463 a.installed_headers.append(&install_dir.step) catch unreachable;
464}
465
466pub fn installLibraryHeaders(a: *LibExeObjStep, l: *LibExeObjStep) void {
467 assert(l.kind == .lib);
468 const install_step = a.builder.getInstallStep();
469 // Copy each element from installed_headers, modifying the builder
470 // to be the new parent's builder.
471 for (l.installed_headers.items) |step| {
472 const step_copy = switch (step.id) {
473 inline .install_file, .install_dir => |id| blk: {
474 const T = id.Type();
475 const ptr = a.builder.allocator.create(T) catch unreachable;
476 ptr.* = step.cast(T).?.*;
477 ptr.override_source_builder = ptr.builder;
478 ptr.builder = a.builder;
479 break :blk &ptr.step;
480 },
481 else => unreachable,
482 };
483 a.installed_headers.append(step_copy) catch unreachable;
484 install_step.dependOn(step_copy);
485 }
486 a.installed_headers.appendSlice(l.installed_headers.items) catch unreachable;
487}
488
489/// Creates a `RunStep` with an executable built with `addExecutable`.
490/// Add command line arguments with `addArg`.
491pub fn run(exe: *LibExeObjStep) *RunStep {
492 assert(exe.kind == .exe or exe.kind == .test_exe);
493
494 // It doesn't have to be native. We catch that if you actually try to run it.
495 // Consider that this is declarative; the run step may not be run unless a user
496 // option is supplied.
497 const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}));
498 run_step.addArtifactArg(exe);
499
500 if (exe.kind == .test_exe) {
501 run_step.addArg(exe.builder.zig_exe);
502 }
503
504 if (exe.vcpkg_bin_path) |path| {
505 run_step.addPathDir(path);
506 }
507
508 return run_step;
509}
510
511/// Creates an `EmulatableRunStep` with an executable built with `addExecutable`.
512/// Allows running foreign binaries through emulation platforms such as Qemu or Rosetta.
513/// When a binary cannot be ran through emulation or the option is disabled, a warning
514/// will be printed and the binary will *NOT* be ran.
515pub fn runEmulatable(exe: *LibExeObjStep) *EmulatableRunStep {
516 assert(exe.kind == .exe or exe.kind == .test_exe);
517
518 const run_step = EmulatableRunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}), exe);
519 if (exe.vcpkg_bin_path) |path| {
520 RunStep.addPathDirInternal(&run_step.step, exe.builder, path);
521 }
522 return run_step;
523}
524
525pub fn checkObject(self: *LibExeObjStep, obj_format: std.Target.ObjectFormat) *CheckObjectStep {
526 return CheckObjectStep.create(self.builder, self.getOutputSource(), obj_format);
527}
528
529pub fn setLinkerScriptPath(self: *LibExeObjStep, source: FileSource) void {
530 self.linker_script = source.dupe(self.builder);
531 source.addStepDependencies(&self.step);
532}
533
534pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void {
535 self.frameworks.put(self.builder.dupe(framework_name), .{}) catch unreachable;
536}
537
538pub fn linkFrameworkNeeded(self: *LibExeObjStep, framework_name: []const u8) void {
539 self.frameworks.put(self.builder.dupe(framework_name), .{
540 .needed = true,
541 }) catch unreachable;
542}
543
544pub fn linkFrameworkWeak(self: *LibExeObjStep, framework_name: []const u8) void {
545 self.frameworks.put(self.builder.dupe(framework_name), .{
546 .weak = true,
547 }) catch unreachable;
548}
549
550/// Returns whether the library, executable, or object depends on a particular system library.
551pub fn dependsOnSystemLibrary(self: LibExeObjStep, name: []const u8) bool {
552 if (isLibCLibrary(name)) {
553 return self.is_linking_libc;
554 }
555 if (isLibCppLibrary(name)) {
556 return self.is_linking_libcpp;
557 }
558 for (self.link_objects.items) |link_object| {
559 switch (link_object) {
560 .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
561 else => continue,
562 }
563 }
564 return false;
565}
566
567pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void {
568 assert(lib.kind == .lib);
569 self.linkLibraryOrObject(lib);
570}
571
572pub fn isDynamicLibrary(self: *LibExeObjStep) bool {
573 return self.kind == .lib and self.linkage == Linkage.dynamic;
574}
575
576pub fn isStaticLibrary(self: *LibExeObjStep) bool {
577 return self.kind == .lib and self.linkage != Linkage.dynamic;
578}
579
580pub fn producesPdbFile(self: *LibExeObjStep) bool {
581 if (!self.target.isWindows() and !self.target.isUefi()) return false;
582 if (self.target.getObjectFormat() == .c) return false;
583 if (self.strip == true) return false;
584 return self.isDynamicLibrary() or self.kind == .exe or self.kind == .test_exe;
585}
586
587pub fn linkLibC(self: *LibExeObjStep) void {
588 self.is_linking_libc = true;
589}
590
591pub fn linkLibCpp(self: *LibExeObjStep) void {
592 self.is_linking_libcpp = true;
593}
594
595/// If the value is omitted, it is set to 1.
596/// `name` and `value` need not live longer than the function call.
597pub fn defineCMacro(self: *LibExeObjStep, name: []const u8, value: ?[]const u8) void {
598 const macro = std.Build.constructCMacro(self.builder.allocator, name, value);
599 self.c_macros.append(macro) catch unreachable;
600}
601
602/// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1.
603pub fn defineCMacroRaw(self: *LibExeObjStep, name_and_value: []const u8) void {
604 self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable;
605}
606
607/// This one has no integration with anything, it just puts -lname on the command line.
608/// Prefer to use `linkSystemLibrary` instead.
609pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void {
610 self.link_objects.append(.{
611 .system_lib = .{
612 .name = self.builder.dupe(name),
613 .needed = false,
614 .weak = false,
615 .use_pkg_config = .no,
616 },
617 }) catch unreachable;
618}
619
620/// This one has no integration with anything, it just puts -needed-lname on the command line.
621/// Prefer to use `linkSystemLibraryNeeded` instead.
622pub fn linkSystemLibraryNeededName(self: *LibExeObjStep, name: []const u8) void {
623 self.link_objects.append(.{
624 .system_lib = .{
625 .name = self.builder.dupe(name),
626 .needed = true,
627 .weak = false,
628 .use_pkg_config = .no,
629 },
630 }) catch unreachable;
631}
632
633/// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the
634/// command line. Prefer to use `linkSystemLibraryWeak` instead.
635pub fn linkSystemLibraryWeakName(self: *LibExeObjStep, name: []const u8) void {
636 self.link_objects.append(.{
637 .system_lib = .{
638 .name = self.builder.dupe(name),
639 .needed = false,
640 .weak = true,
641 .use_pkg_config = .no,
642 },
643 }) catch unreachable;
644}
645
646/// This links against a system library, exclusively using pkg-config to find the library.
647/// Prefer to use `linkSystemLibrary` instead.
648pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) void {
649 self.link_objects.append(.{
650 .system_lib = .{
651 .name = self.builder.dupe(lib_name),
652 .needed = false,
653 .weak = false,
654 .use_pkg_config = .force,
655 },
656 }) catch unreachable;
657}
658
659/// This links against a system library, exclusively using pkg-config to find the library.
660/// Prefer to use `linkSystemLibraryNeeded` instead.
661pub fn linkSystemLibraryNeededPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) void {
662 self.link_objects.append(.{
663 .system_lib = .{
664 .name = self.builder.dupe(lib_name),
665 .needed = true,
666 .weak = false,
667 .use_pkg_config = .force,
668 },
669 }) catch unreachable;
670}
671
672/// Run pkg-config for the given library name and parse the output, returning the arguments
673/// that should be passed to zig to link the given library.
674pub fn runPkgConfig(self: *LibExeObjStep, lib_name: []const u8) ![]const []const u8 {
675 const pkg_name = match: {
676 // First we have to map the library name to pkg config name. Unfortunately,
677 // there are several examples where this is not straightforward:
678 // -lSDL2 -> pkg-config sdl2
679 // -lgdk-3 -> pkg-config gdk-3.0
680 // -latk-1.0 -> pkg-config atk
681 const pkgs = try getPkgConfigList(self.builder);
682
683 // Exact match means instant winner.
684 for (pkgs) |pkg| {
685 if (mem.eql(u8, pkg.name, lib_name)) {
686 break :match pkg.name;
687 }
688 }
689
690 // Next we'll try ignoring case.
691 for (pkgs) |pkg| {
692 if (std.ascii.eqlIgnoreCase(pkg.name, lib_name)) {
693 break :match pkg.name;
694 }
695 }
696
697 // Now try appending ".0".
698 for (pkgs) |pkg| {
699 if (std.ascii.indexOfIgnoreCase(pkg.name, lib_name)) |pos| {
700 if (pos != 0) continue;
701 if (mem.eql(u8, pkg.name[lib_name.len..], ".0")) {
702 break :match pkg.name;
703 }
704 }
705 }
706
707 // Trimming "-1.0".
708 if (mem.endsWith(u8, lib_name, "-1.0")) {
709 const trimmed_lib_name = lib_name[0 .. lib_name.len - "-1.0".len];
710 for (pkgs) |pkg| {
711 if (std.ascii.eqlIgnoreCase(pkg.name, trimmed_lib_name)) {
712 break :match pkg.name;
713 }
714 }
715 }
716
717 return error.PackageNotFound;
718 };
719
720 var code: u8 = undefined;
721 const stdout = if (self.builder.execAllowFail(&[_][]const u8{
722 "pkg-config",
723 pkg_name,
724 "--cflags",
725 "--libs",
726 }, &code, .Ignore)) |stdout| stdout else |err| switch (err) {
727 error.ProcessTerminated => return error.PkgConfigCrashed,
728 error.ExecNotSupported => return error.PkgConfigFailed,
729 error.ExitCodeFailure => return error.PkgConfigFailed,
730 error.FileNotFound => return error.PkgConfigNotInstalled,
731 error.ChildExecFailed => return error.PkgConfigFailed,
732 else => return err,
733 };
734
735 var zig_args = ArrayList([]const u8).init(self.builder.allocator);
736 defer zig_args.deinit();
737
738 var it = mem.tokenize(u8, stdout, " \r\n\t");
739 while (it.next()) |tok| {
740 if (mem.eql(u8, tok, "-I")) {
741 const dir = it.next() orelse return error.PkgConfigInvalidOutput;
742 try zig_args.appendSlice(&[_][]const u8{ "-I", dir });
743 } else if (mem.startsWith(u8, tok, "-I")) {
744 try zig_args.append(tok);
745 } else if (mem.eql(u8, tok, "-L")) {
746 const dir = it.next() orelse return error.PkgConfigInvalidOutput;
747 try zig_args.appendSlice(&[_][]const u8{ "-L", dir });
748 } else if (mem.startsWith(u8, tok, "-L")) {
749 try zig_args.append(tok);
750 } else if (mem.eql(u8, tok, "-l")) {
751 const lib = it.next() orelse return error.PkgConfigInvalidOutput;
752 try zig_args.appendSlice(&[_][]const u8{ "-l", lib });
753 } else if (mem.startsWith(u8, tok, "-l")) {
754 try zig_args.append(tok);
755 } else if (mem.eql(u8, tok, "-D")) {
756 const macro = it.next() orelse return error.PkgConfigInvalidOutput;
757 try zig_args.appendSlice(&[_][]const u8{ "-D", macro });
758 } else if (mem.startsWith(u8, tok, "-D")) {
759 try zig_args.append(tok);
760 } else if (self.builder.verbose) {
761 log.warn("Ignoring pkg-config flag '{s}'", .{tok});
762 }
763 }
764
765 return zig_args.toOwnedSlice();
766}
767
768pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
769 self.linkSystemLibraryInner(name, .{});
770}
771
772pub fn linkSystemLibraryNeeded(self: *LibExeObjStep, name: []const u8) void {
773 self.linkSystemLibraryInner(name, .{ .needed = true });
774}
775
776pub fn linkSystemLibraryWeak(self: *LibExeObjStep, name: []const u8) void {
777 self.linkSystemLibraryInner(name, .{ .weak = true });
778}
779
780fn linkSystemLibraryInner(self: *LibExeObjStep, name: []const u8, opts: struct {
781 needed: bool = false,
782 weak: bool = false,
783}) void {
784 if (isLibCLibrary(name)) {
785 self.linkLibC();
786 return;
787 }
788 if (isLibCppLibrary(name)) {
789 self.linkLibCpp();
790 return;
791 }
792
793 self.link_objects.append(.{
794 .system_lib = .{
795 .name = self.builder.dupe(name),
796 .needed = opts.needed,
797 .weak = opts.weak,
798 .use_pkg_config = .yes,
799 },
800 }) catch unreachable;
801}
802
803pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
804 assert(self.kind == .@"test" or self.kind == .test_exe);
805 self.name_prefix = self.builder.dupe(text);
806}
807
808pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void {
809 assert(self.kind == .@"test" or self.kind == .test_exe);
810 self.filter = if (text) |t| self.builder.dupe(t) else null;
811}
812
813pub fn setTestRunner(self: *LibExeObjStep, path: ?[]const u8) void {
814 assert(self.kind == .@"test" or self.kind == .test_exe);
815 self.test_runner = if (path) |p| self.builder.dupePath(p) else null;
816}
817
818/// Handy when you have many C/C++ source files and want them all to have the same flags.
819pub fn addCSourceFiles(self: *LibExeObjStep, files: []const []const u8, flags: []const []const u8) void {
820 const c_source_files = self.builder.allocator.create(CSourceFiles) catch unreachable;
821
822 const files_copy = self.builder.dupeStrings(files);
823 const flags_copy = self.builder.dupeStrings(flags);
824
825 c_source_files.* = .{
826 .files = files_copy,
827 .flags = flags_copy,
828 };
829 self.link_objects.append(.{ .c_source_files = c_source_files }) catch unreachable;
830}
831
832pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, flags: []const []const u8) void {
833 self.addCSourceFileSource(.{
834 .args = flags,
835 .source = .{ .path = file },
836 });
837}
838
839pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void {
840 const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
841 c_source_file.* = source.dupe(self.builder);
842 self.link_objects.append(.{ .c_source_file = c_source_file }) catch unreachable;
843 source.source.addStepDependencies(&self.step);
844}
845
846pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
847 self.verbose_link = value;
848}
849
850pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void {
851 self.verbose_cc = value;
852}
853
854pub fn overrideZigLibDir(self: *LibExeObjStep, dir_path: []const u8) void {
855 self.override_lib_dir = self.builder.dupePath(dir_path);
856}
857
858pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void {
859 self.main_pkg_path = self.builder.dupePath(dir_path);
860}
861
862pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?FileSource) void {
863 self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null;
864}
865
866/// Returns the generated executable, library or object file.
867/// To run an executable built with zig build, use `run`, or create an install step and invoke it.
868pub fn getOutputSource(self: *LibExeObjStep) FileSource {
869 return FileSource{ .generated = &self.output_path_source };
870}
871
872/// Returns the generated import library. This function can only be called for libraries.
873pub fn getOutputLibSource(self: *LibExeObjStep) FileSource {
874 assert(self.kind == .lib);
875 return FileSource{ .generated = &self.output_lib_path_source };
876}
877
878/// Returns the generated header file.
879/// This function can only be called for libraries or object files which have `emit_h` set.
880pub fn getOutputHSource(self: *LibExeObjStep) FileSource {
881 assert(self.kind != .exe and self.kind != .test_exe and self.kind != .@"test");
882 assert(self.emit_h);
883 return FileSource{ .generated = &self.output_h_path_source };
884}
885
886/// Returns the generated PDB file. This function can only be called for Windows and UEFI.
887pub fn getOutputPdbSource(self: *LibExeObjStep) FileSource {
888 // TODO: Is this right? Isn't PDB for *any* PE/COFF file?
889 assert(self.target.isWindows() or self.target.isUefi());
890 return FileSource{ .generated = &self.output_pdb_path_source };
891}
892
893pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
894 self.link_objects.append(.{
895 .assembly_file = .{ .path = self.builder.dupe(path) },
896 }) catch unreachable;
897}
898
899pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void {
900 const source_duped = source.dupe(self.builder);
901 self.link_objects.append(.{ .assembly_file = source_duped }) catch unreachable;
902 source_duped.addStepDependencies(&self.step);
903}
904
905pub fn addObjectFile(self: *LibExeObjStep, source_file: []const u8) void {
906 self.addObjectFileSource(.{ .path = source_file });
907}
908
909pub fn addObjectFileSource(self: *LibExeObjStep, source: FileSource) void {
910 self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch unreachable;
911 source.addStepDependencies(&self.step);
912}
913
914pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void {
915 assert(obj.kind == .obj);
916 self.linkLibraryOrObject(obj);
917}
918
919pub const addSystemIncludeDir = @compileError("deprecated; use addSystemIncludePath");
920pub const addIncludeDir = @compileError("deprecated; use addIncludePath");
921pub const addLibPath = @compileError("deprecated, use addLibraryPath");
922pub const addFrameworkDir = @compileError("deprecated, use addFrameworkPath");
923
924pub fn addSystemIncludePath(self: *LibExeObjStep, path: []const u8) void {
925 self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable;
926}
927
928pub fn addIncludePath(self: *LibExeObjStep, path: []const u8) void {
929 self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch unreachable;
930}
931
932pub fn addConfigHeader(self: *LibExeObjStep, config_header: *ConfigHeaderStep) void {
933 self.step.dependOn(&config_header.step);
934 self.include_dirs.append(.{ .config_header_step = config_header }) catch @panic("OOM");
935}
936
937pub fn addLibraryPath(self: *LibExeObjStep, path: []const u8) void {
938 self.lib_paths.append(self.builder.dupe(path)) catch unreachable;
939}
940
941pub fn addRPath(self: *LibExeObjStep, path: []const u8) void {
942 self.rpaths.append(self.builder.dupe(path)) catch unreachable;
943}
944
945pub fn addFrameworkPath(self: *LibExeObjStep, dir_path: []const u8) void {
946 self.framework_dirs.append(self.builder.dupe(dir_path)) catch unreachable;
947}
948
949pub fn addPackage(self: *LibExeObjStep, package: Pkg) void {
950 self.packages.append(self.builder.dupePkg(package)) catch unreachable;
951 self.addRecursiveBuildDeps(package);
952}
953
954pub fn addOptions(self: *LibExeObjStep, package_name: []const u8, options: *OptionsStep) void {
955 self.addPackage(options.getPackage(package_name));
956}
957
958fn addRecursiveBuildDeps(self: *LibExeObjStep, package: Pkg) void {
959 package.source.addStepDependencies(&self.step);
960 if (package.dependencies) |deps| {
961 for (deps) |dep| {
962 self.addRecursiveBuildDeps(dep);
963 }
964 }
965}
966
967pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
968 self.addPackage(Pkg{
969 .name = self.builder.dupe(name),
970 .source = .{ .path = self.builder.dupe(pkg_index_path) },
971 });
972}
973
974/// If Vcpkg was found on the system, it will be added to include and lib
975/// paths for the specified target.
976pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: LibExeObjStep.Linkage) !void {
977 // Ideally in the Unattempted case we would call the function recursively
978 // after findVcpkgRoot and have only one switch statement, but the compiler
979 // cannot resolve the error set.
980 switch (self.builder.vcpkg_root) {
981 .unattempted => {
982 self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root|
983 VcpkgRoot{ .found = root }
984 else
985 .not_found;
986 },
987 .not_found => return error.VcpkgNotFound,
988 .found => {},
989 }
990
991 switch (self.builder.vcpkg_root) {
992 .unattempted => unreachable,
993 .not_found => return error.VcpkgNotFound,
994 .found => |root| {
995 const allocator = self.builder.allocator;
996 const triplet = try self.target.vcpkgTriplet(allocator, if (linkage == .static) .Static else .Dynamic);
997 defer self.builder.allocator.free(triplet);
998
999 const include_path = self.builder.pathJoin(&.{ root, "installed", triplet, "include" });
1000 errdefer allocator.free(include_path);
1001 try self.include_dirs.append(IncludeDir{ .raw_path = include_path });
1002
1003 const lib_path = self.builder.pathJoin(&.{ root, "installed", triplet, "lib" });
1004 try self.lib_paths.append(lib_path);
1005
1006 self.vcpkg_bin_path = self.builder.pathJoin(&.{ root, "installed", triplet, "bin" });
1007 },
1008 }
1009}
1010
1011pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
1012 assert(self.kind == .@"test");
1013 const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable;
1014 for (args) |arg, i| {
1015 duped_args[i] = if (arg) |a| self.builder.dupe(a) else null;
1016 }
1017 self.exec_cmd_args = duped_args;
1018}
1019
1020fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void {
1021 self.step.dependOn(&other.step);
1022 self.link_objects.append(.{ .other_step = other }) catch unreachable;
1023 self.include_dirs.append(.{ .other_step = other }) catch unreachable;
1024}
1025
1026fn makePackageCmd(self: *LibExeObjStep, pkg: Pkg, zig_args: *ArrayList([]const u8)) error{OutOfMemory}!void {
1027 const builder = self.builder;
1028
1029 try zig_args.append("--pkg-begin");
1030 try zig_args.append(pkg.name);
1031 try zig_args.append(builder.pathFromRoot(pkg.source.getPath(self.builder)));
1032
1033 if (pkg.dependencies) |dependencies| {
1034 for (dependencies) |sub_pkg| {
1035 try self.makePackageCmd(sub_pkg, zig_args);
1036 }
1037 }
1038
1039 try zig_args.append("--pkg-end");
1040}
1041
1042fn make(step: *Step) !void {
1043 const self = @fieldParentPtr(LibExeObjStep, "step", step);
1044 const builder = self.builder;
1045
1046 if (self.root_src == null and self.link_objects.items.len == 0) {
1047 log.err("{s}: linker needs 1 or more objects to link", .{self.step.name});
1048 return error.NeedAnObject;
1049 }
1050
1051 var zig_args = ArrayList([]const u8).init(builder.allocator);
1052 defer zig_args.deinit();
1053
1054 zig_args.append(builder.zig_exe) catch unreachable;
1055
1056 const cmd = switch (self.kind) {
1057 .lib => "build-lib",
1058 .exe => "build-exe",
1059 .obj => "build-obj",
1060 .@"test" => "test",
1061 .test_exe => "test",
1062 };
1063 zig_args.append(cmd) catch unreachable;
1064
1065 if (builder.color != .auto) {
1066 try zig_args.append("--color");
1067 try zig_args.append(@tagName(builder.color));
1068 }
1069
1070 if (builder.reference_trace) |some| {
1071 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-freference-trace={d}", .{some}));
1072 }
1073
1074 try addFlag(&zig_args, "LLVM", self.use_llvm);
1075 try addFlag(&zig_args, "LLD", self.use_lld);
1076
1077 if (self.target.ofmt) |ofmt| {
1078 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
1079 }
1080
1081 if (self.entry_symbol_name) |entry| {
1082 try zig_args.append("--entry");
1083 try zig_args.append(entry);
1084 }
1085
1086 if (self.stack_size) |stack_size| {
1087 try zig_args.append("--stack");
1088 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "{}", .{stack_size}));
1089 }
1090
1091 if (self.root_src) |root_src| try zig_args.append(root_src.getPath(builder));
1092
1093 // We will add link objects from transitive dependencies, but we want to keep
1094 // all link objects in the same order provided.
1095 // This array is used to keep self.link_objects immutable.
1096 var transitive_deps: TransitiveDeps = .{
1097 .link_objects = ArrayList(LinkObject).init(builder.allocator),
1098 .seen_system_libs = StringHashMap(void).init(builder.allocator),
1099 .seen_steps = std.AutoHashMap(*const Step, void).init(builder.allocator),
1100 .is_linking_libcpp = self.is_linking_libcpp,
1101 .is_linking_libc = self.is_linking_libc,
1102 .frameworks = &self.frameworks,
1103 };
1104
1105 try transitive_deps.seen_steps.put(&self.step, {});
1106 try transitive_deps.add(self.link_objects.items);
1107
1108 var prev_has_extra_flags = false;
1109
1110 for (transitive_deps.link_objects.items) |link_object| {
1111 switch (link_object) {
1112 .static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
1113
1114 .other_step => |other| switch (other.kind) {
1115 .exe => @panic("Cannot link with an executable build artifact"),
1116 .test_exe => @panic("Cannot link with an executable build artifact"),
1117 .@"test" => @panic("Cannot link with a test"),
1118 .obj => {
1119 try zig_args.append(other.getOutputSource().getPath(builder));
1120 },
1121 .lib => l: {
1122 if (self.isStaticLibrary() and other.isStaticLibrary()) {
1123 // Avoid putting a static library inside a static library.
1124 break :l;
1125 }
1126
1127 const full_path_lib = other.getOutputLibSource().getPath(builder);
1128 try zig_args.append(full_path_lib);
1129
1130 if (other.linkage == Linkage.dynamic and !self.target.isWindows()) {
1131 if (fs.path.dirname(full_path_lib)) |dirname| {
1132 try zig_args.append("-rpath");
1133 try zig_args.append(dirname);
1134 }
1135 }
1136 },
1137 },
1138
1139 .system_lib => |system_lib| {
1140 const prefix: []const u8 = prefix: {
1141 if (system_lib.needed) break :prefix "-needed-l";
1142 if (system_lib.weak) {
1143 if (self.target.isDarwin()) break :prefix "-weak-l";
1144 log.warn("Weak library import used for a non-darwin target, this will be converted to normally library import `-lname`", .{});
1145 }
1146 break :prefix "-l";
1147 };
1148 switch (system_lib.use_pkg_config) {
1149 .no => try zig_args.append(builder.fmt("{s}{s}", .{ prefix, system_lib.name })),
1150 .yes, .force => {
1151 if (self.runPkgConfig(system_lib.name)) |args| {
1152 try zig_args.appendSlice(args);
1153 } else |err| switch (err) {
1154 error.PkgConfigInvalidOutput,
1155 error.PkgConfigCrashed,
1156 error.PkgConfigFailed,
1157 error.PkgConfigNotInstalled,
1158 error.PackageNotFound,
1159 => switch (system_lib.use_pkg_config) {
1160 .yes => {
1161 // pkg-config failed, so fall back to linking the library
1162 // by name directly.
1163 try zig_args.append(builder.fmt("{s}{s}", .{
1164 prefix,
1165 system_lib.name,
1166 }));
1167 },
1168 .force => {
1169 panic("pkg-config failed for library {s}", .{system_lib.name});
1170 },
1171 .no => unreachable,
1172 },
1173
1174 else => |e| return e,
1175 }
1176 },
1177 }
1178 },
1179
1180 .assembly_file => |asm_file| {
1181 if (prev_has_extra_flags) {
1182 try zig_args.append("-extra-cflags");
1183 try zig_args.append("--");
1184 prev_has_extra_flags = false;
1185 }
1186 try zig_args.append(asm_file.getPath(builder));
1187 },
1188
1189 .c_source_file => |c_source_file| {
1190 if (c_source_file.args.len == 0) {
1191 if (prev_has_extra_flags) {
1192 try zig_args.append("-cflags");
1193 try zig_args.append("--");
1194 prev_has_extra_flags = false;
1195 }
1196 } else {
1197 try zig_args.append("-cflags");
1198 for (c_source_file.args) |arg| {
1199 try zig_args.append(arg);
1200 }
1201 try zig_args.append("--");
1202 }
1203 try zig_args.append(c_source_file.source.getPath(builder));
1204 },
1205
1206 .c_source_files => |c_source_files| {
1207 if (c_source_files.flags.len == 0) {
1208 if (prev_has_extra_flags) {
1209 try zig_args.append("-cflags");
1210 try zig_args.append("--");
1211 prev_has_extra_flags = false;
1212 }
1213 } else {
1214 try zig_args.append("-cflags");
1215 for (c_source_files.flags) |flag| {
1216 try zig_args.append(flag);
1217 }
1218 try zig_args.append("--");
1219 }
1220 for (c_source_files.files) |file| {
1221 try zig_args.append(builder.pathFromRoot(file));
1222 }
1223 },
1224 }
1225 }
1226
1227 if (transitive_deps.is_linking_libcpp) {
1228 try zig_args.append("-lc++");
1229 }
1230
1231 if (transitive_deps.is_linking_libc) {
1232 try zig_args.append("-lc");
1233 }
1234
1235 if (self.image_base) |image_base| {
1236 try zig_args.append("--image-base");
1237 try zig_args.append(builder.fmt("0x{x}", .{image_base}));
1238 }
1239
1240 if (self.filter) |filter| {
1241 try zig_args.append("--test-filter");
1242 try zig_args.append(filter);
1243 }
1244
1245 if (self.test_evented_io) {
1246 try zig_args.append("--test-evented-io");
1247 }
1248
1249 if (self.name_prefix.len != 0) {
1250 try zig_args.append("--test-name-prefix");
1251 try zig_args.append(self.name_prefix);
1252 }
1253
1254 if (self.test_runner) |test_runner| {
1255 try zig_args.append("--test-runner");
1256 try zig_args.append(builder.pathFromRoot(test_runner));
1257 }
1258
1259 for (builder.debug_log_scopes) |log_scope| {
1260 try zig_args.append("--debug-log");
1261 try zig_args.append(log_scope);
1262 }
1263
1264 if (builder.debug_compile_errors) {
1265 try zig_args.append("--debug-compile-errors");
1266 }
1267
1268 if (builder.verbose_cimport) zig_args.append("--verbose-cimport") catch unreachable;
1269 if (builder.verbose_air) zig_args.append("--verbose-air") catch unreachable;
1270 if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable;
1271 if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable;
1272 if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable;
1273 if (builder.verbose_llvm_cpu_features) zig_args.append("--verbose-llvm-cpu-features") catch unreachable;
1274
1275 if (self.emit_analysis.getArg(builder, "emit-analysis")) |arg| try zig_args.append(arg);
1276 if (self.emit_asm.getArg(builder, "emit-asm")) |arg| try zig_args.append(arg);
1277 if (self.emit_bin.getArg(builder, "emit-bin")) |arg| try zig_args.append(arg);
1278 if (self.emit_docs.getArg(builder, "emit-docs")) |arg| try zig_args.append(arg);
1279 if (self.emit_implib.getArg(builder, "emit-implib")) |arg| try zig_args.append(arg);
1280 if (self.emit_llvm_bc.getArg(builder, "emit-llvm-bc")) |arg| try zig_args.append(arg);
1281 if (self.emit_llvm_ir.getArg(builder, "emit-llvm-ir")) |arg| try zig_args.append(arg);
1282
1283 if (self.emit_h) try zig_args.append("-femit-h");
1284
1285 try addFlag(&zig_args, "strip", self.strip);
1286 try addFlag(&zig_args, "unwind-tables", self.unwind_tables);
1287
1288 switch (self.compress_debug_sections) {
1289 .none => {},
1290 .zlib => try zig_args.append("--compress-debug-sections=zlib"),
1291 }
1292
1293 if (self.link_eh_frame_hdr) {
1294 try zig_args.append("--eh-frame-hdr");
1295 }
1296 if (self.link_emit_relocs) {
1297 try zig_args.append("--emit-relocs");
1298 }
1299 if (self.link_function_sections) {
1300 try zig_args.append("-ffunction-sections");
1301 }
1302 if (self.link_gc_sections) |x| {
1303 try zig_args.append(if (x) "--gc-sections" else "--no-gc-sections");
1304 }
1305 if (self.linker_allow_shlib_undefined) |x| {
1306 try zig_args.append(if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined");
1307 }
1308 if (self.link_z_notext) {
1309 try zig_args.append("-z");
1310 try zig_args.append("notext");
1311 }
1312 if (!self.link_z_relro) {
1313 try zig_args.append("-z");
1314 try zig_args.append("norelro");
1315 }
1316 if (self.link_z_lazy) {
1317 try zig_args.append("-z");
1318 try zig_args.append("lazy");
1319 }
1320 if (self.link_z_common_page_size) |size| {
1321 try zig_args.append("-z");
1322 try zig_args.append(builder.fmt("common-page-size={d}", .{size}));
1323 }
1324 if (self.link_z_max_page_size) |size| {
1325 try zig_args.append("-z");
1326 try zig_args.append(builder.fmt("max-page-size={d}", .{size}));
1327 }
1328
1329 if (self.libc_file) |libc_file| {
1330 try zig_args.append("--libc");
1331 try zig_args.append(libc_file.getPath(builder));
1332 } else if (builder.libc_file) |libc_file| {
1333 try zig_args.append("--libc");
1334 try zig_args.append(libc_file);
1335 }
1336
1337 switch (self.optimize) {
1338 .Debug => {}, // Skip since it's the default.
1339 else => zig_args.append(builder.fmt("-O{s}", .{@tagName(self.optimize)})) catch unreachable,
1340 }
1341
1342 try zig_args.append("--cache-dir");
1343 try zig_args.append(builder.pathFromRoot(builder.cache_root));
1344
1345 try zig_args.append("--global-cache-dir");
1346 try zig_args.append(builder.pathFromRoot(builder.global_cache_root));
1347
1348 zig_args.append("--name") catch unreachable;
1349 zig_args.append(self.name) catch unreachable;
1350
1351 if (self.linkage) |some| switch (some) {
1352 .dynamic => try zig_args.append("-dynamic"),
1353 .static => try zig_args.append("-static"),
1354 };
1355 if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic) {
1356 if (self.version) |version| {
1357 zig_args.append("--version") catch unreachable;
1358 zig_args.append(builder.fmt("{}", .{version})) catch unreachable;
1359 }
1360
1361 if (self.target.isDarwin()) {
1362 const install_name = self.install_name orelse builder.fmt("@rpath/{s}{s}{s}", .{
1363 self.target.libPrefix(),
1364 self.name,
1365 self.target.dynamicLibSuffix(),
1366 });
1367 try zig_args.append("-install_name");
1368 try zig_args.append(install_name);
1369 }
1370 }
1371
1372 if (self.entitlements) |entitlements| {
1373 try zig_args.appendSlice(&[_][]const u8{ "--entitlements", entitlements });
1374 }
1375 if (self.pagezero_size) |pagezero_size| {
1376 const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{pagezero_size});
1377 try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });
1378 }
1379 if (self.search_strategy) |strat| switch (strat) {
1380 .paths_first => try zig_args.append("-search_paths_first"),
1381 .dylibs_first => try zig_args.append("-search_dylibs_first"),
1382 };
1383 if (self.headerpad_size) |headerpad_size| {
1384 const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{headerpad_size});
1385 try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size });
1386 }
1387 if (self.headerpad_max_install_names) {
1388 try zig_args.append("-headerpad_max_install_names");
1389 }
1390 if (self.dead_strip_dylibs) {
1391 try zig_args.append("-dead_strip_dylibs");
1392 }
1393
1394 try addFlag(&zig_args, "compiler-rt", self.bundle_compiler_rt);
1395 try addFlag(&zig_args, "single-threaded", self.single_threaded);
1396 if (self.disable_stack_probing) {
1397 try zig_args.append("-fno-stack-check");
1398 }
1399 try addFlag(&zig_args, "stack-protector", self.stack_protector);
1400 if (self.red_zone) |red_zone| {
1401 if (red_zone) {
1402 try zig_args.append("-mred-zone");
1403 } else {
1404 try zig_args.append("-mno-red-zone");
1405 }
1406 }
1407 try addFlag(&zig_args, "omit-frame-pointer", self.omit_frame_pointer);
1408 try addFlag(&zig_args, "dll-export-fns", self.dll_export_fns);
1409
1410 if (self.disable_sanitize_c) {
1411 try zig_args.append("-fno-sanitize-c");
1412 }
1413 if (self.sanitize_thread) {
1414 try zig_args.append("-fsanitize-thread");
1415 }
1416 if (self.rdynamic) {
1417 try zig_args.append("-rdynamic");
1418 }
1419 if (self.import_memory) {
1420 try zig_args.append("--import-memory");
1421 }
1422 if (self.import_symbols) {
1423 try zig_args.append("--import-symbols");
1424 }
1425 if (self.import_table) {
1426 try zig_args.append("--import-table");
1427 }
1428 if (self.export_table) {
1429 try zig_args.append("--export-table");
1430 }
1431 if (self.initial_memory) |initial_memory| {
1432 try zig_args.append(builder.fmt("--initial-memory={d}", .{initial_memory}));
1433 }
1434 if (self.max_memory) |max_memory| {
1435 try zig_args.append(builder.fmt("--max-memory={d}", .{max_memory}));
1436 }
1437 if (self.shared_memory) {
1438 try zig_args.append("--shared-memory");
1439 }
1440 if (self.global_base) |global_base| {
1441 try zig_args.append(builder.fmt("--global-base={d}", .{global_base}));
1442 }
1443
1444 if (self.code_model != .default) {
1445 try zig_args.append("-mcmodel");
1446 try zig_args.append(@tagName(self.code_model));
1447 }
1448 if (self.wasi_exec_model) |model| {
1449 try zig_args.append(builder.fmt("-mexec-model={s}", .{@tagName(model)}));
1450 }
1451 for (self.export_symbol_names) |symbol_name| {
1452 try zig_args.append(builder.fmt("--export={s}", .{symbol_name}));
1453 }
1454
1455 if (!self.target.isNative()) {
1456 try zig_args.appendSlice(&.{
1457 "-target", try self.target.zigTriple(builder.allocator),
1458 "-mcpu", try std.Build.serializeCpu(builder.allocator, self.target.getCpu()),
1459 });
1460
1461 if (self.target.dynamic_linker.get()) |dynamic_linker| {
1462 try zig_args.append("--dynamic-linker");
1463 try zig_args.append(dynamic_linker);
1464 }
1465 }
1466
1467 if (self.linker_script) |linker_script| {
1468 try zig_args.append("--script");
1469 try zig_args.append(linker_script.getPath(builder));
1470 }
1471
1472 if (self.version_script) |version_script| {
1473 try zig_args.append("--version-script");
1474 try zig_args.append(builder.pathFromRoot(version_script));
1475 }
1476
1477 if (self.kind == .@"test") {
1478 if (self.exec_cmd_args) |exec_cmd_args| {
1479 for (exec_cmd_args) |cmd_arg| {
1480 if (cmd_arg) |arg| {
1481 try zig_args.append("--test-cmd");
1482 try zig_args.append(arg);
1483 } else {
1484 try zig_args.append("--test-cmd-bin");
1485 }
1486 }
1487 } else {
1488 const need_cross_glibc = self.target.isGnuLibC() and transitive_deps.is_linking_libc;
1489
1490 switch (builder.host.getExternalExecutor(self.target_info, .{
1491 .qemu_fixes_dl = need_cross_glibc and builder.glibc_runtimes_dir != null,
1492 .link_libc = transitive_deps.is_linking_libc,
1493 })) {
1494 .native => {},
1495 .bad_dl, .bad_os_or_cpu => {
1496 try zig_args.append("--test-no-exec");
1497 },
1498 .rosetta => if (builder.enable_rosetta) {
1499 try zig_args.append("--test-cmd-bin");
1500 } else {
1501 try zig_args.append("--test-no-exec");
1502 },
1503 .qemu => |bin_name| ok: {
1504 if (builder.enable_qemu) qemu: {
1505 const glibc_dir_arg = if (need_cross_glibc)
1506 builder.glibc_runtimes_dir orelse break :qemu
1507 else
1508 null;
1509 try zig_args.append("--test-cmd");
1510 try zig_args.append(bin_name);
1511 if (glibc_dir_arg) |dir| {
1512 // TODO look into making this a call to `linuxTriple`. This
1513 // needs the directory to be called "i686" rather than
1514 // "x86" which is why we do it manually here.
1515 const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}";
1516 const cpu_arch = self.target.getCpuArch();
1517 const os_tag = self.target.getOsTag();
1518 const abi = self.target.getAbi();
1519 const cpu_arch_name: []const u8 = if (cpu_arch == .x86)
1520 "i686"
1521 else
1522 @tagName(cpu_arch);
1523 const full_dir = try std.fmt.allocPrint(builder.allocator, fmt_str, .{
1524 dir, cpu_arch_name, @tagName(os_tag), @tagName(abi),
1525 });
1526
1527 try zig_args.append("--test-cmd");
1528 try zig_args.append("-L");
1529 try zig_args.append("--test-cmd");
1530 try zig_args.append(full_dir);
1531 }
1532 try zig_args.append("--test-cmd-bin");
1533 break :ok;
1534 }
1535 try zig_args.append("--test-no-exec");
1536 },
1537 .wine => |bin_name| if (builder.enable_wine) {
1538 try zig_args.append("--test-cmd");
1539 try zig_args.append(bin_name);
1540 try zig_args.append("--test-cmd-bin");
1541 } else {
1542 try zig_args.append("--test-no-exec");
1543 },
1544 .wasmtime => |bin_name| if (builder.enable_wasmtime) {
1545 try zig_args.append("--test-cmd");
1546 try zig_args.append(bin_name);
1547 try zig_args.append("--test-cmd");
1548 try zig_args.append("--dir=.");
1549 try zig_args.append("--test-cmd-bin");
1550 } else {
1551 try zig_args.append("--test-no-exec");
1552 },
1553 .darling => |bin_name| if (builder.enable_darling) {
1554 try zig_args.append("--test-cmd");
1555 try zig_args.append(bin_name);
1556 try zig_args.append("--test-cmd-bin");
1557 } else {
1558 try zig_args.append("--test-no-exec");
1559 },
1560 }
1561 }
1562 } else if (self.kind == .test_exe) {
1563 try zig_args.append("--test-no-exec");
1564 }
1565
1566 for (self.packages.items) |pkg| {
1567 try self.makePackageCmd(pkg, &zig_args);
1568 }
1569
1570 for (self.include_dirs.items) |include_dir| {
1571 switch (include_dir) {
1572 .raw_path => |include_path| {
1573 try zig_args.append("-I");
1574 try zig_args.append(builder.pathFromRoot(include_path));
1575 },
1576 .raw_path_system => |include_path| {
1577 if (builder.sysroot != null) {
1578 try zig_args.append("-iwithsysroot");
1579 } else {
1580 try zig_args.append("-isystem");
1581 }
1582
1583 const resolved_include_path = builder.pathFromRoot(include_path);
1584
1585 const common_include_path = if (builtin.os.tag == .windows and builder.sysroot != null and fs.path.isAbsolute(resolved_include_path)) blk: {
1586 // We need to check for disk designator and strip it out from dir path so
1587 // that zig/clang can concat resolved_include_path with sysroot.
1588 const disk_designator = fs.path.diskDesignatorWindows(resolved_include_path);
1589
1590 if (mem.indexOf(u8, resolved_include_path, disk_designator)) |where| {
1591 break :blk resolved_include_path[where + disk_designator.len ..];
1592 }
1593
1594 break :blk resolved_include_path;
1595 } else resolved_include_path;
1596
1597 try zig_args.append(common_include_path);
1598 },
1599 .other_step => |other| {
1600 if (other.emit_h) {
1601 const h_path = other.getOutputHSource().getPath(builder);
1602 try zig_args.append("-isystem");
1603 try zig_args.append(fs.path.dirname(h_path).?);
1604 }
1605 if (other.installed_headers.items.len > 0) {
1606 for (other.installed_headers.items) |install_step| {
1607 try install_step.make();
1608 }
1609 try zig_args.append("-I");
1610 try zig_args.append(builder.pathJoin(&.{
1611 other.builder.install_prefix, "include",
1612 }));
1613 }
1614 },
1615 .config_header_step => |config_header| {
1616 try zig_args.append("-I");
1617 try zig_args.append(config_header.output_dir);
1618 },
1619 }
1620 }
1621
1622 for (self.lib_paths.items) |lib_path| {
1623 try zig_args.append("-L");
1624 try zig_args.append(lib_path);
1625 }
1626
1627 for (self.rpaths.items) |rpath| {
1628 try zig_args.append("-rpath");
1629 try zig_args.append(rpath);
1630 }
1631
1632 for (self.c_macros.items) |c_macro| {
1633 try zig_args.append("-D");
1634 try zig_args.append(c_macro);
1635 }
1636
1637 if (self.target.isDarwin()) {
1638 for (self.framework_dirs.items) |dir| {
1639 if (builder.sysroot != null) {
1640 try zig_args.append("-iframeworkwithsysroot");
1641 } else {
1642 try zig_args.append("-iframework");
1643 }
1644 try zig_args.append(dir);
1645 try zig_args.append("-F");
1646 try zig_args.append(dir);
1647 }
1648
1649 var it = self.frameworks.iterator();
1650 while (it.next()) |entry| {
1651 const name = entry.key_ptr.*;
1652 const info = entry.value_ptr.*;
1653 if (info.needed) {
1654 zig_args.append("-needed_framework") catch unreachable;
1655 } else if (info.weak) {
1656 zig_args.append("-weak_framework") catch unreachable;
1657 } else {
1658 zig_args.append("-framework") catch unreachable;
1659 }
1660 zig_args.append(name) catch unreachable;
1661 }
1662 } else {
1663 if (self.framework_dirs.items.len > 0) {
1664 log.info("Framework directories have been added for a non-darwin target, this will have no affect on the build", .{});
1665 }
1666
1667 if (self.frameworks.count() > 0) {
1668 log.info("Frameworks have been added for a non-darwin target, this will have no affect on the build", .{});
1669 }
1670 }
1671
1672 if (builder.sysroot) |sysroot| {
1673 try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });
1674 }
1675
1676 for (builder.search_prefixes.items) |search_prefix| {
1677 try zig_args.append("-L");
1678 try zig_args.append(builder.pathJoin(&.{
1679 search_prefix, "lib",
1680 }));
1681 try zig_args.append("-I");
1682 try zig_args.append(builder.pathJoin(&.{
1683 search_prefix, "include",
1684 }));
1685 }
1686
1687 try addFlag(&zig_args, "valgrind", self.valgrind_support);
1688 try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
1689 try addFlag(&zig_args, "build-id", self.build_id);
1690
1691 if (self.override_lib_dir) |dir| {
1692 try zig_args.append("--zig-lib-dir");
1693 try zig_args.append(builder.pathFromRoot(dir));
1694 } else if (builder.override_lib_dir) |dir| {
1695 try zig_args.append("--zig-lib-dir");
1696 try zig_args.append(builder.pathFromRoot(dir));
1697 }
1698
1699 if (self.main_pkg_path) |dir| {
1700 try zig_args.append("--main-pkg-path");
1701 try zig_args.append(builder.pathFromRoot(dir));
1702 }
1703
1704 try addFlag(&zig_args, "PIC", self.force_pic);
1705 try addFlag(&zig_args, "PIE", self.pie);
1706 try addFlag(&zig_args, "lto", self.want_lto);
1707
1708 if (self.subsystem) |subsystem| {
1709 try zig_args.append("--subsystem");
1710 try zig_args.append(switch (subsystem) {
1711 .Console => "console",
1712 .Windows => "windows",
1713 .Posix => "posix",
1714 .Native => "native",
1715 .EfiApplication => "efi_application",
1716 .EfiBootServiceDriver => "efi_boot_service_driver",
1717 .EfiRom => "efi_rom",
1718 .EfiRuntimeDriver => "efi_runtime_driver",
1719 });
1720 }
1721
1722 try zig_args.append("--enable-cache");
1723
1724 // Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux
1725 // 2,097,152. If our args exceed 30 KiB, we instead write them to a "response file" and
1726 // pass that to zig, e.g. via 'zig build-lib @args.rsp'
1727 // See @file syntax here: https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html
1728 var args_length: usize = 0;
1729 for (zig_args.items) |arg| {
1730 args_length += arg.len + 1; // +1 to account for null terminator
1731 }
1732 if (args_length >= 30 * 1024) {
1733 const args_dir = try fs.path.join(
1734 builder.allocator,
1735 &[_][]const u8{ builder.pathFromRoot("zig-cache"), "args" },
1736 );
1737 try std.fs.cwd().makePath(args_dir);
1738
1739 var args_arena = std.heap.ArenaAllocator.init(builder.allocator);
1740 defer args_arena.deinit();
1741
1742 const args_to_escape = zig_args.items[2..];
1743 var escaped_args = try ArrayList([]const u8).initCapacity(args_arena.allocator(), args_to_escape.len);
1744
1745 arg_blk: for (args_to_escape) |arg| {
1746 for (arg) |c, arg_idx| {
1747 if (c == '\\' or c == '"') {
1748 // Slow path for arguments that need to be escaped. We'll need to allocate and copy
1749 var escaped = try ArrayList(u8).initCapacity(args_arena.allocator(), arg.len + 1);
1750 const writer = escaped.writer();
1751 writer.writeAll(arg[0..arg_idx]) catch unreachable;
1752 for (arg[arg_idx..]) |to_escape| {
1753 if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\');
1754 try writer.writeByte(to_escape);
1755 }
1756 escaped_args.appendAssumeCapacity(escaped.items);
1757 continue :arg_blk;
1758 }
1759 }
1760 escaped_args.appendAssumeCapacity(arg); // no escaping needed so just use original argument
1761 }
1762
1763 // Write the args to zig-cache/args/<SHA256 hash of args> to avoid conflicts with
1764 // other zig build commands running in parallel.
1765 const partially_quoted = try std.mem.join(builder.allocator, "\" \"", escaped_args.items);
1766 const args = try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "\"", partially_quoted, "\"" });
1767
1768 var args_hash: [Sha256.digest_length]u8 = undefined;
1769 Sha256.hash(args, &args_hash, .{});
1770 var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined;
1771 _ = try std.fmt.bufPrint(
1772 &args_hex_hash,
1773 "{s}",
1774 .{std.fmt.fmtSliceHexLower(&args_hash)},
1775 );
1776
1777 const args_file = try fs.path.join(builder.allocator, &[_][]const u8{ args_dir, args_hex_hash[0..] });
1778 try std.fs.cwd().writeFile(args_file, args);
1779
1780 zig_args.shrinkRetainingCapacity(2);
1781 try zig_args.append(try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "@", args_file }));
1782 }
1783
1784 const output_dir_nl = try builder.execFromStep(zig_args.items, &self.step);
1785 const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n");
1786
1787 if (self.output_dir) |output_dir| {
1788 var src_dir = try std.fs.cwd().openIterableDir(build_output_dir, .{});
1789 defer src_dir.close();
1790
1791 // Create the output directory if it doesn't exist.
1792 try std.fs.cwd().makePath(output_dir);
1793
1794 var dest_dir = try std.fs.cwd().openDir(output_dir, .{});
1795 defer dest_dir.close();
1796
1797 var it = src_dir.iterate();
1798 while (try it.next()) |entry| {
1799 // The compiler can put these files into the same directory, but we don't
1800 // want to copy them over.
1801 if (mem.eql(u8, entry.name, "llvm-ar.id") or
1802 mem.eql(u8, entry.name, "libs.txt") or
1803 mem.eql(u8, entry.name, "builtin.zig") or
1804 mem.eql(u8, entry.name, "zld.id") or
1805 mem.eql(u8, entry.name, "lld.id")) continue;
1806
1807 _ = try src_dir.dir.updateFile(entry.name, dest_dir, entry.name, .{});
1808 }
1809 } else {
1810 self.output_dir = build_output_dir;
1811 }
1812
1813 // This will ensure all output filenames will now have the output_dir available!
1814 self.computeOutFileNames();
1815
1816 // Update generated files
1817 if (self.output_dir != null) {
1818 self.output_path_source.path = builder.pathJoin(
1819 &.{ self.output_dir.?, self.out_filename },
1820 );
1821
1822 if (self.emit_h) {
1823 self.output_h_path_source.path = builder.pathJoin(
1824 &.{ self.output_dir.?, self.out_h_filename },
1825 );
1826 }
1827
1828 if (self.target.isWindows() or self.target.isUefi()) {
1829 self.output_pdb_path_source.path = builder.pathJoin(
1830 &.{ self.output_dir.?, self.out_pdb_filename },
1831 );
1832 }
1833 }
1834
1835 if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) {
1836 try doAtomicSymLinks(builder.allocator, self.getOutputSource().getPath(builder), self.major_only_filename.?, self.name_only_filename.?);
1837 }
1838}
1839
1840fn isLibCLibrary(name: []const u8) bool {
1841 const libc_libraries = [_][]const u8{ "c", "m", "dl", "rt", "pthread" };
1842 for (libc_libraries) |libc_lib_name| {
1843 if (mem.eql(u8, name, libc_lib_name))
1844 return true;
1845 }
1846 return false;
1847}
1848
1849fn isLibCppLibrary(name: []const u8) bool {
1850 const libcpp_libraries = [_][]const u8{ "c++", "stdc++" };
1851 for (libcpp_libraries) |libcpp_lib_name| {
1852 if (mem.eql(u8, name, libcpp_lib_name))
1853 return true;
1854 }
1855 return false;
1856}
1857
1858/// Returned slice must be freed by the caller.
1859fn findVcpkgRoot(allocator: Allocator) !?[]const u8 {
1860 const appdata_path = try fs.getAppDataDir(allocator, "vcpkg");
1861 defer allocator.free(appdata_path);
1862
1863 const path_file = try fs.path.join(allocator, &[_][]const u8{ appdata_path, "vcpkg.path.txt" });
1864 defer allocator.free(path_file);
1865
1866 const file = fs.cwd().openFile(path_file, .{}) catch return null;
1867 defer file.close();
1868
1869 const size = @intCast(usize, try file.getEndPos());
1870 const vcpkg_path = try allocator.alloc(u8, size);
1871 const size_read = try file.read(vcpkg_path);
1872 std.debug.assert(size == size_read);
1873
1874 return vcpkg_path;
1875}
1876
1877pub fn doAtomicSymLinks(allocator: Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
1878 const out_dir = fs.path.dirname(output_path) orelse ".";
1879 const out_basename = fs.path.basename(output_path);
1880 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1881 const major_only_path = fs.path.join(
1882 allocator,
1883 &[_][]const u8{ out_dir, filename_major_only },
1884 ) catch unreachable;
1885 fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
1886 log.err("Unable to symlink {s} -> {s}", .{ major_only_path, out_basename });
1887 return err;
1888 };
1889 // sym link for libfoo.so to libfoo.so.1
1890 const name_only_path = fs.path.join(
1891 allocator,
1892 &[_][]const u8{ out_dir, filename_name_only },
1893 ) catch unreachable;
1894 fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
1895 log.err("Unable to symlink {s} -> {s}", .{ name_only_path, filename_major_only });
1896 return err;
1897 };
1898}
1899
1900fn execPkgConfigList(self: *std.Build, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg {
1901 const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore);
1902 var list = ArrayList(PkgConfigPkg).init(self.allocator);
1903 errdefer list.deinit();
1904 var line_it = mem.tokenize(u8, stdout, "\r\n");
1905 while (line_it.next()) |line| {
1906 if (mem.trim(u8, line, " \t").len == 0) continue;
1907 var tok_it = mem.tokenize(u8, line, " \t");
1908 try list.append(PkgConfigPkg{
1909 .name = tok_it.next() orelse return error.PkgConfigInvalidOutput,
1910 .desc = tok_it.rest(),
1911 });
1912 }
1913 return list.toOwnedSlice();
1914}
1915
1916fn getPkgConfigList(self: *std.Build) ![]const PkgConfigPkg {
1917 if (self.pkg_config_pkg_list) |res| {
1918 return res;
1919 }
1920 var code: u8 = undefined;
1921 if (execPkgConfigList(self, &code)) |list| {
1922 self.pkg_config_pkg_list = list;
1923 return list;
1924 } else |err| {
1925 const result = switch (err) {
1926 error.ProcessTerminated => error.PkgConfigCrashed,
1927 error.ExecNotSupported => error.PkgConfigFailed,
1928 error.ExitCodeFailure => error.PkgConfigFailed,
1929 error.FileNotFound => error.PkgConfigNotInstalled,
1930 error.InvalidName => error.PkgConfigNotInstalled,
1931 error.PkgConfigInvalidOutput => error.PkgConfigInvalidOutput,
1932 error.ChildExecFailed => error.PkgConfigFailed,
1933 else => return err,
1934 };
1935 self.pkg_config_pkg_list = result;
1936 return result;
1937 }
1938}
1939
1940test "addPackage" {
1941 if (builtin.os.tag == .wasi) return error.SkipZigTest;
1942
1943 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
1944 defer arena.deinit();
1945
1946 const host = try NativeTargetInfo.detect(.{});
1947
1948 var builder = try std.Build.create(
1949 arena.allocator(),
1950 "test",
1951 "test",
1952 "test",
1953 "test",
1954 host,
1955 );
1956 defer builder.destroy();
1957
1958 const pkg_dep = Pkg{
1959 .name = "pkg_dep",
1960 .source = .{ .path = "/not/a/pkg_dep.zig" },
1961 };
1962 const pkg_top = Pkg{
1963 .name = "pkg_dep",
1964 .source = .{ .path = "/not/a/pkg_top.zig" },
1965 .dependencies = &[_]Pkg{pkg_dep},
1966 };
1967
1968 var exe = builder.addExecutable("not_an_executable", "/not/an/executable.zig");
1969 exe.addPackage(pkg_top);
1970
1971 try std.testing.expectEqual(@as(usize, 1), exe.packages.items.len);
1972
1973 const dupe = exe.packages.items[0];
1974 try std.testing.expectEqualStrings(pkg_top.name, dupe.name);
1975}
1976
1977fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool) !void {
1978 const cond = opt orelse return;
1979 try args.ensureUnusedCapacity(1);
1980 if (cond) {
1981 args.appendAssumeCapacity("-f" ++ name);
1982 } else {
1983 args.appendAssumeCapacity("-fno-" ++ name);
1984 }
1985}
1986
1987const TransitiveDeps = struct {
1988 link_objects: ArrayList(LinkObject),
1989 seen_system_libs: StringHashMap(void),
1990 seen_steps: std.AutoHashMap(*const Step, void),
1991 is_linking_libcpp: bool,
1992 is_linking_libc: bool,
1993 frameworks: *StringHashMap(FrameworkLinkInfo),
1994
1995 fn add(td: *TransitiveDeps, link_objects: []const LinkObject) !void {
1996 try td.link_objects.ensureUnusedCapacity(link_objects.len);
1997
1998 for (link_objects) |link_object| {
1999 try td.link_objects.append(link_object);
2000 switch (link_object) {
2001 .other_step => |other| try addInner(td, other, other.isDynamicLibrary()),
2002 else => {},
2003 }
2004 }
2005 }
2006
2007 fn addInner(td: *TransitiveDeps, other: *LibExeObjStep, dyn: bool) !void {
2008 // Inherit dependency on libc and libc++
2009 td.is_linking_libcpp = td.is_linking_libcpp or other.is_linking_libcpp;
2010 td.is_linking_libc = td.is_linking_libc or other.is_linking_libc;
2011
2012 // Inherit dependencies on darwin frameworks
2013 if (!dyn) {
2014 var it = other.frameworks.iterator();
2015 while (it.next()) |framework| {
2016 try td.frameworks.put(framework.key_ptr.*, framework.value_ptr.*);
2017 }
2018 }
2019
2020 // Inherit dependencies on system libraries and static libraries.
2021 for (other.link_objects.items) |other_link_object| {
2022 switch (other_link_object) {
2023 .system_lib => |system_lib| {
2024 if ((try td.seen_system_libs.fetchPut(system_lib.name, {})) != null)
2025 continue;
2026
2027 if (dyn)
2028 continue;
2029
2030 try td.link_objects.append(other_link_object);
2031 },
2032 .other_step => |inner_other| {
2033 if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)
2034 continue;
2035
2036 if (!dyn)
2037 try td.link_objects.append(other_link_object);
2038
2039 try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());
2040 },
2041 else => continue,
2042 }
2043 }
2044 }
2045};
lib/std/Build/OptionsStep.zig+3-3
...@@ -3,7 +3,7 @@ const builtin = @import("builtin");...@@ -3,7 +3,7 @@ const builtin = @import("builtin");
3const fs = std.fs;3const fs = std.fs;
4const Step = std.Build.Step;4const Step = std.Build.Step;
5const GeneratedFile = std.Build.GeneratedFile;5const GeneratedFile = std.Build.GeneratedFile;
6const LibExeObjStep = std.Build.LibExeObjStep;6const CompileStep = std.Build.CompileStep;
7const FileSource = std.Build.FileSource;7const FileSource = std.Build.FileSource;
88
9const OptionsStep = @This();9const OptionsStep = @This();
...@@ -195,7 +195,7 @@ pub fn addOptionFileSource(...@@ -195,7 +195,7 @@ pub fn addOptionFileSource(
195195
196/// The value is the path in the cache dir.196/// The value is the path in the cache dir.
197/// Adds a dependency automatically.197/// Adds a dependency automatically.
198pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *LibExeObjStep) void {198pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *CompileStep) void {
199 self.artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch unreachable;199 self.artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch unreachable;
200 self.step.dependOn(&artifact.step);200 self.step.dependOn(&artifact.step);
201}201}
...@@ -266,7 +266,7 @@ fn hashContentsToFileName(self: *OptionsStep) [64]u8 {...@@ -266,7 +266,7 @@ fn hashContentsToFileName(self: *OptionsStep) [64]u8 {
266266
267const OptionArtifactArg = struct {267const OptionArtifactArg = struct {
268 name: []const u8,268 name: []const u8,
269 artifact: *LibExeObjStep,269 artifact: *CompileStep,
270};270};
271271
272const OptionFileSourceArg = struct {272const OptionFileSourceArg = struct {
lib/std/Build/RunStep.zig+5-5
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Step = std.Build.Step;3const Step = std.Build.Step;
4const LibExeObjStep = std.Build.LibExeObjStep;4const CompileStep = std.Build.CompileStep;
5const WriteFileStep = std.Build.WriteFileStep;5const WriteFileStep = std.Build.WriteFileStep;
6const fs = std.fs;6const fs = std.fs;
7const mem = std.mem;7const mem = std.mem;
...@@ -48,7 +48,7 @@ pub const StdIoAction = union(enum) {...@@ -48,7 +48,7 @@ pub const StdIoAction = union(enum) {
48};48};
4949
50pub const Arg = union(enum) {50pub const Arg = union(enum) {
51 artifact: *LibExeObjStep,51 artifact: *CompileStep,
52 file_source: std.Build.FileSource,52 file_source: std.Build.FileSource,
53 bytes: []u8,53 bytes: []u8,
54};54};
...@@ -66,7 +66,7 @@ pub fn create(builder: *std.Build, name: []const u8) *RunStep {...@@ -66,7 +66,7 @@ pub fn create(builder: *std.Build, name: []const u8) *RunStep {
66 return self;66 return self;
67}67}
6868
69pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void {69pub fn addArtifactArg(self: *RunStep, artifact: *CompileStep) void {
70 self.argv.append(Arg{ .artifact = artifact }) catch unreachable;70 self.argv.append(Arg{ .artifact = artifact }) catch unreachable;
71 self.step.dependOn(&artifact.step);71 self.step.dependOn(&artifact.step);
72}72}
...@@ -355,13 +355,13 @@ fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {...@@ -355,13 +355,13 @@ fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
355 std.debug.print("\n", .{});355 std.debug.print("\n", .{});
356}356}
357357
358fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void {358fn addPathForDynLibs(self: *RunStep, artifact: *CompileStep) void {
359 addPathForDynLibsInternal(&self.step, self.builder, artifact);359 addPathForDynLibsInternal(&self.step, self.builder, artifact);
360}360}
361361
362/// This should only be used for internal usage, this is called automatically362/// This should only be used for internal usage, this is called automatically
363/// for the user.363/// for the user.
364pub fn addPathForDynLibsInternal(step: *Step, builder: *std.Build, artifact: *LibExeObjStep) void {364pub fn addPathForDynLibsInternal(step: *Step, builder: *std.Build, artifact: *CompileStep) void {
365 for (artifact.link_objects.items) |link_object| {365 for (artifact.link_objects.items) |link_object| {
366 switch (link_object) {366 switch (link_object) {
367 .other_step => |other| {367 .other_step => |other| {
lib/std/Build/Step.zig+2-2
...@@ -7,7 +7,7 @@ done_flag: bool,...@@ -7,7 +7,7 @@ done_flag: bool,
77
8pub const Id = enum {8pub const Id = enum {
9 top_level,9 top_level,
10 lib_exe_obj,10 compile,
11 install_artifact,11 install_artifact,
12 install_file,12 install_file,
13 install_dir,13 install_dir,
...@@ -28,7 +28,7 @@ pub const Id = enum {...@@ -28,7 +28,7 @@ pub const Id = enum {
28 pub fn Type(comptime id: Id) type {28 pub fn Type(comptime id: Id) type {
29 return switch (id) {29 return switch (id) {
30 .top_level => Build.TopLevelStep,30 .top_level => Build.TopLevelStep,
31 .lib_exe_obj => Build.LibExeObjStep,31 .compile => Build.CompileStep,
32 .install_artifact => Build.InstallArtifactStep,32 .install_artifact => Build.InstallArtifactStep,
33 .install_file => Build.InstallFileStep,33 .install_file => Build.InstallFileStep,
34 .install_dir => Build.InstallDirStep,34 .install_dir => Build.InstallDirStep,
lib/std/Build/TranslateCStep.zig+3-3
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const Step = std.Build.Step;2const Step = std.Build.Step;
3const LibExeObjStep = std.Build.LibExeObjStep;3const CompileStep = std.Build.CompileStep;
4const CheckFileStep = std.Build.CheckFileStep;4const CheckFileStep = std.Build.CheckFileStep;
5const fs = std.fs;5const fs = std.fs;
6const mem = std.mem;6const mem = std.mem;
...@@ -51,11 +51,11 @@ pub const AddExecutableOptions = struct {...@@ -51,11 +51,11 @@ pub const AddExecutableOptions = struct {
51 version: ?std.builtin.Version = null,51 version: ?std.builtin.Version = null,
52 target: ?CrossTarget = null,52 target: ?CrossTarget = null,
53 optimize: ?std.builtin.Mode = null,53 optimize: ?std.builtin.Mode = null,
54 linkage: ?LibExeObjStep.Linkage = null,54 linkage: ?CompileStep.Linkage = null,
55};55};
5656
57/// Creates a step to build an executable from the translated source.57/// Creates a step to build an executable from the translated source.
58pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *LibExeObjStep {58pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *CompileStep {
59 return self.builder.addExecutable(.{59 return self.builder.addExecutable(.{
60 .root_source_file = .{ .generated = &self.output_file },60 .root_source_file = .{ .generated = &self.output_file },
61 .name = options.name orelse "translated_c",61 .name = options.name orelse "translated_c",
lib/std/std.zig+2
...@@ -97,8 +97,10 @@ pub const zig = @import("zig.zig");...@@ -97,8 +97,10 @@ pub const zig = @import("zig.zig");
97pub const start = @import("start.zig");97pub const start = @import("start.zig");
9898
99///// Deprecated. Use `std.Build` instead.99///// Deprecated. Use `std.Build` instead.
100///// TODO: remove this after releasing 0.11.0
100//pub const build = struct {101//pub const build = struct {
101// /// Deprecated. Use `std.Build` instead.102// /// Deprecated. Use `std.Build` instead.
103// /// TODO: remove this after releasing 0.11.0
102// pub const Builder = Build;104// pub const Builder = Build;
103//};105//};
104106
test/link/macho/bugs/13457/build.zig-1
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
test/link/macho/dead_strip/build.zig+5-2
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
...@@ -36,7 +35,11 @@ pub fn build(b: *std.Build) void {...@@ -36,7 +35,11 @@ pub fn build(b: *std.Build) void {
36 }35 }
37}36}
3837
39fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {38fn createScenario(
39 b: *std.Build,
40 optimize: std.builtin.OptimizeMode,
41 target: std.zig.CrossTarget,
42) *std.Build.CompileStep {
40 const exe = b.addExecutable(.{43 const exe = b.addExecutable(.{
41 .name = "test",44 .name = "test",
42 .optimize = optimize,45 .optimize = optimize,
test/link/macho/dead_strip_dylibs/build.zig+1-2
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
...@@ -35,7 +34,7 @@ pub fn build(b: *std.Build) void {...@@ -35,7 +34,7 @@ pub fn build(b: *std.Build) void {
35 }34 }
36}35}
3736
38fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {37fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode) *std.Build.CompileStep {
39 const exe = b.addExecutable(.{38 const exe = b.addExecutable(.{
40 .name = "test",39 .name = "test",
41 .optimize = optimize,40 .optimize = optimize,
test/link/macho/headerpad/build.zig+1-2
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const LibExeObjectStep = std.Build.LibExeObjStep;
43
5pub fn build(b: *std.Build) void {4pub fn build(b: *std.Build) void {
6 const optimize = b.standardOptimizeOption(.{});5 const optimize = b.standardOptimizeOption(.{});
...@@ -93,7 +92,7 @@ pub fn build(b: *std.Build) void {...@@ -93,7 +92,7 @@ pub fn build(b: *std.Build) void {
93 }92 }
94}93}
9594
96fn simpleExe(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {95fn simpleExe(b: *std.Build, optimize: std.builtin.OptimizeMode) *std.Build.CompileStep {
97 const exe = b.addExecutable(.{96 const exe = b.addExecutable(.{
98 .name = "main",97 .name = "main",
99 .optimize = optimize,98 .optimize = optimize,
test/link/macho/needed_framework/build.zig-1
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
test/link/macho/needed_library/build.zig-1
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
test/link/macho/search_strategy/build.zig+5-2
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
...@@ -35,7 +34,11 @@ pub fn build(b: *std.Build) void {...@@ -35,7 +34,11 @@ pub fn build(b: *std.Build) void {
35 }34 }
36}35}
3736
38fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {37fn createScenario(
38 b: *std.Build,
39 optimize: std.builtin.OptimizeMode,
40 target: std.zig.CrossTarget,
41) *std.Build.CompileStep {
39 const static = b.addStaticLibrary(.{42 const static = b.addStaticLibrary(.{
40 .name = "a",43 .name = "a",
41 .optimize = optimize,44 .optimize = optimize,
test/link/macho/strict_validation/build.zig-1
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const LibExeObjectStep = std.Build.LibExeObjStep;
43
5pub fn build(b: *std.Build) void {4pub fn build(b: *std.Build) void {
6 const optimize = b.standardOptimizeOption(.{});5 const optimize = b.standardOptimizeOption(.{});
test/link/macho/unwind_info/build.zig+5-2
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const LibExeObjectStep = std.Build.LibExeObjStep;
43
5pub fn build(b: *std.Build) void {4pub fn build(b: *std.Build) void {
6 const optimize = b.standardOptimizeOption(.{});5 const optimize = b.standardOptimizeOption(.{});
...@@ -51,7 +50,11 @@ fn testUnwindInfo(...@@ -51,7 +50,11 @@ fn testUnwindInfo(
51 test_step.dependOn(&run_cmd.step);50 test_step.dependOn(&run_cmd.step);
52}51}
5352
54fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {53fn createScenario(
54 b: *std.Build,
55 optimize: std.builtin.OptimizeMode,
56 target: std.zig.CrossTarget,
57) *std.Build.CompileStep {
55 const exe = b.addExecutable(.{58 const exe = b.addExecutable(.{
56 .name = "test",59 .name = "test",
57 .optimize = optimize,60 .optimize = optimize,
test/link/macho/uuid/build.zig+5-2
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const test_step = b.step("test", "Test");4 const test_step = b.step("test", "Test");
...@@ -51,7 +50,11 @@ fn testUuid(...@@ -51,7 +50,11 @@ fn testUuid(
51 }50 }
52}51}
5352
54fn simpleDylib(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {53fn simpleDylib(
54 b: *std.Build,
55 optimize: std.builtin.OptimizeMode,
56 target: std.zig.CrossTarget,
57) *std.Build.CompileStep {
55 const dylib = b.addSharedLibrary(.{58 const dylib = b.addSharedLibrary(.{
56 .name = "test",59 .name = "test",
57 .version = .{ .major = 1, .minor = 0 },60 .version = .{ .major = 1, .minor = 0 },
test/link/macho/weak_framework/build.zig-1
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
test/link/macho/weak_library/build.zig-1
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const LibExeObjectStep = std.Build.LibExeObjStep;
32
4pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
5 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
test/tests.zig+5-5
...@@ -8,7 +8,7 @@ const mem = std.mem;...@@ -8,7 +8,7 @@ const mem = std.mem;
8const fmt = std.fmt;8const fmt = std.fmt;
9const ArrayList = std.ArrayList;9const ArrayList = std.ArrayList;
10const OptimizeMode = std.builtin.OptimizeMode;10const OptimizeMode = std.builtin.OptimizeMode;
11const LibExeObjStep = std.Build.LibExeObjStep;11const CompileStep = std.Build.CompileStep;
12const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
13const ExecError = std.Build.ExecError;13const ExecError = std.Build.ExecError;
14const Step = std.Build.Step;14const Step = std.Build.Step;
...@@ -842,7 +842,7 @@ pub const StackTracesContext = struct {...@@ -842,7 +842,7 @@ pub const StackTracesContext = struct {
842842
843 step: Step,843 step: Step,
844 context: *StackTracesContext,844 context: *StackTracesContext,
845 exe: *LibExeObjStep,845 exe: *CompileStep,
846 name: []const u8,846 name: []const u8,
847 optimize_mode: OptimizeMode,847 optimize_mode: OptimizeMode,
848 expect_output: []const u8,848 expect_output: []const u8,
...@@ -850,7 +850,7 @@ pub const StackTracesContext = struct {...@@ -850,7 +850,7 @@ pub const StackTracesContext = struct {
850850
851 pub fn create(851 pub fn create(
852 context: *StackTracesContext,852 context: *StackTracesContext,
853 exe: *LibExeObjStep,853 exe: *CompileStep,
854 name: []const u8,854 name: []const u8,
855 optimize_mode: OptimizeMode,855 optimize_mode: OptimizeMode,
856 expect_output: []const u8,856 expect_output: []const u8,
...@@ -1180,14 +1180,14 @@ pub const GenHContext = struct {...@@ -1180,14 +1180,14 @@ pub const GenHContext = struct {
1180 const GenHCmpOutputStep = struct {1180 const GenHCmpOutputStep = struct {
1181 step: Step,1181 step: Step,
1182 context: *GenHContext,1182 context: *GenHContext,
1183 obj: *LibExeObjStep,1183 obj: *CompileStep,
1184 name: []const u8,1184 name: []const u8,
1185 test_index: usize,1185 test_index: usize,
1186 case: *const TestCase,1186 case: *const TestCase,
11871187
1188 pub fn create(1188 pub fn create(
1189 context: *GenHContext,1189 context: *GenHContext,
1190 obj: *LibExeObjStep,1190 obj: *CompileStep,
1191 name: []const u8,1191 name: []const u8,
1192 case: *const TestCase,1192 case: *const TestCase,
1193 ) *GenHCmpOutputStep {1193 ) *GenHCmpOutputStep {