diff options
Diffstat (limited to 'backend/ninja')
-rw-r--r-- | backend/ninja/Ninja.cpp | 317 | ||||
-rw-r--r-- | backend/ninja/Ninja.hpp | 4 |
2 files changed, 262 insertions, 59 deletions
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index d9b4eed..49bda4f 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -8,6 +8,12 @@ using namespace std; using namespace sibs; +#if OS_FAMILY == OS_FAMILY_POSIX +#define nprintf printf +#else +#define nprintf wprintf +#endif + namespace backend { string join(const vector<string> &list, const char *joinStr) @@ -38,7 +44,7 @@ namespace backend return result; } - + bool endsWith(const string &str, const string &endWithStr) { if(endWithStr.size() > str.size()) @@ -46,7 +52,7 @@ namespace backend else return strncmp(&str[str.size() - endWithStr.size()], &endWithStr[0], endWithStr.size()) == 0; } - + Ninja::LibraryType getNinjaLibraryType(PackageType packageType) { switch(packageType) @@ -61,6 +67,78 @@ namespace backend } } + string getIncludeOptionFlag(Compiler compiler, const string &filepath) + { + string result; + switch (compiler) + { + case Compiler::GCC: + { + result = "'-I"; + result += filepath; + result += "'"; + break; + } + case Compiler::MSVC: + { + result = "/I \""; + result += filepath; + result += "\""; + break; + } + } + return result; + } + + string getCompileWithoutLinkingFlag(Compiler compiler) + { + string result; + switch (compiler) + { + case Compiler::GCC: + { + result = "-c"; + break; + } + case Compiler::MSVC: + { + result = "/c"; + break; + } + } + return result; + } + + string getObjectFileNameFlag(Compiler compiler, const string &objectFileName) + { + string result; + switch (compiler) + { + case Compiler::GCC: + { + result = "-o "; + result += objectFileName; + break; + } + case Compiler::MSVC: + { + result = "/Fo"; + result += objectFileName; + break; + } + } + return result; + } + + const char* getObjectFileExtension(Compiler compiler) + { + switch (compiler) + { + case Compiler::GCC: return ".o"; + case Compiler::MSVC: return ".obj"; + } + } + Ninja::Ninja() { @@ -127,6 +205,7 @@ namespace backend return false; } +#if OS_FAMILY == OS_FAMILY_POSIX Result<bool> validatePkgConfigPackageVersionExists(const Dependency &dependency) { Result<bool> dependencyValidationResult = PkgConfig::validatePackageExists(dependency.name); @@ -139,7 +218,7 @@ namespace backend return Result<bool>::Ok(true); } - +#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 @@ -147,14 +226,18 @@ namespace backend const vector<Dependency> &dependencies = config.getDependencies(); if(dependencies.empty()) return Result<bool>::Ok(true); - string globalLibDir = getHomeDir(); - globalLibDir += "/.sibs/lib"; + Result<FileString> globalLibDirResult = getHomeDir(); + if (!globalLibDirResult) + return Result<bool>::Err(globalLibDirResult); + FileString globalLibDir = globalLibDirResult.unwrap(); + globalLibDir += TINYDIR_STRING("/.sibs/lib"); Result<bool> createGlobalLibDirResult = createDirectoryRecursive(globalLibDir.c_str()); if(createGlobalLibDirResult.isErr()) return createGlobalLibDirResult; - vector<Dependency> pkgConfigDependencies; vector<Dependency> globalLibDependencies; +#if OS_FAMILY == OS_FAMILY_POSIX + vector<Dependency> pkgConfigDependencies; for(const Dependency &dependency : dependencies) { Result<bool> pkgConfigDependencyValidation = validatePkgConfigPackageVersionExists(dependency); @@ -169,11 +252,11 @@ namespace backend } Result<string> pkgConfigLinkerFlagsResult = PkgConfig::getDynamicLibsLinkerFlags(pkgConfigDependencies); - if(pkgConfigLinkerFlagsResult.isErr()) + if (pkgConfigLinkerFlagsResult.isErr()) { printf("%s, using global lib...\n", pkgConfigLinkerFlagsResult.getErrMsg().c_str()); globalLibDependencies.reserve(globalLibDependencies.size() + pkgConfigDependencies.size()); - for(const Dependency &pkgConfigDependency : pkgConfigDependencies) + for (const Dependency &pkgConfigDependency : pkgConfigDependencies) { globalLibDependencies.push_back(pkgConfigDependency); } @@ -181,9 +264,15 @@ namespace backend } else { - if(!pkgConfigLinkerFlagsResult.unwrap().empty()) + if (!pkgConfigLinkerFlagsResult.unwrap().empty()) dynamicLinkerFlagCallback(pkgConfigLinkerFlagsResult.unwrap()); } +#else + for (const Dependency &dependency : dependencies) + { + globalLibDependencies.push_back(dependency); + } +#endif for(const Dependency &globalLibDependency : globalLibDependencies) { @@ -221,7 +310,7 @@ namespace backend return Result<bool>::Ok(true); } - Result<bool> Ninja::build(const SibsConfig &config, const char *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) + Result<bool> Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) { // TODO: Do not quit here if no source files are provided. The source-less project could have dependencies if(sourceFiles.empty()) @@ -230,29 +319,35 @@ namespace backend Result<bool> createBuildDirResult = createDirectoryRecursive(savePath); if(createBuildDirResult.isErr()) return createBuildDirResult; - + LibraryType libraryType = getNinjaLibraryType(config.getPackageType()); - string ninjaBuildFilePath = savePath; - ninjaBuildFilePath += "/build.ninja"; + string savePathUtf8 = toUtf8(savePath); + + FileString ninjaBuildFilePath = savePath; + ninjaBuildFilePath += TINYDIR_STRING("/build.ninja"); string result; result.reserve(16384); - string globalIncDir = getHomeDir(); - globalIncDir += "/.sibs/lib"; + Result<FileString> globalIncDirResult = getHomeDir(); + if (!globalIncDirResult) + return Result<bool>::Err(globalIncDirResult); - result += "globalIncDir = '-I"; - result += globalIncDir; - result += "'"; + FileString globalIncDir = globalIncDirResult.unwrap(); + globalIncDir += TINYDIR_STRING("/.sibs/lib"); + + result += "globalIncDir = "; + result += getIncludeOptionFlag(config.getCompiler(), toUtf8(globalIncDir)); for(const auto &includeDir : config.getIncludeDirs()) { - result += " '-I../../"; - result += includeDir; - result += "'"; + string includeDirRelative = "../../"; + includeDirRelative += includeDir; + result += " "; + result += getIncludeOptionFlag(config.getCompiler(), includeDirRelative); } result += "\n\n"; - + string defines; for(const auto &definePair : config.getDefines()) { @@ -262,25 +357,54 @@ namespace backend defines += definePair.second; defines += "'"; } - + if(!defines.empty()) printf("Custom define: %s\n", defines.c_str()); + string compilerName; + switch (config.getCompiler()) + { + case Compiler::GCC: + compilerName = "ccache c++"; + break; + case Compiler::MSVC: + compilerName = "cl.exe"; + break; + } + string buildJob; switch(libraryType) { case LibraryType::EXECUTABLE: { - result += "rule cpp_COMPILER\n"; - result += " command = ccache c++ $ARGS -c $in -o $out\n\n"; + switch (config.getCompiler()) + { + case Compiler::GCC: + { + result += "rule cpp_COMPILER\n"; + result += " command = ccache c++ $ARGS -c $in -o $out\n\n"; + + result += "rule cpp_BUILD_EXEC\n"; + result += " command = ccache c++ $ARGS -o $out $in $LINK_ARGS $aliasing\n\n"; + break; + } + case Compiler::MSVC: + { + result += "rule cpp_COMPILER\n"; + result += " command = cl.exe $ARGS /c $in /Fo$out\n\n"; + + result += "rule cpp_BUILD_EXEC\n"; + result += " command = cl.exe $ARGS $in /Fe$out $LINK_ARGS\n\n"; + break; + } + } - result += "rule cpp_BUILD_EXEC\n"; - result += " command = ccache c++ $ARGS -o $out $in $LINK_ARGS $aliasing\n\n"; buildJob = "cpp_BUILD_EXEC"; break; } case LibraryType::STATIC: { + // TODO: Write equivalent code for msvc result += "rule cpp_COMPILER\n"; result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n"; @@ -294,12 +418,32 @@ namespace backend } case LibraryType::DYNAMIC: { - result += "rule cpp_COMPILER\n"; - result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n"; + switch (config.getCompiler()) + { + case Compiler::GCC: + { + result += "rule cpp_COMPILER\n"; + result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n"; + + // --whole-archive + result += "rule cpp_BUILD_DYNAMIC\n"; + result += " command = ccache c++ $in -shared -o $out $LINK_ARGS $aliasing\n\n"; + break; + } + case Compiler::MSVC: + { + result += "rule cpp_COMPILER\n"; + result += " command = cl.exe $ARGS /c $in /Fo$out\n\n"; + + //result += "rule cpp_BUILD_DYNAMIC\n"; + //result += " command = cl.exe /LD $in /Fe$out $LINK_ARGS\n\n"; + + result += "rule cpp_BUILD_DYNAMIC\n"; + result += " command = lib.exe /OUT:$out $in\n\n"; + break; + } + } - // --whole-archive - result += "rule cpp_BUILD_DYNAMIC\n"; - result += " command = ccache c++ $in -shared -o $out $LINK_ARGS $aliasing\n\n"; buildJob = "cpp_BUILD_DYNAMIC"; break; } @@ -328,21 +472,28 @@ namespace backend sourceFileLanguage = "c"; //string sourceFileEncoded = sourceFile; //replace(sourceFileEncoded, '/', '@'); - string objectName = config.getPackageName() + "@exe/" + sourceFile + ".o"; + string objectName = config.getPackageName() + "@exe/" + sourceFile; + objectName += getObjectFileExtension(config.getCompiler()); result += "build "; result += objectName; result += ": cpp_COMPILER ../../"; result += sourceFile; result += "\n"; - result += " ARGS = $globalIncDir '-I" + config.getPackageName() + "@exe' '-I..' "; + result += " ARGS = $globalIncDir "; if(!defines.empty()) result += defines; - result += " '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' " + optimizationFlags + " '-g'\n\n"; + 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'"; + 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) @@ -374,7 +525,7 @@ namespace backend string projectGeneratedBinary = allLinkerFlags; projectGeneratedBinary += " '"; - projectGeneratedBinary += savePath; + projectGeneratedBinary += savePathUtf8; projectGeneratedBinary += "/"; switch(libraryType) { @@ -385,7 +536,20 @@ namespace backend result += ": " + buildJob + " "; result += join(objectNames, " "); result += "\n"; - result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' "; + switch (config.getCompiler()) + { + case Compiler::GCC: + { + result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' "; + break; + } + case Compiler::MSVC: + { + result += " LINK_ARGS = "; + break; + } + } + if(!allLinkerFlags.empty()) { result += allLinkerFlags; @@ -401,24 +565,56 @@ namespace backend result += ": " + buildJob + " "; result += join(objectNames, " "); result += "\n\n"; - projectGeneratedBinary += config.getPackageName() + ".a"; + + switch (config.getCompiler()) + { + case Compiler::GCC: + { + projectGeneratedBinary += config.getPackageName() + ".a"; + break; + } + case Compiler::MSVC: + { + projectGeneratedBinary += config.getPackageName() + ".lib"; + break; + } + } break; } case LibraryType::DYNAMIC: { - result += "build lib"; - result += config.getPackageName(); - result += ".so: " + buildJob + " "; - result += join(objectNames, " "); - result += "\n"; - result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' "; + switch (config.getCompiler()) + { + 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"; + result += " LINK_ARGS = "; + projectGeneratedBinary += config.getPackageName() + ".lib"; + break; + } + } + if(!allLinkerFlags.empty()) { result += allLinkerFlags; //result += " '-Wl,--no-whole-archive'"; } result += "\n\n"; - projectGeneratedBinary += "lib" + config.getPackageName() + ".so"; break; } default: @@ -431,7 +627,7 @@ namespace backend if(fileOverwriteResult.isErr()) return fileOverwriteResult; - printf("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) @@ -444,13 +640,13 @@ namespace backend return Result<bool>::Ok(true); } - const char *sourceFileExtensions[] = { "c", "cc", "cpp", "cxx" }; + 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 char *sourceFileExtension : sourceFileExtensions) + for(const _tinydir_char_t *sourceFileExtension : sourceFileExtensions) { if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0) return true; @@ -480,11 +676,17 @@ namespace backend for(const string &testSourceDir : testSourceDirs) { - string projectConfFilePath = testSourceDir; - projectConfFilePath += "/project.conf"; +#if OS_FAMILY == OS_FAMILY_POSIX + FileString testSourceDirNative = testSourceDir; + FileString projectConfFilePath = testSourceDir; +#else + FileString testSourceDirNative = utf8To16(testSourceDir); + FileString projectConfFilePath = testSourceDirNative; +#endif + projectConfFilePath += TINYDIR_STRING("/project.conf"); FileType projectConfFileType = getFileType(projectConfFilePath.c_str()); - SibsTestConfig sibsTestConfig(testSourceDir); + SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative); if(projectConfFileType == FileType::REGULAR) { Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig); @@ -494,11 +696,12 @@ namespace backend backend::Ninja ninja; ninja.addDependency(projectGeneratedBinary); - walkDirFilesRecursive(testSourceDir.c_str(), [&ninja, &sibsTestConfig](tinydir_file *file) + walkDirFilesRecursive(testSourceDirNative.c_str(), [&ninja, &sibsTestConfig](tinydir_file *file) { if (isSourceFile(file)) { - ninja.addSourceFile(file->path + sibsTestConfig.getProjectPath().size() + 1); + string filePathUtf8 = toUtf8(file->path + sibsTestConfig.getProjectPath().size() + 1); + ninja.addSourceFile(filePathUtf8.c_str()); } else { @@ -508,7 +711,7 @@ namespace backend if(!ninja.getSourceFiles().empty()) { - string debugBuildPath = testSourceDir + "/sibs-build/debug"; + FileString debugBuildPath = testSourceDirNative + TINYDIR_STRING("/sibs-build/debug"); Result<bool> buildFileResult = ninja.build(sibsTestConfig, debugBuildPath.c_str()); if (!buildFileResult) return buildFileResult; @@ -522,11 +725,11 @@ namespace backend return Result<bool>::Ok(true); } - Result<bool> Ninja::build(const char *buildFilePath) + Result<bool> Ninja::build(const _tinydir_char_t *buildFilePath) { - string command = "ninja -C '"; + FileString command = TINYDIR_STRING("ninja -C \""); command += buildFilePath; - command += "'"; + command += TINYDIR_STRING("\""); Result<ExecResult> execResult = exec(command.c_str(), true); if(execResult.isOk()) { diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index 17649aa..36a57ff 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 char *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); private: sibs::Result<bool> buildTests(const std::string &projectGeneratedBinary, const sibs::SibsConfig &config, const char *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 char *buildFilePath); + sibs::Result<bool> build(const _tinydir_char_t *buildFilePath); private: std::vector<std::string> sourceFiles; std::vector<std::string> testSourceDirs; |