forked from lix-project/lix
Compare commits
17 commits
pipe-opera
...
main
Author | SHA1 | Date | |
---|---|---|---|
Artemis Tosini | 60a48311e8 | ||
jade | c4c7cb7613 | ||
Qyriad | 8d12e0fbb7 | ||
Artemis Tosini | 3b96b51cf4 | ||
jade | 98e8cf9c63 | ||
jade | 12a5838d11 | ||
jade | 2436f2110a | ||
jade | 916b5c68fb | ||
Artemis Tosini | 53f3e39815 | ||
Pierre Bourdon | 73c013a5df | ||
Pierre Bourdon | e76245f8e9 | ||
eldritch horrors | 472ff1b833 | ||
eldritch horrors | 7bf1aff44a | ||
eldritch horrors | 58a91d70c9 | ||
eldritch horrors | ad36fb43ad | ||
eldritch horrors | d70e045f90 | ||
eldritch horrors | 20f53346df |
|
@ -314,6 +314,10 @@ nlohmann_json = dependency('nlohmann_json', required : true)
|
|||
# *absolutely* are not going to make it work)
|
||||
lix_doc = declare_dependency(link_args : [ '-llix_doc' ])
|
||||
|
||||
if is_freebsd
|
||||
libprocstat = declare_dependency(link_args : [ '-lprocstat' ])
|
||||
endif
|
||||
|
||||
#
|
||||
# Build-time tools
|
||||
#
|
||||
|
|
36
package.nix
36
package.nix
|
@ -92,31 +92,19 @@ let
|
|||
|
||||
# Reimplementation of Nixpkgs' Meson cross file, with some additions to make
|
||||
# it actually work.
|
||||
mesonCrossFile =
|
||||
let
|
||||
cpuFamily =
|
||||
platform:
|
||||
with platform;
|
||||
if isAarch32 then
|
||||
"arm"
|
||||
else if isx86_32 then
|
||||
"x86"
|
||||
else
|
||||
platform.uname.processor;
|
||||
in
|
||||
builtins.toFile "lix-cross-file.conf" ''
|
||||
[properties]
|
||||
# Meson is convinced that if !buildPlatform.canExecute hostPlatform then we cannot
|
||||
# build anything at all, which is not at all correct. If we can't execute the host
|
||||
# platform, we'll just disable tests and doc gen.
|
||||
needs_exe_wrapper = false
|
||||
mesonCrossFile = builtins.toFile "lix-cross-file.conf" ''
|
||||
[properties]
|
||||
# Meson is convinced that if !buildPlatform.canExecute hostPlatform then we cannot
|
||||
# build anything at all, which is not at all correct. If we can't execute the host
|
||||
# platform, we'll just disable tests and doc gen.
|
||||
needs_exe_wrapper = false
|
||||
|
||||
[binaries]
|
||||
# Meson refuses to consider any CMake binary during cross compilation if it's
|
||||
# not explicitly specified here, in the cross file.
|
||||
# https://github.com/mesonbuild/meson/blob/0ed78cf6fa6d87c0738f67ae43525e661b50a8a2/mesonbuild/cmake/executor.py#L72
|
||||
cmake = 'cmake'
|
||||
'';
|
||||
[binaries]
|
||||
# Meson refuses to consider any CMake binary during cross compilation if it's
|
||||
# not explicitly specified here, in the cross file.
|
||||
# https://github.com/mesonbuild/meson/blob/0ed78cf6fa6d87c0738f67ae43525e661b50a8a2/mesonbuild/cmake/executor.py#L72
|
||||
cmake = 'cmake'
|
||||
'';
|
||||
|
||||
# The internal API docs need these for the build, but if we're not building
|
||||
# Nix itself, then these don't need to be propagated.
|
||||
|
|
|
@ -236,9 +236,9 @@ static int main_build_remote(int argc, char * * argv)
|
|||
}
|
||||
|
||||
#if __APPLE__
|
||||
futimes(bestSlotLock.get(), NULL);
|
||||
futimes(bestSlotLock.get(), nullptr);
|
||||
#else
|
||||
futimens(bestSlotLock.get(), NULL);
|
||||
futimens(bestSlotLock.get(), nullptr);
|
||||
#endif
|
||||
|
||||
lock.reset();
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "checked-arithmetic.hh"
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
#include <functional> // std::less
|
||||
#include <utility> // std::pair
|
||||
|
@ -18,8 +20,6 @@
|
|||
#include <gc/gc_allocator.h>
|
||||
#include <gc/gc_cpp.h>
|
||||
|
||||
#include "checked-arithmetic.hh"
|
||||
|
||||
/// calloc, transparently GC-enabled.
|
||||
#define LIX_GC_CALLOC(size) GC_MALLOC(size)
|
||||
|
||||
|
|
|
@ -695,7 +695,7 @@ struct GitInputScheme : InputScheme
|
|||
});
|
||||
Finally const _wait([&] { proc.wait(); });
|
||||
|
||||
unpackTarfile(*proc.stdout(), tmpDir);
|
||||
unpackTarfile(*proc.getStdout(), tmpDir);
|
||||
}
|
||||
|
||||
auto storePath = store->addToStore(name, tmpDir, FileIngestionMethod::Recursive, htSHA256, filter);
|
||||
|
|
|
@ -932,7 +932,7 @@ void runPostBuildHook(
|
|||
Finally const _wait([&] { proc.wait(); });
|
||||
|
||||
// FIXME just process the data, without a wrapper sink class
|
||||
proc.stdout()->drainInto(sink);
|
||||
proc.getStdout()->drainInto(sink);
|
||||
}
|
||||
|
||||
void DerivationGoal::buildDone()
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "store-api.hh"
|
||||
#include "goal.hh"
|
||||
#include "realisation.hh"
|
||||
#include <thread>
|
||||
#include <future>
|
||||
|
||||
namespace nix {
|
||||
|
@ -41,11 +40,6 @@ class DrvOutputSubstitutionGoal : public Goal {
|
|||
*/
|
||||
std::shared_ptr<Store> sub;
|
||||
|
||||
/**
|
||||
* The substituter thread.
|
||||
*/
|
||||
std::thread thr;
|
||||
|
||||
std::unique_ptr<MaintainCount<uint64_t>> maintainRunningSubstitutions;
|
||||
|
||||
struct DownloadState
|
||||
|
|
|
@ -22,7 +22,7 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod
|
|||
if (ex)
|
||||
logError(i->ex->info());
|
||||
else
|
||||
ex = std::move(i->ex);
|
||||
ex = std::move(*i->ex);
|
||||
}
|
||||
if (i->exitCode != Goal::ecSuccess) {
|
||||
if (auto i2 = dynamic_cast<DerivationGoal *>(i.get()))
|
||||
|
|
|
@ -34,18 +34,10 @@ BuildResult Goal::getBuildResult(const DerivedPath & req) const {
|
|||
}
|
||||
|
||||
|
||||
void addToWeakGoals(WeakGoals & goals, GoalPtr p)
|
||||
{
|
||||
if (goals.find(p) != goals.end())
|
||||
return;
|
||||
goals.insert(p);
|
||||
}
|
||||
|
||||
|
||||
void Goal::addWaitee(GoalPtr waitee)
|
||||
{
|
||||
waitees.insert(waitee);
|
||||
addToWeakGoals(waitee->waiters, shared_from_this());
|
||||
waitee->waiters.insert(shared_from_this());
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,15 +71,14 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
|
|||
void Goal::amDone(ExitCode result, std::optional<Error> ex)
|
||||
{
|
||||
trace("done");
|
||||
assert(exitCode == ecBusy);
|
||||
assert(result == ecSuccess || result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure);
|
||||
assert(!exitCode.has_value());
|
||||
exitCode = result;
|
||||
|
||||
if (ex) {
|
||||
if (!waiters.empty())
|
||||
logError(ex->info());
|
||||
else
|
||||
this->ex = std::move(*ex);
|
||||
this->ex = std::make_unique<Error>(std::move(*ex));
|
||||
}
|
||||
|
||||
for (auto & i : waiters) {
|
||||
|
|
|
@ -53,7 +53,7 @@ enum struct JobCategory {
|
|||
|
||||
struct Goal : public std::enable_shared_from_this<Goal>
|
||||
{
|
||||
typedef enum {ecBusy, ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode;
|
||||
typedef enum {ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode;
|
||||
|
||||
/**
|
||||
* Backlink to the worker.
|
||||
|
@ -96,7 +96,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
|
|||
/**
|
||||
* Whether the goal is finished.
|
||||
*/
|
||||
ExitCode exitCode = ecBusy;
|
||||
std::optional<ExitCode> exitCode;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -121,7 +121,7 @@ public:
|
|||
/**
|
||||
* Exception containing an error message, if any.
|
||||
*/
|
||||
std::optional<Error> ex;
|
||||
std::unique_ptr<Error> ex;
|
||||
|
||||
Goal(Worker & worker, DerivedPath path)
|
||||
: worker(worker)
|
||||
|
@ -175,6 +175,4 @@ public:
|
|||
virtual JobCategory jobCategory() const = 0;
|
||||
};
|
||||
|
||||
void addToWeakGoals(WeakGoals & goals, GoalPtr p);
|
||||
|
||||
}
|
||||
|
|
|
@ -1882,7 +1882,7 @@ void LocalDerivationGoal::runChild()
|
|||
sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING");
|
||||
sandboxArgs.push_back("1");
|
||||
}
|
||||
if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) {
|
||||
if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), nullptr)) {
|
||||
writeFull(STDERR_FILENO, "failed to configure sandbox\n");
|
||||
_exit(1);
|
||||
}
|
||||
|
|
|
@ -214,9 +214,7 @@ void PathSubstitutionGoal::tryToRun()
|
|||
|
||||
outPipe.create();
|
||||
|
||||
promise = std::promise<void>();
|
||||
|
||||
thr = std::thread([this]() {
|
||||
thr = std::async(std::launch::async, [this]() {
|
||||
auto & fetchPath = subPath ? *subPath : storePath;
|
||||
try {
|
||||
ReceiveInterrupts receiveInterrupts;
|
||||
|
@ -230,16 +228,12 @@ void PathSubstitutionGoal::tryToRun()
|
|||
copyStorePath(
|
||||
*sub, worker.store, fetchPath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs
|
||||
);
|
||||
|
||||
promise.set_value();
|
||||
} catch (const EndOfFile &) {
|
||||
promise.set_exception(std::make_exception_ptr(EndOfFile(
|
||||
throw EndOfFile(
|
||||
"NAR for '%s' fetched from '%s' is incomplete",
|
||||
sub->printStorePath(fetchPath),
|
||||
sub->getUri()
|
||||
)));
|
||||
} catch (...) {
|
||||
promise.set_exception(std::current_exception());
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -253,11 +247,10 @@ void PathSubstitutionGoal::finished()
|
|||
{
|
||||
trace("substitute finished");
|
||||
|
||||
thr.join();
|
||||
worker.childTerminated(this);
|
||||
|
||||
try {
|
||||
promise.get_future().get();
|
||||
thr.get();
|
||||
} catch (std::exception & e) {
|
||||
printError(e.what());
|
||||
|
||||
|
@ -316,9 +309,9 @@ void PathSubstitutionGoal::handleEOF(int fd)
|
|||
void PathSubstitutionGoal::cleanup()
|
||||
{
|
||||
try {
|
||||
if (thr.joinable()) {
|
||||
if (thr.valid()) {
|
||||
// FIXME: signal worker thread to quit.
|
||||
thr.join();
|
||||
thr.get();
|
||||
worker.childTerminated(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,9 +50,7 @@ struct PathSubstitutionGoal : public Goal
|
|||
/**
|
||||
* The substituter thread.
|
||||
*/
|
||||
std::thread thr;
|
||||
|
||||
std::promise<void> promise;
|
||||
std::future<void> thr;
|
||||
|
||||
/**
|
||||
* Whether to try to repair a valid path.
|
||||
|
|
|
@ -157,21 +157,13 @@ void Worker::removeGoal(GoalPtr goal)
|
|||
if (goal->exitCode == Goal::ecFailed && !settings.keepGoing)
|
||||
topGoals.clear();
|
||||
}
|
||||
|
||||
/* Wake up goals waiting for any goal to finish. */
|
||||
for (auto & i : waitingForAnyGoal) {
|
||||
GoalPtr goal = i.lock();
|
||||
if (goal) wakeUp(goal);
|
||||
}
|
||||
|
||||
waitingForAnyGoal.clear();
|
||||
}
|
||||
|
||||
|
||||
void Worker::wakeUp(GoalPtr goal)
|
||||
{
|
||||
goal->trace("woken up");
|
||||
addToWeakGoals(awake, goal);
|
||||
awake.insert(goal);
|
||||
}
|
||||
|
||||
|
||||
|
@ -213,7 +205,7 @@ void Worker::childStarted(GoalPtr goal, const std::set<int> & fds,
|
|||
}
|
||||
|
||||
|
||||
void Worker::childTerminated(Goal * goal, bool wakeSleepers)
|
||||
void Worker::childTerminated(Goal * goal)
|
||||
{
|
||||
auto i = std::find_if(children.begin(), children.end(),
|
||||
[&](const Child & child) { return child.goal2 == goal; });
|
||||
|
@ -236,16 +228,13 @@ void Worker::childTerminated(Goal * goal, bool wakeSleepers)
|
|||
|
||||
children.erase(i);
|
||||
|
||||
if (wakeSleepers) {
|
||||
|
||||
/* Wake up goals waiting for a build slot. */
|
||||
for (auto & j : wantingToBuild) {
|
||||
GoalPtr goal = j.lock();
|
||||
if (goal) wakeUp(goal);
|
||||
}
|
||||
|
||||
wantingToBuild.clear();
|
||||
/* Wake up goals waiting for a build slot. */
|
||||
for (auto & j : wantingToBuild) {
|
||||
GoalPtr goal = j.lock();
|
||||
if (goal) wakeUp(goal);
|
||||
}
|
||||
|
||||
wantingToBuild.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -257,21 +246,14 @@ void Worker::waitForBuildSlot(GoalPtr goal)
|
|||
(isSubstitutionGoal && getNrSubstitutions() < settings.maxSubstitutionJobs))
|
||||
wakeUp(goal); /* we can do it right away */
|
||||
else
|
||||
addToWeakGoals(wantingToBuild, goal);
|
||||
}
|
||||
|
||||
|
||||
void Worker::waitForAnyGoal(GoalPtr goal)
|
||||
{
|
||||
debug("wait for any goal");
|
||||
addToWeakGoals(waitingForAnyGoal, goal);
|
||||
wantingToBuild.insert(goal);
|
||||
}
|
||||
|
||||
|
||||
void Worker::waitForAWhile(GoalPtr goal)
|
||||
{
|
||||
debug("wait for a while");
|
||||
addToWeakGoals(waitingForAWhile, goal);
|
||||
waitingForAWhile.insert(goal);
|
||||
}
|
||||
|
||||
|
||||
|
@ -429,7 +411,7 @@ void Worker::waitForInput()
|
|||
GoalPtr goal = j->goal.lock();
|
||||
assert(goal);
|
||||
|
||||
if (goal->exitCode == Goal::ecBusy &&
|
||||
if (!goal->exitCode.has_value() &&
|
||||
0 != settings.maxSilentTime &&
|
||||
j->respectTimeouts &&
|
||||
after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime))
|
||||
|
@ -440,7 +422,7 @@ void Worker::waitForInput()
|
|||
continue;
|
||||
}
|
||||
|
||||
else if (goal->exitCode == Goal::ecBusy &&
|
||||
else if (!goal->exitCode.has_value() &&
|
||||
0 != settings.buildTimeout &&
|
||||
j->respectTimeouts &&
|
||||
after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout))
|
||||
|
|
|
@ -90,11 +90,6 @@ private:
|
|||
std::map<StorePath, std::weak_ptr<PathSubstitutionGoal>> substitutionGoals;
|
||||
std::map<DrvOutput, std::weak_ptr<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals;
|
||||
|
||||
/**
|
||||
* Goals waiting for busy paths to be unlocked.
|
||||
*/
|
||||
WeakGoals waitingForAnyGoal;
|
||||
|
||||
/**
|
||||
* Goals sleeping for a few seconds (polling a lock).
|
||||
*/
|
||||
|
@ -228,12 +223,9 @@ public:
|
|||
bool inBuildSlot, bool respectTimeouts);
|
||||
|
||||
/**
|
||||
* Unregisters a running child process. `wakeSleepers` should be
|
||||
* false if there is no sense in waking up goals that are sleeping
|
||||
* because they can't run yet (e.g., there is no free build slot,
|
||||
* or the hook would still say `postpone`).
|
||||
* Unregisters a running child process.
|
||||
*/
|
||||
void childTerminated(Goal * goal, bool wakeSleepers = true);
|
||||
void childTerminated(Goal * goal);
|
||||
|
||||
/**
|
||||
* Put `goal` to sleep until a build slot becomes available (which
|
||||
|
@ -241,12 +233,6 @@ public:
|
|||
*/
|
||||
void waitForBuildSlot(GoalPtr goal);
|
||||
|
||||
/**
|
||||
* Wait for any goal to finish. Pretty indiscriminate way to
|
||||
* wait for some resource that some other goal is holding.
|
||||
*/
|
||||
void waitForAnyGoal(GoalPtr goal);
|
||||
|
||||
/**
|
||||
* Wait for a few seconds and then retry this goal. Used when
|
||||
* waiting for a lock held by another process. This kind of
|
||||
|
|
|
@ -177,14 +177,14 @@ static bool hasVirt() {
|
|||
size_t size;
|
||||
|
||||
size = sizeof(hasVMM);
|
||||
if (sysctlbyname("kern.hv_vmm_present", &hasVMM, &size, NULL, 0) == 0) {
|
||||
if (sysctlbyname("kern.hv_vmm_present", &hasVMM, &size, nullptr, 0) == 0) {
|
||||
if (hasVMM)
|
||||
return false;
|
||||
}
|
||||
|
||||
// whether the kernel and hardware supports virt
|
||||
size = sizeof(hvSupport);
|
||||
if (sysctlbyname("kern.hv_support", &hvSupport, &size, NULL, 0) == 0) {
|
||||
if (sysctlbyname("kern.hv_support", &hvSupport, &size, nullptr, 0) == 0) {
|
||||
return hvSupport == 1;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -557,7 +557,7 @@ void LocalStore::openDB(State & state, bool create)
|
|||
if (sqlite3_exec(db, "pragma main.journal_size_limit = 1099511627776;", 0, 0, 0) != SQLITE_OK)
|
||||
SQLiteError::throw_(db, "setting journal_size_limit");
|
||||
int enable = 1;
|
||||
if (sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, &enable) != SQLITE_OK)
|
||||
if (sqlite3_file_control(db, nullptr, SQLITE_FCNTL_PERSIST_WAL, &enable) != SQLITE_OK)
|
||||
SQLiteError::throw_(db, "setting persistent WAL mode");
|
||||
}
|
||||
|
||||
|
|
|
@ -167,6 +167,9 @@ if host_machine.system() == 'linux'
|
|||
elif host_machine.system() == 'darwin'
|
||||
libstore_sources += files('platform/darwin.cc')
|
||||
libstore_headers += files('platform/darwin.hh')
|
||||
elif host_machine.system() == 'freebsd'
|
||||
libstore_sources += files('platform/freebsd.cc')
|
||||
libstore_headers += files('platform/freebsd.hh')
|
||||
else
|
||||
libstore_sources += files('platform/fallback.cc')
|
||||
libstore_headers += files('platform/fallback.hh')
|
||||
|
@ -202,23 +205,29 @@ foreach name, value : cpp_str_defines
|
|||
]
|
||||
endforeach
|
||||
|
||||
dependencies = [
|
||||
libarchive,
|
||||
liblixutil, # Internal.
|
||||
seccomp,
|
||||
sqlite,
|
||||
sodium,
|
||||
curl,
|
||||
openssl,
|
||||
aws_sdk,
|
||||
aws_s3,
|
||||
aws_sdk_transfer,
|
||||
nlohmann_json,
|
||||
]
|
||||
|
||||
if host_machine.system() == 'freebsd'
|
||||
dependencies += [ libprocstat ]
|
||||
endif
|
||||
|
||||
libstore = library(
|
||||
'lixstore',
|
||||
libstore_generated_headers,
|
||||
libstore_sources,
|
||||
dependencies : [
|
||||
libarchive,
|
||||
liblixutil, # Internal.
|
||||
seccomp,
|
||||
sqlite,
|
||||
sodium,
|
||||
curl,
|
||||
openssl,
|
||||
aws_sdk,
|
||||
aws_s3,
|
||||
aws_sdk_transfer,
|
||||
nlohmann_json,
|
||||
],
|
||||
dependencies : dependencies,
|
||||
cpp_args : cpp_args,
|
||||
cpp_pch : cpp_pch,
|
||||
install : true,
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "platform/linux.hh"
|
||||
#elif __APPLE__
|
||||
#include "platform/darwin.hh"
|
||||
#elif __FreeBSD__
|
||||
#include "platform/freebsd.hh"
|
||||
#else
|
||||
#include "platform/fallback.hh"
|
||||
#endif
|
||||
|
@ -16,6 +18,8 @@ std::shared_ptr<LocalStore> LocalStore::makeLocalStore(const Params & params)
|
|||
return std::shared_ptr<LocalStore>(new LinuxLocalStore(params));
|
||||
#elif __APPLE__
|
||||
return std::shared_ptr<LocalStore>(new DarwinLocalStore(params));
|
||||
#elif __FreeBSD__
|
||||
return std::shared_ptr<LocalStore>(new FreeBSDLocalStore(params));
|
||||
#else
|
||||
return std::shared_ptr<LocalStore>(new FallbackLocalStore(params));
|
||||
#endif
|
||||
|
@ -32,6 +36,8 @@ std::shared_ptr<LocalDerivationGoal> LocalDerivationGoal::makeLocalDerivationGoa
|
|||
return std::make_shared<LinuxLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||
#elif __APPLE__
|
||||
return std::make_shared<DarwinLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||
#elif __FreeBSD__
|
||||
return std::make_shared<FreeBSDLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||
#else
|
||||
return std::make_shared<FallbackLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||
#endif
|
||||
|
@ -53,6 +59,10 @@ std::shared_ptr<LocalDerivationGoal> LocalDerivationGoal::makeLocalDerivationGoa
|
|||
return std::make_shared<DarwinLocalDerivationGoal>(
|
||||
drvPath, drv, wantedOutputs, worker, buildMode
|
||||
);
|
||||
#elif __FreeBSD__
|
||||
return std::make_shared<FreeBSDLocalDerivationGoal>(
|
||||
drvPath, drv, wantedOutputs, worker, buildMode
|
||||
);
|
||||
#else
|
||||
return std::make_shared<FallbackLocalDerivationGoal>(
|
||||
drvPath, drv, wantedOutputs, worker, buildMode
|
||||
|
|
|
@ -235,15 +235,15 @@ void DarwinLocalDerivationGoal::execBuilder(std::string builder, Strings args, S
|
|||
if (drv->platform == "aarch64-darwin") {
|
||||
// Unset kern.curproc_arch_affinity so we can escape Rosetta
|
||||
int affinity = 0;
|
||||
sysctlbyname("kern.curproc_arch_affinity", NULL, NULL, &affinity, sizeof(affinity));
|
||||
sysctlbyname("kern.curproc_arch_affinity", nullptr, nullptr, &affinity, sizeof(affinity));
|
||||
|
||||
cpu_type_t cpu = CPU_TYPE_ARM64;
|
||||
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL);
|
||||
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, nullptr);
|
||||
} else if (drv->platform == "x86_64-darwin") {
|
||||
cpu_type_t cpu = CPU_TYPE_X86_64;
|
||||
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL);
|
||||
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, nullptr);
|
||||
}
|
||||
|
||||
posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
|
||||
posix_spawn(nullptr, builder.c_str(), nullptr, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
|
||||
}
|
||||
}
|
||||
|
|
142
src/libstore/platform/freebsd.cc
Normal file
142
src/libstore/platform/freebsd.cc
Normal file
|
@ -0,0 +1,142 @@
|
|||
#include "platform/freebsd.hh"
|
||||
#include "regex.hh"
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <libprocstat.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
static void readSysctlRoots(const char * name, UncheckedRoots & unchecked)
|
||||
{
|
||||
size_t len = 0;
|
||||
std::string value;
|
||||
if (int err = sysctlbyname(name, nullptr, &len, nullptr, 0) < 0) {
|
||||
if (err == ENOENT || err == EACCES) {
|
||||
return;
|
||||
} else {
|
||||
throw SysError(err, "sysctlbyname %1%", name);
|
||||
}
|
||||
}
|
||||
|
||||
value.resize(len, ' ');
|
||||
if (int err = sysctlbyname(name, value.data(), &len, nullptr, 0) < 0) {
|
||||
if (err == ENOENT || err == EACCES) {
|
||||
return;
|
||||
} else {
|
||||
throw SysError(err, "sysctlbyname %1%", name);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & path : tokenizeString<Strings>(value, ";")) {
|
||||
unchecked[path].emplace(fmt("{{sysctl:%1%}}", name));
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcstatDeleter
|
||||
{
|
||||
void operator()(struct procstat * ps)
|
||||
{
|
||||
procstat_close(ps);
|
||||
}
|
||||
};
|
||||
|
||||
template<auto del>
|
||||
struct ProcstatReferredDeleter
|
||||
{
|
||||
struct procstat * ps;
|
||||
|
||||
ProcstatReferredDeleter(struct procstat * ps) : ps(ps) {}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T * p)
|
||||
{
|
||||
del(ps, p);
|
||||
}
|
||||
};
|
||||
|
||||
void FreeBSDLocalStore::findPlatformRoots(UncheckedRoots & unchecked)
|
||||
{
|
||||
readSysctlRoots("kern.module_path", unchecked);
|
||||
|
||||
auto storePathRegex = regex::storePathRegex(storeDir);
|
||||
|
||||
auto ps = std::unique_ptr<struct procstat, ProcstatDeleter>(procstat_open_sysctl());
|
||||
if (!ps) {
|
||||
throw SysError("procstat_open_sysctl");
|
||||
}
|
||||
|
||||
auto procs = std::unique_ptr<struct kinfo_proc[], ProcstatReferredDeleter<procstat_freeprocs>>(
|
||||
nullptr, ps.get()
|
||||
);
|
||||
auto files = std::unique_ptr<struct filestat_list, ProcstatReferredDeleter<procstat_freefiles>>(
|
||||
nullptr, ps.get()
|
||||
);
|
||||
|
||||
unsigned int numprocs = 0;
|
||||
procs.reset(procstat_getprocs(ps.get(), KERN_PROC_PROC, 0, &numprocs));
|
||||
if (!procs || numprocs == 0) {
|
||||
throw SysError("procstat_getprocs");
|
||||
};
|
||||
|
||||
for (unsigned int procidx = 0; procidx < numprocs; procidx++) {
|
||||
// Includes file descriptors, executable, cwd,
|
||||
// and mmapped files (including dynamic libraries)
|
||||
files.reset(procstat_getfiles(ps.get(), &procs[procidx], 1));
|
||||
// We only have permission if we're root so just skip it if we fail
|
||||
if (!files) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (struct filestat * file = files->stqh_first; file; file = file->next.stqe_next) {
|
||||
if (!file->fs_path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string role;
|
||||
if (file->fs_uflags & PS_FST_UFLAG_CTTY) {
|
||||
role = "ctty";
|
||||
} else if (file->fs_uflags & PS_FST_UFLAG_CDIR) {
|
||||
role = "cwd";
|
||||
} else if (file->fs_uflags & PS_FST_UFLAG_JAIL) {
|
||||
role = "jail";
|
||||
} else if (file->fs_uflags & PS_FST_UFLAG_RDIR) {
|
||||
role = "root";
|
||||
} else if (file->fs_uflags & PS_FST_UFLAG_TEXT) {
|
||||
role = "text";
|
||||
} else if (file->fs_uflags & PS_FST_UFLAG_TRACE) {
|
||||
role = "trace";
|
||||
} else if (file->fs_uflags & PS_FST_UFLAG_MMAP) {
|
||||
role = "mmap";
|
||||
} else {
|
||||
role = fmt("fd/%1%", file->fs_fd);
|
||||
}
|
||||
|
||||
unchecked[file->fs_path].emplace(fmt("{procstat:%1%/%2%}", procs[procidx].ki_pid, role)
|
||||
);
|
||||
}
|
||||
|
||||
auto env_name = fmt("{procstat:%1%/env}", procs[procidx].ki_pid);
|
||||
// No need to free, the buffer is reused on next call and deallocated in procstat_close
|
||||
char ** env = procstat_getenvv(ps.get(), &procs[procidx], 0);
|
||||
if (env == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; env[i]; i++) {
|
||||
auto envString = std::string(env[i]);
|
||||
|
||||
auto envEnd = std::sregex_iterator{};
|
||||
for (auto match =
|
||||
std::sregex_iterator{envString.begin(), envString.end(), storePathRegex};
|
||||
match != envEnd;
|
||||
match++)
|
||||
{
|
||||
unchecked[match->str()].emplace(env_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
src/libstore/platform/freebsd.hh
Normal file
47
src/libstore/platform/freebsd.hh
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "build/local-derivation-goal.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "local-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* FreeBSD-specific implementation of LocalStore
|
||||
*/
|
||||
class FreeBSDLocalStore : public LocalStore
|
||||
{
|
||||
public:
|
||||
FreeBSDLocalStore(const Params & params)
|
||||
: StoreConfig(params)
|
||||
, LocalFSStoreConfig(params)
|
||||
, LocalStoreConfig(params)
|
||||
, Store(params)
|
||||
, LocalFSStore(params)
|
||||
, LocalStore(params)
|
||||
{
|
||||
}
|
||||
FreeBSDLocalStore(const std::string scheme, std::string path, const Params & params)
|
||||
: FreeBSDLocalStore(params)
|
||||
{
|
||||
throw UnimplementedError("FreeBSDLocalStore");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void findPlatformRoots(UncheckedRoots & unchecked) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* FreeBSD-specific implementation of LocalDerivationGoal
|
||||
*/
|
||||
class FreeBSDLocalDerivationGoal : public LocalDerivationGoal
|
||||
{
|
||||
public:
|
||||
using LocalDerivationGoal::LocalDerivationGoal;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
|
@ -15,6 +15,11 @@
|
|||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if __FreeBSD__
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <cgroup.hh>
|
||||
|
||||
|
@ -102,6 +107,24 @@ std::optional<Path> getSelfExe()
|
|||
return buf;
|
||||
else
|
||||
return std::nullopt;
|
||||
#elif __FreeBSD__
|
||||
int sysctlName[] = {
|
||||
CTL_KERN,
|
||||
KERN_PROC,
|
||||
KERN_PROC_PATHNAME,
|
||||
-1,
|
||||
};
|
||||
size_t pathLen = 0;
|
||||
if (sysctl(sysctlName, sizeof(sysctlName) / sizeof(sysctlName[0]), nullptr, &pathLen, nullptr, 0) < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<char> path(pathLen);
|
||||
if (sysctl(sysctlName, sizeof(sysctlName) / sizeof(sysctlName[0]), path.data(), &pathLen, nullptr, 0) < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return Path(path.begin(), path.end());
|
||||
#else
|
||||
return std::nullopt;
|
||||
#endif
|
||||
|
|
|
@ -21,22 +21,14 @@ Path absPath(Path path, std::optional<PathView> dir, bool resolveSymlinks)
|
|||
{
|
||||
if (path.empty() || path[0] != '/') {
|
||||
if (!dir) {
|
||||
#ifdef __GNU__
|
||||
/* GNU (aka. GNU/Hurd) doesn't have any limitation on path
|
||||
lengths and doesn't define `PATH_MAX'. */
|
||||
char *buf = getcwd(NULL, 0);
|
||||
if (buf == NULL)
|
||||
#else
|
||||
char buf[PATH_MAX];
|
||||
if (!getcwd(buf, sizeof(buf)))
|
||||
#endif
|
||||
if (!getcwd(buf, sizeof(buf))) {
|
||||
throw SysError("cannot get cwd");
|
||||
}
|
||||
path = concatStrings(buf, "/", path);
|
||||
#ifdef __GNU__
|
||||
free(buf);
|
||||
#endif
|
||||
} else
|
||||
} else {
|
||||
path = concatStrings(*dir, "/", path);
|
||||
}
|
||||
}
|
||||
return canonPath(path, resolveSymlinks);
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ std::pair<int, std::string> runProgram(RunOptions && options)
|
|||
try {
|
||||
auto proc = runProgram2(options);
|
||||
Finally const _wait([&] { proc.wait(); });
|
||||
stdout = proc.stdout()->drain();
|
||||
stdout = proc.getStdout()->drain();
|
||||
} catch (ExecError & e) {
|
||||
status = e.status;
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ public:
|
|||
|
||||
void wait();
|
||||
|
||||
Source * stdout() const { return stdoutSource.get(); }
|
||||
Source * getStdout() const { return stdoutSource.get(); };
|
||||
};
|
||||
|
||||
std::pair<int, std::string> runProgram(RunOptions && options);
|
||||
|
|
|
@ -54,7 +54,7 @@ TarArchive::TarArchive(Source & source, bool raw) : buffer(65536)
|
|||
archive_read_support_format_raw(archive);
|
||||
archive_read_support_format_empty(archive);
|
||||
}
|
||||
archive_read_set_option(archive, NULL, "mac-ext", NULL);
|
||||
archive_read_set_option(archive, nullptr, "mac-ext", nullptr);
|
||||
check(archive_read_open(archive, (void *)this, callback_open, callback_read, callback_close), "Failed to open archive (%s)");
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ TarArchive::TarArchive(const Path & path)
|
|||
|
||||
archive_read_support_filter_all(archive);
|
||||
archive_read_support_format_all(archive);
|
||||
archive_read_set_option(archive, NULL, "mac-ext", NULL);
|
||||
archive_read_set_option(archive, nullptr, "mac-ext", nullptr);
|
||||
check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s");
|
||||
}
|
||||
|
||||
|
|
|
@ -24,24 +24,17 @@ GroupedPaths getClosureInfo(ref<Store> store, const StorePath & toplevel)
|
|||
|
||||
GroupedPaths groupedPaths;
|
||||
|
||||
for (auto & path : closure) {
|
||||
for (auto const & path : closure) {
|
||||
/* Strip the output name. Unfortunately this is ambiguous (we
|
||||
can't distinguish between output names like "bin" and
|
||||
version suffixes like "unstable"). */
|
||||
static std::regex regex("(.*)-([a-z]+|lib32|lib64)");
|
||||
std::smatch match;
|
||||
std::cmatch match;
|
||||
std::string name{path.name()};
|
||||
// Used to keep name alive through being potentially overwritten below
|
||||
// (to not invalidate the references from the regex result)
|
||||
//
|
||||
// n.b. cannot be just path.name().{begin,end}() since that returns const
|
||||
// char *, which does not, for some reason, convert as required on
|
||||
// libstdc++. Seems like a libstdc++ bug or standard bug to me... we
|
||||
// can afford the allocation in any case.
|
||||
const std::string origName{path.name()};
|
||||
std::string_view const origName = path.name();
|
||||
std::string outputName;
|
||||
|
||||
if (std::regex_match(origName, match, regex)) {
|
||||
if (std::regex_match(origName.begin(), origName.end(), match, regex)) {
|
||||
name = match[1];
|
||||
outputName = match[2];
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ std::set<std::string> runResolver(const Path & filename)
|
|||
return {};
|
||||
}
|
||||
|
||||
char* obj = (char*) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd.get(), 0);
|
||||
char* obj = (char*) mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd.get(), 0);
|
||||
if (!obj)
|
||||
throw SysError("mmapping '%s'", filename);
|
||||
|
||||
|
|
Loading…
Reference in a new issue