aboutsummaryrefslogtreecommitdiff
path: root/backend/ninja/Ninja.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/ninja/Ninja.cpp')
-rw-r--r--backend/ninja/Ninja.cpp375
1 files changed, 230 insertions, 145 deletions
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp
index 49bda4f..0b46891 100644
--- a/backend/ninja/Ninja.cpp
+++ b/backend/ninja/Ninja.cpp
@@ -90,6 +90,33 @@ namespace backend
return result;
}
+ 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;
+ }
+ case Compiler::MSVC:
+ {
+ result = "\"/D";
+ result += name;
+ result += "=";
+ result += value;
+ result += "\"";
+ break;
+ }
+ }
+ return result;
+ }
+
string getCompileWithoutLinkingFlag(Compiler compiler)
{
string result;
@@ -221,7 +248,7 @@ namespace backend
#endif
// TODO: First check if pkg-config is installed. If it's not, only check dependencies that exists in the dependencies sub directory.
// If pkg-config is installed and dependency is not installed, check in dependencies sub directory.
- Result<bool> Ninja::getLinkerFlags(const SibsConfig &config, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const
+ Result<bool> Ninja::getLinkerFlags(const SibsConfig &config, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) const
{
const vector<Dependency> &dependencies = config.getDependencies();
if(dependencies.empty()) return Result<bool>::Ok(true);
@@ -277,7 +304,7 @@ namespace backend
for(const Dependency &globalLibDependency : globalLibDependencies)
{
printf("Dependency %s is missing from pkg-config, trying global lib\n", globalLibDependency.name.c_str());
- Result<string> globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback);
+ Result<bool> globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
if(globalLibLinkerFlagsResult.isErr())
{
if(globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_NOT_FOUND || globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_VERSION_NO_MATCH)
@@ -296,7 +323,7 @@ namespace backend
if(downloadDependencyResult.isErr())
return downloadDependencyResult;
- globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback);
+ globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
if(globalLibLinkerFlagsResult.isErr())
return Result<bool>::Err(globalLibLinkerFlagsResult);
}
@@ -310,19 +337,19 @@ namespace backend
return Result<bool>::Ok(true);
}
- Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback)
+ Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
{
- // TODO: Do not quit here if no source files are provided. The source-less project could have dependencies
- if(sourceFiles.empty())
- return Result<bool>::Err("No source files provided");
-
- Result<bool> createBuildDirResult = createDirectoryRecursive(savePath);
- if(createBuildDirResult.isErr())
- return createBuildDirResult;
+ if (!sourceFiles.empty())
+ {
+ Result<bool> createBuildDirResult = createDirectoryRecursive(savePath);
+ if (createBuildDirResult.isErr())
+ return createBuildDirResult;
+ }
LibraryType libraryType = getNinjaLibraryType(config.getPackageType());
string savePathUtf8 = toUtf8(savePath);
+ string projectPathUtf8 = toUtf8(config.getProjectPath());
FileString ninjaBuildFilePath = savePath;
ninjaBuildFilePath += TINYDIR_STRING("/build.ninja");
@@ -336,9 +363,11 @@ namespace backend
FileString globalIncDir = globalIncDirResult.unwrap();
globalIncDir += TINYDIR_STRING("/.sibs/lib");
+ string globalIncDirUtf8 = toUtf8(globalIncDir);
result += "globalIncDir = ";
- result += getIncludeOptionFlag(config.getCompiler(), toUtf8(globalIncDir));
+ result += getIncludeOptionFlag(config.getCompiler(), globalIncDirUtf8);
+
for(const auto &includeDir : config.getIncludeDirs())
{
string includeDirRelative = "../../";
@@ -346,16 +375,67 @@ namespace backend
result += " ";
result += getIncludeOptionFlag(config.getCompiler(), includeDirRelative);
}
+
+ auto parentGlobalIncludeDirCallback = globalIncludeDirCallback;
+ for (const string &globalIncludeDir : config.getGlobalIncludeDirs())
+ {
+ string globalIncludeDirFull = projectPathUtf8;
+ globalIncludeDirFull += "/";
+ globalIncludeDirFull += globalIncludeDir;
+ if(parentGlobalIncludeDirCallback)
+ parentGlobalIncludeDirCallback(globalIncludeDirFull);
+ }
+
+ globalIncludeDirCallback = [&parentGlobalIncludeDirCallback, &globalIncludeDirCallback, &result, &config](const string &globalIncludeDir)
+ {
+ result += " ";
+ result += getIncludeOptionFlag(config.getCompiler(), globalIncludeDir);
+ if (parentGlobalIncludeDirCallback)
+ parentGlobalIncludeDirCallback(globalIncludeDir);
+ };
+
+#if OS_TYPE == OS_TYPE_LINUX
+ // TODO: Allow configuring default linking flags. Maybe have `package.useThreads = false` to disable this flag
+ string allLinkerFlags = "-pthread";
+#else
+ string allLinkerFlags = "";
+#endif
+
+ // TODO: Somehow check loading order, because it has to be correct to work.. Or does it for dynamic libraries?
+ // Anyways it's required for static libraries (especially on Windows)
+ for (const string &binaryDependency : binaryDependencies)
+ {
+ allLinkerFlags += " ";
+ allLinkerFlags += binaryDependency;
+ }
+
+ if (!staticLinkerFlagCallbackFunc || libraryType == LibraryType::DYNAMIC)
+ {
+ staticLinkerFlagCallbackFunc = [&allLinkerFlags](const string &linkerFlag)
+ {
+ allLinkerFlags += " ";
+ allLinkerFlags += linkerFlag;
+ };
+ }
+
+ // TODO: If project contains no source files, then we shouldn't override this function
+ dynamicLinkerFlagCallback = [&allLinkerFlags](const string &linkerFlag)
+ {
+ allLinkerFlags += " ";
+ allLinkerFlags += linkerFlag;
+ };
+
+ Result<bool> linkerFlags = getLinkerFlags(config, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
+ if (linkerFlags.isErr())
+ return Result<bool>::Err(linkerFlags.getErrMsg());
+
result += "\n\n";
string defines;
for(const auto &definePair : config.getDefines())
{
- defines += " '-D";
- defines += definePair.first;
- defines += "=";
- defines += definePair.second;
- defines += "'";
+ defines += " ";
+ defines += getDefineFlag(config.getCompiler(), definePair.first, definePair.second);
}
if(!defines.empty())
@@ -452,6 +532,7 @@ namespace backend
return Result<bool>::Err("Unexpected error");
}
+ // TODO: Add equivalent functionality for msvc. Currently msvc always builds as debug build
string optimizationFlags;
switch(config.getOptimizationLevel())
{
@@ -482,156 +563,156 @@ namespace backend
result += " ARGS = $globalIncDir ";
if(!defines.empty())
result += defines;
- if(config.getCompiler() != Compiler::MSVC)
- result += " '-I" + config.getPackageName() + "@exe' '-I..' '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' " + optimizationFlags + " '-g'";
+ switch (config.getCompiler())
+ {
+ case Compiler::GCC:
+ {
+ result += " '-I" + config.getPackageName() + "@exe' '-I..' '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' " + optimizationFlags + " '-g'";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ result += " /EHsc";
+ 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;
+ }
+ break;
+ }
+ }
result += "\n\n";
objectNames.emplace_back(objectName);
}
-#if OS_TYPE == OS_TYPE_LINUX
- // TODO: Allow configuring default linking flags. Maybe have `package.useThreads = false` to disable this flag
- string allLinkerFlags = "-pthread";
-#else
- string allLinkerFlags = "";
-#endif
-
- // TODO: Somehow check loading order, because it has to be correct to work.. Or does it for dynamic libraries?
- // Anyways it's required for static libraries (especially on Windows)
- for(const string &binaryDependency : binaryDependencies)
+ string projectGeneratedBinary;
+ if (!sourceFiles.empty())
{
- allLinkerFlags += " ";
- allLinkerFlags += binaryDependency;
- }
-
- if(!staticLinkerFlagCallbackFunc || libraryType == LibraryType::DYNAMIC)
- {
- staticLinkerFlagCallbackFunc = [&allLinkerFlags](const string &linkerFlag)
+ projectGeneratedBinary = allLinkerFlags;
+ projectGeneratedBinary += " \"";
+ projectGeneratedBinary += savePathUtf8;
+ projectGeneratedBinary += "/";
+ switch (libraryType)
{
- allLinkerFlags += " ";
- allLinkerFlags += linkerFlag;
- };
- }
-
- // TODO: If project contains no source files, then we shouldn't override this function
- dynamicLinkerFlagCallback = [&allLinkerFlags](const string &linkerFlag)
- {
- allLinkerFlags += " ";
- allLinkerFlags += linkerFlag;
- };
-
- Result<bool> linkerFlags = getLinkerFlags(config, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback);
- if(linkerFlags.isErr())
- return Result<bool>::Err(linkerFlags.getErrMsg());
-
- string projectGeneratedBinary = allLinkerFlags;
- projectGeneratedBinary += " '";
- projectGeneratedBinary += savePathUtf8;
- projectGeneratedBinary += "/";
- switch(libraryType)
- {
- case LibraryType::EXECUTABLE:
- {
- result += "build ";
- result += config.getPackageName();
- result += ": " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n";
- switch (config.getCompiler())
+ case LibraryType::EXECUTABLE:
{
- case Compiler::GCC:
+ result += "build ";
+ result += config.getPackageName();
+ result += ": " + buildJob + " ";
+ result += join(objectNames, " ");
+ result += "\n";
+ switch (config.getCompiler())
{
- result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' ";
- break;
+ case Compiler::GCC:
+ {
+ result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' ";
+ 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 ";
+ break;
+ }
}
- case Compiler::MSVC:
+
+ if (!allLinkerFlags.empty())
{
- result += " LINK_ARGS = ";
- break;
+ result += allLinkerFlags;
}
+ result += "\n\n";
+ projectGeneratedBinary += config.getPackageName();
+ break;
}
-
- if(!allLinkerFlags.empty())
+ case LibraryType::STATIC:
{
- result += allLinkerFlags;
- }
- result += "\n\n";
- projectGeneratedBinary += config.getPackageName();
- break;
- }
- case LibraryType::STATIC:
- {
- result += "build ";
- result += config.getPackageName();
- result += ": " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n\n";
+ result += "build ";
+ result += config.getPackageName();
+ result += ": " + buildJob + " ";
+ result += join(objectNames, " ");
+ result += "\n\n";
- switch (config.getCompiler())
- {
- case Compiler::GCC:
+ switch (config.getCompiler())
{
- projectGeneratedBinary += config.getPackageName() + ".a";
- break;
- }
- case Compiler::MSVC:
- {
- projectGeneratedBinary += config.getPackageName() + ".lib";
- break;
+ case Compiler::GCC:
+ {
+ projectGeneratedBinary += config.getPackageName() + ".a";
+ break;
+ }
+ case Compiler::MSVC:
+ {
+ projectGeneratedBinary += config.getPackageName() + ".lib";
+ break;
+ }
}
+ break;
}
- break;
- }
- case LibraryType::DYNAMIC:
- {
- switch (config.getCompiler())
+ case LibraryType::DYNAMIC:
{
- case Compiler::GCC:
+ switch (config.getCompiler())
{
- result += "build lib";
- result += config.getPackageName();
- result += ".so: " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n";
- result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' ";
- projectGeneratedBinary += "lib" + config.getPackageName() + ".so";
- break;
+ 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' ";
+ projectGeneratedBinary += "lib" + config.getPackageName() + ".so";
+ 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 ";
+ projectGeneratedBinary += config.getPackageName() + ".lib";
+ break;
+ }
}
- case Compiler::MSVC:
+
+ if (!allLinkerFlags.empty())
{
- result += "build ";
- result += config.getPackageName();
- result += ".lib: " + buildJob + " ";
- result += join(objectNames, " ");
- result += "\n";
- result += " LINK_ARGS = ";
- projectGeneratedBinary += config.getPackageName() + ".lib";
- break;
+ result += allLinkerFlags;
+ //result += " '-Wl,--no-whole-archive'";
}
+ result += "\n\n";
+ break;
}
-
- if(!allLinkerFlags.empty())
- {
- result += allLinkerFlags;
- //result += " '-Wl,--no-whole-archive'";
- }
- result += "\n\n";
- break;
+ default:
+ assert(false);
+ return Result<bool>::Err("Unexpected error");
}
- default:
- assert(false);
- return Result<bool>::Err("Unexpected error");
- }
- projectGeneratedBinary += "'";
+ projectGeneratedBinary += "\"";
- Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size()));
- if(fileOverwriteResult.isErr())
- return fileOverwriteResult;
+ Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size()));
+ if (fileOverwriteResult.isErr())
+ return fileOverwriteResult;
- nprintf(TINYDIR_STRING("Created ninja build file: %s\n"), ninjaBuildFilePath.c_str());
+ nprintf(TINYDIR_STRING("Created ninja build file: %s\n"), ninjaBuildFilePath.c_str());
- Result<bool> buildResult = build(savePath);
- if(!buildResult)
- return buildResult;
+ Result<bool> buildResult = compile(savePath);
+ if (!buildResult)
+ return buildResult;
+ }
Result<bool> buildTestResult = buildTests(projectGeneratedBinary, config, savePath);
if(!buildTestResult)
@@ -655,8 +736,10 @@ namespace backend
return false;
}
- Result<bool> Ninja::buildTests(const std::string &projectGeneratedBinary, const SibsConfig &config, const char *savePath)
+ Result<bool> Ninja::buildTests(const std::string &projectGeneratedBinary, const SibsConfig &config, const _tinydir_char_t *savePath)
{
+ printf("build tests!\n");
+
if(testSourceDirs.empty())
return Result<bool>::Ok(true);
@@ -671,6 +754,7 @@ namespace backend
// TODO: Do not allow defining `main` in project.conf or as program argument to sibs (when sibs supports defines).
// It's ok if `define` fails. It could fail if `main` has already been replaced by other tests somehow.
parentProjConfigLib.define("main", "sibs_lib_ignore_main");
+ parentProjConfigLib.define("wmain", "sibs_lib_ignore_wmain");
return build(parentProjConfigLib, savePath, nullptr, nullptr);
}
@@ -686,7 +770,7 @@ namespace backend
projectConfFilePath += TINYDIR_STRING("/project.conf");
FileType projectConfFileType = getFileType(projectConfFilePath.c_str());
- SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative);
+ SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative, config.getOptimizationLevel());
if(projectConfFileType == FileType::REGULAR)
{
Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig);
@@ -695,7 +779,8 @@ namespace backend
}
backend::Ninja ninja;
- ninja.addDependency(projectGeneratedBinary);
+ if(!projectGeneratedBinary.empty())
+ ninja.addDependency(projectGeneratedBinary);
walkDirFilesRecursive(testSourceDirNative.c_str(), [&ninja, &sibsTestConfig](tinydir_file *file)
{
if (isSourceFile(file))
@@ -716,7 +801,7 @@ namespace backend
if (!buildFileResult)
return buildFileResult;
- Result<bool> buildResult = ninja.build(debugBuildPath.c_str());
+ Result<bool> buildResult = ninja.compile(debugBuildPath.c_str());
if (!buildResult)
return buildResult;
}
@@ -725,7 +810,7 @@ namespace backend
return Result<bool>::Ok(true);
}
- Result<bool> Ninja::build(const _tinydir_char_t *buildFilePath)
+ Result<bool> Ninja::compile(const _tinydir_char_t *buildFilePath)
{
FileString command = TINYDIR_STRING("ninja -C \"");
command += buildFilePath;