@@ -93,6 +93,8 @@ named_writefiles: std.StringArrayHashMap(*Step.WriteFile),
93
93
/// A map from build root dirs to the corresponding `*Dependency`. This is shared with all child
94
94
/// `Build`s.
95
95
initialized_deps : * InitializedDepMap ,
96
+ /// The hash of this instance's package. `""` means that this is the root package.
97
+ pkg_hash : []const u8 ,
96
98
/// A mapping from dependency names to package hashes.
97
99
available_deps : AvailableDeps ,
98
100
@@ -305,6 +307,7 @@ pub fn create(
305
307
.modules = std .StringArrayHashMap (* Module ).init (arena ),
306
308
.named_writefiles = std .StringArrayHashMap (* Step .WriteFile ).init (arena ),
307
309
.initialized_deps = initialized_deps ,
310
+ .pkg_hash = "" ,
308
311
.available_deps = available_deps ,
309
312
.release_mode = .off ,
310
313
};
@@ -318,10 +321,11 @@ fn createChild(
318
321
parent : * Build ,
319
322
dep_name : []const u8 ,
320
323
build_root : Cache.Directory ,
324
+ pkg_hash : []const u8 ,
321
325
pkg_deps : AvailableDeps ,
322
326
user_input_options : UserInputOptionsMap ,
323
327
) ! * Build {
324
- const child = try createChildOnly (parent , dep_name , build_root , pkg_deps , user_input_options );
328
+ const child = try createChildOnly (parent , dep_name , build_root , pkg_hash , pkg_deps , user_input_options );
325
329
try determineAndApplyInstallPrefix (child );
326
330
return child ;
327
331
}
@@ -330,6 +334,7 @@ fn createChildOnly(
330
334
parent : * Build ,
331
335
dep_name : []const u8 ,
332
336
build_root : Cache.Directory ,
337
+ pkg_hash : []const u8 ,
333
338
pkg_deps : AvailableDeps ,
334
339
user_input_options : UserInputOptionsMap ,
335
340
) ! * Build {
@@ -397,6 +402,7 @@ fn createChildOnly(
397
402
.modules = std .StringArrayHashMap (* Module ).init (allocator ),
398
403
.named_writefiles = std .StringArrayHashMap (* Step .WriteFile ).init (allocator ),
399
404
.initialized_deps = parent .initialized_deps ,
405
+ .pkg_hash = pkg_hash ,
400
406
.available_deps = pkg_deps ,
401
407
.release_mode = parent .release_mode ,
402
408
};
@@ -1831,6 +1837,26 @@ fn findPkgHashOrFatal(b: *Build, name: []const u8) []const u8 {
1831
1837
std .debug .panic ("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file" , .{ name , full_path });
1832
1838
}
1833
1839
1840
+ inline fn findImportPkgHashOrFatal (b : * Build , comptime asking_build_zig : type , comptime dep_name : []const u8 ) []const u8 {
1841
+ const build_runner = @import ("root" );
1842
+ const deps = build_runner .dependencies ;
1843
+
1844
+ const b_pkg_hash , const b_pkg_deps = comptime for (@typeInfo (deps .packages ).Struct .decls ) | decl | {
1845
+ const pkg_hash = decl .name ;
1846
+ const pkg = @field (deps .packages , pkg_hash );
1847
+ if (@hasDecl (pkg , "build_zig" ) and pkg .build_zig == asking_build_zig ) break .{ pkg_hash , pkg .deps };
1848
+ } else .{ "" , deps .root_deps };
1849
+ if (! std .mem .eql (u8 , b_pkg_hash , b .pkg_hash )) {
1850
+ std .debug .panic ("'{}' is not the struct that corresponds to '{s}'" , .{ asking_build_zig , b .pathFromRoot ("build.zig" ) });
1851
+ }
1852
+ comptime for (b_pkg_deps ) | dep | {
1853
+ if (std .mem .eql (u8 , dep [0 ], dep_name )) return dep [1 ];
1854
+ };
1855
+
1856
+ const full_path = b .pathFromRoot ("build.zig.zon" );
1857
+ 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 });
1858
+ }
1859
+
1834
1860
fn markNeededLazyDep (b : * Build , pkg_hash : []const u8 ) void {
1835
1861
b .graph .needed_lazy_dependencies .put (b .graph .arena , pkg_hash , {}) catch @panic ("OOM" );
1836
1862
}
@@ -1861,7 +1887,7 @@ pub fn lazyDependency(b: *Build, name: []const u8, args: anytype) ?*Dependency {
1861
1887
markNeededLazyDep (b , pkg_hash );
1862
1888
return null ;
1863
1889
}
1864
- return dependencyInner (b , name , pkg .build_root , if (@hasDecl (pkg , "build_zig" )) pkg .build_zig else null , pkg .deps , args );
1890
+ return dependencyInner (b , name , pkg .build_root , if (@hasDecl (pkg , "build_zig" )) pkg .build_zig else null , pkg_hash , pkg .deps , args );
1865
1891
}
1866
1892
}
1867
1893
@@ -1879,13 +1905,48 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
1879
1905
if (@hasDecl (pkg , "available" )) {
1880
1906
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 });
1881
1907
}
1882
- return dependencyInner (b , name , pkg .build_root , if (@hasDecl (pkg , "build_zig" )) pkg .build_zig else null , pkg .deps , args );
1908
+ return dependencyInner (b , name , pkg .build_root , if (@hasDecl (pkg , "build_zig" )) pkg .build_zig else null , pkg_hash , pkg .deps , args );
1883
1909
}
1884
1910
}
1885
1911
1886
1912
unreachable ; // Bad @dependencies source
1887
1913
}
1888
1914
1915
+ /// In a build.zig file, this function is to `@import` what `lazyDependency` is to `dependency`.
1916
+ /// If the dependency is lazy and has not yet been fetched, it instructs the parent process to fetch
1917
+ /// that dependency after the build script has finished running, then returns `null`.
1918
+ /// If the dependency is lazy but has already been fetched, or if it is eager, it returns
1919
+ /// the build.zig struct of that dependency, just like a regular `@import`.
1920
+ pub inline fn lazyImport (
1921
+ b : * Build ,
1922
+ /// The build.zig struct of the package importing the dependency.
1923
+ /// When calling this function from the `build` function of a build.zig file's, you normally
1924
+ /// pass `@This()`.
1925
+ comptime asking_build_zig : type ,
1926
+ comptime dep_name : []const u8 ,
1927
+ ) ? type {
1928
+ const build_runner = @import ("root" );
1929
+ const deps = build_runner .dependencies ;
1930
+ const pkg_hash = findImportPkgHashOrFatal (b , asking_build_zig , dep_name );
1931
+
1932
+ inline for (@typeInfo (deps .packages ).Struct .decls ) | decl | {
1933
+ if (comptime mem .eql (u8 , decl .name , pkg_hash )) {
1934
+ const pkg = @field (deps .packages , decl .name );
1935
+ const available = ! @hasDecl (pkg , "available" ) or pkg .available ;
1936
+ if (! available ) {
1937
+ markNeededLazyDep (b , pkg_hash );
1938
+ return null ;
1939
+ }
1940
+ return if (@hasDecl (pkg , "build_zig" ))
1941
+ pkg .build_zig
1942
+ else
1943
+ @compileError ("dependency '" ++ dep_name ++ "' does not have a build.zig" );
1944
+ }
1945
+ }
1946
+
1947
+ comptime unreachable ; // Bad @dependencies source
1948
+ }
1949
+
1889
1950
pub fn anonymousDependency (
1890
1951
b : * Build ,
1891
1952
/// The path to the directory containing the dependency's build.zig file,
@@ -1902,7 +1963,7 @@ pub fn anonymousDependency(
1902
1963
'/' , '\\ ' = > byte .* = '.' ,
1903
1964
else = > continue ,
1904
1965
};
1905
- return dependencyInner (b , name , build_root , build_zig , &.{}, args );
1966
+ return dependencyInner (b , name , build_root , build_zig , "anonymous" , &.{}, args );
1906
1967
}
1907
1968
1908
1969
fn userValuesAreSame (lhs : UserValue , rhs : UserValue ) bool {
@@ -1957,6 +2018,7 @@ pub fn dependencyInner(
1957
2018
name : []const u8 ,
1958
2019
build_root_string : []const u8 ,
1959
2020
comptime build_zig : ? type ,
2021
+ pkg_hash : []const u8 ,
1960
2022
pkg_deps : AvailableDeps ,
1961
2023
args : anytype ,
1962
2024
) * Dependency {
@@ -1977,7 +2039,7 @@ pub fn dependencyInner(
1977
2039
},
1978
2040
};
1979
2041
1980
- const sub_builder = b .createChild (name , build_root , pkg_deps , user_input_options ) catch @panic ("unhandled error" );
2042
+ const sub_builder = b .createChild (name , build_root , pkg_hash , pkg_deps , user_input_options ) catch @panic ("unhandled error" );
1981
2043
if (build_zig ) | bz | {
1982
2044
sub_builder .runBuild (bz ) catch @panic ("unhandled error" );
1983
2045
0 commit comments