167 lines
6.5 KiB
C++
167 lines
6.5 KiB
C++
|
|
/*
|
||
|
|
Crafter® Build
|
||
|
|
Copyright (C) 2026 Catcrafts®
|
||
|
|
Catcrafts.net
|
||
|
|
|
||
|
|
This library is free software; you can redistribute it and/or
|
||
|
|
modify it under the terms of the GNU Lesser General Public
|
||
|
|
License version 3.0 as published by the Free Software Foundation;
|
||
|
|
|
||
|
|
This library is distributed in the hope that it will be useful,
|
||
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
|
Lesser General Public License for more details.
|
||
|
|
|
||
|
|
You should have received a copy of the GNU Lesser General Public
|
||
|
|
License along with this library; if not, write to the Free Software
|
||
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
|
*/
|
||
|
|
|
||
|
|
export module Crafter.Build:Platform_impl;
|
||
|
|
import std;
|
||
|
|
import :Platform;
|
||
|
|
import :Clang;
|
||
|
|
namespace fs = std::filesystem;
|
||
|
|
using namespace Crafter;
|
||
|
|
|
||
|
|
|
||
|
|
#if defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_pc_windows_msvc) || defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_w64_mingw32)
|
||
|
|
std::string RunCommand(const std::string_view cmd) {
|
||
|
|
std::array<char, 128> buffer;
|
||
|
|
std::string result;
|
||
|
|
|
||
|
|
// Use cmd.exe to interpret redirection
|
||
|
|
std::string with = "cmd /C \"" + std::string(cmd) + " 2>&1\"";
|
||
|
|
|
||
|
|
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) {
|
||
|
|
result += buffer.data();
|
||
|
|
}
|
||
|
|
|
||
|
|
_pclose(pipe);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
fs::path BuildStdPcm(Configuration& config, fs::path stdPcm) {
|
||
|
|
std::string libcxx = std::getenv("LIBCXX_DIR");
|
||
|
|
std::string stdPcm = std::format("{}\\{}{}\\std.pcm", exeDir.string(), config.target, config.march);
|
||
|
|
std::string stdcppm = std::format("{}\\modules\\c++\\v1\\std.cppm", libcxx);
|
||
|
|
|
||
|
|
if(!fs::exists(stdPcm) || fs::last_write_time(stdPcm) < fs::last_write_time(stdcppm)) {
|
||
|
|
return RunCommand(std::format("clang++ --target={} -march={} -mtune={} -isystem %LIBCXX_DIR%\\include\\c++\\v1 -nostdinc++ -nostdlib++ -std=c++26 -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile %LIBCXX_DIR%\\modules\\c++\\v1\\std.cppm -o {}", config.target, config.march, config.mtune, stdPcm));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fs::path GetCacheDir() {
|
||
|
|
if (const char* local = std::getenv("LOCALAPPDATA")) {
|
||
|
|
return fs::path(local) / "crafter.build";
|
||
|
|
}
|
||
|
|
|
||
|
|
throw std::runtime_error("LOCALAPPDATA not set");
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GetBaseCommand(Configuration& config) {
|
||
|
|
return std::format("clang++ -nostdinc++ -nostdlib++ -isystem %LIBCXX_DIR%\\include\\c++\\v1");
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_pc_linux_gnu
|
||
|
|
|
||
|
|
std::string RunCommand(const std::string_view cmd) {
|
||
|
|
std::array<char, 128> buffer;
|
||
|
|
std::string result;
|
||
|
|
|
||
|
|
std::string with = std::string(cmd) + " 2>&1";
|
||
|
|
// Open pipe to file
|
||
|
|
FILE* pipe = popen(with.c_str(), "r");
|
||
|
|
if (!pipe) throw std::runtime_error("popen() failed!");
|
||
|
|
|
||
|
|
// Read till end of process:
|
||
|
|
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
|
||
|
|
result += buffer.data();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Close pipe
|
||
|
|
pclose(pipe);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
fs::path BuildStdPcm(Configuration& config, fs::path stdPcm) {
|
||
|
|
if(config.target == "x86_64-w64-mingw32") {
|
||
|
|
std::vector<std::string> folders;
|
||
|
|
|
||
|
|
// Iterate through the directory and collect all subdirectories
|
||
|
|
for (const auto& entry : fs::directory_iterator("/usr/x86_64-w64-mingw32/include/c++")) {
|
||
|
|
if (entry.is_directory()) {
|
||
|
|
folders.push_back(entry.path().filename().string());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Sort the folders by version in descending order
|
||
|
|
std::sort(folders.begin(), folders.end(), [](const std::string& a, const std::string& b) {
|
||
|
|
return std::lexicographical_compare(b.begin(), b.end(), a.begin(), a.end());
|
||
|
|
});
|
||
|
|
|
||
|
|
std::string mingWversion = folders.front();
|
||
|
|
|
||
|
|
fs::path stdCc = fs::path(std::format("/usr/x86_64-w64-mingw32/include/c++/{}/bits/std.cc", mingWversion));
|
||
|
|
|
||
|
|
if(!fs::exists(stdPcm) || fs::last_write_time(stdPcm) < fs::last_write_time(stdCc)) {
|
||
|
|
std::string result = RunCommand(std::format("cp {} {}/{}{}/std.cppm\nclang++ --target={} -march={} -mtune={} -O3 -std=c++26 -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile {}/{}{}/std.cppm -o {}", stdCc.string(), exeDir.string(), config.target, config.march, config.target, config.march, config.mtune, exeDir.string(), config.target, config.march, stdPcm));
|
||
|
|
if(!result.empty()) {
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
// Iterate over the source directory
|
||
|
|
for (const auto& entry : fs::directory_iterator("/usr/x86_64-w64-mingw32/bin/")) {
|
||
|
|
// Check if the file is a regular file and ends with ".dll"
|
||
|
|
if (fs::is_regular_file(entry) && entry.path().extension() == ".dll") {
|
||
|
|
// Construct the destination file path
|
||
|
|
fs::path dest_file = project.binDir / config.name / entry.path().filename();
|
||
|
|
|
||
|
|
// Check if the destination file exists and if it is older than the source file
|
||
|
|
if (!fs::exists(dest_file) || fs::last_write_time(entry.path()) > fs::last_write_time(dest_file)) {
|
||
|
|
// Copy the file if it doesn't exist or is older
|
||
|
|
fs::copy(entry.path(), dest_file, fs::copy_options::overwrite_existing);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} catch (const fs::filesystem_error& e) {
|
||
|
|
return e.what();
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if(!fs::exists(stdPcm) || fs::last_write_time(stdPcm) < fs::last_write_time("/usr/share/libc++/v1/std.cppm")) {
|
||
|
|
return RunCommand(std::format("clang++ --target={} -std=c++26 -stdlib=libc++ -march={} -mtune={} -O3 -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile /usr/share/libc++/v1/std.cppm -o {}", config.target, config.march, config.mtune, stdPcm));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fs::path GetCacheDir() {
|
||
|
|
if (const char* xdg = std::getenv("XDG_CACHE_HOME"); xdg && *xdg) {
|
||
|
|
return fs::path(xdg) / "crafter.build";
|
||
|
|
}
|
||
|
|
|
||
|
|
if (const char* home = std::getenv("HOME")) {
|
||
|
|
return fs::path(home) / ".cache" / "crafter.build";
|
||
|
|
}
|
||
|
|
|
||
|
|
throw std::runtime_error("Neither XDG_CACHE_HOME nor HOME set");
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GetBaseCommand(Configuration& config) {
|
||
|
|
std::string stdlib;
|
||
|
|
if(config.target == "x86_64-w64-mingw32") {
|
||
|
|
stdlib = "";
|
||
|
|
} else {
|
||
|
|
stdlib = "-stdlib=libc++";
|
||
|
|
}
|
||
|
|
std::string command = std::format("clang++ {}", stdlib);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|