aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/BackendUtils.cpp51
-rw-r--r--backend/BackendUtils.hpp6
-rw-r--r--backend/ninja/Ninja.cpp223
m---------depends/libninja0
-rw-r--r--include/Conf.hpp36
-rw-r--r--include/Exec.hpp4
-rw-r--r--include/FileUtil.hpp24
-rw-r--r--include/GlobalLib.hpp4
-rw-r--r--include/PkgConfig.hpp9
-rw-r--r--src/CmakeModule.cpp53
-rw-r--r--src/Conf.cpp26
-rw-r--r--src/Exec.cpp173
-rw-r--r--src/GlobalLib.cpp89
-rw-r--r--src/PkgConfig.cpp83
-rw-r--r--src/main.cpp78
-rw-r--r--tests/src/confTest/confTest.cpp24
16 files changed, 399 insertions, 484 deletions
diff --git a/backend/BackendUtils.cpp b/backend/BackendUtils.cpp
index 158cd12..befd7ed 100644
--- a/backend/BackendUtils.cpp
+++ b/backend/BackendUtils.cpp
@@ -6,9 +6,9 @@
using namespace std;
using namespace sibs;
-static const char *cCompilerPath = nullptr;
-static const char *cppCompilerPath = nullptr;
-static const char *linkerPath = nullptr;
+static std::vector<FileString> cCompilerPath;
+static std::vector<FileString> cppCompilerPath;
+static std::vector<FileString> linkerPath;
namespace backend
{
@@ -108,7 +108,6 @@ namespace backend
#endif
projectConfPath += TINYDIR_STRING("project.conf");
- auto projectConfFileType = getFileType(projectConfPath.c_str());
if(!sibsConfig.isTest() && getFileType(projectConfPath.c_str()) == FileType::REGULAR)
{
backend::Ninja *subProject = new backend::Ninja();
@@ -131,82 +130,82 @@ namespace backend
});
}
- string BackendUtils::getCompilerCExecutable(Compiler compiler)
+ std::vector<sibs::FileString> BackendUtils::getCompilerCExecutable(Compiler compiler)
{
- if(cCompilerPath)
+ if(!cCompilerPath.empty())
return cCompilerPath;
char *cc = std::getenv("CC");
if(cc)
{
- cCompilerPath = cc;
+ cCompilerPath = { toFileString(cc) };
return cCompilerPath;
}
switch(compiler)
{
case Compiler::GCC:
- cCompilerPath = "ccache cc";
+ cCompilerPath = { TINYDIR_STRING("ccache"), TINYDIR_STRING("cc") };
break;
case Compiler::MINGW_W64:
- cCompilerPath = "x86_64-w64-mingw32-cc";
+ cCompilerPath = { TINYDIR_STRING("x86_64-w64-mingw32-cc") };
break;
case Compiler::MSVC:
- cCompilerPath = "cl.exe";
+ cCompilerPath = { TINYDIR_STRING("cl.exe") };
break;
}
return cCompilerPath;
}
- string BackendUtils::getCompilerCppExecutable(Compiler compiler)
+ std::vector<sibs::FileString> BackendUtils::getCompilerCppExecutable(Compiler compiler)
{
- if(cppCompilerPath)
+ if(!cppCompilerPath.empty())
return cppCompilerPath;
char *cxx = std::getenv("CXX");
if(cxx)
{
- cppCompilerPath = cxx;
+ cppCompilerPath = { toFileString(cxx) };
return cppCompilerPath;
}
switch(compiler)
{
case Compiler::GCC:
- cppCompilerPath = "ccache c++";
+ cppCompilerPath = { TINYDIR_STRING("ccache"), TINYDIR_STRING("c++") };
break;
case Compiler::MINGW_W64:
- cppCompilerPath = "x86_64-w64-mingw32-c++";
+ cppCompilerPath = { TINYDIR_STRING("x86_64-w64-mingw32-c++") };
break;
case Compiler::MSVC:
- cppCompilerPath = "cl.exe";
+ cppCompilerPath = { TINYDIR_STRING("cl.exe") };
break;
}
return cppCompilerPath;
}
- string BackendUtils::getCompilerLinker(Compiler compiler)
+ std::vector<sibs::FileString> BackendUtils::getCompilerLinker(Compiler compiler)
{
- if(linkerPath)
+ if(!linkerPath.empty())
return linkerPath;
char *ar = std::getenv("AR");
if(ar)
{
- linkerPath = ar;
+ linkerPath = { toFileString(ar) };
return linkerPath;
}
switch(compiler)
{
case Compiler::GCC:
- linkerPath = "ar";
+ linkerPath = { TINYDIR_STRING("ar") };
break;
case Compiler::MINGW_W64:
- linkerPath = "x86_64-w64-mingw32-ar";
+ linkerPath = { TINYDIR_STRING("x86_64-w64-mingw32-ar") };
break;
case Compiler::MSVC:
- linkerPath = "lib.exe";
+ linkerPath = { TINYDIR_STRING("lib.exe") };
break;
}
return linkerPath;
@@ -215,7 +214,9 @@ namespace backend
RuntimeCompilerType BackendUtils::getCCompilerType(Compiler compiler)
{
RuntimeCompilerType cCompilerType = RuntimeCompilerType::NONE;
- Result<ExecResult> cCompilerVersion = exec(toFileString(getCompilerCExecutable(compiler)) + TINYDIR_STRING(" --version"));
+ std::vector<FileString> args = getCompilerCExecutable(compiler);
+ args.push_back(TINYDIR_STRING("--version"));
+ Result<ExecResult> cCompilerVersion = exec(args);
if(cCompilerVersion && cCompilerVersion.unwrap().exitCode == 0)
{
if(cCompilerVersion.unwrap().execStdout.find("Emscripten") != string::npos)
@@ -231,7 +232,9 @@ namespace backend
RuntimeCompilerType BackendUtils::getCppCompilerType(Compiler compiler)
{
RuntimeCompilerType cppCompilerType = RuntimeCompilerType::NONE;
- Result<ExecResult> cppCompilerVersion = exec(toFileString(getCompilerCppExecutable(compiler)) + TINYDIR_STRING(" --version"));
+ std::vector<FileString> args = getCompilerCppExecutable(compiler);
+ args.push_back(TINYDIR_STRING("--version"));
+ Result<ExecResult> cppCompilerVersion = exec(args);
if(cppCompilerVersion && cppCompilerVersion.unwrap().exitCode == 0)
{
if(cppCompilerVersion.unwrap().execStdout.find("Emscripten") != string::npos)
diff --git a/backend/BackendUtils.hpp b/backend/BackendUtils.hpp
index d53620c..9992e5c 100644
--- a/backend/BackendUtils.hpp
+++ b/backend/BackendUtils.hpp
@@ -21,9 +21,9 @@ namespace backend
static sibs::Language getFileLanguage(const _tinydir_char_t *extension);
static sibs::Language getFileLanguage(tinydir_file *file);
static void collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const sibs::SibsConfig &sibsConfig, bool recursive = true);
- static std::string getCompilerCExecutable(sibs::Compiler compiler);
- static std::string getCompilerCppExecutable(sibs::Compiler compiler);
- static std::string getCompilerLinker(sibs::Compiler compiler);
+ static std::vector<sibs::FileString> getCompilerCExecutable(sibs::Compiler compiler);
+ static std::vector<sibs::FileString> getCompilerCppExecutable(sibs::Compiler compiler);
+ static std::vector<sibs::FileString> getCompilerLinker(sibs::Compiler compiler);
static RuntimeCompilerType getCCompilerType(sibs::Compiler compiler);
static RuntimeCompilerType getCppCompilerType(sibs::Compiler compiler);
};
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp
index ea3d96f..be78ba1 100644
--- a/backend/ninja/Ninja.cpp
+++ b/backend/ninja/Ninja.cpp
@@ -40,43 +40,6 @@ namespace backend
return result;
}
- static string join(const vector<string> &list, const char *joinStr)
- {
- if(list.empty()) return "";
- string result;
- long stringSize = 0;
- long joinStrLen = strlen(joinStr);
- int i = 0;
- for(const string &str : list)
- {
- stringSize += str.size();
- if(!str.empty() && i > 0)
- stringSize += joinStrLen;
- ++i;
- }
-
- result.reserve(stringSize);
-
- i = 0;
- for(const string &str : list)
- {
- if(i > 0)
- result += joinStr;
- result += str;
- ++i;
- }
-
- return result;
- }
-
- static bool endsWith(const string &str, const string &endWithStr)
- {
- if(endWithStr.size() > str.size())
- return false;
- else
- return strncmp(&str[str.size() - endWithStr.size()], &endWithStr[0], endWithStr.size()) == 0;
- }
-
static Ninja::LibraryType getNinjaLibraryType(PackageType packageType)
{
switch(packageType)
@@ -147,31 +110,6 @@ namespace backend
return "";
}
- static string getObjectFileNameFlag(Compiler compiler, const string &objectFileName)
- {
- string result;
- switch (compiler)
- {
- case Compiler::MINGW_W64:
- case Compiler::GCC:
- {
- result = "-o ";
- result += objectFileName;
- break;
- }
- case Compiler::MSVC:
- {
- result = "/Fo";
- result += objectFileName;
- break;
- }
- default:
- assert(false);
- break;
- }
- return result;
- }
-
static vector<ninja::NinjaArg> getLanguageVersionFlag(Compiler compiler, CVersion cVersion)
{
switch (compiler)
@@ -320,22 +258,20 @@ namespace backend
Result<bool> Ninja::getLinkerFlags(const SibsConfig &config, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback, CflagsCallbackFunc cflagsCallbackFunc) const
{
- const vector<PackageListDependency*> &packageListDependencies = config.getPackageListDependencies();
+ const vector<PackageListDependency> &packageListDependencies = config.getPackageListDependencies();
Result<FileString> globalLibDirResult = getHomeDir();
if (!globalLibDirResult)
return Result<bool>::Err(globalLibDirResult);
- FileString globalLibDir = globalLibDirResult.unwrap();
- globalLibDir += TINYDIR_STRING("/.cache/sibs/lib/");
- globalLibDir += toFileString(asString(config.platform));
- Result<bool> createGlobalLibDirResult = createDirectoryRecursive(globalLibDir.c_str());
+ Path globalLibDir = Path(globalLibDirResult.unwrap()).join(".cache/sibs/lib").join(toFileString(asString(config.platform)));
+ Result<bool> createGlobalLibDirResult = createDirectoryRecursive(globalLibDir.data.c_str());
if(createGlobalLibDirResult.isErr())
return createGlobalLibDirResult;
// If pkg-config is not available then it will be ignored and we check if package instead exists as a global lib (on github etc)
- vector<PackageListDependency*> globalLibDependencies;
- vector<PackageListDependency*> pkgConfigDependencies;
- for(PackageListDependency *dependency : packageListDependencies)
+ vector<PackageListDependency> globalLibDependencies;
+ vector<PackageListDependency> pkgConfigDependencies;
+ for(const PackageListDependency &dependency : packageListDependencies)
{
// PkgConfig libraries, even the static ones are most likely not built statically against libgcc/libc++, so we don't use them
if(!config.packaging && PkgConfig::validatePkgConfigPackageVersionExists(dependency))
@@ -353,7 +289,7 @@ namespace backend
{
printf("%s, using global lib...\n", pkgConfigFlagsResult.getErrMsg().c_str());
globalLibDependencies.reserve(globalLibDependencies.size() + pkgConfigDependencies.size());
- for (PackageListDependency *pkgConfigDependency : pkgConfigDependencies)
+ for (const PackageListDependency &pkgConfigDependency : pkgConfigDependencies)
{
globalLibDependencies.push_back(pkgConfigDependency);
}
@@ -368,7 +304,7 @@ namespace backend
cflagsCallbackFunc(pkgConfigFlag.cflags);
}
- return GlobalLib::getLibs(globalLibDependencies, config, globalLibDir, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
+ return GlobalLib::getLibs(globalLibDependencies, config, globalLibDir.data, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
}
Result<bool> Ninja::buildSubProjects(LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
@@ -764,9 +700,9 @@ namespace backend
Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
{
- string cCompilerName = BackendUtils::getCompilerCExecutable(config.getCompiler());
- string cppCompilerName = BackendUtils::getCompilerCppExecutable(config.getCompiler());
- string compilerLinker = BackendUtils::getCompilerLinker(config.getCompiler());
+ std::vector<FileString> cCompilerName = BackendUtils::getCompilerCExecutable(config.getCompiler());
+ std::vector<FileString> cppCompilerName = BackendUtils::getCompilerCppExecutable(config.getCompiler());
+ std::vector<FileString> compilerLinker = BackendUtils::getCompilerLinker(config.getCompiler());
RuntimeCompilerType cCompilerType = BackendUtils::getCCompilerType(config.getCompiler());
RuntimeCompilerType cppCompilerType = BackendUtils::getCppCompilerType(config.getCompiler());
@@ -786,19 +722,17 @@ namespace backend
if (!createBuildDirResult)
return createBuildDirResult;
- FileString generatedHeadersDir = config.getProjectPath() + TINYDIR_STRING("/sibs-build/");
- generatedHeadersDir += toFileString(asString(config.platform)) + TINYDIR_STRING("/");
- generatedHeadersDir += TINYDIR_STRING("generated-headers");
- Result<bool> createGeneratedHeadersDirResult = createDirectoryRecursive(generatedHeadersDir.c_str());
+ Path generatedHeadersDir = Path(config.getProjectPath()).join(TINYDIR_STRING("sibs-build")).join(toFileString(asString(config.platform))).join(TINYDIR_STRING("generated-headers"));
+ Result<bool> createGeneratedHeadersDirResult = createDirectoryRecursive(generatedHeadersDir.data.c_str());
if (!createGeneratedHeadersDirResult)
return createGeneratedHeadersDirResult;
- FileString generatedZigHeadersDir = generatedHeadersDir + TINYDIR_STRING("/zig");
- Result<bool> createGeneratedZigHeadersDirResult = createDirectory(generatedZigHeadersDir.c_str());
+ Path generatedZigHeadersDir = Path(generatedHeadersDir).join(TINYDIR_STRING("zig"));
+ Result<bool> createGeneratedZigHeadersDirResult = createDirectory(generatedZigHeadersDir.data.c_str());
if (!createGeneratedZigHeadersDirResult)
return createGeneratedZigHeadersDirResult;
- string generatedZigHeaderDirUtf8 = toUtf8(generatedZigHeadersDir);
+ string generatedZigHeaderDirUtf8 = toUtf8(generatedZigHeadersDir.data);
LibraryType libraryType = getNinjaLibraryType(config.getPackageType());
// TODO: Instead of statically linking everything, maybe we should build everything as they prefer to be built
@@ -814,8 +748,7 @@ namespace backend
string savePathUtf8 = toUtf8(savePath);
string projectPathUtf8 = toUtf8(config.getProjectPath());
- FileString ninjaBuildFilePath = savePath;
- ninjaBuildFilePath += TINYDIR_STRING("/build.ninja");
+ Path ninjaBuildFilePath = Path(savePath).join(TINYDIR_STRING("build.ninja"));
ninja::NinjaBuildFile ninjaBuildFile;
@@ -929,7 +862,7 @@ namespace backend
}
globalIncDir += dependencyExportIncludeDirs;
- globalIncDir += " " + getIncludeOptionFlag(config.getCompiler(), toUtf8(generatedHeadersDir));
+ globalIncDir += " " + getIncludeOptionFlag(config.getCompiler(), toUtf8(generatedHeadersDir.data));
ninjaBuildFile.defineGlobalVariable("globalIncDir", globalIncDir);
// TODO: Find a better way to convert includes, this could be slow...
ninjaBuildFile.defineGlobalVariable("globalIncDirZig", convertCIncludeSyntaxToZigInclude(config.getCompiler(), globalIncDir));
@@ -992,7 +925,6 @@ namespace backend
case LibraryType::EXECUTABLE:
{
baseCompileCArgs.insert(baseCompileCArgs.end(), {
- ninja::NinjaArg::createRaw(cCompilerName),
ninja::NinjaArg("-c"),
ninja::NinjaArg::createRaw("-fPIE -fPIC"),
ninja::NinjaArg("$in"),
@@ -1005,7 +937,6 @@ namespace backend
case LibraryType::DYNAMIC:
{
baseCompileCArgs.insert(baseCompileCArgs.end(), {
- ninja::NinjaArg::createRaw(cCompilerName),
ninja::NinjaArg("-c"),
ninja::NinjaArg("-fPIC"),
ninja::NinjaArg("$in"),
@@ -1064,11 +995,18 @@ namespace backend
compileCCommand.push_back(std::move(sanitizerFlag));
compileCppCommand = compileCCommand;
- compileCppCommand[0] = ninja::NinjaArg::createRaw(cppCompilerName);
compileCppCommand.insert(compileCppCommand.end(), {
ninja::NinjaArg("-fexceptions"),
ninja::NinjaArg("-Wnon-virtual-dtor")
});
+
+ for(auto it = cCompilerName.rbegin(), end = cCompilerName.rend(); it != end; ++it) {
+ compileCCommand.insert(compileCCommand.begin(), ninja::NinjaArg(*it));
+ }
+
+ for(auto it = cppCompilerName.rbegin(), end = cppCompilerName.rend(); it != end; ++it) {
+ compileCppCommand.insert(compileCppCommand.begin(), ninja::NinjaArg(*it));
+ }
break;
}
case Compiler::MSVC:
@@ -1388,9 +1326,17 @@ namespace backend
case Compiler::MINGW_W64:
case Compiler::GCC:
{
+ if(usesCppFiles) {
+ for(const FileString &arg : cppCompilerName) {
+ buildExeArgs.push_back(ninja::NinjaArg(arg));
+ }
+ } else {
+ for(const FileString &arg : cCompilerName) {
+ buildExeArgs.push_back(ninja::NinjaArg(arg));
+ }
+ }
string rpath = extractDynamicLibDirsFromLinkerFlags(dynamicLinkerFlags);
buildExeArgs.insert(buildExeArgs.end(), {
- ninja::NinjaArg::createRaw(usesCppFiles ? cppCompilerName : cCompilerName),
ninja::NinjaArg::createRaw("-o"),
ninja::NinjaArg::createRaw("$out"),
ninja::NinjaArg::createRaw("$in"),
@@ -1437,9 +1383,11 @@ namespace backend
}
case Compiler::MSVC:
{
+ for(const FileString &arg : cppCompilerName) {
+ buildExeArgs.push_back(ninja::NinjaArg(arg));
+ }
// TODO: Do not link all of these. Find a way to only link the ones that are needed
buildExeArgs.insert(buildExeArgs.end(), {
- ninja::NinjaArg::createRaw(cppCompilerName),
ninja::NinjaArg::createRaw("$in"),
ninja::NinjaArg::createRaw("/Fe$out"),
ninja::NinjaArg::createRaw("Ws2_32.lib"),
@@ -1535,8 +1483,10 @@ namespace backend
case Compiler::MINGW_W64:
case Compiler::GCC:
{
+ for(const FileString &arg : compilerLinker) {
+ buildStaticArgs.push_back(ninja::NinjaArg(arg));
+ }
buildStaticArgs.insert(buildStaticArgs.end(), {
- ninja::NinjaArg::createRaw(compilerLinker),
ninja::NinjaArg::createRaw("rcs"),
ninja::NinjaArg::createRaw("$out"),
ninja::NinjaArg::createRaw("$in")
@@ -1545,8 +1495,10 @@ namespace backend
}
case Compiler::MSVC:
{
+ for(const FileString &arg : compilerLinker) {
+ buildStaticArgs.push_back(ninja::NinjaArg(arg));
+ }
buildStaticArgs.insert(buildStaticArgs.end(), {
- ninja::NinjaArg::createRaw(compilerLinker),
ninja::NinjaArg::createRaw("/OUT:$out"),
ninja::NinjaArg::createRaw("$in")
});
@@ -1623,8 +1575,16 @@ namespace backend
case Compiler::MINGW_W64:
case Compiler::GCC:
{
+ if(usesCppFiles) {
+ for(const FileString &arg : cppCompilerName) {
+ buildDynamicArgs.push_back(ninja::NinjaArg(arg));
+ }
+ } else {
+ for(const FileString &arg : cCompilerName) {
+ buildDynamicArgs.push_back(ninja::NinjaArg(arg));
+ }
+ }
buildDynamicArgs.insert(buildDynamicArgs.end(), {
- ninja::NinjaArg::createRaw(usesCppFiles ? cppCompilerName : cCompilerName),
ninja::NinjaArg::createRaw("$in"),
ninja::NinjaArg::createRaw("-shared"),
ninja::NinjaArg("-Wl,-soname," + generatedFile),
@@ -1665,8 +1625,10 @@ namespace backend
}
case Compiler::MSVC:
{
+ for(const FileString &arg : compilerLinker) {
+ buildDynamicArgs.push_back(ninja::NinjaArg(arg));
+ }
buildDynamicArgs.insert(buildDynamicArgs.end(), {
- ninja::NinjaArg::createRaw(compilerLinker),
ninja::NinjaArg::createRaw("/OUT:$out"),
ninja::NinjaArg::createRaw("$in"),
ninja::NinjaArg::createRaw("Ws2_32.lib"),
@@ -1735,7 +1697,7 @@ namespace backend
if(!sourceFiles.empty())
{
string result = ninjaBuildFile.generate();
- Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size()));
+ Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.data.c_str(), sibs::StringView(result.data(), result.size()));
if (fileOverwriteResult.isErr())
return fileOverwriteResult;
@@ -1777,24 +1739,18 @@ namespace backend
parentExportIncludeDirs += getIncludeOptionFlag(config.getCompiler(), parentExportIncludeDir);
}
-#if OS_FAMILY == OS_FAMILY_POSIX
- FileString testSourceDirNative = testSourceDir;
- FileString projectConfFilePath = testSourceDir;
-#else
- FileString testSourceDirNative = utf8To16(testSourceDir);
- FileString projectConfFilePath = testSourceDirNative;
-#endif
- projectConfFilePath += TINYDIR_STRING("/project.conf");
+ Path testSourceDirNative = toFileString(testSourceDir);
+ Path projectConfFilePath = Path(testSourceDirNative).join("project.conf");
- FileType projectConfFileType = getFileType(projectConfFilePath.c_str());
- SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative, config.getOptimizationLevel());
+ FileType projectConfFileType = getFileType(projectConfFilePath.data.c_str());
+ SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative.data, config.getOptimizationLevel());
sibsTestConfig.platform = config.platform;
sibsTestConfig.setSanitize(config.getSanitize());
sibsTestConfig.zigTestFiles = move(config.zigTestFiles);
sibsTestConfig.zigTestAllFiles = config.zigTestAllFiles;
if(projectConfFileType == FileType::REGULAR)
{
- Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig);
+ Result<bool> result = Config::readFromFile(projectConfFilePath.data.c_str(), sibsTestConfig);
if(!result)
return result;
}
@@ -1826,7 +1782,7 @@ namespace backend
bool zigTest = false;
if(config.zigTestAllFiles)
{
- backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig);
+ backend::BackendUtils::collectSourceFiles(testSourceDirNative.data.c_str(), &ninja, sibsTestConfig);
// TODO: This can be optimized as well. No need to insert non-zig files if we are going to remove them.
// Maybe pass a filter callback function to @collectSourceFiles.
for(auto it = ninja.sourceFiles.begin(); it != ninja.sourceFiles.end(); )
@@ -1853,33 +1809,29 @@ namespace backend
}
else
{
- backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig);
+ backend::BackendUtils::collectSourceFiles(testSourceDirNative.data.c_str(), &ninja, sibsTestConfig);
}
if(!ninja.getSourceFiles().empty())
{
- FileString buildPath = testSourceDirNative;
- buildPath += TINYDIR_STRING("/sibs-build/") + toFileString(asString(config.platform));
+ Path buildPath = Path(testSourceDirNative).join(TINYDIR_STRING("sibs-build")).join(toFileString(asString(config.platform)));
switch(sibsTestConfig.getOptimizationLevel())
{
case OPT_LEV_DEBUG:
- buildPath += TINYDIR_STRING("/debug");
+ buildPath.join(TINYDIR_STRING("debug"));
break;
case OPT_LEV_RELEASE:
- buildPath += TINYDIR_STRING("/release");
+ buildPath.join(TINYDIR_STRING("release"));
break;
}
- Result<bool> buildFileResult = ninja.build(sibsTestConfig, buildPath.c_str());
+ Result<bool> buildFileResult = ninja.build(sibsTestConfig, buildPath.data.c_str());
if (!buildFileResult)
return buildFileResult;
if(!zigTest)
{
- FileString testExecutableName = buildPath;
- testExecutableName += TINYDIR_STRING("/");
- testExecutableName += toFileString(sibsTestConfig.getPackageName());
- Result<ExecResult> runTestResult = exec(testExecutableName.c_str(), true);
+ Result<ExecResult> runTestResult = exec({ Path(buildPath).join(toFileString(sibsTestConfig.getPackageName())).data }, true);
if(!runTestResult)
return Result<bool>::Err(runTestResult);
@@ -1893,26 +1845,7 @@ namespace backend
Result<bool> Ninja::compile(const _tinydir_char_t *buildFilePath)
{
-#if OS_TYPE == OS_TYPE_LINUX
- FileString command;
- if(isatty(STDOUT_FILENO) == 1)
- {
- command = TINYDIR_STRING("script -eqc 'ninja -C \"");
- command += buildFilePath;
- command += TINYDIR_STRING("\"' /dev/null");
- }
- else
- {
- command = TINYDIR_STRING("ninja -C \"");
- command += buildFilePath;
- command += TINYDIR_STRING("\"");
- }
-#else
- FileString command = TINYDIR_STRING("ninja -C \"");
- command += buildFilePath;
- command += TINYDIR_STRING("\"");
-#endif
- Result<ExecResult> execResult = exec(command.c_str(), true);
+ Result<ExecResult> execResult = exec({ TINYDIR_STRING("ninja"), TINYDIR_STRING("-C"), buildFilePath }, true);
if(execResult.isOk())
{
if(execResult.unwrap().exitCode == 0)
@@ -1929,15 +1862,17 @@ namespace backend
Result<bool> Ninja::buildCompilationDatabase(const _tinydir_char_t *buildFilePath, const FileString &saveDir)
{
- FileString command = TINYDIR_STRING("ninja -C \"");
- command += buildFilePath;
- command += TINYDIR_STRING("\" -t compdb compile_c compile_cpp > \"");
- command += saveDir;
- command += TINYDIR_STRING("/compile_commands.json\"");
- Result<ExecResult> execResult = exec(command.c_str(), false);
+ Result<ExecResult> execResult = exec({
+ TINYDIR_STRING("ninja"), TINYDIR_STRING("-C"), buildFilePath, TINYDIR_STRING("-t"),
+ TINYDIR_STRING("compdb"), TINYDIR_STRING("compile_c"), TINYDIR_STRING("compile_cpp")
+ }, false);
if(execResult)
{
- if(execResult.unwrap().exitCode != 0)
+ if(execResult.unwrap().exitCode == 0)
+ {
+ fileOverwrite(Path(saveDir).join("compile_commands.json").data.c_str(), { execResult.unwrap().execStdout.data(), execResult.unwrap().execStdout.size() });
+ }
+ else
{
string errMsg = "Failed to build compilation database, reason: ";
errMsg += execResult.unwrap().execStdout;
diff --git a/depends/libninja b/depends/libninja
-Subproject f3f053984698845828f169b1bcc09065bf9fe84
+Subproject 691adcce8c2b23af4d0ed855ac7003bda0c8a17
diff --git a/include/Conf.hpp b/include/Conf.hpp
index 8098206..cfe0133 100644
--- a/include/Conf.hpp
+++ b/include/Conf.hpp
@@ -237,10 +237,10 @@ namespace sibs
switch(optimizationLevel)
{
case OPT_LEV_DEBUG:
- cmakeArgsGlobal = TINYDIR_STRING("-G Ninja \"-DCMAKE_BUILD_TYPE=Debug\"");
+ cmakeArgsGlobal = { TINYDIR_STRING("-G"), TINYDIR_STRING("Ninja"), TINYDIR_STRING("-DCMAKE_BUILD_TYPE=Debug") };
break;
case OPT_LEV_RELEASE:
- cmakeArgsGlobal = TINYDIR_STRING("-G Ninja \"-DCMAKE_BUILD_TYPE=Release\"");
+ cmakeArgsGlobal = { TINYDIR_STRING("-G"), TINYDIR_STRING("Ninja"), TINYDIR_STRING("-DCMAKE_BUILD_TYPE=Release") };
break;
}
}
@@ -274,7 +274,7 @@ namespace sibs
this->testPath = testPath;
}
- virtual const std::vector<PackageListDependency*>& getPackageListDependencies() const
+ virtual const std::vector<PackageListDependency>& getPackageListDependencies() const
{
return packageListDependencies;
}
@@ -340,30 +340,24 @@ namespace sibs
}
// Get cmake args for all builds. This is args under [cmake] only
- const FileString& getCmakeArgs() const
+ const std::vector<FileString>& getCmakeArgs() const
{
return cmakeArgsGlobal;
}
// Get cmake args for static build. This is a combination of args under [cmake] and under [cmake.static]
- FileString getCmakeArgsStatic() const
+ std::vector<FileString> getCmakeArgsStatic() const
{
- FileString result;
- result.reserve(cmakeArgsGlobal.size() + 1 + cmakeArgsStatic.size());
- result += cmakeArgsGlobal;
- result += TINYDIR_STRING(" ");
- result += cmakeArgsStatic;
+ std::vector<FileString> result = cmakeArgsGlobal;
+ result.insert(result.end(), cmakeArgsStatic.begin(), cmakeArgsStatic.end());
return result;
}
// Get cmake args for dynamic build. This is a combination of args under [cmake] and under [cmake.dynamic]
- FileString getCmakeArgsDynamic() const
+ std::vector<FileString> getCmakeArgsDynamic() const
{
- FileString result;
- result.reserve(cmakeArgsGlobal.size() + 1 + cmakeArgsDynamic.size());
- result += cmakeArgsGlobal;
- result += TINYDIR_STRING(" ");
- result += cmakeArgsDynamic;
+ std::vector<FileString> result = cmakeArgsGlobal;
+ result.insert(result.end(), cmakeArgsDynamic.begin(), cmakeArgsDynamic.end());
return result;
}
@@ -451,7 +445,7 @@ namespace sibs
std::string parsePlatformConfigStatic(const StringView &fieldName, const ConfigValue &fieldValue);
void parsePlatformConfigStaticDebug(const StringView &fieldName, const ConfigValue &fieldValue);
void parsePlatformConfigStaticRelease(const StringView &fieldName, const ConfigValue &fieldValue);
- void parseCmake(const StringView &fieldName, const ConfigValue &fieldValue, FileString &cmakeDir, FileString &cmakeArgs);
+ void parseCmake(const StringView &fieldName, const ConfigValue &fieldValue, FileString &cmakeDir, std::vector<FileString> &cmakeArgs);
void validatePackageName() const;
protected:
StringView currentObject;
@@ -460,7 +454,7 @@ namespace sibs
std::string packageName;
FileString testPath;
PackageType packageType;
- std::vector<PackageListDependency*> packageListDependencies;
+ std::vector<PackageListDependency> packageListDependencies;
std::vector<Platform> platforms;
std::unordered_map<std::string, std::string> defines;
OptimizationLevel optimizationLevel;
@@ -469,9 +463,9 @@ namespace sibs
FileString cmakeDirGlobal;
FileString cmakeDirStatic;
FileString cmakeDirDynamic;
- FileString cmakeArgsGlobal;
- FileString cmakeArgsStatic;
- FileString cmakeArgsDynamic;
+ std::vector<FileString> cmakeArgsGlobal;
+ std::vector<FileString> cmakeArgsStatic;
+ std::vector<FileString> cmakeArgsDynamic;
CVersion cVersion;
CPPVersion cppVersion;
bool useCmake;
diff --git a/include/Exec.hpp b/include/Exec.hpp
index 93ce307..538f0dc 100644
--- a/include/Exec.hpp
+++ b/include/Exec.hpp
@@ -4,6 +4,7 @@
#include "Result.hpp"
#include "../include/FileUtil.hpp"
#include <string>
+#include <vector>
namespace sibs
{
@@ -13,8 +14,7 @@ namespace sibs
int exitCode;
};
- Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print = false);
- Result<ExecResult> exec(const FileString &cmd, bool print = false);
+ Result<ExecResult> exec(const std::vector<FileString> &args, bool print_instead_of_pipe = false);
}
#endif //SIBS_EXEC_HPP
diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp
index f2a1799..5bd4d33 100644
--- a/include/FileUtil.hpp
+++ b/include/FileUtil.hpp
@@ -38,6 +38,30 @@ namespace sibs
void replaceChar(FileString &input, wchar_t charToReplace, wchar_t charToReplaceWith);
#endif
+ class Path {
+ public:
+ Path(const FileString &str) : data(str) {}
+
+ Path& join(const _tinydir_char_t *str) {
+ data += TINYDIR_STRING("/");
+ data += str;
+ return *this;
+ }
+
+ Path& join(const Path &other) {
+ data += TINYDIR_STRING("/");
+ data += other.data;
+ return *this;
+ }
+
+ Path& append(const FileString &str) {
+ data += str;
+ return *this;
+ }
+
+ FileString data;
+ };
+
// Return true if you want to continue iterating the remaining files, return false if you want to stop
using FileWalkCallbackFunc = std::function<bool(tinydir_file*)>;
diff --git a/include/GlobalLib.hpp b/include/GlobalLib.hpp
index 92739df..953df7e 100644
--- a/include/GlobalLib.hpp
+++ b/include/GlobalLib.hpp
@@ -18,10 +18,10 @@ namespace sibs
DEPENDENCY_VERSION_NO_MATCH = 20
};
- static Result<bool> getLibs(const std::vector<PackageListDependency*> &libs, const SibsConfig &parentConfig, const FileString &globalLibRootDir, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback);
+ static Result<bool> getLibs(const std::vector<PackageListDependency> &libs, const SibsConfig &parentConfig, const FileString &globalLibRootDir, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback);
static Result<bool> validatePackageExists(const FileString &globalLibRootDir, const std::string &name);
static Result<bool> getLibsLinkerFlags(const SibsConfig &parentConfig, const FileString &globalLibRootDir, const std::string &name, const PackageVersionRange &versionRange, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback);
- static Result<bool> downloadDependency(PackageListDependency *dependency, Platform platform);
+ static Result<bool> downloadDependency(const PackageListDependency &dependency, Platform platform);
private:
static Result<bool> getLibsLinkerFlagsCommon(const SibsConfig &parentConfig, const FileString &packageDir, const std::string &dependencyName, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback);
};
diff --git a/include/PkgConfig.hpp b/include/PkgConfig.hpp
index 24aeb78..23c1b12 100644
--- a/include/PkgConfig.hpp
+++ b/include/PkgConfig.hpp
@@ -22,13 +22,12 @@ namespace sibs
{
public:
static void setPkgConfigPath(const FileString &path);
- static Result<bool> validatePkgConfigPackageVersionExists(PackageListDependency *dependency);
+ static Result<bool> validatePkgConfigPackageVersionExists(const PackageListDependency &dependency);
static Result<bool> validatePackageExists(const std::string &name);
- static Result<bool> validatePackageVersionAtLeast(const std::string &name, const std::string &version);
static Result<PackageVersion> getPackageVersion(const std::string &name);
- static Result<std::string> getDynamicLibsLinkerFlags(const std::vector<PackageListDependency*> &libs);
- static Result<std::string> getDynamicLibsCflags(const std::vector<PackageListDependency*> &libs);
- static Result<PkgConfigFlags> getDynamicLibsFlags(const std::vector<PackageListDependency*> &libs);
+ static Result<std::string> getDynamicLibsLinkerFlags(const std::vector<PackageListDependency> &libs);
+ static Result<std::string> getDynamicLibsCflags(const std::vector<PackageListDependency> &libs);
+ static Result<PkgConfigFlags> getDynamicLibsFlags(const std::vector<PackageListDependency> &libs);
};
}
diff --git a/src/CmakeModule.cpp b/src/CmakeModule.cpp
index 5bf9400..a706e64 100644
--- a/src/CmakeModule.cpp
+++ b/src/CmakeModule.cpp
@@ -131,10 +131,10 @@ namespace sibs
// CMakeLists.txt may contain: set(CMAKE_MODULE_PATH "PathToModules"). This needs to be replaced with list append,
// otherwise our added module path is replaced.
// It may work to do like vcpkg instead - to use -DCMAKE_TOOLCHAIN_FILE program argument to specify path to script (https://github.com/Microsoft/vcpkg/blob/master/docs/examples/using-sqlite.md)
- vector<PackageListDependency*> globalLibDependencies;
+ vector<PackageListDependency> globalLibDependencies;
#if OS_FAMILY == OS_FAMILY_POSIX
- vector<PackageListDependency*> pkgConfigDependencies;
- for(PackageListDependency *dependency : config.getPackageListDependencies())
+ vector<PackageListDependency> pkgConfigDependencies;
+ for(const PackageListDependency &dependency : config.getPackageListDependencies())
{
Result<bool> pkgConfigDependencyValidation = PkgConfig::validatePkgConfigPackageVersionExists(dependency);
if(pkgConfigDependencyValidation.isOk())
@@ -153,7 +153,7 @@ namespace sibs
{
printf("%s, using global lib...\n", pkgConfigLinkerFlagsResult.getErrMsg().c_str());
globalLibDependencies.reserve(globalLibDependencies.size() + pkgConfigDependencies.size());
- for (PackageListDependency *pkgConfigDependency : pkgConfigDependencies)
+ for (const PackageListDependency &pkgConfigDependency : pkgConfigDependencies)
{
globalLibDependencies.push_back(pkgConfigDependency);
}
@@ -165,7 +165,7 @@ namespace sibs
dynamicLinkerFlagCallbackFunc(pkgConfigLinkerFlagsResult.unwrap());
}
#else
- for (PackageListDependency *dependency : config.getPackageListDependencies())
+ for (const PackageListDependency &dependency : config.getPackageListDependencies())
{
globalLibDependencies.push_back(dependency);
}
@@ -194,8 +194,7 @@ namespace sibs
_putenv("CXXFLAGS=-fPIC");
#endif
#endif
- FileString cmd = cmakePath;
- cmd += TINYDIR_STRING(" ");
+ std::vector<FileString> cmd = { cmakePath };
FileString cflags = TINYDIR_STRING("-fPIC");
FileString cxxflags;
@@ -240,56 +239,57 @@ namespace sibs
}
cxxflags = cflags;
- cmd += TINYDIR_STRING(" \"-DCMAKE_C_FLAGS=") + cflags + TINYDIR_STRING("\"");
- cmd += TINYDIR_STRING(" \"-DCMAKE_CXX_FLAGS=") + cxxflags + TINYDIR_STRING("\" ");
+ cmd.push_back(TINYDIR_STRING("-DCMAKE_C_FLAGS=") + cflags);
+ cmd.push_back(TINYDIR_STRING("-DCMAKE_CXX_FLAGS=") + cxxflags);
switch(config.getPackageType())
{
case PackageType::EXECUTABLE:
{
- cmd += config.getCmakeArgs();
+ auto cmake_args = config.getCmakeArgs();
+ cmd.insert(cmd.end(), cmake_args.begin(), cmake_args.end());
break;
}
case PackageType::STATIC:
{
- cmd += config.getCmakeArgsStatic();
+ auto cmake_args = config.getCmakeArgsStatic();
+ cmd.insert(cmd.end(), cmake_args.begin(), cmake_args.end());
break;
}
case PackageType::DYNAMIC:
case PackageType::LIBRARY:
{
- cmd += config.getCmakeArgsDynamic();
+ auto cmake_args = config.getCmakeArgsDynamic();
+ cmd.insert(cmd.end(), cmake_args.begin(), cmake_args.end());
break;
}
}
- //cmd += TINYDIR_STRING(" -DCMAKE_SKIP_RPATH=\"1\"");
- cmd += TINYDIR_STRING(" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON");
- cmd += TINYDIR_STRING(" \"-B");
- cmd += buildPath;
- cmd += TINYDIR_STRING("\" \"-H");
+ //cmd.push_back(TINYDIR_STRING("-DCMAKE_SKIP_RPATH=1"));
+ cmd.push_back(TINYDIR_STRING("-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"));
+ cmd.push_back(TINYDIR_STRING("-B") + buildPath);
+ cmd.push_back(TINYDIR_STRING("-H"));
switch(config.getPackageType())
{
case PackageType::EXECUTABLE:
{
- cmd += config.getCmakeDir();
+ cmd.back() += config.getCmakeDir();
break;
}
case PackageType::STATIC:
{
- cmd += config.getCmakeDirStatic();
+ cmd.back() += config.getCmakeDirStatic();
break;
}
case PackageType::DYNAMIC:
case PackageType::LIBRARY:
{
- cmd += config.getCmakeDirDynamic();
+ cmd.back() += config.getCmakeDirDynamic();
break;
}
}
- cmd += TINYDIR_STRING("\"");
- nprintf("Compiling with cmake with arguments: %s\n", cmd.c_str());
+ //nprintf("Compiling with cmake with arguments: %s\n", cmd.c_str());
- Result<ExecResult> execResult = exec(cmd.c_str(), true);
+ Result<ExecResult> execResult = exec(cmd, true);
if(execResult.isOk())
{
if(execResult.unwrap().exitCode != 0)
@@ -298,11 +298,8 @@ namespace sibs
else
return Result<bool>::Err(execResult);
- FileString ninjaCommand = TINYDIR_STRING("ninja -C \"");
- ninjaCommand += buildPath;
- ninjaCommand += TINYDIR_STRING("\"");
- nprintf("Compiling cmake generated ninja file: %s\n", ninjaCommand.c_str());
- execResult = exec(ninjaCommand.c_str(), true);
+ //nprintf("Compiling cmake generated ninja file: %s\n", buildPath.c_str());
+ execResult = exec({ TINYDIR_STRING("ninja"), TINYDIR_STRING("-C"), buildPath }, true);
if(execResult.isOk())
{
if(execResult.unwrap().exitCode != 0)
diff --git a/src/Conf.cpp b/src/Conf.cpp
index 12421e0..543c8d9 100644
--- a/src/Conf.cpp
+++ b/src/Conf.cpp
@@ -643,13 +643,7 @@ namespace sibs
SibsConfig::~SibsConfig()
{
- // TODO: Fix this shit.. why does this cause segfault?
- /*
- for(PackageListDependency *dependency : packageListDependencies)
- {
- //delete dependency;
- }
- */
+
}
bool SibsConfig::isDefined(const std::string &name) const
@@ -1102,10 +1096,10 @@ namespace sibs
if(!dependencyVersionResult)
throw ParserException("Dependency " + string(name.data, name.size) + " version is in invalid format, error: " + dependencyVersionResult.getErrMsg());
- PackageListDependency *dependency = new PackageListDependency();
- dependency->name = string(name.data, name.size);
- dependency->version = dependencyVersionResult.unwrap();
- packageListDependencies.emplace_back(dependency);
+ PackageListDependency dependency;
+ dependency.name = string(name.data, name.size);
+ dependency.version = dependencyVersionResult.unwrap();
+ packageListDependencies.push_back(std::move(dependency));
}
else
throw ParserException("Expected field under dependencies to be a single value or an object, was a list");
@@ -1287,7 +1281,7 @@ namespace sibs
getLibFiles(parsePlatformConfigStatic(fieldName, fieldValue), releaseStaticLibs);
}
- void SibsConfig::parseCmake(const StringView &fieldName, const ConfigValue &fieldValue, FileString &cmakeDir, FileString &cmakeArgs)
+ void SibsConfig::parseCmake(const StringView &fieldName, const ConfigValue &fieldValue, FileString &cmakeDir, std::vector<FileString> &cmakeArgs)
{
if(fieldName.equals("dir"))
{
@@ -1314,13 +1308,7 @@ namespace sibs
{
for(const StringView &arg : fieldValue.asList())
{
- bool prependSpace = !cmakeArgs.empty();
- cmakeArgs.reserve(cmakeArgs.size() + 4 + (prependSpace ? 1 : 0) + arg.size);
- if(prependSpace)
- cmakeArgs += TINYDIR_STRING(" ");
- cmakeArgs += TINYDIR_STRING("\"-D");
- cmakeArgs += toFileString(arg);
- cmakeArgs += TINYDIR_STRING("\"");
+ cmakeArgs.push_back(TINYDIR_STRING("-D") + toFileString(arg));
}
}
else
diff --git a/src/Exec.cpp b/src/Exec.cpp
index 169858f..12e373d 100644
--- a/src/Exec.cpp
+++ b/src/Exec.cpp
@@ -3,6 +3,7 @@
#if OS_FAMILY == OS_FAMILY_POSIX
#include <sys/wait.h>
+#include <unistd.h>
#endif
using namespace std;
@@ -13,60 +14,129 @@ const int BUFSIZE = 4096;
namespace sibs
{
#if OS_FAMILY == OS_FAMILY_POSIX
- Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print)
+ Result<ExecResult> exec(const std::vector<FileString> &args, bool print_instead_of_pipe)
{
char buffer[BUFSIZE];
std::string execStdout;
- FILE *pipe = popen(cmd, "r");
- if(!pipe)
- return Result<ExecResult>::Err("popen() failed");
- while(!feof(pipe))
- {
- if(fgets(buffer, BUFSIZE, pipe))
- {
- int bytesRead = strlen(buffer);
- execStdout.append(buffer, bytesRead);
- if(print)
- printf("%.*s", bytesRead, buffer);
+ if(args.empty())
+ return Result<ExecResult>::Err("exec requires at least one argument (the program name)");
+
+ std::vector<const char*> exec_args;
+ for(const FileString &arg : args) {
+ exec_args.push_back(arg.c_str());
+ }
+ exec_args.push_back(nullptr);
+
+ int fd[2];
+ if(!print_instead_of_pipe && pipe(fd) == -1)
+ return Result<ExecResult>::Err(strerror(errno));
+
+ pid_t pid = fork();
+ if(pid == -1) {
+ if(!print_instead_of_pipe) {
+ close(fd[0]);
+ close(fd[1]);
}
+ return Result<ExecResult>::Err("Failed to exec " + args[0] + " (failed to fork)");
+ } else if(pid == 0) { // child
+ if(!print_instead_of_pipe) {
+ dup2(fd[1], STDOUT_FILENO);
+ close(fd[0]);
+ close(fd[1]);
+ }
+ execvp(exec_args[0], (char* const*)exec_args.data());
+ perror("execvp");
+ _exit(127);
+ } else { // parent
+ if(!print_instead_of_pipe)
+ close(fd[1]);
}
- int processCloseResult = pclose(pipe);
- if(WIFEXITED(processCloseResult))
+ if(!print_instead_of_pipe) {
+ for(;;) {
+ ssize_t bytes_read = read(fd[0], buffer, sizeof(buffer));
+ if(bytes_read == 0) {
+ break;
+ } else if(bytes_read == -1) {
+ std::string err_msg = "Failed to read from pipe to program " + args[0] + ", error: " + strerror(errno);
+ kill(pid, SIGTERM);
+ close(fd[0]);
+ return Result<ExecResult>::Err(err_msg);
+ }
+
+ execStdout.append(buffer, bytes_read);
+ }
+ }
+
+ int status = 0;
+ if(waitpid(pid, &status, 0) == -1) {
+ std::string err_msg = std::string("waitpid failed, error: ") + strerror(errno);
+ if(!print_instead_of_pipe)
+ close(fd[0]);
+ return Result<ExecResult>::Err(err_msg);
+ }
+ if(!print_instead_of_pipe)
+ close(fd[0]);
+
+ if(WIFEXITED(status))
{
- int returned = WEXITSTATUS(processCloseResult);
+ int returned = WEXITSTATUS(status);
ExecResult execResult;
execResult.execStdout = move(execStdout);
execResult.exitCode = returned;
return Result<ExecResult>::Ok(execResult);
}
- else if(WIFSIGNALED(processCloseResult))
+ else if(WIFSIGNALED(status))
{
- int signum = WSTOPSIG(processCloseResult);
+ int signum = WSTOPSIG(status);
string errMsg = "Exited due to receiving signal ";
errMsg += to_string(signum);
return Result<ExecResult>::Err(errMsg);
}
- else if(WIFSTOPPED(processCloseResult))
+ else if(WIFSTOPPED(status))
{
- int signum = WSTOPSIG(processCloseResult);
+ int signum = WSTOPSIG(status);
string errMsg = "Stopped due to receiving signal ";
errMsg += to_string(signum);
return Result<ExecResult>::Err(errMsg);
}
else
{
- string errMsg = "exec unexpected error on pclose: ";
- errMsg += to_string(processCloseResult);
+ string errMsg = "exec unexpected error on waitpid: ";
+ errMsg += to_string(status);
return Result<ExecResult>::Err(errMsg);
}
}
+
#else
+ static FileString escape_arg(const FileString &arg) {
+ FileString escaped = TINYDIR_STRING("\"");
+ for(_tinydir_char_t c : arg) {
+ if(c == '"') {
+ escaped += TINYDIR_STRING("\"\"");
+ } else {
+ escaped += c;
+ }
+ }
+ escaped += TINYDIR_STRING("\"");
+ return escaped;
+ }
+
+ static FileString command_list_to_command_string(const std::vector<FileString> &args) {
+ FileString cmd;
+ for(size_t i = 0; i < args.size(); ++i) {
+ if(i > 0)
+ cmd += TINYDIR_STRING(" ");
+ cmd += escape_arg(args[i]);
+ }
+ return cmd;
+ }
+
// Currently stdout is read in text mode so \n is replaced with \r\n, should we read in binary mode instead?
- Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print)
+ Result<ExecResult> exec(const std::vector<FileString> &args, bool print_instead_of_pipe)
{
- FileString cmdNonConst = cmd;
+ FileString cmdNonConst = command_list_to_command_string(args);
std::string execStdout;
SECURITY_ATTRIBUTES saAttr;
@@ -77,15 +147,17 @@ namespace sibs
HANDLE childReadHandle = nullptr;
HANDLE childStdoutHandle = nullptr;
- if (!CreatePipe(&childReadHandle, &childStdoutHandle, &saAttr, 0))
- {
- string errMsg = "exec unexpected error: ";
- errMsg += toUtf8(getLastErrorAsString());
- return Result<ExecResult>::Err(errMsg);
- }
+ if(!print_instead_of_pipe) {
+ if (!CreatePipe(&childReadHandle, &childStdoutHandle, &saAttr, 0))
+ {
+ string errMsg = "exec unexpected error: ";
+ errMsg += toUtf8(getLastErrorAsString());
+ return Result<ExecResult>::Err(errMsg);
+ }
- if (!SetHandleInformation(childReadHandle, HANDLE_FLAG_INHERIT, 0))
- goto cleanupAndExit;
+ if (!SetHandleInformation(childReadHandle, HANDLE_FLAG_INHERIT, 0))
+ goto cleanupAndExit;
+ }
PROCESS_INFORMATION piProcInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
@@ -94,7 +166,7 @@ namespace sibs
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = nullptr;
- siStartInfo.hStdOutput = childStdoutHandle;
+ siStartInfo.hStdOutput = print_instead_of_pipe ? nullptr : childStdoutHandle;
siStartInfo.hStdInput = nullptr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
@@ -103,19 +175,22 @@ namespace sibs
if (!CreateProcessW(nullptr, (LPWSTR)cmdNonConst.data(), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &siStartInfo, &piProcInfo))
goto cleanupAndExit;
- CloseHandle(childStdoutHandle);
- childStdoutHandle = nullptr;
- DWORD bytesRead;
- CHAR buffer[BUFSIZE];
- while (true)
- {
- BOOL bSuccess = ReadFile(childReadHandle, buffer, BUFSIZE, &bytesRead, nullptr);
- if (!bSuccess || bytesRead == 0)
- break;
+ if(!print_instead_of_pipe) {
+ CloseHandle(childStdoutHandle);
+ childStdoutHandle = nullptr;
+
+ DWORD bytesRead;
+ CHAR buffer[BUFSIZE];
+ while (true)
+ {
+ BOOL bSuccess = ReadFile(childReadHandle, buffer, BUFSIZE, &bytesRead, nullptr);
+ if (!bSuccess || bytesRead == 0)
+ break;
- execStdout.append(buffer, bytesRead);
- if (print)
- printf("%.*s", bytesRead, buffer);
+ execStdout.append(buffer, bytesRead);
+ if (print)
+ printf("%.*s", bytesRead, buffer);
+ }
}
WaitForSingleObject(piProcInfo.hProcess, INFINITE);
@@ -134,13 +209,11 @@ namespace sibs
cleanupAndExit:
string errMsg = "exec unexpected error: ";
errMsg += toUtf8(getLastErrorAsString());
- CloseHandle(childReadHandle);
- CloseHandle(childStdoutHandle);
+ if(childReadHandle)
+ CloseHandle(childReadHandle);
+ if(childStdoutHandle)
+ CloseHandle(childStdoutHandle);
return Result<ExecResult>::Err(errMsg);
}
#endif
- Result<ExecResult> exec(const FileString &cmd, bool print)
- {
- return exec(cmd.c_str(), print);
- }
}
diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp
index 8ad1678..b390571 100644
--- a/src/GlobalLib.cpp
+++ b/src/GlobalLib.cpp
@@ -15,25 +15,20 @@ namespace sibs
{
Result<bool> GlobalLib::validatePackageExists(const FileString &globalLibRootDir, const std::string &name)
{
- FileString packageDir = globalLibRootDir + TINYDIR_STRING("/");
-#if OS_FAMILY == OS_FAMILY_POSIX
- packageDir += name;
-#else
- packageDir += utf8To16(name);
-#endif
- FileType packageDirFileType = getFileType(packageDir.c_str());
+ Path packageDir = Path(globalLibRootDir).join(toFileString(name));
+ FileType packageDirFileType = getFileType(packageDir.data.c_str());
switch(packageDirFileType)
{
case FileType::FILE_NOT_FOUND:
{
string errMsg = "Global lib dependency not found: ";
- errMsg += toUtf8(packageDir);
+ errMsg += toUtf8(packageDir.data);
return Result<bool>::Err(errMsg, DependencyError::DEPENDENCY_NOT_FOUND);
}
case FileType::REGULAR:
{
string errMsg = "Corrupt library directory. ";
- errMsg += toUtf8(packageDir);
+ errMsg += toUtf8(packageDir.data);
errMsg += " is a file, expected it to be a directory";
return Result<bool>::Err(errMsg);
}
@@ -54,10 +49,8 @@ namespace sibs
if (!libPathResult)
return Result<bool>::Err(libPathResult);
- FileString libArchivedFilePath = libPathResult.unwrap();
- libArchivedFilePath += TINYDIR_STRING("/.cache/sibs/archive/");
- libArchivedFilePath += toFileString(name);
- FileType archive_path_file_type = getFileType(libArchivedFilePath.c_str());
+ Path libArchivedFilePath = Path(libPathResult.unwrap()).join(".cache/sibs/archive").join(toFileString(name));
+ FileType archive_path_file_type = getFileType(libArchivedFilePath.data.c_str());
if(archive_path_file_type == FileType::FILE_NOT_FOUND)
return Result<bool>::Ok(true);
@@ -66,7 +59,7 @@ namespace sibs
return Result<bool>::Err("A previous download of package is corrupt, attempting to redownload...");
bool isEmpty = true;
- walkDir(libArchivedFilePath.c_str(), [&isEmpty](tinydir_file *file)
+ walkDir(libArchivedFilePath.data.c_str(), [&isEmpty](tinydir_file *file)
{
isEmpty = false;
return false;
@@ -78,13 +71,13 @@ namespace sibs
return Result<bool>::Ok(true);
}
- Result<bool> GlobalLib::getLibs(const std::vector<PackageListDependency*> &libs, const SibsConfig &parentConfig, const FileString &globalLibRootDir, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
+ Result<bool> GlobalLib::getLibs(const std::vector<PackageListDependency> &libs, const SibsConfig &parentConfig, const FileString &globalLibRootDir, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
{
- for(PackageListDependency *globalLibDependency : libs)
+ for(const PackageListDependency &globalLibDependency : libs)
{
if(!parentConfig.packaging)
- printf("Dependency %s in version range %s is missing from pkg-config, trying global lib\n", globalLibDependency->name.c_str(), globalLibDependency->version.toString().c_str());
- Result<bool> globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(parentConfig, globalLibRootDir, globalLibDependency->name, globalLibDependency->version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback);
+ printf("Dependency %s in version range %s is missing from pkg-config, trying global lib\n", globalLibDependency.name.c_str(), globalLibDependency.version.toString().c_str());
+ Result<bool> globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(parentConfig, globalLibRootDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback);
if(!globalLibLinkerFlagsResult)
{
if(globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_NOT_FOUND || globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_VERSION_NO_MATCH)
@@ -103,7 +96,7 @@ namespace sibs
if(!downloadDependencyResult)
return downloadDependencyResult;
- globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(parentConfig, globalLibRootDir, globalLibDependency->name, globalLibDependency->version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback);
+ globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(parentConfig, globalLibRootDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback);
if(!globalLibLinkerFlagsResult)
return globalLibLinkerFlagsResult;
}
@@ -122,17 +115,9 @@ namespace sibs
if (packageExistsResult.isErr())
return packageExistsResult;
-#if OS_FAMILY == OS_FAMILY_POSIX
- FileString namePlatformNative = name;
-#else
- FileString namePlatformNative = utf8To16(name);
-#endif
-
- FileString packageDir = globalLibRootDir + TINYDIR_STRING("/");
- packageDir += namePlatformNative;
-
+ Path packageDir = Path(globalLibRootDir).join(toFileString(name));
FileString foundVersion;
- walkDir(packageDir.c_str(), [&foundVersion, &versionRange](tinydir_file *file)
+ walkDir(packageDir.data.c_str(), [&foundVersion, &versionRange](tinydir_file *file)
{
if(file->is_dir)
{
@@ -150,10 +135,8 @@ namespace sibs
if(foundVersion.empty())
return Result<bool>::Err("Global lib dependency found, but version isn't in range of version", DependencyError::DEPENDENCY_VERSION_NO_MATCH);
- packageDir += TINYDIR_STRING("/");
- packageDir += foundVersion;
-
- return GlobalLib::getLibsLinkerFlagsCommon(parentConfig, packageDir, name, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback);
+ packageDir.join(foundVersion);
+ return GlobalLib::getLibsLinkerFlagsCommon(parentConfig, packageDir.data, name, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback);
}
Result<bool> GlobalLib::getLibsLinkerFlagsCommon(const SibsConfig &parentConfig, const FileString &packageDir, const string &dependencyName, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
@@ -237,9 +220,9 @@ namespace sibs
}
}
- Result<bool> GlobalLib::downloadDependency(PackageListDependency *dependency, Platform platform)
+ Result<bool> GlobalLib::downloadDependency(const PackageListDependency &dependency, Platform platform)
{
- Result<PackageMetadata> packageResult = Package::getPackage(dependency->name.c_str(), dependency->version, platform);
+ Result<PackageMetadata> packageResult = Package::getPackage(dependency.name.c_str(), dependency.version, platform);
if(!packageResult)
return Result<bool>::Err(packageResult);
@@ -248,41 +231,35 @@ namespace sibs
Result<FileString> libPathResult = getHomeDir();
if (!libPathResult)
return Result<bool>::Err(libPathResult);
- FileString libPath = libPathResult.unwrap();
- libPath += TINYDIR_STRING("/.cache/sibs/lib/");
- libPath += toFileString(asString(platform));
- libPath += TINYDIR_STRING("/");
- libPath += toFileString(dependency->name);
- libPath += TINYDIR_STRING("/");
- libPath += toFileString(package.version.toString());
+ Path libPath = Path(libPathResult.unwrap())
+ .join(TINYDIR_STRING(".cache/sibs/lib"))
+ .join(toFileString(asString(platform)))
+ .join(toFileString(dependency.name))
+ .join(toFileString(package.version.toString()));
- FileString libArchivedFilePath = libPathResult.unwrap();
- libArchivedFilePath += TINYDIR_STRING("/.cache/sibs/archive/");
- libArchivedFilePath += toFileString(dependency->name);
- Result<bool> createArchiveDirResult = createDirectoryRecursive(libArchivedFilePath.c_str());
+ Path libArchivedFilePath = Path(libPathResult.unwrap()).join(TINYDIR_STRING("/.cache/sibs/archive/")).join(toFileString(dependency.name));
+ Result<bool> createArchiveDirResult = createDirectoryRecursive(libArchivedFilePath.data.c_str());
if(!createArchiveDirResult)
return createArchiveDirResult;
- FileString libArchivedDir = libArchivedFilePath;
- libArchivedFilePath += TINYDIR_STRING("/");
- libArchivedFilePath += toFileString(package.version.toString());
- Result<bool> downloadResult = curl::downloadFile(package.urls[0].c_str(), libArchivedFilePath.c_str());
+ Path libArchivedDir = Path(libArchivedFilePath).join(toFileString(package.version.toString()));
+ Result<bool> downloadResult = curl::downloadFile(package.urls[0].c_str(), libArchivedFilePath.data.c_str());
if(!downloadResult)
return downloadResult;
// Create build path. This is done here because we dont want to create it if download fails
- Result<bool> createLibDirResult = createDirectoryRecursive(libPath.c_str());
+ Result<bool> createLibDirResult = createDirectoryRecursive(libPath.data.c_str());
if(!createLibDirResult)
return createLibDirResult;
- Result<bool> archiveExtractResult = Archive::extract(libArchivedFilePath.c_str(), libPath.c_str());
+ Result<bool> archiveExtractResult = Archive::extract(libArchivedFilePath.data.c_str(), libPath.data.c_str());
// We have extracted the archive, we dont need to cache it. If remove fails, it doesn't really matter, user can remove it himself
#if OS_FAMILY == OS_FAMILY_POSIX
- remove(libArchivedFilePath.c_str());
- remove(libArchivedDir.c_str());
+ remove(libArchivedFilePath.data.c_str());
+ remove(libArchivedDir.data.c_str());
#else
- _wremove(libArchivedFilePath.c_str());
- _wremove(libArchivedDir.c_str());
+ _wremove(libArchivedFilePath.data.c_str());
+ _wremove(libArchivedDir.data.c_str());
#endif
return archiveExtractResult;
}
diff --git a/src/PkgConfig.cpp b/src/PkgConfig.cpp
index 89d3a44..73df008 100644
--- a/src/PkgConfig.cpp
+++ b/src/PkgConfig.cpp
@@ -27,28 +27,25 @@ namespace sibs
pkgConfigPath = path;
}
- Result<bool> PkgConfig::validatePkgConfigPackageVersionExists(PackageListDependency *dependency)
+ Result<bool> PkgConfig::validatePkgConfigPackageVersionExists(const PackageListDependency &dependency)
{
- Result<bool> dependencyValidationResult = PkgConfig::validatePackageExists(dependency->name);
+ Result<bool> dependencyValidationResult = PkgConfig::validatePackageExists(dependency.name);
if(dependencyValidationResult.isErr())
return Result<bool>::Err(dependencyValidationResult.getErrMsg());
- Result<PackageVersion> dependencyVersionResult = PkgConfig::getPackageVersion(dependency->name);
+ Result<PackageVersion> dependencyVersionResult = PkgConfig::getPackageVersion(dependency.name);
if(!dependencyVersionResult)
return Result<bool>::Err(dependencyVersionResult);
- if(!dependency->version.isInRange(dependencyVersionResult.unwrap()))
- return Result<bool>::Err("pkg-config package " + dependency->name + " exists but the version does not match our expected version range");
+ if(!dependency.version.isInRange(dependencyVersionResult.unwrap()))
+ return Result<bool>::Err("pkg-config package " + dependency.name + " exists but the version does not match our expected version range");
return Result<bool>::Ok(true);
}
Result<bool> PkgConfig::validatePackageExists(const string &name)
{
- FileString command = pkgConfigPath + TINYDIR_STRING(" --exists '");
- command += toFileString(name);
- command += TINYDIR_STRING("'");
- Result<ExecResult> execResult = exec(command.c_str());
+ Result<ExecResult> execResult = exec({ pkgConfigPath, TINYDIR_STRING("--exists"), TINYDIR_STRING("--"), toFileString(name) });
if(execResult.isErr())
return Result<bool>::Err(execResult.getErrMsg());
@@ -72,45 +69,9 @@ namespace sibs
return Result<bool>::Ok(true);
}
- Result<bool> PkgConfig::validatePackageVersionAtLeast(const string &name, const string &version)
- {
- FileString command = pkgConfigPath + TINYDIR_STRING(" '--atleast-version=");
- command += toFileString(version);
- command += TINYDIR_STRING("' '");
- command += toFileString(name);
- command += TINYDIR_STRING("'");
- Result<ExecResult> execResult = exec(command.c_str());
- if(execResult.isErr())
- return Result<bool>::Err(execResult.getErrMsg());
-
- if(execResult.unwrap().exitCode == 1)
- {
- string errMsg = "Dependency ";
- errMsg += name;
- errMsg += " is installed but the version older than ";
- errMsg += version;
- return Result<bool>::Err(errMsg);
- }
- else if(execResult.unwrap().exitCode == 127)
- {
- return Result<bool>::Err("pkg-config is not installed");
- }
- else if(execResult.unwrap().exitCode != 0)
- {
- string errMsg = "Failed to check pkg-config package version, Unknown error, exit code: ";
- errMsg += to_string(execResult.unwrap().exitCode);
- return Result<bool>::Err(errMsg);
- }
-
- return Result<bool>::Ok(true);
- }
-
Result<PackageVersion> PkgConfig::getPackageVersion(const std::string &name)
{
- FileString command = pkgConfigPath + TINYDIR_STRING(" --modversion '");
- command += toFileString(name);
- command += TINYDIR_STRING("'");
- Result<ExecResult> execResult = exec(command.c_str());
+ Result<ExecResult> execResult = exec({ pkgConfigPath, TINYDIR_STRING("--modversion"), TINYDIR_STRING("--"), toFileString(name) });
if(!execResult)
return Result<PackageVersion>::Err(execResult.getErrMsg());
@@ -136,21 +97,17 @@ namespace sibs
return parsePackageVersion({ execResult.unwrap().execStdout.data(), execResult.unwrap().execStdout.size() }, nullptr);
}
- Result<string> PkgConfig::getDynamicLibsLinkerFlags(const vector<PackageListDependency*> &libs)
+ Result<string> PkgConfig::getDynamicLibsLinkerFlags(const vector<PackageListDependency> &libs)
{
if(libs.empty()) return Result<string>::Ok("");
- string args;
- for(PackageListDependency *lib : libs)
+ std::vector<FileString> args = { pkgConfigPath, TINYDIR_STRING("--libs"), TINYDIR_STRING("--") };
+ for(const PackageListDependency &lib : libs)
{
- args += " '";
- args += lib->name;
- args += "'";
+ args.push_back(toFileString(lib.name));
}
- FileString command = pkgConfigPath + TINYDIR_STRING(" --libs");
- command += toFileString(args);
- Result<ExecResult> execResult = exec(command.c_str());
+ Result<ExecResult> execResult = exec(args);
if(execResult.isErr())
return Result<string>::Err(execResult.getErrMsg());
@@ -179,21 +136,17 @@ namespace sibs
}
}
- Result<string> PkgConfig::getDynamicLibsCflags(const vector<PackageListDependency*> &libs)
+ Result<string> PkgConfig::getDynamicLibsCflags(const vector<PackageListDependency> &libs)
{
if(libs.empty()) return Result<string>::Ok("");
- string args;
- for(PackageListDependency *lib : libs)
+ std::vector<FileString> args = { pkgConfigPath, TINYDIR_STRING("--cflags"), TINYDIR_STRING("--") };
+ for(const PackageListDependency &lib : libs)
{
- args += " '";
- args += lib->name;
- args += "'";
+ args.push_back(toFileString(lib.name));
}
- FileString command = pkgConfigPath + TINYDIR_STRING(" --cflags");
- command += toFileString(args);
- Result<ExecResult> execResult = exec(command.c_str());
+ Result<ExecResult> execResult = exec(args);
if(execResult.isErr())
return Result<string>::Err(execResult.getErrMsg());
@@ -222,7 +175,7 @@ namespace sibs
}
}
- Result<PkgConfigFlags> PkgConfig::getDynamicLibsFlags(const vector<PackageListDependency*> &libs)
+ Result<PkgConfigFlags> PkgConfig::getDynamicLibsFlags(const vector<PackageListDependency> &libs)
{
PkgConfigFlags flags;
diff --git a/src/main.cpp b/src/main.cpp
index 713514d..ecb0e99 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -80,9 +80,6 @@ using namespace std::chrono;
// TODO: Add program command for generating compile_commands.json without compiling code, without using Ninja
-// TODO: Make Process::exec safe to use. Currently you pass an argument and it's run as a command, but the string can be escaped to perform malicious acts.
-// Process::exec should be modified to take a list of arguments to execute command with.
-
// TODO: Verify paths (test path, ignore dirs, include dirs, expose include dir, sibs test --file dir) are sub directory of the project
// TODO: When creating a package with `sibs package` copy LICENSE files into archive.
@@ -97,6 +94,8 @@ using namespace std::chrono;
// TODO: If dependencies are using a version that is not within our dependency version range then ask the user if they still want to use the dependency (the closest matching dependency).
// Currently if dependency version does not match, build will always fail with no option to ignore version mismatch.
+// TODO: Check if ninja args are properly escaped.
+
#if OS_FAMILY == OS_FAMILY_POSIX
#define fout std::cout
#define ferr std::cerr
@@ -314,7 +313,8 @@ struct MicrosoftBuildTool
static MicrosoftBuildTool locateLatestMicrosoftBuildTool()
{
MicrosoftBuildTool result = { 0 };
- Result<ExecResult> execResult = exec(TINYDIR_STRING("locate_windows_sdk x64"));
+ // TODO: x86
+ Result<ExecResult> execResult = exec({ TINYDIR_STRING("locate_windows_sdk"), TINYDIR_STRING("x64") });
if (execResult && execResult.unwrap().exitCode == 0)
{
auto &str = execResult.unwrap().execStdout;
@@ -363,7 +363,7 @@ static void appendBuildToolToPathEnv()
#endif
}
-static int buildProject(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig, bool run, FileString run_args)
+static int buildProject(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig, bool run, const std::vector<FileString> &run_args)
{
FileString buildPath;
readSibsConfig(projectPath, projectConfFilePath, sibsConfig, buildPath);
@@ -455,7 +455,11 @@ static int buildProject(const FileString &projectPath, const FileString &project
FileString executableName = toFileString(sibsConfig.getPackageName());
if(isSamePlatformFamily(sibsConfig.platform, PLATFORM_WIN))
executableName += TINYDIR_STRING(".exe");
- auto exec_result = exec(buildPath + TINYDIR_STRING("/") + executableName + TINYDIR_STRING(" ") + run_args, true);
+
+ std::vector<FileString> args = { Path(buildPath).join(executableName).data };
+ args.insert(args.end(), run_args.begin(), run_args.end());
+
+ auto exec_result = exec(args, true);
if(!exec_result) {
ferr << "Failed to execute" << (buildPath + TINYDIR_STRING("/") + executableName) << ", error: " << toFileString(exec_result.getErrMsg()) << endl;
return 1;
@@ -466,35 +470,6 @@ static int buildProject(const FileString &projectPath, const FileString &project
return 0;
}
-#if OS_FAMILY == OS_FAMILY_WINDOWS
-#define NATIVE_CHAR_PREFIX L
-#else
-#define NATIVE_CHAR_PREFIX
-#endif
-
-static FileString replace_all(const _tinydir_char_t *str) {
- FileString result = TINYDIR_STRING("'");
- while(*str != NATIVE_CHAR_PREFIX'\0') {
- if(*str == NATIVE_CHAR_PREFIX'\'')
- result += TINYDIR_STRING("\\'");
- else
- result += *str;
- ++str;
- }
- result += NATIVE_CHAR_PREFIX'\'';
- return result;
-}
-
-static FileString escape_args(const std::vector<const _tinydir_char_t*> &args) {
- FileString result;
- for(const _tinydir_char_t *arg : args) {
- if(!result.empty())
- result += NATIVE_CHAR_PREFIX' ';
- result += replace_all(arg);
- }
- return result;
-}
-
static Sanitize sanitize_string_to_type(const _tinydir_char_t *str) {
if(strcmp(str, TINYDIR_STRING("address")) == 0)
return Sanitize::ADDRESS;
@@ -517,7 +492,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv, bool run)
Sanitize sanitize = Sanitize::NONE;
FileString platformName;
bool use_lto = false;
- std::vector<const _tinydir_char_t*> run_args;
+ std::vector<FileString> run_args;
for(int i = 0; i < argc; ++i)
{
@@ -652,7 +627,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv, bool run)
sibsConfig.platform = platform;
sibsConfig.setSanitize(sanitize);
sibsConfig.use_lto = use_lto;
- return buildProject(projectPath, projectConfFilePath, sibsConfig, run, escape_args(run_args));
+ return buildProject(projectPath, projectConfFilePath, sibsConfig, run, run_args);
}
static int testProject(int argc, const _tinydir_char_t **argv)
@@ -797,7 +772,7 @@ static int testProject(int argc, const _tinydir_char_t **argv)
sibsConfig.zigTestFiles = move(filesToTest);
sibsConfig.zigTestAllFiles = testAllFiles;
- return buildProject(projectPath, projectConfFilePath, sibsConfig, false, TINYDIR_STRING(""));
+ return buildProject(projectPath, projectConfFilePath, sibsConfig, false, {});
}
// Returns nullptr if @charToFind is not found
@@ -844,10 +819,7 @@ static void createProjectFile(const FileString &projectFilePath, const string &f
// so there is no reason to do it (right now)
static Result<ExecResult> gitInitProject(const FileString &projectPath)
{
- FileString cmd = TINYDIR_STRING("git init \"");
- cmd += projectPath;
- cmd += TINYDIR_STRING("\"");
- return exec(cmd.c_str());
+ return exec({ TINYDIR_STRING("git"), TINYDIR_STRING("init"), TINYDIR_STRING("--"), projectPath });
}
static bool gitIgnoreContainsSibs(const FileString &gitIgnoreFilePath)
@@ -1236,7 +1208,7 @@ static int packageProject(int argc, const _tinydir_char_t **argv)
sibsConfig.packaging = packagingType == PackagingType::STATIC;
sibsConfig.bundling = (packagingType == PackagingType::BUNDLE) || (packagingType == PackagingType::BUNDLE_INSTALL);
sibsConfig.use_lto = true;
- int result = buildProject(projectPath, projectConfFilePath, sibsConfig, false, TINYDIR_STRING(""));
+ int result = buildProject(projectPath, projectConfFilePath, sibsConfig, false, {});
if(result != 0)
return result;
@@ -1244,8 +1216,8 @@ static int packageProject(int argc, const _tinydir_char_t **argv)
{
case PackagingType::STATIC:
{
- string packagePath = toUtf8(projectPath + TINYDIR_STRING("/sibs-build/") + toFileString(asString(sibsConfig.platform)) + TINYDIR_STRING("/package"));
- printf("Project %s was successfully packaged and can be found at %s\n", sibsConfig.getPackageName().c_str(), packagePath.c_str());
+ Path packagePath = Path(projectPath).join(TINYDIR_STRING("sibs-build")).join(toFileString(asString(sibsConfig.platform))).join(TINYDIR_STRING("package"));
+ printf("Project %s was successfully packaged and can be found at %s\n", sibsConfig.getPackageName().c_str(), packagePath.data.c_str());
break;
}
case PackagingType::BUNDLE:
@@ -1262,21 +1234,11 @@ static int packageProject(int argc, const _tinydir_char_t **argv)
break;
}
- FileString packagePath = projectPath + TINYDIR_STRING("/sibs-build/") + toFileString(asString(sibsConfig.platform)) + TINYDIR_STRING("/package");
- FileString executablePath = projectPath + TINYDIR_STRING("/sibs-build/") + toFileString(asString(sibsConfig.platform)) + TINYDIR_STRING("/release/")+ toFileString(sibsConfig.getPackageName());
+ Path packagePath = Path(projectPath).join(TINYDIR_STRING("sibs-build")).join(toFileString(asString(sibsConfig.platform))).join(TINYDIR_STRING("package"));
+ Path executablePath = Path(projectPath).join(TINYDIR_STRING("sibs-build")).join(toFileString(asString(sibsConfig.platform))).join(TINYDIR_STRING("release")).join(toFileString(sibsConfig.getPackageName()));
printf("Creating a package from project and dependencies...\n");
// args: executable_path program_version destination_path <--bundle|--bundle-install>
- FileString cmd = TINYDIR_STRING("python3 \"") +
- packageScriptPath +
- TINYDIR_STRING("\" \"") +
- executablePath +
- TINYDIR_STRING("\" \"") +
- toFileString(sibsConfig.version.toString()) +
- TINYDIR_STRING("\" \"") +
- packagePath +
- TINYDIR_STRING("\" ") +
- bundleType;
- Result<ExecResult> bundleResult = exec(cmd.c_str(), true);
+ Result<ExecResult> bundleResult = exec({ TINYDIR_STRING("python3"), packageScriptPath, executablePath.data, toFileString(sibsConfig.version.toString()), packagePath.data, bundleType }, true);
if(!bundleResult)
{
fprintf(stderr, "Error: failed to package project as a bundle, reason: %s\n", bundleResult.getErrMsg().c_str());
diff --git a/tests/src/confTest/confTest.cpp b/tests/src/confTest/confTest.cpp
index 68e2225..c770266 100644
--- a/tests/src/confTest/confTest.cpp
+++ b/tests/src/confTest/confTest.cpp
@@ -3,6 +3,16 @@
using namespace sibs;
+static FileString arg_list_to_string(const std::vector<FileString> &args) {
+ FileString result;
+ for(const FileString &arg : args) {
+ if(!result.empty())
+ result += TINYDIR_STRING(" ");
+ result += TINYDIR_STRING("\"") + arg + TINYDIR_STRING("\"");
+ }
+ return result;
+}
+
TEST_CASE("parse config")
{
SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"), OPT_LEV_DEBUG, false);
@@ -20,28 +30,28 @@ TEST_CASE("parse config")
REQUIRE(containsPlatform(sibsConfig.getPlatforms(), PLATFORM_WIN64));
REQUIRE(sibsConfig.getPackageListDependencies().size() == 2);
- for(auto *dep : sibsConfig.getPackageListDependencies())
+ for(const auto &dep : sibsConfig.getPackageListDependencies())
{
- REQUIRE(dep->getSource() == Dependency::Source::PACKAGE_LIST);
+ REQUIRE(dep.getSource() == Dependency::Source::PACKAGE_LIST);
}
- auto *xxhashDependency = sibsConfig.getPackageListDependencies()[0]->asPackageListDependency();
+ auto *xxhashDependency = sibsConfig.getPackageListDependencies()[0].asPackageListDependency();
REQUIRE(xxhashDependency->name == "xxhash");
REQUIRE(xxhashDependency->version.toString() == ">=0.1.0 and <1.0.0");
- const auto &catch2Dependency = sibsConfig.getPackageListDependencies()[1]->asPackageListDependency();
+ const auto &catch2Dependency = sibsConfig.getPackageListDependencies()[1].asPackageListDependency();
REQUIRE(catch2Dependency->name == "catch2");
REQUIRE(catch2Dependency->version.toString() == ">=1.0.0 and <2.0.0");
REQUIRE(sibsConfig.shouldUseCmake());
REQUIRE(sibsConfig.getCmakeDir() == TINYDIR_STRING("tests/src/confTest/cmakeGlobal"));
- REQUIRE(sibsConfig.getCmakeArgs() == "-G Ninja \"-DCMAKE_BUILD_TYPE=Debug\" \"-DENTITYX_RUN_BENCHMARKS=0\"");
+ REQUIRE(arg_list_to_string(sibsConfig.getCmakeArgs()) == "\"-G\" \"Ninja\" \"-DCMAKE_BUILD_TYPE=Debug\" \"-DENTITYX_RUN_BENCHMARKS=0\"");
REQUIRE(sibsConfig.getCmakeDirStatic() == TINYDIR_STRING("tests/src/confTest/cmakeStatic"));
- REQUIRE(sibsConfig.getCmakeArgsStatic() == "-G Ninja \"-DCMAKE_BUILD_TYPE=Debug\" \"-DENTITYX_RUN_BENCHMARKS=0\" \"-DENTITYX_BUILD_TESTING=0\"");
+ REQUIRE(arg_list_to_string(sibsConfig.getCmakeArgsStatic()) == "\"-G\" \"Ninja\" \"-DCMAKE_BUILD_TYPE=Debug\" \"-DENTITYX_RUN_BENCHMARKS=0\" \"-DENTITYX_BUILD_TESTING=0\"");
REQUIRE(sibsConfig.getCmakeDirDynamic() == TINYDIR_STRING("tests/src/confTest/cmakeDynamic"));
- REQUIRE(sibsConfig.getCmakeArgsDynamic() == "-G Ninja \"-DCMAKE_BUILD_TYPE=Debug\" \"-DENTITYX_RUN_BENCHMARKS=0\" \"-DENTITYX_BUILD_TESTING=0\" \"-DENTITYX_BUILD_SHARED=1\"");
+ REQUIRE(arg_list_to_string(sibsConfig.getCmakeArgsDynamic()) == "\"-G\" \"Ninja\" \"-DCMAKE_BUILD_TYPE=Debug\" \"-DENTITYX_RUN_BENCHMARKS=0\" \"-DENTITYX_BUILD_TESTING=0\" \"-DENTITYX_BUILD_SHARED=1\"");
}
TEST_CASE("parse config - invalid object")