From 98ad7dd049a366e21d60a34548736a3c8ef72877 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 30 Dec 2017 04:32:49 +0100 Subject: Add support for windows (ugly fast solution) --- backend/ninja/Ninja.cpp | 314 +++++++++++++++++++++++++++++++++++++++--------- backend/ninja/Ninja.hpp | 6 +- 2 files changed, 262 insertions(+), 58 deletions(-) (limited to 'backend') diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index ddc20dd..b2a073b 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 &list, const char *joinStr) @@ -30,7 +36,7 @@ namespace backend i = 0; for(const string &str : list) { - if(i > 0); + if(i > 0) result += joinStr; result += str; ++i; @@ -39,6 +45,78 @@ namespace backend return move(result); } + 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(LibraryType _libraryType) : libraryType(_libraryType) { @@ -105,7 +183,8 @@ namespace backend } return false; } - + +#if OS_FAMILY == OS_FAMILY_POSIX Result validatePkgConfigPackageVersionExists(const Dependency &dependency) { Result dependencyValidationResult = PkgConfig::validatePackageExists(dependency.name); @@ -118,7 +197,7 @@ namespace backend return Result::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 Ninja::getLinkerFlags(const SibsConfig &config, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const @@ -126,14 +205,18 @@ namespace backend const vector &dependencies = config.getDependencies(); if(dependencies.empty()) return Result::Ok(true); - string globalLibDir = getHomeDir(); - globalLibDir += "/.sibs/lib"; + Result globalLibDirResult = getHomeDir(); + if (!globalLibDirResult) + return Result::Err(globalLibDirResult); + FileString globalLibDir = globalLibDirResult.unwrap(); + globalLibDir += TINYDIR_STRING("/.sibs/lib"); Result createGlobalLibDirResult = createDirectoryRecursive(globalLibDir.c_str()); if(createGlobalLibDirResult.isErr()) return createGlobalLibDirResult; - vector pkgConfigDependencies; vector globalLibDependencies; +#if OS_FAMILY == OS_FAMILY_POSIX + vector pkgConfigDependencies; for(const Dependency &dependency : dependencies) { Result pkgConfigDependencyValidation = validatePkgConfigPackageVersionExists(dependency); @@ -148,11 +231,11 @@ namespace backend } Result 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); } @@ -160,9 +243,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) { @@ -200,7 +289,7 @@ namespace backend return Result::Ok(true); } - Result Ninja::build(const SibsConfig &config, const char *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) + Result 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()) @@ -210,41 +299,76 @@ namespace backend if(createBuildDirResult.isErr()) return createBuildDirResult; - 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 globalIncDirResult = getHomeDir(); + if (!globalIncDirResult) + return Result::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 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"; @@ -258,12 +382,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; } @@ -289,18 +433,26 @@ namespace backend { //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..' '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' " + optimizationFlags + " '-g'\n\n"; + result += " ARGS = $globalIncDir"; + 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) @@ -332,7 +484,7 @@ namespace backend string projectGeneratedBinary = allLinkerFlags; projectGeneratedBinary += " '"; - projectGeneratedBinary += savePath; + projectGeneratedBinary += savePathUtf8; projectGeneratedBinary += "/"; switch(libraryType) { @@ -343,7 +495,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; @@ -359,24 +524,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: @@ -389,26 +586,26 @@ 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 buildResult = build(savePath); if(!buildResult) return buildResult; - Result buildTestResult = buildTests(projectGeneratedBinary); + Result buildTestResult = buildTests(config, projectGeneratedBinary); if(!buildTestResult) return buildTestResult; return Result::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; @@ -417,7 +614,7 @@ namespace backend return false; } - Result Ninja::buildTests(const std::string &projectGeneratedBinary) + Result Ninja::buildTests(const SibsConfig &parentConfig, const std::string &projectGeneratedBinary) { if(testSourceDirs.empty()) return Result::Ok(true); @@ -428,11 +625,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(parentConfig.getCompiler(), testSourceDirNative); if(projectConfFileType == FileType::REGULAR) { Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig); @@ -442,11 +645,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 { @@ -456,7 +660,7 @@ namespace backend if(!ninja.getSourceFiles().empty()) { - string debugBuildPath = testSourceDir + "/sibs-build/debug"; + FileString debugBuildPath = testSourceDirNative + TINYDIR_STRING("/sibs-build/debug"); Result buildFileResult = ninja.build(sibsTestConfig, debugBuildPath.c_str()); if (!buildFileResult) return buildFileResult; @@ -470,11 +674,11 @@ namespace backend return Result::Ok(true); } - Result Ninja::build(const char *buildFilePath) + Result 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 = exec(command.c_str(), true); if(execResult.isOk()) { diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index fddcaf3..e37a5ca 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& getSourceFiles() const; - sibs::Result build(const sibs::SibsConfig &config, const char *savePath, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc = nullptr, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback = nullptr); + sibs::Result build(const sibs::SibsConfig &config, const _tinydir_char_t *savePath, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc = nullptr, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback = nullptr); private: - sibs::Result buildTests(const std::string &projectGeneratedBinary); + sibs::Result buildTests(const sibs::SibsConfig &parentConfig, const std::string &projectGeneratedBinary); bool containsSourceFile(const std::string &filepath) const; bool containsTestSourceDir(const std::string &dir) const; bool containsDependency(const std::string &dependency) const; sibs::Result getLinkerFlags(const sibs::SibsConfig &config, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const; - sibs::Result build(const char *buildFilePath); + sibs::Result build(const _tinydir_char_t *buildFilePath); private: std::vector sourceFiles; std::vector testSourceDirs; -- cgit v1.2.3