diff options
author | dec05eba <dec05eba@protonmail.com> | 2018-03-21 14:56:51 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2018-03-21 14:58:31 +0100 |
commit | 23117906c571714b0b55caf35cf9f876d1f9fa2e (patch) | |
tree | 21574306de1efb6eafd2af48f5188bf9e3550dd8 /backend | |
parent | b44ff4ec7d2c2458aab04b5daf79134e5d284f6e (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.cpp | 85 | ||||
-rw-r--r-- | backend/BackendUtils.hpp | 15 | ||||
-rw-r--r-- | backend/ninja/Ninja.cpp | 88 | ||||
-rw-r--r-- | backend/ninja/Ninja.hpp | 23 |
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; }; } |