diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml
index 89b8aac78..ec96f750e 100644
--- a/doc/manual/command-ref/conf-file.xml
+++ b/doc/manual/command-ref/conf-file.xml
@@ -562,6 +562,40 @@ flag, e.g. --option gc-keep-outputs false.
+ pre-build-hook
+
+
+
+
+ If set, the path to a program that can set extra
+ derivation-specific settings for this system. This is used for settings
+ that can't be captured by the derivation model itself and are too variable
+ between different versions of the same system to be hard-coded into nix.
+
+
+ The hook is passed the derivation path and, if chroots are enabled,
+ the chroot directory. It can then modify the chroot and send a series of
+ commands to modify various settings to stdout. The currently recognized
+ commands are:
+
+
+ extra-chroot-dirs
+
+
+
+ Pass a list of files and directories to be included in the
+ chroot for this build. One entry per line, terminated by an empty
+ line. Entries have the same format as build-chroot-dirs.
+
+
+
+
+
+
+
+
+
+
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 1fc5d4181..08b647cd6 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1969,6 +1969,42 @@ void DerivationGoal::startBuilder()
}
}
+ if (settings.preBuildHook != "") {
+ printMsg(lvlChatty, format("executing pre-build hook ‘%1%’")
+ % settings.preBuildHook);
+ auto args = useChroot ? Strings({drvPath, chrootRootDir}) :
+ Strings({ drvPath });
+ enum BuildHookState {
+ stBegin,
+ stExtraChrootDirs
+ };
+ auto state = stBegin;
+ auto lines = runProgram(settings.preBuildHook, false, args);
+ auto lastPos = std::string::size_type{0};
+ for (auto nlPos = lines.find('\n'); nlPos != string::npos;
+ nlPos = lines.find('\n', lastPos)) {
+ auto line = std::string{lines, lastPos, nlPos};
+ lastPos = nlPos + 1;
+ if (state == stBegin) {
+ if (line == "extra-chroot-dirs") {
+ state = stExtraChrootDirs;
+ } else {
+ throw Error(format("unknown pre-build hook command ‘%1%’")
+ % line);
+ }
+ } else if (state == stExtraChrootDirs) {
+ if (line == "") {
+ state = stBegin;
+ } else {
+ auto p = line.find('=');
+ if (p == string::npos)
+ dirsInChroot[line] = line;
+ else
+ dirsInChroot[string(line, 0, p)] = string(line, p + 1);
+ }
+ }
+ }
+ }
/* Run the builder. */
printMsg(lvlChatty, format("executing builder ‘%1%’") % drv.builder);
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 052ca45cc..d5615d93c 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -182,6 +182,7 @@ void Settings::update()
_get(logServers, "log-servers");
_get(enableImportNative, "allow-unsafe-native-code-during-evaluation");
_get(useCaseHack, "use-case-hack");
+ _get(preBuildHook, "pre-build-hook");
string subs = getEnv("NIX_SUBSTITUTERS", "default");
if (subs == "default") {
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 195558dd3..60b11afe6 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -206,6 +206,10 @@ struct Settings {
/* Whether the importNative primop should be enabled */
bool enableImportNative;
+ /* The hook to run just before a build to set derivation-specific
+ build settings */
+ Path preBuildHook;
+
private:
SettingsMap settings, overrides;