diff options
Diffstat (limited to 'backend/ninja')
-rw-r--r-- | backend/ninja/Ninja.cpp | 375 | ||||
-rw-r--r-- | backend/ninja/Ninja.hpp | 8 |
2 files changed, 234 insertions, 149 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; diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index 36a57ff..eeea1be 100644 --- a/backend/ninja/Ninja.hpp +++ b/backend/ninja/Ninja.hpp @@ -28,14 +28,14 @@ namespace backend void addTestSourceDir(const char *dir); void addDependency(const std::string &binaryFile); 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::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 char *savePath); + sibs::Result<bool> buildTests(const std::string &projectGeneratedBinary, const sibs::SibsConfig &config, const _tinydir_char_t *savePath); bool containsSourceFile(const std::string &filepath) const; bool containsTestSourceDir(const std::string &dir) const; bool containsDependency(const std::string &dependency) const; - sibs::Result<bool> getLinkerFlags(const sibs::SibsConfig &config, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const; - sibs::Result<bool> build(const _tinydir_char_t *buildFilePath); + sibs::Result<bool> getLinkerFlags(const sibs::SibsConfig &config, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback) const; + sibs::Result<bool> compile(const _tinydir_char_t *buildFilePath); private: std::vector<std::string> sourceFiles; std::vector<std::string> testSourceDirs; |