authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-28 22:47:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 17:51:18-07:00
logc20ad51c621ba18d2c90cc96d1b550831dc5d7a3
tree41786dd2be23e90fb13c3c867ad3881117b09b0f
parent134e8cf76a6664ebd028fbcbfbd7a1b85ad031f5

introduce std.Build.Module and extract some logic into it

This moves many settings from `std.Build.Step.Compile` and into `std.Build.Module`, and then makes them transitive. In other words, it adds support for exposing Zig modules in packages, which are configured in various ways, such as depending on other link objects, include paths, or even a different optimization mode. Now, transitive dependencies will be included in the compilation, so you can, for example, make a Zig module depend on some C source code, and expose that Zig module in a package. Currently, the compiler frontend autogenerates only one `@import("builtin")` module for the entire compilation, however, a future enhancement will be to make it honor the differences in modules, so that modules can be compiled with different optimization modes, code model, valgrind integration, or even target CPU feature set. closes #14719

4 files changed, 991 insertions(+), 950 deletions(-)

lib/std/Build.zig+44-120
......@@ -29,36 +29,7 @@ pub const Builder = Build;
2929pub const InstallDirectoryOptions = Step.InstallDir.Options;
3030
3131pub const Step = @import("Build/Step.zig");
32/// deprecated: use `Step.CheckFile`.
33pub const CheckFileStep = @import("Build/Step/CheckFile.zig");
34/// deprecated: use `Step.CheckObject`.
35pub const CheckObjectStep = @import("Build/Step/CheckObject.zig");
36/// deprecated: use `Step.ConfigHeader`.
37pub const ConfigHeaderStep = @import("Build/Step/ConfigHeader.zig");
38/// deprecated: use `Step.Fmt`.
39pub const FmtStep = @import("Build/Step/Fmt.zig");
40/// deprecated: use `Step.InstallArtifact`.
41pub const InstallArtifactStep = @import("Build/Step/InstallArtifact.zig");
42/// deprecated: use `Step.InstallDir`.
43pub const InstallDirStep = @import("Build/Step/InstallDir.zig");
44/// deprecated: use `Step.InstallFile`.
45pub const InstallFileStep = @import("Build/Step/InstallFile.zig");
46/// deprecated: use `Step.ObjCopy`.
47pub const ObjCopyStep = @import("Build/Step/ObjCopy.zig");
48/// deprecated: use `Step.Compile`.
49pub const CompileStep = @import("Build/Step/Compile.zig");
50/// deprecated: use `Step.Options`.
51pub const OptionsStep = @import("Build/Step/Options.zig");
52/// deprecated: use `Step.RemoveDir`.
53pub const RemoveDirStep = @import("Build/Step/RemoveDir.zig");
54/// deprecated: use `Step.Run`.
55pub const RunStep = @import("Build/Step/Run.zig");
56/// deprecated: use `Step.TranslateC`.
57pub const TranslateCStep = @import("Build/Step/TranslateC.zig");
58/// deprecated: use `Step.WriteFile`.
59pub const WriteFileStep = @import("Build/Step/WriteFile.zig");
60/// deprecated: use `LazyPath`.
61pub const FileSource = LazyPath;
32pub const Module = @import("Build/Module.zig");
6233
6334install_tls: TopLevelStep,
6435uninstall_tls: TopLevelStep,
......@@ -634,34 +605,31 @@ pub const ExecutableOptions = struct {
634605 use_llvm: ?bool = null,
635606 use_lld: ?bool = null,
636607 zig_lib_dir: ?LazyPath = null,
637 main_mod_path: ?LazyPath = null,
638608 /// Embed a `.manifest` file in the compilation if the object format supports it.
639609 /// https://learn.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference
640610 /// Manifest files must have the extension `.manifest`.
641611 /// Can be set regardless of target. The `.manifest` file will be ignored
642612 /// if the target object format does not support embedded manifests.
643613 win32_manifest: ?LazyPath = null,
644
645 /// Deprecated; use `main_mod_path`.
646 main_pkg_path: ?LazyPath = null,
647614};
648615
649616pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile {
650617 return Step.Compile.create(b, .{
651618 .name = options.name,
652 .root_source_file = options.root_source_file,
619 .root_module = .{
620 .root_source_file = options.root_source_file,
621 .target = options.target,
622 .optimize = options.optimize,
623 .link_libc = options.link_libc,
624 .single_threaded = options.single_threaded,
625 },
653626 .version = options.version,
654 .target = options.target,
655 .optimize = options.optimize,
656627 .kind = .exe,
657628 .linkage = options.linkage,
658629 .max_rss = options.max_rss,
659 .link_libc = options.link_libc,
660 .single_threaded = options.single_threaded,
661630 .use_llvm = options.use_llvm,
662631 .use_lld = options.use_lld,
663632 .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
664 .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
665633 .win32_manifest = options.win32_manifest,
666634 });
667635}
......@@ -677,26 +645,23 @@ pub const ObjectOptions = struct {
677645 use_llvm: ?bool = null,
678646 use_lld: ?bool = null,
679647 zig_lib_dir: ?LazyPath = null,
680 main_mod_path: ?LazyPath = null,
681
682 /// Deprecated; use `main_mod_path`.
683 main_pkg_path: ?LazyPath = null,
684648};
685649
686650pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile {
687651 return Step.Compile.create(b, .{
688652 .name = options.name,
689 .root_source_file = options.root_source_file,
690 .target = options.target,
691 .optimize = options.optimize,
653 .root_module = .{
654 .root_source_file = options.root_source_file,
655 .target = options.target,
656 .optimize = options.optimize,
657 .link_libc = options.link_libc,
658 .single_threaded = options.single_threaded,
659 },
692660 .kind = .obj,
693661 .max_rss = options.max_rss,
694 .link_libc = options.link_libc,
695 .single_threaded = options.single_threaded,
696662 .use_llvm = options.use_llvm,
697663 .use_lld = options.use_lld,
698664 .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
699 .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
700665 });
701666}
702667
......@@ -712,34 +677,31 @@ pub const SharedLibraryOptions = struct {
712677 use_llvm: ?bool = null,
713678 use_lld: ?bool = null,
714679 zig_lib_dir: ?LazyPath = null,
715 main_mod_path: ?LazyPath = null,
716680 /// Embed a `.manifest` file in the compilation if the object format supports it.
717681 /// https://learn.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference
718682 /// Manifest files must have the extension `.manifest`.
719683 /// Can be set regardless of target. The `.manifest` file will be ignored
720684 /// if the target object format does not support embedded manifests.
721685 win32_manifest: ?LazyPath = null,
722
723 /// Deprecated; use `main_mod_path`.
724 main_pkg_path: ?LazyPath = null,
725686};
726687
727688pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile {
728689 return Step.Compile.create(b, .{
729690 .name = options.name,
730 .root_source_file = options.root_source_file,
691 .root_module = .{
692 .target = options.target,
693 .optimize = options.optimize,
694 .root_source_file = options.root_source_file,
695 .link_libc = options.link_libc,
696 .single_threaded = options.single_threaded,
697 },
731698 .kind = .lib,
732699 .linkage = .dynamic,
733700 .version = options.version,
734 .target = options.target,
735 .optimize = options.optimize,
736701 .max_rss = options.max_rss,
737 .link_libc = options.link_libc,
738 .single_threaded = options.single_threaded,
739702 .use_llvm = options.use_llvm,
740703 .use_lld = options.use_lld,
741704 .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
742 .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
743705 .win32_manifest = options.win32_manifest,
744706 });
745707}
......@@ -756,28 +718,25 @@ pub const StaticLibraryOptions = struct {
756718 use_llvm: ?bool = null,
757719 use_lld: ?bool = null,
758720 zig_lib_dir: ?LazyPath = null,
759 main_mod_path: ?LazyPath = null,
760
761 /// Deprecated; use `main_mod_path`.
762 main_pkg_path: ?LazyPath = null,
763721};
764722
765723pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile {
766724 return Step.Compile.create(b, .{
767725 .name = options.name,
768 .root_source_file = options.root_source_file,
726 .root_module = .{
727 .target = options.target,
728 .optimize = options.optimize,
729 .root_source_file = options.root_source_file,
730 .link_libc = options.link_libc,
731 .single_threaded = options.single_threaded,
732 },
769733 .kind = .lib,
770734 .linkage = .static,
771735 .version = options.version,
772 .target = options.target,
773 .optimize = options.optimize,
774736 .max_rss = options.max_rss,
775 .link_libc = options.link_libc,
776 .single_threaded = options.single_threaded,
777737 .use_llvm = options.use_llvm,
778738 .use_lld = options.use_lld,
779739 .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
780 .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
781740 });
782741}
783742
......@@ -795,28 +754,25 @@ pub const TestOptions = struct {
795754 use_llvm: ?bool = null,
796755 use_lld: ?bool = null,
797756 zig_lib_dir: ?LazyPath = null,
798 main_mod_path: ?LazyPath = null,
799
800 /// Deprecated; use `main_mod_path`.
801 main_pkg_path: ?LazyPath = null,
802757};
803758
804759pub fn addTest(b: *Build, options: TestOptions) *Step.Compile {
805760 return Step.Compile.create(b, .{
806761 .name = options.name,
807762 .kind = .@"test",
808 .root_source_file = options.root_source_file,
809 .target = options.target,
810 .optimize = options.optimize,
763 .root_module = .{
764 .root_source_file = options.root_source_file,
765 .target = options.target,
766 .optimize = options.optimize,
767 .link_libc = options.link_libc,
768 .single_threaded = options.single_threaded,
769 },
811770 .max_rss = options.max_rss,
812771 .filter = options.filter,
813772 .test_runner = options.test_runner,
814 .link_libc = options.link_libc,
815 .single_threaded = options.single_threaded,
816773 .use_llvm = options.use_llvm,
817774 .use_lld = options.use_lld,
818775 .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
819 .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
820776 });
821777}
822778
......@@ -833,9 +789,10 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile {
833789 const obj_step = Step.Compile.create(b, .{
834790 .name = options.name,
835791 .kind = .obj,
836 .root_source_file = null,
837 .target = options.target,
838 .optimize = options.optimize,
792 .root_module = .{
793 .target = options.target,
794 .optimize = options.optimize,
795 },
839796 .max_rss = options.max_rss,
840797 .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
841798 });
......@@ -846,41 +803,17 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile {
846803/// This function creates a module and adds it to the package's module set, making
847804/// it available to other packages which depend on this one.
848805/// `createModule` can be used instead to create a private module.
849pub fn addModule(b: *Build, name: []const u8, options: CreateModuleOptions) *Module {
850 const module = b.createModule(options);
806pub fn addModule(b: *Build, name: []const u8, options: Module.CreateOptions) *Module {
807 const module = Module.create(b, options);
851808 b.modules.put(b.dupe(name), module) catch @panic("OOM");
852809 return module;
853810}
854811
855pub const ModuleDependency = struct {
856 name: []const u8,
857 module: *Module,
858};
859
860pub const CreateModuleOptions = struct {
861 source_file: LazyPath,
862 dependencies: []const ModuleDependency = &.{},
863};
864
865812/// This function creates a private module, to be used by the current package,
866813/// but not exposed to other packages depending on this one.
867814/// `addModule` can be used instead to create a public module.
868pub fn createModule(b: *Build, options: CreateModuleOptions) *Module {
869 const module = b.allocator.create(Module) catch @panic("OOM");
870 module.* = .{
871 .builder = b,
872 .source_file = options.source_file.dupe(b),
873 .dependencies = moduleDependenciesToArrayHashMap(b.allocator, options.dependencies),
874 };
875 return module;
876}
877
878fn moduleDependenciesToArrayHashMap(arena: Allocator, deps: []const ModuleDependency) std.StringArrayHashMap(*Module) {
879 var result = std.StringArrayHashMap(*Module).init(arena);
880 for (deps) |dep| {
881 result.put(dep.name, dep.module) catch @panic("OOM");
882 }
883 return result;
815pub fn createModule(b: *Build, options: Module.CreateOptions) *Module {
816 return Module.create(b, options);
884817}
885818
886819/// Initializes a `Step.Run` with argv, which must at least have the path to the
......@@ -1885,15 +1818,6 @@ pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void {
18851818 }
18861819}
18871820
1888pub const Module = struct {
1889 builder: *Build,
1890 /// This could either be a generated file, in which case the module
1891 /// contains exactly one file, or it could be a path to the root source
1892 /// file of directory of files which constitute the module.
1893 source_file: LazyPath,
1894 dependencies: std.StringArrayHashMap(*Module),
1895};
1896
18971821/// A file that is generated by a build step.
18981822/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic.
18991823pub const GeneratedFile = struct {
lib/std/Build/Module.zig created+616
......@@ -0,0 +1,616 @@
1/// The one responsible for creating this module.
2owner: *std.Build,
3/// Tracks the set of steps that depend on this `Module`. This ensures that
4/// when making this `Module` depend on other `Module` objects and `Step`
5/// objects, respective `Step` dependencies can be added.
6depending_steps: std.AutoArrayHashMapUnmanaged(*std.Build.Step.Compile, void),
7/// This could either be a generated file, in which case the module
8/// contains exactly one file, or it could be a path to the root source
9/// file of directory of files which constitute the module.
10/// If `null`, it means this module is made up of only `link_objects`.
11root_source_file: ?LazyPath,
12/// The modules that are mapped into this module's import table.
13import_table: std.StringArrayHashMap(*Module),
14
15target: std.zig.CrossTarget,
16target_info: NativeTargetInfo,
17optimize: std.builtin.OptimizeMode,
18dwarf_format: ?std.dwarf.Format,
19
20c_macros: std.ArrayList([]const u8),
21include_dirs: std.ArrayList(IncludeDir),
22lib_paths: std.ArrayList(LazyPath),
23rpaths: std.ArrayList(LazyPath),
24frameworks: std.StringArrayHashMapUnmanaged(FrameworkLinkInfo),
25c_std: std.Build.CStd,
26link_objects: std.ArrayList(LinkObject),
27
28strip: ?bool,
29unwind_tables: ?bool,
30single_threaded: ?bool,
31stack_protector: ?bool,
32stack_check: ?bool,
33sanitize_c: ?bool,
34sanitize_thread: ?bool,
35code_model: std.builtin.CodeModel,
36/// Whether to emit machine code that integrates with Valgrind.
37valgrind: ?bool,
38/// Position Independent Code
39pic: ?bool,
40red_zone: ?bool,
41/// Whether to omit the stack frame pointer. Frees up a register and makes it
42/// more more difficiult to obtain stack traces. Has target-dependent effects.
43omit_frame_pointer: ?bool,
44/// `true` requires a compilation that includes this Module to link libc.
45/// `false` causes a build failure if a compilation that includes this Module would link libc.
46/// `null` neither requires nor prevents libc from being linked.
47link_libc: ?bool,
48/// `true` requires a compilation that includes this Module to link libc++.
49/// `false` causes a build failure if a compilation that includes this Module would link libc++.
50/// `null` neither requires nor prevents libc++ from being linked.
51link_libcpp: ?bool,
52
53/// Symbols to be exported when compiling to WebAssembly.
54export_symbol_names: []const []const u8 = &.{},
55
56pub const LinkObject = union(enum) {
57 static_path: LazyPath,
58 other_step: *std.Build.Step.Compile,
59 system_lib: SystemLib,
60 assembly_file: LazyPath,
61 c_source_file: *CSourceFile,
62 c_source_files: *CSourceFiles,
63 win32_resource_file: *RcSourceFile,
64};
65
66pub const SystemLib = struct {
67 name: []const u8,
68 needed: bool,
69 weak: bool,
70 use_pkg_config: UsePkgConfig,
71 preferred_link_mode: std.builtin.LinkMode,
72 search_strategy: SystemLib.SearchStrategy,
73
74 pub const UsePkgConfig = enum {
75 /// Don't use pkg-config, just pass -lfoo where foo is name.
76 no,
77 /// Try to get information on how to link the library from pkg-config.
78 /// If that fails, fall back to passing -lfoo where foo is name.
79 yes,
80 /// Try to get information on how to link the library from pkg-config.
81 /// If that fails, error out.
82 force,
83 };
84
85 pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
86};
87
88pub const CSourceFiles = struct {
89 dependency: ?*std.Build.Dependency,
90 /// If `dependency` is not null relative to it,
91 /// else relative to the build root.
92 files: []const []const u8,
93 flags: []const []const u8,
94};
95
96pub const CSourceFile = struct {
97 file: LazyPath,
98 flags: []const []const u8,
99
100 pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile {
101 return .{
102 .file = self.file.dupe(b),
103 .flags = b.dupeStrings(self.flags),
104 };
105 }
106};
107
108pub const RcSourceFile = struct {
109 file: LazyPath,
110 /// Any option that rc.exe accepts will work here, with the exception of:
111 /// - `/fo`: The output filename is set by the build system
112 /// - `/p`: Only running the preprocessor is not supported in this context
113 /// - `/:no-preprocess` (non-standard option): Not supported in this context
114 /// - Any MUI-related option
115 /// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-
116 ///
117 /// Implicitly defined options:
118 /// /x (ignore the INCLUDE environment variable)
119 /// /D_DEBUG or /DNDEBUG depending on the optimization mode
120 flags: []const []const u8 = &.{},
121
122 pub fn dupe(self: RcSourceFile, b: *std.Build) RcSourceFile {
123 return .{
124 .file = self.file.dupe(b),
125 .flags = b.dupeStrings(self.flags),
126 };
127 }
128};
129
130pub const IncludeDir = union(enum) {
131 path: LazyPath,
132 path_system: LazyPath,
133 path_after: LazyPath,
134 framework_path: LazyPath,
135 framework_path_system: LazyPath,
136 other_step: *std.Build.Step.Compile,
137 config_header_step: *std.Build.Step.ConfigHeader,
138};
139
140pub const FrameworkLinkInfo = struct {
141 needed: bool = false,
142 weak: bool = false,
143};
144
145pub const CreateOptions = struct {
146 target: std.zig.CrossTarget,
147 target_info: ?NativeTargetInfo = null,
148 optimize: std.builtin.OptimizeMode,
149 root_source_file: ?LazyPath = null,
150 import_table: []const Import = &.{},
151 link_libc: ?bool = null,
152 link_libcpp: ?bool = null,
153 single_threaded: ?bool = null,
154 strip: ?bool = null,
155 unwind_tables: ?bool = null,
156 dwarf_format: ?std.dwarf.Format = null,
157 c_std: std.Build.CStd = .C99,
158 code_model: std.builtin.CodeModel = .default,
159 stack_protector: ?bool = null,
160 stack_check: ?bool = null,
161 sanitize_c: ?bool = null,
162 sanitize_thread: ?bool = null,
163 valgrind: ?bool = null,
164 pic: ?bool = null,
165 red_zone: ?bool = null,
166 /// Whether to omit the stack frame pointer. Frees up a register and makes it
167 /// more more difficiult to obtain stack traces. Has target-dependent effects.
168 omit_frame_pointer: ?bool = null,
169};
170
171pub const Import = struct {
172 name: []const u8,
173 module: *Module,
174};
175
176pub fn init(owner: *std.Build, options: CreateOptions, compile: ?*std.Build.Step.Compile) Module {
177 var m: Module = .{
178 .owner = owner,
179 .depending_steps = .{},
180 .root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null,
181 .import_table = std.StringArrayHashMap(*Module).init(owner.allocator),
182 .target = options.target,
183 .target_info = options.target_info orelse
184 NativeTargetInfo.detect(options.target) catch @panic("unhandled error"),
185 .optimize = options.optimize,
186 .link_libc = options.link_libc,
187 .link_libcpp = options.link_libcpp,
188 .dwarf_format = options.dwarf_format,
189 .c_macros = std.ArrayList([]const u8).init(owner.allocator),
190 .include_dirs = std.ArrayList(IncludeDir).init(owner.allocator),
191 .lib_paths = std.ArrayList(LazyPath).init(owner.allocator),
192 .rpaths = std.ArrayList(LazyPath).init(owner.allocator),
193 .frameworks = .{},
194 .c_std = options.c_std,
195 .link_objects = std.ArrayList(LinkObject).init(owner.allocator),
196 .strip = options.strip,
197 .unwind_tables = options.unwind_tables,
198 .single_threaded = options.single_threaded,
199 .stack_protector = options.stack_protector,
200 .stack_check = options.stack_check,
201 .sanitize_c = options.sanitize_c,
202 .sanitize_thread = options.sanitize_thread,
203 .code_model = options.code_model,
204 .valgrind = options.valgrind,
205 .pic = options.pic,
206 .red_zone = options.red_zone,
207 .omit_frame_pointer = options.omit_frame_pointer,
208 .export_symbol_names = &.{},
209 };
210
211 if (compile) |c| {
212 m.depending_steps.put(owner.allocator, c, {}) catch @panic("OOM");
213 }
214
215 m.import_table.ensureUnusedCapacity(options.import_table.len) catch @panic("OOM");
216 for (options.import_table) |dep| {
217 m.import_table.putAssumeCapacity(dep.name, dep.module);
218 }
219
220 var it = m.iterateDependencies(null);
221 while (it.next()) |item| addShallowDependencies(&m, item.module);
222
223 return m;
224}
225
226pub fn create(owner: *std.Build, options: CreateOptions) *Module {
227 const m = owner.allocator.create(Module) catch @panic("OOM");
228 m.* = init(owner, options, null);
229 return m;
230}
231
232/// Adds an existing module to be used with `@import`.
233pub fn addImport(m: *Module, name: []const u8, module: *Module) void {
234 const b = m.owner;
235 m.import_table.put(b.dupe(name), module) catch @panic("OOM");
236
237 var it = module.iterateDependencies(null);
238 while (it.next()) |item| addShallowDependencies(m, item.module);
239}
240
241/// Creates step dependencies and updates `depending_steps` of `dependee` so that
242/// subsequent calls to `addImport` on `dependee` will additionally create step
243/// dependencies on `m`'s `depending_steps`.
244fn addShallowDependencies(m: *Module, dependee: *Module) void {
245 if (dependee.root_source_file) |lazy_path| addLazyPathDependencies(m, dependee, lazy_path);
246 for (dependee.lib_paths.items) |lib_path| addLazyPathDependencies(m, dependee, lib_path);
247 for (dependee.rpaths.items) |rpath| addLazyPathDependencies(m, dependee, rpath);
248
249 for (dependee.link_objects.items) |link_object| switch (link_object) {
250 .other_step => |compile| addStepDependencies(m, dependee, &compile.step),
251
252 .static_path,
253 .assembly_file,
254 => |lp| addLazyPathDependencies(m, dependee, lp),
255
256 .c_source_file => |x| addLazyPathDependencies(m, dependee, x.file),
257 .win32_resource_file => |x| addLazyPathDependencies(m, dependee, x.file),
258
259 .c_source_files,
260 .system_lib,
261 => {},
262 };
263}
264
265fn addLazyPathDependencies(m: *Module, module: *Module, lazy_path: LazyPath) void {
266 addLazyPathDependenciesOnly(m, lazy_path);
267 if (m != module) {
268 for (m.depending_steps.keys()) |compile| {
269 module.depending_steps.put(m.owner.allocator, compile, {}) catch @panic("OOM");
270 }
271 }
272}
273
274fn addLazyPathDependenciesOnly(m: *Module, lazy_path: LazyPath) void {
275 for (m.depending_steps.keys()) |compile| {
276 lazy_path.addStepDependencies(&compile.step);
277 }
278}
279
280fn addStepDependencies(m: *Module, module: *Module, dependee: *std.Build.Step) void {
281 addStepDependenciesOnly(m, dependee);
282 if (m != module) {
283 for (m.depending_steps.keys()) |compile| {
284 module.depending_steps.put(m.owner.allocator, compile, {}) catch @panic("OOM");
285 }
286 }
287}
288
289fn addStepDependenciesOnly(m: *Module, dependee: *std.Build.Step) void {
290 for (m.depending_steps.keys()) |compile| {
291 compile.step.dependOn(dependee);
292 }
293}
294
295/// Creates a new module and adds it to be used with `@import`.
296pub fn addAnonymousImport(m: *Module, name: []const u8, options: std.Build.CreateModuleOptions) void {
297 const b = m.step.owner;
298 const module = b.createModule(options);
299 return addImport(m, name, module);
300}
301
302pub fn addOptions(m: *Module, module_name: []const u8, options: *std.Build.Step.Options) void {
303 addImport(m, module_name, options.createModule());
304}
305
306pub const DependencyIterator = struct {
307 allocator: std.mem.Allocator,
308 index: usize,
309 set: std.AutoArrayHashMapUnmanaged(Key, []const u8),
310
311 pub const Key = struct {
312 /// The compilation that contains the `Module`. Note that a `Module` might be
313 /// used by more than one compilation.
314 compile: ?*std.Build.Step.Compile,
315 module: *Module,
316 };
317
318 pub const Item = struct {
319 /// The compilation that contains the `Module`. Note that a `Module` might be
320 /// used by more than one compilation.
321 compile: ?*std.Build.Step.Compile,
322 module: *Module,
323 name: []const u8,
324 };
325
326 pub fn deinit(it: *DependencyIterator) void {
327 it.set.deinit(it.allocator);
328 it.* = undefined;
329 }
330
331 pub fn next(it: *DependencyIterator) ?Item {
332 if (it.index >= it.set.count()) {
333 it.set.clearAndFree(it.allocator);
334 return null;
335 }
336 const key = it.set.keys()[it.index];
337 const name = it.set.values()[it.index];
338 it.index += 1;
339 const module = key.module;
340 it.set.ensureUnusedCapacity(it.allocator, module.import_table.count()) catch
341 @panic("OOM");
342 for (module.import_table.keys(), module.import_table.values()) |dep_name, dep| {
343 it.set.putAssumeCapacity(.{
344 .module = dep,
345 .compile = key.compile,
346 }, dep_name);
347 }
348
349 if (key.compile != null) {
350 for (module.link_objects.items) |link_object| switch (link_object) {
351 .other_step => |compile| {
352 it.set.put(it.allocator, .{
353 .module = &compile.root_module,
354 .compile = compile,
355 }, "root") catch @panic("OOM");
356 },
357 else => {},
358 };
359 }
360
361 return .{
362 .compile = key.compile,
363 .module = key.module,
364 .name = name,
365 };
366 }
367};
368
369pub fn iterateDependencies(
370 m: *Module,
371 chase_steps: ?*std.Build.Step.Compile,
372) DependencyIterator {
373 var it: DependencyIterator = .{
374 .allocator = m.owner.allocator,
375 .index = 0,
376 .set = .{},
377 };
378 it.set.ensureUnusedCapacity(m.owner.allocator, m.import_table.count() + 1) catch @panic("OOM");
379 it.set.putAssumeCapacity(.{
380 .module = m,
381 .compile = chase_steps,
382 }, "root");
383 return it;
384}
385
386pub const LinkSystemLibraryOptions = struct {
387 needed: bool = false,
388 weak: bool = false,
389 use_pkg_config: SystemLib.UsePkgConfig = .yes,
390 preferred_link_mode: std.builtin.LinkMode = .Dynamic,
391 search_strategy: SystemLib.SearchStrategy = .paths_first,
392};
393
394pub fn linkSystemLibrary(
395 m: *Module,
396 name: []const u8,
397 options: LinkSystemLibraryOptions,
398) void {
399 const b = m.owner;
400 if (m.target_info.target.is_libc_lib_name(name)) {
401 m.link_libc = true;
402 return;
403 }
404 if (m.target_info.target.is_libcpp_lib_name(name)) {
405 m.link_libcpp = true;
406 return;
407 }
408
409 m.link_objects.append(.{
410 .system_lib = .{
411 .name = b.dupe(name),
412 .needed = options.needed,
413 .weak = options.weak,
414 .use_pkg_config = options.use_pkg_config,
415 .preferred_link_mode = options.preferred_link_mode,
416 .search_strategy = options.search_strategy,
417 },
418 }) catch @panic("OOM");
419}
420
421pub const AddCSourceFilesOptions = struct {
422 /// When provided, `files` are relative to `dependency` rather than the
423 /// package that owns the `Compile` step.
424 dependency: ?*std.Build.Dependency = null,
425 files: []const []const u8,
426 flags: []const []const u8 = &.{},
427};
428
429/// Handy when you have many C/C++ source files and want them all to have the same flags.
430pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
431 const c_source_files = m.owner.allocator.create(CSourceFiles) catch @panic("OOM");
432 c_source_files.* = .{
433 .dependency = options.dependency,
434 .files = m.owner.dupeStrings(options.files),
435 .flags = m.owner.dupeStrings(options.flags),
436 };
437 m.link_objects.append(.{ .c_source_files = c_source_files }) catch @panic("OOM");
438}
439
440pub fn addCSourceFile(m: *Module, source: CSourceFile) void {
441 const c_source_file = m.owner.allocator.create(CSourceFile) catch @panic("OOM");
442 c_source_file.* = source.dupe(m.owner);
443 m.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM");
444 addLazyPathDependenciesOnly(m, source.file);
445}
446
447/// Resource files must have the extension `.rc`.
448/// Can be called regardless of target. The .rc file will be ignored
449/// if the target object format does not support embedded resources.
450pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void {
451 // Only the PE/COFF format has a Resource Table, so for any other target
452 // the resource file is ignored.
453 if (m.target_info.target.ofmt != .coff) return;
454
455 const rc_source_file = m.owner.allocator.create(RcSourceFile) catch @panic("OOM");
456 rc_source_file.* = source.dupe(m.owner);
457 m.link_objects.append(.{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
458 addLazyPathDependenciesOnly(m, source.file);
459}
460
461pub fn addAssemblyFile(m: *Module, source: LazyPath) void {
462 m.link_objects.append(.{ .assembly_file = source.dupe(m.owner) }) catch @panic("OOM");
463 addLazyPathDependenciesOnly(m, source);
464}
465
466pub fn addObjectFile(m: *Module, source: LazyPath) void {
467 m.link_objects.append(.{ .static_path = source.dupe(m.owner) }) catch @panic("OOM");
468 addLazyPathDependencies(m, source);
469}
470
471pub fn appendZigProcessFlags(
472 m: *Module,
473 zig_args: *std.ArrayList([]const u8),
474 asking_step: ?*std.Build.Step,
475) !void {
476 const b = m.owner;
477
478 try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip");
479 try addFlag(zig_args, m.unwind_tables, "-funwind-tables", "-fno-unwind-tables");
480 try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded");
481 try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check");
482 try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector");
483 try addFlag(zig_args, m.omit_frame_pointer, "-fomit-frame-pointer", "-fno-omit-frame-pointer");
484 try addFlag(zig_args, m.sanitize_c, "-fsanitize-c", "-fno-sanitize-c");
485 try addFlag(zig_args, m.sanitize_thread, "-fsanitize-thread", "-fno-sanitize-thread");
486 try addFlag(zig_args, m.valgrind, "-fvalgrind", "-fno-valgrind");
487 try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC");
488 try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone");
489
490 if (m.dwarf_format) |dwarf_format| {
491 try zig_args.append(switch (dwarf_format) {
492 .@"32" => "-gdwarf32",
493 .@"64" => "-gdwarf64",
494 });
495 }
496
497 try zig_args.ensureUnusedCapacity(1);
498 switch (m.optimize) {
499 .Debug => {}, // Skip since it's the default.
500 .ReleaseSmall => zig_args.appendAssumeCapacity("-OReleaseSmall"),
501 .ReleaseFast => zig_args.appendAssumeCapacity("-OReleaseFast"),
502 .ReleaseSafe => zig_args.appendAssumeCapacity("-OReleaseSafe"),
503 }
504
505 if (m.code_model != .default) {
506 try zig_args.append("-mcmodel");
507 try zig_args.append(@tagName(m.code_model));
508 }
509
510 if (!m.target.isNative()) {
511 try zig_args.appendSlice(&.{
512 "-target", try m.target.zigTriple(b.allocator),
513 "-mcpu", try std.Build.serializeCpu(b.allocator, m.target.getCpu()),
514 });
515
516 if (m.target.dynamic_linker.get()) |dynamic_linker| {
517 try zig_args.append("--dynamic-linker");
518 try zig_args.append(dynamic_linker);
519 }
520 }
521
522 for (m.export_symbol_names) |symbol_name| {
523 try zig_args.append(b.fmt("--export={s}", .{symbol_name}));
524 }
525
526 for (m.include_dirs.items) |include_dir| {
527 switch (include_dir) {
528 .path => |include_path| {
529 try zig_args.append("-I");
530 try zig_args.append(include_path.getPath(b));
531 },
532 .path_system => |include_path| {
533 try zig_args.append("-isystem");
534 try zig_args.append(include_path.getPath(b));
535 },
536 .path_after => |include_path| {
537 try zig_args.append("-idirafter");
538 try zig_args.append(include_path.getPath(b));
539 },
540 .framework_path => |include_path| {
541 try zig_args.append("-F");
542 try zig_args.append(include_path.getPath2(b, asking_step));
543 },
544 .framework_path_system => |include_path| {
545 try zig_args.append("-iframework");
546 try zig_args.append(include_path.getPath2(b, asking_step));
547 },
548 .other_step => |other| {
549 if (other.generated_h) |header| {
550 try zig_args.append("-isystem");
551 try zig_args.append(std.fs.path.dirname(header.path.?).?);
552 }
553 if (other.installed_headers.items.len > 0) {
554 try zig_args.append("-I");
555 try zig_args.append(b.pathJoin(&.{
556 other.step.owner.install_prefix, "include",
557 }));
558 }
559 },
560 .config_header_step => |config_header| {
561 const full_file_path = config_header.output_file.path.?;
562 const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len];
563 try zig_args.appendSlice(&.{ "-I", header_dir_path });
564 },
565 }
566 }
567
568 for (m.c_macros.items) |c_macro| {
569 try zig_args.append("-D");
570 try zig_args.append(c_macro);
571 }
572
573 try zig_args.ensureUnusedCapacity(2 * m.lib_paths.items.len);
574 for (m.lib_paths.items) |lib_path| {
575 zig_args.appendAssumeCapacity("-L");
576 zig_args.appendAssumeCapacity(lib_path.getPath2(b, asking_step));
577 }
578
579 try zig_args.ensureUnusedCapacity(2 * m.rpaths.items.len);
580 for (m.rpaths.items) |rpath| {
581 zig_args.appendAssumeCapacity("-rpath");
582
583 if (m.target_info.target.isDarwin()) switch (rpath) {
584 .path, .cwd_relative => |path| {
585 // On Darwin, we should not try to expand special runtime paths such as
586 // * @executable_path
587 // * @loader_path
588 if (std.mem.startsWith(u8, path, "@executable_path") or
589 std.mem.startsWith(u8, path, "@loader_path"))
590 {
591 zig_args.appendAssumeCapacity(path);
592 continue;
593 }
594 },
595 .generated, .dependency => {},
596 };
597
598 zig_args.appendAssumeCapacity(rpath.getPath2(b, asking_step));
599 }
600}
601
602fn addFlag(
603 args: *std.ArrayList([]const u8),
604 opt: ?bool,
605 then_name: []const u8,
606 else_name: []const u8,
607) !void {
608 const cond = opt orelse return;
609 return args.append(if (cond) then_name else else_name);
610}
611
612const Module = @This();
613const std = @import("std");
614const assert = std.debug.assert;
615const LazyPath = std.Build.LazyPath;
616const NativeTargetInfo = std.zig.system.NativeTargetInfo;
lib/std/Build/Step/Compile.zig+313-812
......@@ -24,36 +24,24 @@ const Compile = @This();
2424pub const base_id: Step.Id = .compile;
2525
2626step: Step,
27root_module: Module,
28
2729name: []const u8,
28target: CrossTarget,
29target_info: NativeTargetInfo,
30optimize: std.builtin.OptimizeMode,
3130linker_script: ?LazyPath = null,
3231version_script: ?[]const u8 = null,
3332out_filename: []const u8,
33out_lib_filename: []const u8,
3434linkage: ?Linkage = null,
3535version: ?std.SemanticVersion,
3636kind: Kind,
3737major_only_filename: ?[]const u8,
3838name_only_filename: ?[]const u8,
39strip: ?bool,
40formatted_panics: ?bool = null,
41unwind_tables: ?bool,
4239// keep in sync with src/link.zig:CompressDebugSections
4340compress_debug_sections: enum { none, zlib, zstd } = .none,
44lib_paths: ArrayList(LazyPath),
45rpaths: ArrayList(LazyPath),
46frameworks: StringHashMap(FrameworkLinkInfo),
4741verbose_link: bool,
4842verbose_cc: bool,
4943bundle_compiler_rt: ?bool = null,
50single_threaded: ?bool,
51stack_protector: ?bool = null,
52disable_stack_probing: bool,
53disable_sanitize_c: bool,
54sanitize_thread: bool,
5544rdynamic: bool,
56dwarf_format: ?std.dwarf.Format = null,
5745import_memory: bool = false,
5846export_memory: bool = false,
5947/// For WebAssembly targets, this will allow for undefined symbols to
......@@ -65,31 +53,16 @@ initial_memory: ?u64 = null,
6553max_memory: ?u64 = null,
6654shared_memory: bool = false,
6755global_base: ?u64 = null,
68c_std: std.Build.CStd,
6956/// Set via options; intended to be read-only after that.
7057zig_lib_dir: ?LazyPath,
71/// Set via options; intended to be read-only after that.
72main_mod_path: ?LazyPath,
7358exec_cmd_args: ?[]const ?[]const u8,
7459filter: ?[]const u8,
7560test_evented_io: bool = false,
7661test_runner: ?[]const u8,
7762test_server_mode: bool,
78code_model: std.builtin.CodeModel = .default,
7963wasi_exec_model: ?std.builtin.WasiExecModel = null,
80/// Symbols to be exported when compiling to wasm
81export_symbol_names: []const []const u8 = &.{},
82
83root_src: ?LazyPath,
84out_lib_filename: []const u8,
85modules: std.StringArrayHashMap(*Module),
8664
87link_objects: ArrayList(LinkObject),
88include_dirs: ArrayList(IncludeDir),
89c_macros: ArrayList([]const u8),
9065installed_headers: ArrayList(*Step),
91is_linking_libc: bool,
92is_linking_libcpp: bool,
9366vcpkg_bin_path: ?[]const u8 = null,
9467
9568// keep in sync with src/Compilation.zig:RcIncludes
......@@ -111,7 +84,6 @@ image_base: ?u64 = null,
11184
11285libc_file: ?LazyPath = null,
11386
114valgrind_support: ?bool = null,
11587each_lib_rpath: ?bool = null,
11688/// On ELF targets, this will emit a link section called ".note.gnu.build-id"
11789/// which can be used to coordinate a stripped binary with its debug symbols.
......@@ -177,15 +149,9 @@ headerpad_max_install_names: bool = false,
177149/// (Darwin) Remove dylibs that are unreachable by the entry point or exported symbols.
178150dead_strip_dylibs: bool = false,
179151
180/// Position Independent Code
181force_pic: ?bool = null,
182
183152/// Position Independent Executable
184153pie: ?bool = null,
185154
186red_zone: ?bool = null,
187
188omit_frame_pointer: ?bool = null,
189155dll_export_fns: ?bool = null,
190156
191157subsystem: ?std.Target.SubSystem = null,
......@@ -226,90 +192,16 @@ generated_h: ?*GeneratedFile,
226192/// Defaults to `std.math.maxInt(u16)`
227193error_limit: ?u32 = null,
228194
195/// Computed during make().
196is_linking_libc: bool = false,
197/// Computed during make().
198is_linking_libcpp: bool = false,
199
229200pub const ExpectedCompileErrors = union(enum) {
230201 contains: []const u8,
231202 exact: []const []const u8,
232203};
233204
234pub const CSourceFiles = struct {
235 dependency: ?*std.Build.Dependency,
236 /// If `dependency` is not null relative to it,
237 /// else relative to the build root.
238 files: []const []const u8,
239 flags: []const []const u8,
240};
241
242pub const CSourceFile = struct {
243 file: LazyPath,
244 flags: []const []const u8,
245
246 pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile {
247 return .{
248 .file = self.file.dupe(b),
249 .flags = b.dupeStrings(self.flags),
250 };
251 }
252};
253
254pub const RcSourceFile = struct {
255 file: LazyPath,
256 /// Any option that rc.exe accepts will work here, with the exception of:
257 /// - `/fo`: The output filename is set by the build system
258 /// - `/p`: Only running the preprocessor is not supported in this context
259 /// - `/:no-preprocess` (non-standard option): Not supported in this context
260 /// - Any MUI-related option
261 /// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-
262 ///
263 /// Implicitly defined options:
264 /// /x (ignore the INCLUDE environment variable)
265 /// /D_DEBUG or /DNDEBUG depending on the optimization mode
266 flags: []const []const u8 = &.{},
267
268 pub fn dupe(self: RcSourceFile, b: *std.Build) RcSourceFile {
269 return .{
270 .file = self.file.dupe(b),
271 .flags = b.dupeStrings(self.flags),
272 };
273 }
274};
275
276pub const LinkObject = union(enum) {
277 static_path: LazyPath,
278 other_step: *Compile,
279 system_lib: SystemLib,
280 assembly_file: LazyPath,
281 c_source_file: *CSourceFile,
282 c_source_files: *CSourceFiles,
283 win32_resource_file: *RcSourceFile,
284};
285
286pub const SystemLib = struct {
287 name: []const u8,
288 needed: bool,
289 weak: bool,
290 use_pkg_config: UsePkgConfig,
291 preferred_link_mode: std.builtin.LinkMode,
292 search_strategy: SystemLib.SearchStrategy,
293
294 pub const UsePkgConfig = enum {
295 /// Don't use pkg-config, just pass -lfoo where foo is name.
296 no,
297 /// Try to get information on how to link the library from pkg-config.
298 /// If that fails, fall back to passing -lfoo where foo is name.
299 yes,
300 /// Try to get information on how to link the library from pkg-config.
301 /// If that fails, error out.
302 force,
303 };
304
305 pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
306};
307
308const FrameworkLinkInfo = struct {
309 needed: bool = false,
310 weak: bool = false,
311};
312
313205const Entry = union(enum) {
314206 /// Let the compiler decide whether to make an entry point and what to name
315207 /// it.
......@@ -322,42 +214,24 @@ const Entry = union(enum) {
322214 symbol_name: []const u8,
323215};
324216
325pub const IncludeDir = union(enum) {
326 path: LazyPath,
327 path_system: LazyPath,
328 path_after: LazyPath,
329 framework_path: LazyPath,
330 framework_path_system: LazyPath,
331 other_step: *Compile,
332 config_header_step: *Step.ConfigHeader,
333};
334
335217pub const Options = struct {
336218 name: []const u8,
337 root_source_file: ?LazyPath = null,
338 target: CrossTarget,
339 optimize: std.builtin.OptimizeMode,
219 root_module: Module.CreateOptions,
340220 kind: Kind,
341221 linkage: ?Linkage = null,
342222 version: ?std.SemanticVersion = null,
343223 max_rss: usize = 0,
344224 filter: ?[]const u8 = null,
345225 test_runner: ?[]const u8 = null,
346 link_libc: ?bool = null,
347 single_threaded: ?bool = null,
348226 use_llvm: ?bool = null,
349227 use_lld: ?bool = null,
350228 zig_lib_dir: ?LazyPath = null,
351 main_mod_path: ?LazyPath = null,
352229 /// Embed a `.manifest` file in the compilation if the object format supports it.
353230 /// https://learn.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference
354231 /// Manifest files must have the extension `.manifest`.
355232 /// Can be set regardless of target. The `.manifest` file will be ignored
356233 /// if the target object format does not support embedded manifests.
357234 win32_manifest: ?LazyPath = null,
358
359 /// deprecated; use `main_mod_path`.
360 main_pkg_path: ?LazyPath = null,
361235};
362236
363237pub const BuildId = union(enum) {
......@@ -447,7 +321,6 @@ pub const Linkage = enum { dynamic, static };
447321
448322pub fn create(owner: *std.Build, options: Options) *Compile {
449323 const name = owner.dupe(options.name);
450 const root_src: ?LazyPath = if (options.root_source_file) |rsrc| rsrc.dupe(owner) else null;
451324 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
452325 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
453326 }
......@@ -466,11 +339,12 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
466339 .@"test" => "zig test",
467340 },
468341 name_adjusted,
469 @tagName(options.optimize),
470 options.target.zigTriple(owner.allocator) catch @panic("OOM"),
342 @tagName(options.root_module.optimize),
343 options.root_module.target.zigTriple(owner.allocator) catch @panic("OOM"),
471344 });
472345
473 const target_info = NativeTargetInfo.detect(options.target) catch @panic("unhandled error");
346 const target_info = NativeTargetInfo.detect(options.root_module.target) catch
347 @panic("unhandled error");
474348
475349 const out_filename = std.zig.binNameAlloc(owner.allocator, .{
476350 .root_name = name,
......@@ -489,17 +363,12 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
489363
490364 const self = owner.allocator.create(Compile) catch @panic("OOM");
491365 self.* = .{
492 .strip = null,
493 .unwind_tables = null,
366 .root_module = Module.init(owner, options.root_module, self),
494367 .verbose_link = false,
495368 .verbose_cc = false,
496 .optimize = options.optimize,
497 .target = options.target,
498369 .linkage = options.linkage,
499370 .kind = options.kind,
500 .root_src = root_src,
501371 .name = name,
502 .frameworks = StringHashMap(FrameworkLinkInfo).init(owner.allocator),
503372 .step = Step.init(.{
504373 .id = base_id,
505374 .name = step_name,
......@@ -512,23 +381,12 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
512381 .out_lib_filename = undefined,
513382 .major_only_filename = null,
514383 .name_only_filename = null,
515 .modules = std.StringArrayHashMap(*Module).init(owner.allocator),
516 .include_dirs = ArrayList(IncludeDir).init(owner.allocator),
517 .link_objects = ArrayList(LinkObject).init(owner.allocator),
518 .c_macros = ArrayList([]const u8).init(owner.allocator),
519 .lib_paths = ArrayList(LazyPath).init(owner.allocator),
520 .rpaths = ArrayList(LazyPath).init(owner.allocator),
521384 .installed_headers = ArrayList(*Step).init(owner.allocator),
522 .c_std = std.Build.CStd.C99,
523385 .zig_lib_dir = null,
524 .main_mod_path = null,
525386 .exec_cmd_args = null,
526387 .filter = options.filter,
527388 .test_runner = options.test_runner,
528389 .test_server_mode = options.test_runner == null,
529 .disable_stack_probing = false,
530 .disable_sanitize_c = false,
531 .sanitize_thread = false,
532390 .rdynamic = false,
533391 .installed_path = null,
534392 .force_undefined_symbols = StringHashMap(void).init(owner.allocator),
......@@ -543,11 +401,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
543401 .generated_llvm_ir = null,
544402 .generated_h = null,
545403
546 .target_info = target_info,
547
548 .is_linking_libc = options.link_libc orelse false,
549 .is_linking_libcpp = false,
550 .single_threaded = options.single_threaded,
551404 .use_llvm = options.use_llvm,
552405 .use_lld = options.use_lld,
553406 };
......@@ -557,14 +410,9 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
557410 lp.addStepDependencies(&self.step);
558411 }
559412
560 if (options.main_mod_path orelse options.main_pkg_path) |lp| {
561 self.main_mod_path = lp.dupe(self.step.owner);
562 lp.addStepDependencies(&self.step);
563 }
564
565413 // Only the PE/COFF format has a Resource Table which is where the manifest
566414 // gets embedded, so for any other target the manifest file is just ignored.
567 if (self.target.getObjectFormat() == .coff) {
415 if (target_info.target.ofmt == .coff) {
568416 if (options.win32_manifest) |lp| {
569417 self.win32_manifest = lp.dupe(self.step.owner);
570418 lp.addStepDependencies(&self.step);
......@@ -600,8 +448,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
600448 }
601449 }
602450
603 if (root_src) |rs| rs.addStepDependencies(&self.step);
604
605451 return self;
606452}
607453
......@@ -738,19 +584,30 @@ pub fn linkFrameworkWeak(self: *Compile, framework_name: []const u8) void {
738584}
739585
740586/// Returns whether the library, executable, or object depends on a particular system library.
741pub fn dependsOnSystemLibrary(self: Compile, name: []const u8) bool {
742 if (isLibCLibrary(name)) {
743 return self.is_linking_libc;
587pub fn dependsOnSystemLibrary(self: *const Compile, name: []const u8) bool {
588 var is_linking_libc = false;
589 var is_linking_libcpp = false;
590
591 var it = self.root_module.iterateDependencies(self);
592 while (it.next()) |module| {
593 for (module.link_objects.items) |link_object| {
594 switch (link_object) {
595 .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
596 else => continue,
597 }
598 }
599 is_linking_libc = is_linking_libc or module.link_libcpp == true;
600 is_linking_libcpp = is_linking_libcpp or module.link_libcpp == true;
744601 }
745 if (isLibCppLibrary(name)) {
746 return self.is_linking_libcpp;
602
603 if (self.root_module.target_info.target.is_libc_lib_name(name)) {
604 return is_linking_libc;
747605 }
748 for (self.link_objects.items) |link_object| {
749 switch (link_object) {
750 .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
751 else => continue,
752 }
606
607 if (self.root_module.target_info.target.is_libcpp_lib_name(name)) {
608 return is_linking_libcpp;
753609 }
610
754611 return false;
755612}
756613
......@@ -759,11 +616,11 @@ pub fn linkLibrary(self: *Compile, lib: *Compile) void {
759616 self.linkLibraryOrObject(lib);
760617}
761618
762pub fn isDynamicLibrary(self: *Compile) bool {
619pub fn isDynamicLibrary(self: *const Compile) bool {
763620 return self.kind == .lib and self.linkage == Linkage.dynamic;
764621}
765622
766pub fn isStaticLibrary(self: *Compile) bool {
623pub fn isStaticLibrary(self: *const Compile) bool {
767624 return self.kind == .lib and self.linkage != Linkage.dynamic;
768625}
769626
......@@ -777,15 +634,15 @@ pub fn producesPdbFile(self: *Compile) bool {
777634}
778635
779636pub fn producesImplib(self: *Compile) bool {
780 return self.isDynamicLibrary() and self.target.isWindows();
637 return self.isDynamicLibrary() and self.root_module.target_info.target.os.tag == .windows;
781638}
782639
783640pub fn linkLibC(self: *Compile) void {
784 self.is_linking_libc = true;
641 self.root_module.link_libc = true;
785642}
786643
787644pub fn linkLibCpp(self: *Compile) void {
788 self.is_linking_libcpp = true;
645 self.root_module.link_libcpp = true;
789646}
790647
791648/// If the value is omitted, it is set to 1.
......@@ -802,31 +659,6 @@ pub fn defineCMacroRaw(self: *Compile, name_and_value: []const u8) void {
802659 self.c_macros.append(b.dupe(name_and_value)) catch @panic("OOM");
803660}
804661
805/// deprecated: use linkSystemLibrary2
806pub fn linkSystemLibraryName(self: *Compile, name: []const u8) void {
807 return linkSystemLibrary2(self, name, .{ .use_pkg_config = .no });
808}
809
810/// deprecated: use linkSystemLibrary2
811pub fn linkSystemLibraryNeededName(self: *Compile, name: []const u8) void {
812 return linkSystemLibrary2(self, name, .{ .needed = true, .use_pkg_config = .no });
813}
814
815/// deprecated: use linkSystemLibrary2
816pub fn linkSystemLibraryWeakName(self: *Compile, name: []const u8) void {
817 return linkSystemLibrary2(self, name, .{ .weak = true, .use_pkg_config = .no });
818}
819
820/// deprecated: use linkSystemLibrary2
821pub fn linkSystemLibraryPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
822 return linkSystemLibrary2(self, lib_name, .{ .use_pkg_config = .force });
823}
824
825/// deprecated: use linkSystemLibrary2
826pub fn linkSystemLibraryNeededPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
827 return linkSystemLibrary2(self, lib_name, .{ .needed = true, .use_pkg_config = .force });
828}
829
830662/// Run pkg-config for the given library name and parse the output, returning the arguments
831663/// that should be passed to zig to link the given library.
832664fn runPkgConfig(self: *Compile, lib_name: []const u8) ![]const []const u8 {
......@@ -924,98 +756,31 @@ fn runPkgConfig(self: *Compile, lib_name: []const u8) ![]const []const u8 {
924756}
925757
926758pub fn linkSystemLibrary(self: *Compile, name: []const u8) void {
927 self.linkSystemLibrary2(name, .{});
928}
929
930/// deprecated: use linkSystemLibrary2
931pub fn linkSystemLibraryNeeded(self: *Compile, name: []const u8) void {
932 return linkSystemLibrary2(self, name, .{ .needed = true });
759 return self.root_module.linkSystemLibrary(name, .{});
933760}
934761
935/// deprecated: use linkSystemLibrary2
936pub fn linkSystemLibraryWeak(self: *Compile, name: []const u8) void {
937 return linkSystemLibrary2(self, name, .{ .weak = true });
938}
939
940pub const LinkSystemLibraryOptions = struct {
941 needed: bool = false,
942 weak: bool = false,
943 use_pkg_config: SystemLib.UsePkgConfig = .yes,
944 preferred_link_mode: std.builtin.LinkMode = .Dynamic,
945 search_strategy: SystemLib.SearchStrategy = .paths_first,
946};
947
948762pub fn linkSystemLibrary2(
949763 self: *Compile,
950764 name: []const u8,
951 options: LinkSystemLibraryOptions,
765 options: Module.LinkSystemLibraryOptions,
952766) void {
953 const b = self.step.owner;
954 if (isLibCLibrary(name)) {
955 self.linkLibC();
956 return;
957 }
958 if (isLibCppLibrary(name)) {
959 self.linkLibCpp();
960 return;
961 }
962
963 self.link_objects.append(.{
964 .system_lib = .{
965 .name = b.dupe(name),
966 .needed = options.needed,
967 .weak = options.weak,
968 .use_pkg_config = options.use_pkg_config,
969 .preferred_link_mode = options.preferred_link_mode,
970 .search_strategy = options.search_strategy,
971 },
972 }) catch @panic("OOM");
767 return self.root_module.linkSystemLibrary(name, options);
973768}
974769
975pub const AddCSourceFilesOptions = struct {
976 /// When provided, `files` are relative to `dependency` rather than the package that owns the `Compile` step.
977 dependency: ?*std.Build.Dependency = null,
978 files: []const []const u8,
979 flags: []const []const u8 = &.{},
980};
981
982770/// Handy when you have many C/C++ source files and want them all to have the same flags.
983pub fn addCSourceFiles(self: *Compile, options: AddCSourceFilesOptions) void {
984 const b = self.step.owner;
985 const c_source_files = b.allocator.create(CSourceFiles) catch @panic("OOM");
986
987 const files_copy = b.dupeStrings(options.files);
988 const flags_copy = b.dupeStrings(options.flags);
989
990 c_source_files.* = .{
991 .dependency = options.dependency,
992 .files = files_copy,
993 .flags = flags_copy,
994 };
995 self.link_objects.append(.{ .c_source_files = c_source_files }) catch @panic("OOM");
771pub fn addCSourceFiles(self: *Compile, options: Module.AddCSourceFilesOptions) void {
772 self.root_module.addCSourceFiles(options);
996773}
997774
998pub fn addCSourceFile(self: *Compile, source: CSourceFile) void {
999 const b = self.step.owner;
1000 const c_source_file = b.allocator.create(CSourceFile) catch @panic("OOM");
1001 c_source_file.* = source.dupe(b);
1002 self.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM");
1003 source.file.addStepDependencies(&self.step);
775pub fn addCSourceFile(self: *Compile, source: Module.CSourceFile) void {
776 self.root_module.addCSourceFile(source);
1004777}
1005778
1006779/// Resource files must have the extension `.rc`.
1007780/// Can be called regardless of target. The .rc file will be ignored
1008781/// if the target object format does not support embedded resources.
1009pub fn addWin32ResourceFile(self: *Compile, source: RcSourceFile) void {
1010 // Only the PE/COFF format has a Resource Table, so for any other target
1011 // the resource file is just ignored.
1012 if (self.target.getObjectFormat() != .coff) return;
1013
1014 const b = self.step.owner;
1015 const rc_source_file = b.allocator.create(RcSourceFile) catch @panic("OOM");
1016 rc_source_file.* = source.dupe(b);
1017 self.link_objects.append(.{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
1018 source.file.addStepDependencies(&self.step);
782pub fn addWin32ResourceFile(self: *Compile, source: Module.RcSourceFile) void {
783 self.root_module.addWin32ResourceFile(source);
1019784}
1020785
1021786pub fn setVerboseLink(self: *Compile, value: bool) void {
......@@ -1112,16 +877,11 @@ pub fn getEmittedLlvmBc(self: *Compile) LazyPath {
1112877}
1113878
1114879pub fn addAssemblyFile(self: *Compile, source: LazyPath) void {
1115 const b = self.step.owner;
1116 const source_duped = source.dupe(b);
1117 self.link_objects.append(.{ .assembly_file = source_duped }) catch @panic("OOM");
1118 source_duped.addStepDependencies(&self.step);
880 self.root_module.addAssemblyFile(source);
1119881}
1120882
1121883pub fn addObjectFile(self: *Compile, source: LazyPath) void {
1122 const b = self.step.owner;
1123 self.link_objects.append(.{ .static_path = source.dupe(b) }) catch @panic("OOM");
1124 source.addStepDependencies(&self.step);
884 self.root_module.addObjectFile(source);
1125885}
1126886
1127887pub fn addObject(self: *Compile, obj: *Compile) void {
......@@ -1131,19 +891,19 @@ pub fn addObject(self: *Compile, obj: *Compile) void {
1131891
1132892pub fn addAfterIncludePath(self: *Compile, path: LazyPath) void {
1133893 const b = self.step.owner;
1134 self.include_dirs.append(IncludeDir{ .path_after = path.dupe(b) }) catch @panic("OOM");
894 self.include_dirs.append(.{ .path_after = path.dupe(b) }) catch @panic("OOM");
1135895 path.addStepDependencies(&self.step);
1136896}
1137897
1138898pub fn addSystemIncludePath(self: *Compile, path: LazyPath) void {
1139899 const b = self.step.owner;
1140 self.include_dirs.append(IncludeDir{ .path_system = path.dupe(b) }) catch @panic("OOM");
900 self.include_dirs.append(.{ .path_system = path.dupe(b) }) catch @panic("OOM");
1141901 path.addStepDependencies(&self.step);
1142902}
1143903
1144904pub fn addIncludePath(self: *Compile, path: LazyPath) void {
1145905 const b = self.step.owner;
1146 self.include_dirs.append(IncludeDir{ .path = path.dupe(b) }) catch @panic("OOM");
906 self.include_dirs.append(.{ .path = path.dupe(b) }) catch @panic("OOM");
1147907 path.addStepDependencies(&self.step);
1148908}
1149909
......@@ -1166,48 +926,16 @@ pub fn addRPath(self: *Compile, directory_source: LazyPath) void {
1166926
1167927pub fn addSystemFrameworkPath(self: *Compile, directory_source: LazyPath) void {
1168928 const b = self.step.owner;
1169 self.include_dirs.append(IncludeDir{ .framework_path_system = directory_source.dupe(b) }) catch @panic("OOM");
929 self.include_dirs.append(.{ .framework_path_system = directory_source.dupe(b) }) catch @panic("OOM");
1170930 directory_source.addStepDependencies(&self.step);
1171931}
1172932
1173933pub fn addFrameworkPath(self: *Compile, directory_source: LazyPath) void {
1174934 const b = self.step.owner;
1175 self.include_dirs.append(IncludeDir{ .framework_path = directory_source.dupe(b) }) catch @panic("OOM");
935 self.include_dirs.append(.{ .framework_path = directory_source.dupe(b) }) catch @panic("OOM");
1176936 directory_source.addStepDependencies(&self.step);
1177937}
1178938
1179/// Adds a module to be used with `@import` and exposing it in the current
1180/// package's module table using `name`.
1181pub fn addModule(cs: *Compile, name: []const u8, module: *Module) void {
1182 const b = cs.step.owner;
1183 cs.modules.put(b.dupe(name), module) catch @panic("OOM");
1184
1185 var done = std.AutoHashMap(*Module, void).init(b.allocator);
1186 defer done.deinit();
1187 cs.addRecursiveBuildDeps(module, &done) catch @panic("OOM");
1188}
1189
1190/// Adds a module to be used with `@import` without exposing it in the current
1191/// package's module table.
1192pub fn addAnonymousModule(cs: *Compile, name: []const u8, options: std.Build.CreateModuleOptions) void {
1193 const b = cs.step.owner;
1194 const module = b.createModule(options);
1195 return addModule(cs, name, module);
1196}
1197
1198pub fn addOptions(cs: *Compile, module_name: []const u8, options: *Step.Options) void {
1199 addModule(cs, module_name, options.createModule());
1200}
1201
1202fn addRecursiveBuildDeps(cs: *Compile, module: *Module, done: *std.AutoHashMap(*Module, void)) !void {
1203 if (done.contains(module)) return;
1204 try done.put(module, {});
1205 module.source_file.addStepDependencies(&cs.step);
1206 for (module.dependencies.values()) |dep| {
1207 try cs.addRecursiveBuildDeps(dep, done);
1208 }
1209}
1210
1211939/// If Vcpkg was found on the system, it will be added to include and lib
1212940/// paths for the specified target.
1213941pub fn addVcpkgPaths(self: *Compile, linkage: Compile.Linkage) !void {
......@@ -1236,7 +964,7 @@ pub fn addVcpkgPaths(self: *Compile, linkage: Compile.Linkage) !void {
1236964
1237965 const include_path = b.pathJoin(&.{ root, "installed", triplet, "include" });
1238966 errdefer allocator.free(include_path);
1239 try self.include_dirs.append(IncludeDir{ .path = .{ .path = include_path } });
967 try self.include_dirs.append(.{ .path = .{ .path = include_path } });
1240968
1241969 const lib_path = b.pathJoin(&.{ root, "installed", triplet, "lib" });
1242970 try self.lib_paths.append(.{ .path = lib_path });
......@@ -1270,87 +998,53 @@ fn linkLibraryOrObject(self: *Compile, other: *Compile) void {
1270998 }
1271999}
12721000
1273fn appendModuleArgs(
1274 cs: *Compile,
1275 zig_args: *ArrayList([]const u8),
1276) error{OutOfMemory}!void {
1001fn appendModuleArgs(cs: *Compile, zig_args: *ArrayList([]const u8)) !void {
12771002 const b = cs.step.owner;
1278 // First, traverse the whole dependency graph and give every module a unique name, ideally one
1279 // named after what it's called somewhere in the graph. It will help here to have both a mapping
1280 // from module to name and a set of all the currently-used names.
1281 var mod_names = std.AutoHashMap(*Module, []const u8).init(b.allocator);
1003 // First, traverse the whole dependency graph and give every module a
1004 // unique name, ideally one named after what it's called somewhere in the
1005 // graph. It will help here to have both a mapping from module to name and
1006 // a set of all the currently-used names.
1007 var mod_names: std.AutoArrayHashMapUnmanaged(*Module, []const u8) = .{};
12821008 var names = std.StringHashMap(void).init(b.allocator);
12831009
1284 var to_name = std.ArrayList(struct {
1285 name: []const u8,
1286 mod: *Module,
1287 }).init(b.allocator);
12881010 {
1289 var it = cs.modules.iterator();
1290 while (it.next()) |kv| {
1011 var it = cs.root_module.iterateDependencies(null);
1012 _ = it.next(); // Skip over the root module.
1013 while (it.next()) |item| {
12911014 // While we're traversing the root dependencies, let's make sure that no module names
12921015 // have colons in them, since the CLI forbids it. We handle this for transitive
12931016 // dependencies further down.
1294 if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) {
1295 @panic("Module names cannot contain colons");
1017 if (std.mem.indexOfScalar(u8, item.name, ':') != null) {
1018 return cs.step.fail("module '{s}' contains a colon", .{item.name});
12961019 }
1297 try to_name.append(.{
1298 .name = kv.key_ptr.*,
1299 .mod = kv.value_ptr.*,
1300 });
1301 }
1302 }
1303
1304 while (to_name.popOrNull()) |dep| {
1305 if (mod_names.contains(dep.mod)) continue;
13061020
1307 // We'll use this buffer to store the name we decide on
1308 var buf = try b.allocator.alloc(u8, dep.name.len + 32);
1309 // First, try just the exposed dependency name
1310 @memcpy(buf[0..dep.name.len], dep.name);
1311 var name = buf[0..dep.name.len];
1312 var n: usize = 0;
1313 while (names.contains(name)) {
1314 // If that failed, append an incrementing number to the end
1315 name = std.fmt.bufPrint(buf, "{s}{}", .{ dep.name, n }) catch unreachable;
1316 n += 1;
1317 }
1318
1319 try mod_names.put(dep.mod, name);
1320 try names.put(name, {});
1321
1322 var it = dep.mod.dependencies.iterator();
1323 while (it.next()) |kv| {
1324 // Same colon-in-name check as above, but for transitive dependencies.
1325 if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) {
1326 @panic("Module names cannot contain colons");
1021 var name = item.name;
1022 var n: usize = 0;
1023 while (names.contains(name)) {
1024 name = b.fmt("{s}{d}", .{ item.name, n });
1025 n += 1;
13271026 }
1328 try to_name.append(.{
1329 .name = kv.key_ptr.*,
1330 .mod = kv.value_ptr.*,
1331 });
1027
1028 try mod_names.put(b.allocator, item.module, name);
1029 try names.put(name, {});
13321030 }
13331031 }
13341032
1335 // Since the module names given to the CLI are based off of the exposed names, we already know
1336 // that none of the CLI names have colons in them, so there's no need to check that explicitly.
1033 // Since the module names given to the CLI are based off of the exposed
1034 // names, we already know that none of the CLI names have colons in them,
1035 // so there's no need to check that explicitly.
13371036
13381037 // Every module in the graph is now named; output their definitions
1339 {
1340 var it = mod_names.iterator();
1341 while (it.next()) |kv| {
1342 const mod = kv.key_ptr.*;
1343 const name = kv.value_ptr.*;
1344
1345 const deps_str = try constructDepString(b.allocator, mod_names, mod.dependencies);
1346 const src = mod.source_file.getPath(mod.builder);
1347 try zig_args.append("--mod");
1348 try zig_args.append(try std.fmt.allocPrint(b.allocator, "{s}:{s}:{s}", .{ name, deps_str, src }));
1349 }
1038 for (mod_names.keys(), mod_names.values()) |mod, name| {
1039 const root_src = mod.root_source_file orelse continue;
1040 const deps_str = try constructDepString(b.allocator, mod_names, mod.import_table);
1041 const src = root_src.getPath2(mod.owner, &cs.step);
1042 try zig_args.append("--mod");
1043 try zig_args.append(b.fmt("{s}:{s}:{s}", .{ name, deps_str, src }));
13501044 }
13511045
13521046 // Lastly, output the root dependencies
1353 const deps_str = try constructDepString(b.allocator, mod_names, cs.modules);
1047 const deps_str = try constructDepString(b.allocator, mod_names, cs.root_module.import_table);
13541048 if (deps_str.len > 0) {
13551049 try zig_args.append("--deps");
13561050 try zig_args.append(deps_str);
......@@ -1359,7 +1053,7 @@ fn appendModuleArgs(
13591053
13601054fn constructDepString(
13611055 allocator: std.mem.Allocator,
1362 mod_names: std.AutoHashMap(*Module, []const u8),
1056 mod_names: std.AutoArrayHashMapUnmanaged(*Module, []const u8),
13631057 deps: std.StringArrayHashMap(*Module),
13641058) ![]const u8 {
13651059 var deps_str = std.ArrayList(u8).init(allocator);
......@@ -1408,10 +1102,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14081102 const b = step.owner;
14091103 const self = @fieldParentPtr(Compile, "step", step);
14101104
1411 if (self.root_src == null and self.link_objects.items.len == 0) {
1412 return step.fail("the linker needs one or more objects to link", .{});
1413 }
1414
14151105 var zig_args = ArrayList([]const u8).init(b.allocator);
14161106 defer zig_args.deinit();
14171107
......@@ -1432,7 +1122,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14321122 try addFlag(&zig_args, "llvm", self.use_llvm);
14331123 try addFlag(&zig_args, "lld", self.use_lld);
14341124
1435 if (self.target.ofmt) |ofmt| {
1125 if (self.root_module.target.ofmt) |ofmt| {
14361126 try zig_args.append(try std.fmt.allocPrint(b.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
14371127 }
14381128
......@@ -1458,204 +1148,248 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14581148 try zig_args.append(try std.fmt.allocPrint(b.allocator, "{}", .{stack_size}));
14591149 }
14601150
1461 if (self.root_src) |root_src| try zig_args.append(root_src.getPath(b));
1151 {
1152 var seen_system_libs: std.StringHashMapUnmanaged(void) = .{};
1153 var frameworks: std.StringArrayHashMapUnmanaged(Module.FrameworkLinkInfo) = .{};
1154
1155 var prev_has_cflags = false;
1156 var prev_has_rcflags = false;
1157 var prev_search_strategy: Module.SystemLib.SearchStrategy = .paths_first;
1158 var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;
1159 // Track the number of positional arguments so that a nice error can be
1160 // emitted if there is nothing to link.
1161 var total_linker_objects: usize = 0;
1162
1163 if (self.root_module.root_source_file) |lp| {
1164 try zig_args.append(lp.getPath(b));
1165 total_linker_objects += 1;
1166 }
14621167
1463 // We will add link objects from transitive dependencies, but we want to keep
1464 // all link objects in the same order provided.
1465 // This array is used to keep self.link_objects immutable.
1466 var transitive_deps: TransitiveDeps = .{
1467 .link_objects = ArrayList(LinkObject).init(b.allocator),
1468 .seen_system_libs = StringHashMap(void).init(b.allocator),
1469 .seen_steps = std.AutoHashMap(*const Step, void).init(b.allocator),
1470 .is_linking_libcpp = self.is_linking_libcpp,
1471 .is_linking_libc = self.is_linking_libc,
1472 .frameworks = &self.frameworks,
1473 };
1168 try self.root_module.appendZigProcessFlags(&zig_args, step);
14741169
1475 try transitive_deps.seen_steps.put(&self.step, {});
1476 try transitive_deps.add(self.link_objects.items);
1477
1478 var prev_has_cflags = false;
1479 var prev_has_rcflags = false;
1480 var prev_search_strategy: SystemLib.SearchStrategy = .paths_first;
1481 var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;
1482
1483 for (transitive_deps.link_objects.items) |link_object| {
1484 switch (link_object) {
1485 .static_path => |static_path| try zig_args.append(static_path.getPath(b)),
1486
1487 .other_step => |other| switch (other.kind) {
1488 .exe => @panic("Cannot link with an executable build artifact"),
1489 .@"test" => @panic("Cannot link with a test"),
1490 .obj => {
1491 try zig_args.append(other.getEmittedBin().getPath(b));
1492 },
1493 .lib => l: {
1494 if (self.isStaticLibrary() and other.isStaticLibrary()) {
1495 // Avoid putting a static library inside a static library.
1496 break :l;
1497 }
1170 var it = self.root_module.iterateDependencies(self);
1171 while (it.next()) |key| {
1172 const module = key.module;
1173 const compile = key.compile.?;
1174 const dyn = compile.isDynamicLibrary();
14981175
1499 // For DLLs, we gotta link against the implib. For
1500 // everything else, we directly link against the library file.
1501 const full_path_lib = if (other.producesImplib())
1502 other.getGeneratedFilePath("generated_implib", &self.step)
1503 else
1504 other.getGeneratedFilePath("generated_bin", &self.step);
1505 try zig_args.append(full_path_lib);
1506
1507 if (other.linkage == Linkage.dynamic and !self.target.isWindows()) {
1508 if (fs.path.dirname(full_path_lib)) |dirname| {
1509 try zig_args.append("-rpath");
1510 try zig_args.append(dirname);
1511 }
1512 }
1513 },
1514 },
1176 // Inherit dependency on libc and libc++.
1177 if (module.link_libc == true) self.is_linking_libc = true;
1178 if (module.link_libcpp == true) self.is_linking_libcpp = true;
15151179
1516 .system_lib => |system_lib| {
1517 if ((system_lib.search_strategy != prev_search_strategy or
1518 system_lib.preferred_link_mode != prev_preferred_link_mode) and
1519 self.linkage != .static)
1520 {
1521 switch (system_lib.search_strategy) {
1522 .no_fallback => switch (system_lib.preferred_link_mode) {
1523 .Dynamic => try zig_args.append("-search_dylibs_only"),
1524 .Static => try zig_args.append("-search_static_only"),
1525 },
1526 .paths_first => switch (system_lib.preferred_link_mode) {
1527 .Dynamic => try zig_args.append("-search_paths_first"),
1528 .Static => try zig_args.append("-search_paths_first_static"),
1529 },
1530 .mode_first => switch (system_lib.preferred_link_mode) {
1531 .Dynamic => try zig_args.append("-search_dylibs_first"),
1532 .Static => try zig_args.append("-search_static_first"),
1533 },
1534 }
1535 prev_search_strategy = system_lib.search_strategy;
1536 prev_preferred_link_mode = system_lib.preferred_link_mode;
1180 // Inherit dependencies on darwin frameworks.
1181 if (!dyn) {
1182 for (module.frameworks.keys(), module.frameworks.values()) |name, info| {
1183 try frameworks.put(b.allocator, name, info);
15371184 }
1185 }
15381186
1539 const prefix: []const u8 = prefix: {
1540 if (system_lib.needed) break :prefix "-needed-l";
1541 if (system_lib.weak) break :prefix "-weak-l";
1542 break :prefix "-l";
1543 };
1544 switch (system_lib.use_pkg_config) {
1545 .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })),
1546 .yes, .force => {
1547 if (self.runPkgConfig(system_lib.name)) |args| {
1548 try zig_args.appendSlice(args);
1549 } else |err| switch (err) {
1550 error.PkgConfigInvalidOutput,
1551 error.PkgConfigCrashed,
1552 error.PkgConfigFailed,
1553 error.PkgConfigNotInstalled,
1554 error.PackageNotFound,
1555 => switch (system_lib.use_pkg_config) {
1556 .yes => {
1557 // pkg-config failed, so fall back to linking the library
1558 // by name directly.
1559 try zig_args.append(b.fmt("{s}{s}", .{
1560 prefix,
1561 system_lib.name,
1562 }));
1187 // Inherit dependencies on system libraries and static libraries.
1188 total_linker_objects += module.link_objects.items.len;
1189 for (module.link_objects.items) |link_object| {
1190 switch (link_object) {
1191 .static_path => |static_path| try zig_args.append(static_path.getPath(b)),
1192 .system_lib => |system_lib| {
1193 if ((try seen_system_libs.fetchPut(b.allocator, system_lib.name, {})) != null)
1194 continue;
1195
1196 if (dyn)
1197 continue;
1198
1199 if ((system_lib.search_strategy != prev_search_strategy or
1200 system_lib.preferred_link_mode != prev_preferred_link_mode) and
1201 self.linkage != .static)
1202 {
1203 switch (system_lib.search_strategy) {
1204 .no_fallback => switch (system_lib.preferred_link_mode) {
1205 .Dynamic => try zig_args.append("-search_dylibs_only"),
1206 .Static => try zig_args.append("-search_static_only"),
1207 },
1208 .paths_first => switch (system_lib.preferred_link_mode) {
1209 .Dynamic => try zig_args.append("-search_paths_first"),
1210 .Static => try zig_args.append("-search_paths_first_static"),
15631211 },
1564 .force => {
1565 panic("pkg-config failed for library {s}", .{system_lib.name});
1212 .mode_first => switch (system_lib.preferred_link_mode) {
1213 .Dynamic => try zig_args.append("-search_dylibs_first"),
1214 .Static => try zig_args.append("-search_static_first"),
15661215 },
1567 .no => unreachable,
1216 }
1217 prev_search_strategy = system_lib.search_strategy;
1218 prev_preferred_link_mode = system_lib.preferred_link_mode;
1219 }
1220
1221 const prefix: []const u8 = prefix: {
1222 if (system_lib.needed) break :prefix "-needed-l";
1223 if (system_lib.weak) break :prefix "-weak-l";
1224 break :prefix "-l";
1225 };
1226 switch (system_lib.use_pkg_config) {
1227 .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })),
1228 .yes, .force => {
1229 if (self.runPkgConfig(system_lib.name)) |args| {
1230 try zig_args.appendSlice(args);
1231 } else |err| switch (err) {
1232 error.PkgConfigInvalidOutput,
1233 error.PkgConfigCrashed,
1234 error.PkgConfigFailed,
1235 error.PkgConfigNotInstalled,
1236 error.PackageNotFound,
1237 => switch (system_lib.use_pkg_config) {
1238 .yes => {
1239 // pkg-config failed, so fall back to linking the library
1240 // by name directly.
1241 try zig_args.append(b.fmt("{s}{s}", .{
1242 prefix,
1243 system_lib.name,
1244 }));
1245 },
1246 .force => {
1247 panic("pkg-config failed for library {s}", .{system_lib.name});
1248 },
1249 .no => unreachable,
1250 },
1251
1252 else => |e| return e,
1253 }
1254 },
1255 }
1256 },
1257 .other_step => |other| {
1258 const included_in_lib = (compile.kind == .lib and other.kind == .obj);
1259 if (dyn or included_in_lib)
1260 continue;
1261
1262 switch (other.kind) {
1263 .exe => return step.fail("cannot link with an executable build artifact", .{}),
1264 .@"test" => return step.fail("cannot link with a test", .{}),
1265 .obj => {
1266 try zig_args.append(other.getEmittedBin().getPath(b));
1267 },
1268 .lib => l: {
1269 if (self.isStaticLibrary() and other.isStaticLibrary()) {
1270 // Avoid putting a static library inside a static library.
1271 break :l;
1272 }
1273
1274 // For DLLs, we gotta link against the implib. For
1275 // everything else, we directly link against the library file.
1276 const full_path_lib = if (other.producesImplib())
1277 other.getGeneratedFilePath("generated_implib", &self.step)
1278 else
1279 other.getGeneratedFilePath("generated_bin", &self.step);
1280 try zig_args.append(full_path_lib);
1281
1282 if (other.linkage == Linkage.dynamic and
1283 self.root_module.target_info.target.os.tag != .windows)
1284 {
1285 if (fs.path.dirname(full_path_lib)) |dirname| {
1286 try zig_args.append("-rpath");
1287 try zig_args.append(dirname);
1288 }
1289 }
15681290 },
1291 }
1292 },
1293 .assembly_file => |asm_file| {
1294 if (prev_has_cflags) {
1295 try zig_args.append("-cflags");
1296 try zig_args.append("--");
1297 prev_has_cflags = false;
1298 }
1299 try zig_args.append(asm_file.getPath(b));
1300 },
15691301
1570 else => |e| return e,
1302 .c_source_file => |c_source_file| {
1303 if (c_source_file.flags.len == 0) {
1304 if (prev_has_cflags) {
1305 try zig_args.append("-cflags");
1306 try zig_args.append("--");
1307 prev_has_cflags = false;
1308 }
1309 } else {
1310 try zig_args.append("-cflags");
1311 for (c_source_file.flags) |arg| {
1312 try zig_args.append(arg);
1313 }
1314 try zig_args.append("--");
1315 prev_has_cflags = true;
15711316 }
1317 try zig_args.append(c_source_file.file.getPath(b));
15721318 },
1573 }
1574 },
15751319
1576 .assembly_file => |asm_file| {
1577 if (prev_has_cflags) {
1578 try zig_args.append("-cflags");
1579 try zig_args.append("--");
1580 prev_has_cflags = false;
1581 }
1582 try zig_args.append(asm_file.getPath(b));
1583 },
1320 .c_source_files => |c_source_files| {
1321 if (c_source_files.flags.len == 0) {
1322 if (prev_has_cflags) {
1323 try zig_args.append("-cflags");
1324 try zig_args.append("--");
1325 prev_has_cflags = false;
1326 }
1327 } else {
1328 try zig_args.append("-cflags");
1329 for (c_source_files.flags) |flag| {
1330 try zig_args.append(flag);
1331 }
1332 try zig_args.append("--");
1333 prev_has_cflags = true;
1334 }
1335 if (c_source_files.dependency) |dep| {
1336 for (c_source_files.files) |file| {
1337 try zig_args.append(dep.builder.pathFromRoot(file));
1338 }
1339 } else {
1340 for (c_source_files.files) |file| {
1341 try zig_args.append(b.pathFromRoot(file));
1342 }
1343 }
1344 },
15841345
1585 .c_source_file => |c_source_file| {
1586 if (c_source_file.flags.len == 0) {
1587 if (prev_has_cflags) {
1588 try zig_args.append("-cflags");
1589 try zig_args.append("--");
1590 prev_has_cflags = false;
1591 }
1592 } else {
1593 try zig_args.append("-cflags");
1594 for (c_source_file.flags) |arg| {
1595 try zig_args.append(arg);
1596 }
1597 try zig_args.append("--");
1598 prev_has_cflags = true;
1346 .win32_resource_file => |rc_source_file| {
1347 if (rc_source_file.flags.len == 0) {
1348 if (prev_has_rcflags) {
1349 try zig_args.append("-rcflags");
1350 try zig_args.append("--");
1351 prev_has_rcflags = false;
1352 }
1353 } else {
1354 try zig_args.append("-rcflags");
1355 for (rc_source_file.flags) |arg| {
1356 try zig_args.append(arg);
1357 }
1358 try zig_args.append("--");
1359 prev_has_rcflags = true;
1360 }
1361 try zig_args.append(rc_source_file.file.getPath(b));
1362 },
15991363 }
1600 try zig_args.append(c_source_file.file.getPath(b));
1601 },
1364 }
1365 }
16021366
1603 .c_source_files => |c_source_files| {
1604 if (c_source_files.flags.len == 0) {
1605 if (prev_has_cflags) {
1606 try zig_args.append("-cflags");
1607 try zig_args.append("--");
1608 prev_has_cflags = false;
1609 }
1610 } else {
1611 try zig_args.append("-cflags");
1612 for (c_source_files.flags) |flag| {
1613 try zig_args.append(flag);
1614 }
1615 try zig_args.append("--");
1616 prev_has_cflags = true;
1617 }
1618 if (c_source_files.dependency) |dep| {
1619 for (c_source_files.files) |file| {
1620 try zig_args.append(dep.builder.pathFromRoot(file));
1621 }
1622 } else {
1623 for (c_source_files.files) |file| {
1624 try zig_args.append(b.pathFromRoot(file));
1625 }
1626 }
1627 },
1367 if (total_linker_objects == 0) {
1368 return step.fail("the linker needs one or more objects to link", .{});
1369 }
16281370
1629 .win32_resource_file => |rc_source_file| {
1630 if (rc_source_file.flags.len == 0) {
1631 if (prev_has_rcflags) {
1632 try zig_args.append("-rcflags");
1633 try zig_args.append("--");
1634 prev_has_rcflags = false;
1635 }
1636 } else {
1637 try zig_args.append("-rcflags");
1638 for (rc_source_file.flags) |arg| {
1639 try zig_args.append(arg);
1640 }
1641 try zig_args.append("--");
1642 prev_has_rcflags = true;
1643 }
1644 try zig_args.append(rc_source_file.file.getPath(b));
1645 },
1371 for (frameworks.keys(), frameworks.values()) |name, info| {
1372 if (info.needed) {
1373 try zig_args.append("-needed_framework");
1374 } else if (info.weak) {
1375 try zig_args.append("-weak_framework");
1376 } else {
1377 try zig_args.append("-framework");
1378 }
1379 try zig_args.append(name);
16461380 }
1647 }
16481381
1649 if (self.win32_manifest) |manifest_file| {
1650 try zig_args.append(manifest_file.getPath(b));
1651 }
1382 if (self.is_linking_libcpp) {
1383 try zig_args.append("-lc++");
1384 }
16521385
1653 if (transitive_deps.is_linking_libcpp) {
1654 try zig_args.append("-lc++");
1386 if (self.is_linking_libc) {
1387 try zig_args.append("-lc");
1388 }
16551389 }
16561390
1657 if (transitive_deps.is_linking_libc) {
1658 try zig_args.append("-lc");
1391 if (self.win32_manifest) |manifest_file| {
1392 try zig_args.append(manifest_file.getPath(b));
16591393 }
16601394
16611395 if (self.image_base) |image_base| {
......@@ -1702,17 +1436,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17021436 if (self.generated_llvm_ir != null) try zig_args.append("-femit-llvm-ir");
17031437 if (self.generated_h != null) try zig_args.append("-femit-h");
17041438
1705 try addFlag(&zig_args, "strip", self.strip);
1706 try addFlag(&zig_args, "formatted-panics", self.formatted_panics);
1707 try addFlag(&zig_args, "unwind-tables", self.unwind_tables);
1708
1709 if (self.dwarf_format) |dwarf_format| {
1710 try zig_args.append(switch (dwarf_format) {
1711 .@"32" => "-gdwarf32",
1712 .@"64" => "-gdwarf64",
1713 });
1714 }
1715
17161439 switch (self.compress_debug_sections) {
17171440 .none => {},
17181441 .zlib => try zig_args.append("--compress-debug-sections=zlib"),
......@@ -1769,11 +1492,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17691492 try zig_args.append(libc_file);
17701493 }
17711494
1772 switch (self.optimize) {
1773 .Debug => {}, // Skip since it's the default.
1774 else => try zig_args.append(b.fmt("-O{s}", .{@tagName(self.optimize)})),
1775 }
1776
17771495 try zig_args.append("--cache-dir");
17781496 try zig_args.append(b.cache_root.path orelse ".");
17791497
......@@ -1793,11 +1511,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17931511 try zig_args.append(b.fmt("{}", .{version}));
17941512 }
17951513
1796 if (self.target.isDarwin()) {
1514 if (self.root_module.target_info.target.isDarwin()) {
17971515 const install_name = self.install_name orelse b.fmt("@rpath/{s}{s}{s}", .{
1798 self.target.libPrefix(),
1516 self.root_module.target_info.target.libPrefix(),
17991517 self.name,
1800 self.target.dynamicLibSuffix(),
1518 self.root_module.target_info.target.dynamicLibSuffix(),
18011519 });
18021520 try zig_args.append("-install_name");
18031521 try zig_args.append(install_name);
......@@ -1823,27 +1541,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
18231541 }
18241542
18251543 try addFlag(&zig_args, "compiler-rt", self.bundle_compiler_rt);
1826 try addFlag(&zig_args, "single-threaded", self.single_threaded);
1827 if (self.disable_stack_probing) {
1828 try zig_args.append("-fno-stack-check");
1829 }
1830 try addFlag(&zig_args, "stack-protector", self.stack_protector);
1831 if (self.red_zone) |red_zone| {
1832 if (red_zone) {
1833 try zig_args.append("-mred-zone");
1834 } else {
1835 try zig_args.append("-mno-red-zone");
1836 }
1837 }
1838 try addFlag(&zig_args, "omit-frame-pointer", self.omit_frame_pointer);
18391544 try addFlag(&zig_args, "dll-export-fns", self.dll_export_fns);
1840
1841 if (self.disable_sanitize_c) {
1842 try zig_args.append("-fno-sanitize-c");
1843 }
1844 if (self.sanitize_thread) {
1845 try zig_args.append("-fsanitize-thread");
1846 }
18471545 if (self.rdynamic) {
18481546 try zig_args.append("-rdynamic");
18491547 }
......@@ -1875,29 +1573,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
18751573 try zig_args.append(b.fmt("--global-base={d}", .{global_base}));
18761574 }
18771575
1878 if (self.code_model != .default) {
1879 try zig_args.append("-mcmodel");
1880 try zig_args.append(@tagName(self.code_model));
1881 }
18821576 if (self.wasi_exec_model) |model| {
18831577 try zig_args.append(b.fmt("-mexec-model={s}", .{@tagName(model)}));
18841578 }
1885 for (self.export_symbol_names) |symbol_name| {
1886 try zig_args.append(b.fmt("--export={s}", .{symbol_name}));
1887 }
1888
1889 if (!self.target.isNative()) {
1890 try zig_args.appendSlice(&.{
1891 "-target", try self.target.zigTriple(b.allocator),
1892 "-mcpu", try std.Build.serializeCpu(b.allocator, self.target.getCpu()),
1893 });
1894
1895 if (self.target.dynamic_linker.get()) |dynamic_linker| {
1896 try zig_args.append("--dynamic-linker");
1897 try zig_args.append(dynamic_linker);
1898 }
1899 }
1900
19011579 if (self.linker_script) |linker_script| {
19021580 try zig_args.append("--script");
19031581 try zig_args.append(linker_script.getPath(b));
......@@ -1923,97 +1601,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
19231601
19241602 try self.appendModuleArgs(&zig_args);
19251603
1926 for (self.include_dirs.items) |include_dir| {
1927 switch (include_dir) {
1928 .path => |include_path| {
1929 try zig_args.append("-I");
1930 try zig_args.append(include_path.getPath(b));
1931 },
1932 .path_system => |include_path| {
1933 try zig_args.append("-isystem");
1934 try zig_args.append(include_path.getPath(b));
1935 },
1936 .path_after => |include_path| {
1937 try zig_args.append("-idirafter");
1938 try zig_args.append(include_path.getPath(b));
1939 },
1940 .framework_path => |include_path| {
1941 try zig_args.append("-F");
1942 try zig_args.append(include_path.getPath2(b, step));
1943 },
1944 .framework_path_system => |include_path| {
1945 try zig_args.append("-iframework");
1946 try zig_args.append(include_path.getPath2(b, step));
1947 },
1948 .other_step => |other| {
1949 if (other.generated_h) |header| {
1950 try zig_args.append("-isystem");
1951 try zig_args.append(fs.path.dirname(header.path.?).?);
1952 }
1953 if (other.installed_headers.items.len > 0) {
1954 try zig_args.append("-I");
1955 try zig_args.append(b.pathJoin(&.{
1956 other.step.owner.install_prefix, "include",
1957 }));
1958 }
1959 },
1960 .config_header_step => |config_header| {
1961 const full_file_path = config_header.output_file.path.?;
1962 const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len];
1963 try zig_args.appendSlice(&.{ "-I", header_dir_path });
1964 },
1965 }
1966 }
1967
1968 for (self.c_macros.items) |c_macro| {
1969 try zig_args.append("-D");
1970 try zig_args.append(c_macro);
1971 }
1972
1973 try zig_args.ensureUnusedCapacity(2 * self.lib_paths.items.len);
1974 for (self.lib_paths.items) |lib_path| {
1975 zig_args.appendAssumeCapacity("-L");
1976 zig_args.appendAssumeCapacity(lib_path.getPath2(b, step));
1977 }
1978
1979 try zig_args.ensureUnusedCapacity(2 * self.rpaths.items.len);
1980 for (self.rpaths.items) |rpath| {
1981 zig_args.appendAssumeCapacity("-rpath");
1982
1983 if (self.target_info.target.isDarwin()) switch (rpath) {
1984 .path, .cwd_relative => |path| {
1985 // On Darwin, we should not try to expand special runtime paths such as
1986 // * @executable_path
1987 // * @loader_path
1988 if (mem.startsWith(u8, path, "@executable_path") or
1989 mem.startsWith(u8, path, "@loader_path"))
1990 {
1991 zig_args.appendAssumeCapacity(path);
1992 continue;
1993 }
1994 },
1995 .generated, .dependency => {},
1996 };
1997
1998 zig_args.appendAssumeCapacity(rpath.getPath2(b, step));
1999 }
2000
2001 {
2002 var it = self.frameworks.iterator();
2003 while (it.next()) |entry| {
2004 const name = entry.key_ptr.*;
2005 const info = entry.value_ptr.*;
2006 if (info.needed) {
2007 try zig_args.append("-needed_framework");
2008 } else if (info.weak) {
2009 try zig_args.append("-weak_framework");
2010 } else {
2011 try zig_args.append("-framework");
2012 }
2013 try zig_args.append(name);
2014 }
2015 }
2016
20171604 if (b.sysroot) |sysroot| {
20181605 try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });
20191606 }
......@@ -2058,7 +1645,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
20581645 try zig_args.append(@tagName(self.rc_includes));
20591646 }
20601647
2061 try addFlag(&zig_args, "valgrind", self.valgrind_support);
20621648 try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
20631649
20641650 if (self.build_id) |build_id| {
......@@ -2075,12 +1661,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
20751661 try zig_args.append(dir.getPath(b));
20761662 }
20771663
2078 if (self.main_mod_path) |dir| {
2079 try zig_args.append("--main-mod-path");
2080 try zig_args.append(dir.getPath(b));
2081 }
2082
2083 try addFlag(&zig_args, "PIC", self.force_pic);
20841664 try addFlag(&zig_args, "PIE", self.pie);
20851665 try addFlag(&zig_args, "lto", self.want_lto);
20861666
......@@ -2223,7 +1803,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
22231803 }
22241804
22251805 if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic and
2226 self.version != null and self.target.wantSharedLibSymLinks())
1806 self.version != null and self.root_module.target.wantSharedLibSymLinks())
22271807 {
22281808 try doAtomicSymLinks(
22291809 step,
......@@ -2234,24 +1814,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
22341814 }
22351815}
22361816
2237fn isLibCLibrary(name: []const u8) bool {
2238 const libc_libraries = [_][]const u8{ "c", "m", "dl", "rt", "pthread" };
2239 for (libc_libraries) |libc_lib_name| {
2240 if (mem.eql(u8, name, libc_lib_name))
2241 return true;
2242 }
2243 return false;
2244}
2245
2246fn isLibCppLibrary(name: []const u8) bool {
2247 const libcpp_libraries = [_][]const u8{ "c++", "stdc++" };
2248 for (libcpp_libraries) |libcpp_lib_name| {
2249 if (mem.eql(u8, name, libcpp_lib_name))
2250 return true;
2251 }
2252 return false;
2253}
2254
22551817/// Returned slice must be freed by the caller.
22561818fn findVcpkgRoot(allocator: Allocator) !?[]const u8 {
22571819 const appdata_path = try fs.getAppDataDir(allocator, "vcpkg");
......@@ -2345,67 +1907,6 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)
23451907 }
23461908}
23471909
2348const TransitiveDeps = struct {
2349 link_objects: ArrayList(LinkObject),
2350 seen_system_libs: StringHashMap(void),
2351 seen_steps: std.AutoHashMap(*const Step, void),
2352 is_linking_libcpp: bool,
2353 is_linking_libc: bool,
2354 frameworks: *StringHashMap(FrameworkLinkInfo),
2355
2356 fn add(td: *TransitiveDeps, link_objects: []const LinkObject) !void {
2357 try td.link_objects.ensureUnusedCapacity(link_objects.len);
2358
2359 for (link_objects) |link_object| {
2360 try td.link_objects.append(link_object);
2361 switch (link_object) {
2362 .other_step => |other| try addInner(td, other, other.isDynamicLibrary()),
2363 else => {},
2364 }
2365 }
2366 }
2367
2368 fn addInner(td: *TransitiveDeps, other: *Compile, dyn: bool) !void {
2369 // Inherit dependency on libc and libc++
2370 td.is_linking_libcpp = td.is_linking_libcpp or other.is_linking_libcpp;
2371 td.is_linking_libc = td.is_linking_libc or other.is_linking_libc;
2372
2373 // Inherit dependencies on darwin frameworks
2374 if (!dyn) {
2375 var it = other.frameworks.iterator();
2376 while (it.next()) |framework| {
2377 try td.frameworks.put(framework.key_ptr.*, framework.value_ptr.*);
2378 }
2379 }
2380
2381 // Inherit dependencies on system libraries and static libraries.
2382 for (other.link_objects.items) |other_link_object| {
2383 switch (other_link_object) {
2384 .system_lib => |system_lib| {
2385 if ((try td.seen_system_libs.fetchPut(system_lib.name, {})) != null)
2386 continue;
2387
2388 if (dyn)
2389 continue;
2390
2391 try td.link_objects.append(other_link_object);
2392 },
2393 .other_step => |inner_other| {
2394 if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)
2395 continue;
2396
2397 const included_in_lib = (other.kind == .lib and inner_other.kind == .obj);
2398 if (!dyn and !included_in_lib)
2399 try td.link_objects.append(other_link_object);
2400
2401 try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());
2402 },
2403 else => continue,
2404 }
2405 }
2406 }
2407};
2408
24091910fn checkCompileErrors(self: *Compile) !void {
24101911 // Clear this field so that it does not get printed by the build runner.
24111912 const actual_eb = self.step.result_error_bundle;
lib/std/Build/Step/Run.zig+18-18
......@@ -488,7 +488,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
488488 man.hash.addBytes(file_path);
489489 },
490490 .artifact => |artifact| {
491 if (artifact.target.isWindows()) {
491 if (artifact.root_module.target_info.target.os.tag == .windows) {
492492 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
493493 self.addPathForDynLibs(artifact);
494494 }
......@@ -682,8 +682,9 @@ fn runCommand(
682682 else => break :interpret,
683683 }
684684
685 const need_cross_glibc = exe.target.isGnuLibC() and exe.is_linking_libc;
686 switch (b.host.getExternalExecutor(&exe.target_info, .{
685 const need_cross_glibc = exe.root_module.target_info.target.isGnuLibC() and
686 exe.is_linking_libc;
687 switch (b.host.getExternalExecutor(&exe.root_module.target_info, .{
687688 .qemu_fixes_dl = need_cross_glibc and b.glibc_runtimes_dir != null,
688689 .link_libc = exe.is_linking_libc,
689690 })) {
......@@ -714,9 +715,9 @@ fn runCommand(
714715 // needs the directory to be called "i686" rather than
715716 // "x86" which is why we do it manually here.
716717 const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}";
717 const cpu_arch = exe.target.getCpuArch();
718 const os_tag = exe.target.getOsTag();
719 const abi = exe.target.getAbi();
718 const cpu_arch = exe.root_module.target_info.target.cpu.arch;
719 const os_tag = exe.root_module.target_info.target.os.tag;
720 const abi = exe.root_module.target_info.target.abi;
720721 const cpu_arch_name: []const u8 = if (cpu_arch == .x86)
721722 "i686"
722723 else
......@@ -769,7 +770,7 @@ fn runCommand(
769770 if (allow_skip) return error.MakeSkipped;
770771
771772 const host_name = try b.host.target.zigTriple(b.allocator);
772 const foreign_name = try exe.target.zigTriple(b.allocator);
773 const foreign_name = try exe.root_module.target_info.target.zigTriple(b.allocator);
773774
774775 return step.fail("the host system ({s}) is unable to execute binaries from the target ({s})", .{
775776 host_name, foreign_name,
......@@ -777,7 +778,7 @@ fn runCommand(
777778 },
778779 }
779780
780 if (exe.target.isWindows()) {
781 if (exe.root_module.target_info.target.os.tag == .windows) {
781782 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
782783 self.addPathForDynLibs(exe);
783784 }
......@@ -1295,15 +1296,14 @@ fn evalGeneric(self: *Run, child: *std.process.Child) !StdIoResult {
12951296
12961297fn addPathForDynLibs(self: *Run, artifact: *Step.Compile) void {
12971298 const b = self.step.owner;
1298 for (artifact.link_objects.items) |link_object| {
1299 switch (link_object) {
1300 .other_step => |other| {
1301 if (other.target.isWindows() and other.isDynamicLibrary()) {
1302 addPathDir(self, fs.path.dirname(other.getEmittedBin().getPath(b)).?);
1303 addPathForDynLibs(self, other);
1304 }
1305 },
1306 else => {},
1299 var it = artifact.root_module.iterateDependencies(artifact);
1300 while (it.next()) |item| {
1301 const other = item.compile.?;
1302 if (item.module == &other.root_module) {
1303 if (item.module.target_info.target.os.tag == .windows and other.isDynamicLibrary()) {
1304 addPathDir(self, fs.path.dirname(other.getEmittedBin().getPath(b)).?);
1305 addPathForDynLibs(self, other);
1306 }
13071307 }
13081308 }
13091309}
......@@ -1321,7 +1321,7 @@ fn failForeign(
13211321
13221322 const b = self.step.owner;
13231323 const host_name = try b.host.target.zigTriple(b.allocator);
1324 const foreign_name = try exe.target.zigTriple(b.allocator);
1324 const foreign_name = try exe.root_module.target_info.target.zigTriple(b.allocator);
13251325
13261326 return self.step.fail(
13271327 \\unable to spawn foreign binary '{s}' ({s}) on host system ({s})