aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-03-21 14:56:51 +0100
committerdec05eba <dec05eba@protonmail.com>2018-03-21 14:58:31 +0100
commit23117906c571714b0b55caf35cf9f876d1f9fa2e (patch)
tree21574306de1efb6eafd2af48f5188bf9e3550dd8 /backend
parentb44ff4ec7d2c2458aab04b5daf79134e5d284f6e (diff)
Add sub projects (should be used with git submodules)
Fix issue where static lib dependencies are not built correctly because their dynamic lib dependencies are not propagated to dependant project
Diffstat (limited to 'backend')
-rw-r--r--backend/BackendUtils.cpp85
-rw-r--r--backend/BackendUtils.hpp15
-rw-r--r--backend/ninja/Ninja.cpp88
-rw-r--r--backend/ninja/Ninja.hpp23
4 files changed, 181 insertions, 30 deletions
diff --git a/backend/BackendUtils.cpp b/backend/BackendUtils.cpp
new file mode 100644
index 0000000..68794f5
--- /dev/null
+++ b/backend/BackendUtils.cpp
@@ -0,0 +1,85 @@
+#include "BackendUtils.hpp"
+#include "../include/FileUtil.hpp"
+#include "ninja/Ninja.hpp"
+
+using namespace std;
+using namespace sibs;
+
+namespace backend
+{
+ 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[] = { TINYDIR_STRING("c"), TINYDIR_STRING("cc"), TINYDIR_STRING("cpp"), TINYDIR_STRING("cxx"), TINYDIR_STRING("c++") };
+ bool BackendUtils::isSourceFile(tinydir_file *file)
+ {
+ if(!file->is_reg)
+ return false;
+
+ for(const _tinydir_char_t *sourceFileExtension : sourceFileExtensions)
+ {
+ if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ void BackendUtils::collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const SibsConfig &sibsConfig)
+ {
+ walkDir(projectPath, [ninjaProject, &sibsConfig](tinydir_file *file)
+ {
+ FileString pathNative = file->path;
+ #if OS_FAMILY == OS_FAMILY_WINDOWS
+ replaceChar(pathNative, L'/', L'\\');
+ #endif
+ if(file->is_reg)
+ {
+ if (isSourceFile(file))
+ {
+ string filePathUtf8 = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size());
+ ninjaProject->addSourceFile(filePathUtf8.c_str());
+ }
+ else
+ {
+ //printf("Ignoring non-source file: %s\n", file->path + projectPath.size());
+ }
+ }
+ else
+ {
+ 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()))
+ {
+ FileString projectConfPath = file->path;
+ #if OS_FAMILY == OS_FAMILY_WINDOWS
+ projectConfPath += L'\\';
+ #else
+ projectConfPath += '/';
+ #endif
+ projectConfPath += TINYDIR_STRING("project.conf");
+
+ auto projectConfFileType = getFileType(projectConfPath.c_str());
+ if(projectConfFileType == FileType::REGULAR)
+ {
+ backend::Ninja *subProject = new backend::Ninja();
+
+ SibsConfig *subProjectConfig = new SibsConfig(sibsConfig.getCompiler(), file->path, sibsConfig.getOptimizationLevel(), false);
+ FileString subProjectBuildPath;
+ readSibsConfig(file->path, projectConfPath, *subProjectConfig, subProjectBuildPath);
+
+ collectSourceFiles(file->path, subProject, *subProjectConfig);
+ ninjaProject->addSubProject(subProject, subProjectConfig, move(subProjectBuildPath));
+ }
+ else
+ collectSourceFiles(file->path, ninjaProject, sibsConfig);
+ }
+ }
+ });
+ }
+}
diff --git a/backend/BackendUtils.hpp b/backend/BackendUtils.hpp
new file mode 100644
index 0000000..b2fe280
--- /dev/null
+++ b/backend/BackendUtils.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "../include/Conf.hpp"
+
+namespace backend
+{
+ class Ninja;
+
+ class BackendUtils
+ {
+ public:
+ static bool isSourceFile(tinydir_file *file);
+ static void collectSourceFiles(const _tinydir_char_t *projectPath, Ninja *ninjaProject, const sibs::SibsConfig &sibsConfig);
+ };
+}
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp
index fb081de..614d08c 100644
--- a/backend/ninja/Ninja.cpp
+++ b/backend/ninja/Ninja.cpp
@@ -1,4 +1,5 @@
#include <cstring>
+#include "../BackendUtils.hpp"
#include "Ninja.hpp"
#include "../../include/FileUtil.hpp"
#include "../../include/Exec.hpp"
@@ -237,6 +238,11 @@ namespace backend
if(!containsDependency(binaryFile))
binaryDependencies.emplace_back(binaryFile);
}
+
+ void Ninja::addSubProject(Ninja *subProject, SibsConfig *config, sibs::FileString &&buildPath)
+ {
+ subProjects.emplace_back(NinjaSubProject{ subProject, config, move(buildPath) });
+ }
const std::vector<std::string>& Ninja::getSourceFiles() const
{
@@ -318,7 +324,7 @@ namespace backend
else
{
const PkgConfigFlags &pkgConfigFlag = pkgConfigFlagsResult.unwrap();
- if (dynamicLinkerFlagCallback && !pkgConfigFlag.linkerFlags.empty())
+ if (!pkgConfigFlag.linkerFlags.empty())
dynamicLinkerFlagCallback(pkgConfigFlag.linkerFlags);
if(!pkgConfigFlag.cflags.empty())
cflagsCallbackFunc(pkgConfigFlag.cflags);
@@ -338,6 +344,26 @@ namespace backend
C,
CPP
};
+
+ Result<bool> Ninja::buildSubProjects(LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
+ {
+ for(auto &subProject : subProjects)
+ {
+ if(subProject.config->getPackageType() == PackageType::EXECUTABLE)
+ {
+ string errMsg = "The sub project ";
+ errMsg += toUtf8(subProject.buildPath);
+ errMsg += " is an executable. Only libraries can be sub projects";
+ return Result<bool>::Err(errMsg);
+ }
+
+ Result<bool> buildResult = subProject.subProject->build(*subProject.config, subProject.buildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
+ if(!buildResult)
+ return buildResult;
+ }
+
+ return Result<bool>::Ok(true);
+ }
Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback)
{
@@ -405,7 +431,7 @@ namespace backend
#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)
+ // Anyways it's required for static libraries
for (const string &binaryDependency : binaryDependencies)
{
allLinkerFlags += " ";
@@ -413,6 +439,7 @@ namespace backend
}
string staticLinkerFlags;
+ auto parentProjStaticLinkerFlagCallbackFunc = staticLinkerFlagCallbackFunc;
if (!staticLinkerFlagCallbackFunc || libraryType == LibraryType::DYNAMIC)
{
staticLinkerFlagCallbackFunc = [&staticLinkerFlags](const string &linkerFlag)
@@ -423,8 +450,8 @@ namespace backend
}
string dynamicLinkerFlags;
- // TODO: Do same for cmake
- if (!sourceFiles.empty())
+ auto parentProjDynamicLinkerFlagCallbackFunc = dynamicLinkerFlagCallback;
+ if(!dynamicLinkerFlagCallback || libraryType != LibraryType::STATIC)
{
dynamicLinkerFlagCallback = [&dynamicLinkerFlags](const string &linkerFlag)
{
@@ -439,6 +466,10 @@ namespace backend
cflags += " ";
cflags += dependencyCflags;
};
+
+ Result<bool> buildSubProjectResult = buildSubProjects(staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback);
+ if(!buildSubProjectResult)
+ return buildSubProjectResult;
Result<bool> linkerFlags = getLinkerFlags(config, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback, cflagsCallbackFunc);
if (linkerFlags.isErr())
@@ -739,13 +770,13 @@ namespace backend
objectNames.emplace_back(objectName);
}
- string projectGeneratedBinary;
+ string projectGeneratedBinaryFlags;
if (!sourceFiles.empty())
{
- projectGeneratedBinary = allLinkerFlags;
- projectGeneratedBinary += " \"";
+ string projectGeneratedBinary = "\"";
projectGeneratedBinary += savePathUtf8;
projectGeneratedBinary += "/";
+
switch (libraryType)
{
case LibraryType::EXECUTABLE:
@@ -776,7 +807,11 @@ namespace backend
result += allLinkerFlags;
}
result += "\n\n";
+
projectGeneratedBinary += config.getPackageName();
+ #if OS_FAMILY == OS_FAMILY_WINDOWS
+ projectGeneratedBinary += ".exe";
+ #endif
break;
}
case LibraryType::STATIC:
@@ -804,6 +839,11 @@ namespace backend
break;
}
}
+
+ projectGeneratedBinary += "\"";
+ if(parentProjStaticLinkerFlagCallbackFunc)
+ parentProjStaticLinkerFlagCallbackFunc(projectGeneratedBinary);
+
break;
}
case LibraryType::DYNAMIC:
@@ -841,13 +881,19 @@ namespace backend
//result += " '-Wl,--no-whole-archive'";
}
result += "\n\n";
+
+ projectGeneratedBinary += "\"";
+ if(parentProjDynamicLinkerFlagCallbackFunc)
+ parentProjDynamicLinkerFlagCallbackFunc(projectGeneratedBinary);
+
break;
}
default:
assert(false);
return Result<bool>::Err("Unexpected error");
}
- projectGeneratedBinary += "\"";
+
+ projectGeneratedBinaryFlags = allLinkerFlags + " " + projectGeneratedBinary;
Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size()));
if (fileOverwriteResult.isErr())
@@ -863,30 +909,14 @@ 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(projectGeneratedBinary, config, savePath, dependencyExportIncludeDirs);
+ Result<bool> buildTestResult = buildTests(projectGeneratedBinaryFlags, config, savePath, dependencyExportIncludeDirs);
if(!buildTestResult)
return buildTestResult;
return Result<bool>::Ok(true);
}
- // TODO: Add "c++" file extension, seems to be used in some places?
- const _tinydir_char_t *sourceFileExtensions[] = { TINYDIR_STRING("c"), TINYDIR_STRING("cc"), TINYDIR_STRING("cpp"), TINYDIR_STRING("cxx") };
- bool isSourceFile(tinydir_file *file)
- {
- if(!file->is_reg)
- return false;
-
- for(const _tinydir_char_t *sourceFileExtension : sourceFileExtensions)
- {
- if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
- return true;
- }
-
- return false;
- }
-
- Result<bool> Ninja::buildTests(const std::string &projectGeneratedBinary, const SibsConfig &config, const _tinydir_char_t *savePath, const string &parentDependencyExportIncludeDirs)
+ Result<bool> Ninja::buildTests(const std::string &projectGeneratedBinaryFlags, const SibsConfig &config, const _tinydir_char_t *savePath, const string &parentDependencyExportIncludeDirs)
{
if(testSourceDirs.empty() || !config.shouldBuildTests())
return Result<bool>::Ok(true);
@@ -940,12 +970,12 @@ namespace backend
backend::Ninja ninja;
ninja.addGlobalIncludeDirs(parentExportIncludeDirs);
- if(!projectGeneratedBinary.empty())
- ninja.addDependency(projectGeneratedBinary);
+ 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 (isSourceFile(file))
+ if (backend::BackendUtils::isSourceFile(file))
{
string filePathUtf8 = toUtf8(file->path + sibsTestConfig.getProjectPath().size() + 1);
ninja.addSourceFile(filePathUtf8.c_str());
diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp
index 8411137..7bbff51 100644
--- a/backend/ninja/Ninja.hpp
+++ b/backend/ninja/Ninja.hpp
@@ -11,6 +11,24 @@
namespace backend
{
+ class Ninja;
+
+ struct NinjaSubProject
+ {
+ Ninja *subProject;
+ sibs::SibsConfig *config;
+ sibs::FileString buildPath;
+
+ NinjaSubProject() : subProject(nullptr), config(nullptr) {}
+ NinjaSubProject(Ninja *_subProject, sibs::SibsConfig *_config, sibs::FileString &&_buildPath) :
+ subProject(_subProject),
+ config(_config),
+ buildPath(move(_buildPath))
+ {
+
+ }
+ };
+
class Ninja
{
public:
@@ -27,10 +45,12 @@ namespace backend
void addSourceFile(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;
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> buildTests(const std::string &projectGeneratedBinary, const sibs::SibsConfig &config, const _tinydir_char_t *savePath, const std::string &parentDependencyExportIncludeDirs);
+ sibs::Result<bool> buildSubProjects(sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback);
+ sibs::Result<bool> buildTests(const std::string &projectGeneratedBinaryFlags, const sibs::SibsConfig &config, const _tinydir_char_t *savePath, const std::string &parentDependencyExportIncludeDirs);
bool containsSourceFile(const std::string &filepath) const;
bool containsTestSourceDir(const std::string &dir) const;
bool containsDependency(const std::string &dependency) const;
@@ -41,6 +61,7 @@ namespace backend
std::vector<std::string> sourceFiles;
std::vector<std::string> testSourceDirs;
std::vector<std::string> binaryDependencies;
+ std::vector<NinjaSubProject> subProjects;
};
}