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-17 20:12:39+02:00
logf2f0d97a9b9df2e4aa43c1e4b7876bcc97cb83ff
tree58224cd6c8a44abfdfb492c3fb9e3c5f6533b34a
parent093d28dfae39a64ef315c334e70ab3b72a698bb7

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
...@@ -44,7 +44,8 @@ pub const std_options: std.Options = .{...@@ -44,7 +44,8 @@ pub const std_options: std.Options = .{
4444
45gpa: Allocator,45gpa: Allocator,
46graph: *Graph,46graph: *Graph,
47install_paths: InstallPaths,47install_paths: PrefixPaths,
48deployed_paths: PrefixPaths,
48scanned_config: *const ScannedConfig,49scanned_config: *const ScannedConfig,
49/// Includes an extra auto-generated placeholder Step at the end that indicates50/// Includes an extra auto-generated placeholder Step at the end that indicates
50/// configure must be rerun. It is done this way so that the hot path of file51/// configure must be rerun. It is done this way so that the hot path of file
...@@ -95,7 +96,7 @@ const use_safe_allocator = switch (builtin.mode) {...@@ -95,7 +96,7 @@ const use_safe_allocator = switch (builtin.mode) {
95 .fast, .small => false,96 .fast, .small => false,
96};97};
9798
98const InstallPaths = struct {99const PrefixPaths = struct {
99 prefix: Path,100 prefix: Path,
100 lib: Path,101 lib: Path,
101 bin: Path,102 bin: Path,
...@@ -692,42 +693,62 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -692,42 +693,62 @@ pub fn main(init: process.Init.Minimal) !void {
692 });693 });
693 defer main_progress_node.end();694 defer main_progress_node.end();
694695
695 const install_prefix_path: Path = if (graph.environ_map.get("DESTDIR")) |dest_dir| .{696 const deployed_paths: PrefixPaths = blk: {
696 .root_dir = .cwd(),697 const prefix: Path = if (override_install_prefix) |cwd_relative| .{
697 .sub_path = try Dir.path.join(arena, &.{ dest_dir, override_install_prefix orelse "/usr" }),698 .root_dir = .cwd(),
698 } else if (override_install_prefix) |cwd_relative| .{699 .sub_path = cwd_relative,
699 .root_dir = .cwd(),700 } else if (graph.environ_map.get("DESTDIR") != null) .{
700 .sub_path = cwd_relative,701 .root_dir = .cwd(),
701 } else .{702 .sub_path = "/usr",
702 .root_dir = graph.build_root_directory,703 } else .{
703 .sub_path = "zig-out",704 .root_dir = graph.build_root_directory,
705 .sub_path = "zig-out",
706 };
707 break :blk .{
708 .prefix = prefix,
709 // The lib/bin/include overrides are interpreted relative to the
710 // install prefix unless absolute paths are used.
711 .lib = if (override_lib_dir) |lib_dir|
712 if (Dir.path.isAbsolute(lib_dir)) .{
713 .root_dir = .cwd(),
714 .sub_path = lib_dir,
715 } else try prefix.join(arena, lib_dir)
716 else
717 try prefix.join(arena, "lib"),
718 .bin = if (override_bin_dir) |bin_dir|
719 if (Dir.path.isAbsolute(bin_dir)) .{
720 .root_dir = .cwd(),
721 .sub_path = bin_dir,
722 } else try prefix.join(arena, bin_dir)
723 else
724 try prefix.join(arena, "bin"),
725 .include = if (override_include_dir) |include_dir|
726 if (Dir.path.isAbsolute(include_dir)) .{
727 .root_dir = .cwd(),
728 .sub_path = include_dir,
729 } else try prefix.join(arena, include_dir)
730 else
731 try prefix.join(arena, "include"),
732 };
704 };733 };
705734 const install_paths: PrefixPaths = if (graph.environ_map.get("DESTDIR")) |destdir| .{
706 // These three overrides are meant to be relative to the install prefix,735 .prefix = .{
707 // not current working directory, unless absolute paths are used.
708 const install_lib_path: Path = if (override_lib_dir) |lib_dir|
709 if (Dir.path.isAbsolute(lib_dir)) .{
710 .root_dir = .cwd(),736 .root_dir = .cwd(),
711 .sub_path = lib_dir,737 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.prefix.sub_path }),
712 } else try install_prefix_path.join(arena, lib_dir)738 },
713 else739 .lib = .{
714 try install_prefix_path.join(arena, "lib");
715
716 const install_bin_path: Path = if (override_bin_dir) |bin_dir|
717 if (Dir.path.isAbsolute(bin_dir)) .{
718 .root_dir = .cwd(),740 .root_dir = .cwd(),
719 .sub_path = bin_dir,741 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.lib.sub_path }),
720 } else try install_prefix_path.join(arena, bin_dir)742 },
721 else743 .bin = .{
722 try install_prefix_path.join(arena, "bin");
723
724 const install_include_path: Path = if (override_include_dir) |include_dir|
725 if (Dir.path.isAbsolute(include_dir)) .{
726 .root_dir = .cwd(),744 .root_dir = .cwd(),
727 .sub_path = include_dir,745 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.bin.sub_path }),
728 } else try install_prefix_path.join(arena, include_dir)746 },
729 else747 .include = .{
730 try install_prefix_path.join(arena, "include");748 .root_dir = .cwd(),
749 .sub_path = try Dir.path.join(arena, &.{ destdir, deployed_paths.include.sub_path }),
750 },
751 } else deployed_paths;
731752
732 const now = Io.Clock.Timestamp.now(io, .awake);753 const now = Io.Clock.Timestamp.now(io, .awake);
733754
...@@ -830,12 +851,8 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -830,12 +851,8 @@ pub fn main(init: process.Init.Minimal) !void {
830 .gpa = gpa,851 .gpa = gpa,
831 .graph = &graph,852 .graph = &graph,
832 .scanned_config = &scanned_config,853 .scanned_config = &scanned_config,
833 .install_paths = .{854 .install_paths = install_paths,
834 .prefix = install_prefix_path,855 .deployed_paths = deployed_paths,
835 .lib = install_lib_path,
836 .bin = install_bin_path,
837 .include = install_include_path,
838 },
839856
840 .steps = &.{},857 .steps = &.{},
841 .generated_files = &.{},858 .generated_files = &.{},
...@@ -4099,6 +4116,10 @@ pub fn relativePath(...@@ -4099,6 +4116,10 @@ pub fn relativePath(
4099 .install_lib => try maker.install_paths.lib.join(arena, sub_path),4116 .install_lib => try maker.install_paths.lib.join(arena, sub_path),
4100 .install_bin => try maker.install_paths.bin.join(arena, sub_path),4117 .install_bin => try maker.install_paths.bin.join(arena, sub_path),
4101 .install_include => try maker.install_paths.include.join(arena, sub_path),4118 .install_include => try maker.install_paths.include.join(arena, sub_path),
4119 .deployed_prefix => try maker.deployed_paths.prefix.join(arena, sub_path),
4120 .deployed_lib => try maker.deployed_paths.lib.join(arena, sub_path),
4121 .deployed_bin => try maker.deployed_paths.bin.join(arena, sub_path),
4122 .deployed_include => try maker.deployed_paths.include.join(arena, sub_path),
4102 .libc_runtimes => if (maker.graph.libc_runtimes_dir) |libc_runtimes_dir| .{4123 .libc_runtimes => if (maker.graph.libc_runtimes_dir) |libc_runtimes_dir| .{
4103 .root_dir = .cwd(),4124 .root_dir = .cwd(),
4104 .sub_path = try Dir.path.join(arena, &.{ libc_runtimes_dir, sub_path }),4125 .sub_path = try Dir.path.join(arena, &.{ libc_runtimes_dir, sub_path }),
...@@ -4708,6 +4729,10 @@ fn confPathDepToCachePath(...@@ -4708,6 +4729,10 @@ fn confPathDepToCachePath(
4708 .install_lib => @panic("TODO"),4729 .install_lib => @panic("TODO"),
4709 .install_bin => @panic("TODO"),4730 .install_bin => @panic("TODO"),
4710 .install_include => @panic("TODO"),4731 .install_include => @panic("TODO"),
4732 .deployed_prefix => @panic("TODO"),
4733 .deployed_lib => @panic("TODO"),
4734 .deployed_bin => @panic("TODO"),
4735 .deployed_include => @panic("TODO"),
4711 .libc_runtimes => @panic("TODO"),4736 .libc_runtimes => @panic("TODO"),
4712 };4737 };
4713}4738}
lib/std/Build.zig+4
...@@ -2760,6 +2760,10 @@ fn validateConfigureDependency(lazy_path: LazyPath) void {...@@ -2760,6 +2760,10 @@ fn validateConfigureDependency(lazy_path: LazyPath) void {
2760 .install_lib,2760 .install_lib,
2761 .install_bin,2761 .install_bin,
2762 .install_include,2762 .install_include,
2763 .deployed_prefix,
2764 .deployed_lib,
2765 .deployed_bin,
2766 .deployed_include,
2763 => @panic("configure phase cannot depend on files installed during make phase"),2767 => @panic("configure phase cannot depend on files installed during make phase"),
2764 .libc_runtimes,2768 .libc_runtimes,
2765 => @panic("configure phase cannot depend on directory known only during make phase"),2769 => @panic("configure phase cannot depend on directory known only during make phase"),
lib/std/Build/Configuration.zig+30
...@@ -1607,6 +1607,13 @@ pub const LazyPath = union(@This().Tag) {...@@ -1607,6 +1607,13 @@ pub const LazyPath = union(@This().Tag) {
1607 _: u16 = 0,1607 _: u16 = 0,
1608 };1608 };
16091609
1610 /// The deployed_prefix and related paths exist to support the use-case
1611 /// of embedding absolute paths to other build artifacts in the build
1612 /// artifacts themselves. For example pkg-config files are artifacts
1613 /// which must contain absolute paths to the other library/header
1614 /// artifacts they describe. Note that this feature is only supported to
1615 /// faciliate interoperability with such legacy systems. In general,
1616 /// embedding absolute paths in build artifacts should be avoided.
1610 pub const Base = enum(u8) {1617 pub const Base = enum(u8) {
1611 cwd,1618 cwd,
1612 local_cache,1619 local_cache,
...@@ -1615,10 +1622,33 @@ pub const LazyPath = union(@This().Tag) {...@@ -1615,10 +1622,33 @@ pub const LazyPath = union(@This().Tag) {
1615 build_root,1622 build_root,
1616 zig_exe,1623 zig_exe,
1617 zig_lib,1624 zig_lib,
1625
1626 /// Path that artifacts will be written to by the build system.
1627 /// Equivalent to $DESTDIR/deployed_prefix if $DESTDIR is set.
1618 install_prefix,1628 install_prefix,
1629 /// Path that artifacts will be written to by the build system.
1630 /// Equivalent to $DESTDIR/deployed_lib if $DESTDIR is set.
1619 install_lib,1631 install_lib,
1632 /// Path that artifacts will be written to by the build system.
1633 /// Equivalent to $DESTDIR/deployed_bin if $DESTDIR is set.
1620 install_bin,1634 install_bin,
1635 /// Path that artifacts will be written to by the build system.
1636 /// Equivalent to $DESTDIR/deployed_include if $DESTDIR is set.
1621 install_include,1637 install_include,
1638
1639 /// Path that artifacts will be deployed to on the target system.
1640 /// Unaffected by $DESTDIR.
1641 deployed_prefix,
1642 /// Path that artifacts will be deployed to on the target system.
1643 /// Unaffected by $DESTDIR.
1644 deployed_lib,
1645 /// Path that artifacts will be deployed to on the target system.
1646 /// Unaffected by $DESTDIR.
1647 deployed_bin,
1648 /// Path that artifacts will be deployed to on the target system.
1649 /// Unaffected by $DESTDIR.
1650 deployed_include,
1651
1622 libc_runtimes,1652 libc_runtimes,
1623 };1653 };
1624 };1654 };