2023-01-31 00:19:51 -07:00
const builtin = @import ( " builtin " ) ;
2025-10-06 18:34:51 -07:00
const std = @import ( " std.zig " ) ;
const Io = std . Io ;
2023-01-31 00:19:51 -07:00
const fs = std . fs ;
const mem = std . mem ;
const debug = std . debug ;
const panic = std . debug . panic ;
const assert = debug . assert ;
const log = std . log ;
const StringHashMap = std . StringHashMap ;
const Allocator = mem . Allocator ;
2023-12-04 12:35:04 -07:00
const Target = std . Target ;
2023-01-31 00:19:51 -07:00
const process = std . process ;
const EnvMap = std . process . EnvMap ;
2024-05-04 14:29:17 -04:00
const File = fs . File ;
2023-01-31 00:19:51 -07:00
const Sha256 = std . crypto . hash . sha2 . Sha256 ;
const Build = @This ( ) ;
2025-07-31 21:54:07 -07:00
const ArrayList = std . ArrayList ;
2023-01-31 00:19:51 -07:00
2023-02-05 19:39:04 -07:00
pub const Cache = @import ( " Build/Cache.zig " ) ;
2023-01-31 00:19:51 -07:00
pub const Step = @import ( " Build/Step.zig " ) ;
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
2023-11-28 22:47:34 -07:00
pub const Module = @import ( " Build/Module.zig " ) ;
2024-07-09 18:17:27 -07:00
pub const Watch = @import ( " Build/Watch.zig " ) ;
2024-07-23 21:17:14 -07:00
pub const Fuzz = @import ( " Build/Fuzz.zig " ) ;
build system: replace fuzzing UI with build UI, add time report
This commit replaces the "fuzzer" UI, previously accessed with the
`--fuzz` and `--port` flags, with a more interesting web UI which allows
more interactions with the Zig build system. Most notably, it allows
accessing the data emitted by a new "time report" system, which allows
users to see which parts of Zig programs take the longest to compile.
The option to expose the web UI is `--webui`. By default, it will listen
on `[::1]` on a random port, but any IPv6 or IPv4 address can be
specified with e.g. `--webui=[::1]:8000` or `--webui=127.0.0.1:8000`.
The options `--fuzz` and `--time-report` both imply `--webui` if not
given. Currently, `--webui` is incompatible with `--watch`; specifying
both will cause `zig build` to exit with a fatal error.
When the web UI is enabled, the build runner spawns the web server as
soon as the configure phase completes. The frontend code consists of one
HTML file, one JavaScript file, two CSS files, and a few Zig source
files which are built into a WASM blob on-demand -- this is all very
similar to the old fuzzer UI. Also inherited from the fuzzer UI is that
the build system communicates with web clients over a WebSocket
connection.
When the build finishes, if `--webui` was passed (i.e. if the web server
is running), the build runner does not terminate; it continues running
to serve web requests, allowing interactive control of the build system.
In the web interface is an overall "status" indicating whether a build
is currently running, and also a list of all steps in this build. There
are visual indicators (colors and spinners) for in-progress, succeeded,
and failed steps. There is a "Rebuild" button which will cause the build
system to reset the state of every step (note that this does not affect
caching) and evaluate the step graph again.
If `--time-report` is passed to `zig build`, a new section of the
interface becomes visible, which associates every build step with a
"time report". For most steps, this is just a simple "time taken" value.
However, for `Compile` steps, the compiler communicates with the build
system to provide it with much more interesting information: time taken
for various pipeline phases, with a per-declaration and per-file
breakdown, sorted by slowest declarations/files first. This feature is
still in its early stages: the data can be a little tricky to
understand, and there is no way to, for instance, sort by different
properties, or filter to certain files. However, it has already given us
some interesting statistics, and can be useful for spotting, for
instance, particularly complex and slow compile-time logic.
Additionally, if a compilation uses LLVM, its time report includes the
"LLVM pass timing" information, which was previously accessible with the
(now removed) `-ftime-report` compiler flag.
To make time reports more useful, ZIR and compilation caches are ignored
by the Zig compiler when they are enabled -- in other words, `Compile`
steps *always* run, even if their result should be cached. This means
that the flag can be used to analyze a project's compile time without
having to repeatedly clear cache directory, for instance. However, when
using `-fincremental`, updates other than the first will only show you
the statistics for what changed on that particular update. Notably, this
gives us a fairly nice way to see exactly which declarations were
re-analyzed by an incremental update.
If `--fuzz` is passed to `zig build`, another section of the web
interface becomes visible, this time exposing the fuzzer. This is quite
similar to the fuzzer UI this commit replaces, with only a few cosmetic
tweaks. The interface is closer than before to supporting multiple fuzz
steps at a time (in line with the overall strategy for this build UI,
the goal will be for all of the fuzz steps to be accessible in the same
interface), but still doesn't actually support it. The fuzzer UI looks
quite different under the hood: as a result, various bugs are fixed,
although other bugs remain. For instance, viewing the source code of any
file other than the root of the main module is completely broken (as on
master) due to some bogus file-to-module assignment logic in the fuzzer
UI.
Implementation notes:
* The `lib/build-web/` directory holds the client side of the web UI.
* The general server logic is in `std.Build.WebServer`.
* Fuzzing-specific logic is in `std.Build.Fuzz`.
* `std.Build.abi` is the new home of `std.Build.Fuzz.abi`, since it now
relates to the build system web UI in general.
* The build runner now has an **actual** general-purpose allocator,
because thanks to `--watch` and `--webui`, the process can be
arbitrarily long-lived. The gpa is `std.heap.DebugAllocator`, but the
arena remains backed by `std.heap.page_allocator` for efficiency. I
fixed several crashes caused by conflation of `gpa` and `arena` in the
build runner and `std.Build`, but there may still be some I have
missed.
* The I/O logic in `std.Build.WebServer` is pretty gnarly; there are a
*lot* of threads involved. I anticipate this situation improving
significantly once the `std.Io` interface (with concurrency support)
is introduced.
2025-07-10 09:18:10 +01:00
pub const WebServer = @import ( " Build/WebServer.zig " ) ;
pub const abi = @import ( " Build/abi.zig " ) ;
2023-01-31 00:19:51 -07:00
2024-02-01 15:44:44 -07:00
/// Shared state among all Build instances.
graph : * Graph ,
2023-01-31 00:19:51 -07:00
install_tls : TopLevelStep ,
uninstall_tls : TopLevelStep ,
allocator : Allocator ,
user_input_options : UserInputOptionsMap ,
available_options_map : AvailableOptionsMap ,
2025-07-31 21:54:07 -07:00
available_options_list : std . array_list . Managed ( AvailableOption ) ,
2023-01-31 00:19:51 -07:00
verbose : bool ,
verbose_link : bool ,
verbose_cc : bool ,
verbose_air : bool ,
2023-03-16 01:32:43 -04:00
verbose_llvm_ir : ? [ ] const u8 ,
verbose_llvm_bc : ? [ ] const u8 ,
2023-01-31 00:19:51 -07:00
verbose_cimport : bool ,
verbose_llvm_cpu_features : bool ,
reference_trace : ? u32 = null ,
invalid_user_input : bool ,
default_step : * Step ,
2023-02-13 13:10:20 -07:00
top_level_steps : std . StringArrayHashMapUnmanaged ( * TopLevelStep ) ,
2023-01-31 00:19:51 -07:00
install_prefix : [ ] const u8 ,
dest_dir : ? [ ] const u8 ,
lib_dir : [ ] const u8 ,
exe_dir : [ ] const u8 ,
h_dir : [ ] const u8 ,
install_path : [ ] const u8 ,
sysroot : ? [ ] const u8 = null ,
2025-07-31 21:54:07 -07:00
search_prefixes : ArrayList ( [ ] const u8 ) ,
2023-01-31 00:19:51 -07:00
libc_file : ? [ ] const u8 = null ,
/// Path to the directory containing build.zig.
2023-02-09 10:01:01 -07:00
build_root : Cache . Directory ,
cache_root : Cache . Directory ,
2023-01-31 00:19:51 -07:00
pkg_config_pkg_list : ? ( PkgConfigError ! [ ] const PkgConfigPkg ) = null ,
2024-06-20 12:12:20 +01:00
args : ? [ ] const [ ] const u8 = null ,
2023-01-31 00:19:51 -07:00
debug_log_scopes : [ ] const [ ] const u8 = & . { } ,
debug_compile_errors : bool = false ,
2025-05-24 22:25:17 +01:00
debug_incremental : bool = false ,
2023-03-03 20:39:40 -07:00
debug_pkg_config : bool = false ,
2023-08-11 12:19:56 +02:00
/// Number of stack frames captured when a `StackTrace` is recorded for debug purposes,
/// in particular at `Step` creation.
/// Set to 0 to disable stack collection.
debug_stack_frames_count : u8 = 8 ,
2023-01-31 00:19:51 -07:00
2024-02-01 17:40:36 -07:00
/// Experimental. Use system Darling installation to run cross compiled macOS build artifacts.
enable_darling : bool = false ,
/// Use system QEMU installation to run cross compiled foreign architecture build artifacts.
enable_qemu : bool = false ,
/// Darwin. Use Rosetta to run x86_64 macOS build artifacts on arm64 macOS.
enable_rosetta : bool = false ,
/// Use system Wasmtime installation to run cross compiled wasm/wasi build artifacts.
enable_wasmtime : bool = false ,
/// Use system Wine installation to run cross compiled Windows build artifacts.
enable_wine : bool = false ,
/// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc,
/// this will be the directory $glibc-build-dir/install/glibcs
/// Given the example of the aarch64 target, this is the directory
/// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`.
2025-05-06 01:52:47 +02:00
/// Also works for dynamic musl.
libc_runtimes_dir : ? [ ] const u8 = null ,
2024-02-01 17:40:36 -07:00
2023-01-31 00:19:51 -07:00
dep_prefix : [ ] const u8 = " " ,
2023-02-03 17:22:31 -07:00
modules : std . StringArrayHashMap ( * Module ) ,
2023-10-22 16:10:01 +02:00
named_writefiles : std . StringArrayHashMap ( * Step . WriteFile ) ,
2024-09-11 09:06:54 +01:00
named_lazy_paths : std . StringArrayHashMap ( LazyPath ) ,
2024-02-18 19:56:34 +01:00
/// The hash of this instance's package. `""` means that this is the root package.
pkg_hash : [ ] const u8 ,
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
/// A mapping from dependency names to package hashes.
available_deps : AvailableDeps ,
2024-02-01 20:17:07 -07:00
release_mode : ReleaseMode ,
2025-01-17 20:53:30 +01:00
build_id : ? std . zig . BuildId = null ,
2024-02-01 20:17:07 -07:00
pub const ReleaseMode = enum {
off ,
any ,
fast ,
safe ,
small ,
} ;
2024-02-01 15:44:44 -07:00
/// Shared state among all Build instances.
/// Settings that are here rather than in Build are not configurable per-package.
pub const Graph = struct {
2025-10-06 18:34:51 -07:00
io : Io ,
2024-02-01 15:44:44 -07:00
arena : Allocator ,
2024-09-02 22:32:21 +01:00
system_library_options : std . StringArrayHashMapUnmanaged ( SystemLibraryMode ) = . empty ,
2024-02-01 15:44:44 -07:00
system_package_mode : bool = false ,
2024-07-24 17:41:44 -07:00
debug_compiler_runtime_libs : bool = false ,
2024-02-01 15:44:44 -07:00
cache : Cache ,
zig_exe : [ : 0 ] const u8 ,
env_map : EnvMap ,
global_cache_root : Cache . Directory ,
2024-07-11 16:26:04 -07:00
zig_lib_directory : Cache . Directory ,
2024-09-02 22:32:21 +01:00
needed_lazy_dependencies : std . StringArrayHashMapUnmanaged ( void ) = . empty ,
std.Build: revert --host-target, --host-cpu, --host-dynamic-linker
This is a partial revert of 105db13536b4dc2affe130cb8d2eee6c97c89bcd.
As we learned from Void Linux packaging, these options are not actually
helpful since the distribution package manager may very well want to
cross-compile the packages that it is building.
So, let's not overcomplicate things. There are already the standard
options: -Dtarget, -Dcpu, and -Ddynamic-linker.
These options are generally provided when the project generates machine
code artifacts, however, there may be a project that does no such thing,
in which case it makes sense for these options to be missing. The Zig
Build System is a general-purpose build system, after all.
2024-04-17 17:57:03 -07:00
/// Information about the native target. Computed before build() is invoked.
host : ResolvedTarget ,
2024-07-14 22:27:51 -07:00
incremental : ? bool = null ,
2024-07-22 16:03:11 -07:00
random_seed : u32 = 0 ,
2024-09-27 09:44:44 -06:00
dependency_cache : InitializedDepMap = . empty ,
2024-10-14 22:57:12 -07:00
allow_so_scripts : ? bool = null ,
build system: replace fuzzing UI with build UI, add time report
This commit replaces the "fuzzer" UI, previously accessed with the
`--fuzz` and `--port` flags, with a more interesting web UI which allows
more interactions with the Zig build system. Most notably, it allows
accessing the data emitted by a new "time report" system, which allows
users to see which parts of Zig programs take the longest to compile.
The option to expose the web UI is `--webui`. By default, it will listen
on `[::1]` on a random port, but any IPv6 or IPv4 address can be
specified with e.g. `--webui=[::1]:8000` or `--webui=127.0.0.1:8000`.
The options `--fuzz` and `--time-report` both imply `--webui` if not
given. Currently, `--webui` is incompatible with `--watch`; specifying
both will cause `zig build` to exit with a fatal error.
When the web UI is enabled, the build runner spawns the web server as
soon as the configure phase completes. The frontend code consists of one
HTML file, one JavaScript file, two CSS files, and a few Zig source
files which are built into a WASM blob on-demand -- this is all very
similar to the old fuzzer UI. Also inherited from the fuzzer UI is that
the build system communicates with web clients over a WebSocket
connection.
When the build finishes, if `--webui` was passed (i.e. if the web server
is running), the build runner does not terminate; it continues running
to serve web requests, allowing interactive control of the build system.
In the web interface is an overall "status" indicating whether a build
is currently running, and also a list of all steps in this build. There
are visual indicators (colors and spinners) for in-progress, succeeded,
and failed steps. There is a "Rebuild" button which will cause the build
system to reset the state of every step (note that this does not affect
caching) and evaluate the step graph again.
If `--time-report` is passed to `zig build`, a new section of the
interface becomes visible, which associates every build step with a
"time report". For most steps, this is just a simple "time taken" value.
However, for `Compile` steps, the compiler communicates with the build
system to provide it with much more interesting information: time taken
for various pipeline phases, with a per-declaration and per-file
breakdown, sorted by slowest declarations/files first. This feature is
still in its early stages: the data can be a little tricky to
understand, and there is no way to, for instance, sort by different
properties, or filter to certain files. However, it has already given us
some interesting statistics, and can be useful for spotting, for
instance, particularly complex and slow compile-time logic.
Additionally, if a compilation uses LLVM, its time report includes the
"LLVM pass timing" information, which was previously accessible with the
(now removed) `-ftime-report` compiler flag.
To make time reports more useful, ZIR and compilation caches are ignored
by the Zig compiler when they are enabled -- in other words, `Compile`
steps *always* run, even if their result should be cached. This means
that the flag can be used to analyze a project's compile time without
having to repeatedly clear cache directory, for instance. However, when
using `-fincremental`, updates other than the first will only show you
the statistics for what changed on that particular update. Notably, this
gives us a fairly nice way to see exactly which declarations were
re-analyzed by an incremental update.
If `--fuzz` is passed to `zig build`, another section of the web
interface becomes visible, this time exposing the fuzzer. This is quite
similar to the fuzzer UI this commit replaces, with only a few cosmetic
tweaks. The interface is closer than before to supporting multiple fuzz
steps at a time (in line with the overall strategy for this build UI,
the goal will be for all of the fuzz steps to be accessible in the same
interface), but still doesn't actually support it. The fuzzer UI looks
quite different under the hood: as a result, various bugs are fixed,
although other bugs remain. For instance, viewing the source code of any
file other than the root of the main module is completely broken (as on
master) due to some bogus file-to-module assignment logic in the fuzzer
UI.
Implementation notes:
* The `lib/build-web/` directory holds the client side of the web UI.
* The general server logic is in `std.Build.WebServer`.
* Fuzzing-specific logic is in `std.Build.Fuzz`.
* `std.Build.abi` is the new home of `std.Build.Fuzz.abi`, since it now
relates to the build system web UI in general.
* The build runner now has an **actual** general-purpose allocator,
because thanks to `--watch` and `--webui`, the process can be
arbitrarily long-lived. The gpa is `std.heap.DebugAllocator`, but the
arena remains backed by `std.heap.page_allocator` for efficiency. I
fixed several crashes caused by conflation of `gpa` and `arena` in the
build runner and `std.Build`, but there may still be some I have
missed.
* The I/O logic in `std.Build.WebServer` is pretty gnarly; there are a
*lot* of threads involved. I anticipate this situation improving
significantly once the `std.Io` interface (with concurrency support)
is introduced.
2025-07-10 09:18:10 +01:00
time_report : bool ,
2024-02-01 15:44:44 -07:00
} ;
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
const AvailableDeps = [ ] const struct { [ ] const u8 , [ ] const u8 } ;
2023-08-10 15:32:55 -07:00
2024-02-01 15:44:44 -07:00
const SystemLibraryMode = enum {
2024-01-31 22:02:27 -07:00
/// User asked for the library to be disabled.
/// The build runner has not confirmed whether the setting is recognized yet.
user_disabled ,
/// User asked for the library to be enabled.
/// The build runner has not confirmed whether the setting is recognized yet.
user_enabled ,
/// The build runner has confirmed that this setting is recognized.
/// System integration with this library has been resolved to off.
declared_disabled ,
/// The build runner has confirmed that this setting is recognized.
/// System integration with this library has been resolved to on.
declared_enabled ,
} ;
2024-09-27 09:44:44 -06:00
const InitializedDepMap = std . HashMapUnmanaged ( InitializedDepKey , * Dependency , InitializedDepContext , std . hash_map . default_max_load_percentage ) ;
2023-08-10 15:32:55 -07:00
const InitializedDepKey = struct {
build_root_string : [ ] const u8 ,
user_input_options : UserInputOptionsMap ,
} ;
const InitializedDepContext = struct {
allocator : Allocator ,
2024-05-04 14:29:17 -04:00
pub fn hash ( ctx : @This ( ) , k : InitializedDepKey ) u64 {
2023-08-10 15:32:55 -07:00
var hasher = std . hash . Wyhash . init ( 0 ) ;
hasher . update ( k . build_root_string ) ;
2024-05-04 14:29:17 -04:00
hashUserInputOptionsMap ( ctx . allocator , k . user_input_options , & hasher ) ;
2023-08-10 15:32:55 -07:00
return hasher . final ( ) ;
}
2024-05-04 14:29:17 -04:00
pub fn eql ( _ : @This ( ) , lhs : InitializedDepKey , rhs : InitializedDepKey ) bool {
2023-08-10 15:32:55 -07:00
if ( ! std . mem . eql ( u8 , lhs . build_root_string , rhs . build_root_string ) )
return false ;
if ( lhs . user_input_options . count ( ) != rhs . user_input_options . count ( ) )
return false ;
var it = lhs . user_input_options . iterator ( ) ;
while ( it . next ( ) ) | lhs_entry | {
const rhs_value = rhs . user_input_options . get ( lhs_entry . key_ptr .* ) orelse return false ;
if ( ! userValuesAreSame ( lhs_entry . value_ptr .* . value , rhs_value . value ) )
return false ;
}
return true ;
}
} ;
2023-02-03 17:22:31 -07:00
2023-10-19 22:36:11 +02:00
pub const RunError = error {
2023-01-31 00:19:51 -07:00
ReadFailure ,
ExitCodeFailure ,
ProcessTerminated ,
ExecNotSupported ,
2024-05-23 11:25:41 -07:00
} || std . process . Child . SpawnError ;
2023-01-31 00:19:51 -07:00
pub const PkgConfigError = error {
PkgConfigCrashed ,
PkgConfigFailed ,
PkgConfigNotInstalled ,
PkgConfigInvalidOutput ,
} ;
pub const PkgConfigPkg = struct {
name : [ ] const u8 ,
desc : [ ] const u8 ,
} ;
const UserInputOptionsMap = StringHashMap ( UserInputOption ) ;
const AvailableOptionsMap = StringHashMap ( AvailableOption ) ;
const AvailableOption = struct {
name : [ ] const u8 ,
type_id : TypeId ,
description : [ ] const u8 ,
2024-06-06 06:02:42 +02:00
/// If the `type_id` is `enum` or `enum_list` this provides the list of enum options
2023-01-31 00:19:51 -07:00
enum_options : ? [ ] const [ ] const u8 ,
} ;
const UserInputOption = struct {
name : [ ] const u8 ,
value : UserValue ,
used : bool ,
} ;
const UserValue = union ( enum ) {
flag : void ,
scalar : [ ] const u8 ,
2025-07-31 21:54:07 -07:00
list : std . array_list . Managed ( [ ] const u8 ) ,
2023-01-31 00:19:51 -07:00
map : StringHashMap ( * const UserValue ) ,
2024-10-05 00:58:48 +02:00
lazy_path : LazyPath ,
2025-07-31 21:54:07 -07:00
lazy_path_list : std . array_list . Managed ( LazyPath ) ,
2023-01-31 00:19:51 -07:00
} ;
const TypeId = enum {
bool ,
int ,
float ,
@" enum " ,
2024-06-06 06:02:42 +02:00
enum_list ,
2023-01-31 00:19:51 -07:00
string ,
list ,
2023-05-16 20:00:47 -07:00
build_id ,
2024-10-05 00:58:48 +02:00
lazy_path ,
lazy_path_list ,
2023-01-31 00:19:51 -07:00
} ;
const TopLevelStep = struct {
2024-05-04 14:29:17 -04:00
pub const base_id : Step . Id = . top_level ;
2023-01-31 00:19:51 -07:00
step : Step ,
description : [ ] const u8 ,
} ;
pub const DirList = struct {
lib_dir : ? [ ] const u8 = null ,
exe_dir : ? [ ] const u8 = null ,
include_dir : ? [ ] const u8 = null ,
} ;
pub fn create (
2024-02-01 15:44:44 -07:00
graph : * Graph ,
2023-02-09 10:01:01 -07:00
build_root : Cache . Directory ,
cache_root : Cache . Directory ,
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
available_deps : AvailableDeps ,
2024-12-26 00:17:56 +05:00
) error { OutOfMemory } ! * Build {
2024-02-01 15:44:44 -07:00
const arena = graph . arena ;
2023-01-31 00:19:51 -07:00
2024-05-04 14:29:17 -04:00
const b = try arena . create ( Build ) ;
b .* = . {
2024-02-01 15:44:44 -07:00
. graph = graph ,
2023-01-31 00:19:51 -07:00
. build_root = build_root ,
2023-02-09 10:01:01 -07:00
. cache_root = cache_root ,
2023-01-31 00:19:51 -07:00
. verbose = false ,
. verbose_link = false ,
. verbose_cc = false ,
. verbose_air = false ,
2023-03-16 01:32:43 -04:00
. verbose_llvm_ir = null ,
. verbose_llvm_bc = null ,
2023-01-31 00:19:51 -07:00
. verbose_cimport = false ,
. verbose_llvm_cpu_features = false ,
. invalid_user_input = false ,
2024-02-01 15:44:44 -07:00
. allocator = arena ,
. user_input_options = UserInputOptionsMap . init ( arena ) ,
. available_options_map = AvailableOptionsMap . init ( arena ) ,
2025-07-31 21:54:07 -07:00
. available_options_list = std . array_list . Managed ( AvailableOption ) . init ( arena ) ,
2023-02-13 13:10:20 -07:00
. top_level_steps = . { } ,
2023-01-31 00:19:51 -07:00
. default_step = undefined ,
2025-07-31 21:54:07 -07:00
. search_prefixes = . empty ,
2023-01-31 00:19:51 -07:00
. install_prefix = undefined ,
. lib_dir = undefined ,
. exe_dir = undefined ,
. h_dir = undefined ,
2024-02-01 15:44:44 -07:00
. dest_dir = graph . env_map . get ( " DESTDIR " ) ,
2023-02-14 12:47:45 -07:00
. install_tls = . {
2025-07-02 11:16:20 -07:00
. step = . init ( . {
2024-05-04 14:29:17 -04:00
. id = TopLevelStep . base_id ,
2023-02-14 12:47:45 -07:00
. name = " install " ,
2024-05-04 14:29:17 -04:00
. owner = b ,
2023-02-14 12:47:45 -07:00
} ) ,
2023-01-31 00:19:51 -07:00
. description = " Copy build artifacts to prefix path " ,
} ,
2023-02-14 12:47:45 -07:00
. uninstall_tls = . {
2025-07-02 11:16:20 -07:00
. step = . init ( . {
2024-05-04 14:29:17 -04:00
. id = TopLevelStep . base_id ,
2023-02-14 12:47:45 -07:00
. name = " uninstall " ,
2024-05-04 14:29:17 -04:00
. owner = b ,
2023-02-14 12:47:45 -07:00
. makeFn = makeUninstall ,
} ) ,
2023-01-31 00:19:51 -07:00
. description = " Remove build artifacts from prefix path " ,
} ,
. install_path = undefined ,
. args = null ,
2024-09-11 09:06:54 +01:00
. modules = . init ( arena ) ,
. named_writefiles = . init ( arena ) ,
. named_lazy_paths = . init ( arena ) ,
2024-02-18 19:56:34 +01:00
. pkg_hash = " " ,
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
. available_deps = available_deps ,
2024-02-01 20:17:07 -07:00
. release_mode = . off ,
2023-01-31 00:19:51 -07:00
} ;
2024-05-04 14:29:17 -04:00
try b . top_level_steps . put ( arena , b . install_tls . step . name , & b . install_tls ) ;
try b . top_level_steps . put ( arena , b . uninstall_tls . step . name , & b . uninstall_tls ) ;
b . default_step = & b . install_tls . step ;
return b ;
2023-01-31 00:19:51 -07:00
}
fn createChild (
parent : * Build ,
dep_name : [ ] const u8 ,
2023-02-09 10:01:01 -07:00
build_root : Cache . Directory ,
2024-02-18 19:56:34 +01:00
pkg_hash : [ ] const u8 ,
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
pkg_deps : AvailableDeps ,
2023-08-10 15:32:55 -07:00
user_input_options : UserInputOptionsMap ,
2024-12-26 00:17:56 +05:00
) error { OutOfMemory } ! * Build {
2024-02-18 19:56:34 +01:00
const child = try createChildOnly ( parent , dep_name , build_root , pkg_hash , pkg_deps , user_input_options ) ;
2023-08-10 15:32:55 -07:00
try determineAndApplyInstallPrefix ( child ) ;
2023-01-31 00:19:51 -07:00
return child ;
}
2024-01-31 22:02:27 -07:00
fn createChildOnly (
parent : * Build ,
dep_name : [ ] const u8 ,
build_root : Cache . Directory ,
2024-02-18 19:56:34 +01:00
pkg_hash : [ ] const u8 ,
2024-01-31 22:02:27 -07:00
pkg_deps : AvailableDeps ,
user_input_options : UserInputOptionsMap ,
2024-12-26 00:17:56 +05:00
) error { OutOfMemory } ! * Build {
2023-01-31 00:19:51 -07:00
const allocator = parent . allocator ;
const child = try allocator . create ( Build ) ;
child .* = . {
2024-02-01 15:44:44 -07:00
. graph = parent . graph ,
2023-01-31 00:19:51 -07:00
. allocator = allocator ,
. install_tls = . {
2025-07-02 11:16:20 -07:00
. step = . init ( . {
2024-05-04 14:29:17 -04:00
. id = TopLevelStep . base_id ,
2023-02-14 12:47:45 -07:00
. name = " install " ,
zig build: many enhancements related to parallel building
Rework std.Build.Step to have an `owner: *Build` field. This
simplified the implementation of installation steps, as well as provided
some much-needed common API for the new parallelized build system.
--verbose is now defined very concretely: it prints to stderr just
before spawning a child process.
Child process execution is updated to conform to the new
parallel-friendly make() function semantics.
DRY up the failWithCacheError handling code. It now integrates properly
with the step graph instead of incorrectly dumping to stderr and calling
process exit.
In the main CLI, fix `zig fmt` crash when there are no errors and stdin
is used.
Deleted steps:
* EmulatableRunStep - this entire thing can be removed in favor of a
flag added to std.Build.RunStep called `skip_foreign_checks`.
* LogStep - this doesn't really fit with a multi-threaded build runner
and is effectively superseded by the new build summary output.
build runner:
* add -fsummary and -fno-summary to override the default behavior,
which is to print a summary if any of the build steps fail.
* print the dep prefix when emitting error messages for steps.
std.Build.FmtStep:
* This step now supports exclude paths as well as a check flag.
* The check flag decides between two modes, modify mode, and check
mode. These can be used to update source files in place, or to fail
the build, respectively.
Zig's own build.zig:
* The `test-fmt` step will do all the `zig fmt` checking that we expect
to be done. Since the `test` step depends on this one, we can simply
remove the explicit call to `zig fmt` in the CI.
* The new `fmt` step will actually perform `zig fmt` and update source
files in place.
std.Build.RunStep:
* expose max_stdio_size is a field (previously an unchangeable
hard-coded value).
* rework the API. Instead of configuring each stream independently,
there is a `stdio` field where you can choose between
`infer_from_args`, `inherit`, or `check`. These determine whether the
RunStep is considered to have side-effects or not. The previous
field, `condition` is gone.
* when stdio mode is set to `check` there is a slice of any number of
checks to make, which include things like exit code, stderr matching,
or stdout matching.
* remove the ill-defined `print` field.
* when adding an output arg, it takes the opportunity to give itself a
better name.
* The flag `skip_foreign_checks` is added. If this is true, a RunStep
which is configured to check the output of the executed binary will
not fail the build if the binary cannot be executed due to being for
a foreign binary to the host system which is running the build graph.
Command-line arguments such as -fqemu and -fwasmtime may affect
whether a binary is detected as foreign, as well as system
configuration such as Rosetta (macOS) and binfmt_misc (Linux).
- This makes EmulatableRunStep no longer needed.
* Fix the child process handling to properly integrate with the new
bulid API and to avoid deadlocks in stdout/stderr streams by polling
if necessary.
std.Build.RemoveDirStep now uses the open build_root directory handle
instead of an absolute path.
2023-03-01 22:56:37 -07:00
. owner = child ,
2023-02-14 12:47:45 -07:00
} ) ,
2023-01-31 00:19:51 -07:00
. description = " Copy build artifacts to prefix path " ,
} ,
. uninstall_tls = . {
2025-07-02 11:16:20 -07:00
. step = . init ( . {
2024-05-04 14:29:17 -04:00
. id = TopLevelStep . base_id ,
2023-02-14 12:47:45 -07:00
. name = " uninstall " ,
zig build: many enhancements related to parallel building
Rework std.Build.Step to have an `owner: *Build` field. This
simplified the implementation of installation steps, as well as provided
some much-needed common API for the new parallelized build system.
--verbose is now defined very concretely: it prints to stderr just
before spawning a child process.
Child process execution is updated to conform to the new
parallel-friendly make() function semantics.
DRY up the failWithCacheError handling code. It now integrates properly
with the step graph instead of incorrectly dumping to stderr and calling
process exit.
In the main CLI, fix `zig fmt` crash when there are no errors and stdin
is used.
Deleted steps:
* EmulatableRunStep - this entire thing can be removed in favor of a
flag added to std.Build.RunStep called `skip_foreign_checks`.
* LogStep - this doesn't really fit with a multi-threaded build runner
and is effectively superseded by the new build summary output.
build runner:
* add -fsummary and -fno-summary to override the default behavior,
which is to print a summary if any of the build steps fail.
* print the dep prefix when emitting error messages for steps.
std.Build.FmtStep:
* This step now supports exclude paths as well as a check flag.
* The check flag decides between two modes, modify mode, and check
mode. These can be used to update source files in place, or to fail
the build, respectively.
Zig's own build.zig:
* The `test-fmt` step will do all the `zig fmt` checking that we expect
to be done. Since the `test` step depends on this one, we can simply
remove the explicit call to `zig fmt` in the CI.
* The new `fmt` step will actually perform `zig fmt` and update source
files in place.
std.Build.RunStep:
* expose max_stdio_size is a field (previously an unchangeable
hard-coded value).
* rework the API. Instead of configuring each stream independently,
there is a `stdio` field where you can choose between
`infer_from_args`, `inherit`, or `check`. These determine whether the
RunStep is considered to have side-effects or not. The previous
field, `condition` is gone.
* when stdio mode is set to `check` there is a slice of any number of
checks to make, which include things like exit code, stderr matching,
or stdout matching.
* remove the ill-defined `print` field.
* when adding an output arg, it takes the opportunity to give itself a
better name.
* The flag `skip_foreign_checks` is added. If this is true, a RunStep
which is configured to check the output of the executed binary will
not fail the build if the binary cannot be executed due to being for
a foreign binary to the host system which is running the build graph.
Command-line arguments such as -fqemu and -fwasmtime may affect
whether a binary is detected as foreign, as well as system
configuration such as Rosetta (macOS) and binfmt_misc (Linux).
- This makes EmulatableRunStep no longer needed.
* Fix the child process handling to properly integrate with the new
bulid API and to avoid deadlocks in stdout/stderr streams by polling
if necessary.
std.Build.RemoveDirStep now uses the open build_root directory handle
instead of an absolute path.
2023-03-01 22:56:37 -07:00
. owner = child ,
2023-02-14 12:47:45 -07:00
. makeFn = makeUninstall ,
} ) ,
2023-01-31 00:19:51 -07:00
. description = " Remove build artifacts from prefix path " ,
} ,
2023-08-10 15:32:55 -07:00
. user_input_options = user_input_options ,
2023-01-31 00:19:51 -07:00
. available_options_map = AvailableOptionsMap . init ( allocator ) ,
2025-07-31 21:54:07 -07:00
. available_options_list = std . array_list . Managed ( AvailableOption ) . init ( allocator ) ,
2023-01-31 00:19:51 -07:00
. verbose = parent . verbose ,
. verbose_link = parent . verbose_link ,
. verbose_cc = parent . verbose_cc ,
. verbose_air = parent . verbose_air ,
. verbose_llvm_ir = parent . verbose_llvm_ir ,
2023-03-16 01:32:43 -04:00
. verbose_llvm_bc = parent . verbose_llvm_bc ,
2023-01-31 00:19:51 -07:00
. verbose_cimport = parent . verbose_cimport ,
. verbose_llvm_cpu_features = parent . verbose_llvm_cpu_features ,
. reference_trace = parent . reference_trace ,
. invalid_user_input = false ,
. default_step = undefined ,
2023-02-13 13:10:20 -07:00
. top_level_steps = . { } ,
2023-01-31 00:19:51 -07:00
. install_prefix = undefined ,
. dest_dir = parent . dest_dir ,
. lib_dir = parent . lib_dir ,
. exe_dir = parent . exe_dir ,
. h_dir = parent . h_dir ,
. install_path = parent . install_path ,
. sysroot = parent . sysroot ,
2023-10-17 22:25:40 -07:00
. search_prefixes = parent . search_prefixes ,
2023-01-31 00:19:51 -07:00
. libc_file = parent . libc_file ,
. build_root = build_root ,
. cache_root = parent . cache_root ,
. debug_log_scopes = parent . debug_log_scopes ,
. debug_compile_errors = parent . debug_compile_errors ,
2025-05-24 22:25:17 +01:00
. debug_incremental = parent . debug_incremental ,
2023-03-03 20:39:40 -07:00
. debug_pkg_config = parent . debug_pkg_config ,
2024-02-01 17:40:36 -07:00
. enable_darling = parent . enable_darling ,
. enable_qemu = parent . enable_qemu ,
. enable_rosetta = parent . enable_rosetta ,
. enable_wasmtime = parent . enable_wasmtime ,
. enable_wine = parent . enable_wine ,
2025-05-06 01:52:47 +02:00
. libc_runtimes_dir = parent . libc_runtimes_dir ,
2023-01-31 00:19:51 -07:00
. dep_prefix = parent . fmt ( " {s}{s}. " , . { parent . dep_prefix , dep_name } ) ,
2024-09-11 09:06:54 +01:00
. modules = . init ( allocator ) ,
. named_writefiles = . init ( allocator ) ,
. named_lazy_paths = . init ( allocator ) ,
2024-02-18 19:56:34 +01:00
. pkg_hash = pkg_hash ,
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
. available_deps = pkg_deps ,
2024-02-01 20:17:07 -07:00
. release_mode = parent . release_mode ,
2023-01-31 00:19:51 -07:00
} ;
2023-02-13 13:10:20 -07:00
try child . top_level_steps . put ( allocator , child . install_tls . step . name , & child . install_tls ) ;
try child . top_level_steps . put ( allocator , child . uninstall_tls . step . name , & child . uninstall_tls ) ;
2023-01-31 00:19:51 -07:00
child . default_step = & child . install_tls . step ;
return child ;
}
2025-03-23 22:45:38 +01:00
fn userInputOptionsFromArgs ( arena : Allocator , args : anytype ) UserInputOptionsMap {
var map = UserInputOptionsMap . init ( arena ) ;
2024-08-28 02:35:53 +01:00
inline for ( @typeInfo ( @TypeOf ( args ) ) . @" struct " . fields ) | field | {
2025-04-30 18:42:23 +03:30
if ( field . type == @TypeOf ( null ) ) continue ;
2025-03-23 22:45:38 +01:00
addUserInputOptionFromArg ( arena , & map , field , field . type , @field ( args , field . name ) ) ;
}
return map ;
}
fn addUserInputOptionFromArg (
arena : Allocator ,
map : * UserInputOptionsMap ,
field : std . builtin . Type . StructField ,
comptime T : type ,
/// If null, the value won't be added, but `T` will still be type-checked.
maybe_value : ? T ,
) void {
switch ( T ) {
Target . Query = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
. name = field . name ,
. value = . { . scalar = v . zigTriple ( arena ) catch @panic ( " OOM " ) } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
map . put ( " cpu " , . {
. name = " cpu " ,
. value = . { . scalar = v . serializeCpuAlloc ( arena ) catch @panic ( " OOM " ) } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
ResolvedTarget = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
. name = field . name ,
. value = . { . scalar = v . query . zigTriple ( arena ) catch @panic ( " OOM " ) } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
map . put ( " cpu " , . {
. name = " cpu " ,
. value = . { . scalar = v . query . serializeCpuAlloc ( arena ) catch @panic ( " OOM " ) } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
2025-03-24 14:25:47 +01:00
std . zig . BuildId = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
. name = field . name ,
. value = . { . scalar = std . fmt . allocPrint ( arena , " {f} " , . { v } ) catch @panic ( " OOM " ) } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
2025-03-23 22:45:38 +01:00
LazyPath = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
. name = field . name ,
. value = . { . lazy_path = v . dupeInner ( arena ) } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
[ ] const LazyPath = > return if ( maybe_value ) | v | {
2025-07-31 21:54:07 -07:00
var list = std . array_list . Managed ( LazyPath ) . initCapacity ( arena , v . len ) catch @panic ( " OOM " ) ;
2025-03-23 22:45:38 +01:00
for ( v ) | lp | list . appendAssumeCapacity ( lp . dupeInner ( arena ) ) ;
map . put ( field . name , . {
. name = field . name ,
. value = . { . lazy_path_list = list } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
[ ] const u8 = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
. name = field . name ,
2025-03-24 13:25:56 +01:00
. value = . { . scalar = arena . dupe ( u8 , v ) catch @panic ( " OOM " ) } ,
2025-03-23 22:45:38 +01:00
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
[ ] const [ ] const u8 = > return if ( maybe_value ) | v | {
2025-07-31 21:54:07 -07:00
var list = std . array_list . Managed ( [ ] const u8 ) . initCapacity ( arena , v . len ) catch @panic ( " OOM " ) ;
2025-03-24 13:25:56 +01:00
for ( v ) | s | list . appendAssumeCapacity ( arena . dupe ( u8 , s ) catch @panic ( " OOM " ) ) ;
2025-03-23 22:45:38 +01:00
map . put ( field . name , . {
. name = field . name ,
. value = . { . list = list } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
else = > switch ( @typeInfo ( T ) ) {
. bool = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
2024-10-05 00:58:48 +02:00
. name = field . name ,
2025-03-23 22:45:38 +01:00
. value = . { . scalar = if ( v ) " true " else " false " } ,
2024-10-05 00:58:48 +02:00
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
2025-03-23 22:45:38 +01:00
. @" enum " , . enum_literal = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
2024-10-05 00:58:48 +02:00
. name = field . name ,
2025-03-23 22:45:38 +01:00
. value = . { . scalar = @tagName ( v ) } ,
2024-10-05 00:58:48 +02:00
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
2025-03-23 22:45:38 +01:00
. comptime_int , . int = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
2023-01-31 00:19:51 -07:00
. name = field . name ,
2025-03-23 22:45:38 +01:00
. value = . { . scalar = std . fmt . allocPrint ( arena , " {d} " , . { v } ) catch @panic ( " OOM " ) } ,
2023-01-31 00:19:51 -07:00
. used = false ,
2023-08-10 15:32:55 -07:00
} ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
} ,
2025-03-23 22:45:38 +01:00
. comptime_float , . float = > return if ( maybe_value ) | v | {
map . put ( field . name , . {
2023-12-31 19:42:48 -08:00
. name = field . name ,
2025-03-24 13:22:08 +01:00
. value = . { . scalar = std . fmt . allocPrint ( arena , " {x} " , . { v } ) catch @panic ( " OOM " ) } ,
2023-12-31 19:42:48 -08:00
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
2025-03-24 00:01:28 +01:00
. pointer = > | ptr_info | switch ( ptr_info . size ) {
. one = > switch ( @typeInfo ( ptr_info . child ) ) {
. array = > | array_info | {
addUserInputOptionFromArg (
arena ,
map ,
field ,
2025-04-30 18:42:23 +03:30
@Pointer ( . slice , . { . @" const " = true } , array_info . child , null ) ,
2025-03-24 00:01:28 +01:00
maybe_value orelse null ,
) ;
return ;
} ,
else = > { } ,
} ,
2025-03-24 00:14:25 +01:00
. slice = > switch ( @typeInfo ( ptr_info . child ) ) {
. @" enum " = > return if ( maybe_value ) | v | {
2025-07-31 21:54:07 -07:00
var list = std . array_list . Managed ( [ ] const u8 ) . initCapacity ( arena , v . len ) catch @panic ( " OOM " ) ;
2025-03-24 00:14:25 +01:00
for ( v ) | tag | list . appendAssumeCapacity ( @tagName ( tag ) ) ;
map . put ( field . name , . {
. name = field . name ,
. value = . { . list = list } ,
. used = false ,
} ) catch @panic ( " OOM " ) ;
} ,
else = > {
addUserInputOptionFromArg (
arena ,
map ,
field ,
2025-04-30 18:42:23 +03:30
@Pointer ( ptr_info . size , . { . @" const " = true } , ptr_info . child , null ) ,
2025-03-24 00:14:25 +01:00
maybe_value orelse null ,
) ;
return ;
} ,
2025-03-24 00:01:28 +01:00
} ,
else = > { } ,
} ,
2025-03-23 22:45:38 +01:00
. null = > unreachable ,
. optional = > | info | switch ( @typeInfo ( info . child ) ) {
. optional = > { } ,
else = > {
addUserInputOptionFromArg (
arena ,
map ,
field ,
info . child ,
maybe_value orelse null ,
) ;
return ;
2024-07-04 10:39:17 +02:00
} ,
2023-01-31 00:19:51 -07:00
} ,
2025-03-23 22:45:38 +01:00
else = > { } ,
} ,
2023-01-31 00:19:51 -07:00
}
2025-03-23 22:45:38 +01:00
@compileError ( " option ' " ++ field . name ++ " ' has unsupported type: " ++ @typeName ( field . type ) ) ;
2023-08-10 15:32:55 -07:00
}
const OrderedUserValue = union ( enum ) {
flag : void ,
scalar : [ ] const u8 ,
2025-07-31 21:54:07 -07:00
list : std . array_list . Managed ( [ ] const u8 ) ,
map : std . array_list . Managed ( Pair ) ,
2024-10-05 00:58:48 +02:00
lazy_path : LazyPath ,
2025-07-31 21:54:07 -07:00
lazy_path_list : std . array_list . Managed ( LazyPath ) ,
2023-08-10 15:32:55 -07:00
const Pair = struct {
name : [ ] const u8 ,
value : OrderedUserValue ,
fn lessThan ( _ : void , lhs : Pair , rhs : Pair ) bool {
return std . ascii . lessThanIgnoreCase ( lhs . name , rhs . name ) ;
}
} ;
2024-05-04 14:29:17 -04:00
fn hash ( val : OrderedUserValue , hasher : * std . hash . Wyhash ) void {
2024-10-05 00:58:48 +02:00
hasher . update ( & std . mem . toBytes ( std . meta . activeTag ( val ) ) ) ;
2024-05-04 14:29:17 -04:00
switch ( val ) {
2023-08-10 15:32:55 -07:00
. flag = > { } ,
. scalar = > | scalar | hasher . update ( scalar ) ,
// lists are already ordered
. list = > | list | for ( list . items ) | list_entry |
hasher . update ( list_entry ) ,
. map = > | map | for ( map . items ) | map_entry | {
hasher . update ( map_entry . name ) ;
map_entry . value . hash ( hasher ) ;
} ,
2024-10-05 00:58:48 +02:00
. lazy_path = > | lp | hashLazyPath ( lp , hasher ) ,
. lazy_path_list = > | lp_list | for ( lp_list . items ) | lp | {
hashLazyPath ( lp , hasher ) ;
} ,
}
}
fn hashLazyPath ( lp : LazyPath , hasher : * std . hash . Wyhash ) void {
switch ( lp ) {
. src_path = > | sp | {
hasher . update ( sp . owner . pkg_hash ) ;
hasher . update ( sp . sub_path ) ;
} ,
. generated = > | gen | {
hasher . update ( gen . file . step . owner . pkg_hash ) ;
hasher . update ( std . mem . asBytes ( & gen . up ) ) ;
hasher . update ( gen . sub_path ) ;
} ,
. cwd_relative = > | rel_path | {
hasher . update ( rel_path ) ;
} ,
. dependency = > | dep | {
hasher . update ( dep . dependency . builder . pkg_hash ) ;
hasher . update ( dep . sub_path ) ;
} ,
2023-08-10 15:32:55 -07:00
}
}
2025-07-31 21:54:07 -07:00
fn mapFromUnordered ( allocator : Allocator , unordered : std . StringHashMap ( * const UserValue ) ) std . array_list . Managed ( Pair ) {
var ordered = std . array_list . Managed ( Pair ) . init ( allocator ) ;
2023-08-10 15:32:55 -07:00
var it = unordered . iterator ( ) ;
while ( it . next ( ) ) | entry | {
ordered . append ( . {
. name = entry . key_ptr .* ,
. value = OrderedUserValue . fromUnordered ( allocator , entry . value_ptr .* .* ) ,
} ) catch @panic ( " OOM " ) ;
}
std . mem . sortUnstable ( Pair , ordered . items , { } , Pair . lessThan ) ;
return ordered ;
}
fn fromUnordered ( allocator : Allocator , unordered : UserValue ) OrderedUserValue {
return switch ( unordered ) {
. flag = > . { . flag = { } } ,
. scalar = > | scalar | . { . scalar = scalar } ,
. list = > | list | . { . list = list } ,
. map = > | map | . { . map = OrderedUserValue . mapFromUnordered ( allocator , map ) } ,
2024-10-05 00:58:48 +02:00
. lazy_path = > | lp | . { . lazy_path = lp } ,
. lazy_path_list = > | list | . { . lazy_path_list = list } ,
2023-08-10 15:32:55 -07:00
} ;
}
} ;
const OrderedUserInputOption = struct {
name : [ ] const u8 ,
value : OrderedUserValue ,
used : bool ,
2024-05-04 14:29:17 -04:00
fn hash ( opt : OrderedUserInputOption , hasher : * std . hash . Wyhash ) void {
hasher . update ( opt . name ) ;
opt . value . hash ( hasher ) ;
2023-08-10 15:32:55 -07:00
}
fn fromUnordered ( allocator : Allocator , user_input_option : UserInputOption ) OrderedUserInputOption {
return OrderedUserInputOption {
. name = user_input_option . name ,
. used = user_input_option . used ,
. value = OrderedUserValue . fromUnordered ( allocator , user_input_option . value ) ,
} ;
}
fn lessThan ( _ : void , lhs : OrderedUserInputOption , rhs : OrderedUserInputOption ) bool {
return std . ascii . lessThanIgnoreCase ( lhs . name , rhs . name ) ;
}
} ;
// The hash should be consistent with the same values given a different order.
// This function takes a user input map, orders it, then hashes the contents.
fn hashUserInputOptionsMap ( allocator : Allocator , user_input_options : UserInputOptionsMap , hasher : * std . hash . Wyhash ) void {
2025-07-31 21:54:07 -07:00
var ordered = std . array_list . Managed ( OrderedUserInputOption ) . init ( allocator ) ;
2023-08-10 15:32:55 -07:00
var it = user_input_options . iterator ( ) ;
while ( it . next ( ) ) | entry |
ordered . append ( OrderedUserInputOption . fromUnordered ( allocator , entry . value_ptr .* ) ) catch @panic ( " OOM " ) ;
std . mem . sortUnstable ( OrderedUserInputOption , ordered . items , { } , OrderedUserInputOption . lessThan ) ;
// juice it
for ( ordered . items ) | user_option |
user_option . hash ( hasher ) ;
}
2024-12-26 00:17:56 +05:00
fn determineAndApplyInstallPrefix ( b : * Build ) error { OutOfMemory } ! void {
2023-03-09 21:16:53 -07:00
// Create an installation directory local to this package. This will be used when
// dependant packages require a standard prefix, such as include directories for C headers.
2024-02-01 15:44:44 -07:00
var hash = b . graph . cache . hash ;
2023-01-31 00:19:51 -07:00
// Random bytes to make unique. Refresh this with new random bytes when
// implementation is modified in a non-backwards-compatible way.
2023-03-09 21:16:53 -07:00
hash . add ( @as ( u32 , 0xd8cb0055 ) ) ;
hash . addBytes ( b . dep_prefix ) ;
2023-08-10 15:32:55 -07:00
var wyhash = std . hash . Wyhash . init ( 0 ) ;
hashUserInputOptionsMap ( b . allocator , b . user_input_options , & wyhash ) ;
hash . add ( wyhash . final ( ) ) ;
2023-03-09 21:16:53 -07:00
const digest = hash . final ( ) ;
const install_prefix = try b . cache_root . join ( b . allocator , & . { " i " , & digest } ) ;
2023-01-31 00:19:51 -07:00
b . resolveInstallPrefix ( install_prefix , . { } ) ;
}
/// This function is intended to be called by lib/build_runner.zig, not a build.zig file.
2024-05-04 14:29:17 -04:00
pub fn resolveInstallPrefix ( b : * Build , install_prefix : ? [ ] const u8 , dir_list : DirList ) void {
if ( b . dest_dir ) | dest_dir | {
b . install_prefix = install_prefix orelse " /usr " ;
b . install_path = b . pathJoin ( & . { dest_dir , b . install_prefix } ) ;
2023-01-31 00:19:51 -07:00
} else {
2024-05-04 14:29:17 -04:00
b . install_prefix = install_prefix orelse
( b . build_root . join ( b . allocator , & . { " zig-out " } ) catch @panic ( " unhandled error " ) ) ;
b . install_path = b . install_prefix ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
var lib_list = [ _ ] [ ] const u8 { b . install_path , " lib " } ;
var exe_list = [ _ ] [ ] const u8 { b . install_path , " bin " } ;
var h_list = [ _ ] [ ] const u8 { b . install_path , " include " } ;
2023-01-31 00:19:51 -07:00
if ( dir_list . lib_dir ) | dir | {
2024-05-04 14:29:17 -04:00
if ( fs . path . isAbsolute ( dir ) ) lib_list [ 0 ] = b . dest_dir orelse " " ;
2023-01-31 00:19:51 -07:00
lib_list [ 1 ] = dir ;
}
if ( dir_list . exe_dir ) | dir | {
2024-05-04 14:29:17 -04:00
if ( fs . path . isAbsolute ( dir ) ) exe_list [ 0 ] = b . dest_dir orelse " " ;
2023-01-31 00:19:51 -07:00
exe_list [ 1 ] = dir ;
}
if ( dir_list . include_dir ) | dir | {
2024-05-04 14:29:17 -04:00
if ( fs . path . isAbsolute ( dir ) ) h_list [ 0 ] = b . dest_dir orelse " " ;
2023-01-31 00:19:51 -07:00
h_list [ 1 ] = dir ;
}
2024-05-04 14:29:17 -04:00
b . lib_dir = b . pathJoin ( & lib_list ) ;
b . exe_dir = b . pathJoin ( & exe_list ) ;
b . h_dir = b . pathJoin ( & h_list ) ;
2023-01-31 00:19:51 -07:00
}
2024-01-18 21:31:45 -07:00
/// Create a set of key-value pairs that can be converted into a Zig source
/// file and then inserted into a Zig compilation's module table for importing.
/// In other words, this provides a way to expose build.zig values to Zig
/// source code with `@import`.
/// Related: `Module.addOptions`.
2024-05-04 14:29:17 -04:00
pub fn addOptions ( b : * Build ) * Step . Options {
return Step . Options . create ( b ) ;
2023-01-31 00:19:51 -07:00
}
pub const ExecutableOptions = struct {
name : [ ] const u8 ,
2025-03-05 03:17:54 +00:00
root_module : * Module ,
2023-02-21 18:39:22 +01:00
version : ? std . SemanticVersion = null ,
2024-02-18 20:34:32 -08:00
linkage : ? std . builtin . LinkMode = null ,
zig build: add an OOM-prevention system
The problem is that one may execute too many subprocesses concurrently
that, together, exceed an RSS value that causes the OOM killer to kill
something problematic such as the window manager. Or worse, nothing, and
the system freezes.
This is a real world problem. For example when building LLVM a simple
`ninja install` will bring your system to its knees if you don't know
that you should add `-DLLVM_PARALLEL_LINK_JOBS=1`.
In particular: compiling the zig std lib tests takes about 2G each,
which at 16x at once (8 cores + hyperthreading) is using all 32GB of my
RAM, causing the OOM killer to kill my window manager
The idea here is that you can annotate steps that might use a high
amount of system resources with an upper bound. So for example I could
mark the std lib tests as having an upper bound peak RSS of 3 GiB.
Then the build system will do 2 things:
1. ulimit the child process, so that it will fail if it would exceed
that memory limit.
2. Notice how much system RAM is available and avoid running too many
concurrent jobs at once that would total more than that.
This implements (1) not with an operating system enforced limit, but by
checking the maxrss after a child process exits.
However it does implement (2) correctly.
The available memory used by the build system defaults to the total
system memory, regardless of whether it is used by other processes at
the time of spawning the build runner. This value can be overridden with
the new --maxrss flag to `zig build`. This mechanism will ensure that
the sum total of upper bound RSS memory of concurrent tasks will not
exceed this value.
This system makes it so that project maintainers can annotate
problematic subprocesses, avoiding bug reports from users, who can
blissfully execute `zig build` without worrying about the project's
internals.
Nobody's computer crashes, and the build system uses as much parallelism
as possible without risking OOM. Users do not need to unnecessarily
resort to -j1 when the build system can figure this out for them.
2023-03-06 00:20:11 -07:00
max_rss : usize = 0 ,
2023-04-13 16:44:28 -07:00
use_llvm : ? bool = null ,
use_lld : ? bool = null ,
2023-07-29 23:57:52 -07:00
zig_lib_dir : ? LazyPath = null ,
Add preliminary support for Windows .manifest files
An embedded manifest file is really just XML data embedded as a RT_MANIFEST resource (ID = 24). Typically, the Windows-only 'Manifest Tool' (`mt.exe`) is used to embed manifest files, and `mt.exe` also seems to perform some transformation of the manifest data before embedding, but in testing it doesn't seem like the transformations are necessary to get the intended result.
So, to handle embedding manifest files, Zig now takes the following approach:
- Generate a .rc file with the contents `1 24 "path-to-manifest.manifest"`
- Compile that generated .rc file into a .res file
- Link the .res file into the final binary
This effectively achieves the same thing as `mt.exe` minus the validation/transformations of the XML data that it performs.
How this is used:
On the command line:
```
zig build-exe main.zig main.manifest
```
(on the command line, specifying a .manifest file when the target object format is not COFF is an error)
or in build.zig:
```
const exe = b.addExecutable(.{
.name = "manifest-test",
.root_source_file = .{ .path = "main.zig" },
.target = target,
.optimize = optimize,
.win32_manifest = .{ .path = "main.manifest" },
});
```
(in build.zig, the manifest file is ignored if the target object format is not COFF)
Note: Currently, only one manifest file can be specified per compilation. This is because the ID of the manifest resource is currently always 1. Specifying multiple manifests could be supported if a way for the user to specify an ID for each manifest is added (manifest IDs must be a u16).
Closes #17406
options
2023-10-09 04:06:28 -07:00
/// 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 ,
2023-01-31 00:19:51 -07:00
} ;
2023-05-03 11:49:55 +03:00
pub fn addExecutable ( b : * Build , options : ExecutableOptions ) * Step . Compile {
2024-06-18 23:49:21 +05:00
return . create ( b , . {
2023-01-31 00:19:51 -07:00
. name = options . name ,
2025-03-05 03:17:54 +00:00
. root_module = options . root_module ,
2023-01-31 00:19:51 -07:00
. version = options . version ,
. kind = . exe ,
. linkage = options . linkage ,
zig build: add an OOM-prevention system
The problem is that one may execute too many subprocesses concurrently
that, together, exceed an RSS value that causes the OOM killer to kill
something problematic such as the window manager. Or worse, nothing, and
the system freezes.
This is a real world problem. For example when building LLVM a simple
`ninja install` will bring your system to its knees if you don't know
that you should add `-DLLVM_PARALLEL_LINK_JOBS=1`.
In particular: compiling the zig std lib tests takes about 2G each,
which at 16x at once (8 cores + hyperthreading) is using all 32GB of my
RAM, causing the OOM killer to kill my window manager
The idea here is that you can annotate steps that might use a high
amount of system resources with an upper bound. So for example I could
mark the std lib tests as having an upper bound peak RSS of 3 GiB.
Then the build system will do 2 things:
1. ulimit the child process, so that it will fail if it would exceed
that memory limit.
2. Notice how much system RAM is available and avoid running too many
concurrent jobs at once that would total more than that.
This implements (1) not with an operating system enforced limit, but by
checking the maxrss after a child process exits.
However it does implement (2) correctly.
The available memory used by the build system defaults to the total
system memory, regardless of whether it is used by other processes at
the time of spawning the build runner. This value can be overridden with
the new --maxrss flag to `zig build`. This mechanism will ensure that
the sum total of upper bound RSS memory of concurrent tasks will not
exceed this value.
This system makes it so that project maintainers can annotate
problematic subprocesses, avoiding bug reports from users, who can
blissfully execute `zig build` without worrying about the project's
internals.
Nobody's computer crashes, and the build system uses as much parallelism
as possible without risking OOM. Users do not need to unnecessarily
resort to -j1 when the build system can figure this out for them.
2023-03-06 00:20:11 -07:00
. max_rss = options . max_rss ,
2023-04-13 16:44:28 -07:00
. use_llvm = options . use_llvm ,
. use_lld = options . use_lld ,
2024-07-11 16:26:04 -07:00
. zig_lib_dir = options . zig_lib_dir ,
Add preliminary support for Windows .manifest files
An embedded manifest file is really just XML data embedded as a RT_MANIFEST resource (ID = 24). Typically, the Windows-only 'Manifest Tool' (`mt.exe`) is used to embed manifest files, and `mt.exe` also seems to perform some transformation of the manifest data before embedding, but in testing it doesn't seem like the transformations are necessary to get the intended result.
So, to handle embedding manifest files, Zig now takes the following approach:
- Generate a .rc file with the contents `1 24 "path-to-manifest.manifest"`
- Compile that generated .rc file into a .res file
- Link the .res file into the final binary
This effectively achieves the same thing as `mt.exe` minus the validation/transformations of the XML data that it performs.
How this is used:
On the command line:
```
zig build-exe main.zig main.manifest
```
(on the command line, specifying a .manifest file when the target object format is not COFF is an error)
or in build.zig:
```
const exe = b.addExecutable(.{
.name = "manifest-test",
.root_source_file = .{ .path = "main.zig" },
.target = target,
.optimize = optimize,
.win32_manifest = .{ .path = "main.manifest" },
});
```
(in build.zig, the manifest file is ignored if the target object format is not COFF)
Note: Currently, only one manifest file can be specified per compilation. This is because the ID of the manifest resource is currently always 1. Specifying multiple manifests could be supported if a way for the user to specify an ID for each manifest is added (manifest IDs must be a u16).
Closes #17406
options
2023-10-09 04:06:28 -07:00
. win32_manifest = options . win32_manifest ,
2023-01-31 00:19:51 -07:00
} ) ;
}
pub const ObjectOptions = struct {
name : [ ] const u8 ,
2025-03-05 03:17:54 +00:00
root_module : * Module ,
2024-06-18 23:49:21 +05:00
max_rss : usize = 0 ,
use_llvm : ? bool = null ,
use_lld : ? bool = null ,
zig_lib_dir : ? LazyPath = null ,
2023-01-31 00:19:51 -07:00
} ;
2023-05-03 11:49:55 +03:00
pub fn addObject ( b : * Build , options : ObjectOptions ) * Step . Compile {
2024-06-18 23:49:21 +05:00
return . create ( b , . {
2023-01-31 00:19:51 -07:00
. name = options . name ,
2025-03-05 03:17:54 +00:00
. root_module = options . root_module ,
2023-01-31 00:19:51 -07:00
. kind = . obj ,
zig build: add an OOM-prevention system
The problem is that one may execute too many subprocesses concurrently
that, together, exceed an RSS value that causes the OOM killer to kill
something problematic such as the window manager. Or worse, nothing, and
the system freezes.
This is a real world problem. For example when building LLVM a simple
`ninja install` will bring your system to its knees if you don't know
that you should add `-DLLVM_PARALLEL_LINK_JOBS=1`.
In particular: compiling the zig std lib tests takes about 2G each,
which at 16x at once (8 cores + hyperthreading) is using all 32GB of my
RAM, causing the OOM killer to kill my window manager
The idea here is that you can annotate steps that might use a high
amount of system resources with an upper bound. So for example I could
mark the std lib tests as having an upper bound peak RSS of 3 GiB.
Then the build system will do 2 things:
1. ulimit the child process, so that it will fail if it would exceed
that memory limit.
2. Notice how much system RAM is available and avoid running too many
concurrent jobs at once that would total more than that.
This implements (1) not with an operating system enforced limit, but by
checking the maxrss after a child process exits.
However it does implement (2) correctly.
The available memory used by the build system defaults to the total
system memory, regardless of whether it is used by other processes at
the time of spawning the build runner. This value can be overridden with
the new --maxrss flag to `zig build`. This mechanism will ensure that
the sum total of upper bound RSS memory of concurrent tasks will not
exceed this value.
This system makes it so that project maintainers can annotate
problematic subprocesses, avoiding bug reports from users, who can
blissfully execute `zig build` without worrying about the project's
internals.
Nobody's computer crashes, and the build system uses as much parallelism
as possible without risking OOM. Users do not need to unnecessarily
resort to -j1 when the build system can figure this out for them.
2023-03-06 00:20:11 -07:00
. max_rss = options . max_rss ,
2023-04-13 16:44:28 -07:00
. use_llvm = options . use_llvm ,
. use_lld = options . use_lld ,
2024-07-11 16:26:04 -07:00
. zig_lib_dir = options . zig_lib_dir ,
2023-01-31 00:19:51 -07:00
} ) ;
}
std.Build: add `addLibrary` function (#22554)
Acts as a replacement for `addSharedLibrary` and `addStaticLibrary`, but
linking mode can be changed more easily in build.zig, for example:
In library:
```zig
const linkage = b.option(std.builtin.LinkMode, "linkage", "Link mode for a foo_bar library") orelse .static; // or other default
const lib = b.addLibrary(.{
.linkage = linkage,
.name = "foo_bar",
.root_module = mod,
});
```
In consumer:
```zig
const dep_foo_bar = b.dependency("foo_bar", .{
.target = target,
.optimize = optimize,
.linkage = .static // or dynamic
});
mod.linkLibrary(dep_foor_bar.artifact("foo_bar"));
```
It also matches nicely with `linkLibrary` name.
Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-01-22 07:29:21 +05:00
pub const LibraryOptions = struct {
linkage : std . builtin . LinkMode = . static ,
name : [ ] const u8 ,
root_module : * Module ,
version : ? std . SemanticVersion = null ,
max_rss : usize = 0 ,
use_llvm : ? bool = null ,
use_lld : ? bool = null ,
zig_lib_dir : ? 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 ,
} ;
pub fn addLibrary ( b : * Build , options : LibraryOptions ) * Step . Compile {
return . create ( b , . {
. name = options . name ,
. root_module = options . root_module ,
. kind = . lib ,
. linkage = options . linkage ,
. version = options . version ,
. max_rss = options . max_rss ,
. use_llvm = options . use_llvm ,
. use_lld = options . use_lld ,
. zig_lib_dir = options . zig_lib_dir ,
. win32_manifest = options . win32_manifest ,
} ) ;
}
2023-01-31 00:19:51 -07:00
pub const TestOptions = struct {
name : [ ] const u8 = " test " ,
2025-03-05 03:17:54 +00:00
root_module : * Module ,
zig build: add an OOM-prevention system
The problem is that one may execute too many subprocesses concurrently
that, together, exceed an RSS value that causes the OOM killer to kill
something problematic such as the window manager. Or worse, nothing, and
the system freezes.
This is a real world problem. For example when building LLVM a simple
`ninja install` will bring your system to its knees if you don't know
that you should add `-DLLVM_PARALLEL_LINK_JOBS=1`.
In particular: compiling the zig std lib tests takes about 2G each,
which at 16x at once (8 cores + hyperthreading) is using all 32GB of my
RAM, causing the OOM killer to kill my window manager
The idea here is that you can annotate steps that might use a high
amount of system resources with an upper bound. So for example I could
mark the std lib tests as having an upper bound peak RSS of 3 GiB.
Then the build system will do 2 things:
1. ulimit the child process, so that it will fail if it would exceed
that memory limit.
2. Notice how much system RAM is available and avoid running too many
concurrent jobs at once that would total more than that.
This implements (1) not with an operating system enforced limit, but by
checking the maxrss after a child process exits.
However it does implement (2) correctly.
The available memory used by the build system defaults to the total
system memory, regardless of whether it is used by other processes at
the time of spawning the build runner. This value can be overridden with
the new --maxrss flag to `zig build`. This mechanism will ensure that
the sum total of upper bound RSS memory of concurrent tasks will not
exceed this value.
This system makes it so that project maintainers can annotate
problematic subprocesses, avoiding bug reports from users, who can
blissfully execute `zig build` without worrying about the project's
internals.
Nobody's computer crashes, and the build system uses as much parallelism
as possible without risking OOM. Users do not need to unnecessarily
resort to -j1 when the build system can figure this out for them.
2023-03-06 00:20:11 -07:00
max_rss : usize = 0 ,
2024-02-25 14:04:06 +01:00
filters : [ ] const [ ] const u8 = & . { } ,
std.Build: extend `test_runner` option to specify whether runner uses `std.zig.Server`
The previous logic here was trying to assume that custom test runners
never used `std.zig.Server` to communicate with the build runner;
however, it was flawed, because modifying the `test_runner` field on
`Step.Compile` would not update this flag. That might have been
intentional (allowing a way for the user to specify a custom test runner
which *does* use the compiler server protocol), but if so, it was a
flawed API, since it was too easy to update one field without updating
the other.
Instead, bundle these two pieces of state into a new type
`std.Build.Step.Compile.TestRunner`. When passing a custom test runner,
you are now *provided* to specify whether it is a "simple" runner, or
whether it uses the compiler server protocol.
This is a breaking change, but is unlikely to affect many people, since
custom test runners are seldom used in the wild.
2025-01-10 10:48:52 +00:00
test_runner : ? Step . Compile . TestRunner = null ,
2024-06-18 23:49:21 +05:00
use_llvm : ? bool = null ,
use_lld : ? bool = null ,
zig_lib_dir : ? LazyPath = null ,
2025-04-20 17:54:11 +01:00
/// Emits an object file instead of a test binary.
/// The object must be linked separately.
/// Usually used in conjunction with a custom `test_runner`.
emit_object : bool = false ,
2023-01-31 00:19:51 -07:00
} ;
2024-03-21 14:02:58 -07:00
/// Creates an executable containing unit tests.
///
/// Equivalent to running the command `zig test --test-no-exec ...`.
///
/// **This step does not run the unit tests**. Typically, the result of this
/// function will be passed to `addRunArtifact`, creating a `Step.Run`. These
/// two steps are separated because they are independently configured and
/// cached.
2023-05-03 11:49:55 +03:00
pub fn addTest ( b : * Build , options : TestOptions ) * Step . Compile {
2024-06-18 23:49:21 +05:00
return . create ( b , . {
2023-01-31 00:19:51 -07:00
. name = options . name ,
2025-04-20 17:54:11 +01:00
. kind = if ( options . emit_object ) . test_obj else . @" test " ,
2025-03-05 03:17:54 +00:00
. root_module = options . root_module ,
zig build: add an OOM-prevention system
The problem is that one may execute too many subprocesses concurrently
that, together, exceed an RSS value that causes the OOM killer to kill
something problematic such as the window manager. Or worse, nothing, and
the system freezes.
This is a real world problem. For example when building LLVM a simple
`ninja install` will bring your system to its knees if you don't know
that you should add `-DLLVM_PARALLEL_LINK_JOBS=1`.
In particular: compiling the zig std lib tests takes about 2G each,
which at 16x at once (8 cores + hyperthreading) is using all 32GB of my
RAM, causing the OOM killer to kill my window manager
The idea here is that you can annotate steps that might use a high
amount of system resources with an upper bound. So for example I could
mark the std lib tests as having an upper bound peak RSS of 3 GiB.
Then the build system will do 2 things:
1. ulimit the child process, so that it will fail if it would exceed
that memory limit.
2. Notice how much system RAM is available and avoid running too many
concurrent jobs at once that would total more than that.
This implements (1) not with an operating system enforced limit, but by
checking the maxrss after a child process exits.
However it does implement (2) correctly.
The available memory used by the build system defaults to the total
system memory, regardless of whether it is used by other processes at
the time of spawning the build runner. This value can be overridden with
the new --maxrss flag to `zig build`. This mechanism will ensure that
the sum total of upper bound RSS memory of concurrent tasks will not
exceed this value.
This system makes it so that project maintainers can annotate
problematic subprocesses, avoiding bug reports from users, who can
blissfully execute `zig build` without worrying about the project's
internals.
Nobody's computer crashes, and the build system uses as much parallelism
as possible without risking OOM. Users do not need to unnecessarily
resort to -j1 when the build system can figure this out for them.
2023-03-06 00:20:11 -07:00
. max_rss = options . max_rss ,
2025-03-05 03:17:54 +00:00
. filters = b . dupeStrings ( options . filters ) ,
2023-04-10 18:09:39 -07:00
. test_runner = options . test_runner ,
2023-04-13 16:44:28 -07:00
. use_llvm = options . use_llvm ,
. use_lld = options . use_lld ,
2024-07-11 16:26:04 -07:00
. zig_lib_dir = options . zig_lib_dir ,
2023-01-31 00:19:51 -07:00
} ) ;
}
pub const AssemblyOptions = struct {
name : [ ] const u8 ,
2023-07-19 10:49:34 +02:00
source_file : LazyPath ,
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
/// To choose the same computer as the one building the package, pass the
/// `host` field of the package's `Build` instance.
target : ResolvedTarget ,
2023-08-09 13:39:34 -05:00
optimize : std . builtin . OptimizeMode ,
zig build: add an OOM-prevention system
The problem is that one may execute too many subprocesses concurrently
that, together, exceed an RSS value that causes the OOM killer to kill
something problematic such as the window manager. Or worse, nothing, and
the system freezes.
This is a real world problem. For example when building LLVM a simple
`ninja install` will bring your system to its knees if you don't know
that you should add `-DLLVM_PARALLEL_LINK_JOBS=1`.
In particular: compiling the zig std lib tests takes about 2G each,
which at 16x at once (8 cores + hyperthreading) is using all 32GB of my
RAM, causing the OOM killer to kill my window manager
The idea here is that you can annotate steps that might use a high
amount of system resources with an upper bound. So for example I could
mark the std lib tests as having an upper bound peak RSS of 3 GiB.
Then the build system will do 2 things:
1. ulimit the child process, so that it will fail if it would exceed
that memory limit.
2. Notice how much system RAM is available and avoid running too many
concurrent jobs at once that would total more than that.
This implements (1) not with an operating system enforced limit, but by
checking the maxrss after a child process exits.
However it does implement (2) correctly.
The available memory used by the build system defaults to the total
system memory, regardless of whether it is used by other processes at
the time of spawning the build runner. This value can be overridden with
the new --maxrss flag to `zig build`. This mechanism will ensure that
the sum total of upper bound RSS memory of concurrent tasks will not
exceed this value.
This system makes it so that project maintainers can annotate
problematic subprocesses, avoiding bug reports from users, who can
blissfully execute `zig build` without worrying about the project's
internals.
Nobody's computer crashes, and the build system uses as much parallelism
as possible without risking OOM. Users do not need to unnecessarily
resort to -j1 when the build system can figure this out for them.
2023-03-06 00:20:11 -07:00
max_rss : usize = 0 ,
2023-07-29 23:57:52 -07:00
zig_lib_dir : ? LazyPath = null ,
2023-01-31 00:19:51 -07:00
} ;
2023-03-03 16:17:23 -07:00
/// 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.
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
2023-11-28 22:47:34 -07:00
pub fn addModule ( b : * Build , name : [ ] const u8 , options : Module . CreateOptions ) * Module {
const module = Module . create ( b , options ) ;
2023-03-03 16:17:23 -07:00
b . modules . put ( b . dupe ( name ) , module ) catch @panic ( " OOM " ) ;
return module ;
2023-02-03 17:22:31 -07:00
}
2023-03-03 16:17:23 -07:00
/// 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.
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
2023-11-28 22:47:34 -07:00
pub fn createModule ( b : * Build , options : Module . CreateOptions ) * Module {
return Module . create ( b , options ) ;
2023-02-03 17:22:31 -07:00
}
2023-05-03 11:49:55 +03:00
/// Initializes a `Step.Run` with argv, which must at least have the path to the
2023-01-31 00:19:51 -07:00
/// executable. More command line arguments can be added with `addArg`,
/// `addArgs`, and `addArtifactArg`.
/// Be careful using this function, as it introduces a system dependency.
2023-05-03 11:49:55 +03:00
/// To run an executable built with zig build, see `Step.Compile.run`.
2024-05-04 14:29:17 -04:00
pub fn addSystemCommand ( b : * Build , argv : [ ] const [ ] const u8 ) * Step . Run {
2023-01-31 00:19:51 -07:00
assert ( argv . len >= 1 ) ;
2024-05-04 14:29:17 -04:00
const run_step = Step . Run . create ( b , b . fmt ( " run {s} " , . { argv [ 0 ] } ) ) ;
2023-01-31 00:19:51 -07:00
run_step . addArgs ( argv ) ;
return run_step ;
}
2023-05-03 11:49:55 +03:00
/// Creates a `Step.Run` with an executable built with `addExecutable`.
/// Add command line arguments with methods of `Step.Run`.
pub fn addRunArtifact ( b : * Build , exe : * Step . Compile ) * Step . Run {
2023-02-05 16:44:03 -07:00
// It doesn't have to be native. We catch that if you actually try to run it.
// Consider that this is declarative; the run step may not be run unless a user
// option is supplied.
2025-06-13 05:46:15 -04:00
// Avoid the common case of the step name looking like "run test test".
const step_name = if ( exe . kind . isTest ( ) and mem . eql ( u8 , exe . name , " test " ) )
b . fmt ( " run {s} " , . { @tagName ( exe . kind ) } )
else
b . fmt ( " run {s} {s} " , . { @tagName ( exe . kind ) , exe . name } ) ;
const run_step = Step . Run . create ( b , step_name ) ;
2024-07-23 20:49:00 -07:00
run_step . producer = exe ;
2024-04-13 15:30:03 +02:00
if ( exe . kind == . @" test " ) {
if ( exe . exec_cmd_args ) | exec_cmd_args | {
for ( exec_cmd_args ) | cmd_arg | {
if ( cmd_arg ) | arg | {
run_step . addArg ( arg ) ;
} else {
run_step . addArtifactArg ( exe ) ;
}
}
} else {
run_step . addArtifactArg ( exe ) ;
}
2023-02-05 16:44:03 -07:00
2025-09-13 16:16:11 +01:00
const test_server_mode : bool = s : {
if ( exe . test_runner ) | r | break : s r . mode == . server ;
if ( exe . use_llvm == false ) {
// The default test runner does not use the server protocol if the selected backend
// is too immature to support it. Keep this logic in sync with `need_simple` in the
// default test runner implementation.
switch ( exe . rootModuleTarget ( ) . cpu . arch ) {
// stage2_aarch64
. aarch64 ,
. aarch64_be ,
// stage2_powerpc
. powerpc ,
. powerpcle ,
. powerpc64 ,
. powerpc64le ,
// stage2_riscv64
. riscv64 ,
= > break : s false ,
else = > { } ,
}
}
break : s true ;
} ;
if ( test_server_mode ) {
run_step . enableTestRunnerMode ( ) ;
} else if ( exe . test_runner == null ) {
// If a test runner does not use the `std.zig.Server` protocol, it can instead
// communicate failure via its exit code.
run_step . expectExitCode ( 0 ) ;
}
2024-04-13 15:30:03 +02:00
} else {
run_step . addArtifactArg ( exe ) ;
2023-02-05 16:44:03 -07:00
}
return run_step ;
}
2023-02-04 22:44:21 -07:00
/// Using the `values` provided, produces a C header file, possibly based on a
/// template input file (e.g. config.h.in).
/// When an input template file is provided, this function will fail the build
/// when an option not found in the input file is provided in `values`, and
/// when an option found in the input file is missing from `values`.
2023-01-31 00:19:51 -07:00
pub fn addConfigHeader (
b : * Build ,
2023-05-03 11:49:55 +03:00
options : Step . ConfigHeader . Options ,
2023-01-31 00:19:51 -07:00
values : anytype ,
2023-05-03 11:49:55 +03:00
) * Step . ConfigHeader {
2023-02-14 12:47:45 -07:00
var options_copy = options ;
if ( options_copy . first_ret_addr == null )
options_copy . first_ret_addr = @returnAddress ( ) ;
2023-05-03 11:49:55 +03:00
const config_header_step = Step . ConfigHeader . create ( b , options_copy ) ;
2023-01-31 00:19:51 -07:00
config_header_step . addValues ( values ) ;
return config_header_step ;
}
/// Allocator.dupe without the need to handle out of memory.
2024-05-04 14:29:17 -04:00
pub fn dupe ( b : * Build , bytes : [ ] const u8 ) [ ] u8 {
2024-10-05 00:58:48 +02:00
return dupeInner ( b . allocator , bytes ) ;
}
pub fn dupeInner ( allocator : std . mem . Allocator , bytes : [ ] const u8 ) [ ] u8 {
return allocator . dupe ( u8 , bytes ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
}
/// Duplicates an array of strings without the need to handle out of memory.
2024-05-04 14:29:17 -04:00
pub fn dupeStrings ( b : * Build , strings : [ ] const [ ] const u8 ) [ ] [ ] u8 {
const array = b . allocator . alloc ( [ ] u8 , strings . len ) catch @panic ( " OOM " ) ;
for ( array , strings ) | * dest , source | dest .* = b . dupe ( source ) ;
2023-01-31 00:19:51 -07:00
return array ;
}
/// Duplicates a path and converts all slashes to the OS's canonical path separator.
2024-05-04 14:29:17 -04:00
pub fn dupePath ( b : * Build , bytes : [ ] const u8 ) [ ] u8 {
2024-10-05 00:58:48 +02:00
return dupePathInner ( b . allocator , bytes ) ;
}
fn dupePathInner ( allocator : std . mem . Allocator , bytes : [ ] const u8 ) [ ] u8 {
const the_copy = dupeInner ( allocator , bytes ) ;
2023-01-31 00:19:51 -07:00
for ( the_copy ) | * byte | {
switch ( byte .* ) {
'/' , '\\' = > byte .* = fs . path . sep ,
else = > { } ,
}
}
return the_copy ;
}
2024-05-04 14:29:17 -04:00
pub fn addWriteFile ( b : * Build , file_path : [ ] const u8 , data : [ ] const u8 ) * Step . WriteFile {
const write_file_step = b . addWriteFiles ( ) ;
2023-05-24 14:26:07 -07:00
_ = write_file_step . add ( file_path , data ) ;
2023-01-31 00:19:51 -07:00
return write_file_step ;
}
2023-10-22 16:10:01 +02:00
pub fn addNamedWriteFiles ( b : * Build , name : [ ] const u8 ) * Step . WriteFile {
const wf = Step . WriteFile . create ( b ) ;
b . named_writefiles . put ( b . dupe ( name ) , wf ) catch @panic ( " OOM " ) ;
return wf ;
}
2024-09-11 09:06:54 +01:00
pub fn addNamedLazyPath ( b : * Build , name : [ ] const u8 , lp : LazyPath ) void {
b . named_lazy_paths . put ( b . dupe ( name ) , lp . dupe ( b ) ) catch @panic ( " OOM " ) ;
}
2023-05-03 11:49:55 +03:00
pub fn addWriteFiles ( b : * Build ) * Step . WriteFile {
return Step . WriteFile . create ( b ) ;
2023-01-31 00:19:51 -07:00
}
2024-07-09 21:47:26 -07:00
pub fn addUpdateSourceFiles ( b : * Build ) * Step . UpdateSourceFiles {
return Step . UpdateSourceFiles . create ( b ) ;
}
2024-07-09 21:08:20 -07:00
pub fn addRemoveDirTree ( b : * Build , dir_path : LazyPath ) * Step . RemoveDir {
2024-05-04 14:29:17 -04:00
return Step . RemoveDir . create ( b , dir_path ) ;
2023-01-31 00:19:51 -07:00
}
2024-06-16 04:42:58 +02:00
pub fn addFail ( b : * Build , error_msg : [ ] const u8 ) * Step . Fail {
return Step . Fail . create ( b , error_msg ) ;
}
2023-05-03 11:49:55 +03:00
pub fn addFmt ( b : * Build , options : Step . Fmt . Options ) * Step . Fmt {
return Step . Fmt . create ( b , options ) ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn addTranslateC ( b : * Build , options : Step . TranslateC . Options ) * Step . TranslateC {
return Step . TranslateC . create ( b , options ) ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn getInstallStep ( b : * Build ) * Step {
return & b . install_tls . step ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn getUninstallStep ( b : * Build ) * Step {
return & b . uninstall_tls . step ;
2023-01-31 00:19:51 -07:00
}
2024-07-14 19:48:08 -07:00
fn makeUninstall ( uninstall_step : * Step , options : Step . MakeOptions ) anyerror ! void {
_ = options ;
2024-03-19 12:46:38 +01:00
const uninstall_tls : * TopLevelStep = @fieldParentPtr ( " step " , uninstall_step ) ;
2024-05-04 14:29:17 -04:00
const b : * Build = @fieldParentPtr ( " uninstall_tls " , uninstall_tls ) ;
2023-01-31 00:19:51 -07:00
2024-07-05 13:05:56 -07:00
_ = b ;
@panic ( " TODO implement https://github.com/ziglang/zig/issues/14943 " ) ;
2023-01-31 00:19:51 -07:00
}
2024-01-18 21:31:45 -07:00
/// Creates a configuration option to be passed to the build.zig script.
/// When a user directly runs `zig build`, they can set these options with `-D` arguments.
/// When a project depends on a Zig package as a dependency, it programmatically sets
/// these options when calling the dependency's build.zig script as a function.
/// `null` is returned when an option is left to default.
2024-05-04 14:29:17 -04:00
pub fn option ( b : * Build , comptime T : type , name_raw : [ ] const u8 , description_raw : [ ] const u8 ) ? T {
const name = b . dupe ( name_raw ) ;
const description = b . dupe ( description_raw ) ;
2023-01-31 00:19:51 -07:00
const type_id = comptime typeToEnum ( T ) ;
2024-06-06 06:02:42 +02:00
const enum_options = if ( type_id == . @" enum " or type_id == . enum_list ) blk : {
2024-08-28 02:35:53 +01:00
const EnumType = if ( type_id == . enum_list ) @typeInfo ( T ) . pointer . child else T ;
2024-06-06 06:02:42 +02:00
const fields = comptime std . meta . fields ( EnumType ) ;
2025-07-31 21:54:07 -07:00
var options = std . array_list . Managed ( [ ] const u8 ) . initCapacity ( b . allocator , fields . len ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
inline for ( fields ) | field | {
options . appendAssumeCapacity ( field . name ) ;
}
2023-01-31 14:02:32 -07:00
break : blk options . toOwnedSlice ( ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
} else null ;
const available_option = AvailableOption {
. name = name ,
. type_id = type_id ,
. description = description ,
. enum_options = enum_options ,
} ;
2024-05-04 14:29:17 -04:00
if ( ( b . available_options_map . fetchPut ( name , available_option ) catch @panic ( " OOM " ) ) != null ) {
2023-01-31 00:19:51 -07:00
panic ( " Option '{s}' declared twice " , . { name } ) ;
}
2024-05-04 14:29:17 -04:00
b . available_options_list . append ( available_option ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
2024-05-04 14:29:17 -04:00
const option_ptr = b . user_input_options . getPtr ( name ) orelse return null ;
2023-01-31 00:19:51 -07:00
option_ptr . used = true ;
switch ( type_id ) {
. bool = > switch ( option_ptr . value ) {
. flag = > return true ,
. scalar = > | s | {
if ( mem . eql ( u8 , s , " true " ) ) {
return true ;
} else if ( mem . eql ( u8 , s , " false " ) ) {
return false ;
} else {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be a boolean, but received '{s}' " , . { name , s } ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
}
} ,
2024-10-05 00:58:48 +02:00
. list , . map , . lazy_path , . lazy_path_list = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be a boolean, but received a {s}. " , . {
2023-01-31 00:19:51 -07:00
name , @tagName ( option_ptr . value ) ,
} ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
} ,
. int = > switch ( option_ptr . value ) {
2024-10-05 00:58:48 +02:00
. flag , . list , . map , . lazy_path , . lazy_path_list = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be an integer, but received a {s}. " , . {
2023-01-31 00:19:51 -07:00
name , @tagName ( option_ptr . value ) ,
} ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
. scalar = > | s | {
const n = std . fmt . parseInt ( T , s , 10 ) catch | err | switch ( err ) {
error . Overflow = > {
2023-05-16 20:00:47 -07:00
log . err ( " -D{s} value {s} cannot fit into type {s}. " , . { name , s , @typeName ( T ) } ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
else = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be an integer of type {s}. " , . { name , @typeName ( T ) } ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
} ;
return n ;
} ,
} ,
. float = > switch ( option_ptr . value ) {
2024-10-05 00:58:48 +02:00
. flag , . map , . list , . lazy_path , . lazy_path_list = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be a float, but received a {s}. " , . {
2023-01-31 00:19:51 -07:00
name , @tagName ( option_ptr . value ) ,
} ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
. scalar = > | s | {
const n = std . fmt . parseFloat ( T , s ) catch {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be a float of type {s}. " , . { name , @typeName ( T ) } ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ;
return n ;
} ,
} ,
. @" enum " = > switch ( option_ptr . value ) {
2024-10-05 00:58:48 +02:00
. flag , . map , . list , . lazy_path , . lazy_path_list = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be an enum, but received a {s}. " , . {
2023-01-31 00:19:51 -07:00
name , @tagName ( option_ptr . value ) ,
} ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
. scalar = > | s | {
if ( std . meta . stringToEnum ( T , s ) ) | enum_lit | {
return enum_lit ;
} else {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be of type {s}. " , . { name , @typeName ( T ) } ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
}
} ,
} ,
. string = > switch ( option_ptr . value ) {
2024-10-05 00:58:48 +02:00
. flag , . list , . map , . lazy_path , . lazy_path_list = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be a string, but received a {s}. " , . {
2023-01-31 00:19:51 -07:00
name , @tagName ( option_ptr . value ) ,
} ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
. scalar = > | s | return s ,
} ,
2023-05-16 20:00:47 -07:00
. build_id = > switch ( option_ptr . value ) {
2024-10-05 00:58:48 +02:00
. flag , . map , . list , . lazy_path , . lazy_path_list = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be an enum, but received a {s}. " , . {
name , @tagName ( option_ptr . value ) ,
} ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-05-16 20:00:47 -07:00
return null ;
} ,
. scalar = > | s | {
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
if ( std . zig . BuildId . parse ( s ) ) | build_id | {
2023-05-16 20:00:47 -07:00
return build_id ;
} else | err | {
log . err ( " unable to parse option '-D{s}': {s} " , . { name , @errorName ( err ) } ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-05-16 20:00:47 -07:00
return null ;
}
} ,
} ,
2023-01-31 00:19:51 -07:00
. list = > switch ( option_ptr . value ) {
2024-10-05 00:58:48 +02:00
. flag , . map , . lazy_path , . lazy_path_list = > {
2023-05-16 20:00:47 -07:00
log . err ( " Expected -D{s} to be a list, but received a {s}. " , . {
2023-01-31 00:19:51 -07:00
name , @tagName ( option_ptr . value ) ,
} ) ;
2024-05-04 14:29:17 -04:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return null ;
} ,
. scalar = > | s | {
2024-05-04 14:29:17 -04:00
return b . allocator . dupe ( [ ] const u8 , & [ _ ] [ ] const u8 { s } ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
} ,
. list = > | lst | return lst . items ,
} ,
2024-06-06 06:02:42 +02:00
. enum_list = > switch ( option_ptr . value ) {
2024-10-05 00:58:48 +02:00
. flag , . map , . lazy_path , . lazy_path_list = > {
2024-06-06 06:02:42 +02:00
log . err ( " Expected -D{s} to be a list, but received a {s}. " , . {
name , @tagName ( option_ptr . value ) ,
} ) ;
b . markInvalidUserInput ( ) ;
return null ;
} ,
. scalar = > | s | {
2024-08-28 02:35:53 +01:00
const Child = @typeInfo ( T ) . pointer . child ;
2024-06-06 06:02:42 +02:00
const value = std . meta . stringToEnum ( Child , s ) orelse {
log . err ( " Expected -D{s} to be of type {s}. " , . { name , @typeName ( Child ) } ) ;
b . markInvalidUserInput ( ) ;
return null ;
} ;
return b . allocator . dupe ( Child , & [ _ ] Child { value } ) catch @panic ( " OOM " ) ;
} ,
. list = > | lst | {
2024-08-28 02:35:53 +01:00
const Child = @typeInfo ( T ) . pointer . child ;
2024-10-05 00:58:48 +02:00
const new_list = b . allocator . alloc ( Child , lst . items . len ) catch @panic ( " OOM " ) ;
for ( new_list , lst . items ) | * new_item , str | {
new_item .* = std . meta . stringToEnum ( Child , str ) orelse {
2024-06-06 06:02:42 +02:00
log . err ( " Expected -D{s} to be of type {s}. " , . { name , @typeName ( Child ) } ) ;
b . markInvalidUserInput ( ) ;
b . allocator . free ( new_list ) ;
return null ;
} ;
}
return new_list ;
} ,
} ,
2024-10-05 00:58:48 +02:00
. lazy_path = > switch ( option_ptr . value ) {
. scalar = > | s | return . { . cwd_relative = s } ,
. lazy_path = > | lp | return lp ,
. flag , . map , . list , . lazy_path_list = > {
log . err ( " Expected -D{s} to be a path, but received a {s}. " , . {
name , @tagName ( option_ptr . value ) ,
} ) ;
b . markInvalidUserInput ( ) ;
return null ;
} ,
} ,
. lazy_path_list = > switch ( option_ptr . value ) {
. scalar = > | s | return b . allocator . dupe ( LazyPath , & [ _ ] LazyPath { . { . cwd_relative = s } } ) catch @panic ( " OOM " ) ,
. lazy_path = > | lp | return b . allocator . dupe ( LazyPath , & [ _ ] LazyPath { lp } ) catch @panic ( " OOM " ) ,
. list = > | lst | {
const new_list = b . allocator . alloc ( LazyPath , lst . items . len ) catch @panic ( " OOM " ) ;
for ( new_list , lst . items ) | * new_item , str | {
new_item .* = . { . cwd_relative = str } ;
}
return new_list ;
} ,
. lazy_path_list = > | lp_list | return lp_list . items ,
. flag , . map = > {
log . err ( " Expected -D{s} to be a path, but received a {s}. " , . {
name , @tagName ( option_ptr . value ) ,
} ) ;
b . markInvalidUserInput ( ) ;
return null ;
} ,
} ,
2023-01-31 00:19:51 -07:00
}
}
2024-05-04 14:29:17 -04:00
pub fn step ( b : * Build , name : [ ] const u8 , description : [ ] const u8 ) * Step {
const step_info = b . allocator . create ( TopLevelStep ) catch @panic ( " OOM " ) ;
zig build: many enhancements related to parallel building
Rework std.Build.Step to have an `owner: *Build` field. This
simplified the implementation of installation steps, as well as provided
some much-needed common API for the new parallelized build system.
--verbose is now defined very concretely: it prints to stderr just
before spawning a child process.
Child process execution is updated to conform to the new
parallel-friendly make() function semantics.
DRY up the failWithCacheError handling code. It now integrates properly
with the step graph instead of incorrectly dumping to stderr and calling
process exit.
In the main CLI, fix `zig fmt` crash when there are no errors and stdin
is used.
Deleted steps:
* EmulatableRunStep - this entire thing can be removed in favor of a
flag added to std.Build.RunStep called `skip_foreign_checks`.
* LogStep - this doesn't really fit with a multi-threaded build runner
and is effectively superseded by the new build summary output.
build runner:
* add -fsummary and -fno-summary to override the default behavior,
which is to print a summary if any of the build steps fail.
* print the dep prefix when emitting error messages for steps.
std.Build.FmtStep:
* This step now supports exclude paths as well as a check flag.
* The check flag decides between two modes, modify mode, and check
mode. These can be used to update source files in place, or to fail
the build, respectively.
Zig's own build.zig:
* The `test-fmt` step will do all the `zig fmt` checking that we expect
to be done. Since the `test` step depends on this one, we can simply
remove the explicit call to `zig fmt` in the CI.
* The new `fmt` step will actually perform `zig fmt` and update source
files in place.
std.Build.RunStep:
* expose max_stdio_size is a field (previously an unchangeable
hard-coded value).
* rework the API. Instead of configuring each stream independently,
there is a `stdio` field where you can choose between
`infer_from_args`, `inherit`, or `check`. These determine whether the
RunStep is considered to have side-effects or not. The previous
field, `condition` is gone.
* when stdio mode is set to `check` there is a slice of any number of
checks to make, which include things like exit code, stderr matching,
or stdout matching.
* remove the ill-defined `print` field.
* when adding an output arg, it takes the opportunity to give itself a
better name.
* The flag `skip_foreign_checks` is added. If this is true, a RunStep
which is configured to check the output of the executed binary will
not fail the build if the binary cannot be executed due to being for
a foreign binary to the host system which is running the build graph.
Command-line arguments such as -fqemu and -fwasmtime may affect
whether a binary is detected as foreign, as well as system
configuration such as Rosetta (macOS) and binfmt_misc (Linux).
- This makes EmulatableRunStep no longer needed.
* Fix the child process handling to properly integrate with the new
bulid API and to avoid deadlocks in stdout/stderr streams by polling
if necessary.
std.Build.RemoveDirStep now uses the open build_root directory handle
instead of an absolute path.
2023-03-01 22:56:37 -07:00
step_info .* = . {
2025-07-02 11:16:20 -07:00
. step = . init ( . {
2024-05-04 14:29:17 -04:00
. id = TopLevelStep . base_id ,
2023-02-14 12:47:45 -07:00
. name = name ,
2024-05-04 14:29:17 -04:00
. owner = b ,
2023-02-14 12:47:45 -07:00
} ) ,
2024-05-04 14:29:17 -04:00
. description = b . dupe ( description ) ,
2023-01-31 00:19:51 -07:00
} ;
2024-05-04 14:29:17 -04:00
const gop = b . top_level_steps . getOrPut ( b . allocator , name ) catch @panic ( " OOM " ) ;
2023-03-10 13:03:40 +11:00
if ( gop . found_existing ) std . debug . panic ( " A top-level step with name \" {s} \" already exists " , . { name } ) ;
gop . key_ptr .* = step_info . step . name ;
gop . value_ptr .* = step_info ;
2023-01-31 00:19:51 -07:00
return & step_info . step ;
}
pub const StandardOptimizeOptionOptions = struct {
2023-08-09 13:39:34 -05:00
preferred_optimize_mode : ? std . builtin . OptimizeMode = null ,
2023-01-31 00:19:51 -07:00
} ;
2024-02-01 20:17:07 -07:00
pub fn standardOptimizeOption ( b : * Build , options : StandardOptimizeOptionOptions ) std . builtin . OptimizeMode {
2023-01-31 00:19:51 -07:00
if ( options . preferred_optimize_mode ) | mode | {
2024-02-01 20:17:07 -07:00
if ( b . option ( bool , " release " , " optimize for end users " ) orelse ( b . release_mode != . off ) ) {
2023-01-31 00:19:51 -07:00
return mode ;
} else {
return . Debug ;
}
}
2024-02-01 20:17:07 -07:00
if ( b . option (
std . builtin . OptimizeMode ,
" optimize " ,
2024-02-01 22:43:41 -07:00
" Prioritize performance, safety, or binary size " ,
2024-02-01 20:17:07 -07:00
) ) | mode | {
return mode ;
}
return switch ( b . release_mode ) {
. off = > . Debug ,
. any = > {
std . debug . print ( " the project does not declare a preferred optimization mode. choose: --release=fast, --release=safe, or --release=small \n " , . { } ) ;
process . exit ( 1 ) ;
} ,
. fast = > . ReleaseFast ,
. safe = > . ReleaseSafe ,
. small = > . ReleaseSmall ,
} ;
2023-01-31 00:19:51 -07:00
}
pub const StandardTargetOptionsArgs = struct {
2023-12-04 12:35:04 -07:00
whitelist : ? [ ] const Target . Query = null ,
default_target : Target . Query = . { } ,
2023-01-31 00:19:51 -07:00
} ;
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
/// Exposes standard `zig build` options for choosing a target and additionally
/// resolves the target query.
pub fn standardTargetOptions ( b : * Build , args : StandardTargetOptionsArgs ) ResolvedTarget {
const query = b . standardTargetOptionsQueryOnly ( args ) ;
return b . resolveTargetQuery ( query ) ;
}
2024-02-13 21:08:13 +01:00
/// Obtain a target query from a string, reporting diagnostics to stderr if the
/// parsing failed.
/// Asserts that the `diagnostics` field of `options` is `null`. This use case
/// is handled instead by calling `std.Target.Query.parse` directly.
2024-02-01 15:44:44 -07:00
pub fn parseTargetQuery ( options : std . Target . Query . ParseOptions ) error { ParseFailed } ! std . Target . Query {
2024-02-13 21:08:13 +01:00
assert ( options . diagnostics == null ) ;
2023-12-04 12:35:04 -07:00
var diags : Target . Query . ParseOptions . Diagnostics = . { } ;
2024-02-01 15:44:44 -07:00
var opts_copy = options ;
opts_copy . diagnostics = & diags ;
2024-02-13 21:08:13 +01:00
return std . Target . Query . parse ( opts_copy ) catch | err | switch ( err ) {
2023-01-31 00:19:51 -07:00
error . UnknownCpuModel = > {
2024-02-01 15:44:44 -07:00
std . debug . print ( " unknown CPU: '{s}' \n available CPUs for architecture '{s}': \n " , . {
diags . cpu_name .? , @tagName ( diags . arch .? ) ,
2023-01-31 00:19:51 -07:00
} ) ;
for ( diags . arch .? . allCpuModels ( ) ) | cpu | {
2024-02-01 15:44:44 -07:00
std . debug . print ( " {s} \n " , . { cpu . name } ) ;
2023-01-31 00:19:51 -07:00
}
2024-02-01 15:44:44 -07:00
return error . ParseFailed ;
2023-01-31 00:19:51 -07:00
} ,
error . UnknownCpuFeature = > {
2024-02-01 15:44:44 -07:00
std . debug . print (
\\unknown CPU feature: '{s}'
\\available CPU features for architecture '{s}':
2023-01-31 00:19:51 -07:00
\\
, . {
diags . unknown_feature_name .? ,
@tagName ( diags . arch .? ) ,
} ) ;
for ( diags . arch .? . allFeaturesList ( ) ) | feature | {
2024-02-01 15:44:44 -07:00
std . debug . print ( " {s}: {s} \n " , . { feature . name , feature . description } ) ;
2023-01-31 00:19:51 -07:00
}
2024-02-01 15:44:44 -07:00
return error . ParseFailed ;
2023-01-31 00:19:51 -07:00
} ,
error . UnknownOperatingSystem = > {
2024-02-01 15:44:44 -07:00
std . debug . print (
\\unknown OS: '{s}'
\\available operating systems:
2023-01-31 00:19:51 -07:00
\\
, . { diags . os_name .? } ) ;
2023-12-04 12:35:04 -07:00
inline for ( std . meta . fields ( Target . Os . Tag ) ) | field | {
2024-02-01 15:44:44 -07:00
std . debug . print ( " {s} \n " , . { field . name } ) ;
2023-01-31 00:19:51 -07:00
}
2024-02-01 15:44:44 -07:00
return error . ParseFailed ;
2023-01-31 00:19:51 -07:00
} ,
else = > | e | {
2024-02-01 15:44:44 -07:00
std . debug . print ( " unable to parse target '{s}': {s} \n " , . {
options . arch_os_abi , @errorName ( e ) ,
} ) ;
return error . ParseFailed ;
} ,
} ;
}
/// Exposes standard `zig build` options for choosing a target.
pub fn standardTargetOptionsQueryOnly ( b : * Build , args : StandardTargetOptionsArgs ) Target . Query {
const maybe_triple = b . option (
[ ] const u8 ,
" target " ,
" The CPU architecture, OS, and ABI to build for " ,
) ;
const mcpu = b . option (
[ ] const u8 ,
" cpu " ,
" Target CPU features to add or subtract " ,
) ;
2025-01-24 08:11:16 +01:00
const ofmt = b . option (
[ ] const u8 ,
" ofmt " ,
" Target object format " ,
) ;
2024-02-01 15:44:44 -07:00
const dynamic_linker = b . option (
[ ] const u8 ,
" dynamic-linker " ,
" Path to interpreter on the target system " ,
) ;
2025-01-24 08:11:16 +01:00
if ( maybe_triple == null and mcpu == null and ofmt == null and dynamic_linker == null )
2024-02-01 15:44:44 -07:00
return args . default_target ;
const triple = maybe_triple orelse " native " ;
const selected_target = parseTargetQuery ( . {
. arch_os_abi = triple ,
. cpu_features = mcpu ,
2025-01-24 08:11:16 +01:00
. object_format = ofmt ,
2024-02-01 15:44:44 -07:00
. dynamic_linker = dynamic_linker ,
} ) catch | err | switch ( err ) {
error . ParseFailed = > {
2023-12-04 20:30:32 -07:00
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
return args . default_target ;
} ,
} ;
2023-12-04 20:30:32 -07:00
const whitelist = args . whitelist orelse return selected_target ;
// Make sure it's a match of one of the list.
for ( whitelist ) | q | {
if ( q . eql ( selected_target ) )
return selected_target ;
2023-01-31 00:19:51 -07:00
}
2023-12-04 20:30:32 -07:00
for ( whitelist ) | q | {
log . info ( " allowed target: -Dtarget={s} -Dcpu={s} " , . {
q . zigTriple ( b . allocator ) catch @panic ( " OOM " ) ,
q . serializeCpuAlloc ( b . allocator ) catch @panic ( " OOM " ) ,
} ) ;
}
log . err ( " chosen target '{s}' does not match one of the allowed targets " , . {
selected_target . zigTriple ( b . allocator ) catch @panic ( " OOM " ) ,
} ) ;
b . markInvalidUserInput ( ) ;
return args . default_target ;
2023-01-31 00:19:51 -07:00
}
2024-12-26 00:17:56 +05:00
pub fn addUserInputOption ( b : * Build , name_raw : [ ] const u8 , value_raw : [ ] const u8 ) error { OutOfMemory } ! bool {
2024-05-04 14:29:17 -04:00
const name = b . dupe ( name_raw ) ;
const value = b . dupe ( value_raw ) ;
const gop = try b . user_input_options . getOrPut ( name ) ;
2023-01-31 00:19:51 -07:00
if ( ! gop . found_existing ) {
gop . value_ptr .* = UserInputOption {
. name = name ,
. value = . { . scalar = value } ,
. used = false ,
} ;
return false ;
}
// option already exists
switch ( gop . value_ptr . value ) {
. scalar = > | s | {
// turn it into a list
2025-07-31 21:54:07 -07:00
var list = std . array_list . Managed ( [ ] const u8 ) . init ( b . allocator ) ;
2023-01-31 14:02:32 -07:00
try list . append ( s ) ;
try list . append ( value ) ;
2024-05-04 14:29:17 -04:00
try b . user_input_options . put ( name , . {
2023-01-31 00:19:51 -07:00
. name = name ,
. value = . { . list = list } ,
. used = false ,
2023-01-31 14:02:32 -07:00
} ) ;
2023-01-31 00:19:51 -07:00
} ,
. list = > | * list | {
// append to the list
2023-01-31 14:02:32 -07:00
try list . append ( value ) ;
2024-05-04 14:29:17 -04:00
try b . user_input_options . put ( name , . {
2023-01-31 00:19:51 -07:00
. name = name ,
. value = . { . list = list .* } ,
. used = false ,
2023-01-31 14:02:32 -07:00
} ) ;
2023-01-31 00:19:51 -07:00
} ,
. flag = > {
2024-01-31 22:02:27 -07:00
log . warn ( " option '-D{s}={s}' conflicts with flag '-D{s}'. " , . { name , value , name } ) ;
2023-01-31 00:19:51 -07:00
return true ;
} ,
. map = > | * map | {
_ = map ;
log . warn ( " TODO maps as command line arguments is not implemented yet. " , . { } ) ;
return true ;
} ,
2024-10-05 00:58:48 +02:00
. lazy_path , . lazy_path_list = > {
2025-06-27 20:05:22 -07:00
log . warn ( " the lazy path value type isn't added from the CLI, but somehow '{s}' is a .{f} " , . { name , std . zig . fmtId ( @tagName ( gop . value_ptr . value ) ) } ) ;
2024-10-05 00:58:48 +02:00
return true ;
} ,
2023-01-31 00:19:51 -07:00
}
return false ;
}
2024-12-26 00:17:56 +05:00
pub fn addUserInputFlag ( b : * Build , name_raw : [ ] const u8 ) error { OutOfMemory } ! bool {
2024-05-04 14:29:17 -04:00
const name = b . dupe ( name_raw ) ;
const gop = try b . user_input_options . getOrPut ( name ) ;
2023-01-31 00:19:51 -07:00
if ( ! gop . found_existing ) {
gop . value_ptr .* = . {
. name = name ,
. value = . { . flag = { } } ,
. used = false ,
} ;
return false ;
}
// option already exists
switch ( gop . value_ptr . value ) {
. scalar = > | s | {
log . err ( " Flag '-D{s}' conflicts with option '-D{s}={s}'. " , . { name , name , s } ) ;
return true ;
} ,
2024-10-05 00:58:48 +02:00
. list , . map , . lazy_path_list = > {
2023-01-31 00:19:51 -07:00
log . err ( " Flag '-D{s}' conflicts with multiple options of the same name. " , . { name } ) ;
return true ;
} ,
2024-10-05 00:58:48 +02:00
. lazy_path = > | lp | {
log . err ( " Flag '-D{s}' conflicts with option '-D{s}={s}'. " , . { name , name , lp . getDisplayName ( ) } ) ;
return true ;
} ,
2023-01-31 00:19:51 -07:00
. flag = > { } ,
}
return false ;
}
fn typeToEnum ( comptime T : type ) TypeId {
2023-05-16 20:00:47 -07:00
return switch ( T ) {
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
std . zig . BuildId = > . build_id ,
2024-10-05 00:58:48 +02:00
LazyPath = > . lazy_path ,
2023-05-16 20:00:47 -07:00
else = > return switch ( @typeInfo ( T ) ) {
2024-08-28 02:35:53 +01:00
. int = > . int ,
. float = > . float ,
. bool = > . bool ,
. @" enum " = > . @" enum " ,
. pointer = > | pointer | switch ( pointer . child ) {
2024-06-06 06:02:42 +02:00
u8 = > . string ,
[ ] const u8 = > . list ,
2024-10-05 00:58:48 +02:00
LazyPath = > . lazy_path_list ,
2024-06-06 06:02:42 +02:00
else = > switch ( @typeInfo ( pointer . child ) ) {
2024-08-28 02:35:53 +01:00
. @" enum " = > . enum_list ,
2024-06-06 06:02:42 +02:00
else = > @compileError ( " Unsupported type: " ++ @typeName ( T ) ) ,
} ,
2023-05-16 20:00:47 -07:00
} ,
2024-06-06 06:02:42 +02:00
else = > @compileError ( " Unsupported type: " ++ @typeName ( T ) ) ,
2023-01-31 00:19:51 -07:00
} ,
} ;
}
2024-05-04 14:29:17 -04:00
fn markInvalidUserInput ( b : * Build ) void {
b . invalid_user_input = true ;
2023-01-31 00:19:51 -07:00
}
2024-01-31 22:02:27 -07:00
pub fn validateUserInputDidItFail ( b : * Build ) bool {
// Make sure all args are used.
var it = b . user_input_options . iterator ( ) ;
2023-01-31 00:19:51 -07:00
while ( it . next ( ) ) | entry | {
if ( ! entry . value_ptr . used ) {
2024-01-31 22:02:27 -07:00
log . err ( " invalid option: -D{s} " , . { entry . key_ptr .* } ) ;
b . markInvalidUserInput ( ) ;
2023-01-31 00:19:51 -07:00
}
}
2024-01-31 22:02:27 -07:00
return b . invalid_user_input ;
2023-01-31 00:19:51 -07:00
}
2023-07-29 23:57:52 -07:00
/// This creates the install step and adds it to the dependencies of the
/// top-level install step, using all the default options.
/// See `addInstallArtifact` for a more flexible function.
2024-05-04 14:29:17 -04:00
pub fn installArtifact ( b : * Build , artifact : * Step . Compile ) void {
b . getInstallStep ( ) . dependOn ( & b . addInstallArtifact ( artifact , . { } ) . step ) ;
2023-01-31 00:19:51 -07:00
}
2023-07-29 23:57:52 -07:00
/// This merely creates the step; it does not add it to the dependencies of the
/// top-level install step.
pub fn addInstallArtifact (
2024-05-04 14:29:17 -04:00
b : * Build ,
2023-07-29 23:57:52 -07:00
artifact : * Step . Compile ,
options : Step . InstallArtifact . Options ,
) * Step . InstallArtifact {
2024-05-04 14:29:17 -04:00
return Step . InstallArtifact . create ( b , artifact , options ) ;
2023-01-31 00:19:51 -07:00
}
///`dest_rel_path` is relative to prefix path
2024-04-11 14:02:47 -07:00
pub fn installFile ( b : * Build , src_path : [ ] const u8 , dest_rel_path : [ ] const u8 ) void {
b . getInstallStep ( ) . dependOn ( & b . addInstallFileWithDir ( b . path ( src_path ) , . prefix , dest_rel_path ) . step ) ;
2023-01-31 00:19:51 -07:00
}
2024-04-11 14:02:47 -07:00
pub fn installDirectory ( b : * Build , options : Step . InstallDir . Options ) void {
b . getInstallStep ( ) . dependOn ( & b . addInstallDirectory ( options ) . step ) ;
2023-01-31 00:19:51 -07:00
}
///`dest_rel_path` is relative to bin path
2024-04-11 14:02:47 -07:00
pub fn installBinFile ( b : * Build , src_path : [ ] const u8 , dest_rel_path : [ ] const u8 ) void {
b . getInstallStep ( ) . dependOn ( & b . addInstallFileWithDir ( b . path ( src_path ) , . bin , dest_rel_path ) . step ) ;
2023-01-31 00:19:51 -07:00
}
///`dest_rel_path` is relative to lib path
2024-04-11 14:02:47 -07:00
pub fn installLibFile ( b : * Build , src_path : [ ] const u8 , dest_rel_path : [ ] const u8 ) void {
b . getInstallStep ( ) . dependOn ( & b . addInstallFileWithDir ( b . path ( src_path ) , . lib , dest_rel_path ) . step ) ;
2023-01-31 00:19:51 -07:00
}
2023-07-19 10:49:34 +02:00
pub fn addObjCopy ( b : * Build , source : LazyPath , options : Step . ObjCopy . Options ) * Step . ObjCopy {
2023-05-03 11:49:55 +03:00
return Step . ObjCopy . create ( b , source , options ) ;
2023-01-31 00:19:51 -07:00
}
2024-03-10 12:17:33 +01:00
/// `dest_rel_path` is relative to install prefix path
2024-03-02 23:32:44 +01:00
pub fn addInstallFile ( b : * Build , source : LazyPath , dest_rel_path : [ ] const u8 ) * Step . InstallFile {
return b . addInstallFileWithDir ( source , . prefix , dest_rel_path ) ;
2023-01-31 00:19:51 -07:00
}
2024-03-10 12:17:33 +01:00
/// `dest_rel_path` is relative to bin path
2024-03-02 23:32:44 +01:00
pub fn addInstallBinFile ( b : * Build , source : LazyPath , dest_rel_path : [ ] const u8 ) * Step . InstallFile {
return b . addInstallFileWithDir ( source , . bin , dest_rel_path ) ;
2023-01-31 00:19:51 -07:00
}
2024-03-10 12:17:33 +01:00
/// `dest_rel_path` is relative to lib path
2024-03-02 23:32:44 +01:00
pub fn addInstallLibFile ( b : * Build , source : LazyPath , dest_rel_path : [ ] const u8 ) * Step . InstallFile {
return b . addInstallFileWithDir ( source , . lib , dest_rel_path ) ;
2023-01-31 00:19:51 -07:00
}
2024-03-10 12:17:33 +01:00
/// `dest_rel_path` is relative to header path
2024-03-02 23:32:44 +01:00
pub fn addInstallHeaderFile ( b : * Build , source : LazyPath , dest_rel_path : [ ] const u8 ) * Step . InstallFile {
return b . addInstallFileWithDir ( source , . header , dest_rel_path ) ;
2023-01-31 00:19:51 -07:00
}
pub fn addInstallFileWithDir (
2024-05-04 14:29:17 -04:00
b : * Build ,
2023-07-19 10:49:34 +02:00
source : LazyPath ,
2023-01-31 00:19:51 -07:00
install_dir : InstallDir ,
dest_rel_path : [ ] const u8 ,
2023-05-03 11:49:55 +03:00
) * Step . InstallFile {
2024-05-04 14:29:17 -04:00
return Step . InstallFile . create ( b , source , install_dir , dest_rel_path ) ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn addInstallDirectory ( b : * Build , options : Step . InstallDir . Options ) * Step . InstallDir {
return Step . InstallDir . create ( b , options ) ;
2023-01-31 00:19:51 -07:00
}
2023-03-06 22:44:36 -07:00
pub fn addCheckFile (
b : * Build ,
2023-07-19 10:49:34 +02:00
file_source : LazyPath ,
2023-05-03 11:49:55 +03:00
options : Step . CheckFile . Options ,
) * Step . CheckFile {
return Step . CheckFile . create ( b , file_source , options ) ;
2023-03-06 22:44:36 -07:00
}
2024-12-26 00:17:56 +05:00
pub fn truncateFile ( b : * Build , dest_path : [ ] const u8 ) ( fs . Dir . MakeError || fs . Dir . StatFileError ) ! void {
2024-05-04 14:29:17 -04:00
if ( b . verbose ) {
2023-01-31 00:19:51 -07:00
log . info ( " truncate {s} " , . { dest_path } ) ;
}
const cwd = fs . cwd ( ) ;
var src_file = cwd . createFile ( dest_path , . { } ) catch | err | switch ( err ) {
error . FileNotFound = > blk : {
if ( fs . path . dirname ( dest_path ) ) | dirname | {
try cwd . makePath ( dirname ) ;
}
break : blk try cwd . createFile ( dest_path , . { } ) ;
} ,
else = > | e | return e ,
} ;
src_file . close ( ) ;
}
2024-04-09 18:23:48 -07:00
/// References a file or directory relative to the source root.
pub fn path ( b : * Build , sub_path : [ ] const u8 ) LazyPath {
2024-04-11 14:02:47 -07:00
if ( fs . path . isAbsolute ( sub_path ) ) {
std . debug . panic ( " sub_path is expected to be relative to the build root, but was this absolute path: '{s}'. It is best avoid absolute paths, but if you must, it is supported by LazyPath.cwd_relative " , . {
sub_path ,
} ) ;
}
2024-04-09 18:23:48 -07:00
return . { . src_path = . {
. owner = b ,
. sub_path = sub_path ,
} } ;
}
/// This is low-level implementation details of the build system, not meant to
/// be called by users' build scripts. Even in the build system itself it is a
/// code smell to call this function.
2024-05-04 14:29:17 -04:00
pub fn pathFromRoot ( b : * Build , sub_path : [ ] const u8 ) [ ] u8 {
return b . pathResolve ( & . { b . build_root . path orelse " . " , sub_path } ) ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
fn pathFromCwd ( b : * Build , sub_path : [ ] const u8 ) [ ] u8 {
2023-07-30 18:19:39 -07:00
const cwd = process . getCwdAlloc ( b . allocator ) catch @panic ( " OOM " ) ;
2024-05-04 14:29:17 -04:00
return b . pathResolve ( & . { cwd , sub_path } ) ;
2023-07-30 18:19:39 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn pathJoin ( b : * Build , paths : [ ] const [ ] const u8 ) [ ] u8 {
return fs . path . join ( b . allocator , paths ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn pathResolve ( b : * Build , paths : [ ] const [ ] const u8 ) [ ] u8 {
return fs . path . resolve ( b . allocator , paths ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn fmt ( b : * Build , comptime format : [ ] const u8 , args : anytype ) [ ] u8 {
return std . fmt . allocPrint ( b . allocator , format , args ) catch @panic ( " OOM " ) ;
}
2024-06-18 07:08:12 +02:00
fn supportedWindowsProgramExtension ( ext : [ ] const u8 ) bool {
2024-08-28 02:35:53 +01:00
inline for ( @typeInfo ( std . process . Child . WindowsExtension ) . @" enum " . fields ) | field | {
2024-06-18 07:08:12 +02:00
if ( std . ascii . eqlIgnoreCase ( ext , " . " ++ field . name ) ) return true ;
}
return false ;
}
fn tryFindProgram ( b : * Build , full_path : [ ] const u8 ) ? [ ] const u8 {
if ( fs . realpathAlloc ( b . allocator , full_path ) ) | p | {
return p ;
} else | err | switch ( err ) {
error . OutOfMemory = > @panic ( " OOM " ) ,
else = > { } ,
}
if ( builtin . os . tag == . windows ) {
if ( b . graph . env_map . get ( " PATHEXT " ) ) | PATHEXT | {
var it = mem . tokenizeScalar ( u8 , PATHEXT , fs . path . delimiter ) ;
while ( it . next ( ) ) | ext | {
if ( ! supportedWindowsProgramExtension ( ext ) ) continue ;
return fs . realpathAlloc ( b . allocator , b . fmt ( " {s}{s} " , . { full_path , ext } ) ) catch | err | switch ( err ) {
error . OutOfMemory = > @panic ( " OOM " ) ,
else = > continue ,
} ;
}
}
}
return null ;
}
2024-12-26 00:17:56 +05:00
pub fn findProgram ( b : * Build , names : [ ] const [ ] const u8 , paths : [ ] const [ ] const u8 ) error { FileNotFound } ! [ ] const u8 {
2023-01-31 00:19:51 -07:00
// TODO report error for ambiguous situations
2024-05-04 14:29:17 -04:00
for ( b . search_prefixes . items ) | search_prefix | {
2023-01-31 00:19:51 -07:00
for ( names ) | name | {
if ( fs . path . isAbsolute ( name ) ) {
return name ;
}
2024-06-18 07:08:12 +02:00
return tryFindProgram ( b , b . pathJoin ( & . { search_prefix , " bin " , name } ) ) orelse continue ;
2023-01-31 00:19:51 -07:00
}
}
2024-05-04 14:29:17 -04:00
if ( b . graph . env_map . get ( " PATH " ) ) | PATH | {
2023-01-31 00:19:51 -07:00
for ( names ) | name | {
if ( fs . path . isAbsolute ( name ) ) {
return name ;
}
2023-05-04 18:05:40 -07:00
var it = mem . tokenizeScalar ( u8 , PATH , fs . path . delimiter ) ;
2024-04-09 18:23:48 -07:00
while ( it . next ( ) ) | p | {
2024-06-18 07:08:12 +02:00
return tryFindProgram ( b , b . pathJoin ( & . { p , name } ) ) orelse continue ;
2023-01-31 00:19:51 -07:00
}
}
}
for ( names ) | name | {
if ( fs . path . isAbsolute ( name ) ) {
return name ;
}
2024-04-09 18:23:48 -07:00
for ( paths ) | p | {
2024-06-18 07:08:12 +02:00
return tryFindProgram ( b , b . pathJoin ( & . { p , name } ) ) orelse continue ;
2023-01-31 00:19:51 -07:00
}
}
return error . FileNotFound ;
}
2023-10-19 22:36:11 +02:00
pub fn runAllowFail (
2024-05-04 14:29:17 -04:00
b : * Build ,
2023-01-31 00:19:51 -07:00
argv : [ ] const [ ] const u8 ,
out_code : * u8 ,
2024-05-23 11:25:41 -07:00
stderr_behavior : std . process . Child . StdIo ,
2023-10-19 22:36:11 +02:00
) RunError ! [ ] u8 {
2023-01-31 00:19:51 -07:00
assert ( argv . len != 0 ) ;
2023-02-14 12:47:45 -07:00
if ( ! process . can_spawn )
2023-01-31 00:19:51 -07:00
return error . ExecNotSupported ;
2025-10-07 22:31:06 -07:00
const io = b . graph . io ;
2023-01-31 00:19:51 -07:00
const max_output_size = 400 * 1024 ;
2024-05-23 11:25:41 -07:00
var child = std . process . Child . init ( argv , b . allocator ) ;
2023-01-31 00:19:51 -07:00
child . stdin_behavior = . Ignore ;
child . stdout_behavior = . Pipe ;
child . stderr_behavior = stderr_behavior ;
2024-05-04 14:29:17 -04:00
child . env_map = & b . graph . env_map ;
2023-01-31 00:19:51 -07:00
2024-08-23 21:46:36 -07:00
try Step . handleVerbose2 ( b , null , child . env_map , argv ) ;
2023-01-31 00:19:51 -07:00
try child . spawn ( ) ;
2025-10-07 22:31:06 -07:00
var stdout_reader = child . stdout .? . readerStreaming ( io , & . { } ) ;
2025-08-27 21:20:18 -07:00
const stdout = stdout_reader . interface . allocRemaining ( b . allocator , . limited ( max_output_size ) ) catch {
2023-01-31 00:19:51 -07:00
return error . ReadFailure ;
} ;
2024-05-04 14:29:17 -04:00
errdefer b . allocator . free ( stdout ) ;
2023-01-31 00:19:51 -07:00
const term = try child . wait ( ) ;
switch ( term ) {
. Exited = > | code | {
if ( code != 0 ) {
2023-06-22 18:46:56 +01:00
out_code .* = @as ( u8 , @truncate ( code ) ) ;
2023-01-31 00:19:51 -07:00
return error . ExitCodeFailure ;
}
return stdout ;
} ,
. Signal , . Stopped , . Unknown = > | code | {
2023-06-22 18:46:56 +01:00
out_code .* = @as ( u8 , @truncate ( code ) ) ;
2023-01-31 00:19:51 -07:00
return error . ProcessTerminated ;
} ,
}
}
2023-02-14 02:53:05 -07:00
/// This is a helper function to be called from build.zig scripts, *not* from
/// inside step make() functions. If any errors occur, it fails the build with
/// a helpful message.
2023-10-19 22:36:11 +02:00
pub fn run ( b : * Build , argv : [ ] const [ ] const u8 ) [ ] u8 {
2023-02-14 12:47:45 -07:00
if ( ! process . can_spawn ) {
2023-02-28 17:15:06 -07:00
std . debug . print ( " unable to spawn the following command: cannot spawn child process \n {s} \n " , . {
2025-08-26 16:28:42 +01:00
try Step . allocPrintCmd ( b . allocator , null , argv ) ,
2023-02-14 02:53:05 -07:00
} ) ;
process . exit ( 1 ) ;
}
var code : u8 = undefined ;
2023-10-19 22:36:11 +02:00
return b . runAllowFail ( argv , & code , . Inherit ) catch | err | {
2025-08-26 16:28:42 +01:00
const printed_cmd = Step . allocPrintCmd ( b . allocator , null , argv ) catch @panic ( " OOM " ) ;
2023-02-28 17:15:06 -07:00
std . debug . print ( " unable to spawn the following command: {s} \n {s} \n " , . {
2023-02-14 02:53:05 -07:00
@errorName ( err ) , printed_cmd ,
} ) ;
process . exit ( 1 ) ;
} ;
2023-01-31 00:19:51 -07:00
}
2024-02-01 15:44:44 -07:00
pub fn addSearchPrefix ( b : * Build , search_prefix : [ ] const u8 ) void {
b . search_prefixes . append ( b . allocator , b . dupePath ( search_prefix ) ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
}
2024-05-04 14:29:17 -04:00
pub fn getInstallPath ( b : * Build , dir : InstallDir , dest_rel_path : [ ] const u8 ) [ ] const u8 {
2023-01-31 00:19:51 -07:00
assert ( ! fs . path . isAbsolute ( dest_rel_path ) ) ; // Install paths must be relative to the prefix
const base_dir = switch ( dir ) {
2024-05-04 14:29:17 -04:00
. prefix = > b . install_path ,
. bin = > b . exe_dir ,
. lib = > b . lib_dir ,
. header = > b . h_dir ,
. custom = > | p | b . pathJoin ( & . { b . install_path , p } ) ,
2023-01-31 00:19:51 -07:00
} ;
2024-05-04 14:29:17 -04:00
return b . pathResolve ( & . { base_dir , dest_rel_path } ) ;
2023-01-31 00:19:51 -07:00
}
pub const Dependency = struct {
builder : * Build ,
2023-05-03 11:49:55 +03:00
pub fn artifact ( d : * Dependency , name : [ ] const u8 ) * Step . Compile {
var found : ? * Step . Compile = null ;
2023-01-31 00:19:51 -07:00
for ( d . builder . install_tls . step . dependencies . items ) | dep_step | {
2023-05-03 11:49:55 +03:00
const inst = dep_step . cast ( Step . InstallArtifact ) orelse continue ;
2023-01-31 00:19:51 -07:00
if ( mem . eql ( u8 , inst . artifact . name , name ) ) {
if ( found != null ) panic ( " artifact name '{s}' is ambiguous " , . { name } ) ;
found = inst . artifact ;
}
}
return found orelse {
for ( d . builder . install_tls . step . dependencies . items ) | dep_step | {
2023-05-03 11:49:55 +03:00
const inst = dep_step . cast ( Step . InstallArtifact ) orelse continue ;
2023-01-31 00:19:51 -07:00
log . info ( " available artifact: '{s}' " , . { inst . artifact . name } ) ;
}
panic ( " unable to find artifact '{s}' " , . { name } ) ;
} ;
}
2023-02-03 17:22:31 -07:00
pub fn module ( d : * Dependency , name : [ ] const u8 ) * Module {
return d . builder . modules . get ( name ) orelse {
panic ( " unable to find module '{s}' " , . { name } ) ;
} ;
}
2023-09-17 19:38:19 +02:00
2023-10-22 16:10:01 +02:00
pub fn namedWriteFiles ( d : * Dependency , name : [ ] const u8 ) * Step . WriteFile {
return d . builder . named_writefiles . get ( name ) orelse {
panic ( " unable to find named writefiles '{s}' " , . { name } ) ;
} ;
}
2024-09-11 09:06:54 +01:00
pub fn namedLazyPath ( d : * Dependency , name : [ ] const u8 ) LazyPath {
return d . builder . named_lazy_paths . get ( name ) orelse {
panic ( " unable to find named lazypath '{s}' " , . { name } ) ;
} ;
}
2023-09-17 19:38:19 +02:00
pub fn path ( d : * Dependency , sub_path : [ ] const u8 ) LazyPath {
return . {
. dependency = . {
. dependency = d ,
. sub_path = sub_path ,
} ,
} ;
}
2023-01-31 00:19:51 -07:00
} ;
build system: implement lazy dependencies, part 1
Build manifest files support `lazy: true` for dependency sections.
This causes the auto-generated dependencies.zig to have 2 more
possibilities:
1. It communicates whether a dependency is lazy or not.
2. The dependency might be acknowledged, but missing due to being lazy
and not fetched.
Lazy dependencies are not fetched by default, but if they are already
fetched then they are provided to the build script.
The build runner reports the set of missing lazy dependenices that are
required to the parent process via stdout and indicates the situation
with exit code 3.
std.Build now has a `lazyDependency` function. I'll let the doc comments
speak for themselves:
When this function is called, it means that the current build does, in
fact, require this dependency. If the dependency is already fetched, it
proceeds in the same manner as `dependency`. However if the dependency
was not fetched, then when the build script is finished running, the
build will not proceed to the make phase. Instead, the parent process
will additionally fetch all the lazy dependencies that were actually
required by running the build script, rebuild the build script, and then
run it again.
In other words, if this function returns `null` it means that the only
purpose of completing the configure phase is to find out all the other
lazy dependencies that are also required.
It is allowed to use this function for non-lazy dependencies, in which
case it will never return `null`. This allows toggling laziness via
build.zig.zon without changing build.zig logic.
The CLI for `zig build` detects this situation, but the logic for then
redoing the build process with these extra dependencies fetched is not
yet implemented.
2024-02-02 14:42:29 -07:00
fn findPkgHashOrFatal ( b : * Build , name : [ ] const u8 ) [ ] const u8 {
for ( b . available_deps ) | dep | {
if ( mem . eql ( u8 , dep [ 0 ] , name ) ) return dep [ 1 ] ;
}
const full_path = b . pathFromRoot ( " build.zig.zon " ) ;
std . debug . panic ( " no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file " , . { name , full_path } ) ;
}
2024-02-18 19:56:34 +01:00
inline fn findImportPkgHashOrFatal ( b : * Build , comptime asking_build_zig : type , comptime dep_name : [ ] const u8 ) [ ] const u8 {
const build_runner = @import ( " root " ) ;
const deps = build_runner . dependencies ;
2024-08-28 02:35:53 +01:00
const b_pkg_hash , const b_pkg_deps = comptime for ( @typeInfo ( deps . packages ) . @" struct " . decls ) | decl | {
2024-02-18 19:56:34 +01:00
const pkg_hash = decl . name ;
const pkg = @field ( deps . packages , pkg_hash ) ;
if ( @hasDecl ( pkg , " build_zig " ) and pkg . build_zig == asking_build_zig ) break . { pkg_hash , pkg . deps } ;
} else . { " " , deps . root_deps } ;
if ( ! std . mem . eql ( u8 , b_pkg_hash , b . pkg_hash ) ) {
std . debug . panic ( " '{}' is not the struct that corresponds to '{s}' " , . { asking_build_zig , b . pathFromRoot ( " build.zig " ) } ) ;
}
comptime for ( b_pkg_deps ) | dep | {
if ( std . mem . eql ( u8 , dep [ 0 ] , dep_name ) ) return dep [ 1 ] ;
} ;
const full_path = b . pathFromRoot ( " build.zig.zon " ) ;
std . debug . panic ( " no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file " , . { dep_name , full_path } ) ;
}
build system: implement lazy dependencies, part 1
Build manifest files support `lazy: true` for dependency sections.
This causes the auto-generated dependencies.zig to have 2 more
possibilities:
1. It communicates whether a dependency is lazy or not.
2. The dependency might be acknowledged, but missing due to being lazy
and not fetched.
Lazy dependencies are not fetched by default, but if they are already
fetched then they are provided to the build script.
The build runner reports the set of missing lazy dependenices that are
required to the parent process via stdout and indicates the situation
with exit code 3.
std.Build now has a `lazyDependency` function. I'll let the doc comments
speak for themselves:
When this function is called, it means that the current build does, in
fact, require this dependency. If the dependency is already fetched, it
proceeds in the same manner as `dependency`. However if the dependency
was not fetched, then when the build script is finished running, the
build will not proceed to the make phase. Instead, the parent process
will additionally fetch all the lazy dependencies that were actually
required by running the build script, rebuild the build script, and then
run it again.
In other words, if this function returns `null` it means that the only
purpose of completing the configure phase is to find out all the other
lazy dependencies that are also required.
It is allowed to use this function for non-lazy dependencies, in which
case it will never return `null`. This allows toggling laziness via
build.zig.zon without changing build.zig logic.
The CLI for `zig build` detects this situation, but the logic for then
redoing the build process with these extra dependencies fetched is not
yet implemented.
2024-02-02 14:42:29 -07:00
fn markNeededLazyDep ( b : * Build , pkg_hash : [ ] const u8 ) void {
b . graph . needed_lazy_dependencies . put ( b . graph . arena , pkg_hash , { } ) catch @panic ( " OOM " ) ;
}
/// When this function is called, it means that the current build does, in
/// fact, require this dependency. If the dependency is already fetched, it
/// proceeds in the same manner as `dependency`. However if the dependency was
/// not fetched, then when the build script is finished running, the build will
/// not proceed to the make phase. Instead, the parent process will
/// additionally fetch all the lazy dependencies that were actually required by
/// running the build script, rebuild the build script, and then run it again.
/// In other words, if this function returns `null` it means that the only
/// purpose of completing the configure phase is to find out all the other lazy
/// dependencies that are also required.
/// It is allowed to use this function for non-lazy dependencies, in which case
/// it will never return `null`. This allows toggling laziness via
/// build.zig.zon without changing build.zig logic.
pub fn lazyDependency ( b : * Build , name : [ ] const u8 , args : anytype ) ? * Dependency {
2023-01-31 00:19:51 -07:00
const build_runner = @import ( " root " ) ;
const deps = build_runner . dependencies ;
build system: implement lazy dependencies, part 1
Build manifest files support `lazy: true` for dependency sections.
This causes the auto-generated dependencies.zig to have 2 more
possibilities:
1. It communicates whether a dependency is lazy or not.
2. The dependency might be acknowledged, but missing due to being lazy
and not fetched.
Lazy dependencies are not fetched by default, but if they are already
fetched then they are provided to the build script.
The build runner reports the set of missing lazy dependenices that are
required to the parent process via stdout and indicates the situation
with exit code 3.
std.Build now has a `lazyDependency` function. I'll let the doc comments
speak for themselves:
When this function is called, it means that the current build does, in
fact, require this dependency. If the dependency is already fetched, it
proceeds in the same manner as `dependency`. However if the dependency
was not fetched, then when the build script is finished running, the
build will not proceed to the make phase. Instead, the parent process
will additionally fetch all the lazy dependencies that were actually
required by running the build script, rebuild the build script, and then
run it again.
In other words, if this function returns `null` it means that the only
purpose of completing the configure phase is to find out all the other
lazy dependencies that are also required.
It is allowed to use this function for non-lazy dependencies, in which
case it will never return `null`. This allows toggling laziness via
build.zig.zon without changing build.zig logic.
The CLI for `zig build` detects this situation, but the logic for then
redoing the build process with these extra dependencies fetched is not
yet implemented.
2024-02-02 14:42:29 -07:00
const pkg_hash = findPkgHashOrFatal ( b , name ) ;
2023-01-31 00:19:51 -07:00
2024-08-28 02:35:53 +01:00
inline for ( @typeInfo ( deps . packages ) . @" struct " . decls ) | decl | {
build system: implement lazy dependencies, part 1
Build manifest files support `lazy: true` for dependency sections.
This causes the auto-generated dependencies.zig to have 2 more
possibilities:
1. It communicates whether a dependency is lazy or not.
2. The dependency might be acknowledged, but missing due to being lazy
and not fetched.
Lazy dependencies are not fetched by default, but if they are already
fetched then they are provided to the build script.
The build runner reports the set of missing lazy dependenices that are
required to the parent process via stdout and indicates the situation
with exit code 3.
std.Build now has a `lazyDependency` function. I'll let the doc comments
speak for themselves:
When this function is called, it means that the current build does, in
fact, require this dependency. If the dependency is already fetched, it
proceeds in the same manner as `dependency`. However if the dependency
was not fetched, then when the build script is finished running, the
build will not proceed to the make phase. Instead, the parent process
will additionally fetch all the lazy dependencies that were actually
required by running the build script, rebuild the build script, and then
run it again.
In other words, if this function returns `null` it means that the only
purpose of completing the configure phase is to find out all the other
lazy dependencies that are also required.
It is allowed to use this function for non-lazy dependencies, in which
case it will never return `null`. This allows toggling laziness via
build.zig.zon without changing build.zig logic.
The CLI for `zig build` detects this situation, but the logic for then
redoing the build process with these extra dependencies fetched is not
yet implemented.
2024-02-02 14:42:29 -07:00
if ( mem . eql ( u8 , decl . name , pkg_hash ) ) {
const pkg = @field ( deps . packages , decl . name ) ;
const available = ! @hasDecl ( pkg , " available " ) or pkg . available ;
if ( ! available ) {
markNeededLazyDep ( b , pkg_hash ) ;
return null ;
}
2024-02-18 19:56:34 +01:00
return dependencyInner ( b , name , pkg . build_root , if ( @hasDecl ( pkg , " build_zig " ) ) pkg . build_zig else null , pkg_hash , pkg . deps , args ) ;
build system: implement lazy dependencies, part 1
Build manifest files support `lazy: true` for dependency sections.
This causes the auto-generated dependencies.zig to have 2 more
possibilities:
1. It communicates whether a dependency is lazy or not.
2. The dependency might be acknowledged, but missing due to being lazy
and not fetched.
Lazy dependencies are not fetched by default, but if they are already
fetched then they are provided to the build script.
The build runner reports the set of missing lazy dependenices that are
required to the parent process via stdout and indicates the situation
with exit code 3.
std.Build now has a `lazyDependency` function. I'll let the doc comments
speak for themselves:
When this function is called, it means that the current build does, in
fact, require this dependency. If the dependency is already fetched, it
proceeds in the same manner as `dependency`. However if the dependency
was not fetched, then when the build script is finished running, the
build will not proceed to the make phase. Instead, the parent process
will additionally fetch all the lazy dependencies that were actually
required by running the build script, rebuild the build script, and then
run it again.
In other words, if this function returns `null` it means that the only
purpose of completing the configure phase is to find out all the other
lazy dependencies that are also required.
It is allowed to use this function for non-lazy dependencies, in which
case it will never return `null`. This allows toggling laziness via
build.zig.zon without changing build.zig logic.
The CLI for `zig build` detects this situation, but the logic for then
redoing the build process with these extra dependencies fetched is not
yet implemented.
2024-02-02 14:42:29 -07:00
}
}
unreachable ; // Bad @dependencies source
}
pub fn dependency ( b : * Build , name : [ ] const u8 , args : anytype ) * Dependency {
const build_runner = @import ( " root " ) ;
const deps = build_runner . dependencies ;
const pkg_hash = findPkgHashOrFatal ( b , name ) ;
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
2024-08-28 02:35:53 +01:00
inline for ( @typeInfo ( deps . packages ) . @" struct " . decls ) | decl | {
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
if ( mem . eql ( u8 , decl . name , pkg_hash ) ) {
const pkg = @field ( deps . packages , decl . name ) ;
build system: implement lazy dependencies, part 1
Build manifest files support `lazy: true` for dependency sections.
This causes the auto-generated dependencies.zig to have 2 more
possibilities:
1. It communicates whether a dependency is lazy or not.
2. The dependency might be acknowledged, but missing due to being lazy
and not fetched.
Lazy dependencies are not fetched by default, but if they are already
fetched then they are provided to the build script.
The build runner reports the set of missing lazy dependenices that are
required to the parent process via stdout and indicates the situation
with exit code 3.
std.Build now has a `lazyDependency` function. I'll let the doc comments
speak for themselves:
When this function is called, it means that the current build does, in
fact, require this dependency. If the dependency is already fetched, it
proceeds in the same manner as `dependency`. However if the dependency
was not fetched, then when the build script is finished running, the
build will not proceed to the make phase. Instead, the parent process
will additionally fetch all the lazy dependencies that were actually
required by running the build script, rebuild the build script, and then
run it again.
In other words, if this function returns `null` it means that the only
purpose of completing the configure phase is to find out all the other
lazy dependencies that are also required.
It is allowed to use this function for non-lazy dependencies, in which
case it will never return `null`. This allows toggling laziness via
build.zig.zon without changing build.zig logic.
The CLI for `zig build` detects this situation, but the logic for then
redoing the build process with these extra dependencies fetched is not
yet implemented.
2024-02-02 14:42:29 -07:00
if ( @hasDecl ( pkg , " available " ) ) {
2024-02-02 20:35:14 -07:00
std . debug . panic ( " dependency '{s}{s}' is marked as lazy in build.zig.zon which means it must use the lazyDependency function instead " , . { b . dep_prefix , name } ) ;
build system: implement lazy dependencies, part 1
Build manifest files support `lazy: true` for dependency sections.
This causes the auto-generated dependencies.zig to have 2 more
possibilities:
1. It communicates whether a dependency is lazy or not.
2. The dependency might be acknowledged, but missing due to being lazy
and not fetched.
Lazy dependencies are not fetched by default, but if they are already
fetched then they are provided to the build script.
The build runner reports the set of missing lazy dependenices that are
required to the parent process via stdout and indicates the situation
with exit code 3.
std.Build now has a `lazyDependency` function. I'll let the doc comments
speak for themselves:
When this function is called, it means that the current build does, in
fact, require this dependency. If the dependency is already fetched, it
proceeds in the same manner as `dependency`. However if the dependency
was not fetched, then when the build script is finished running, the
build will not proceed to the make phase. Instead, the parent process
will additionally fetch all the lazy dependencies that were actually
required by running the build script, rebuild the build script, and then
run it again.
In other words, if this function returns `null` it means that the only
purpose of completing the configure phase is to find out all the other
lazy dependencies that are also required.
It is allowed to use this function for non-lazy dependencies, in which
case it will never return `null`. This allows toggling laziness via
build.zig.zon without changing build.zig logic.
The CLI for `zig build` detects this situation, but the logic for then
redoing the build process with these extra dependencies fetched is not
yet implemented.
2024-02-02 14:42:29 -07:00
}
2024-02-18 19:56:34 +01:00
return dependencyInner ( b , name , pkg . build_root , if ( @hasDecl ( pkg , " build_zig " ) ) pkg . build_zig else null , pkg_hash , pkg . deps , args ) ;
2023-01-31 00:19:51 -07:00
}
}
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
unreachable ; // Bad @dependencies source
2023-01-31 00:19:51 -07:00
}
2024-02-18 19:56:34 +01:00
/// In a build.zig file, this function is to `@import` what `lazyDependency` is to `dependency`.
/// If the dependency is lazy and has not yet been fetched, it instructs the parent process to fetch
/// that dependency after the build script has finished running, then returns `null`.
/// If the dependency is lazy but has already been fetched, or if it is eager, it returns
/// the build.zig struct of that dependency, just like a regular `@import`.
pub inline fn lazyImport (
b : * Build ,
/// The build.zig struct of the package importing the dependency.
/// When calling this function from the `build` function of a build.zig file's, you normally
/// pass `@This()`.
comptime asking_build_zig : type ,
comptime dep_name : [ ] const u8 ,
) ? type {
const build_runner = @import ( " root " ) ;
const deps = build_runner . dependencies ;
const pkg_hash = findImportPkgHashOrFatal ( b , asking_build_zig , dep_name ) ;
2024-08-28 02:35:53 +01:00
inline for ( @typeInfo ( deps . packages ) . @" struct " . decls ) | decl | {
2024-02-18 19:56:34 +01:00
if ( comptime mem . eql ( u8 , decl . name , pkg_hash ) ) {
const pkg = @field ( deps . packages , decl . name ) ;
const available = ! @hasDecl ( pkg , " available " ) or pkg . available ;
if ( ! available ) {
markNeededLazyDep ( b , pkg_hash ) ;
return null ;
}
return if ( @hasDecl ( pkg , " build_zig " ) )
pkg . build_zig
else
@compileError ( " dependency ' " ++ dep_name ++ " ' does not have a build.zig " ) ;
}
}
comptime unreachable ; // Bad @dependencies source
}
2024-02-13 00:02:52 +01:00
pub fn dependencyFromBuildZig (
b : * Build ,
/// The build.zig struct of the dependency, normally obtained by `@import` of the dependency.
/// If called from the build.zig file itself, use `@This` to obtain a reference to the struct.
comptime build_zig : type ,
args : anytype ,
) * Dependency {
const build_runner = @import ( " root " ) ;
const deps = build_runner . dependencies ;
find_dep : {
2024-08-28 02:35:53 +01:00
const pkg , const pkg_hash = inline for ( @typeInfo ( deps . packages ) . @" struct " . decls ) | decl | {
2024-02-13 00:02:52 +01:00
const pkg_hash = decl . name ;
const pkg = @field ( deps . packages , pkg_hash ) ;
if ( @hasDecl ( pkg , " build_zig " ) and pkg . build_zig == build_zig ) break . { pkg , pkg_hash } ;
} else break : find_dep ;
const dep_name = for ( b . available_deps ) | dep | {
if ( mem . eql ( u8 , dep [ 1 ] , pkg_hash ) ) break dep [ 1 ] ;
} else break : find_dep ;
2024-04-18 03:07:44 -07:00
return dependencyInner ( b , dep_name , pkg . build_root , pkg . build_zig , pkg_hash , pkg . deps , args ) ;
2024-02-13 00:02:52 +01:00
}
const full_path = b . pathFromRoot ( " build.zig.zon " ) ;
2024-07-10 00:25:42 +03:00
debug . panic ( " '{}' is not a build.zig struct of a dependency in '{s}' " , . { build_zig , full_path } ) ;
2024-02-13 00:02:52 +01:00
}
2023-08-10 15:32:55 -07:00
fn userValuesAreSame ( lhs : UserValue , rhs : UserValue ) bool {
2024-10-05 00:58:48 +02:00
if ( std . meta . activeTag ( lhs ) != rhs ) return false ;
2023-08-10 15:32:55 -07:00
switch ( lhs ) {
. flag = > { } ,
. scalar = > | lhs_scalar | {
2024-10-05 00:58:48 +02:00
const rhs_scalar = rhs . scalar ;
2023-08-10 15:32:55 -07:00
if ( ! std . mem . eql ( u8 , lhs_scalar , rhs_scalar ) )
return false ;
} ,
. list = > | lhs_list | {
2024-10-05 00:58:48 +02:00
const rhs_list = rhs . list ;
2023-08-10 15:32:55 -07:00
if ( lhs_list . items . len != rhs_list . items . len )
return false ;
for ( lhs_list . items , rhs_list . items ) | lhs_list_entry , rhs_list_entry | {
if ( ! std . mem . eql ( u8 , lhs_list_entry , rhs_list_entry ) )
return false ;
}
} ,
. map = > | lhs_map | {
2024-10-05 00:58:48 +02:00
const rhs_map = rhs . map ;
2023-08-10 15:32:55 -07:00
if ( lhs_map . count ( ) != rhs_map . count ( ) )
return false ;
var lhs_it = lhs_map . iterator ( ) ;
while ( lhs_it . next ( ) ) | lhs_entry | {
const rhs_value = rhs_map . get ( lhs_entry . key_ptr .* ) orelse return false ;
if ( ! userValuesAreSame ( lhs_entry . value_ptr .* .* , rhs_value .* ) )
return false ;
}
} ,
2024-10-05 00:58:48 +02:00
. lazy_path = > | lhs_lp | {
const rhs_lp = rhs . lazy_path ;
return userLazyPathsAreTheSame ( lhs_lp , rhs_lp ) ;
} ,
. lazy_path_list = > | lhs_lp_list | {
const rhs_lp_list = rhs . lazy_path_list ;
if ( lhs_lp_list . items . len != rhs_lp_list . items . len ) return false ;
for ( lhs_lp_list . items , rhs_lp_list . items ) | lhs_lp , rhs_lp | {
if ( ! userLazyPathsAreTheSame ( lhs_lp , rhs_lp ) ) return false ;
}
return true ;
} ,
2023-08-10 15:32:55 -07:00
}
return true ;
}
2024-10-05 00:58:48 +02:00
fn userLazyPathsAreTheSame ( lhs_lp : LazyPath , rhs_lp : LazyPath ) bool {
if ( std . meta . activeTag ( lhs_lp ) != rhs_lp ) return false ;
switch ( lhs_lp ) {
. src_path = > | lhs_sp | {
const rhs_sp = rhs_lp . src_path ;
if ( lhs_sp . owner != rhs_sp . owner ) return false ;
if ( std . mem . eql ( u8 , lhs_sp . sub_path , rhs_sp . sub_path ) ) return false ;
} ,
. generated = > | lhs_gen | {
const rhs_gen = rhs_lp . generated ;
if ( lhs_gen . file != rhs_gen . file ) return false ;
if ( lhs_gen . up != rhs_gen . up ) return false ;
if ( std . mem . eql ( u8 , lhs_gen . sub_path , rhs_gen . sub_path ) ) return false ;
} ,
. cwd_relative = > | lhs_rel_path | {
const rhs_rel_path = rhs_lp . cwd_relative ;
if ( ! std . mem . eql ( u8 , lhs_rel_path , rhs_rel_path ) ) return false ;
} ,
. dependency = > | lhs_dep | {
const rhs_dep = rhs_lp . dependency ;
if ( lhs_dep . dependency != rhs_dep . dependency ) return false ;
if ( ! std . mem . eql ( u8 , lhs_dep . sub_path , rhs_dep . sub_path ) ) return false ;
} ,
}
return true ;
}
2024-02-17 17:51:16 +01:00
fn dependencyInner (
2023-01-31 00:19:51 -07:00
b : * Build ,
name : [ ] const u8 ,
2023-02-09 10:01:01 -07:00
build_root_string : [ ] const u8 ,
2023-09-17 19:38:19 +02:00
comptime build_zig : ? type ,
2024-02-18 19:56:34 +01:00
pkg_hash : [ ] const u8 ,
package manager: write deps in a flat format, eliminating the FQN concept
The new `@depedencies` module contains generated code like the
following (where strings like "abc123" represent hashes):
```zig
pub const root_deps = [_]struct { []const u8, []const u8 }{
.{ "foo", "abc123" },
};
pub const packages = struct {
pub const abc123 = struct {
pub const build_root = "/home/mlugg/.cache/zig/blah/abc123";
pub const build_zig = @import("abc123");
pub const deps = [_]struct { []const u8, []const u8 }{
.{ "bar", "abc123" },
.{ "name", "ghi789" },
};
};
};
```
Each package contains a build root string, the build.zig import, and a
mapping from dependency names to package hashes. There is also such a
mapping for the root package dependencies.
In theory, we could now remove the `dep_prefix` field from `std.Build`,
since its main purpose is now handled differently. I believe this is a
desirable goal, as it doesn't really make sense to assign a single FQN
to any package (because it may appear in many different places in the
package hierarchy). This commit does not remove that field, as it's used
non-trivially in a few places in the build runner and compiler tests:
this will be a future enhancement.
Resolves: #16354
Resolves: #17135
2023-09-13 10:46:25 +01:00
pkg_deps : AvailableDeps ,
2023-01-31 00:19:51 -07:00
args : anytype ,
) * Dependency {
2023-08-10 15:32:55 -07:00
const user_input_options = userInputOptionsFromArgs ( b . allocator , args ) ;
2024-09-27 09:44:44 -06:00
if ( b . graph . dependency_cache . getContext ( . {
2023-08-10 15:32:55 -07:00
. build_root_string = build_root_string ,
. user_input_options = user_input_options ,
2024-09-27 09:44:44 -06:00
} , . { . allocator = b . graph . arena } ) ) | dep |
2023-04-22 18:15:19 +01:00
return dep ;
2023-02-09 10:01:01 -07:00
const build_root : std . Build . Cache . Directory = . {
. path = build_root_string ,
2024-04-09 18:23:48 -07:00
. handle = fs . cwd ( ) . openDir ( build_root_string , . { } ) catch | err | {
2023-02-09 10:01:01 -07:00
std . debug . print ( " unable to open '{s}': {s} \n " , . {
build_root_string , @errorName ( err ) ,
} ) ;
2023-02-14 12:47:45 -07:00
process . exit ( 1 ) ;
2023-02-09 10:01:01 -07:00
} ,
} ;
2023-09-17 19:38:19 +02:00
2024-02-18 19:56:34 +01:00
const sub_builder = b . createChild ( name , build_root , pkg_hash , pkg_deps , user_input_options ) catch @panic ( " unhandled error " ) ;
2023-09-17 19:38:19 +02:00
if ( build_zig ) | bz | {
sub_builder . runBuild ( bz ) catch @panic ( " unhandled error " ) ;
2023-01-31 00:19:51 -07:00
2023-09-17 19:38:19 +02:00
if ( sub_builder . validateUserInputDidItFail ( ) ) {
2025-09-05 20:40:11 +01:00
std . debug . dumpCurrentStackTrace ( . { . first_address = @returnAddress ( ) } ) ;
2023-09-17 19:38:19 +02:00
}
2023-01-31 00:19:51 -07:00
}
2023-01-31 14:02:32 -07:00
const dep = b . allocator . create ( Dependency ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
dep .* = . { . builder = sub_builder } ;
2023-04-22 18:15:19 +01:00
2024-09-27 09:44:44 -06:00
b . graph . dependency_cache . putContext ( b . graph . arena , . {
2023-08-10 15:32:55 -07:00
. build_root_string = build_root_string ,
. user_input_options = user_input_options ,
2024-09-27 09:44:44 -06:00
} , dep , . { . allocator = b . graph . arena } ) catch @panic ( " OOM " ) ;
2023-01-31 00:19:51 -07:00
return dep ;
}
pub fn runBuild ( b : * Build , build_zig : anytype ) anyerror ! void {
2024-08-28 02:35:53 +01:00
switch ( @typeInfo ( @typeInfo ( @TypeOf ( build_zig . build ) ) . @" fn " . return_type .? ) ) {
. void = > build_zig . build ( b ) ,
. error_union = > try build_zig . build ( b ) ,
2023-01-31 00:19:51 -07:00
else = > @compileError ( " expected return type of build to be 'void' or '!void' " ) ,
}
}
/// 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 {
/// The step that generates the file
step : * Step ,
2025-05-22 03:26:11 +01:00
/// The path to the generated file. Must be either absolute or relative to the build runner cwd.
2023-01-31 00:19:51 -07:00
/// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards.
path : ? [ ] const u8 = null ,
2025-06-13 12:01:59 -04:00
/// Deprecated, see `getPath2`.
2024-05-04 14:29:17 -04:00
pub fn getPath ( gen : GeneratedFile ) [ ] const u8 {
2025-05-22 03:26:11 +01:00
return gen . step . owner . pathFromCwd ( gen . path orelse std . debug . panic (
2023-02-14 12:47:45 -07:00
" getPath() was called on a GeneratedFile that wasn't built yet. Is there a missing Step dependency on step '{s}'? " ,
2024-05-04 14:29:17 -04:00
. { gen . step . name } ,
) ) ;
2023-01-31 00:19:51 -07:00
}
2025-06-13 12:01:59 -04:00
pub fn getPath2 ( gen : GeneratedFile , src_builder : * Build , asking_step : ? * Step ) [ ] const u8 {
return gen . path orelse {
2025-10-28 12:42:05 +00:00
const w , const ttyconf = debug . lockStderrWriter ( & . { } ) ;
dumpBadGetPathHelp ( gen . step , w , ttyconf , src_builder , asking_step ) catch { } ;
2025-07-02 11:16:20 -07:00
debug . unlockStderrWriter ( ) ;
2025-06-13 12:01:59 -04:00
@panic ( " misconfigured build script " ) ;
} ;
}
2023-01-31 00:19:51 -07:00
} ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
// dirnameAllowEmpty is a variant of fs.path.dirname
// that allows "" to refer to the root for relative paths.
//
// For context, dirname("foo") and dirname("") are both null.
// However, for relative paths, we want dirname("foo") to be ""
// so that we can join it with another path (e.g. build root, cache root, etc.)
//
// dirname("") should still be null, because we can't go up any further.
2024-04-09 18:23:48 -07:00
fn dirnameAllowEmpty ( full_path : [ ] const u8 ) ? [ ] const u8 {
return fs . path . dirname ( full_path ) orelse {
if ( fs . path . isAbsolute ( full_path ) or full_path . len == 0 ) return null ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
return " " ;
} ;
}
test dirnameAllowEmpty {
try std . testing . expectEqualStrings (
" foo " ,
dirnameAllowEmpty ( " foo " ++ fs . path . sep_str ++ " bar " ) orelse @panic ( " unexpected null " ) ,
) ;
try std . testing . expectEqualStrings (
" " ,
dirnameAllowEmpty ( " foo " ) orelse @panic ( " unexpected null " ) ,
) ;
try std . testing . expect ( dirnameAllowEmpty ( " " ) == null ) ;
}
2023-07-19 10:49:34 +02:00
/// A reference to an existing or future path.
pub const LazyPath = union ( enum ) {
2024-04-09 18:23:48 -07:00
/// A source file path relative to build root.
src_path : struct {
owner : * std . Build ,
sub_path : [ ] const u8 ,
} ,
2024-05-04 15:12:24 -04:00
generated : struct {
file : * const GeneratedFile ,
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
/// The number of parent directories to go up.
2024-05-04 15:12:24 -04:00
/// 0 means the generated file itself.
/// 1 means the directory of the generated file.
/// 2 means the parent of that directory, and so on.
up : usize = 0 ,
/// Applied after `up`.
sub_path : [ ] const u8 = " " ,
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
} ,
2023-07-29 23:57:52 -07:00
/// An absolute path or a path relative to the current working directory of
/// the build runner process.
/// This is uncommon but used for system environment paths such as `--zig-lib-dir` which
/// ignore the file system path of build.zig and instead are relative to the directory from
/// which `zig build` was invoked.
/// Use of this tag indicates a dependency on the host system.
cwd_relative : [ ] const u8 ,
2023-09-17 19:38:19 +02:00
dependency : struct {
dependency : * Dependency ,
sub_path : [ ] const u8 ,
} ,
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
/// Returns a lazy path referring to the directory containing this path.
///
/// The dirname is not allowed to escape the logical root for underlying path.
/// For example, if the path is relative to the build root,
/// the dirname is not allowed to traverse outside of the build root.
/// Similarly, if the path is a generated file inside zig-cache,
/// the dirname is not allowed to traverse outside of zig-cache.
2024-05-04 14:29:17 -04:00
pub fn dirname ( lazy_path : LazyPath ) LazyPath {
return switch ( lazy_path ) {
2024-04-09 18:23:48 -07:00
. src_path = > | sp | . { . src_path = . {
. owner = sp . owner ,
. sub_path = dirnameAllowEmpty ( sp . sub_path ) orelse {
dumpBadDirnameHelp ( null , null , " dirname() attempted to traverse outside the build root \n " , . { } ) catch { } ;
@panic ( " misconfigured build script " ) ;
} ,
} } ,
2024-05-04 15:12:24 -04:00
. generated = > | generated | . { . generated = if ( dirnameAllowEmpty ( generated . sub_path ) ) | sub_dirname | . {
. file = generated . file ,
. up = generated . up ,
. sub_path = sub_dirname ,
} else . {
. file = generated . file ,
. up = generated . up + 1 ,
. sub_path = " " ,
} } ,
2024-05-04 14:29:17 -04:00
. cwd_relative = > | rel_path | . {
. cwd_relative = dirnameAllowEmpty ( rel_path ) orelse {
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
// If we get null, it means one of two things:
2024-05-04 14:29:17 -04:00
// - rel_path was absolute, and is now root
// - rel_path was relative, and is now ""
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
// In either case, the build script tried to go too far
// and we should panic.
2024-05-04 14:29:17 -04:00
if ( fs . path . isAbsolute ( rel_path ) ) {
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
dumpBadDirnameHelp ( null , null ,
\\dirname() attempted to traverse outside the root.
\\No more directories left to go up.
\\
, . { } ) catch { } ;
@panic ( " misconfigured build script " ) ;
} else {
dumpBadDirnameHelp ( null , null ,
\\dirname() attempted to traverse outside the current working directory.
\\
, . { } ) catch { } ;
@panic ( " misconfigured build script " ) ;
}
} ,
} ,
. dependency = > | dep | . { . dependency = . {
. dependency = dep . dependency ,
. sub_path = dirnameAllowEmpty ( dep . sub_path ) orelse {
dumpBadDirnameHelp ( null , null ,
\\dirname() attempted to traverse outside the dependency root.
\\
, . { } ) catch { } ;
@panic ( " misconfigured build script " ) ;
} ,
} } ,
} ;
}
2024-05-04 15:12:24 -04:00
pub fn path ( lazy_path : LazyPath , b : * Build , sub_path : [ ] const u8 ) LazyPath {
2024-07-31 22:54:05 -07:00
return lazy_path . join ( b . allocator , sub_path ) catch @panic ( " OOM " ) ;
}
pub fn join ( lazy_path : LazyPath , arena : Allocator , sub_path : [ ] const u8 ) Allocator . Error ! LazyPath {
2024-05-04 15:12:24 -04:00
return switch ( lazy_path ) {
. src_path = > | src | . { . src_path = . {
. owner = src . owner ,
2024-07-31 22:54:05 -07:00
. sub_path = try fs . path . resolve ( arena , & . { src . sub_path , sub_path } ) ,
2024-05-04 15:12:24 -04:00
} } ,
. generated = > | gen | . { . generated = . {
. file = gen . file ,
. up = gen . up ,
2024-07-31 22:54:05 -07:00
. sub_path = try fs . path . resolve ( arena , & . { gen . sub_path , sub_path } ) ,
2024-05-04 15:12:24 -04:00
} } ,
. cwd_relative = > | cwd_relative | . {
2024-07-31 22:54:05 -07:00
. cwd_relative = try fs . path . resolve ( arena , & . { cwd_relative , sub_path } ) ,
2024-05-04 15:12:24 -04:00
} ,
. dependency = > | dep | . { . dependency = . {
. dependency = dep . dependency ,
2024-07-31 22:54:05 -07:00
. sub_path = try fs . path . resolve ( arena , & . { dep . sub_path , sub_path } ) ,
2024-05-04 15:12:24 -04:00
} } ,
} ;
}
2023-01-31 00:19:51 -07:00
/// Returns a string that can be shown to represent the file source.
2024-05-04 15:12:24 -04:00
/// Either returns the path, `"generated"`, or `"dependency"`.
2024-05-04 14:29:17 -04:00
pub fn getDisplayName ( lazy_path : LazyPath ) [ ] const u8 {
return switch ( lazy_path ) {
2024-05-04 15:12:24 -04:00
. src_path = > | sp | sp . sub_path ,
. cwd_relative = > | p | p ,
2023-01-31 00:19:51 -07:00
. generated = > " generated " ,
2023-09-17 19:38:19 +02:00
. dependency = > " dependency " ,
2023-01-31 00:19:51 -07:00
} ;
}
/// Adds dependencies this file source implies to the given step.
2024-05-04 14:29:17 -04:00
pub fn addStepDependencies ( lazy_path : LazyPath , other_step : * Step ) void {
switch ( lazy_path ) {
2024-05-04 15:12:24 -04:00
. src_path , . cwd_relative , . dependency = > { } ,
. generated = > | gen | other_step . dependOn ( gen . file . step ) ,
2023-01-31 00:19:51 -07:00
}
}
2024-07-09 23:14:18 -07:00
/// Deprecated, see `getPath3`.
2024-05-04 14:29:17 -04:00
pub fn getPath ( lazy_path : LazyPath , src_builder : * Build ) [ ] const u8 {
return getPath2 ( lazy_path , src_builder , null ) ;
2023-02-14 13:12:47 -07:00
}
2024-07-09 23:14:18 -07:00
/// Deprecated, see `getPath3`.
pub fn getPath2 ( lazy_path : LazyPath , src_builder : * Build , asking_step : ? * Step ) [ ] const u8 {
const p = getPath3 ( lazy_path , src_builder , asking_step ) ;
return src_builder . pathResolve ( & . { p . root_dir . path orelse " . " , p . sub_path } ) ;
}
2023-07-29 23:57:52 -07:00
/// Intended to be used during the make phase only.
///
/// `asking_step` is only used for debugging purposes; it's the step being
/// run that is asking for the path.
2024-07-09 23:14:18 -07:00
pub fn getPath3 ( lazy_path : LazyPath , src_builder : * Build , asking_step : ? * Step ) Cache . Path {
2024-05-04 14:29:17 -04:00
switch ( lazy_path ) {
2024-07-09 23:14:18 -07:00
. src_path = > | sp | return . {
. root_dir = sp . owner . build_root ,
. sub_path = sp . sub_path ,
} ,
. cwd_relative = > | sub_path | return . {
. root_dir = Cache . Directory . cwd ( ) ,
. sub_path = sub_path ,
} ,
2024-05-04 15:12:24 -04:00
. generated = > | gen | {
2024-07-09 23:14:18 -07:00
// TODO make gen.file.path not be absolute and use that as the
// basis for not traversing up too many directories.
var file_path : Cache . Path = . {
2024-08-18 00:43:33 +02:00
. root_dir = Cache . Directory . cwd ( ) ,
2024-07-09 23:14:18 -07:00
. sub_path = gen . file . path orelse {
2025-10-28 12:42:05 +00:00
const w , const ttyconf = debug . lockStderrWriter ( & . { } ) ;
dumpBadGetPathHelp ( gen . file . step , w , ttyconf , src_builder , asking_step ) catch { } ;
2025-07-02 11:16:20 -07:00
debug . unlockStderrWriter ( ) ;
2024-07-09 23:14:18 -07:00
@panic ( " misconfigured build script " ) ;
} ,
} ;
2024-05-04 15:12:24 -04:00
if ( gen . up > 0 ) {
const cache_root_path = src_builder . cache_root . path orelse
( src_builder . cache_root . join ( src_builder . allocator , & . { " . " } ) catch @panic ( " OOM " ) ) ;
for ( 0 .. gen . up ) | _ | {
2024-07-09 23:14:18 -07:00
if ( mem . eql ( u8 , file_path . sub_path , cache_root_path ) ) {
2024-05-04 15:12:24 -04:00
// If we hit the cache root and there's still more to go,
// the script attempted to go too far.
dumpBadDirnameHelp ( gen . file . step , asking_step ,
\\dirname() attempted to traverse outside the cache root.
\\This is not allowed.
\\
, . { } ) catch { } ;
@panic ( " misconfigured build script " ) ;
}
// path is absolute.
// dirname will return null only if we're at root.
// Typically, we'll stop well before that at the cache root.
2024-07-09 23:14:18 -07:00
file_path . sub_path = fs . path . dirname ( file_path . sub_path ) orelse {
2024-05-04 15:12:24 -04:00
dumpBadDirnameHelp ( gen . file . step , asking_step ,
\\dirname() reached root.
\\No more directories left to go up.
\\
, . { } ) catch { } ;
@panic ( " misconfigured build script " ) ;
} ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
}
}
2024-05-04 15:12:24 -04:00
2024-07-09 23:14:18 -07:00
return file_path . join ( src_builder . allocator , gen . sub_path ) catch @panic ( " OOM " ) ;
} ,
. dependency = > | dep | return . {
. root_dir = dep . dependency . builder . build_root ,
. sub_path = dep . sub_path ,
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
} ,
2023-02-14 12:47:45 -07:00
}
2023-01-31 00:19:51 -07:00
}
2025-06-13 12:01:59 -04:00
pub fn basename ( lazy_path : LazyPath , src_builder : * Build , asking_step : ? * Step ) [ ] const u8 {
return fs . path . basename ( switch ( lazy_path ) {
. src_path = > | sp | sp . sub_path ,
. cwd_relative = > | sub_path | sub_path ,
. generated = > | gen | if ( gen . sub_path . len > 0 )
gen . sub_path
else
gen . file . getPath2 ( src_builder , asking_step ) ,
. dependency = > | dep | dep . sub_path ,
} ) ;
}
2024-04-11 14:02:47 -07:00
/// Copies the internal strings.
///
/// The `b` parameter is only used for its allocator. All *Build instances
/// share the same allocator.
2024-05-04 14:29:17 -04:00
pub fn dupe ( lazy_path : LazyPath , b : * Build ) LazyPath {
2024-10-05 00:58:48 +02:00
return lazy_path . dupeInner ( b . allocator ) ;
}
fn dupeInner ( lazy_path : LazyPath , allocator : std . mem . Allocator ) LazyPath {
2024-05-04 14:29:17 -04:00
return switch ( lazy_path ) {
2024-04-09 18:23:48 -07:00
. src_path = > | sp | . { . src_path = . {
. owner = sp . owner ,
2024-04-11 14:02:47 -07:00
. sub_path = sp . owner . dupePath ( sp . sub_path ) ,
2024-04-09 18:23:48 -07:00
} } ,
2024-10-05 00:58:48 +02:00
. cwd_relative = > | p | . { . cwd_relative = dupePathInner ( allocator , p ) } ,
2024-05-04 15:12:24 -04:00
. generated = > | gen | . { . generated = . {
. file = gen . file ,
. up = gen . up ,
2024-10-05 00:58:48 +02:00
. sub_path = dupePathInner ( allocator , gen . sub_path ) ,
2024-05-04 15:12:24 -04:00
} } ,
2025-10-07 16:12:16 +01:00
. dependency = > | dep | . { . dependency = . {
. dependency = dep . dependency ,
. sub_path = dupePathInner ( allocator , dep . sub_path ) ,
} } ,
2023-01-31 00:19:51 -07:00
} ;
}
} ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
fn dumpBadDirnameHelp (
fail_step : ? * Step ,
asking_step : ? * Step ,
comptime msg : [ ] const u8 ,
args : anytype ,
) anyerror ! void {
2025-10-28 12:42:05 +00:00
const w , const tty_config = debug . lockStderrWriter ( & . { } ) ;
2025-07-02 11:16:20 -07:00
defer debug . unlockStderrWriter ( ) ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
try w . print ( msg , args ) ;
if ( fail_step ) | s | {
tty_config . setColor ( w , . red ) catch { } ;
2025-07-02 11:16:20 -07:00
try w . writeAll ( " The step was created by this stack trace: \n " ) ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
tty_config . setColor ( w , . reset ) catch { } ;
2025-07-02 11:16:20 -07:00
s . dump ( w , tty_config ) ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
}
if ( asking_step ) | as | {
tty_config . setColor ( w , . red ) catch { } ;
2025-07-02 11:16:20 -07:00
try w . print ( " The step '{s}' that is missing a dependency on the above step was created by this stack trace: \n " , . { as . name } ) ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
tty_config . setColor ( w , . reset ) catch { } ;
2025-07-02 11:16:20 -07:00
as . dump ( w , tty_config ) ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
}
tty_config . setColor ( w , . red ) catch { } ;
2025-07-02 11:16:20 -07:00
try w . writeAll ( " Hope that helps. Proceeding to panic. \n " ) ;
build/LazyPath: Add dirname (#18371)
Adds a variant to the LazyPath union representing a parent directory
of a generated path.
```zig
const LazyPath = union(enum) {
generated_dirname: struct {
generated: *const GeneratedFile,
up: usize,
},
// ...
}
```
These can be constructed with the new method:
```zig
pub fn dirname(self: LazyPath) LazyPath
```
For the cases where the LazyPath is already known
(`.path`, `.cwd_relative`, and `dependency`)
this is evaluated right away.
For dirnames of generated files and their dirnames,
this is evaluated at getPath time.
dirname calls can be chained, but for safety,
they are not allowed to escape outside a root
defined for each case:
- path: This is relative to the build root,
so dirname can't escape outside the build root.
- generated: Can't escape the zig-cache.
- cwd_relative: This can be a relative or absolute path.
If relative, can't escape the current directory,
and if absolute, can't go beyond root (/).
- dependency: Can't escape the dependency's root directory.
Testing:
I've included a standalone case for many of the happy cases.
I couldn't find an easy way to test the negatives, though,
because tests cannot yet expect panics.
2024-01-04 15:47:28 -08:00
tty_config . setColor ( w , . reset ) catch { } ;
}
2023-07-29 23:57:52 -07:00
/// In this function the stderr mutex has already been locked.
pub fn dumpBadGetPathHelp (
s : * Step ,
2025-08-27 21:20:18 -07:00
w : * std . Io . Writer ,
tty_config : std . Io . tty . Config ,
2023-07-29 23:57:52 -07:00
src_builder : * Build ,
asking_step : ? * Step ,
) anyerror ! void {
try w . print (
\\getPath() was called on a GeneratedFile that wasn't built yet.
\\ source package path: {s}
\\ Is there a missing Step dependency on step '{s}'?
\\
, . {
src_builder . build_root . path orelse " . " ,
s . name ,
} ) ;
tty_config . setColor ( w , . red ) catch { } ;
2025-07-02 11:16:20 -07:00
try w . writeAll ( " The step was created by this stack trace: \n " ) ;
2023-07-29 23:57:52 -07:00
tty_config . setColor ( w , . reset ) catch { } ;
2025-07-02 11:16:20 -07:00
s . dump ( w , tty_config ) ;
2023-07-29 23:57:52 -07:00
if ( asking_step ) | as | {
tty_config . setColor ( w , . red ) catch { } ;
2025-07-02 11:16:20 -07:00
try w . print ( " The step '{s}' that is missing a dependency on the above step was created by this stack trace: \n " , . { as . name } ) ;
2023-07-29 23:57:52 -07:00
tty_config . setColor ( w , . reset ) catch { } ;
2025-07-02 11:16:20 -07:00
as . dump ( w , tty_config ) ;
2023-07-29 23:57:52 -07:00
}
tty_config . setColor ( w , . red ) catch { } ;
2025-07-02 11:16:20 -07:00
try w . writeAll ( " Hope that helps. Proceeding to panic. \n " ) ;
2023-07-29 23:57:52 -07:00
tty_config . setColor ( w , . reset ) catch { } ;
}
2023-01-31 00:19:51 -07:00
pub const InstallDir = union ( enum ) {
prefix : void ,
lib : void ,
bin : void ,
header : void ,
/// A path relative to the prefix
custom : [ ] const u8 ,
/// Duplicates the install directory including the path if set to custom.
2024-05-04 14:29:17 -04:00
pub fn dupe ( dir : InstallDir , builder : * Build ) InstallDir {
if ( dir == . custom ) {
return . { . custom = builder . dupe ( dir . custom ) } ;
2023-01-31 00:19:51 -07:00
} else {
2024-05-04 14:29:17 -04:00
return dir ;
2023-01-31 00:19:51 -07:00
}
}
} ;
2023-03-06 22:44:36 -07:00
/// This function is intended to be called in the `configure` phase only.
/// It returns an absolute directory path, which is potentially going to be a
/// source of API breakage in the future, so keep that in mind when using this
/// function.
pub fn makeTempPath ( b : * Build ) [ ] const u8 {
const rand_int = std . crypto . random . int ( u64 ) ;
2024-07-19 17:39:55 -07:00
const tmp_dir_sub_path = " tmp " ++ fs . path . sep_str ++ std . fmt . hex ( rand_int ) ;
2023-03-06 22:44:36 -07:00
const result_path = b . cache_root . join ( b . allocator , & . { tmp_dir_sub_path } ) catch @panic ( " OOM " ) ;
2023-03-18 18:32:43 -07:00
b . cache_root . handle . makePath ( tmp_dir_sub_path ) catch | err | {
2023-03-06 22:44:36 -07:00
std . debug . print ( " unable to make tmp path '{s}': {s} \n " , . {
result_path , @errorName ( err ) ,
} ) ;
} ;
return result_path ;
}
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
/// A pair of target query and fully resolved target.
/// This type is generally required by build system API that need to be given a
/// target. The query is kept because the Zig toolchain needs to know which parts
/// of the target are "native". This can apply to the CPU, the OS, or even the ABI.
pub const ResolvedTarget = struct {
2023-12-04 12:35:04 -07:00
query : Target . Query ,
2023-12-05 16:09:07 -07:00
result : Target ,
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
} ;
/// Converts a target query into a fully resolved target that can be passed to
/// various parts of the API.
2023-12-04 12:35:04 -07:00
pub fn resolveTargetQuery ( b : * Build , query : Target . Query ) ResolvedTarget {
2024-02-01 19:22:05 -07:00
if ( query . isNative ( ) ) {
std.Build: revert --host-target, --host-cpu, --host-dynamic-linker
This is a partial revert of 105db13536b4dc2affe130cb8d2eee6c97c89bcd.
As we learned from Void Linux packaging, these options are not actually
helpful since the distribution package manager may very well want to
cross-compile the packages that it is building.
So, let's not overcomplicate things. There are already the standard
options: -Dtarget, -Dcpu, and -Ddynamic-linker.
These options are generally provided when the project generates machine
code artifacts, however, there may be a project that does no such thing,
in which case it makes sense for these options to be missing. The Zig
Build System is a general-purpose build system, after all.
2024-04-17 17:57:03 -07:00
// Hot path. This is faster than querying the native CPU and OS again.
return b . graph . host ;
2024-02-01 19:22:05 -07:00
}
2025-10-06 18:34:51 -07:00
const io = b . graph . io ;
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
return . {
. query = query ,
2025-10-06 18:34:51 -07:00
. result = std . zig . system . resolveTargetQuery ( io , query ) catch
2023-12-04 15:26:57 -07:00
@panic ( " unable to resolve target query " ) ,
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
} ;
}
2023-12-04 12:35:04 -07:00
pub fn wantSharedLibSymLinks ( target : Target ) bool {
zig build system: change target, compilation, and module APIs
Introduce the concept of "target query" and "resolved target". A target
query is what the user specifies, with some things left to default. A
resolved target has the default things discovered and populated.
In the future, std.zig.CrossTarget will be rename to std.Target.Query.
Introduces `std.Build.resolveTargetQuery` to get from one to the other.
The concept of `main_mod_path` is gone, no longer supported. You have to
put the root source file at the module root now.
* remove deprecated API
* update build.zig for the breaking API changes in this branch
* move std.Build.Step.Compile.BuildId to std.zig.BuildId
* add more options to std.Build.ExecutableOptions, std.Build.ObjectOptions,
std.Build.SharedLibraryOptions, std.Build.StaticLibraryOptions, and
std.Build.TestOptions.
* remove `std.Build.constructCMacro`. There is no use for this API.
* deprecate `std.Build.Step.Compile.defineCMacro`. Instead,
`std.Build.Module.addCMacro` is provided.
- remove `std.Build.Step.Compile.defineCMacroRaw`.
* deprecate `std.Build.Step.Compile.linkFrameworkNeeded`
- use `std.Build.Module.linkFramework`
* deprecate `std.Build.Step.Compile.linkFrameworkWeak`
- use `std.Build.Module.linkFramework`
* move more logic into `std.Build.Module`
* allow `target` and `optimize` to be `null` when creating a Module.
Along with other fields, those unspecified options will be inherited
from parent `Module` when inserted into an import table.
* the `target` field of `addExecutable` is now required. pass `b.host`
to get the host target.
2023-12-02 21:51:34 -07:00
return target . os . tag != . windows ;
}
2024-02-01 23:04:23 -07:00
pub const SystemIntegrationOptionConfig = struct {
/// If left as null, then the default will depend on system_package_mode.
default : ? bool = null ,
} ;
pub fn systemIntegrationOption (
b : * Build ,
name : [ ] const u8 ,
config : SystemIntegrationOptionConfig ,
) bool {
2024-02-01 15:44:44 -07:00
const gop = b . graph . system_library_options . getOrPut ( b . allocator , name ) catch @panic ( " OOM " ) ;
2024-01-31 22:02:27 -07:00
if ( gop . found_existing ) switch ( gop . value_ptr .* ) {
. user_disabled = > {
gop . value_ptr .* = . declared_disabled ;
return false ;
} ,
. user_enabled = > {
gop . value_ptr .* = . declared_enabled ;
return true ;
} ,
. declared_disabled = > return false ,
. declared_enabled = > return true ,
} else {
gop . key_ptr .* = b . dupe ( name ) ;
2024-02-01 23:04:23 -07:00
if ( config . default orelse b . graph . system_package_mode ) {
2024-01-31 22:02:27 -07:00
gop . value_ptr .* = . declared_enabled ;
return true ;
} else {
gop . value_ptr .* = . declared_disabled ;
return false ;
}
}
}
2023-01-31 00:19:51 -07:00
test {
2023-10-21 19:30:45 -04:00
_ = Cache ;
2023-05-03 11:49:55 +03:00
_ = Step ;
2023-01-31 00:19:51 -07:00
}