This commit is contained in:
parent
a25b0a1ded
commit
8892154b28
70 changed files with 2780 additions and 596 deletions
|
|
@ -1,5 +1,5 @@
|
|||
//SPDX-License-Identifier: LGPL-3.0-only
|
||||
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||
|
||||
module;
|
||||
#if defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_pc_windows_msvc) || defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_w64_mingw32)
|
||||
|
|
@ -42,7 +42,7 @@ namespace {
|
|||
// don't keep the lock alive past our own release.
|
||||
class CacheLock {
|
||||
#ifdef CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_pc_linux_gnu
|
||||
int fd_ = -1;
|
||||
std::int32_t fd_ = -1;
|
||||
public:
|
||||
explicit CacheLock(const fs::path& cacheDir) {
|
||||
fd_ = ::open((cacheDir / ".lock").c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0644);
|
||||
|
|
@ -59,9 +59,7 @@ namespace {
|
|||
HANDLE handle_ = INVALID_HANDLE_VALUE;
|
||||
public:
|
||||
explicit CacheLock(const fs::path& cacheDir) {
|
||||
handle_ = CreateFileW((cacheDir / ".lock").wstring().c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
handle_ = CreateFileW((cacheDir / ".lock").wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (handle_ != INVALID_HANDLE_VALUE) {
|
||||
OVERLAPPED ov{};
|
||||
LockFileEx(handle_, LOCKFILE_EXCLUSIVE_LOCK, 0, MAXDWORD, MAXDWORD, &ov);
|
||||
|
|
@ -111,15 +109,43 @@ fs::path Crafter::GetCrafterBuildHome() {
|
|||
if (parent == dir) break;
|
||||
dir = parent;
|
||||
}
|
||||
std::string msg = std::format(
|
||||
"could not locate crafter-build runtime assets relative to {} (set CRAFTER_BUILD_HOME). Tried:",
|
||||
hostExe.string());
|
||||
std::string msg = std::format("could not locate crafter-build runtime assets relative to {} (set CRAFTER_BUILD_HOME). Tried:", hostExe.string());
|
||||
for (const auto& p : tried) {
|
||||
msg += "\n " + p.string();
|
||||
msg += std::format("\n {}", p.string());
|
||||
}
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
bool Crafter::MatchGlob(std::string_view glob, std::string_view name) {
|
||||
std::size_t gi = 0;
|
||||
std::size_t ni = 0;
|
||||
std::size_t star = std::string_view::npos;
|
||||
std::size_t mark = 0;
|
||||
while (ni < name.size()) {
|
||||
if (gi < glob.size() && (glob[gi] == '?' || glob[gi] == name[ni])) {
|
||||
++gi; ++ni;
|
||||
} else if (gi < glob.size() && glob[gi] == '*') {
|
||||
star = gi++;
|
||||
mark = ni;
|
||||
} else if (star != std::string_view::npos) {
|
||||
gi = star + 1;
|
||||
ni = ++mark;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (gi < glob.size() && glob[gi] == '*') ++gi;
|
||||
return gi == glob.size();
|
||||
}
|
||||
|
||||
bool Crafter::MatchAny(std::span<const std::string> globs, std::string_view name) {
|
||||
if (globs.empty()) return true;
|
||||
for (const auto& g : globs) {
|
||||
if (MatchGlob(g, name)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_pc_windows_msvc) || defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_w64_mingw32)
|
||||
std::string Crafter::RunCommand(const std::string_view cmd) {
|
||||
Progress::EchoCommand(cmd);
|
||||
|
|
@ -127,14 +153,14 @@ std::string Crafter::RunCommand(const std::string_view cmd) {
|
|||
std::string result;
|
||||
|
||||
// Use cmd.exe to interpret redirection
|
||||
std::string with = "cmd /C \"" + std::string(cmd) + " 2>&1\"";
|
||||
std::string with = std::format("cmd /C \"{} 2>&1\"", std::string(cmd));
|
||||
|
||||
FILE* pipe = _popen(with.c_str(), "r");
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("_popen() failed!");
|
||||
}
|
||||
|
||||
while (fgets(buffer.data(), static_cast<int>(buffer.size()), pipe) != nullptr) {
|
||||
while (fgets(buffer.data(), static_cast<std::int32_t>(buffer.size()), pipe) != nullptr) {
|
||||
result += buffer.data();
|
||||
}
|
||||
|
||||
|
|
@ -146,14 +172,14 @@ CommandResult Crafter::RunCommandChecked(std::string_view cmd) {
|
|||
std::array<char, 128> buffer;
|
||||
CommandResult result{};
|
||||
|
||||
std::string with = "cmd /C \"" + std::string(cmd) + " 2>&1\"";
|
||||
std::string with = std::format("cmd /C \"{} 2>&1\"", std::string(cmd));
|
||||
|
||||
FILE* pipe = _popen(with.c_str(), "r");
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("_popen() failed!");
|
||||
}
|
||||
|
||||
while (fgets(buffer.data(), static_cast<int>(buffer.size()), pipe) != nullptr) {
|
||||
while (fgets(buffer.data(), static_cast<std::int32_t>(buffer.size()), pipe) != nullptr) {
|
||||
result.output += buffer.data();
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +191,8 @@ CommandResult Crafter::RunCommandWithTimeout(std::string_view cmd, std::chrono::
|
|||
CommandResult result{};
|
||||
|
||||
SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, TRUE };
|
||||
HANDLE readEnd = nullptr, writeEnd = nullptr;
|
||||
HANDLE readEnd = nullptr;
|
||||
HANDLE writeEnd = nullptr;
|
||||
if (!CreatePipe(&readEnd, &writeEnd, &sa, 0)) {
|
||||
throw std::runtime_error("CreatePipe failed");
|
||||
}
|
||||
|
|
@ -196,14 +223,11 @@ CommandResult Crafter::RunCommandWithTimeout(std::string_view cmd, std::chrono::
|
|||
// &&, ||) as popen("/bin/sh -c …") does on Linux. cmd's special-case
|
||||
// /C parsing strips the outer quote pair when the inner text contains
|
||||
// additional quotes, which is the common case here.
|
||||
std::string wrapped = "cmd /C \"" + std::string(cmd) + "\"";
|
||||
std::string wrapped = std::format("cmd /C \"{}\"", std::string(cmd));
|
||||
std::vector<char> cmdBuf(wrapped.begin(), wrapped.end());
|
||||
cmdBuf.push_back('\0');
|
||||
|
||||
BOOL ok = CreateProcessA(
|
||||
nullptr, cmdBuf.data(), nullptr, nullptr, TRUE,
|
||||
CREATE_NO_WINDOW | CREATE_SUSPENDED,
|
||||
nullptr, nullptr, &si, &pi);
|
||||
BOOL ok = CreateProcessA(nullptr, cmdBuf.data(), nullptr, nullptr, TRUE, CREATE_NO_WINDOW | CREATE_SUSPENDED, nullptr, nullptr, &si, &pi);
|
||||
if (!ok) {
|
||||
CloseHandle(readEnd);
|
||||
CloseHandle(writeEnd);
|
||||
|
|
@ -226,9 +250,7 @@ CommandResult Crafter::RunCommandWithTimeout(std::string_view cmd, std::chrono::
|
|||
}
|
||||
});
|
||||
|
||||
DWORD waitMs = static_cast<DWORD>(std::min<long long>(
|
||||
static_cast<long long>(timeout.count()) * 1000LL,
|
||||
static_cast<long long>(INFINITE) - 1));
|
||||
DWORD waitMs = static_cast<DWORD>(std::min<std::int64_t>(static_cast<std::int64_t>(timeout.count()) * 1000LL, static_cast<std::int64_t>(INFINITE) - 1));
|
||||
DWORD waitResult = WaitForSingleObject(pi.hProcess, waitMs);
|
||||
|
||||
if (waitResult == WAIT_TIMEOUT) {
|
||||
|
|
@ -245,9 +267,9 @@ CommandResult Crafter::RunCommandWithTimeout(std::string_view cmd, std::chrono::
|
|||
// so the runner shows 💥 instead of a numeric exit code.
|
||||
if ((exit & 0xC0000000) == 0xC0000000) {
|
||||
result.crashed = true;
|
||||
result.signal = static_cast<int>(exit);
|
||||
result.signal = static_cast<std::int32_t>(exit);
|
||||
}
|
||||
result.exitCode = static_cast<int>(exit);
|
||||
result.exitCode = static_cast<std::int32_t>(exit);
|
||||
}
|
||||
|
||||
reader.join();
|
||||
|
|
@ -269,7 +291,7 @@ fs::path Crafter::GetCacheDir() {
|
|||
}
|
||||
|
||||
namespace {
|
||||
constexpr std::array<std::string_view, 10> kCrafterBuildModules = {
|
||||
constexpr std::array<std::string_view, 11> CrafterBuildModules = {
|
||||
"Crafter.Build-Shader",
|
||||
"Crafter.Build-Platform",
|
||||
"Crafter.Build-Interface",
|
||||
|
|
@ -277,6 +299,7 @@ namespace {
|
|||
"Crafter.Build-External",
|
||||
"Crafter.Build-Clang",
|
||||
"Crafter.Build-Test",
|
||||
"Crafter.Build-Lint",
|
||||
"Crafter.Build-Progress",
|
||||
"Crafter.Build-Asset",
|
||||
"Crafter.Build",
|
||||
|
|
@ -305,9 +328,9 @@ std::string Crafter::GetBaseCommand(const Configuration& config) {
|
|||
namespace {
|
||||
void EnsureCrafterBuildPcms(const fs::path& sourceDir, const fs::path& cacheDir) {
|
||||
CacheLock lock(cacheDir);
|
||||
for (std::string_view name : kCrafterBuildModules) {
|
||||
fs::path cppmPath = sourceDir / (std::string(name) + ".cppm");
|
||||
fs::path pcmPath = cacheDir / (std::string(name) + ".pcm");
|
||||
for (std::string_view name : CrafterBuildModules) {
|
||||
fs::path cppmPath = sourceDir / std::format("{}.cppm", name);
|
||||
fs::path pcmPath = cacheDir / std::format("{}.pcm", name);
|
||||
if (!fs::exists(cppmPath)) {
|
||||
throw std::runtime_error(std::format("module source {} not found in {} (set CRAFTER_BUILD_HOME)", name, sourceDir.string()));
|
||||
}
|
||||
|
|
@ -336,7 +359,7 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
if (!fs::exists(buildDir)) {
|
||||
fs::create_directories(buildDir);
|
||||
}
|
||||
fs::path dllPath = buildDir / (absProject.stem().string() + ".dll");
|
||||
fs::path dllPath = buildDir / std::format("{}.dll", absProject.stem().string());
|
||||
|
||||
char hostExeBuf[MAX_PATH];
|
||||
DWORD hostExeLen = GetModuleFileNameA(nullptr, hostExeBuf, MAX_PATH);
|
||||
|
|
@ -361,9 +384,7 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
|
||||
EnsureCrafterBuildPcms(sourceDir, cacheDir);
|
||||
|
||||
bool stale = !fs::exists(dllPath)
|
||||
|| fs::last_write_time(dllPath) < fs::last_write_time(absProject)
|
||||
|| fs::last_write_time(dllPath) < fs::last_write_time(hostExe);
|
||||
bool stale = !fs::exists(dllPath) || fs::last_write_time(dllPath) < fs::last_write_time(absProject) || fs::last_write_time(dllPath) < fs::last_write_time(hostExe);
|
||||
|
||||
if (stale) {
|
||||
fs::path crafterBuildLib = hostExe.parent_path() / "crafter-build.lib";
|
||||
|
|
@ -427,9 +448,7 @@ namespace {
|
|||
std::string MingwGccVersion() {
|
||||
fs::path includeRoot = MingwPrefix() / "include" / "c++";
|
||||
if (!fs::exists(includeRoot)) {
|
||||
throw std::runtime_error(std::format(
|
||||
"mingw-w64 not found at {} (install msys2 mingw-w64-x86_64-toolchain or set CRAFTER_MINGW_DIR)",
|
||||
MingwPrefix().string()));
|
||||
throw std::runtime_error(std::format("mingw-w64 not found at {} (install msys2 mingw-w64-x86_64-toolchain or set CRAFTER_MINGW_DIR)", MingwPrefix().string()));
|
||||
}
|
||||
std::vector<std::string> versions;
|
||||
for (const auto& entry : fs::directory_iterator(includeRoot)) {
|
||||
|
|
@ -505,13 +524,11 @@ namespace {
|
|||
void EnsureCrafterBuildPcms(const fs::path& sourceDir, const fs::path& cacheDir) {
|
||||
CacheLock lock(cacheDir);
|
||||
fs::path prefix = MingwPrefix();
|
||||
for (std::string_view name : kCrafterBuildModules) {
|
||||
fs::path cppmPath = sourceDir / (std::string(name) + ".cppm");
|
||||
fs::path pcmPath = cacheDir / (std::string(name) + ".pcm");
|
||||
for (std::string_view name : CrafterBuildModules) {
|
||||
fs::path cppmPath = sourceDir / std::format("{}.cppm", name);
|
||||
fs::path pcmPath = cacheDir / std::format("{}.pcm", name);
|
||||
if (!fs::exists(cppmPath)) {
|
||||
throw std::runtime_error(std::format(
|
||||
"module source {} not found in {} (set CRAFTER_BUILD_HOME)",
|
||||
name, sourceDir.string()));
|
||||
throw std::runtime_error(std::format("module source {} not found in {} (set CRAFTER_BUILD_HOME)", name, sourceDir.string()));
|
||||
}
|
||||
if (fs::exists(pcmPath) && fs::last_write_time(cppmPath) < fs::last_write_time(pcmPath)) {
|
||||
continue;
|
||||
|
|
@ -526,8 +543,7 @@ namespace {
|
|||
prefix.string(), cacheDir.string(), cppmPath.string(), pcmPath.string());
|
||||
CommandResult r = Crafter::RunCommandChecked(cmd);
|
||||
if (r.exitCode != 0) {
|
||||
throw std::runtime_error(std::format(
|
||||
"Failed to precompile {} (exit {}): {}", name, r.exitCode, r.output));
|
||||
throw std::runtime_error(std::format("Failed to precompile {} (exit {}): {}", name, r.exitCode, r.output));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -537,7 +553,7 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
fs::path absProject = fs::canonical(projectFile);
|
||||
fs::path buildDir = absProject.parent_path() / "build";
|
||||
if (!fs::exists(buildDir)) fs::create_directories(buildDir);
|
||||
fs::path dllPath = buildDir / (absProject.stem().string() + ".dll");
|
||||
fs::path dllPath = buildDir / std::format("{}.dll", absProject.stem().string());
|
||||
|
||||
char hostExeBuf[MAX_PATH];
|
||||
DWORD hostExeLen = GetModuleFileNameA(nullptr, hostExeBuf, MAX_PATH);
|
||||
|
|
@ -562,9 +578,7 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
|
||||
EnsureCrafterBuildPcms(sourceDir, cacheDir);
|
||||
|
||||
bool stale = !fs::exists(dllPath)
|
||||
|| fs::last_write_time(dllPath) < fs::last_write_time(absProject)
|
||||
|| fs::last_write_time(dllPath) < fs::last_write_time(hostExe);
|
||||
bool stale = !fs::exists(dllPath) || fs::last_write_time(dllPath) < fs::last_write_time(absProject) || fs::last_write_time(dllPath) < fs::last_write_time(hostExe);
|
||||
|
||||
if (stale) {
|
||||
// The import lib lives next to the launcher exe (Build()'s mingw
|
||||
|
|
@ -589,8 +603,7 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
|
||||
std::string result = RunCommand(compileCmd);
|
||||
if (!result.empty()) {
|
||||
throw std::runtime_error(std::format(
|
||||
"Failed to compile project {}: {}", absProject.string(), result));
|
||||
throw std::runtime_error(std::format("Failed to compile project {}: {}", absProject.string(), result));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -604,15 +617,13 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
|
||||
HMODULE handle = LoadLibraryA(dllPath.string().c_str());
|
||||
if (!handle) {
|
||||
throw std::runtime_error(std::format(
|
||||
"Failed to load project {}: error {}", dllPath.string(), GetLastError()));
|
||||
throw std::runtime_error(std::format("Failed to load project {}: error {}", dllPath.string(), GetLastError()));
|
||||
}
|
||||
|
||||
using ProjectFn = Configuration (*)(std::span<const std::string_view>);
|
||||
auto fn = reinterpret_cast<ProjectFn>(GetProcAddress(handle, "CrafterBuildProject"));
|
||||
if (!fn) {
|
||||
throw std::runtime_error(std::format(
|
||||
"CrafterBuildProject not found in {}: error {}", dllPath.string(), GetLastError()));
|
||||
throw std::runtime_error(std::format("CrafterBuildProject not found in {}: error {}", dllPath.string(), GetLastError()));
|
||||
}
|
||||
|
||||
return fn(args);
|
||||
|
|
@ -626,7 +637,7 @@ std::string Crafter::RunCommand(const std::string_view cmd) {
|
|||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
|
||||
std::string with = std::string(cmd) + " 2>&1";
|
||||
std::string with = std::format("{} 2>&1", cmd);
|
||||
// Open pipe to file
|
||||
FILE* pipe = popen(with.c_str(), "r");
|
||||
if (!pipe) throw std::runtime_error("popen() failed!");
|
||||
|
|
@ -645,7 +656,7 @@ CommandResult Crafter::RunCommandChecked(std::string_view cmd) {
|
|||
std::array<char, 128> buffer;
|
||||
CommandResult result{};
|
||||
|
||||
std::string with = std::string(cmd) + " 2>&1";
|
||||
std::string with = std::format("{} 2>&1", cmd);
|
||||
FILE* pipe = popen(with.c_str(), "r");
|
||||
if (!pipe) throw std::runtime_error("popen() failed!");
|
||||
|
||||
|
|
@ -653,7 +664,7 @@ CommandResult Crafter::RunCommandChecked(std::string_view cmd) {
|
|||
result.output += buffer.data();
|
||||
}
|
||||
|
||||
int status = pclose(pipe);
|
||||
std::int32_t status = pclose(pipe);
|
||||
if (WIFEXITED(status)) {
|
||||
result.exitCode = WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
|
|
@ -670,9 +681,7 @@ CommandResult Crafter::RunCommandWithTimeout(std::string_view cmd, std::chrono::
|
|||
std::array<char, 128> buffer;
|
||||
CommandResult result{};
|
||||
|
||||
std::string wrapped = std::format(
|
||||
"timeout --kill-after=2 {} {} 2>&1",
|
||||
timeout.count(), cmd);
|
||||
std::string wrapped = std::format("timeout --kill-after=2 {} {} 2>&1", timeout.count(), cmd);
|
||||
|
||||
FILE* pipe = popen(wrapped.c_str(), "r");
|
||||
if (!pipe) throw std::runtime_error("popen() failed!");
|
||||
|
|
@ -681,9 +690,9 @@ CommandResult Crafter::RunCommandWithTimeout(std::string_view cmd, std::chrono::
|
|||
result.output += buffer.data();
|
||||
}
|
||||
|
||||
int status = pclose(pipe);
|
||||
std::int32_t status = pclose(pipe);
|
||||
if (WIFEXITED(status)) {
|
||||
int code = WEXITSTATUS(status);
|
||||
std::int32_t code = WEXITSTATUS(status);
|
||||
if (code == 124) {
|
||||
result.timedOut = true;
|
||||
result.exitCode = 124;
|
||||
|
|
@ -774,7 +783,7 @@ std::string Crafter::BuildStdPcm(const Configuration& config, fs::path stdPcm) {
|
|||
// (e.g. -mrelaxed-simd) so the std BMI is feature-compatible. wasm only;
|
||||
// wasmVariantFlags is empty on every other path.
|
||||
if (isWasm) {
|
||||
for (const std::string& f : config.wasmVariantFlags) archFlags += " " + f;
|
||||
for (const std::string& f : config.wasmVariantFlags) archFlags += std::format(" {}", f);
|
||||
}
|
||||
// non-wasm cross builds: the driver ranks the host toolchain's own
|
||||
// libc++ headers (<install>/../include/c++/v1) above --sysroot, so
|
||||
|
|
@ -814,7 +823,7 @@ std::string Crafter::GetBaseCommand(const Configuration& config) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
constexpr std::array<std::string_view, 10> kCrafterBuildModules = {
|
||||
constexpr std::array<std::string_view, 11> CrafterBuildModules = {
|
||||
"Crafter.Build-Shader",
|
||||
"Crafter.Build-Platform",
|
||||
"Crafter.Build-Interface",
|
||||
|
|
@ -822,6 +831,7 @@ namespace {
|
|||
"Crafter.Build-External",
|
||||
"Crafter.Build-Clang",
|
||||
"Crafter.Build-Test",
|
||||
"Crafter.Build-Lint",
|
||||
"Crafter.Build-Progress",
|
||||
"Crafter.Build-Asset",
|
||||
"Crafter.Build",
|
||||
|
|
@ -829,9 +839,9 @@ namespace {
|
|||
|
||||
void EnsureCrafterBuildPcms(const fs::path& sourceDir, const fs::path& cacheDir) {
|
||||
CacheLock lock(cacheDir);
|
||||
for (std::string_view name : kCrafterBuildModules) {
|
||||
fs::path cppmPath = sourceDir / (std::string(name) + ".cppm");
|
||||
fs::path pcmPath = cacheDir / (std::string(name) + ".pcm");
|
||||
for (std::string_view name : CrafterBuildModules) {
|
||||
fs::path cppmPath = sourceDir / std::format("{}.cppm", name);
|
||||
fs::path pcmPath = cacheDir / std::format("{}.pcm", name);
|
||||
if (!fs::exists(cppmPath)) {
|
||||
throw std::runtime_error(std::format("module source {} not found in {} (set CRAFTER_BUILD_HOME)", name, sourceDir.string()));
|
||||
}
|
||||
|
|
@ -859,7 +869,7 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
if (!fs::exists(buildDir)) {
|
||||
fs::create_directories(buildDir);
|
||||
}
|
||||
fs::path soPath = buildDir / (absProject.stem().string() + ".so");
|
||||
fs::path soPath = buildDir / std::format("{}.so", absProject.stem().string());
|
||||
|
||||
fs::path hostExe = fs::read_symlink("/proc/self/exe");
|
||||
|
||||
|
|
@ -879,9 +889,7 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
|
||||
EnsureCrafterBuildPcms(sourceDir, cacheDir);
|
||||
|
||||
bool stale = !fs::exists(soPath)
|
||||
|| fs::last_write_time(soPath) < fs::last_write_time(absProject)
|
||||
|| fs::last_write_time(soPath) < fs::last_write_time(hostExe);
|
||||
bool stale = !fs::exists(soPath) || fs::last_write_time(soPath) < fs::last_write_time(absProject) || fs::last_write_time(soPath) < fs::last_write_time(hostExe);
|
||||
|
||||
if (stale) {
|
||||
std::string compileCmd = std::format(
|
||||
|
|
@ -914,4 +922,4 @@ Configuration Crafter::LoadProject(const fs::path& projectFile, std::span<const
|
|||
return fn(args);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue