authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-10-16 17:55:21+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-18 11:42:44-07:00
log17cf964c25d708c5b28c4811538cd5af4a56b42e
tree19bd7471d70def27b32b355af0d646301bb4a9ae
parent93ce520bc3919670be1e1ca09b745f8f6c4cdb45

std.Build.Configuration: add $DESTDIR-relative LazyPaths

The new deployed_prefix and related paths exist to support the use-case of embedding absolute paths to other build artifacts in the build artifacts themselves. For example pkg-config files are artifacts which must contain absolute paths to the other library/header artifacts they describe. Note that this feature is only supported to faciliate interoperability with such legacy systems. In general, embedding absolute paths in build artifacts should be avoided. This patch also fixes a bug: currently passing an absolute path to e.g. --prefix-lib-dir will cause $DESTDIR to be ignored for build artifacts installed to that path. I'm not entirely satisfied with the new "deployed" naming convention, I want to avoid the breaking change of renaming "installed" to something else and this is the best option I came up with. Closes: https://codeberg.org/ziglang/zig/issues/37124

3 files changed, 99 insertions(+), 40 deletions(-)

lib/compiler/Maker.zig+65-40
...@@ -42,7 +42,8 @@ pub const std_options: std.Options = .{...@@ -42,7 +42,8 @@ pub const std_options: std.Options = .{
4242
43gpa: Allocator,43gpa: Allocator,
44graph: *Graph,44graph: *Graph,
45install_paths: InstallPaths,45install_paths: PrefixPaths,
46deployed_paths: PrefixPaths,
46scanned_config: *const ScannedConfig,47scanned_config: *const ScannedConfig,
47/// Includes an extra auto-generated placeholder Step at the end that indicates48/// Includes an extra auto-generated placeholder Step at the end that indicates
48/// configure must be rerun. It is done this way so that the hot path of file49/// configure must be rerun. It is done this way so that the hot path of file
...@@ -93,7 +94,7 @@ const use_safe_allocator = switch (builtin.mode) {...@@ -93,7 +94,7 @@ const use_safe_allocator = switch (builtin.mode) {
93 .fast, .small => false,94 .fast, .small => false,
94};95};
9596
96const InstallPaths = struct {97const PrefixPaths = struct {
97 prefix: Path,98 prefix: Path,
98 lib: Path,99 lib: Path,
99 bin: Path,100 bin: Path,
...@@ -663,42 +664,62 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -663,42 +664,62 @@ pub fn main(init: process.Init.Minimal) !void {
663 });664 });
664 defer main_progress_node.end();665 defer main_progress_node.end();
665666
666 const install_prefix_path: Path = if (graph.environ_map.get("DESTDIR")) |dest_dir| .{667 const deployed_paths: PrefixPaths = blk: {
667 .root_dir = .cwd(),668 const prefix: Path = if (override_install_prefix) |cwd_relative| .{
668 .sub_path = try Dir.path.join(arena, &.{ dest_dir, override_install_prefix orelse "/usr" }),669 .root_dir = .cwd(),
669 } else if (override_install_prefix) |cwd_relative| .{670 .sub_path = cwd_relative,
670 .root_dir = .cwd(),671 } else if (graph.environ_map.get("DESTDIR") != null) .{
671 .sub_path = cwd_relative,672 .root_dir = .cwd(),
672 } else .{673 .sub_path = "/usr",
673 .root_dir = graph.build_root_directory,674 } else .{
674 .sub_path = "zig-out",675 .root_dir = graph.build_root_directory,
676 .sub_path = "zig-out",
677 };
678 break :blk .{
679 .prefix = prefix,
680 // The lib/bin/include overrides are interpreted relative to the
681 // install prefix unless absolute paths are used.
682 .lib = if (override_lib_dir) |lib_dir|
683 if (Dir.path.isAbsolute(lib_dir)) .{
684 .root_dir = .cwd(),
685 .sub_path = lib_dir,
686 } else try prefix.join(arena, lib_dir)
687 else
688 try prefix.join(arena, "lib"),
689 .bin = if (override_bin_dir) |bin_dir|
690 if (Dir.path.isAbsolute(bin_dir)) .{
691 .root_dir = .cwd(),
692 .sub_path = bin_dir,
693 } else try prefix.join(arena, bin_dir)
694 else
695 try prefix.join(arena, "bin"),
696 .include = if (override_include_dir) |include_dir|
697 if (Dir.path.isAbsolute(include_dir)) .{
698 .root_dir = .cwd(),
699 .sub_path = include_dir,
700 } else try prefix.join(arena, include_dir)
701 else
702 try prefix.join(arena, "include"),
703 };
675 };704 };
676705 const install_paths: PrefixPaths = if (graph.environ_map.get("DESTDIR")) |destdir| .{
677 // These three overrides are meant to be relative to the install prefix,706 .prefix = .{
678 // not current working directory, unless absolute paths are used.
679 const install_lib_path: Path = if (override_lib_dir) |lib_dir|
680 if (Dir.path.isAbsolute(lib_dir)) .{
681 .root_dir = .cwd(),707 .root_dir = .cwd(),
682 .sub_path = lib_dir,708 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.prefix.sub_path }),
683 } else try install_prefix_path.join(arena, lib_dir)709 },
684 else710 .lib = .{
685 try install_prefix_path.join(arena, "lib");
686
687 const install_bin_path: Path = if (override_bin_dir) |bin_dir|
688 if (Dir.path.isAbsolute(bin_dir)) .{
689 .root_dir = .cwd(),711 .root_dir = .cwd(),
690 .sub_path = bin_dir,712 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.lib.sub_path }),
691 } else try install_prefix_path.join(arena, bin_dir)713 },
692 else714 .bin = .{
693 try install_prefix_path.join(arena, "bin");
694
695 const install_include_path: Path = if (override_include_dir) |include_dir|
696 if (Dir.path.isAbsolute(include_dir)) .{
697 .root_dir = .cwd(),715 .root_dir = .cwd(),
698 .sub_path = include_dir,716 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.bin.sub_path }),
699 } else try install_prefix_path.join(arena, include_dir)717 },
700 else718 .include = .{
701 try install_prefix_path.join(arena, "include");719 .root_dir = .cwd(),
720 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.include.sub_path }),
721 },
722 } else deployed_paths;
702723
703 const now = Io.Clock.Timestamp.now(io, .awake);724 const now = Io.Clock.Timestamp.now(io, .awake);
704725
...@@ -795,12 +816,8 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -795,12 +816,8 @@ pub fn main(init: process.Init.Minimal) !void {
795 .gpa = gpa,816 .gpa = gpa,
796 .graph = &graph,817 .graph = &graph,
797 .scanned_config = &scanned_config,818 .scanned_config = &scanned_config,
798 .install_paths = .{819 .install_paths = install_paths,
799 .prefix = install_prefix_path,820 .deployed_paths = deployed_paths,
800 .lib = install_lib_path,
801 .bin = install_bin_path,
802 .include = install_include_path,
803 },
804821
805 .steps = &.{},822 .steps = &.{},
806 .generated_files = &.{},823 .generated_files = &.{},
...@@ -3829,6 +3846,10 @@ pub fn relativePath(...@@ -3829,6 +3846,10 @@ pub fn relativePath(
3829 .install_lib => try maker.install_paths.lib.join(arena, sub_path),3846 .install_lib => try maker.install_paths.lib.join(arena, sub_path),
3830 .install_bin => try maker.install_paths.bin.join(arena, sub_path),3847 .install_bin => try maker.install_paths.bin.join(arena, sub_path),
3831 .install_include => try maker.install_paths.include.join(arena, sub_path),3848 .install_include => try maker.install_paths.include.join(arena, sub_path),
3849 .deployed_prefix => try maker.deployed_paths.prefix.join(arena, sub_path),
3850 .deployed_lib => try maker.deployed_paths.lib.join(arena, sub_path),
3851 .deployed_bin => try maker.deployed_paths.bin.join(arena, sub_path),
3852 .deployed_include => try maker.deployed_paths.include.join(arena, sub_path),
3832 .libc_runtimes => if (maker.graph.libc_runtimes_dir) |libc_runtimes_dir| .{3853 .libc_runtimes => if (maker.graph.libc_runtimes_dir) |libc_runtimes_dir| .{
3833 .root_dir = .cwd(),3854 .root_dir = .cwd(),
3834 .sub_path = try Dir.path.join(arena, &.{ libc_runtimes_dir, sub_path }),3855 .sub_path = try Dir.path.join(arena, &.{ libc_runtimes_dir, sub_path }),
...@@ -4435,6 +4456,10 @@ fn confPathDepToCachePath(...@@ -4435,6 +4456,10 @@ fn confPathDepToCachePath(
4435 .install_lib => @panic("TODO"),4456 .install_lib => @panic("TODO"),
4436 .install_bin => @panic("TODO"),4457 .install_bin => @panic("TODO"),
4437 .install_include => @panic("TODO"),4458 .install_include => @panic("TODO"),
4459 .deployed_prefix => @panic("TODO"),
4460 .deployed_lib => @panic("TODO"),
4461 .deployed_bin => @panic("TODO"),
4462 .deployed_include => @panic("TODO"),
4438 .libc_runtimes => @panic("TODO"),4463 .libc_runtimes => @panic("TODO"),
4439 };4464 };
4440}4465}
lib/std/Build.zig+4
...@@ -2699,6 +2699,10 @@ fn validateConfigureDependency(lazy_path: LazyPath) void {...@@ -2699,6 +2699,10 @@ fn validateConfigureDependency(lazy_path: LazyPath) void {
2699 .install_lib,2699 .install_lib,
2700 .install_bin,2700 .install_bin,
2701 .install_include,2701 .install_include,
2702 .deployed_prefix,
2703 .deployed_lib,
2704 .deployed_bin,
2705 .deployed_include,
2702 => @panic("configure phase cannot depend on files installed during make phase"),2706 => @panic("configure phase cannot depend on files installed during make phase"),
2703 .libc_runtimes,2707 .libc_runtimes,
2704 => @panic("configure phase cannot depend on directory known only during make phase"),2708 => @panic("configure phase cannot depend on directory known only during make phase"),
lib/std/Build/Configuration.zig+30
...@@ -1563,6 +1563,13 @@ pub const LazyPath = union(@This().Tag) {...@@ -1563,6 +1563,13 @@ pub const LazyPath = union(@This().Tag) {
1563 _: u16 = 0,1563 _: u16 = 0,
1564 };1564 };
15651565
1566 /// The deployed_prefix and related paths exist to support the use-case
1567 /// of embedding absolute paths to other build artifacts in the build
1568 /// artifacts themselves. For example pkg-config files are artifacts
1569 /// which must contain absolute paths to the other library/header
1570 /// artifacts they describe. Note that this feature is only supported to
1571 /// faciliate interoperability with such legacy systems. In general,
1572 /// embedding absolute paths in build artifacts should be avoided.
1566 pub const Base = enum(u8) {1573 pub const Base = enum(u8) {
1567 cwd,1574 cwd,
1568 local_cache,1575 local_cache,
...@@ -1571,10 +1578,33 @@ pub const LazyPath = union(@This().Tag) {...@@ -1571,10 +1578,33 @@ pub const LazyPath = union(@This().Tag) {
1571 build_root,1578 build_root,
1572 zig_exe,1579 zig_exe,
1573 zig_lib,1580 zig_lib,
1581
1582 /// Path that artifacts will be written to by the build system.
1583 /// Equivalent to $DESTDIR/deployed_prefix if $DESTDIR is set.
1574 install_prefix,1584 install_prefix,
1585 /// Path that artifacts will be written to by the build system.
1586 /// Equivalent to $DESTDIR/deployed_lib if $DESTDIR is set.
1575 install_lib,1587 install_lib,
1588 /// Path that artifacts will be written to by the build system.
1589 /// Equivalent to $DESTDIR/deployed_bin if $DESTDIR is set.
1576 install_bin,1590 install_bin,
1591 /// Path that artifacts will be written to by the build system.
1592 /// Equivalent to $DESTDIR/deployed_include if $DESTDIR is set.
1577 install_include,1593 install_include,
1594
1595 /// Path that artifacts will be deployed to on the target system.
1596 /// Unaffected by $DESTDIR.
1597 deployed_prefix,
1598 /// Path that artifacts will be deployed to on the target system.
1599 /// Unaffected by $DESTDIR.
1600 deployed_lib,
1601 /// Path that artifacts will be deployed to on the target system.
1602 /// Unaffected by $DESTDIR.
1603 deployed_bin,
1604 /// Path that artifacts will be deployed to on the target system.
1605 /// Unaffected by $DESTDIR.
1606 deployed_include,
1607
1578 libc_runtimes,1608 libc_runtimes,
1579 };1609 };
1580 };1610 };