aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig4
-rw-r--r--doc/internal-api/doxygen.cfg.in39
-rw-r--r--doc/internal-api/meson.build46
-rw-r--r--doc/manual/meson.build1
-rw-r--r--meson.build6
-rw-r--r--src/libstore/build/derivation-goal.cc9
-rw-r--r--src/libstore/build/derivation-goal.hh8
-rw-r--r--src/libstore/build/worker.cc47
-rw-r--r--src/libstore/build/worker.hh2
-rw-r--r--tests/functional/build.sh4
10 files changed, 101 insertions, 65 deletions
diff --git a/.editorconfig b/.editorconfig
index bcee9cfce..bbc2a4908 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -29,3 +29,7 @@ trim_trailing_whitespace = false
indent_style = space
indent_size = 2
max_line_length = 0
+
+[meson.build]
+indent_style = space
+indent_size = 2
diff --git a/doc/internal-api/doxygen.cfg.in b/doc/internal-api/doxygen.cfg.in
index 73fba6948..662fb4333 100644
--- a/doc/internal-api/doxygen.cfg.in
+++ b/doc/internal-api/doxygen.cfg.in
@@ -33,32 +33,7 @@ GENERATE_LATEX = NO
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-# FIXME Make this list more maintainable somehow. We could maybe generate this
-# in the Makefile, but we would need to change how `.in` files are preprocessed
-# so they can expand variables despite configure variables.
-
-INPUT = \
- src/libcmd \
- src/libexpr \
- src/libexpr/flake \
- tests/unit/libexpr \
- tests/unit/libexpr/value \
- tests/unit/libexpr/test \
- tests/unit/libexpr/test/value \
- src/libexpr/value \
- src/libfetchers \
- src/libmain \
- src/libstore \
- src/libstore/build \
- src/libstore/builtins \
- tests/unit/libstore \
- tests/unit/libstore/test \
- src/libutil \
- tests/unit/libutil \
- tests/unit/libutil/test \
- src/nix \
- src/nix-env \
- src/nix-store
+INPUT = @INPUT_PATHS@
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be
@@ -97,3 +72,15 @@ EXPAND_AS_DEFINED = \
DECLARE_WORKER_SERIALISER \
DECLARE_SERVE_SERIALISER \
LENGTH_PREFIXED_PROTO_HELPER
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = "@PROJECT_SOURCE_ROOT@"
diff --git a/doc/internal-api/meson.build b/doc/internal-api/meson.build
index faa30f194..af93b6943 100644
--- a/doc/internal-api/meson.build
+++ b/doc/internal-api/meson.build
@@ -1,3 +1,35 @@
+internal_api_sources = [
+ 'src/libcmd',
+ 'src/libexpr',
+ 'src/libexpr/flake',
+ 'tests/unit/libexpr',
+ 'tests/unit/libexpr/value',
+ 'tests/unit/libexpr/test',
+ 'tests/unit/libexpr/test/value',
+ 'src/libexpr/value',
+ 'src/libfetchers',
+ 'src/libmain',
+ 'src/libstore',
+ 'src/libstore/build',
+ 'src/libstore/builtins',
+ 'tests/unit/libstore',
+ 'tests/unit/libstore/test',
+ 'src/libutil',
+ 'tests/unit/libutil',
+ 'tests/unit/libutil/test',
+ 'src/nix',
+ 'src/nix-env',
+ 'src/nix-store',
+]
+
+# We feed Doxygen absolute paths so it can be invoked from any working directory.
+internal_api_sources_absolute = []
+foreach src : internal_api_sources
+ internal_api_sources_absolute += '"' + (meson.project_source_root() / src) + '"'
+endforeach
+
+internal_api_sources_oneline = ' \\\n '.join(internal_api_sources_absolute)
+
doxygen_cfg = configure_file(
input : 'doxygen.cfg.in',
output : 'doxygen.cfg',
@@ -5,22 +37,16 @@ doxygen_cfg = configure_file(
'PACKAGE_VERSION': meson.project_version(),
'RAPIDCHECK_HEADERS': rapidcheck_meson.get_variable('includedir'),
'docdir' : meson.current_build_dir(),
+ 'INPUT_PATHS' : internal_api_sources_oneline,
+ 'PROJECT_SOURCE_ROOT' : meson.project_source_root(),
},
)
internal_api_docs = custom_target(
'internal-api-docs',
command : [
- bash,
- # Meson can you please just give us a `workdir` argument to custom targets...
- '-c',
- # We have to prefix the doxygen_cfg path with the project build root
- # because of the cd in front.
- 'cd @0@ && @1@ @2@/@INPUT0@'.format(
- meson.project_source_root(),
- doxygen.full_path(),
- meson.project_build_root(),
- ),
+ doxygen.full_path(),
+ '@INPUT0@',
],
input : [
doxygen_cfg,
diff --git a/doc/manual/meson.build b/doc/manual/meson.build
index 38aad55b5..35d94740c 100644
--- a/doc/manual/meson.build
+++ b/doc/manual/meson.build
@@ -126,6 +126,7 @@ manual = custom_target(
'manual',
'markdown',
],
+ install : true,
install_dir : [
datadir / 'doc/nix',
false,
diff --git a/meson.build b/meson.build
index ea2050b6b..a8c6b9621 100644
--- a/meson.build
+++ b/meson.build
@@ -493,12 +493,6 @@ add_project_arguments(
'-Wdeprecated-copy',
'-Wignored-qualifiers',
'-Werror=suggest-override',
- # Enable assertions in libstdc++ by default. Harmless on libc++. Benchmarked
- # at ~1% overhead in `nix search`.
- #
- # FIXME: remove when we get meson 1.4.0 which will default this to on for us:
- # https://mesonbuild.com/Release-notes-for-1-4-0.html#ndebug-setting-now-controls-c-stdlib-assertions
- '-D_GLIBCXX_ASSERTIONS=1',
language : 'cpp',
)
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index fe2bb0145..60389fdd5 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -130,8 +130,12 @@ kj::Promise<Result<Goal::WorkResult>> DerivationGoal::work() noexcept
return useDerivation ? getDerivation() : haveDerivation();
}
-void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
+bool DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
{
+ if (isDone) {
+ return false;
+ }
+
auto newWanted = wantedOutputs.union_(outputs);
switch (needRestart) {
case NeedRestartForMoreOutputs::OutputsUnmodifedDontNeed:
@@ -148,6 +152,7 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
break;
};
wantedOutputs = newWanted;
+ return true;
}
@@ -1680,6 +1685,8 @@ Goal::Finished DerivationGoal::done(
SingleDrvOutputs builtOutputs,
std::optional<Error> ex)
{
+ isDone = true;
+
outputLocks.unlock();
buildResult.status = status;
if (ex)
diff --git a/src/libstore/build/derivation-goal.hh b/src/libstore/build/derivation-goal.hh
index 7505409c0..1e2f9b55c 100644
--- a/src/libstore/build/derivation-goal.hh
+++ b/src/libstore/build/derivation-goal.hh
@@ -74,6 +74,12 @@ struct DerivationGoal : public Goal
struct InputStream;
/**
+ * Whether this goal has completed. Completed goals can not be
+ * asked for more outputs, a new goal must be created instead.
+ */
+ bool isDone = false;
+
+ /**
* Whether to use an on-disk .drv file.
*/
bool useDerivation;
@@ -249,7 +255,7 @@ struct DerivationGoal : public Goal
/**
* Add wanted outputs to an already existing derivation goal.
*/
- void addWantedOutputs(const OutputsSpec & outputs);
+ bool addWantedOutputs(const OutputsSpec & outputs);
/**
* The states.
diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc
index 5be706e42..e063ede71 100644
--- a/src/libstore/build/worker.cc
+++ b/src/libstore/build/worker.cc
@@ -57,24 +57,35 @@ std::pair<std::shared_ptr<G>, kj::Promise<void>> Worker::makeGoalCommon(
std::map<ID, CachedGoal<G>> & map,
const ID & key,
InvocableR<std::unique_ptr<G>> auto create,
- std::invocable<G &> auto modify
+ InvocableR<bool, G &> auto modify
)
{
auto [it, _inserted] = map.try_emplace(key);
- auto & goal_weak = it->second;
- auto goal = goal_weak.goal.lock();
- if (!goal) {
- goal = create();
- goal->notify = std::move(goal_weak.fulfiller);
- goal_weak.goal = goal;
- // do not start working immediately, this round of the event loop
- // may have more calls to this function lined up that'll also run
- // modify(). starting early can then cause the goals to misbehave
- childStarted(goal, kj::evalLater([goal] { return goal->work(); }));
- } else {
- modify(*goal);
+ // try twice to create the goal. we can only loop if we hit the continue,
+ // and then we only want to recreate the goal *once*. concurrent accesses
+ // to the worker are not sound, we want to catch them if at all possible.
+ for ([[maybe_unused]] auto _attempt : {1, 2}) {
+ auto & goal_weak = it->second;
+ auto goal = goal_weak.goal.lock();
+ if (!goal) {
+ goal = create();
+ goal->notify = std::move(goal_weak.fulfiller);
+ goal_weak.goal = goal;
+ // do not start working immediately. if we are not yet running we
+ // may create dependencies as though they were toplevel goals, in
+ // which case the dependencies will not report build errors. when
+ // we are running we may be called for this same goal more times,
+ // and then we want to modify rather than recreate when possible.
+ childStarted(goal, kj::evalLater([goal] { return goal->work(); }));
+ } else {
+ if (!modify(*goal)) {
+ goal_weak = {};
+ continue;
+ }
+ }
+ return {goal, goal_weak.promise->addBranch()};
}
- return {goal, goal_weak.promise->addBranch()};
+ assert(false && "could not make a goal. possible concurrent worker access");
}
@@ -94,7 +105,7 @@ std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> Worker::makeDeriva
drvPath, wantedOutputs, *this, running, buildMode
);
},
- [&](DerivationGoal & g) { g.addWantedOutputs(wantedOutputs); }
+ [&](DerivationGoal & g) { return g.addWantedOutputs(wantedOutputs); }
);
}
@@ -118,7 +129,7 @@ std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> Worker::makeBasicD
drvPath, drv, wantedOutputs, *this, running, buildMode
);
},
- [&](DerivationGoal & g) { g.addWantedOutputs(wantedOutputs); }
+ [&](DerivationGoal & g) { return g.addWantedOutputs(wantedOutputs); }
);
}
@@ -132,7 +143,7 @@ Worker::makePathSubstitutionGoal(
substitutionGoals,
path,
[&] { return std::make_unique<PathSubstitutionGoal>(path, *this, running, repair, ca); },
- [&](auto &) {}
+ [&](auto &) { return true; }
);
}
@@ -146,7 +157,7 @@ Worker::makeDrvOutputSubstitutionGoal(
drvOutputSubstitutionGoals,
id,
[&] { return std::make_unique<DrvOutputSubstitutionGoal>(id, *this, running, repair, ca); },
- [&](auto &) {}
+ [&](auto &) { return true; }
);
}
diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh
index d6cde8384..cd49fb860 100644
--- a/src/libstore/build/worker.hh
+++ b/src/libstore/build/worker.hh
@@ -241,7 +241,7 @@ private:
std::map<ID, CachedGoal<G>> & map,
const ID & key,
InvocableR<std::unique_ptr<G>> auto create,
- std::invocable<G &> auto modify
+ InvocableR<bool, G &> auto modify
);
std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> makeDerivationGoal(
const StorePath & drvPath,
diff --git a/tests/functional/build.sh b/tests/functional/build.sh
index a14f6e3c2..58fba83aa 100644
--- a/tests/functional/build.sh
+++ b/tests/functional/build.sh
@@ -144,8 +144,8 @@ test "$(<<<"$out" grep -E '^error:' | wc -l)" = 1
# --keep-going and FOD
out="$(nix build -f fod-failing.nix -L 2>&1)" && status=0 || status=$?
test "$status" = 1
-# one "hash mismatch" error, one "build of ... failed"
-test "$(<<<"$out" grep -E '^error:' | wc -l)" = 2
+# at least one "hash mismatch" error, one "build of ... failed"
+test "$(<<<"$out" grep -E '^error:' | wc -l)" -ge 2
<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x.\\.drv'"
<<<"$out" grepQuiet -E "likely URL: "
<<<"$out" grepQuiet -E "error: build of '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out' failed"