diff options
author | dec05eba <dec05eba@protonmail.com> | 2017-12-31 05:24:40 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2017-12-31 05:26:07 +0100 |
commit | 017ec45e94204f977dcd7b04c8035d48f230ded3 (patch) | |
tree | 7778ecc069f05fb527329f36876ed13a17a48ab3 /backend/ninja | |
parent | 7a5910121ab0ad2ea8a4a60e5b6599b7255e5a5e (diff) |
Sibs can now build itself on windows
Fixed several bugs.
The windows implementation IS QUICK AND DIRTY! It links
things as static even if you wish to link as dynamic etc.....
NEED TO FIX THIS !!!
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; |