From 23117906c571714b0b55caf35cf9f876d1f9fa2e Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 21 Mar 2018 14:56:51 +0100 Subject: 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 --- backend/ninja/Ninja.cpp | 88 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 29 deletions(-) (limited to 'backend/ninja/Ninja.cpp') 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 +#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& 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 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::Err(errMsg); + } + + Result buildResult = subProject.subProject->build(*subProject.config, subProject.buildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback); + if(!buildResult) + return buildResult; + } + + return Result::Ok(true); + } Result 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 buildSubProjectResult = buildSubProjects(staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback, globalIncludeDirCallback); + if(!buildSubProjectResult) + return buildSubProjectResult; Result 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::Err("Unexpected error"); } - projectGeneratedBinary += "\""; + + projectGeneratedBinaryFlags = allLinkerFlags + " " + projectGeneratedBinary; Result 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 buildTestResult = buildTests(projectGeneratedBinary, config, savePath, dependencyExportIncludeDirs); + Result buildTestResult = buildTests(projectGeneratedBinaryFlags, config, savePath, dependencyExportIncludeDirs); if(!buildTestResult) return buildTestResult; return Result::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 Ninja::buildTests(const std::string &projectGeneratedBinary, const SibsConfig &config, const _tinydir_char_t *savePath, const string &parentDependencyExportIncludeDirs) + Result Ninja::buildTests(const std::string &projectGeneratedBinaryFlags, const SibsConfig &config, const _tinydir_char_t *savePath, const string &parentDependencyExportIncludeDirs) { if(testSourceDirs.empty() || !config.shouldBuildTests()) return Result::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()); -- cgit v1.2.3