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 --- .vscode/launch.json | 2 +- CMakeLists.txt | 1 + backend/BackendUtils.cpp | 85 ++++++++++++++++++++++++++++++++++++ backend/BackendUtils.hpp | 15 +++++++ backend/ninja/Ninja.cpp | 88 +++++++++++++++++++++++++------------- backend/ninja/Ninja.hpp | 23 +++++++++- include/Conf.hpp | 4 +- src/CmakeModule.cpp | 13 +++--- src/Conf.cpp | 57 +++++++++++++++++++++++-- src/GlobalLib.cpp | 109 +---------------------------------------------- src/main.cpp | 91 +++++++++++---------------------------- 11 files changed, 275 insertions(+), 213 deletions(-) create mode 100644 backend/BackendUtils.cpp create mode 100644 backend/BackendUtils.hpp diff --git a/.vscode/launch.json b/.vscode/launch.json index dc20432..e91a145 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "target": "./sibs-build/debug/sibs", "cwd": "${workspaceRoot}", - "arguments": "build /home/dec05eba/git/gen-sfml-ui" + "arguments": "build /home/dec05eba/git/sfml-ui-flat/depends/gen-sfml-ui" } ] } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e1af36..5324cf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_CXX_STANDARD 14) set(SOURCE_FILES external/xxhash.c backend/ninja/Ninja.cpp + backend/BackendUtils.cpp src/main.cpp src/FileUtil.cpp src/Conf.cpp 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 +#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()); 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& getSourceFiles() const; sibs::Result 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 buildTests(const std::string &projectGeneratedBinary, const sibs::SibsConfig &config, const _tinydir_char_t *savePath, const std::string &parentDependencyExportIncludeDirs); + sibs::Result buildSubProjects(sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback); + sibs::Result 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 sourceFiles; std::vector testSourceDirs; std::vector binaryDependencies; + std::vector subProjects; }; } diff --git a/include/Conf.hpp b/include/Conf.hpp index 13245c1..6a6d07c 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -99,7 +99,7 @@ namespace sibs class Config { public: - static Result readFromFile(const _tinydir_char_t *filepath, const ConfigCallback &callback); + static Result readFromFile(const _tinydir_char_t *filepath, ConfigCallback &callback); }; enum OptimizationLevel @@ -449,6 +449,8 @@ namespace sibs void processField(StringView name, const ConfigValue &value) override; void finished() override; }; + + void readSibsConfig(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig, FileString &buildPath); } #endif //SIBS_CONF_HPP diff --git a/src/CmakeModule.cpp b/src/CmakeModule.cpp index 990bf36..eeb8a9c 100644 --- a/src/CmakeModule.cpp +++ b/src/CmakeModule.cpp @@ -53,12 +53,15 @@ namespace sibs } string dynamicLinkerFlags; - // TODO: If project contains no source files, then we shouldn't override this function - dynamicLinkerFlagCallbackFunc = [&dynamicLinkerFlags](const string &linkerFlag) + // TODO: If project contains no source files, then we shouldn't override this function... why? + if(!dynamicLinkerFlagCallbackFunc || config.getPackageType() != PackageType::STATIC) { - dynamicLinkerFlags += " "; - dynamicLinkerFlags += linkerFlag; - }; + dynamicLinkerFlagCallbackFunc = [&dynamicLinkerFlags](const string &linkerFlag) + { + dynamicLinkerFlags += " "; + dynamicLinkerFlags += linkerFlag; + }; + } // TODO: Create a cmake module that contains library/include path for the dependencies (https://cmake.org/Wiki/CMake:How_To_Find_Libraries). // Modify the project CMakeLists.txt and add: list(APPEND CMAKE_MODULE_PATH "PathToDependenciesCmakeModulesGoesHere"). diff --git a/src/Conf.cpp b/src/Conf.cpp index 41cc157..941bdd7 100644 --- a/src/Conf.cpp +++ b/src/Conf.cpp @@ -1,10 +1,17 @@ #include "../include/Conf.hpp" #include "../include/types.hpp" #include "../external/utf8/unchecked.h" +#include using namespace std; using u8string = utf8::unchecked::iterator; +#if OS_FAMILY == OS_FAMILY_POSIX +#define ferr std::cerr +#else +#define ferr std::wcerr +#endif + namespace sibs { static const string EMPTY_STRING = ""; @@ -196,11 +203,11 @@ namespace sibs class Parser { public: - static Result parse(const char *code, const ConfigCallback &callback) + static Result parse(const char *code, ConfigCallback &callback) { try { - Parser parser(code, (ConfigCallback*)&callback); + Parser parser(code, &callback); parser.parse(); return Result::Ok(true); } @@ -438,7 +445,7 @@ namespace sibs bool objectDefined; }; - Result Config::readFromFile(const _tinydir_char_t *filepath, const ConfigCallback &callback) + Result Config::readFromFile(const _tinydir_char_t *filepath, ConfigCallback &callback) { Result fileContentResult = getFileContent(filepath); if(fileContentResult.isErr()) @@ -463,6 +470,50 @@ namespace sibs } return false; } + + void readSibsConfig(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig, FileString &buildPath) + { + Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); + if(result.isErr()) + { + ferr << "Failed to read config: " << toFileString(result.getErrMsg()) << endl; + exit(6); + } + + if(sibsConfig.getPackageName().empty()) + { + ferr << "project.conf is missing required field package.name" << endl; + exit(10); + } + + if (!containsPlatform(sibsConfig.getPlatforms(), SYSTEM_PLATFORM)) + { + string errMsg = "The project "; + errMsg += sibsConfig.getPackageName(); + errMsg += " does not support your platform ("; + errMsg += asString(SYSTEM_PLATFORM); + errMsg += ")"; + cerr << errMsg << endl; + exit(11); + } + + buildPath = projectPath + TINYDIR_STRING("/sibs-build/"); + switch(sibsConfig.getOptimizationLevel()) + { + case OPT_LEV_DEBUG: + buildPath += TINYDIR_STRING("debug"); + break; + case OPT_LEV_RELEASE: + buildPath += TINYDIR_STRING("release"); + break; + } + + if(sibsConfig.shouldBuildTests() && sibsConfig.getTestPath().empty()) + { + printf("Project is missing package.tests config. No tests to build\n"); + exit(0); + } + } const char* asString(Platform platform) { diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp index eee37dd..8618cfd 100644 --- a/src/GlobalLib.cpp +++ b/src/GlobalLib.cpp @@ -1,5 +1,6 @@ #include "../include/GlobalLib.hpp" #include "../include/FileUtil.hpp" +#include "../backend/BackendUtils.hpp" #include "../backend/ninja/Ninja.hpp" #include "../include/Conf.hpp" #include "../include/curl.hpp" @@ -46,26 +47,6 @@ namespace sibs } } } - - 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; - } - - bool isPathSubPathOf(const _tinydir_char_t *path, const FileString &subPathOf) - { - return _tinydir_strncmp(path, subPathOf.c_str(), subPathOf.size()) == 0; - } Result GlobalLib::getLibs(const std::vector &libs, const SibsConfig &parentConfig, const FileString &globalLibRootDir, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) { @@ -284,93 +265,7 @@ namespace sibs else { backend::Ninja ninja; - // TODO: Use same source file finder as in main.cpp - FileWalkCallbackFunc collectSourceFiles = [&ninja, &sibsConfig, &collectSourceFiles](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 fileNameNative = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size() + 1); - ninja.addSourceFile(fileNameNative.c_str()); - } - else - { - //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); - } - } - else - { - // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests... - // OR I believe there is no reason to run tests in dependencies. The main projects tests should cover that? - // But you might want to know exactly which dependency is causing issue and which part of it... - if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) - { - string filePathUtf8 = toUtf8(pathNative.c_str()); - ninja.addTestSourceDir(filePathUtf8.c_str()); - } - else if(!directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs())) - walkDir(file->path, collectSourceFiles); - } - }; - walkDir(packageDir.c_str(), collectSourceFiles); - - if (!ninja.getSourceFiles().empty()) - { - string libPath = toUtf8(buildPath); - switch (sibsConfig.getCompiler()) - { - case Compiler::GCC: - { - libPath += "/lib"; - libPath += dependencyName; - if (sibsConfig.getPackageType() == PackageType::STATIC) - { - libPath += ".a"; - string libPathCmd = "'"; - libPathCmd += libPath; - libPathCmd += "'"; - staticLinkerFlagCallbackFunc(libPathCmd); - } - else - { - libPath += ".so"; - string libPathCmd = "'"; - libPathCmd += libPath; - libPathCmd += "'"; - dynamicLinkerFlagCallbackFunc(libPathCmd); - } - break; - } - case Compiler::MSVC: - { - libPath += "/"; - libPath += dependencyName; - if (sibsConfig.getPackageType() == PackageType::STATIC) - { - libPath += ".lib"; - string libPathCmd = "\""; - libPathCmd += libPath; - libPathCmd += "\""; - staticLinkerFlagCallbackFunc(libPathCmd); - } - else - { - libPath += ".lib"; - string libPathCmd = "\""; - libPathCmd += libPath; - libPathCmd += "\""; - dynamicLinkerFlagCallbackFunc(libPathCmd); - } - break; - } - } - } - + backend::BackendUtils::collectSourceFiles(packageDir.c_str(), &ninja, sibsConfig); return ninja.build(sibsConfig, buildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc, globalIncludeDirCallback); } } diff --git a/src/main.cpp b/src/main.cpp index b9d6c1b..910380a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "../include/Conf.hpp" #include "../include/Exec.hpp" #include "../include/CmakeModule.hpp" +#include "../backend/BackendUtils.hpp" #include "../backend/ninja/Ninja.hpp" using namespace std; @@ -42,11 +43,6 @@ using namespace std::chrono; // Might need to make it possible to define variables if a dependency exists (or doesn't exist) because the code might have // preprocessor like: USE_LIBSODIUM or NO_LIBSODIUM. -// TODO: Set c++ standard to c++11 and c standard to c98 - for consistency across different compilers and compiler version. -// It should be possible to override language version in project.conf - -// TODO: If file extension is common c extension (.c, ...) then remove cast checking (for example using malloc without casting result to result type) - // TODO: When building a sibs project, add a hardlink in ~/.sibs/lib to it. This allows us to have dependency to a project that we can modify // without having to commit & push to remote @@ -199,48 +195,17 @@ bool isPathSubPathOf(const FileString &path, const FileString &subPathOf) return _tinydir_strncmp(path.c_str(), subPathOf.c_str(), subPathOf.size()) == 0; } -int buildProject(const FileString &projectPath, const FileString &projectConfFilePath, const SibsConfig &sibsConfig) +int buildProject(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig) { - Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); - if(result.isErr()) - { - ferr << "Failed to read config: " << toFileString(result.getErrMsg()) << endl; - exit(6); - } - - if(sibsConfig.getPackageName().empty()) - { - ferr << "project.conf is missing required field package.name" << endl; - exit(10); - } - - if (!containsPlatform(sibsConfig.getPlatforms(), SYSTEM_PLATFORM)) - { - string errMsg = "The project "; - errMsg += sibsConfig.getPackageName(); - errMsg += " does not support your platform ("; - errMsg += asString(SYSTEM_PLATFORM); - errMsg += ")"; - cerr << errMsg << endl; - exit(11); - } - - FileString buildPath = projectPath + TINYDIR_STRING("/sibs-build/"); - switch(sibsConfig.getOptimizationLevel()) - { - case OPT_LEV_DEBUG: - buildPath += TINYDIR_STRING("debug"); - break; - case OPT_LEV_RELEASE: - buildPath += TINYDIR_STRING("release"); - break; - } + FileString buildPath; + readSibsConfig(projectPath, projectConfFilePath, sibsConfig, buildPath); auto startTime = high_resolution_clock::now(); if(sibsConfig.shouldUseCmake()) { auto dummyCallback = [](const string&){}; + // TODO: Add test and sub projects CmakeModule cmakeModule; Result cmakeCompileResult = cmakeModule.compile(sibsConfig, buildPath, dummyCallback, dummyCallback, dummyCallback); if(!cmakeCompileResult) @@ -252,42 +217,36 @@ int buildProject(const FileString &projectPath, const FileString &projectConfFil else { backend::Ninja ninja; - FileWalkCallbackFunc collectSourceFiles = [&ninja, &sibsConfig, &collectSourceFiles](tinydir_file *file) + // TODO: Do same for cmake + switch (sibsConfig.getOptimizationLevel()) { - FileString pathNative = file->path; - #if OS_FAMILY == OS_FAMILY_WINDOWS - replaceChar(pathNative, L'/', L'\\'); - #endif - if(file->is_reg) + case OPT_LEV_DEBUG: { - if (isSourceFile(file)) + // TODO: Check if this dependency is static or dynamic and decide which lib path to use from that + for(const string &staticLib : sibsConfig.getDebugStaticLibs()) { - string filePathUtf8 = toUtf8(pathNative.c_str() + sibsConfig.getProjectPath().size()); - ninja.addSourceFile(filePathUtf8.c_str()); - } - else - { - //printf("Ignoring non-source file: %s\n", file->path + projectPath.size()); + string staticLibCmd = "\""; + staticLibCmd += staticLib; + staticLibCmd += "\""; + ninja.addDependency(staticLibCmd); } + break; } - else + case OPT_LEV_RELEASE: { - if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) + // TODO: Check if this dependency is static or dynamic and decide which lib path to use from that + for (const string &staticLib : sibsConfig.getReleaseStaticLibs()) { - string filePathUtf8 = toUtf8(pathNative.c_str()); - ninja.addTestSourceDir(filePathUtf8.c_str()); + string staticLibCmd = "\""; + staticLibCmd += staticLib; + staticLibCmd += "\""; + ninja.addDependency(staticLibCmd); } - else if(!directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs())) - walkDir(file->path, collectSourceFiles); + break; } - }; - walkDir(projectPath.c_str(), collectSourceFiles); - - if(sibsConfig.shouldBuildTests() && sibsConfig.getTestPath().empty()) - { - printf("Project is missing package.tests config. No tests to build\n"); - exit(0); } + + backend::BackendUtils::collectSourceFiles(projectPath.c_str(), &ninja, sibsConfig); Result buildFileResult = ninja.build(sibsConfig, buildPath.c_str()); if(buildFileResult.isErr()) -- cgit v1.2.3