Commit c20ad51c62
Changed files (4)
lib
std
Build
lib/std/Build/Step/Compile.zig
@@ -24,36 +24,24 @@ const Compile = @This();
pub const base_id: Step.Id = .compile;
step: Step,
+root_module: Module,
+
name: []const u8,
-target: CrossTarget,
-target_info: NativeTargetInfo,
-optimize: std.builtin.OptimizeMode,
linker_script: ?LazyPath = null,
version_script: ?[]const u8 = null,
out_filename: []const u8,
+out_lib_filename: []const u8,
linkage: ?Linkage = null,
version: ?std.SemanticVersion,
kind: Kind,
major_only_filename: ?[]const u8,
name_only_filename: ?[]const u8,
-strip: ?bool,
-formatted_panics: ?bool = null,
-unwind_tables: ?bool,
// keep in sync with src/link.zig:CompressDebugSections
compress_debug_sections: enum { none, zlib, zstd } = .none,
-lib_paths: ArrayList(LazyPath),
-rpaths: ArrayList(LazyPath),
-frameworks: StringHashMap(FrameworkLinkInfo),
verbose_link: bool,
verbose_cc: bool,
bundle_compiler_rt: ?bool = null,
-single_threaded: ?bool,
-stack_protector: ?bool = null,
-disable_stack_probing: bool,
-disable_sanitize_c: bool,
-sanitize_thread: bool,
rdynamic: bool,
-dwarf_format: ?std.dwarf.Format = null,
import_memory: bool = false,
export_memory: bool = false,
/// For WebAssembly targets, this will allow for undefined symbols to
@@ -65,31 +53,16 @@ initial_memory: ?u64 = null,
max_memory: ?u64 = null,
shared_memory: bool = false,
global_base: ?u64 = null,
-c_std: std.Build.CStd,
/// Set via options; intended to be read-only after that.
zig_lib_dir: ?LazyPath,
-/// Set via options; intended to be read-only after that.
-main_mod_path: ?LazyPath,
exec_cmd_args: ?[]const ?[]const u8,
filter: ?[]const u8,
test_evented_io: bool = false,
test_runner: ?[]const u8,
test_server_mode: bool,
-code_model: std.builtin.CodeModel = .default,
wasi_exec_model: ?std.builtin.WasiExecModel = null,
-/// Symbols to be exported when compiling to wasm
-export_symbol_names: []const []const u8 = &.{},
-
-root_src: ?LazyPath,
-out_lib_filename: []const u8,
-modules: std.StringArrayHashMap(*Module),
-link_objects: ArrayList(LinkObject),
-include_dirs: ArrayList(IncludeDir),
-c_macros: ArrayList([]const u8),
installed_headers: ArrayList(*Step),
-is_linking_libc: bool,
-is_linking_libcpp: bool,
vcpkg_bin_path: ?[]const u8 = null,
// keep in sync with src/Compilation.zig:RcIncludes
@@ -111,7 +84,6 @@ image_base: ?u64 = null,
libc_file: ?LazyPath = null,
-valgrind_support: ?bool = null,
each_lib_rpath: ?bool = null,
/// On ELF targets, this will emit a link section called ".note.gnu.build-id"
/// which can be used to coordinate a stripped binary with its debug symbols.
@@ -177,15 +149,9 @@ headerpad_max_install_names: bool = false,
/// (Darwin) Remove dylibs that are unreachable by the entry point or exported symbols.
dead_strip_dylibs: bool = false,
-/// Position Independent Code
-force_pic: ?bool = null,
-
/// Position Independent Executable
pie: ?bool = null,
-red_zone: ?bool = null,
-
-omit_frame_pointer: ?bool = null,
dll_export_fns: ?bool = null,
subsystem: ?std.Target.SubSystem = null,
@@ -226,90 +192,16 @@ generated_h: ?*GeneratedFile,
/// Defaults to `std.math.maxInt(u16)`
error_limit: ?u32 = null,
+/// Computed during make().
+is_linking_libc: bool = false,
+/// Computed during make().
+is_linking_libcpp: bool = false,
+
pub const ExpectedCompileErrors = union(enum) {
contains: []const u8,
exact: []const []const u8,
};
-pub const CSourceFiles = struct {
- dependency: ?*std.Build.Dependency,
- /// If `dependency` is not null relative to it,
- /// else relative to the build root.
- files: []const []const u8,
- flags: []const []const u8,
-};
-
-pub const CSourceFile = struct {
- file: LazyPath,
- flags: []const []const u8,
-
- pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile {
- return .{
- .file = self.file.dupe(b),
- .flags = b.dupeStrings(self.flags),
- };
- }
-};
-
-pub const RcSourceFile = struct {
- file: LazyPath,
- /// Any option that rc.exe accepts will work here, with the exception of:
- /// - `/fo`: The output filename is set by the build system
- /// - `/p`: Only running the preprocessor is not supported in this context
- /// - `/:no-preprocess` (non-standard option): Not supported in this context
- /// - Any MUI-related option
- /// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-
- ///
- /// Implicitly defined options:
- /// /x (ignore the INCLUDE environment variable)
- /// /D_DEBUG or /DNDEBUG depending on the optimization mode
- flags: []const []const u8 = &.{},
-
- pub fn dupe(self: RcSourceFile, b: *std.Build) RcSourceFile {
- return .{
- .file = self.file.dupe(b),
- .flags = b.dupeStrings(self.flags),
- };
- }
-};
-
-pub const LinkObject = union(enum) {
- static_path: LazyPath,
- other_step: *Compile,
- system_lib: SystemLib,
- assembly_file: LazyPath,
- c_source_file: *CSourceFile,
- c_source_files: *CSourceFiles,
- win32_resource_file: *RcSourceFile,
-};
-
-pub const SystemLib = struct {
- name: []const u8,
- needed: bool,
- weak: bool,
- use_pkg_config: UsePkgConfig,
- preferred_link_mode: std.builtin.LinkMode,
- search_strategy: SystemLib.SearchStrategy,
-
- pub const UsePkgConfig = enum {
- /// Don't use pkg-config, just pass -lfoo where foo is name.
- no,
- /// Try to get information on how to link the library from pkg-config.
- /// If that fails, fall back to passing -lfoo where foo is name.
- yes,
- /// Try to get information on how to link the library from pkg-config.
- /// If that fails, error out.
- force,
- };
-
- pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
-};
-
-const FrameworkLinkInfo = struct {
- needed: bool = false,
- weak: bool = false,
-};
-
const Entry = union(enum) {
/// Let the compiler decide whether to make an entry point and what to name
/// it.
@@ -322,42 +214,24 @@ const Entry = union(enum) {
symbol_name: []const u8,
};
-pub const IncludeDir = union(enum) {
- path: LazyPath,
- path_system: LazyPath,
- path_after: LazyPath,
- framework_path: LazyPath,
- framework_path_system: LazyPath,
- other_step: *Compile,
- config_header_step: *Step.ConfigHeader,
-};
-
pub const Options = struct {
name: []const u8,
- root_source_file: ?LazyPath = null,
- target: CrossTarget,
- optimize: std.builtin.OptimizeMode,
+ root_module: Module.CreateOptions,
kind: Kind,
linkage: ?Linkage = null,
version: ?std.SemanticVersion = null,
max_rss: usize = 0,
filter: ?[]const u8 = null,
test_runner: ?[]const u8 = null,
- link_libc: ?bool = null,
- single_threaded: ?bool = null,
use_llvm: ?bool = null,
use_lld: ?bool = null,
zig_lib_dir: ?LazyPath = null,
- main_mod_path: ?LazyPath = null,
/// Embed a `.manifest` file in the compilation if the object format supports it.
/// https://learn.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference
/// Manifest files must have the extension `.manifest`.
/// Can be set regardless of target. The `.manifest` file will be ignored
/// if the target object format does not support embedded manifests.
win32_manifest: ?LazyPath = null,
-
- /// deprecated; use `main_mod_path`.
- main_pkg_path: ?LazyPath = null,
};
pub const BuildId = union(enum) {
@@ -447,7 +321,6 @@ pub const Linkage = enum { dynamic, static };
pub fn create(owner: *std.Build, options: Options) *Compile {
const name = owner.dupe(options.name);
- const root_src: ?LazyPath = if (options.root_source_file) |rsrc| rsrc.dupe(owner) else null;
if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
}
@@ -466,11 +339,12 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
.@"test" => "zig test",
},
name_adjusted,
- @tagName(options.optimize),
- options.target.zigTriple(owner.allocator) catch @panic("OOM"),
+ @tagName(options.root_module.optimize),
+ options.root_module.target.zigTriple(owner.allocator) catch @panic("OOM"),
});
- const target_info = NativeTargetInfo.detect(options.target) catch @panic("unhandled error");
+ const target_info = NativeTargetInfo.detect(options.root_module.target) catch
+ @panic("unhandled error");
const out_filename = std.zig.binNameAlloc(owner.allocator, .{
.root_name = name,
@@ -489,17 +363,12 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
const self = owner.allocator.create(Compile) catch @panic("OOM");
self.* = .{
- .strip = null,
- .unwind_tables = null,
+ .root_module = Module.init(owner, options.root_module, self),
.verbose_link = false,
.verbose_cc = false,
- .optimize = options.optimize,
- .target = options.target,
.linkage = options.linkage,
.kind = options.kind,
- .root_src = root_src,
.name = name,
- .frameworks = StringHashMap(FrameworkLinkInfo).init(owner.allocator),
.step = Step.init(.{
.id = base_id,
.name = step_name,
@@ -512,23 +381,12 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
.out_lib_filename = undefined,
.major_only_filename = null,
.name_only_filename = null,
- .modules = std.StringArrayHashMap(*Module).init(owner.allocator),
- .include_dirs = ArrayList(IncludeDir).init(owner.allocator),
- .link_objects = ArrayList(LinkObject).init(owner.allocator),
- .c_macros = ArrayList([]const u8).init(owner.allocator),
- .lib_paths = ArrayList(LazyPath).init(owner.allocator),
- .rpaths = ArrayList(LazyPath).init(owner.allocator),
.installed_headers = ArrayList(*Step).init(owner.allocator),
- .c_std = std.Build.CStd.C99,
.zig_lib_dir = null,
- .main_mod_path = null,
.exec_cmd_args = null,
.filter = options.filter,
.test_runner = options.test_runner,
.test_server_mode = options.test_runner == null,
- .disable_stack_probing = false,
- .disable_sanitize_c = false,
- .sanitize_thread = false,
.rdynamic = false,
.installed_path = null,
.force_undefined_symbols = StringHashMap(void).init(owner.allocator),
@@ -543,11 +401,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
.generated_llvm_ir = null,
.generated_h = null,
- .target_info = target_info,
-
- .is_linking_libc = options.link_libc orelse false,
- .is_linking_libcpp = false,
- .single_threaded = options.single_threaded,
.use_llvm = options.use_llvm,
.use_lld = options.use_lld,
};
@@ -557,14 +410,9 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
lp.addStepDependencies(&self.step);
}
- if (options.main_mod_path orelse options.main_pkg_path) |lp| {
- self.main_mod_path = lp.dupe(self.step.owner);
- lp.addStepDependencies(&self.step);
- }
-
// Only the PE/COFF format has a Resource Table which is where the manifest
// gets embedded, so for any other target the manifest file is just ignored.
- if (self.target.getObjectFormat() == .coff) {
+ if (target_info.target.ofmt == .coff) {
if (options.win32_manifest) |lp| {
self.win32_manifest = lp.dupe(self.step.owner);
lp.addStepDependencies(&self.step);
@@ -600,8 +448,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
}
}
- if (root_src) |rs| rs.addStepDependencies(&self.step);
-
return self;
}
@@ -738,19 +584,30 @@ pub fn linkFrameworkWeak(self: *Compile, framework_name: []const u8) void {
}
/// Returns whether the library, executable, or object depends on a particular system library.
-pub fn dependsOnSystemLibrary(self: Compile, name: []const u8) bool {
- if (isLibCLibrary(name)) {
- return self.is_linking_libc;
+pub fn dependsOnSystemLibrary(self: *const Compile, name: []const u8) bool {
+ var is_linking_libc = false;
+ var is_linking_libcpp = false;
+
+ var it = self.root_module.iterateDependencies(self);
+ while (it.next()) |module| {
+ for (module.link_objects.items) |link_object| {
+ switch (link_object) {
+ .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
+ else => continue,
+ }
+ }
+ is_linking_libc = is_linking_libc or module.link_libcpp == true;
+ is_linking_libcpp = is_linking_libcpp or module.link_libcpp == true;
}
- if (isLibCppLibrary(name)) {
- return self.is_linking_libcpp;
+
+ if (self.root_module.target_info.target.is_libc_lib_name(name)) {
+ return is_linking_libc;
}
- for (self.link_objects.items) |link_object| {
- switch (link_object) {
- .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true,
- else => continue,
- }
+
+ if (self.root_module.target_info.target.is_libcpp_lib_name(name)) {
+ return is_linking_libcpp;
}
+
return false;
}
@@ -759,11 +616,11 @@ pub fn linkLibrary(self: *Compile, lib: *Compile) void {
self.linkLibraryOrObject(lib);
}
-pub fn isDynamicLibrary(self: *Compile) bool {
+pub fn isDynamicLibrary(self: *const Compile) bool {
return self.kind == .lib and self.linkage == Linkage.dynamic;
}
-pub fn isStaticLibrary(self: *Compile) bool {
+pub fn isStaticLibrary(self: *const Compile) bool {
return self.kind == .lib and self.linkage != Linkage.dynamic;
}
@@ -777,15 +634,15 @@ pub fn producesPdbFile(self: *Compile) bool {
}
pub fn producesImplib(self: *Compile) bool {
- return self.isDynamicLibrary() and self.target.isWindows();
+ return self.isDynamicLibrary() and self.root_module.target_info.target.os.tag == .windows;
}
pub fn linkLibC(self: *Compile) void {
- self.is_linking_libc = true;
+ self.root_module.link_libc = true;
}
pub fn linkLibCpp(self: *Compile) void {
- self.is_linking_libcpp = true;
+ self.root_module.link_libcpp = true;
}
/// 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 {
self.c_macros.append(b.dupe(name_and_value)) catch @panic("OOM");
}
-/// deprecated: use linkSystemLibrary2
-pub fn linkSystemLibraryName(self: *Compile, name: []const u8) void {
- return linkSystemLibrary2(self, name, .{ .use_pkg_config = .no });
-}
-
-/// deprecated: use linkSystemLibrary2
-pub fn linkSystemLibraryNeededName(self: *Compile, name: []const u8) void {
- return linkSystemLibrary2(self, name, .{ .needed = true, .use_pkg_config = .no });
-}
-
-/// deprecated: use linkSystemLibrary2
-pub fn linkSystemLibraryWeakName(self: *Compile, name: []const u8) void {
- return linkSystemLibrary2(self, name, .{ .weak = true, .use_pkg_config = .no });
-}
-
-/// deprecated: use linkSystemLibrary2
-pub fn linkSystemLibraryPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
- return linkSystemLibrary2(self, lib_name, .{ .use_pkg_config = .force });
-}
-
-/// deprecated: use linkSystemLibrary2
-pub fn linkSystemLibraryNeededPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
- return linkSystemLibrary2(self, lib_name, .{ .needed = true, .use_pkg_config = .force });
-}
-
/// Run pkg-config for the given library name and parse the output, returning the arguments
/// that should be passed to zig to link the given library.
fn 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 {
}
pub fn linkSystemLibrary(self: *Compile, name: []const u8) void {
- self.linkSystemLibrary2(name, .{});
-}
-
-/// deprecated: use linkSystemLibrary2
-pub fn linkSystemLibraryNeeded(self: *Compile, name: []const u8) void {
- return linkSystemLibrary2(self, name, .{ .needed = true });
+ return self.root_module.linkSystemLibrary(name, .{});
}
-/// deprecated: use linkSystemLibrary2
-pub fn linkSystemLibraryWeak(self: *Compile, name: []const u8) void {
- return linkSystemLibrary2(self, name, .{ .weak = true });
-}
-
-pub const LinkSystemLibraryOptions = struct {
- needed: bool = false,
- weak: bool = false,
- use_pkg_config: SystemLib.UsePkgConfig = .yes,
- preferred_link_mode: std.builtin.LinkMode = .Dynamic,
- search_strategy: SystemLib.SearchStrategy = .paths_first,
-};
-
pub fn linkSystemLibrary2(
self: *Compile,
name: []const u8,
- options: LinkSystemLibraryOptions,
+ options: Module.LinkSystemLibraryOptions,
) void {
- const b = self.step.owner;
- if (isLibCLibrary(name)) {
- self.linkLibC();
- return;
- }
- if (isLibCppLibrary(name)) {
- self.linkLibCpp();
- return;
- }
-
- self.link_objects.append(.{
- .system_lib = .{
- .name = b.dupe(name),
- .needed = options.needed,
- .weak = options.weak,
- .use_pkg_config = options.use_pkg_config,
- .preferred_link_mode = options.preferred_link_mode,
- .search_strategy = options.search_strategy,
- },
- }) catch @panic("OOM");
+ return self.root_module.linkSystemLibrary(name, options);
}
-pub const AddCSourceFilesOptions = struct {
- /// When provided, `files` are relative to `dependency` rather than the package that owns the `Compile` step.
- dependency: ?*std.Build.Dependency = null,
- files: []const []const u8,
- flags: []const []const u8 = &.{},
-};
-
/// Handy when you have many C/C++ source files and want them all to have the same flags.
-pub fn addCSourceFiles(self: *Compile, options: AddCSourceFilesOptions) void {
- const b = self.step.owner;
- const c_source_files = b.allocator.create(CSourceFiles) catch @panic("OOM");
-
- const files_copy = b.dupeStrings(options.files);
- const flags_copy = b.dupeStrings(options.flags);
-
- c_source_files.* = .{
- .dependency = options.dependency,
- .files = files_copy,
- .flags = flags_copy,
- };
- self.link_objects.append(.{ .c_source_files = c_source_files }) catch @panic("OOM");
+pub fn addCSourceFiles(self: *Compile, options: Module.AddCSourceFilesOptions) void {
+ self.root_module.addCSourceFiles(options);
}
-pub fn addCSourceFile(self: *Compile, source: CSourceFile) void {
- const b = self.step.owner;
- const c_source_file = b.allocator.create(CSourceFile) catch @panic("OOM");
- c_source_file.* = source.dupe(b);
- self.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM");
- source.file.addStepDependencies(&self.step);
+pub fn addCSourceFile(self: *Compile, source: Module.CSourceFile) void {
+ self.root_module.addCSourceFile(source);
}
/// Resource files must have the extension `.rc`.
/// Can be called regardless of target. The .rc file will be ignored
/// if the target object format does not support embedded resources.
-pub fn addWin32ResourceFile(self: *Compile, source: RcSourceFile) void {
- // Only the PE/COFF format has a Resource Table, so for any other target
- // the resource file is just ignored.
- if (self.target.getObjectFormat() != .coff) return;
-
- const b = self.step.owner;
- const rc_source_file = b.allocator.create(RcSourceFile) catch @panic("OOM");
- rc_source_file.* = source.dupe(b);
- self.link_objects.append(.{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
- source.file.addStepDependencies(&self.step);
+pub fn addWin32ResourceFile(self: *Compile, source: Module.RcSourceFile) void {
+ self.root_module.addWin32ResourceFile(source);
}
pub fn setVerboseLink(self: *Compile, value: bool) void {
@@ -1112,16 +877,11 @@ pub fn getEmittedLlvmBc(self: *Compile) LazyPath {
}
pub fn addAssemblyFile(self: *Compile, source: LazyPath) void {
- const b = self.step.owner;
- const source_duped = source.dupe(b);
- self.link_objects.append(.{ .assembly_file = source_duped }) catch @panic("OOM");
- source_duped.addStepDependencies(&self.step);
+ self.root_module.addAssemblyFile(source);
}
pub fn addObjectFile(self: *Compile, source: LazyPath) void {
- const b = self.step.owner;
- self.link_objects.append(.{ .static_path = source.dupe(b) }) catch @panic("OOM");
- source.addStepDependencies(&self.step);
+ self.root_module.addObjectFile(source);
}
pub fn addObject(self: *Compile, obj: *Compile) void {
@@ -1131,19 +891,19 @@ pub fn addObject(self: *Compile, obj: *Compile) void {
pub fn addAfterIncludePath(self: *Compile, path: LazyPath) void {
const b = self.step.owner;
- self.include_dirs.append(IncludeDir{ .path_after = path.dupe(b) }) catch @panic("OOM");
+ self.include_dirs.append(.{ .path_after = path.dupe(b) }) catch @panic("OOM");
path.addStepDependencies(&self.step);
}
pub fn addSystemIncludePath(self: *Compile, path: LazyPath) void {
const b = self.step.owner;
- self.include_dirs.append(IncludeDir{ .path_system = path.dupe(b) }) catch @panic("OOM");
+ self.include_dirs.append(.{ .path_system = path.dupe(b) }) catch @panic("OOM");
path.addStepDependencies(&self.step);
}
pub fn addIncludePath(self: *Compile, path: LazyPath) void {
const b = self.step.owner;
- self.include_dirs.append(IncludeDir{ .path = path.dupe(b) }) catch @panic("OOM");
+ self.include_dirs.append(.{ .path = path.dupe(b) }) catch @panic("OOM");
path.addStepDependencies(&self.step);
}
@@ -1166,48 +926,16 @@ pub fn addRPath(self: *Compile, directory_source: LazyPath) void {
pub fn addSystemFrameworkPath(self: *Compile, directory_source: LazyPath) void {
const b = self.step.owner;
- self.include_dirs.append(IncludeDir{ .framework_path_system = directory_source.dupe(b) }) catch @panic("OOM");
+ self.include_dirs.append(.{ .framework_path_system = directory_source.dupe(b) }) catch @panic("OOM");
directory_source.addStepDependencies(&self.step);
}
pub fn addFrameworkPath(self: *Compile, directory_source: LazyPath) void {
const b = self.step.owner;
- self.include_dirs.append(IncludeDir{ .framework_path = directory_source.dupe(b) }) catch @panic("OOM");
+ self.include_dirs.append(.{ .framework_path = directory_source.dupe(b) }) catch @panic("OOM");
directory_source.addStepDependencies(&self.step);
}
-/// Adds a module to be used with `@import` and exposing it in the current
-/// package's module table using `name`.
-pub fn addModule(cs: *Compile, name: []const u8, module: *Module) void {
- const b = cs.step.owner;
- cs.modules.put(b.dupe(name), module) catch @panic("OOM");
-
- var done = std.AutoHashMap(*Module, void).init(b.allocator);
- defer done.deinit();
- cs.addRecursiveBuildDeps(module, &done) catch @panic("OOM");
-}
-
-/// Adds a module to be used with `@import` without exposing it in the current
-/// package's module table.
-pub fn addAnonymousModule(cs: *Compile, name: []const u8, options: std.Build.CreateModuleOptions) void {
- const b = cs.step.owner;
- const module = b.createModule(options);
- return addModule(cs, name, module);
-}
-
-pub fn addOptions(cs: *Compile, module_name: []const u8, options: *Step.Options) void {
- addModule(cs, module_name, options.createModule());
-}
-
-fn addRecursiveBuildDeps(cs: *Compile, module: *Module, done: *std.AutoHashMap(*Module, void)) !void {
- if (done.contains(module)) return;
- try done.put(module, {});
- module.source_file.addStepDependencies(&cs.step);
- for (module.dependencies.values()) |dep| {
- try cs.addRecursiveBuildDeps(dep, done);
- }
-}
-
/// If Vcpkg was found on the system, it will be added to include and lib
/// paths for the specified target.
pub fn addVcpkgPaths(self: *Compile, linkage: Compile.Linkage) !void {
@@ -1236,7 +964,7 @@ pub fn addVcpkgPaths(self: *Compile, linkage: Compile.Linkage) !void {
const include_path = b.pathJoin(&.{ root, "installed", triplet, "include" });
errdefer allocator.free(include_path);
- try self.include_dirs.append(IncludeDir{ .path = .{ .path = include_path } });
+ try self.include_dirs.append(.{ .path = .{ .path = include_path } });
const lib_path = b.pathJoin(&.{ root, "installed", triplet, "lib" });
try self.lib_paths.append(.{ .path = lib_path });
@@ -1270,87 +998,53 @@ fn linkLibraryOrObject(self: *Compile, other: *Compile) void {
}
}
-fn appendModuleArgs(
- cs: *Compile,
- zig_args: *ArrayList([]const u8),
-) error{OutOfMemory}!void {
+fn appendModuleArgs(cs: *Compile, zig_args: *ArrayList([]const u8)) !void {
const b = cs.step.owner;
- // First, traverse the whole dependency graph and give every module a unique name, ideally one
- // named after what it's called somewhere in the graph. It will help here to have both a mapping
- // from module to name and a set of all the currently-used names.
- var mod_names = std.AutoHashMap(*Module, []const u8).init(b.allocator);
+ // First, traverse the whole dependency graph and give every module a
+ // unique name, ideally one named after what it's called somewhere in the
+ // graph. It will help here to have both a mapping from module to name and
+ // a set of all the currently-used names.
+ var mod_names: std.AutoArrayHashMapUnmanaged(*Module, []const u8) = .{};
var names = std.StringHashMap(void).init(b.allocator);
- var to_name = std.ArrayList(struct {
- name: []const u8,
- mod: *Module,
- }).init(b.allocator);
{
- var it = cs.modules.iterator();
- while (it.next()) |kv| {
+ var it = cs.root_module.iterateDependencies(null);
+ _ = it.next(); // Skip over the root module.
+ while (it.next()) |item| {
// While we're traversing the root dependencies, let's make sure that no module names
// have colons in them, since the CLI forbids it. We handle this for transitive
// dependencies further down.
- if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) {
- @panic("Module names cannot contain colons");
+ if (std.mem.indexOfScalar(u8, item.name, ':') != null) {
+ return cs.step.fail("module '{s}' contains a colon", .{item.name});
}
- try to_name.append(.{
- .name = kv.key_ptr.*,
- .mod = kv.value_ptr.*,
- });
- }
- }
-
- while (to_name.popOrNull()) |dep| {
- if (mod_names.contains(dep.mod)) continue;
- // We'll use this buffer to store the name we decide on
- var buf = try b.allocator.alloc(u8, dep.name.len + 32);
- // First, try just the exposed dependency name
- @memcpy(buf[0..dep.name.len], dep.name);
- var name = buf[0..dep.name.len];
- var n: usize = 0;
- while (names.contains(name)) {
- // If that failed, append an incrementing number to the end
- name = std.fmt.bufPrint(buf, "{s}{}", .{ dep.name, n }) catch unreachable;
- n += 1;
- }
-
- try mod_names.put(dep.mod, name);
- try names.put(name, {});
-
- var it = dep.mod.dependencies.iterator();
- while (it.next()) |kv| {
- // Same colon-in-name check as above, but for transitive dependencies.
- if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) {
- @panic("Module names cannot contain colons");
+ var name = item.name;
+ var n: usize = 0;
+ while (names.contains(name)) {
+ name = b.fmt("{s}{d}", .{ item.name, n });
+ n += 1;
}
- try to_name.append(.{
- .name = kv.key_ptr.*,
- .mod = kv.value_ptr.*,
- });
+
+ try mod_names.put(b.allocator, item.module, name);
+ try names.put(name, {});
}
}
- // Since the module names given to the CLI are based off of the exposed names, we already know
- // that none of the CLI names have colons in them, so there's no need to check that explicitly.
+ // Since the module names given to the CLI are based off of the exposed
+ // names, we already know that none of the CLI names have colons in them,
+ // so there's no need to check that explicitly.
// Every module in the graph is now named; output their definitions
- {
- var it = mod_names.iterator();
- while (it.next()) |kv| {
- const mod = kv.key_ptr.*;
- const name = kv.value_ptr.*;
-
- const deps_str = try constructDepString(b.allocator, mod_names, mod.dependencies);
- const src = mod.source_file.getPath(mod.builder);
- try zig_args.append("--mod");
- try zig_args.append(try std.fmt.allocPrint(b.allocator, "{s}:{s}:{s}", .{ name, deps_str, src }));
- }
+ for (mod_names.keys(), mod_names.values()) |mod, name| {
+ const root_src = mod.root_source_file orelse continue;
+ const deps_str = try constructDepString(b.allocator, mod_names, mod.import_table);
+ const src = root_src.getPath2(mod.owner, &cs.step);
+ try zig_args.append("--mod");
+ try zig_args.append(b.fmt("{s}:{s}:{s}", .{ name, deps_str, src }));
}
// Lastly, output the root dependencies
- const deps_str = try constructDepString(b.allocator, mod_names, cs.modules);
+ const deps_str = try constructDepString(b.allocator, mod_names, cs.root_module.import_table);
if (deps_str.len > 0) {
try zig_args.append("--deps");
try zig_args.append(deps_str);
@@ -1359,7 +1053,7 @@ fn appendModuleArgs(
fn constructDepString(
allocator: std.mem.Allocator,
- mod_names: std.AutoHashMap(*Module, []const u8),
+ mod_names: std.AutoArrayHashMapUnmanaged(*Module, []const u8),
deps: std.StringArrayHashMap(*Module),
) ![]const u8 {
var deps_str = std.ArrayList(u8).init(allocator);
@@ -1408,10 +1102,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
const b = step.owner;
const self = @fieldParentPtr(Compile, "step", step);
- if (self.root_src == null and self.link_objects.items.len == 0) {
- return step.fail("the linker needs one or more objects to link", .{});
- }
-
var zig_args = ArrayList([]const u8).init(b.allocator);
defer zig_args.deinit();
@@ -1432,7 +1122,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try addFlag(&zig_args, "llvm", self.use_llvm);
try addFlag(&zig_args, "lld", self.use_lld);
- if (self.target.ofmt) |ofmt| {
+ if (self.root_module.target.ofmt) |ofmt| {
try zig_args.append(try std.fmt.allocPrint(b.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
}
@@ -1458,204 +1148,248 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.append(try std.fmt.allocPrint(b.allocator, "{}", .{stack_size}));
}
- if (self.root_src) |root_src| try zig_args.append(root_src.getPath(b));
+ {
+ var seen_system_libs: std.StringHashMapUnmanaged(void) = .{};
+ var frameworks: std.StringArrayHashMapUnmanaged(Module.FrameworkLinkInfo) = .{};
+
+ var prev_has_cflags = false;
+ var prev_has_rcflags = false;
+ var prev_search_strategy: Module.SystemLib.SearchStrategy = .paths_first;
+ var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;
+ // Track the number of positional arguments so that a nice error can be
+ // emitted if there is nothing to link.
+ var total_linker_objects: usize = 0;
+
+ if (self.root_module.root_source_file) |lp| {
+ try zig_args.append(lp.getPath(b));
+ total_linker_objects += 1;
+ }
- // We will add link objects from transitive dependencies, but we want to keep
- // all link objects in the same order provided.
- // This array is used to keep self.link_objects immutable.
- var transitive_deps: TransitiveDeps = .{
- .link_objects = ArrayList(LinkObject).init(b.allocator),
- .seen_system_libs = StringHashMap(void).init(b.allocator),
- .seen_steps = std.AutoHashMap(*const Step, void).init(b.allocator),
- .is_linking_libcpp = self.is_linking_libcpp,
- .is_linking_libc = self.is_linking_libc,
- .frameworks = &self.frameworks,
- };
+ try self.root_module.appendZigProcessFlags(&zig_args, step);
- try transitive_deps.seen_steps.put(&self.step, {});
- try transitive_deps.add(self.link_objects.items);
-
- var prev_has_cflags = false;
- var prev_has_rcflags = false;
- var prev_search_strategy: SystemLib.SearchStrategy = .paths_first;
- var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;
-
- for (transitive_deps.link_objects.items) |link_object| {
- switch (link_object) {
- .static_path => |static_path| try zig_args.append(static_path.getPath(b)),
-
- .other_step => |other| switch (other.kind) {
- .exe => @panic("Cannot link with an executable build artifact"),
- .@"test" => @panic("Cannot link with a test"),
- .obj => {
- try zig_args.append(other.getEmittedBin().getPath(b));
- },
- .lib => l: {
- if (self.isStaticLibrary() and other.isStaticLibrary()) {
- // Avoid putting a static library inside a static library.
- break :l;
- }
+ var it = self.root_module.iterateDependencies(self);
+ while (it.next()) |key| {
+ const module = key.module;
+ const compile = key.compile.?;
+ const dyn = compile.isDynamicLibrary();
- // For DLLs, we gotta link against the implib. For
- // everything else, we directly link against the library file.
- const full_path_lib = if (other.producesImplib())
- other.getGeneratedFilePath("generated_implib", &self.step)
- else
- other.getGeneratedFilePath("generated_bin", &self.step);
- try zig_args.append(full_path_lib);
-
- if (other.linkage == Linkage.dynamic and !self.target.isWindows()) {
- if (fs.path.dirname(full_path_lib)) |dirname| {
- try zig_args.append("-rpath");
- try zig_args.append(dirname);
- }
- }
- },
- },
+ // Inherit dependency on libc and libc++.
+ if (module.link_libc == true) self.is_linking_libc = true;
+ if (module.link_libcpp == true) self.is_linking_libcpp = true;
- .system_lib => |system_lib| {
- if ((system_lib.search_strategy != prev_search_strategy or
- system_lib.preferred_link_mode != prev_preferred_link_mode) and
- self.linkage != .static)
- {
- switch (system_lib.search_strategy) {
- .no_fallback => switch (system_lib.preferred_link_mode) {
- .Dynamic => try zig_args.append("-search_dylibs_only"),
- .Static => try zig_args.append("-search_static_only"),
- },
- .paths_first => switch (system_lib.preferred_link_mode) {
- .Dynamic => try zig_args.append("-search_paths_first"),
- .Static => try zig_args.append("-search_paths_first_static"),
- },
- .mode_first => switch (system_lib.preferred_link_mode) {
- .Dynamic => try zig_args.append("-search_dylibs_first"),
- .Static => try zig_args.append("-search_static_first"),
- },
- }
- prev_search_strategy = system_lib.search_strategy;
- prev_preferred_link_mode = system_lib.preferred_link_mode;
+ // Inherit dependencies on darwin frameworks.
+ if (!dyn) {
+ for (module.frameworks.keys(), module.frameworks.values()) |name, info| {
+ try frameworks.put(b.allocator, name, info);
}
+ }
- const prefix: []const u8 = prefix: {
- if (system_lib.needed) break :prefix "-needed-l";
- if (system_lib.weak) break :prefix "-weak-l";
- break :prefix "-l";
- };
- switch (system_lib.use_pkg_config) {
- .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })),
- .yes, .force => {
- if (self.runPkgConfig(system_lib.name)) |args| {
- try zig_args.appendSlice(args);
- } else |err| switch (err) {
- error.PkgConfigInvalidOutput,
- error.PkgConfigCrashed,
- error.PkgConfigFailed,
- error.PkgConfigNotInstalled,
- error.PackageNotFound,
- => switch (system_lib.use_pkg_config) {
- .yes => {
- // pkg-config failed, so fall back to linking the library
- // by name directly.
- try zig_args.append(b.fmt("{s}{s}", .{
- prefix,
- system_lib.name,
- }));
+ // Inherit dependencies on system libraries and static libraries.
+ total_linker_objects += module.link_objects.items.len;
+ for (module.link_objects.items) |link_object| {
+ switch (link_object) {
+ .static_path => |static_path| try zig_args.append(static_path.getPath(b)),
+ .system_lib => |system_lib| {
+ if ((try seen_system_libs.fetchPut(b.allocator, system_lib.name, {})) != null)
+ continue;
+
+ if (dyn)
+ continue;
+
+ if ((system_lib.search_strategy != prev_search_strategy or
+ system_lib.preferred_link_mode != prev_preferred_link_mode) and
+ self.linkage != .static)
+ {
+ switch (system_lib.search_strategy) {
+ .no_fallback => switch (system_lib.preferred_link_mode) {
+ .Dynamic => try zig_args.append("-search_dylibs_only"),
+ .Static => try zig_args.append("-search_static_only"),
+ },
+ .paths_first => switch (system_lib.preferred_link_mode) {
+ .Dynamic => try zig_args.append("-search_paths_first"),
+ .Static => try zig_args.append("-search_paths_first_static"),
},
- .force => {
- panic("pkg-config failed for library {s}", .{system_lib.name});
+ .mode_first => switch (system_lib.preferred_link_mode) {
+ .Dynamic => try zig_args.append("-search_dylibs_first"),
+ .Static => try zig_args.append("-search_static_first"),
},
- .no => unreachable,
+ }
+ prev_search_strategy = system_lib.search_strategy;
+ prev_preferred_link_mode = system_lib.preferred_link_mode;
+ }
+
+ const prefix: []const u8 = prefix: {
+ if (system_lib.needed) break :prefix "-needed-l";
+ if (system_lib.weak) break :prefix "-weak-l";
+ break :prefix "-l";
+ };
+ switch (system_lib.use_pkg_config) {
+ .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })),
+ .yes, .force => {
+ if (self.runPkgConfig(system_lib.name)) |args| {
+ try zig_args.appendSlice(args);
+ } else |err| switch (err) {
+ error.PkgConfigInvalidOutput,
+ error.PkgConfigCrashed,
+ error.PkgConfigFailed,
+ error.PkgConfigNotInstalled,
+ error.PackageNotFound,
+ => switch (system_lib.use_pkg_config) {
+ .yes => {
+ // pkg-config failed, so fall back to linking the library
+ // by name directly.
+ try zig_args.append(b.fmt("{s}{s}", .{
+ prefix,
+ system_lib.name,
+ }));
+ },
+ .force => {
+ panic("pkg-config failed for library {s}", .{system_lib.name});
+ },
+ .no => unreachable,
+ },
+
+ else => |e| return e,
+ }
+ },
+ }
+ },
+ .other_step => |other| {
+ const included_in_lib = (compile.kind == .lib and other.kind == .obj);
+ if (dyn or included_in_lib)
+ continue;
+
+ switch (other.kind) {
+ .exe => return step.fail("cannot link with an executable build artifact", .{}),
+ .@"test" => return step.fail("cannot link with a test", .{}),
+ .obj => {
+ try zig_args.append(other.getEmittedBin().getPath(b));
+ },
+ .lib => l: {
+ if (self.isStaticLibrary() and other.isStaticLibrary()) {
+ // Avoid putting a static library inside a static library.
+ break :l;
+ }
+
+ // For DLLs, we gotta link against the implib. For
+ // everything else, we directly link against the library file.
+ const full_path_lib = if (other.producesImplib())
+ other.getGeneratedFilePath("generated_implib", &self.step)
+ else
+ other.getGeneratedFilePath("generated_bin", &self.step);
+ try zig_args.append(full_path_lib);
+
+ if (other.linkage == Linkage.dynamic and
+ self.root_module.target_info.target.os.tag != .windows)
+ {
+ if (fs.path.dirname(full_path_lib)) |dirname| {
+ try zig_args.append("-rpath");
+ try zig_args.append(dirname);
+ }
+ }
},
+ }
+ },
+ .assembly_file => |asm_file| {
+ if (prev_has_cflags) {
+ try zig_args.append("-cflags");
+ try zig_args.append("--");
+ prev_has_cflags = false;
+ }
+ try zig_args.append(asm_file.getPath(b));
+ },
- else => |e| return e,
+ .c_source_file => |c_source_file| {
+ if (c_source_file.flags.len == 0) {
+ if (prev_has_cflags) {
+ try zig_args.append("-cflags");
+ try zig_args.append("--");
+ prev_has_cflags = false;
+ }
+ } else {
+ try zig_args.append("-cflags");
+ for (c_source_file.flags) |arg| {
+ try zig_args.append(arg);
+ }
+ try zig_args.append("--");
+ prev_has_cflags = true;
}
+ try zig_args.append(c_source_file.file.getPath(b));
},
- }
- },
- .assembly_file => |asm_file| {
- if (prev_has_cflags) {
- try zig_args.append("-cflags");
- try zig_args.append("--");
- prev_has_cflags = false;
- }
- try zig_args.append(asm_file.getPath(b));
- },
+ .c_source_files => |c_source_files| {
+ if (c_source_files.flags.len == 0) {
+ if (prev_has_cflags) {
+ try zig_args.append("-cflags");
+ try zig_args.append("--");
+ prev_has_cflags = false;
+ }
+ } else {
+ try zig_args.append("-cflags");
+ for (c_source_files.flags) |flag| {
+ try zig_args.append(flag);
+ }
+ try zig_args.append("--");
+ prev_has_cflags = true;
+ }
+ if (c_source_files.dependency) |dep| {
+ for (c_source_files.files) |file| {
+ try zig_args.append(dep.builder.pathFromRoot(file));
+ }
+ } else {
+ for (c_source_files.files) |file| {
+ try zig_args.append(b.pathFromRoot(file));
+ }
+ }
+ },
- .c_source_file => |c_source_file| {
- if (c_source_file.flags.len == 0) {
- if (prev_has_cflags) {
- try zig_args.append("-cflags");
- try zig_args.append("--");
- prev_has_cflags = false;
- }
- } else {
- try zig_args.append("-cflags");
- for (c_source_file.flags) |arg| {
- try zig_args.append(arg);
- }
- try zig_args.append("--");
- prev_has_cflags = true;
+ .win32_resource_file => |rc_source_file| {
+ if (rc_source_file.flags.len == 0) {
+ if (prev_has_rcflags) {
+ try zig_args.append("-rcflags");
+ try zig_args.append("--");
+ prev_has_rcflags = false;
+ }
+ } else {
+ try zig_args.append("-rcflags");
+ for (rc_source_file.flags) |arg| {
+ try zig_args.append(arg);
+ }
+ try zig_args.append("--");
+ prev_has_rcflags = true;
+ }
+ try zig_args.append(rc_source_file.file.getPath(b));
+ },
}
- try zig_args.append(c_source_file.file.getPath(b));
- },
+ }
+ }
- .c_source_files => |c_source_files| {
- if (c_source_files.flags.len == 0) {
- if (prev_has_cflags) {
- try zig_args.append("-cflags");
- try zig_args.append("--");
- prev_has_cflags = false;
- }
- } else {
- try zig_args.append("-cflags");
- for (c_source_files.flags) |flag| {
- try zig_args.append(flag);
- }
- try zig_args.append("--");
- prev_has_cflags = true;
- }
- if (c_source_files.dependency) |dep| {
- for (c_source_files.files) |file| {
- try zig_args.append(dep.builder.pathFromRoot(file));
- }
- } else {
- for (c_source_files.files) |file| {
- try zig_args.append(b.pathFromRoot(file));
- }
- }
- },
+ if (total_linker_objects == 0) {
+ return step.fail("the linker needs one or more objects to link", .{});
+ }
- .win32_resource_file => |rc_source_file| {
- if (rc_source_file.flags.len == 0) {
- if (prev_has_rcflags) {
- try zig_args.append("-rcflags");
- try zig_args.append("--");
- prev_has_rcflags = false;
- }
- } else {
- try zig_args.append("-rcflags");
- for (rc_source_file.flags) |arg| {
- try zig_args.append(arg);
- }
- try zig_args.append("--");
- prev_has_rcflags = true;
- }
- try zig_args.append(rc_source_file.file.getPath(b));
- },
+ for (frameworks.keys(), frameworks.values()) |name, info| {
+ if (info.needed) {
+ try zig_args.append("-needed_framework");
+ } else if (info.weak) {
+ try zig_args.append("-weak_framework");
+ } else {
+ try zig_args.append("-framework");
+ }
+ try zig_args.append(name);
}
- }
- if (self.win32_manifest) |manifest_file| {
- try zig_args.append(manifest_file.getPath(b));
- }
+ if (self.is_linking_libcpp) {
+ try zig_args.append("-lc++");
+ }
- if (transitive_deps.is_linking_libcpp) {
- try zig_args.append("-lc++");
+ if (self.is_linking_libc) {
+ try zig_args.append("-lc");
+ }
}
- if (transitive_deps.is_linking_libc) {
- try zig_args.append("-lc");
+ if (self.win32_manifest) |manifest_file| {
+ try zig_args.append(manifest_file.getPath(b));
}
if (self.image_base) |image_base| {
@@ -1702,17 +1436,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
if (self.generated_llvm_ir != null) try zig_args.append("-femit-llvm-ir");
if (self.generated_h != null) try zig_args.append("-femit-h");
- try addFlag(&zig_args, "strip", self.strip);
- try addFlag(&zig_args, "formatted-panics", self.formatted_panics);
- try addFlag(&zig_args, "unwind-tables", self.unwind_tables);
-
- if (self.dwarf_format) |dwarf_format| {
- try zig_args.append(switch (dwarf_format) {
- .@"32" => "-gdwarf32",
- .@"64" => "-gdwarf64",
- });
- }
-
switch (self.compress_debug_sections) {
.none => {},
.zlib => try zig_args.append("--compress-debug-sections=zlib"),
@@ -1769,11 +1492,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.append(libc_file);
}
- switch (self.optimize) {
- .Debug => {}, // Skip since it's the default.
- else => try zig_args.append(b.fmt("-O{s}", .{@tagName(self.optimize)})),
- }
-
try zig_args.append("--cache-dir");
try zig_args.append(b.cache_root.path orelse ".");
@@ -1793,11 +1511,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.append(b.fmt("{}", .{version}));
}
- if (self.target.isDarwin()) {
+ if (self.root_module.target_info.target.isDarwin()) {
const install_name = self.install_name orelse b.fmt("@rpath/{s}{s}{s}", .{
- self.target.libPrefix(),
+ self.root_module.target_info.target.libPrefix(),
self.name,
- self.target.dynamicLibSuffix(),
+ self.root_module.target_info.target.dynamicLibSuffix(),
});
try zig_args.append("-install_name");
try zig_args.append(install_name);
@@ -1823,27 +1541,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
}
try addFlag(&zig_args, "compiler-rt", self.bundle_compiler_rt);
- try addFlag(&zig_args, "single-threaded", self.single_threaded);
- if (self.disable_stack_probing) {
- try zig_args.append("-fno-stack-check");
- }
- try addFlag(&zig_args, "stack-protector", self.stack_protector);
- if (self.red_zone) |red_zone| {
- if (red_zone) {
- try zig_args.append("-mred-zone");
- } else {
- try zig_args.append("-mno-red-zone");
- }
- }
- try addFlag(&zig_args, "omit-frame-pointer", self.omit_frame_pointer);
try addFlag(&zig_args, "dll-export-fns", self.dll_export_fns);
-
- if (self.disable_sanitize_c) {
- try zig_args.append("-fno-sanitize-c");
- }
- if (self.sanitize_thread) {
- try zig_args.append("-fsanitize-thread");
- }
if (self.rdynamic) {
try zig_args.append("-rdynamic");
}
@@ -1875,29 +1573,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.append(b.fmt("--global-base={d}", .{global_base}));
}
- if (self.code_model != .default) {
- try zig_args.append("-mcmodel");
- try zig_args.append(@tagName(self.code_model));
- }
if (self.wasi_exec_model) |model| {
try zig_args.append(b.fmt("-mexec-model={s}", .{@tagName(model)}));
}
- for (self.export_symbol_names) |symbol_name| {
- try zig_args.append(b.fmt("--export={s}", .{symbol_name}));
- }
-
- if (!self.target.isNative()) {
- try zig_args.appendSlice(&.{
- "-target", try self.target.zigTriple(b.allocator),
- "-mcpu", try std.Build.serializeCpu(b.allocator, self.target.getCpu()),
- });
-
- if (self.target.dynamic_linker.get()) |dynamic_linker| {
- try zig_args.append("--dynamic-linker");
- try zig_args.append(dynamic_linker);
- }
- }
-
if (self.linker_script) |linker_script| {
try zig_args.append("--script");
try zig_args.append(linker_script.getPath(b));
@@ -1923,97 +1601,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try self.appendModuleArgs(&zig_args);
- for (self.include_dirs.items) |include_dir| {
- switch (include_dir) {
- .path => |include_path| {
- try zig_args.append("-I");
- try zig_args.append(include_path.getPath(b));
- },
- .path_system => |include_path| {
- try zig_args.append("-isystem");
- try zig_args.append(include_path.getPath(b));
- },
- .path_after => |include_path| {
- try zig_args.append("-idirafter");
- try zig_args.append(include_path.getPath(b));
- },
- .framework_path => |include_path| {
- try zig_args.append("-F");
- try zig_args.append(include_path.getPath2(b, step));
- },
- .framework_path_system => |include_path| {
- try zig_args.append("-iframework");
- try zig_args.append(include_path.getPath2(b, step));
- },
- .other_step => |other| {
- if (other.generated_h) |header| {
- try zig_args.append("-isystem");
- try zig_args.append(fs.path.dirname(header.path.?).?);
- }
- if (other.installed_headers.items.len > 0) {
- try zig_args.append("-I");
- try zig_args.append(b.pathJoin(&.{
- other.step.owner.install_prefix, "include",
- }));
- }
- },
- .config_header_step => |config_header| {
- const full_file_path = config_header.output_file.path.?;
- const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len];
- try zig_args.appendSlice(&.{ "-I", header_dir_path });
- },
- }
- }
-
- for (self.c_macros.items) |c_macro| {
- try zig_args.append("-D");
- try zig_args.append(c_macro);
- }
-
- try zig_args.ensureUnusedCapacity(2 * self.lib_paths.items.len);
- for (self.lib_paths.items) |lib_path| {
- zig_args.appendAssumeCapacity("-L");
- zig_args.appendAssumeCapacity(lib_path.getPath2(b, step));
- }
-
- try zig_args.ensureUnusedCapacity(2 * self.rpaths.items.len);
- for (self.rpaths.items) |rpath| {
- zig_args.appendAssumeCapacity("-rpath");
-
- if (self.target_info.target.isDarwin()) switch (rpath) {
- .path, .cwd_relative => |path| {
- // On Darwin, we should not try to expand special runtime paths such as
- // * @executable_path
- // * @loader_path
- if (mem.startsWith(u8, path, "@executable_path") or
- mem.startsWith(u8, path, "@loader_path"))
- {
- zig_args.appendAssumeCapacity(path);
- continue;
- }
- },
- .generated, .dependency => {},
- };
-
- zig_args.appendAssumeCapacity(rpath.getPath2(b, step));
- }
-
- {
- var it = self.frameworks.iterator();
- while (it.next()) |entry| {
- const name = entry.key_ptr.*;
- const info = entry.value_ptr.*;
- if (info.needed) {
- try zig_args.append("-needed_framework");
- } else if (info.weak) {
- try zig_args.append("-weak_framework");
- } else {
- try zig_args.append("-framework");
- }
- try zig_args.append(name);
- }
- }
-
if (b.sysroot) |sysroot| {
try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });
}
@@ -2058,7 +1645,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.append(@tagName(self.rc_includes));
}
- try addFlag(&zig_args, "valgrind", self.valgrind_support);
try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
if (self.build_id) |build_id| {
@@ -2075,12 +1661,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.append(dir.getPath(b));
}
- if (self.main_mod_path) |dir| {
- try zig_args.append("--main-mod-path");
- try zig_args.append(dir.getPath(b));
- }
-
- try addFlag(&zig_args, "PIC", self.force_pic);
try addFlag(&zig_args, "PIE", self.pie);
try addFlag(&zig_args, "lto", self.want_lto);
@@ -2223,7 +1803,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
}
if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic and
- self.version != null and self.target.wantSharedLibSymLinks())
+ self.version != null and self.root_module.target.wantSharedLibSymLinks())
{
try doAtomicSymLinks(
step,
@@ -2234,24 +1814,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
}
}
-fn isLibCLibrary(name: []const u8) bool {
- const libc_libraries = [_][]const u8{ "c", "m", "dl", "rt", "pthread" };
- for (libc_libraries) |libc_lib_name| {
- if (mem.eql(u8, name, libc_lib_name))
- return true;
- }
- return false;
-}
-
-fn isLibCppLibrary(name: []const u8) bool {
- const libcpp_libraries = [_][]const u8{ "c++", "stdc++" };
- for (libcpp_libraries) |libcpp_lib_name| {
- if (mem.eql(u8, name, libcpp_lib_name))
- return true;
- }
- return false;
-}
-
/// Returned slice must be freed by the caller.
fn findVcpkgRoot(allocator: Allocator) !?[]const u8 {
const appdata_path = try fs.getAppDataDir(allocator, "vcpkg");
@@ -2345,67 +1907,6 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)
}
}
-const TransitiveDeps = struct {
- link_objects: ArrayList(LinkObject),
- seen_system_libs: StringHashMap(void),
- seen_steps: std.AutoHashMap(*const Step, void),
- is_linking_libcpp: bool,
- is_linking_libc: bool,
- frameworks: *StringHashMap(FrameworkLinkInfo),
-
- fn add(td: *TransitiveDeps, link_objects: []const LinkObject) !void {
- try td.link_objects.ensureUnusedCapacity(link_objects.len);
-
- for (link_objects) |link_object| {
- try td.link_objects.append(link_object);
- switch (link_object) {
- .other_step => |other| try addInner(td, other, other.isDynamicLibrary()),
- else => {},
- }
- }
- }
-
- fn addInner(td: *TransitiveDeps, other: *Compile, dyn: bool) !void {
- // Inherit dependency on libc and libc++
- td.is_linking_libcpp = td.is_linking_libcpp or other.is_linking_libcpp;
- td.is_linking_libc = td.is_linking_libc or other.is_linking_libc;
-
- // Inherit dependencies on darwin frameworks
- if (!dyn) {
- var it = other.frameworks.iterator();
- while (it.next()) |framework| {
- try td.frameworks.put(framework.key_ptr.*, framework.value_ptr.*);
- }
- }
-
- // Inherit dependencies on system libraries and static libraries.
- for (other.link_objects.items) |other_link_object| {
- switch (other_link_object) {
- .system_lib => |system_lib| {
- if ((try td.seen_system_libs.fetchPut(system_lib.name, {})) != null)
- continue;
-
- if (dyn)
- continue;
-
- try td.link_objects.append(other_link_object);
- },
- .other_step => |inner_other| {
- if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)
- continue;
-
- const included_in_lib = (other.kind == .lib and inner_other.kind == .obj);
- if (!dyn and !included_in_lib)
- try td.link_objects.append(other_link_object);
-
- try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());
- },
- else => continue,
- }
- }
- }
-};
-
fn checkCompileErrors(self: *Compile) !void {
// Clear this field so that it does not get printed by the build runner.
const actual_eb = self.step.result_error_bundle;
lib/std/Build/Step/Run.zig
@@ -488,7 +488,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
man.hash.addBytes(file_path);
},
.artifact => |artifact| {
- if (artifact.target.isWindows()) {
+ if (artifact.root_module.target_info.target.os.tag == .windows) {
// On Windows we don't have rpaths so we have to add .dll search paths to PATH
self.addPathForDynLibs(artifact);
}
@@ -682,8 +682,9 @@ fn runCommand(
else => break :interpret,
}
- const need_cross_glibc = exe.target.isGnuLibC() and exe.is_linking_libc;
- switch (b.host.getExternalExecutor(&exe.target_info, .{
+ const need_cross_glibc = exe.root_module.target_info.target.isGnuLibC() and
+ exe.is_linking_libc;
+ switch (b.host.getExternalExecutor(&exe.root_module.target_info, .{
.qemu_fixes_dl = need_cross_glibc and b.glibc_runtimes_dir != null,
.link_libc = exe.is_linking_libc,
})) {
@@ -714,9 +715,9 @@ fn runCommand(
// needs the directory to be called "i686" rather than
// "x86" which is why we do it manually here.
const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}";
- const cpu_arch = exe.target.getCpuArch();
- const os_tag = exe.target.getOsTag();
- const abi = exe.target.getAbi();
+ const cpu_arch = exe.root_module.target_info.target.cpu.arch;
+ const os_tag = exe.root_module.target_info.target.os.tag;
+ const abi = exe.root_module.target_info.target.abi;
const cpu_arch_name: []const u8 = if (cpu_arch == .x86)
"i686"
else
@@ -769,7 +770,7 @@ fn runCommand(
if (allow_skip) return error.MakeSkipped;
const host_name = try b.host.target.zigTriple(b.allocator);
- const foreign_name = try exe.target.zigTriple(b.allocator);
+ const foreign_name = try exe.root_module.target_info.target.zigTriple(b.allocator);
return step.fail("the host system ({s}) is unable to execute binaries from the target ({s})", .{
host_name, foreign_name,
@@ -777,7 +778,7 @@ fn runCommand(
},
}
- if (exe.target.isWindows()) {
+ if (exe.root_module.target_info.target.os.tag == .windows) {
// On Windows we don't have rpaths so we have to add .dll search paths to PATH
self.addPathForDynLibs(exe);
}
@@ -1295,15 +1296,14 @@ fn evalGeneric(self: *Run, child: *std.process.Child) !StdIoResult {
fn addPathForDynLibs(self: *Run, artifact: *Step.Compile) void {
const b = self.step.owner;
- for (artifact.link_objects.items) |link_object| {
- switch (link_object) {
- .other_step => |other| {
- if (other.target.isWindows() and other.isDynamicLibrary()) {
- addPathDir(self, fs.path.dirname(other.getEmittedBin().getPath(b)).?);
- addPathForDynLibs(self, other);
- }
- },
- else => {},
+ var it = artifact.root_module.iterateDependencies(artifact);
+ while (it.next()) |item| {
+ const other = item.compile.?;
+ if (item.module == &other.root_module) {
+ if (item.module.target_info.target.os.tag == .windows and other.isDynamicLibrary()) {
+ addPathDir(self, fs.path.dirname(other.getEmittedBin().getPath(b)).?);
+ addPathForDynLibs(self, other);
+ }
}
}
}
@@ -1321,7 +1321,7 @@ fn failForeign(
const b = self.step.owner;
const host_name = try b.host.target.zigTriple(b.allocator);
- const foreign_name = try exe.target.zigTriple(b.allocator);
+ const foreign_name = try exe.root_module.target_info.target.zigTriple(b.allocator);
return self.step.fail(
\\unable to spawn foreign binary '{s}' ({s}) on host system ({s})
lib/std/Build/Module.zig
@@ -0,0 +1,616 @@
+/// The one responsible for creating this module.
+owner: *std.Build,
+/// Tracks the set of steps that depend on this `Module`. This ensures that
+/// when making this `Module` depend on other `Module` objects and `Step`
+/// objects, respective `Step` dependencies can be added.
+depending_steps: std.AutoArrayHashMapUnmanaged(*std.Build.Step.Compile, void),
+/// This could either be a generated file, in which case the module
+/// contains exactly one file, or it could be a path to the root source
+/// file of directory of files which constitute the module.
+/// If `null`, it means this module is made up of only `link_objects`.
+root_source_file: ?LazyPath,
+/// The modules that are mapped into this module's import table.
+import_table: std.StringArrayHashMap(*Module),
+
+target: std.zig.CrossTarget,
+target_info: NativeTargetInfo,
+optimize: std.builtin.OptimizeMode,
+dwarf_format: ?std.dwarf.Format,
+
+c_macros: std.ArrayList([]const u8),
+include_dirs: std.ArrayList(IncludeDir),
+lib_paths: std.ArrayList(LazyPath),
+rpaths: std.ArrayList(LazyPath),
+frameworks: std.StringArrayHashMapUnmanaged(FrameworkLinkInfo),
+c_std: std.Build.CStd,
+link_objects: std.ArrayList(LinkObject),
+
+strip: ?bool,
+unwind_tables: ?bool,
+single_threaded: ?bool,
+stack_protector: ?bool,
+stack_check: ?bool,
+sanitize_c: ?bool,
+sanitize_thread: ?bool,
+code_model: std.builtin.CodeModel,
+/// Whether to emit machine code that integrates with Valgrind.
+valgrind: ?bool,
+/// Position Independent Code
+pic: ?bool,
+red_zone: ?bool,
+/// Whether to omit the stack frame pointer. Frees up a register and makes it
+/// more more difficiult to obtain stack traces. Has target-dependent effects.
+omit_frame_pointer: ?bool,
+/// `true` requires a compilation that includes this Module to link libc.
+/// `false` causes a build failure if a compilation that includes this Module would link libc.
+/// `null` neither requires nor prevents libc from being linked.
+link_libc: ?bool,
+/// `true` requires a compilation that includes this Module to link libc++.
+/// `false` causes a build failure if a compilation that includes this Module would link libc++.
+/// `null` neither requires nor prevents libc++ from being linked.
+link_libcpp: ?bool,
+
+/// Symbols to be exported when compiling to WebAssembly.
+export_symbol_names: []const []const u8 = &.{},
+
+pub const LinkObject = union(enum) {
+ static_path: LazyPath,
+ other_step: *std.Build.Step.Compile,
+ system_lib: SystemLib,
+ assembly_file: LazyPath,
+ c_source_file: *CSourceFile,
+ c_source_files: *CSourceFiles,
+ win32_resource_file: *RcSourceFile,
+};
+
+pub const SystemLib = struct {
+ name: []const u8,
+ needed: bool,
+ weak: bool,
+ use_pkg_config: UsePkgConfig,
+ preferred_link_mode: std.builtin.LinkMode,
+ search_strategy: SystemLib.SearchStrategy,
+
+ pub const UsePkgConfig = enum {
+ /// Don't use pkg-config, just pass -lfoo where foo is name.
+ no,
+ /// Try to get information on how to link the library from pkg-config.
+ /// If that fails, fall back to passing -lfoo where foo is name.
+ yes,
+ /// Try to get information on how to link the library from pkg-config.
+ /// If that fails, error out.
+ force,
+ };
+
+ pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
+};
+
+pub const CSourceFiles = struct {
+ dependency: ?*std.Build.Dependency,
+ /// If `dependency` is not null relative to it,
+ /// else relative to the build root.
+ files: []const []const u8,
+ flags: []const []const u8,
+};
+
+pub const CSourceFile = struct {
+ file: LazyPath,
+ flags: []const []const u8,
+
+ pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile {
+ return .{
+ .file = self.file.dupe(b),
+ .flags = b.dupeStrings(self.flags),
+ };
+ }
+};
+
+pub const RcSourceFile = struct {
+ file: LazyPath,
+ /// Any option that rc.exe accepts will work here, with the exception of:
+ /// - `/fo`: The output filename is set by the build system
+ /// - `/p`: Only running the preprocessor is not supported in this context
+ /// - `/:no-preprocess` (non-standard option): Not supported in this context
+ /// - Any MUI-related option
+ /// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-
+ ///
+ /// Implicitly defined options:
+ /// /x (ignore the INCLUDE environment variable)
+ /// /D_DEBUG or /DNDEBUG depending on the optimization mode
+ flags: []const []const u8 = &.{},
+
+ pub fn dupe(self: RcSourceFile, b: *std.Build) RcSourceFile {
+ return .{
+ .file = self.file.dupe(b),
+ .flags = b.dupeStrings(self.flags),
+ };
+ }
+};
+
+pub const IncludeDir = union(enum) {
+ path: LazyPath,
+ path_system: LazyPath,
+ path_after: LazyPath,
+ framework_path: LazyPath,
+ framework_path_system: LazyPath,
+ other_step: *std.Build.Step.Compile,
+ config_header_step: *std.Build.Step.ConfigHeader,
+};
+
+pub const FrameworkLinkInfo = struct {
+ needed: bool = false,
+ weak: bool = false,
+};
+
+pub const CreateOptions = struct {
+ target: std.zig.CrossTarget,
+ target_info: ?NativeTargetInfo = null,
+ optimize: std.builtin.OptimizeMode,
+ root_source_file: ?LazyPath = null,
+ import_table: []const Import = &.{},
+ link_libc: ?bool = null,
+ link_libcpp: ?bool = null,
+ single_threaded: ?bool = null,
+ strip: ?bool = null,
+ unwind_tables: ?bool = null,
+ dwarf_format: ?std.dwarf.Format = null,
+ c_std: std.Build.CStd = .C99,
+ code_model: std.builtin.CodeModel = .default,
+ stack_protector: ?bool = null,
+ stack_check: ?bool = null,
+ sanitize_c: ?bool = null,
+ sanitize_thread: ?bool = null,
+ valgrind: ?bool = null,
+ pic: ?bool = null,
+ red_zone: ?bool = null,
+ /// Whether to omit the stack frame pointer. Frees up a register and makes it
+ /// more more difficiult to obtain stack traces. Has target-dependent effects.
+ omit_frame_pointer: ?bool = null,
+};
+
+pub const Import = struct {
+ name: []const u8,
+ module: *Module,
+};
+
+pub fn init(owner: *std.Build, options: CreateOptions, compile: ?*std.Build.Step.Compile) Module {
+ var m: Module = .{
+ .owner = owner,
+ .depending_steps = .{},
+ .root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null,
+ .import_table = std.StringArrayHashMap(*Module).init(owner.allocator),
+ .target = options.target,
+ .target_info = options.target_info orelse
+ NativeTargetInfo.detect(options.target) catch @panic("unhandled error"),
+ .optimize = options.optimize,
+ .link_libc = options.link_libc,
+ .link_libcpp = options.link_libcpp,
+ .dwarf_format = options.dwarf_format,
+ .c_macros = std.ArrayList([]const u8).init(owner.allocator),
+ .include_dirs = std.ArrayList(IncludeDir).init(owner.allocator),
+ .lib_paths = std.ArrayList(LazyPath).init(owner.allocator),
+ .rpaths = std.ArrayList(LazyPath).init(owner.allocator),
+ .frameworks = .{},
+ .c_std = options.c_std,
+ .link_objects = std.ArrayList(LinkObject).init(owner.allocator),
+ .strip = options.strip,
+ .unwind_tables = options.unwind_tables,
+ .single_threaded = options.single_threaded,
+ .stack_protector = options.stack_protector,
+ .stack_check = options.stack_check,
+ .sanitize_c = options.sanitize_c,
+ .sanitize_thread = options.sanitize_thread,
+ .code_model = options.code_model,
+ .valgrind = options.valgrind,
+ .pic = options.pic,
+ .red_zone = options.red_zone,
+ .omit_frame_pointer = options.omit_frame_pointer,
+ .export_symbol_names = &.{},
+ };
+
+ if (compile) |c| {
+ m.depending_steps.put(owner.allocator, c, {}) catch @panic("OOM");
+ }
+
+ m.import_table.ensureUnusedCapacity(options.import_table.len) catch @panic("OOM");
+ for (options.import_table) |dep| {
+ m.import_table.putAssumeCapacity(dep.name, dep.module);
+ }
+
+ var it = m.iterateDependencies(null);
+ while (it.next()) |item| addShallowDependencies(&m, item.module);
+
+ return m;
+}
+
+pub fn create(owner: *std.Build, options: CreateOptions) *Module {
+ const m = owner.allocator.create(Module) catch @panic("OOM");
+ m.* = init(owner, options, null);
+ return m;
+}
+
+/// Adds an existing module to be used with `@import`.
+pub fn addImport(m: *Module, name: []const u8, module: *Module) void {
+ const b = m.owner;
+ m.import_table.put(b.dupe(name), module) catch @panic("OOM");
+
+ var it = module.iterateDependencies(null);
+ while (it.next()) |item| addShallowDependencies(m, item.module);
+}
+
+/// Creates step dependencies and updates `depending_steps` of `dependee` so that
+/// subsequent calls to `addImport` on `dependee` will additionally create step
+/// dependencies on `m`'s `depending_steps`.
+fn addShallowDependencies(m: *Module, dependee: *Module) void {
+ if (dependee.root_source_file) |lazy_path| addLazyPathDependencies(m, dependee, lazy_path);
+ for (dependee.lib_paths.items) |lib_path| addLazyPathDependencies(m, dependee, lib_path);
+ for (dependee.rpaths.items) |rpath| addLazyPathDependencies(m, dependee, rpath);
+
+ for (dependee.link_objects.items) |link_object| switch (link_object) {
+ .other_step => |compile| addStepDependencies(m, dependee, &compile.step),
+
+ .static_path,
+ .assembly_file,
+ => |lp| addLazyPathDependencies(m, dependee, lp),
+
+ .c_source_file => |x| addLazyPathDependencies(m, dependee, x.file),
+ .win32_resource_file => |x| addLazyPathDependencies(m, dependee, x.file),
+
+ .c_source_files,
+ .system_lib,
+ => {},
+ };
+}
+
+fn addLazyPathDependencies(m: *Module, module: *Module, lazy_path: LazyPath) void {
+ addLazyPathDependenciesOnly(m, lazy_path);
+ if (m != module) {
+ for (m.depending_steps.keys()) |compile| {
+ module.depending_steps.put(m.owner.allocator, compile, {}) catch @panic("OOM");
+ }
+ }
+}
+
+fn addLazyPathDependenciesOnly(m: *Module, lazy_path: LazyPath) void {
+ for (m.depending_steps.keys()) |compile| {
+ lazy_path.addStepDependencies(&compile.step);
+ }
+}
+
+fn addStepDependencies(m: *Module, module: *Module, dependee: *std.Build.Step) void {
+ addStepDependenciesOnly(m, dependee);
+ if (m != module) {
+ for (m.depending_steps.keys()) |compile| {
+ module.depending_steps.put(m.owner.allocator, compile, {}) catch @panic("OOM");
+ }
+ }
+}
+
+fn addStepDependenciesOnly(m: *Module, dependee: *std.Build.Step) void {
+ for (m.depending_steps.keys()) |compile| {
+ compile.step.dependOn(dependee);
+ }
+}
+
+/// Creates a new module and adds it to be used with `@import`.
+pub fn addAnonymousImport(m: *Module, name: []const u8, options: std.Build.CreateModuleOptions) void {
+ const b = m.step.owner;
+ const module = b.createModule(options);
+ return addImport(m, name, module);
+}
+
+pub fn addOptions(m: *Module, module_name: []const u8, options: *std.Build.Step.Options) void {
+ addImport(m, module_name, options.createModule());
+}
+
+pub const DependencyIterator = struct {
+ allocator: std.mem.Allocator,
+ index: usize,
+ set: std.AutoArrayHashMapUnmanaged(Key, []const u8),
+
+ pub const Key = struct {
+ /// The compilation that contains the `Module`. Note that a `Module` might be
+ /// used by more than one compilation.
+ compile: ?*std.Build.Step.Compile,
+ module: *Module,
+ };
+
+ pub const Item = struct {
+ /// The compilation that contains the `Module`. Note that a `Module` might be
+ /// used by more than one compilation.
+ compile: ?*std.Build.Step.Compile,
+ module: *Module,
+ name: []const u8,
+ };
+
+ pub fn deinit(it: *DependencyIterator) void {
+ it.set.deinit(it.allocator);
+ it.* = undefined;
+ }
+
+ pub fn next(it: *DependencyIterator) ?Item {
+ if (it.index >= it.set.count()) {
+ it.set.clearAndFree(it.allocator);
+ return null;
+ }
+ const key = it.set.keys()[it.index];
+ const name = it.set.values()[it.index];
+ it.index += 1;
+ const module = key.module;
+ it.set.ensureUnusedCapacity(it.allocator, module.import_table.count()) catch
+ @panic("OOM");
+ for (module.import_table.keys(), module.import_table.values()) |dep_name, dep| {
+ it.set.putAssumeCapacity(.{
+ .module = dep,
+ .compile = key.compile,
+ }, dep_name);
+ }
+
+ if (key.compile != null) {
+ for (module.link_objects.items) |link_object| switch (link_object) {
+ .other_step => |compile| {
+ it.set.put(it.allocator, .{
+ .module = &compile.root_module,
+ .compile = compile,
+ }, "root") catch @panic("OOM");
+ },
+ else => {},
+ };
+ }
+
+ return .{
+ .compile = key.compile,
+ .module = key.module,
+ .name = name,
+ };
+ }
+};
+
+pub fn iterateDependencies(
+ m: *Module,
+ chase_steps: ?*std.Build.Step.Compile,
+) DependencyIterator {
+ var it: DependencyIterator = .{
+ .allocator = m.owner.allocator,
+ .index = 0,
+ .set = .{},
+ };
+ it.set.ensureUnusedCapacity(m.owner.allocator, m.import_table.count() + 1) catch @panic("OOM");
+ it.set.putAssumeCapacity(.{
+ .module = m,
+ .compile = chase_steps,
+ }, "root");
+ return it;
+}
+
+pub const LinkSystemLibraryOptions = struct {
+ needed: bool = false,
+ weak: bool = false,
+ use_pkg_config: SystemLib.UsePkgConfig = .yes,
+ preferred_link_mode: std.builtin.LinkMode = .Dynamic,
+ search_strategy: SystemLib.SearchStrategy = .paths_first,
+};
+
+pub fn linkSystemLibrary(
+ m: *Module,
+ name: []const u8,
+ options: LinkSystemLibraryOptions,
+) void {
+ const b = m.owner;
+ if (m.target_info.target.is_libc_lib_name(name)) {
+ m.link_libc = true;
+ return;
+ }
+ if (m.target_info.target.is_libcpp_lib_name(name)) {
+ m.link_libcpp = true;
+ return;
+ }
+
+ m.link_objects.append(.{
+ .system_lib = .{
+ .name = b.dupe(name),
+ .needed = options.needed,
+ .weak = options.weak,
+ .use_pkg_config = options.use_pkg_config,
+ .preferred_link_mode = options.preferred_link_mode,
+ .search_strategy = options.search_strategy,
+ },
+ }) catch @panic("OOM");
+}
+
+pub const AddCSourceFilesOptions = struct {
+ /// When provided, `files` are relative to `dependency` rather than the
+ /// package that owns the `Compile` step.
+ dependency: ?*std.Build.Dependency = null,
+ files: []const []const u8,
+ flags: []const []const u8 = &.{},
+};
+
+/// Handy when you have many C/C++ source files and want them all to have the same flags.
+pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
+ const c_source_files = m.owner.allocator.create(CSourceFiles) catch @panic("OOM");
+ c_source_files.* = .{
+ .dependency = options.dependency,
+ .files = m.owner.dupeStrings(options.files),
+ .flags = m.owner.dupeStrings(options.flags),
+ };
+ m.link_objects.append(.{ .c_source_files = c_source_files }) catch @panic("OOM");
+}
+
+pub fn addCSourceFile(m: *Module, source: CSourceFile) void {
+ const c_source_file = m.owner.allocator.create(CSourceFile) catch @panic("OOM");
+ c_source_file.* = source.dupe(m.owner);
+ m.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM");
+ addLazyPathDependenciesOnly(m, source.file);
+}
+
+/// Resource files must have the extension `.rc`.
+/// Can be called regardless of target. The .rc file will be ignored
+/// if the target object format does not support embedded resources.
+pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void {
+ // Only the PE/COFF format has a Resource Table, so for any other target
+ // the resource file is ignored.
+ if (m.target_info.target.ofmt != .coff) return;
+
+ const rc_source_file = m.owner.allocator.create(RcSourceFile) catch @panic("OOM");
+ rc_source_file.* = source.dupe(m.owner);
+ m.link_objects.append(.{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
+ addLazyPathDependenciesOnly(m, source.file);
+}
+
+pub fn addAssemblyFile(m: *Module, source: LazyPath) void {
+ m.link_objects.append(.{ .assembly_file = source.dupe(m.owner) }) catch @panic("OOM");
+ addLazyPathDependenciesOnly(m, source);
+}
+
+pub fn addObjectFile(m: *Module, source: LazyPath) void {
+ m.link_objects.append(.{ .static_path = source.dupe(m.owner) }) catch @panic("OOM");
+ addLazyPathDependencies(m, source);
+}
+
+pub fn appendZigProcessFlags(
+ m: *Module,
+ zig_args: *std.ArrayList([]const u8),
+ asking_step: ?*std.Build.Step,
+) !void {
+ const b = m.owner;
+
+ try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip");
+ try addFlag(zig_args, m.unwind_tables, "-funwind-tables", "-fno-unwind-tables");
+ try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded");
+ try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check");
+ try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector");
+ try addFlag(zig_args, m.omit_frame_pointer, "-fomit-frame-pointer", "-fno-omit-frame-pointer");
+ try addFlag(zig_args, m.sanitize_c, "-fsanitize-c", "-fno-sanitize-c");
+ try addFlag(zig_args, m.sanitize_thread, "-fsanitize-thread", "-fno-sanitize-thread");
+ try addFlag(zig_args, m.valgrind, "-fvalgrind", "-fno-valgrind");
+ try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC");
+ try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone");
+
+ if (m.dwarf_format) |dwarf_format| {
+ try zig_args.append(switch (dwarf_format) {
+ .@"32" => "-gdwarf32",
+ .@"64" => "-gdwarf64",
+ });
+ }
+
+ try zig_args.ensureUnusedCapacity(1);
+ switch (m.optimize) {
+ .Debug => {}, // Skip since it's the default.
+ .ReleaseSmall => zig_args.appendAssumeCapacity("-OReleaseSmall"),
+ .ReleaseFast => zig_args.appendAssumeCapacity("-OReleaseFast"),
+ .ReleaseSafe => zig_args.appendAssumeCapacity("-OReleaseSafe"),
+ }
+
+ if (m.code_model != .default) {
+ try zig_args.append("-mcmodel");
+ try zig_args.append(@tagName(m.code_model));
+ }
+
+ if (!m.target.isNative()) {
+ try zig_args.appendSlice(&.{
+ "-target", try m.target.zigTriple(b.allocator),
+ "-mcpu", try std.Build.serializeCpu(b.allocator, m.target.getCpu()),
+ });
+
+ if (m.target.dynamic_linker.get()) |dynamic_linker| {
+ try zig_args.append("--dynamic-linker");
+ try zig_args.append(dynamic_linker);
+ }
+ }
+
+ for (m.export_symbol_names) |symbol_name| {
+ try zig_args.append(b.fmt("--export={s}", .{symbol_name}));
+ }
+
+ for (m.include_dirs.items) |include_dir| {
+ switch (include_dir) {
+ .path => |include_path| {
+ try zig_args.append("-I");
+ try zig_args.append(include_path.getPath(b));
+ },
+ .path_system => |include_path| {
+ try zig_args.append("-isystem");
+ try zig_args.append(include_path.getPath(b));
+ },
+ .path_after => |include_path| {
+ try zig_args.append("-idirafter");
+ try zig_args.append(include_path.getPath(b));
+ },
+ .framework_path => |include_path| {
+ try zig_args.append("-F");
+ try zig_args.append(include_path.getPath2(b, asking_step));
+ },
+ .framework_path_system => |include_path| {
+ try zig_args.append("-iframework");
+ try zig_args.append(include_path.getPath2(b, asking_step));
+ },
+ .other_step => |other| {
+ if (other.generated_h) |header| {
+ try zig_args.append("-isystem");
+ try zig_args.append(std.fs.path.dirname(header.path.?).?);
+ }
+ if (other.installed_headers.items.len > 0) {
+ try zig_args.append("-I");
+ try zig_args.append(b.pathJoin(&.{
+ other.step.owner.install_prefix, "include",
+ }));
+ }
+ },
+ .config_header_step => |config_header| {
+ const full_file_path = config_header.output_file.path.?;
+ const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len];
+ try zig_args.appendSlice(&.{ "-I", header_dir_path });
+ },
+ }
+ }
+
+ for (m.c_macros.items) |c_macro| {
+ try zig_args.append("-D");
+ try zig_args.append(c_macro);
+ }
+
+ try zig_args.ensureUnusedCapacity(2 * m.lib_paths.items.len);
+ for (m.lib_paths.items) |lib_path| {
+ zig_args.appendAssumeCapacity("-L");
+ zig_args.appendAssumeCapacity(lib_path.getPath2(b, asking_step));
+ }
+
+ try zig_args.ensureUnusedCapacity(2 * m.rpaths.items.len);
+ for (m.rpaths.items) |rpath| {
+ zig_args.appendAssumeCapacity("-rpath");
+
+ if (m.target_info.target.isDarwin()) switch (rpath) {
+ .path, .cwd_relative => |path| {
+ // On Darwin, we should not try to expand special runtime paths such as
+ // * @executable_path
+ // * @loader_path
+ if (std.mem.startsWith(u8, path, "@executable_path") or
+ std.mem.startsWith(u8, path, "@loader_path"))
+ {
+ zig_args.appendAssumeCapacity(path);
+ continue;
+ }
+ },
+ .generated, .dependency => {},
+ };
+
+ zig_args.appendAssumeCapacity(rpath.getPath2(b, asking_step));
+ }
+}
+
+fn addFlag(
+ args: *std.ArrayList([]const u8),
+ opt: ?bool,
+ then_name: []const u8,
+ else_name: []const u8,
+) !void {
+ const cond = opt orelse return;
+ return args.append(if (cond) then_name else else_name);
+}
+
+const Module = @This();
+const std = @import("std");
+const assert = std.debug.assert;
+const LazyPath = std.Build.LazyPath;
+const NativeTargetInfo = std.zig.system.NativeTargetInfo;
lib/std/Build.zig
@@ -29,36 +29,7 @@ pub const Builder = Build;
pub const InstallDirectoryOptions = Step.InstallDir.Options;
pub const Step = @import("Build/Step.zig");
-/// deprecated: use `Step.CheckFile`.
-pub const CheckFileStep = @import("Build/Step/CheckFile.zig");
-/// deprecated: use `Step.CheckObject`.
-pub const CheckObjectStep = @import("Build/Step/CheckObject.zig");
-/// deprecated: use `Step.ConfigHeader`.
-pub const ConfigHeaderStep = @import("Build/Step/ConfigHeader.zig");
-/// deprecated: use `Step.Fmt`.
-pub const FmtStep = @import("Build/Step/Fmt.zig");
-/// deprecated: use `Step.InstallArtifact`.
-pub const InstallArtifactStep = @import("Build/Step/InstallArtifact.zig");
-/// deprecated: use `Step.InstallDir`.
-pub const InstallDirStep = @import("Build/Step/InstallDir.zig");
-/// deprecated: use `Step.InstallFile`.
-pub const InstallFileStep = @import("Build/Step/InstallFile.zig");
-/// deprecated: use `Step.ObjCopy`.
-pub const ObjCopyStep = @import("Build/Step/ObjCopy.zig");
-/// deprecated: use `Step.Compile`.
-pub const CompileStep = @import("Build/Step/Compile.zig");
-/// deprecated: use `Step.Options`.
-pub const OptionsStep = @import("Build/Step/Options.zig");
-/// deprecated: use `Step.RemoveDir`.
-pub const RemoveDirStep = @import("Build/Step/RemoveDir.zig");
-/// deprecated: use `Step.Run`.
-pub const RunStep = @import("Build/Step/Run.zig");
-/// deprecated: use `Step.TranslateC`.
-pub const TranslateCStep = @import("Build/Step/TranslateC.zig");
-/// deprecated: use `Step.WriteFile`.
-pub const WriteFileStep = @import("Build/Step/WriteFile.zig");
-/// deprecated: use `LazyPath`.
-pub const FileSource = LazyPath;
+pub const Module = @import("Build/Module.zig");
install_tls: TopLevelStep,
uninstall_tls: TopLevelStep,
@@ -634,34 +605,31 @@ pub const ExecutableOptions = struct {
use_llvm: ?bool = null,
use_lld: ?bool = null,
zig_lib_dir: ?LazyPath = null,
- main_mod_path: ?LazyPath = null,
/// Embed a `.manifest` file in the compilation if the object format supports it.
/// https://learn.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference
/// Manifest files must have the extension `.manifest`.
/// Can be set regardless of target. The `.manifest` file will be ignored
/// if the target object format does not support embedded manifests.
win32_manifest: ?LazyPath = null,
-
- /// Deprecated; use `main_mod_path`.
- main_pkg_path: ?LazyPath = null,
};
pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile {
return Step.Compile.create(b, .{
.name = options.name,
- .root_source_file = options.root_source_file,
+ .root_module = .{
+ .root_source_file = options.root_source_file,
+ .target = options.target,
+ .optimize = options.optimize,
+ .link_libc = options.link_libc,
+ .single_threaded = options.single_threaded,
+ },
.version = options.version,
- .target = options.target,
- .optimize = options.optimize,
.kind = .exe,
.linkage = options.linkage,
.max_rss = options.max_rss,
- .link_libc = options.link_libc,
- .single_threaded = options.single_threaded,
.use_llvm = options.use_llvm,
.use_lld = options.use_lld,
.zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
- .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
.win32_manifest = options.win32_manifest,
});
}
@@ -677,26 +645,23 @@ pub const ObjectOptions = struct {
use_llvm: ?bool = null,
use_lld: ?bool = null,
zig_lib_dir: ?LazyPath = null,
- main_mod_path: ?LazyPath = null,
-
- /// Deprecated; use `main_mod_path`.
- main_pkg_path: ?LazyPath = null,
};
pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile {
return Step.Compile.create(b, .{
.name = options.name,
- .root_source_file = options.root_source_file,
- .target = options.target,
- .optimize = options.optimize,
+ .root_module = .{
+ .root_source_file = options.root_source_file,
+ .target = options.target,
+ .optimize = options.optimize,
+ .link_libc = options.link_libc,
+ .single_threaded = options.single_threaded,
+ },
.kind = .obj,
.max_rss = options.max_rss,
- .link_libc = options.link_libc,
- .single_threaded = options.single_threaded,
.use_llvm = options.use_llvm,
.use_lld = options.use_lld,
.zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
- .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
});
}
@@ -712,34 +677,31 @@ pub const SharedLibraryOptions = struct {
use_llvm: ?bool = null,
use_lld: ?bool = null,
zig_lib_dir: ?LazyPath = null,
- main_mod_path: ?LazyPath = null,
/// Embed a `.manifest` file in the compilation if the object format supports it.
/// https://learn.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference
/// Manifest files must have the extension `.manifest`.
/// Can be set regardless of target. The `.manifest` file will be ignored
/// if the target object format does not support embedded manifests.
win32_manifest: ?LazyPath = null,
-
- /// Deprecated; use `main_mod_path`.
- main_pkg_path: ?LazyPath = null,
};
pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile {
return Step.Compile.create(b, .{
.name = options.name,
- .root_source_file = options.root_source_file,
+ .root_module = .{
+ .target = options.target,
+ .optimize = options.optimize,
+ .root_source_file = options.root_source_file,
+ .link_libc = options.link_libc,
+ .single_threaded = options.single_threaded,
+ },
.kind = .lib,
.linkage = .dynamic,
.version = options.version,
- .target = options.target,
- .optimize = options.optimize,
.max_rss = options.max_rss,
- .link_libc = options.link_libc,
- .single_threaded = options.single_threaded,
.use_llvm = options.use_llvm,
.use_lld = options.use_lld,
.zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
- .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
.win32_manifest = options.win32_manifest,
});
}
@@ -756,28 +718,25 @@ pub const StaticLibraryOptions = struct {
use_llvm: ?bool = null,
use_lld: ?bool = null,
zig_lib_dir: ?LazyPath = null,
- main_mod_path: ?LazyPath = null,
-
- /// Deprecated; use `main_mod_path`.
- main_pkg_path: ?LazyPath = null,
};
pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile {
return Step.Compile.create(b, .{
.name = options.name,
- .root_source_file = options.root_source_file,
+ .root_module = .{
+ .target = options.target,
+ .optimize = options.optimize,
+ .root_source_file = options.root_source_file,
+ .link_libc = options.link_libc,
+ .single_threaded = options.single_threaded,
+ },
.kind = .lib,
.linkage = .static,
.version = options.version,
- .target = options.target,
- .optimize = options.optimize,
.max_rss = options.max_rss,
- .link_libc = options.link_libc,
- .single_threaded = options.single_threaded,
.use_llvm = options.use_llvm,
.use_lld = options.use_lld,
.zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
- .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
});
}
@@ -795,28 +754,25 @@ pub const TestOptions = struct {
use_llvm: ?bool = null,
use_lld: ?bool = null,
zig_lib_dir: ?LazyPath = null,
- main_mod_path: ?LazyPath = null,
-
- /// Deprecated; use `main_mod_path`.
- main_pkg_path: ?LazyPath = null,
};
pub fn addTest(b: *Build, options: TestOptions) *Step.Compile {
return Step.Compile.create(b, .{
.name = options.name,
.kind = .@"test",
- .root_source_file = options.root_source_file,
- .target = options.target,
- .optimize = options.optimize,
+ .root_module = .{
+ .root_source_file = options.root_source_file,
+ .target = options.target,
+ .optimize = options.optimize,
+ .link_libc = options.link_libc,
+ .single_threaded = options.single_threaded,
+ },
.max_rss = options.max_rss,
.filter = options.filter,
.test_runner = options.test_runner,
- .link_libc = options.link_libc,
- .single_threaded = options.single_threaded,
.use_llvm = options.use_llvm,
.use_lld = options.use_lld,
.zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
- .main_mod_path = options.main_mod_path orelse options.main_pkg_path,
});
}
@@ -833,9 +789,10 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile {
const obj_step = Step.Compile.create(b, .{
.name = options.name,
.kind = .obj,
- .root_source_file = null,
- .target = options.target,
- .optimize = options.optimize,
+ .root_module = .{
+ .target = options.target,
+ .optimize = options.optimize,
+ },
.max_rss = options.max_rss,
.zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir,
});
@@ -846,41 +803,17 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile {
/// This function creates a module and adds it to the package's module set, making
/// it available to other packages which depend on this one.
/// `createModule` can be used instead to create a private module.
-pub fn addModule(b: *Build, name: []const u8, options: CreateModuleOptions) *Module {
- const module = b.createModule(options);
+pub fn addModule(b: *Build, name: []const u8, options: Module.CreateOptions) *Module {
+ const module = Module.create(b, options);
b.modules.put(b.dupe(name), module) catch @panic("OOM");
return module;
}
-pub const ModuleDependency = struct {
- name: []const u8,
- module: *Module,
-};
-
-pub const CreateModuleOptions = struct {
- source_file: LazyPath,
- dependencies: []const ModuleDependency = &.{},
-};
-
/// This function creates a private module, to be used by the current package,
/// but not exposed to other packages depending on this one.
/// `addModule` can be used instead to create a public module.
-pub fn createModule(b: *Build, options: CreateModuleOptions) *Module {
- const module = b.allocator.create(Module) catch @panic("OOM");
- module.* = .{
- .builder = b,
- .source_file = options.source_file.dupe(b),
- .dependencies = moduleDependenciesToArrayHashMap(b.allocator, options.dependencies),
- };
- return module;
-}
-
-fn moduleDependenciesToArrayHashMap(arena: Allocator, deps: []const ModuleDependency) std.StringArrayHashMap(*Module) {
- var result = std.StringArrayHashMap(*Module).init(arena);
- for (deps) |dep| {
- result.put(dep.name, dep.module) catch @panic("OOM");
- }
- return result;
+pub fn createModule(b: *Build, options: Module.CreateOptions) *Module {
+ return Module.create(b, options);
}
/// 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 {
}
}
-pub const Module = struct {
- builder: *Build,
- /// This could either be a generated file, in which case the module
- /// contains exactly one file, or it could be a path to the root source
- /// file of directory of files which constitute the module.
- source_file: LazyPath,
- dependencies: std.StringArrayHashMap(*Module),
-};
-
/// A file that is generated by a build step.
/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic.
pub const GeneratedFile = struct {