aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-09-21 10:22:24 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-06 07:39:33 +0200
commitbf42a3fe559b53b62db9c6363efbec612804dbe7 (patch)
tree9b499988832a053d7efc275e97f9803b2f5d6f5b /backend
parent0415b7bef504b41b43672b3e153bbe260f2cc055 (diff)
Add support for running zig tests
Diffstat (limited to 'backend')
-rw-r--r--backend/BackendUtils.cpp27
-rw-r--r--backend/BackendUtils.hpp2
-rw-r--r--backend/ninja/Ninja.cpp159
3 files changed, 165 insertions, 23 deletions
diff --git a/backend/BackendUtils.cpp b/backend/BackendUtils.cpp
index ac71b07..3c9dd71 100644
--- a/backend/BackendUtils.cpp
+++ b/backend/BackendUtils.cpp
@@ -27,28 +27,43 @@ namespace backend
TINYDIR_STRING("c++")
};
- sibs::Language BackendUtils::getFileLanguage(tinydir_file *file)
+ sibs::FileString BackendUtils::getFileExtension(const sibs::FileString &filepath)
{
- if(!file->is_reg)
- return sibs::Language::NONE;
+ size_t indexOfDot = filepath.find_last_of('.');
+ if(indexOfDot == sibs::FileString::npos)
+ return TINYDIR_STRING("");
+
+ indexOfDot += 1;
+ return filepath.substr(indexOfDot);
+ }
+ sibs::Language BackendUtils::getFileLanguage(const _tinydir_char_t *extension)
+ {
for(const _tinydir_char_t *sourceFileExtension : cFileExtensions)
{
- if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
+ if(_tinydir_strcmp(sourceFileExtension, extension) == 0)
return sibs::Language::C;
}
for(const _tinydir_char_t *sourceFileExtension : cppFileExtensions)
{
- if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
+ if(_tinydir_strcmp(sourceFileExtension, extension) == 0)
return sibs::Language::CPP;
}
- if(_tinydir_strcmp(TINYDIR_STRING("zig"), file->extension) == 0)
+ if(_tinydir_strcmp(TINYDIR_STRING("zig"), extension) == 0)
return sibs::Language::ZIG;
return sibs::Language::NONE;
}
+
+ sibs::Language BackendUtils::getFileLanguage(tinydir_file *file)
+ {
+ if(!file->is_reg)
+ return sibs::Language::NONE;
+
+ return getFileLanguage(file->extension);
+ }
void BackendUtils::collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const SibsConfig &sibsConfig, bool recursive)
{
diff --git a/backend/BackendUtils.hpp b/backend/BackendUtils.hpp
index acef0ca..f99d7e5 100644
--- a/backend/BackendUtils.hpp
+++ b/backend/BackendUtils.hpp
@@ -9,6 +9,8 @@ namespace backend
class BackendUtils
{
public:
+ static sibs::FileString getFileExtension(const sibs::FileString &filepath);
+ 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);
};
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp
index ca88f40..c642a4c 100644
--- a/backend/ninja/Ninja.cpp
+++ b/backend/ninja/Ninja.cpp
@@ -474,6 +474,7 @@ namespace backend
case Compiler::MSVC:
{
includeStartStr = "/I";
+ break;
}
default:
assert(false);
@@ -527,6 +528,72 @@ namespace backend
return result;
}
+ static vector<ninja::NinjaArg> extractLibraryPathsWithoutFlags(Compiler compiler, const string &cLibraries)
+ {
+ vector<ninja::NinjaArg> result;
+
+ size_t i = 0;
+ while(i < cLibraries.size())
+ {
+ char c = cLibraries[i];
+ if(c == '\'' || c == '"')
+ {
+ // TODO: Handle quote escaping
+ char quoteSymbol = c;
+ ++i;
+ size_t libraryIndexStart = i;
+ while(i < cLibraries.size() && cLibraries[i] != quoteSymbol)
+ {
+ ++i;
+ }
+ size_t libraryIndexEnd = i;
+ ++i;
+
+ if(strncmp(&cLibraries[libraryIndexStart], "-l", 2) == 0)
+ libraryIndexStart += 2;
+ else if(strcmp(&cLibraries[libraryIndexStart], "-pthread") == 0)
+ continue;
+
+ size_t libraryPathLength = libraryIndexEnd - libraryIndexStart;
+ if(libraryPathLength > 0)
+ result.push_back(ninja::NinjaArg::createRaw(cLibraries.substr(libraryIndexStart, libraryPathLength)));
+ }
+ else if(c != ' ')
+ {
+ // TODO: Handle space escaping
+ size_t libraryIndexStart = i;
+ while(i < cLibraries.size() && cLibraries[i] != ' ')
+ {
+ ++i;
+ }
+ size_t libraryIndexEnd = i;
+ ++i;
+
+ if(strncmp(&cLibraries[libraryIndexStart], "-l", 2) == 0)
+ libraryIndexStart += 2;
+ else if(strcmp(&cLibraries[libraryIndexStart], "-pthread") == 0)
+ continue;
+
+ size_t libraryPathLength = libraryIndexEnd - libraryIndexStart;
+ if(libraryPathLength > 0)
+ result.push_back(ninja::NinjaArg::createRaw(cLibraries.substr(libraryIndexStart, libraryPathLength)));
+ }
+ }
+
+ return result;
+ }
+
+ static vector<ninja::NinjaArg> convertCLibrariesToZigLibraries(Compiler compiler, const string &cLibraries)
+ {
+ vector<ninja::NinjaArg> result;
+ result = extractLibraryPathsWithoutFlags(compiler, cLibraries);
+ for(ninja::NinjaArg &include : result)
+ {
+ include.arg = "--library \"" + include.arg + "\"";
+ }
+ return result;
+ }
+
Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
{
if (!sourceFiles.empty())
@@ -809,18 +876,29 @@ namespace backend
// TODO: Specify -mconsole or -mwindows for windows.
// TODO: Convert sibs defines to const variables in a zig file that other zig files can include (like a config file).
+ // TODO: Remove --library c if project does not depend on c libraries or project only has .zig files
+ vector<ninja::NinjaArg> zigTestArgs = {
+ ninja::NinjaArg::createRaw("zig test $in --output $out -isystem ../../ --color on --library c $globalIncDirZig")
+ };
+
// TODO: Find a way to do this more efficiently
vector<ninja::NinjaArg> cflagsIncludes = convertCFlagsIncludesToZigIncludes(config.getCompiler(), cflags);
+ vector<ninja::NinjaArg> zigLibraryFlags = convertCLibrariesToZigLibraries(config.getCompiler(), allLinkerFlags);
+
vector<ninja::NinjaArg> compileZigArgs = {
ninja::NinjaArg::createRaw("zig build-obj"),
ninja::NinjaArg::createRaw("$in"),
ninja::NinjaArg::createRaw("--output $out"),
- ninja::NinjaArg::createRaw("-isystem ."),
+ ninja::NinjaArg::createRaw("-isystem ../../"),
ninja::NinjaArg::createRaw("--color on"),
ninja::NinjaArg::createRaw("--library c"), // TODO: Remove this if project does not depend on c libraries or project only has .zig files
ninja::NinjaArg::createRaw("$globalIncDirZig")
};
+ // TODO: Verify if we really need to add all libraries for every object file
compileZigArgs.insert(compileZigArgs.end(), cflagsIncludes.begin(), cflagsIncludes.end());
+ compileZigArgs.insert(compileZigArgs.end(), zigLibraryFlags.begin(), zigLibraryFlags.end());
+ zigTestArgs.insert(zigTestArgs.end(), cflagsIncludes.begin(), cflagsIncludes.end());
+ zigTestArgs.insert(zigTestArgs.end(), zigLibraryFlags.begin(), zigLibraryFlags.end());
if(config.getOptimizationLevel() == sibs::OPT_LEV_RELEASE)
{
@@ -829,6 +907,11 @@ namespace backend
ninja::NinjaArg::createRaw("--release-safe"),
ninja::NinjaArg::createRaw("--strip")
});
+
+ zigTestArgs.insert(zigTestArgs.end(), {
+ ninja::NinjaArg::createRaw("--release-safe"),
+ ninja::NinjaArg::createRaw("--strip")
+ });
}
if(libraryType == LibraryType::STATIC)
@@ -837,9 +920,11 @@ namespace backend
compileZigArgs.push_back(ninja::NinjaArg::createRaw("-rdynamic"));
ninja::NinjaRule *compileZigRule = ninjaBuildFile.createRule("compile_zig", compileZigArgs);
+ ninja::NinjaRule *testZigRule = ninjaBuildFile.createRule("zig_test", zigTestArgs);
bool usesCFiles = false;
bool usesCppFiles = false;
+ bool zigTest = (config.zigTestAllFiles || !config.zigTestFiles.empty());
vector<string> objectNames;
objectNames.reserve(sourceFiles.size());
@@ -868,7 +953,10 @@ namespace backend
{
objectName += "zig-cache/" + sourceFile.filepath;
objectName += getObjectFileExtension(config.getCompiler());
- ninjaBuildFile.build(compileZigRule, "../../" + sourceFile.filepath, objectName, {});
+ if(zigTest)
+ ninjaBuildFile.build(testZigRule, "../../" + sourceFile.filepath, objectName, {});
+ else
+ ninjaBuildFile.build(compileZigRule, "../../" + sourceFile.filepath, objectName, {});
break;
}
default:
@@ -882,7 +970,7 @@ namespace backend
// they should be built with zig if project only contains zig files.
// But how to combine object files with zig? build-exe only wants to accept .zig files
string projectGeneratedBinaryFlags;
- if (!sourceFiles.empty())
+ if (!sourceFiles.empty() && !zigTest)
{
string projectGeneratedBinary = "\"";
projectGeneratedBinary += savePathUtf8;
@@ -1070,6 +1158,10 @@ namespace backend
}
projectGeneratedBinaryFlags = allLinkerFlags + " " + projectGeneratedBinary;
+ }
+
+ if(!sourceFiles.empty())
+ {
string result = ninjaBuildFile.generate();
Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size()));
if (fileOverwriteResult.isErr())
@@ -1089,9 +1181,6 @@ namespace backend
}
}
- // TODO: If tests are being run (sibs test) and root project is an executable, do not run compile (above code) as executable.
- // Sibs test will compile root project as dynamic library so you end up compiling the project twice, first as an executable and then as a dynamic library.
- // Even if the root project has been built before and there is cached object, it will take a few seconds to run compile
Result<bool> buildTestResult = buildTests(projectGeneratedBinaryFlags, config, savePath, dependencyExportIncludeDirs);
if(!buildTestResult)
return buildTestResult;
@@ -1132,6 +1221,8 @@ namespace backend
FileType projectConfFileType = getFileType(projectConfFilePath.c_str());
SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative, config.getOptimizationLevel());
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);
@@ -1144,7 +1235,38 @@ namespace backend
if(!projectGeneratedBinaryFlags.empty())
ninja.addDependency(projectGeneratedBinaryFlags);
- backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig, false);
+ bool zigTest = false;
+ if(config.zigTestAllFiles)
+ {
+ backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig, false);
+ // 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(); )
+ {
+ if(it->language != sibs::Language::ZIG)
+ {
+ it = ninja.sourceFiles.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ zigTest = true;
+ }
+ else if(!config.zigTestFiles.empty())
+ {
+ ninja.sourceFiles.reserve(config.zigTestFiles.size());
+ for(const sibs::FileString &testFile : config.zigTestFiles)
+ {
+ ninja.addSourceFile(sibs::Language::ZIG, testFile.c_str());
+ }
+ zigTest = true;
+ }
+ else
+ {
+ backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig, false);
+ }
if(!ninja.getSourceFiles().empty())
{
@@ -1170,16 +1292,19 @@ namespace backend
if(!buildFileResult)
return buildFileResult;
}
-
- FileString testExecutableName = buildPath;
- testExecutableName += TINYDIR_STRING("/");
- testExecutableName += toFileString(sibsTestConfig.getPackageName());
- Result<ExecResult> runTestResult = exec(testExecutableName.c_str(), true);
- if(!runTestResult)
- return Result<bool>::Err(runTestResult);
-
- if(runTestResult.unwrap().exitCode != 0)
- return Result<bool>::Err("Tests failed", runTestResult.unwrap().exitCode);
+
+ if(!zigTest)
+ {
+ FileString testExecutableName = buildPath;
+ testExecutableName += TINYDIR_STRING("/");
+ testExecutableName += toFileString(sibsTestConfig.getPackageName());
+ Result<ExecResult> runTestResult = exec(testExecutableName.c_str(), true);
+ if(!runTestResult)
+ return Result<bool>::Err(runTestResult);
+
+ if(runTestResult.unwrap().exitCode != 0)
+ return Result<bool>::Err("Tests failed", runTestResult.unwrap().exitCode);
+ }
}
}