aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/BackendUtils.cpp45
-rw-r--r--backend/BackendUtils.hpp4
-rw-r--r--backend/ninja/Ninja.cpp727
-rw-r--r--backend/ninja/Ninja.hpp6
4 files changed, 396 insertions, 386 deletions
diff --git a/backend/BackendUtils.cpp b/backend/BackendUtils.cpp
index a91fc95..6bb0ace 100644
--- a/backend/BackendUtils.cpp
+++ b/backend/BackendUtils.cpp
@@ -7,38 +7,49 @@ using namespace sibs;
namespace backend
{
- bool isPathSubPathOf(const FileString &path, const FileString &subPathOf)
+ static bool isPathSubPathOf(const FileString &path, const FileString &subPathOf)
{
return _tinydir_strncmp(path.c_str(), subPathOf.c_str(), subPathOf.size()) == 0;
}
-
- const _tinydir_char_t *sourceFileExtensions[] =
+
+ const _tinydir_char_t *cFileExtensions[] =
{
TINYDIR_STRING("c"),
TINYDIR_STRING("C"),
- TINYDIR_STRING("cc"),
+ TINYDIR_STRING("cc")
+ };
+
+ const _tinydir_char_t *cppFileExtensions[] =
+ {
TINYDIR_STRING("cp"),
TINYDIR_STRING("cpp"),
TINYDIR_STRING("cxx"),
TINYDIR_STRING("c++")
};
- bool BackendUtils::isSourceFile(tinydir_file *file)
+
+ sibs::Language BackendUtils::getFileLanguage(tinydir_file *file)
{
if(!file->is_reg)
- return false;
+ return sibs::Language::NONE;
+
+ for(const _tinydir_char_t *sourceFileExtension : cFileExtensions)
+ {
+ if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
+ return sibs::Language::C;
+ }
- for(const _tinydir_char_t *sourceFileExtension : sourceFileExtensions)
+ for(const _tinydir_char_t *sourceFileExtension : cppFileExtensions)
{
if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
- return true;
+ return sibs::Language::CPP;
}
- return false;
+ return sibs::Language::NONE;
}
- void BackendUtils::collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const SibsConfig &sibsConfig)
+ void BackendUtils::collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const SibsConfig &sibsConfig, bool recursive)
{
- walkDir(projectPath, [ninjaProject, &sibsConfig](tinydir_file *file)
+ walkDir(projectPath, [ninjaProject, &sibsConfig, recursive](tinydir_file *file)
{
FileString pathNative = file->path;
#if OS_FAMILY == OS_FAMILY_WINDOWS
@@ -46,10 +57,11 @@ namespace backend
#endif
if(file->is_reg)
{
- if (isSourceFile(file))
+ sibs::Language fileLanguage = getFileLanguage(file);
+ if (fileLanguage != sibs::Language::NONE)
{
string filePathUtf8 = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size());
- ninjaProject->addSourceFile(filePathUtf8.c_str());
+ ninjaProject->addSourceFile(fileLanguage, filePathUtf8.c_str());
}
else
{
@@ -58,12 +70,13 @@ namespace backend
}
else
{
+ // TODO: Verify what happens if test has test sub directory
if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath()))
{
string filePathUtf8 = toUtf8(pathNative.c_str());
ninjaProject->addTestSourceDir(filePathUtf8.c_str());
}
- else if(!directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs()))
+ else if(recursive && !directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs()))
{
FileString projectConfPath = file->path;
#if OS_FAMILY == OS_FAMILY_WINDOWS
@@ -82,11 +95,11 @@ namespace backend
FileString subProjectBuildPath;
readSibsConfig(file->path, projectConfPath, *subProjectConfig, subProjectBuildPath);
- collectSourceFiles(file->path, subProject, *subProjectConfig);
+ collectSourceFiles(file->path, subProject, *subProjectConfig, true);
ninjaProject->addSubProject(subProject, subProjectConfig, move(subProjectBuildPath));
}
else
- collectSourceFiles(file->path, ninjaProject, sibsConfig);
+ collectSourceFiles(file->path, ninjaProject, sibsConfig, true);
}
}
});
diff --git a/backend/BackendUtils.hpp b/backend/BackendUtils.hpp
index b2fe280..acef0ca 100644
--- a/backend/BackendUtils.hpp
+++ b/backend/BackendUtils.hpp
@@ -9,7 +9,7 @@ namespace backend
class BackendUtils
{
public:
- static bool isSourceFile(tinydir_file *file);
- static void collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const sibs::SibsConfig &sibsConfig);
+ 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 e6ca47a..6516cfb 100644
--- a/backend/ninja/Ninja.cpp
+++ b/backend/ninja/Ninja.cpp
@@ -5,6 +5,7 @@
#include "../../include/Exec.hpp"
#include "../../include/PkgConfig.hpp"
#include "../../include/GlobalLib.hpp"
+#include <ninja/Ninja.hpp>
using namespace std;
using namespace sibs;
@@ -17,7 +18,7 @@ using namespace sibs;
namespace backend
{
- string join(const vector<string> &list, const char *joinStr)
+ static string join(const vector<string> &list, const char *joinStr)
{
if(list.empty()) return "";
string result;
@@ -46,7 +47,7 @@ namespace backend
return result;
}
- bool endsWith(const string &str, const string &endWithStr)
+ static bool endsWith(const string &str, const string &endWithStr)
{
if(endWithStr.size() > str.size())
return false;
@@ -54,7 +55,7 @@ namespace backend
return strncmp(&str[str.size() - endWithStr.size()], &endWithStr[0], endWithStr.size()) == 0;
}
- Ninja::LibraryType getNinjaLibraryType(PackageType packageType)
+ static Ninja::LibraryType getNinjaLibraryType(PackageType packageType)
{
switch(packageType)
{
@@ -71,7 +72,7 @@ namespace backend
}
}
- string getIncludeOptionFlag(Compiler compiler, const string &filepath)
+ static string getIncludeOptionFlag(Compiler compiler, const string &filepath)
{
string result;
switch (compiler)
@@ -94,34 +95,26 @@ namespace backend
return result;
}
- string getDefineFlag(Compiler compiler, const string &name, const string &value)
+ static string getDefineFlag(Compiler compiler, const string &name, const string &value)
{
- string result;
switch (compiler)
{
case Compiler::GCC:
{
- result = "'-D";
- result += name;
- result += "=";
- result += value;
- result += "'";
- break;
+ return "'-D" + name + "=" + value + "'";
}
case Compiler::MSVC:
{
- result = "\"/D";
- result += name;
- result += "=";
- result += value;
- result += "\"";
- break;
+ return "\"/D" + name + "=" + value + "\"";
}
+ default:
+ assert(false);
+ break;
}
- return result;
+ return "";
}
- string getObjectFileNameFlag(Compiler compiler, const string &objectFileName)
+ static string getObjectFileNameFlag(Compiler compiler, const string &objectFileName)
{
string result;
switch (compiler)
@@ -142,7 +135,7 @@ namespace backend
return result;
}
- string getLanguageVersionFlag(Compiler compiler, CVersion cVersion)
+ static vector<ninja::NinjaArg> getLanguageVersionFlag(Compiler compiler, CVersion cVersion)
{
switch (compiler)
{
@@ -150,23 +143,23 @@ namespace backend
{
switch(cVersion)
{
- case CVersion::C89: return "-std=c89 -pedantic";
- case CVersion::C99: return "-std=c99 -pedantic";
- case CVersion::C11: return "-std=c11 -pedantic";
+ case CVersion::C89: return { ninja::NinjaArg("-std=c89"), ninja::NinjaArg("-pedantic") };
+ case CVersion::C99: return { ninja::NinjaArg("-std=c99"), ninja::NinjaArg("-pedantic") };
+ case CVersion::C11: return { ninja::NinjaArg("-std=c11"), ninja::NinjaArg("-pedantic") };
}
break;
}
case Compiler::MSVC:
{
// TODO: Is it possible to specify c version in msvc?
- return "";
+ return {};
}
}
assert(false);
- return "";
+ return {};
}
- string getLanguageVersionFlag(Compiler compiler, CPPVersion cppVersion)
+ static vector<ninja::NinjaArg> getLanguageVersionFlag(Compiler compiler, CPPVersion cppVersion)
{
switch (compiler)
{
@@ -174,9 +167,9 @@ namespace backend
{
switch(cppVersion)
{
- case CPPVersion::CPP11: return "-std=c++11 -pedantic";
- case CPPVersion::CPP14: return "-std=c++14 -pedantic";
- case CPPVersion::CPP17: return "-std=c++17 -pedantic";
+ case CPPVersion::CPP11: return { ninja::NinjaArg("-std=c++11"), ninja::NinjaArg("-pedantic") };
+ case CPPVersion::CPP14: return { ninja::NinjaArg("-std=c++14"), ninja::NinjaArg("-pedantic") };
+ case CPPVersion::CPP17: return { ninja::NinjaArg("-std=c++17"), ninja::NinjaArg("-pedantic") };
}
break;
}
@@ -185,18 +178,18 @@ namespace backend
switch(cppVersion)
{
// Use /Za flag?
- case CPPVersion::CPP11: return "/std=c++11";
- case CPPVersion::CPP14: return "/std=c++14";
- case CPPVersion::CPP17: return "/std=c++17";
+ case CPPVersion::CPP11: return { ninja::NinjaArg("/std=c++11") };
+ case CPPVersion::CPP14: return { ninja::NinjaArg("/std=c++14") };
+ case CPPVersion::CPP17: return { ninja::NinjaArg("/std=c++17") };
}
break;
}
}
assert(false);
- return "";
+ return {};
}
- const char* getObjectFileExtension(Compiler compiler)
+ static const char* getObjectFileExtension(Compiler compiler)
{
switch (compiler)
{
@@ -216,12 +209,12 @@ namespace backend
customGlobalIncludeDirs = globalIncludeDirs;
}
- void Ninja::addSourceFile(const char *filepath)
+ void Ninja::addSourceFile(sibs::Language language, const char *filepath)
{
string filePathStr = filepath ? filepath : "";
if(filepath && !containsSourceFile(filePathStr))
{
- sourceFiles.emplace_back(filePathStr);
+ sourceFiles.push_back({ language, filePathStr });
//printf("Adding source file: %s\n", filepath);
}
}
@@ -247,16 +240,16 @@ namespace backend
subProjects.emplace_back(NinjaSubProject{ subProject, config, move(buildPath) });
}
- const std::vector<std::string>& Ninja::getSourceFiles() const
+ const std::vector<sibs::SourceFile>& Ninja::getSourceFiles() const
{
return sourceFiles;
}
bool Ninja::containsSourceFile(const string &filepath) const
{
- for(const string &sourceFile : sourceFiles)
+ for(const sibs::SourceFile &sourceFile : sourceFiles)
{
- if(sourceFile == filepath)
+ if(sourceFile.filepath == filepath)
return true;
}
return false;
@@ -342,12 +335,6 @@ namespace backend
return GlobalLib::getLibs(globalLibDependencies, config, globalLibDir, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
}
- enum class SourceFileLanguage
- {
- C,
- CPP
- };
-
Result<bool> Ninja::buildSubProjects(LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
{
for(auto &subProject : subProjects)
@@ -367,6 +354,74 @@ namespace backend
return Result<bool>::Ok(true);
}
+ static vector<ninja::NinjaArg> getCompilerSanitizerFlags(const SibsConfig &config)
+ {
+ if(config.getCompiler() == Compiler::GCC && config.getSanitize())
+ {
+ return {
+ ninja::NinjaArg("-fno-omit-frame-pointer"),
+ ninja::NinjaArg("-fsanitize=address"),
+ ninja::NinjaArg("-fsanitize=undefined")
+ };
+ }
+ return {};
+ }
+
+ static vector<ninja::NinjaArg> getCompilerOptimizationFlags(const SibsConfig &config)
+ {
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ {
+ switch (config.getOptimizationLevel())
+ {
+ case OPT_LEV_DEBUG:
+ {
+ return {
+ ninja::NinjaArg("-Og"),
+ ninja::NinjaArg("-g3"),
+ ninja::NinjaArg("-D_FORTIFY_SOURCE=2"),
+ ninja::NinjaArg("-D_GLIBCXX_ASSERTIONS"),
+ ninja::NinjaArg("-fasynchronous-unwind-tables")
+ };
+ }
+ case OPT_LEV_RELEASE:
+ {
+ return {
+ ninja::NinjaArg("-O3"),
+ ninja::NinjaArg("-g0"),
+ ninja::NinjaArg("-DNDEBUG")
+ };
+ }
+ }
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ switch (config.getOptimizationLevel())
+ {
+ case OPT_LEV_DEBUG:
+ {
+ return {
+ ninja::NinjaArg("/Od"),
+ ninja::NinjaArg("/MTd")
+ };
+ }
+ case OPT_LEV_RELEASE:
+ {
+ return {
+ ninja::NinjaArg("/Ox"),
+ ninja::NinjaArg("/MT"),
+ ninja::NinjaArg("/DNDEBUG")
+ };
+ }
+ }
+ break;
+ }
+ }
+ return {};
+ }
+
Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
{
if (!sourceFiles.empty())
@@ -384,17 +439,15 @@ namespace backend
FileString ninjaBuildFilePath = savePath;
ninjaBuildFilePath += TINYDIR_STRING("/build.ninja");
- string result;
- result.reserve(2048);
-
- result += "globalIncDir = ";
+ ninja::NinjaBuildFile ninjaBuildFile;
+ string globalIncDir;
for(const auto &includeDir : config.getIncludeDirs())
{
string includeDirRelative = "../../";
includeDirRelative += includeDir;
- result += " ";
- result += getIncludeOptionFlag(config.getCompiler(), includeDirRelative);
+ globalIncDir += " ";
+ globalIncDir += getIncludeOptionFlag(config.getCompiler(), includeDirRelative);
}
auto parentGlobalIncludeDirCallback = globalIncludeDirCallback;
@@ -453,11 +506,10 @@ namespace backend
};
}
- string cflags;
+ vector<ninja::NinjaArg> cflags;
auto cflagsCallbackFunc = [&cflags](const string &dependencyCflags)
{
- cflags += " ";
- cflags += dependencyCflags;
+ cflags.push_back(ninja::NinjaArg::createRaw(dependencyCflags));
};
Result<bool> buildSubProjectResult = buildSubProjects(staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
@@ -474,309 +526,206 @@ namespace backend
allLinkerFlags += *it;
}
- result += dependencyExportIncludeDirs;
- result += "\n\n";
+ globalIncDir += dependencyExportIncludeDirs;
+ ninjaBuildFile.defineGlobalVariable("globalIncDir", globalIncDir);
- string defines;
+ vector<ninja::NinjaArg> defines;
for(const auto &definePair : config.getDefines())
{
- defines += " ";
- defines += getDefineFlag(config.getCompiler(), definePair.first, definePair.second);
+ defines.push_back(ninja::NinjaArg::createRaw(getDefineFlag(config.getCompiler(), definePair.first, definePair.second)));
}
-#if OS_TYPE == OS_TYPE_WINDOWS
switch (SYSTEM_PLATFORM)
{
case PLATFORM_WIN64:
- defines += " /DWIN64 /D_WIN64";
+ defines.insert(defines.end(), { ninja::NinjaArg("/DWIN64"), ninja::NinjaArg("/D_WIN64") });
// fallthrough
case PLATFORM_WIN32:
- defines += " /DWIN32 /D_WIN32";
+ defines.insert(defines.end(), { ninja::NinjaArg("/DWIN32"), ninja::NinjaArg("/D_WIN32") });
break;
}
- switch(libraryType)
+ if(SYSTEM_PLATFORM == PLATFORM_WIN32 || SYSTEM_PLATFORM == PLATFORM_WIN64)
{
- case LibraryType::EXECUTABLE:
- defines += " _CONSOLE";
- break;
- case LibraryType::STATIC:
- defines += " _LIB";
- break;
+ switch(libraryType)
+ {
+ // TODO: Executable type does not guarantee the executable should be a console on windows. Find a way to define window type as well
+ case LibraryType::EXECUTABLE:
+ defines.push_back(ninja::NinjaArg(" _CONSOLE"));
+ break;
+ case LibraryType::STATIC:
+ defines.push_back(ninja::NinjaArg(" _LIB"));
+ break;
+ }
}
-#endif
- string buildJob;
- switch(libraryType)
+ // TODO: Verify ccache is installed
+ // -Werror
+ // TODO: Find equivalent -MMD -MP for other compilers than gcc. MMD is used to create "dependency files" -> if headers are modified then source files will be recompiled
+ // when compiling next time...
+
+ vector<ninja::NinjaArg> compileCCommand;
+ vector<ninja::NinjaArg> compileCppCommand;
+
+ switch(config.getCompiler())
{
- case LibraryType::EXECUTABLE:
+ case Compiler::GCC:
{
- switch (config.getCompiler())
+ vector<ninja::NinjaArg> baseCompileCArgs;
+ switch(libraryType)
{
- case Compiler::GCC:
+ case LibraryType::EXECUTABLE:
{
- result += "rule cpp_COMPILER\n";
- result += " depfile = $out.d\n";
- result += " command = ccache c++ $ARGS -c $in -o $out\n\n";
-
- result += "rule BUILD_EXEC\n";
- result += " depfile = $out.d\n";
- result += " command = ccache c++ $ARGS -o $out $in $LINK_ARGS $aliasing\n\n";
-
- result += "rule c_COMPILER\n";
- result += " depfile = $out.d\n";
- result += " command = ccache cc $ARGS -c $in -o $out\n\n";
+ baseCompileCArgs.insert(baseCompileCArgs.end(), {
+ ninja::NinjaArg("ccache"),
+ ninja::NinjaArg("cc"),
+ ninja::NinjaArg("-c"),
+ ninja::NinjaArg("-fpie"),
+ ninja::NinjaArg("$in"),
+ ninja::NinjaArg("-o"),
+ ninja::NinjaArg("$out")
+ });
break;
}
- case Compiler::MSVC:
+ case LibraryType::STATIC:
+ case LibraryType::DYNAMIC:
{
- result += "rule cpp_COMPILER\n";
- result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
-
- result += "rule BUILD_EXEC\n";
- result += " command = cl.exe $ARGS $in /Fe$out $LINK_ARGS\n\n";
-
- result += "rule c_COMPILER\n";
- result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
+ baseCompileCArgs.insert(baseCompileCArgs.end(), {
+ ninja::NinjaArg("ccache"),
+ ninja::NinjaArg("cc"),
+ ninja::NinjaArg("-c"),
+ ninja::NinjaArg("-fpic"),
+ ninja::NinjaArg("$in"),
+ ninja::NinjaArg("-o"),
+ ninja::NinjaArg("$out")
+ });
break;
}
}
- buildJob = "BUILD_EXEC";
- break;
- }
- case LibraryType::STATIC:
- {
- switch (config.getCompiler())
+ compileCCommand.insert(compileCCommand.end(), baseCompileCArgs.begin(), baseCompileCArgs.end());
+ compileCCommand.insert(compileCCommand.end(), {
+ ninja::NinjaArg("-fdiagnostics-show-option"),
+ ninja::NinjaArg("-fdiagnostics-color=always"),
+ ninja::NinjaArg("-pipe"),
+ ninja::NinjaArg("-D_FILE_OFFSET_BITS=64"),
+ ninja::NinjaArg("-Winvalid-pch"),
+ ninja::NinjaArg("-fstack-protector"),
+ ninja::NinjaArg("-MMD"),
+ ninja::NinjaArg("-I" + config.getPackageName() + "@exe"),
+ ninja::NinjaArg("$globalIncDir")
+ });
+
+ compileCCommand.insert(compileCCommand.end(), cflags.begin(), cflags.end());
+ compileCCommand.insert(compileCCommand.end(), defines.begin(), defines.end());
+
+ if(config.showWarnings)
{
- case Compiler::GCC:
- {
- result += "rule cpp_COMPILER\n";
- result += " depfile = $out.d\n";
- result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n";
-
- result += "rule BUILD_STATIC\n";
- result += " command = ar rcs lib";
- result += config.getPackageName();
- result += ".a";
- result += " $in\n\n";
-
- result += "rule c_COMPILER\n";
- result += " depfile = $out.d\n";
- result += " command = ccache cc $ARGS -c -fPIC $in -o $out\n\n";
- break;
- }
- case Compiler::MSVC:
- {
- result += "rule cpp_COMPILER\n";
- result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
-
- result += "rule BUILD_STATIC\n";
- result += " command = lib.exe /OUT:$out $in\n\n";
-
- result += "rule c_COMPILER\n";
- result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
- break;
- }
+ compileCCommand.insert(compileCCommand.end(), {
+ ninja::NinjaArg("-Wall"),
+ ninja::NinjaArg("-Wextra"),
+ ninja::NinjaArg("-Werror=return-type")
+ });
}
-
- buildJob = "BUILD_STATIC";
- break;
- }
- case LibraryType::DYNAMIC:
- {
- switch (config.getCompiler())
+ else
{
- case Compiler::GCC:
- {
- result += "rule cpp_COMPILER\n";
- result += " depfile = $out.d\n";
- result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n";
-
- // --whole-archive
- result += "rule BUILD_DYNAMIC\n";
- result += " depfile = $out.d\n";
- result += " command = ccache c++ $in -shared -o $out $LINK_ARGS $aliasing\n\n";
-
- result += "rule c_COMPILER\n";
- result += " depfile = $out.d\n";
- result += " command = ccache cc $ARGS -c -fPIC $in -o $out\n\n";
- break;
- }
- case Compiler::MSVC:
- {
- result += "rule cpp_COMPILER\n";
- result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
-
- //result += "rule BUILD_DYNAMIC\n";
- //result += " command = cl.exe /LD $in /Fe$out $LINK_ARGS\n\n";
-
- result += "rule BUILD_DYNAMIC\n";
- result += " command = lib.exe /OUT:$out $in\n\n";
-
- result += "rule c_COMPILER\n";
- result += " command = cl.exe $ARGS /c $in /Fo$out\n\n";
- break;
- }
+ compileCCommand.push_back(ninja::NinjaArg("-w"));
}
- buildJob = "BUILD_DYNAMIC";
- break;
- }
- default:
- assert(false);
- return Result<bool>::Err("Unexpected error");
- }
+ vector<ninja::NinjaArg> optimizationFlags = getCompilerOptimizationFlags(config);
+ compileCCommand.insert(compileCCommand.end(), optimizationFlags.begin(), optimizationFlags.end());
- // TODO: Add equivalent functionality for msvc. Currently msvc always builds as debug build
- string optimizationFlags;
- switch (config.getOptimizationLevel())
- {
- case OPT_LEV_DEBUG:
- {
- switch (config.getCompiler())
- {
- case Compiler::GCC:
- {
- optimizationFlags = "'-Og'";
- break;
- }
- case Compiler::MSVC:
- {
- optimizationFlags = "/Od";
- break;
- }
- }
+ vector<ninja::NinjaArg> sanitizerFlags = getCompilerSanitizerFlags(config);
+ compileCCommand.insert(compileCCommand.end(), sanitizerFlags.begin(), sanitizerFlags.end());
+
+ compileCppCommand = compileCCommand;
+ compileCppCommand[1] = ninja::NinjaArg("c++");
+ compileCppCommand.insert(compileCppCommand.end(), {
+ ninja::NinjaArg("-fexceptions"),
+ ninja::NinjaArg("-Wnon-virtual-dtor")
+ });
break;
}
- case OPT_LEV_RELEASE:
+ case Compiler::MSVC:
{
- switch (config.getCompiler())
+ compileCCommand.insert(compileCCommand.end(), {
+ ninja::NinjaArg("cl.exe"),
+ ninja::NinjaArg("/c"),
+ ninja::NinjaArg("$in"),
+ ninja::NinjaArg("/Fo$out")
+ });
+
+ compileCCommand.insert(compileCCommand.end(), cflags.begin(), cflags.end());
+ compileCCommand.insert(compileCCommand.end(), defines.begin(), defines.end());
+
+ if(config.showWarnings)
+ compileCCommand.push_back(ninja::NinjaArg("/Wall"));
+ else
+ compileCCommand.push_back(ninja::NinjaArg("/w"));
+
+ switch (SYSTEM_PLATFORM)
{
- case Compiler::GCC:
- {
- optimizationFlags = "'-O3' '-DNDEBUG'";
+ case PLATFORM_WIN32:
+ compileCCommand.push_back(ninja::NinjaArg("/MACHINE:X86"));
break;
- }
- case Compiler::MSVC:
- {
- optimizationFlags = "/Ox /DNDEBUG";
+ case PLATFORM_WIN64:
+ compileCCommand.push_back(ninja::NinjaArg("/MACHINE:X64"));
break;
- }
}
+
+ vector<ninja::NinjaArg> optimizationFlags = getCompilerOptimizationFlags(config);
+ compileCCommand.insert(compileCCommand.end(), optimizationFlags.begin(), optimizationFlags.end());
+
+ vector<ninja::NinjaArg> sanitizerFlags = getCompilerSanitizerFlags(config);
+ compileCCommand.insert(compileCCommand.end(), sanitizerFlags.begin(), sanitizerFlags.end());
+
+ compileCppCommand = compileCCommand;
+ compileCppCommand.push_back(ninja::NinjaArg("/EHs"));
break;
}
}
+ vector<ninja::NinjaArg> cLanguageVersionFlags = getLanguageVersionFlag(config.getCompiler(), config.getCversion());
+ compileCCommand.insert(compileCCommand.end(), cLanguageVersionFlags.begin(), cLanguageVersionFlags.end());
+
+ vector<ninja::NinjaArg> cppLanguageVersionFlags = getLanguageVersionFlag(config.getCompiler(), config.getCppVersion());
+ compileCppCommand.insert(compileCppCommand.end(), cppLanguageVersionFlags.begin(), cppLanguageVersionFlags.end());
+
+ ninja::NinjaRule *compileCRule = ninjaBuildFile.createRule("compile_c", compileCCommand);
+ compileCRule->depFile = "$out.d";
+
+ ninja::NinjaRule *compileCppRule = ninjaBuildFile.createRule("compile_cpp", compileCppCommand);
+ compileCppRule->depFile = "$out.d";
+
+ bool usesCFiles = false;
+ bool usesCppFiles = false;
+
vector<string> objectNames;
objectNames.reserve(sourceFiles.size());
- for(const string &sourceFile : sourceFiles)
+ for(const sibs::SourceFile &sourceFile : sourceFiles)
{
- SourceFileLanguage sourceFileLanguage = SourceFileLanguage::CPP;
- if(endsWith(sourceFile, ".c"))
- sourceFileLanguage = SourceFileLanguage::C;
-
- const char *buildTarget;
- switch(sourceFileLanguage)
- {
- case SourceFileLanguage::C:
- buildTarget = "c_COMPILER";
- break;
- case SourceFileLanguage::CPP:
- buildTarget = "cpp_COMPILER";
- break;
- }
-
- //string sourceFileEncoded = sourceFile;
- //replace(sourceFileEncoded, '/', '@');
- string objectName = config.getPackageName() + "@exe/" + sourceFile;
+ string objectName = config.getPackageName() + "@exe/" + sourceFile.filepath;
objectName += getObjectFileExtension(config.getCompiler());
- result += "build ";
- result += objectName;
- result += ": ";
- result += buildTarget;
- result += " ../../";
- result += sourceFile;
- result += "\n";
- result += " ARGS = $globalIncDir ";
- if(!defines.empty())
- result += defines;
-
- result += " ";
- switch(sourceFileLanguage)
- {
- case SourceFileLanguage::C:
- result += getLanguageVersionFlag(config.getCompiler(), config.getCversion());
- break;
- case SourceFileLanguage::CPP:
- result += getLanguageVersionFlag(config.getCompiler(), config.getCppVersion());
- break;
- }
-
- switch (config.getCompiler())
+
+ switch(sourceFile.language)
{
- case Compiler::GCC:
+ case sibs::Language::C:
{
- // -Werror
- // TODO: Find equivalent -MMD -MP for other compilers than gcc. MMD is used to create "dependency files" -> if headers are modified then source files will be recompiled
- // when compiling next time...
- result += " -fpie -MMD -MP '-I" + config.getPackageName() + "@exe' " + cflags + " '-I..'";
- if(config.showWarnings)
- result += " -Wall -Wextra -Werror=return-type";
- else
- result += " -w";
- result += " -fdiagnostics-show-option '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Winvalid-pch' -fstack-protector " + optimizationFlags;
- if(sourceFileLanguage == SourceFileLanguage::CPP)
- result += " -fexceptions -Wnon-virtual-dtor";
-
- switch (config.getOptimizationLevel())
- {
- case OPT_LEV_DEBUG:
- result += " -g3 -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS -fasynchronous-unwind-tables";
- break;
- case OPT_LEV_RELEASE:
- result += " -g0";
- break;
- }
-
- if(config.getSanitize())
- {
- result += " -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined";
- }
+ ninjaBuildFile.build(compileCRule, "../../" + sourceFile.filepath, objectName, {});
+ usesCFiles = true;
break;
}
- case Compiler::MSVC:
+ case sibs::Language::CPP:
{
- result += " ";
- result += optimizationFlags;
- result += " /EHs";
- if(config.showWarnings)
- result += "/Wall ";
- else
- result += "/w ";
- result += cflags;
- switch (config.getOptimizationLevel())
- {
- case OPT_LEV_DEBUG:
- result += " /MTd";
- break;
- case OPT_LEV_RELEASE:
- result += " /MT";
- break;
- }
- switch (SYSTEM_PLATFORM)
- {
- case PLATFORM_WIN32:
- result += " /MACHINE:X86";
- break;
- case PLATFORM_WIN64:
- result += " /MACHINE:X64";
- break;
- }
+ ninjaBuildFile.build(compileCppRule, "../../" + sourceFile.filepath, objectName, {});
+ usesCppFiles = true;
break;
}
+ default:
+ assert(false);
+ break;
}
- result += "\n\n";
+
objectNames.emplace_back(objectName);
}
@@ -791,35 +740,62 @@ namespace backend
{
case LibraryType::EXECUTABLE:
{
- result += "build ";
- result += config.getPackageName();
- result += ": " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n";
+ vector<ninja::NinjaArg> buildExeArgs;
switch (config.getCompiler())
{
case Compiler::GCC:
{
- // TODO: Add flag to disable -ldl and -lm (dlopen, dlclose, floor, max, ...)
- result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed'";
+ buildExeArgs.insert(buildExeArgs.end(), {
+ ninja::NinjaArg("ccache"),
+ ninja::NinjaArg(usesCppFiles ? "c++" : "cc"),
+ ninja::NinjaArg("-o"),
+ ninja::NinjaArg("$out"),
+ ninja::NinjaArg("$in"),
+ ninja::NinjaArg("-Wl,--no-undefined,--as-needed")
+ });
+
if(config.getSanitize())
- result += " -lasan -lubsan";
- result += " -ldl -lm ";
+ {
+ buildExeArgs.insert(buildExeArgs.end(), {
+ ninja::NinjaArg("-lasan"),
+ ninja::NinjaArg("-lubsan")
+ });
+ }
+
+ // TODO: Add flag to disable -ldl and -lm (dlopen, dlclose, floor, max, ...)
+ buildExeArgs.insert(buildExeArgs.end(), {
+ ninja::NinjaArg("-ldl"),
+ ninja::NinjaArg("-lm")
+ });
break;
}
case Compiler::MSVC:
{
// TODO: Do not link all of these. Find a way to only link the ones that are needed
- result += " LINK_ARGS = Ws2_32.lib Wldap32.lib Crypt32.lib Advapi32.lib Gdi32.lib User32.lib Userenv.lib OpenGL32.lib GlU32.lib Shell32.lib ";
+ buildExeArgs.insert(buildExeArgs.end(), {
+ ninja::NinjaArg("cl.exe"),
+ ninja::NinjaArg("$in"),
+ ninja::NinjaArg("/Fe$out"),
+ ninja::NinjaArg("Ws2_32.lib"),
+ ninja::NinjaArg("Wldap32.lib"),
+ ninja::NinjaArg("Crypt32.lib"),
+ ninja::NinjaArg("Advapi32.lib"),
+ ninja::NinjaArg("Gdi32.lib"),
+ ninja::NinjaArg("User32.lib"),
+ ninja::NinjaArg("Userenv.lib"),
+ ninja::NinjaArg("OpenGL32.lib"),
+ ninja::NinjaArg("GlU32.lib"),
+ ninja::NinjaArg("Shell32.lib")
+ });
break;
}
}
if (!allLinkerFlags.empty())
- {
- result += allLinkerFlags;
- }
- result += "\n\n";
+ buildExeArgs.push_back(ninja::NinjaArg::createRaw(allLinkerFlags));
+
+ ninja::NinjaRule *buildExeRule = ninjaBuildFile.createRule("build_exec", buildExeArgs);
+ ninjaBuildFile.build(buildExeRule, join(objectNames, " "), config.getPackageName(), {});
projectGeneratedBinary += config.getPackageName();
#if OS_FAMILY == OS_FAMILY_WINDOWS
@@ -829,30 +805,37 @@ namespace backend
}
case LibraryType::STATIC:
{
+ vector<ninja::NinjaArg> buildStaticArgs;
+ string generatedFile;
switch (config.getCompiler())
{
case Compiler::GCC:
{
- result += "build lib";
- result += config.getPackageName();
- result += ".a: " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n\n";
- projectGeneratedBinary += "lib" + config.getPackageName() + ".a";
+ generatedFile = "lib" + config.getPackageName() + ".a";
+ buildStaticArgs.insert(buildStaticArgs.end(), {
+ ninja::NinjaArg::createRaw("ar"),
+ ninja::NinjaArg::createRaw("rcs"),
+ ninja::NinjaArg::createRaw("$out"),
+ ninja::NinjaArg::createRaw("$in")
+ });
break;
}
case Compiler::MSVC:
{
- result += "build ";
- result += config.getPackageName();
- result += ".lib: " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n\n";
- projectGeneratedBinary += config.getPackageName() + ".lib";
+ generatedFile = config.getPackageName() + ".lib";
+ buildStaticArgs.insert(buildStaticArgs.end(), {
+ ninja::NinjaArg::createRaw("lib.exe"),
+ ninja::NinjaArg::createRaw("/OUT:$out"),
+ ninja::NinjaArg::createRaw("$in")
+ });
break;
}
}
+
+ ninja::NinjaRule *buildStaticRule = ninjaBuildFile.createRule("build_static", buildStaticArgs);
+ ninjaBuildFile.build(buildStaticRule, join(objectNames, " "), generatedFile, {});
+ projectGeneratedBinary += generatedFile;
projectGeneratedBinary += "\"";
if(parentProjStaticLinkerFlagCallbackFunc)
parentProjStaticLinkerFlagCallbackFunc(projectGeneratedBinary);
@@ -861,43 +844,68 @@ namespace backend
}
case LibraryType::DYNAMIC:
{
+ vector<ninja::NinjaArg> buildDynamicArgs;
+ string generatedFile;
switch (config.getCompiler())
{
case Compiler::GCC:
{
- result += "build lib";
- result += config.getPackageName();
- result += ".so: " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n";
- result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed'";
+ generatedFile = "lib" + config.getPackageName() + ".so";
+
+ buildDynamicArgs.insert(buildDynamicArgs.end(), {
+ ninja::NinjaArg("ccache"),
+ ninja::NinjaArg(usesCppFiles ? "c++" : "cc"),
+ ninja::NinjaArg("$in"),
+ ninja::NinjaArg("-shared"),
+ ninja::NinjaArg("-o"),
+ ninja::NinjaArg("$out"),
+ ninja::NinjaArg("-Wl,--no-undefined,--as-needed")
+ });
+
if(config.getSanitize())
- result += " -lasan -lubsan";
- result += " -ldl -lm ";
- projectGeneratedBinary += "lib" + config.getPackageName() + ".so";
+ {
+ buildDynamicArgs.insert(buildDynamicArgs.end(), {
+ ninja::NinjaArg("-lasan"),
+ ninja::NinjaArg("-lubsan")
+ });
+ }
+
+ // TODO: Add flag to disable -ldl and -lm (dlopen, dlclose, floor, max, ...)
+ buildDynamicArgs.insert(buildDynamicArgs.end(), {
+ ninja::NinjaArg("-ldl"),
+ ninja::NinjaArg("-lm")
+ });
break;
}
case Compiler::MSVC:
{
- result += "build ";
- result += config.getPackageName();
- result += ".lib: " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n";
- // TODO: Do not link all of these. Find a way to only link the ones that are needed
- result += " LINK_ARGS = Ws2_32.lib Wldap32.lib Crypt32.lib Advapi32.lib Gdi32.lib User32.lib Userenv.lib OpenGL32.lib GlU32.lib Shell32.lib ";
- projectGeneratedBinary += config.getPackageName() + ".lib";
+ generatedFile = config.getPackageName() + ".dll";
+ buildDynamicArgs.insert(buildDynamicArgs.end(), {
+ ninja::NinjaArg::createRaw("lib.exe"),
+ ninja::NinjaArg::createRaw("/OUT:$out"),
+ ninja::NinjaArg::createRaw("$in"),
+ ninja::NinjaArg("Ws2_32.lib"),
+ ninja::NinjaArg("Wldap32.lib"),
+ ninja::NinjaArg("Crypt32.lib"),
+ ninja::NinjaArg("Advapi32.lib"),
+ ninja::NinjaArg("Gdi32.lib"),
+ ninja::NinjaArg("User32.lib"),
+ ninja::NinjaArg("Userenv.lib"),
+ ninja::NinjaArg("OpenGL32.lib"),
+ ninja::NinjaArg("GlU32.lib"),
+ ninja::NinjaArg("Shell32.lib")
+ });
break;
}
}
if (!allLinkerFlags.empty())
- {
- result += allLinkerFlags;
- //result += " '-Wl,--no-whole-archive'";
- }
- result += "\n\n";
+ buildDynamicArgs.push_back(ninja::NinjaArg::createRaw(allLinkerFlags));
+
+ ninja::NinjaRule *buildDynamicRule = ninjaBuildFile.createRule("build_dynamic", buildDynamicArgs);
+ ninjaBuildFile.build(buildDynamicRule, join(objectNames, " "), generatedFile, {});
+ projectGeneratedBinary += generatedFile;
projectGeneratedBinary += "\"";
if(parentProjDynamicLinkerFlagCallbackFunc)
parentProjDynamicLinkerFlagCallbackFunc(projectGeneratedBinary);
@@ -910,7 +918,7 @@ namespace backend
}
projectGeneratedBinaryFlags = allLinkerFlags + " " + projectGeneratedBinary;
-
+ string result = ninjaBuildFile.generate();
Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size()));
if (fileOverwriteResult.isErr())
return fileOverwriteResult;
@@ -983,19 +991,8 @@ namespace backend
ninja.addGlobalIncludeDirs(parentExportIncludeDirs);
if(!projectGeneratedBinaryFlags.empty())
ninja.addDependency(projectGeneratedBinaryFlags);
- // TODO: Use same source file finder as in main.cpp
- walkDirFilesRecursive(testSourceDirNative.c_str(), [&ninja, &sibsTestConfig](tinydir_file *file)
- {
- if (backend::BackendUtils::isSourceFile(file))
- {
- string filePathUtf8 = toUtf8(file->path + sibsTestConfig.getProjectPath().size() + 1);
- ninja.addSourceFile(filePathUtf8.c_str());
- }
- else
- {
- //printf("Ignoring non-source file: %s\n", file->path + projectPath.size());
- }
- });
+
+ backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig, false);
if(!ninja.getSourceFiles().empty())
{
@@ -1014,7 +1011,7 @@ namespace backend
if (!buildFileResult)
return buildFileResult;
- // Convenient to have project setup to tests as well
+ // Main projects test should also have compilation database, so we can use it inside IDE
if(config.isMainProject())
{
buildFileResult = buildCompilationDatabase(buildPath.c_str(), testSourceDirNative);
diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp
index 68e51b1..8606708 100644
--- a/backend/ninja/Ninja.hpp
+++ b/backend/ninja/Ninja.hpp
@@ -42,11 +42,11 @@ namespace backend
Ninja();
void addGlobalIncludeDirs(const std::string &globalIncludeDirs);
- void addSourceFile(const char *filepath);
+ void addSourceFile(sibs::Language language, const char *filepath);
void addTestSourceDir(const char *dir);
void addDependency(const std::string &binaryFile);
void addSubProject(Ninja *subProject, sibs::SibsConfig *config, sibs::FileString &&buildPath);
- const std::vector<std::string>& getSourceFiles() const;
+ const std::vector<sibs::SourceFile>& getSourceFiles() const;
sibs::Result<bool> build(const sibs::SibsConfig &config, const _tinydir_char_t *savePath, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc = nullptr, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback = nullptr, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback = nullptr);
private:
sibs::Result<bool> buildSubProjects(sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback);
@@ -59,7 +59,7 @@ namespace backend
sibs::Result<bool> buildCompilationDatabase(const _tinydir_char_t *buildFilePath, const sibs::FileString &savePath);
private:
std::string customGlobalIncludeDirs;
- std::vector<std::string> sourceFiles;
+ std::vector<sibs::SourceFile> sourceFiles;
std::vector<std::string> testSourceDirs;
std::vector<std::string> binaryDependencies;
std::vector<NinjaSubProject> subProjects;