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 +- include/Archive.hpp | 3 +- include/Conf.hpp | 27 +++-- include/Exec.hpp | 3 +- include/FileUtil.hpp | 44 +++++-- include/GlobalLib.hpp | 4 +- include/PkgConfig.hpp | 5 +- include/curl.hpp | 3 +- include/env.hpp | 28 ++++- src/Archive.cpp | 38 +++--- src/Conf.cpp | 16 +-- src/Exec.cpp | 49 +++++++- src/FileUtil.cpp | 246 +++++++++++++++++++++++++++++++------ src/GlobalLib.cpp | 157 +++++++++++++++--------- src/PkgConfig.cpp | 4 +- src/curl.cpp | 21 +++- src/main.cpp | 160 +++++++++++++----------- 18 files changed, 857 insertions(+), 271 deletions(-) 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; diff --git a/include/Archive.hpp b/include/Archive.hpp index 2545f77..10811ab 100644 --- a/include/Archive.hpp +++ b/include/Archive.hpp @@ -2,6 +2,7 @@ #define SIBS_ZLIB_HPP #include "Result.hpp" +#include "FileUtil.hpp" namespace sibs { @@ -9,7 +10,7 @@ namespace sibs { public: // Note: renames root directory in archive to @destination - static Result extract(const char *source, const char *destination); + static Result extract(const _tinydir_char_t *source, const _tinydir_char_t *destination); }; } diff --git a/include/Conf.hpp b/include/Conf.hpp index 1f680e8..0ad1090 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -1,6 +1,7 @@ #ifndef SIBS_CONF_HPP #define SIBS_CONF_HPP +#include "FileUtil.hpp" #include "Result.hpp" #include "StringView.hpp" #include "utils.hpp" @@ -81,7 +82,7 @@ namespace sibs class Config { public: - static Result readFromFile(const char *filepath, const ConfigCallback &callback); + static Result readFromFile(const _tinydir_char_t *filepath, const ConfigCallback &callback); }; enum OptimizationLevel @@ -91,14 +92,25 @@ namespace sibs OPT_LEV_RELEASE }; + enum class Compiler + { + GCC, + MSVC + }; + const char* asString(OptimizationLevel optLevel); class SibsConfig : public ConfigCallback { public: - SibsConfig(const std::string &_projectPath, OptimizationLevel _optimizationLevel = OPT_LEV_DEBUG) : projectPath(_projectPath), packageType((PackageType)-1), optimizationLevel(_optimizationLevel), finishedProcessing(false) {} + SibsConfig(Compiler _compiler, const FileString &_projectPath, OptimizationLevel _optimizationLevel = OPT_LEV_DEBUG) : compiler(_compiler), projectPath(_projectPath), packageType((PackageType)-1), optimizationLevel(_optimizationLevel), finishedProcessing(false) {} virtual ~SibsConfig(){} + Compiler getCompiler() const + { + return compiler; + } + virtual const std::string& getPackageName() const { assert(finishedProcessing); @@ -111,7 +123,7 @@ namespace sibs return packageType; } - virtual const std::string& getTestPath() const + virtual const FileString& getTestPath() const { return testPath; } @@ -121,7 +133,7 @@ namespace sibs return dependencies; } - virtual const std::string& getProjectPath() const + virtual const FileString& getProjectPath() const { return projectPath; } @@ -141,9 +153,10 @@ namespace sibs virtual void finished() override; protected: StringView currentObject; - std::string projectPath; + Compiler compiler; + FileString projectPath; std::string packageName; - std::string testPath; + FileString testPath; PackageType packageType; std::vector dependencies; std::vector includeDirs; @@ -154,7 +167,7 @@ namespace sibs class SibsTestConfig : public SibsConfig { public: - SibsTestConfig(const std::string &_projectPath) : SibsConfig(_projectPath) + SibsTestConfig(Compiler _compiler, const FileString &_projectPath) : SibsConfig(_compiler, _projectPath) { packageName = "test"; } diff --git a/include/Exec.hpp b/include/Exec.hpp index 42b6905..9996073 100644 --- a/include/Exec.hpp +++ b/include/Exec.hpp @@ -2,6 +2,7 @@ #define SIBS_EXEC_HPP #include "Result.hpp" +#include "../include/FileUtil.hpp" #include namespace sibs @@ -12,7 +13,7 @@ namespace sibs int exitCode; }; - Result exec(const char *cmd, bool print = false); + Result exec(const _tinydir_char_t *cmd, bool print = false); } #endif //SIBS_EXEC_HPP diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp index 5d1594a..89eaa84 100644 --- a/include/FileUtil.hpp +++ b/include/FileUtil.hpp @@ -1,13 +1,37 @@ #ifndef SIBS_FILEUTIL_HPP #define SIBS_FILEUTIL_HPP +#ifndef UNICODE +#define UNICODE +#endif + +#ifndef _UNICODE +#define _UNICODE +#endif + +#include "env.hpp" #include "../external/tinydir.h" +#include "../external/utf8/checked.h" #include "Result.hpp" #include "StringView.hpp" #include namespace sibs { + using FileString = std::basic_string<_tinydir_char_t, std::char_traits<_tinydir_char_t>, std::allocator<_tinydir_char_t>>; + +#if OS_FAMILY == OS_FAMILY_POSIX +#define toUtf8(input) input + FileString toFileString(const std::string &utf8Str); +#else + std::string toUtf8(const sibs::FileString &input); + std::string toUtf8(const TCHAR *input); + FileString utf8To16(const StringView &utf8Str); + FileString utf8To16(const std::string &utf8Str); + FileString toFileString(const std::string &utf8Str); + FileString getLastErrorAsString(); +#endif + using FileWalkCallbackFunc = std::function; enum class FileType @@ -17,17 +41,17 @@ namespace sibs DIRECTORY }; - FileType getFileType(const char *path); - void walkDir(const char *directory, FileWalkCallbackFunc callbackFunc); - void walkDirFiles(const char *directory, FileWalkCallbackFunc callbackFunc); - void walkDirFilesRecursive(const char *directory, FileWalkCallbackFunc callbackFunc); - Result getFileContent(const char *filepath); - Result fileOverwrite(const char *filepath, StringView data); - const char* getHomeDir(); - Result getCwd(); + FileType getFileType(const _tinydir_char_t *path); + void walkDir(const _tinydir_char_t *directory, FileWalkCallbackFunc callbackFunc); + void walkDirFiles(const _tinydir_char_t *directory, FileWalkCallbackFunc callbackFunc); + void walkDirFilesRecursive(const _tinydir_char_t *directory, FileWalkCallbackFunc callbackFunc); + Result getFileContent(const _tinydir_char_t *filepath); + Result fileOverwrite(const _tinydir_char_t *filepath, StringView data); + Result getHomeDir(); + Result getCwd(); // Note: Will not delete created directories if this operation fails for some reason - Result createDirectoryRecursive(const char *path); - Result getRealPath(const char *path); + Result createDirectoryRecursive(const _tinydir_char_t *path); + Result getRealPath(const _tinydir_char_t *path); } #endif //SIBS_FILEUTIL_HPP diff --git a/include/GlobalLib.hpp b/include/GlobalLib.hpp index c67027e..2f4b938 100644 --- a/include/GlobalLib.hpp +++ b/include/GlobalLib.hpp @@ -17,8 +17,8 @@ namespace sibs DEPENDENCY_VERSION_NO_MATCH = 20 }; - static Result validatePackageExists(const std::string &globalLibRootDir, const std::string &name); - static Result getLibsLinkerFlags(const SibsConfig &parentConfig, const std::string &globalLibRootDir, const std::string &name, const std::string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc); + static Result validatePackageExists(const FileString &globalLibRootDir, const std::string &name); + static Result getLibsLinkerFlags(const SibsConfig &parentConfig, const FileString &globalLibRootDir, const std::string &name, const std::string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc); static Result downloadDependency(const Dependency &dependency); }; } diff --git a/include/PkgConfig.hpp b/include/PkgConfig.hpp index 2af4ac9..da78b91 100644 --- a/include/PkgConfig.hpp +++ b/include/PkgConfig.hpp @@ -1,6 +1,8 @@ #ifndef SIBS_PKGCONFIG_HPP #define SIBS_PKGCONFIG_HPP +#include "env.hpp" +#if OS_FAMILY == OS_FAMILY_POSIX #include "Result.hpp" #include "Dependency.hpp" #include @@ -16,5 +18,6 @@ namespace sibs static Result getDynamicLibsLinkerFlags(const std::vector &libs); }; } +#endif // OS_FAMILY_POSIX -#endif //SIBS_PKGCONFIG_HPP +#endif // SIBS_PKGCONFIG_HPP diff --git a/include/curl.hpp b/include/curl.hpp index 7c0ddbe..16b3e52 100644 --- a/include/curl.hpp +++ b/include/curl.hpp @@ -2,6 +2,7 @@ #define SIBS_CURL_HPP #include "Result.hpp" +#include "FileUtil.hpp" #include namespace sibs @@ -17,7 +18,7 @@ namespace sibs class curl { public: - static sibs::Result downloadFile(const char *url, const char *filepath); + static sibs::Result downloadFile(const char *url, const _tinydir_char_t *filepath); static HttpResult get(const char *url); }; } diff --git a/include/env.hpp b/include/env.hpp index f5b1213..51ee2bd 100644 --- a/include/env.hpp +++ b/include/env.hpp @@ -4,6 +4,9 @@ #define OS_FAMILY_WINDOWS 0 #define OS_FAMILY_POSIX 1 +#define OS_TYPE_WINDOWS 0 +#define OS_TYPE_LINUX 1 + #if defined(_WIN32) || defined(_WIN64) #if defined(_WIN64) #define CISB_ENV_64BIT @@ -11,12 +14,31 @@ #define CISB_ENV_32BIT #endif #define OS_FAMILY OS_FAMILY_WINDOWS + #define OS_TYPE OS_TYPE_WINDOWS + + #ifndef UNICODE + #define UNICODE + #endif + + #ifndef _UNICODE + #define _UNICODE + #endif + + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + + #include #endif #if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(_POSIX_VERSION) #define OS_FAMILY OS_FAMILY_POSIX #endif +#ifdef __linux__ + #define OS_TYPE OS_TYPE_LINUX +#endif + #if defined(__GNUC__) #if defined(__x86_64__) || defined(__pc64__) #define CISB_ENV_64BIT @@ -30,7 +52,11 @@ #endif #if !defined(OS_FAMILY) - #error "System not support. Only Windows and Posix systems support" + #error "System not supported. Only Windows and Posix systems supported right now" +#endif + +#if !defined(OS_TYPE) + #error "System not supported. Only Windows and linux systems supported right now" #endif #if !defined(DEBUG) && !defined(NDEBUG) diff --git a/src/Archive.cpp b/src/Archive.cpp index 08ab42b..506b020 100644 --- a/src/Archive.cpp +++ b/src/Archive.cpp @@ -6,6 +6,14 @@ using namespace std; +#if OS_FAMILY == OS_FAMILY_POSIX +#define archive_read_open_filename_native archive_read_open_filename +#define archive_entry_pathname_native archive_entry_pathname +#else +#define archive_read_open_filename_native archive_read_open_filename_w +#define archive_entry_pathname_native archive_entry_pathname_w +#endif + class FileHandler { DISABLE_COPY(FileHandler) @@ -53,7 +61,7 @@ namespace sibs } } - Result Archive::extract(const char *source, const char *destination) + Result Archive::extract(const _tinydir_char_t *source, const _tinydir_char_t *destination) { struct archive *a; struct archive *ext; @@ -67,7 +75,7 @@ namespace sibs flags |= ARCHIVE_EXTRACT_ACL; flags |= ARCHIVE_EXTRACT_FFLAGS; - string rootName; + FileString rootName; a = archive_read_new(); archive_read_support_format_all(a); @@ -77,10 +85,10 @@ namespace sibs archive_write_disk_set_standard_lookup(ext); - if ((r = archive_read_open_filename(a, source, 10240))) + if ((r = archive_read_open_filename_native(a, source, 10240))) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); return Result::Err(errMsg); } @@ -92,7 +100,7 @@ namespace sibs else if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); errMsg += "; reason: "; errMsg += archive_error_string(a); return Result::Err(errMsg); @@ -100,25 +108,27 @@ namespace sibs else if (r < ARCHIVE_WARN) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); errMsg += "; reason: "; errMsg += archive_error_string(a); return Result::Err(errMsg); } - const char* currentFile = archive_entry_pathname(entry); + const _tinydir_char_t* currentFile = archive_entry_pathname_native(entry); if(rootName.empty()) rootName = currentFile; - std::string fullOutputPath = destination; + FileString fullOutputPath = destination; fullOutputPath += (currentFile + (rootName.empty() ? 0 : rootName.size() - 1)); - archive_entry_set_pathname(entry, fullOutputPath.c_str()); + // TODO: Verify if this really works. Why doesn't libarchive have wide string version of archive_entry_set_pathname? + string fullOutputPathUtf8 = toUtf8(fullOutputPath); + archive_entry_set_pathname(entry, fullOutputPathUtf8.c_str()); r = archive_write_header(ext, entry); if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); @@ -128,7 +138,7 @@ namespace sibs if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); @@ -136,7 +146,7 @@ namespace sibs else if (r < ARCHIVE_WARN) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); @@ -147,7 +157,7 @@ namespace sibs if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); @@ -155,7 +165,7 @@ namespace sibs else if (r < ARCHIVE_WARN) { string errMsg = "Failed to extract archive: "; - errMsg += source; + errMsg += toUtf8(source); errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); diff --git a/src/Conf.cpp b/src/Conf.cpp index d6aee2c..743942a 100644 --- a/src/Conf.cpp +++ b/src/Conf.cpp @@ -1,5 +1,5 @@ #include "../include/Conf.hpp" -#include "../include/FileUtil.hpp" +#include "../include/types.hpp" #include "../external/utf8/unchecked.h" using namespace std; @@ -7,8 +7,6 @@ using u8string = utf8::unchecked::iterator; namespace sibs { - u32 min(u32 a, u32 b) { return a < b ? a : b; } - class UnexpectedTokenException : public std::runtime_error { public: @@ -316,7 +314,7 @@ namespace sibs bool objectDefined; }; - Result Config::readFromFile(const char *filepath, const ConfigCallback &callback) + Result Config::readFromFile(const _tinydir_char_t *filepath, const ConfigCallback &callback) { Result fileContentResult = getFileContent(filepath); if(fileContentResult.isErr()) @@ -409,9 +407,13 @@ namespace sibs if (value.isSingle()) { testPath = projectPath; - testPath += "/"; - testPath += string(value.asSingle().data, value.asSingle().size); - Result testRealPathResult = getRealPath(testPath.c_str()); + testPath += TINYDIR_STRING("/"); +#if OS_FAMILY == OS_FAMILY_POSIX + testPath += FileString(value.asSingle().data, value.asSingle().size); +#else + testPath += utf8To16(value.asSingle()); +#endif + Result testRealPathResult = getRealPath(testPath.c_str()); if(!testRealPathResult) { string errMsg = "Failed to resolve package.tests path: "; diff --git a/src/Exec.cpp b/src/Exec.cpp index 37ffef5..e0ae306 100644 --- a/src/Exec.cpp +++ b/src/Exec.cpp @@ -1,10 +1,12 @@ #include "../include/Exec.hpp" +#include "../include/env.hpp" using namespace std; namespace sibs { - Result exec(const char *cmd, bool print) +#if OS_FAMILY == OS_FAMILY_POSIX + Result exec(const _tinydir_char_t *cmd, bool print) { char buffer[128]; std::string result; @@ -52,4 +54,49 @@ namespace sibs return Result::Err(errMsg); } } +#else + // TODO(Windows): Redirect stdout (and stderr) to string + Result exec(const _tinydir_char_t *cmd, bool print) + { + char buffer[128]; + std::string result; + + STARTUPINFO startupInfo; + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + PROCESS_INFORMATION processInfo; + ZeroMemory(&processInfo, sizeof(processInfo)); + + DWORD exitCode; + + if (!CreateProcess(NULL, (LPWSTR)cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) + { + string errMsg = "exec unexpected error: "; + errMsg += toUtf8(getLastErrorAsString()); + return Result::Err(errMsg); + } + + WaitForSingleObject(processInfo.hProcess, INFINITE); + GetExitCodeProcess(processInfo.hProcess, &exitCode); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + + if (exitCode == 0) + { + ExecResult execResult; + execResult.execStdout = result; + execResult.exitCode = exitCode; + return Result::Ok(execResult); + } + else + { + string errMsg = "Exited with non-zero exit code ("; + errMsg += to_string(exitCode); + errMsg += "): "; + errMsg += toUtf8(getLastErrorAsString()); + return Result::Err(errMsg); + } + } +#endif } \ No newline at end of file diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp index d075f2b..5cf8377 100644 --- a/src/FileUtil.cpp +++ b/src/FileUtil.cpp @@ -1,5 +1,4 @@ #include "../include/FileUtil.hpp" -#include "../include/env.hpp" #include #if OS_FAMILY == OS_FAMILY_POSIX @@ -7,27 +6,92 @@ #include #include #include +#else +#include +// Copied from linux libc sys/stat.h: +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif using namespace std; namespace sibs { - FileType getFileType(const char *path) +#if OS_FAMILY == OS_FAMILY_POSIX +#define toUtf8(input) input + FileString toFileString(const std::string &utf8Str) { - tinydir_file file; - if(tinydir_file_open(&file, path) == 0) - { - return file.is_dir ? FileType::DIRECTORY : FileType::REGULAR; - } + return utf8Str; + } +#else + std::string toUtf8(const sibs::FileString &input) + { + std::string result; + utf8::utf16to8(input.data(), input.data() + input.size(), std::back_inserter(result)); + return result; + } + + std::string toUtf8(const TCHAR *input) + { + size_t inputSize = wcslen(input); + std::string result; + utf8::utf16to8(input, input + inputSize, std::back_inserter(result)); + return result; + } + + FileString utf8To16(const StringView &utf8Str) + { + FileString result; + utf8::utf8to16(utf8Str.data, utf8Str.data + utf8Str.size, std::back_inserter(result)); + return result; + } + + FileString utf8To16(const std::string &utf8Str) + { + FileString result; + utf8::utf8to16(utf8Str.data(), utf8Str.data() + utf8Str.size(), std::back_inserter(result)); + return result; + } + + FileString toFileString(const std::string &utf8Str) + { + return utf8To16(utf8Str); + } + + FileString getLastErrorAsString() + { + DWORD errorMessageId = GetLastError(); + if (errorMessageId == 0) return TINYDIR_STRING(""); + LPWSTR messageBuffer = nullptr; + size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, errorMessageId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr); + FileString message(messageBuffer, size); + LocalFree(messageBuffer); + return message; + } +#endif + +#if OS_FAMILY == OS_FAMILY_POSIX + FileType getFileType(const _tinydir_char_t *path) + { + struct stat64 fileStat; + if (stat64(path, &fileStat) == 0) + return S_ISREG(fileStat.st_mode) ? FileType::REGULAR : FileType::DIRECTORY; else - { return FileType::FILE_NOT_FOUND; - } } +#else + FileType getFileType(const _tinydir_char_t *path) + { + struct _stat64i32 fileStat; + if (_wstat(path, &fileStat) == 0) + return S_ISREG(fileStat.st_mode) ? FileType::REGULAR : FileType::DIRECTORY; + else + return FileType::FILE_NOT_FOUND; + } +#endif // TODO: Handle failure (directory doesn't exist, no permission etc) - void walkDir(const char *directory, FileWalkCallbackFunc callbackFunc) + void walkDir(const _tinydir_char_t *directory, FileWalkCallbackFunc callbackFunc) { tinydir_dir dir; tinydir_open(&dir, directory); @@ -36,7 +100,7 @@ namespace sibs { tinydir_file file; tinydir_readfile(&dir, &file); - if(_tinydir_strcmp(file.name, ".") != 0 && _tinydir_strcmp(file.name, "..") != 0) + if(_tinydir_strcmp(file.name, TINYDIR_STRING(".")) != 0 && _tinydir_strcmp(file.name, TINYDIR_STRING("..")) != 0) callbackFunc(&file); tinydir_next(&dir); } @@ -45,7 +109,7 @@ namespace sibs } // TODO: Handle failure (directory doesn't exist, no permission etc) - void walkDirFiles(const char *directory, FileWalkCallbackFunc callbackFunc) + void walkDirFiles(const _tinydir_char_t *directory, FileWalkCallbackFunc callbackFunc) { tinydir_dir dir; tinydir_open(&dir, directory); @@ -63,7 +127,7 @@ namespace sibs } // TODO: Handle failure (directory doesn't exist, no permission etc) - void walkDirFilesRecursive(const char *directory, FileWalkCallbackFunc callbackFunc) + void walkDirFilesRecursive(const _tinydir_char_t *directory, FileWalkCallbackFunc callbackFunc) { tinydir_dir dir; tinydir_open(&dir, directory); @@ -74,7 +138,7 @@ namespace sibs tinydir_readfile(&dir, &file); if(file.is_reg) callbackFunc(&file); - else if(_tinydir_strcmp(file.name, ".") != 0 && _tinydir_strcmp(file.name, "..") != 0) + else if(_tinydir_strcmp(file.name, TINYDIR_STRING(".")) != 0 && _tinydir_strcmp(file.name, TINYDIR_STRING("..")) != 0) walkDirFilesRecursive(file.path, callbackFunc); tinydir_next(&dir); } @@ -82,14 +146,18 @@ namespace sibs tinydir_close(&dir); } - Result getFileContent(const char *filepath) + Result getFileContent(const _tinydir_char_t *filepath) { +#if OS_FAMILY == OS_FAMILY_POSIX FILE *file = fopen(filepath, "rb"); +#else + FILE *file = _wfopen(filepath, TINYDIR_STRING("rb")); +#endif if(!file) { int error = errno; string errMsg = "Failed to open file: "; - errMsg += filepath; + errMsg += toUtf8(filepath); errMsg += "; reason: "; errMsg += strerror(error); return Result::Err(errMsg); @@ -104,7 +172,7 @@ namespace sibs if(!result) { std::string errMsg = "Failed to load file content from file: "; - errMsg += filepath; + errMsg += toUtf8(filepath); throw std::runtime_error(errMsg); } result[fileSize] = '\0'; @@ -113,14 +181,18 @@ namespace sibs return Result::Ok(StringView(result, fileSize)); } - Result fileOverwrite(const char *filepath, StringView data) + Result fileOverwrite(const _tinydir_char_t *filepath, StringView data) { +#if OS_FAMILY == OS_FAMILY_POSIX FILE *file = fopen(filepath, "wb"); +#else + FILE *file = _wfopen(filepath, TINYDIR_STRING("wb")); +#endif if(!file) { int error = errno; string errMsg = "Failed to overwrite file: "; - errMsg += filepath; + errMsg += toUtf8(filepath); errMsg += "; reason: "; errMsg += strerror(error); return Result::Err(errMsg); @@ -130,8 +202,8 @@ namespace sibs fclose(file); return Result::Ok(true); } - - const char* getHomeDir() +#if OS_FAMILY == OS_FAMILY_POSIX + Result getHomeDir() { const char *homeDir = getenv("HOME"); if(!homeDir) @@ -139,26 +211,25 @@ namespace sibs passwd *pw = getpwuid(getuid()); homeDir = pw->pw_dir; } - return homeDir; + return Result::Ok(homeDir); } - Result getCwd() + Result getCwd() { - string cwd; - cwd.reserve(PATH_MAX); - if(getcwd(&cwd[0], PATH_MAX) != 0) + FileString cwd; + cwd.resize(_TINYDIR_PATH_MAX); + if(getcwd(&cwd[0], _TINYDIR_PATH_MAX) != 0) { if(cwd.empty()) cwd = "."; - return Result::Ok(cwd); + cwd.resize(_tinydir_strlen(cwd.c_str())); + return Result::Ok(cwd); } - - return Result::Err(strerror(errno)); + return Result::Err(strerror(errno)); } -#if OS_FAMILY == OS_FAMILY_POSIX - Result createDirectoryRecursive(const char *path) + Result createDirectoryRecursive(const _tinydir_char_t *path) { - char pathBuffer[PATH_MAX]; + char pathBuffer[_TINYDIR_PATH_MAX]; size_t pathLength = strlen(path); if(pathLength > sizeof(pathBuffer) - 1) { @@ -207,25 +278,126 @@ namespace sibs return Result::Ok(true); } - Result getRealPath(const char *path) + Result getRealPath(const _tinydir_char_t *path) { // TODO: Verify NULL can be passed as 'resolved' argument with different compilers and operating systems (clang, freebsd etc) char *resolved = realpath(path, nullptr); if(!resolved) { int error = errno; - string errMsg = "Failed to get real path for \""; + FileString errMsg = "Failed to get real path for \""; errMsg += path; errMsg += "\": "; errMsg += strerror(error); - return Result::Err(errMsg, error); + return Result::Err(errMsg, error); } string result = resolved; free(resolved); - return Result::Ok(result); + return Result::Ok(result); } #else -#error "TODO: Implement createDirectoryRecursive and getRealPath on windows" + +#pragma comment(lib, "Userenv.lib") + + Result getHomeDir() + { + BOOL ret; + HANDLE hToken; + FileString homeDir; + DWORD homeDirLen = _TINYDIR_PATH_MAX; + homeDir.resize(homeDirLen); + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) + return Result::Err("Failed to open process token"); + + if (!GetUserProfileDirectory(hToken, &homeDir[0], &homeDirLen)) + return Result::Err("Failed to get home directory"); + + CloseHandle(hToken); + homeDir.resize(_tinydir_strlen(homeDir.c_str())); + return Result::Ok(homeDir); + } + + Result getCwd() + { + FileString cwd; + cwd.resize(_TINYDIR_PATH_MAX); + if (GetCurrentDirectory(_TINYDIR_PATH_MAX, &cwd[0]) == 0) + { + FileString lastErrStr = getLastErrorAsString(); + return Result::Err(toUtf8(lastErrStr)); + } + cwd.resize(_tinydir_strlen(cwd.c_str())); + return Result::Ok(cwd); + } + + Result createDirectoryRecursive(const _tinydir_char_t *path) + { + _tinydir_char_t pathBuffer[_TINYDIR_PATH_MAX]; + size_t pathLength = _tinydir_strlen(path); + if (pathLength > sizeof(pathBuffer) - 1) + { + string errMsg = "Directory path too long: "; + errMsg += toUtf8(FileString(path, pathLength)); + return Result::Err(errMsg, ENAMETOOLONG); + } + _tinydir_strcpy(pathBuffer, path); + + _tinydir_char_t *p = pathBuffer; + for (size_t i = 0; i < pathLength; ++i) + { + if (i > 0 && *p == '/') + { + *p = '\0'; + if (_wmkdir(pathBuffer) != 0) + { + int error = errno; + if (error != EEXIST) + { + string errMsg = "Failed to create directory: "; + errMsg += toUtf8(pathBuffer); + errMsg += "; reason: "; + errMsg += strerror(error); + return Result::Err(errMsg, error); + } + } + *p = '/'; + } + ++p; + } + + if (_wmkdir(pathBuffer) != 0) + { + int error = errno; + if (error != EEXIST) + { + string errMsg = "Failed to create directory: "; + errMsg += toUtf8(pathBuffer); + errMsg += "; reason: "; + errMsg += strerror(error); + return Result::Err(errMsg, error); + } + } + + return Result::Ok(true); + } + + Result getRealPath(const _tinydir_char_t *path) + { + FileString fullPath; + fullPath.resize(_TINYDIR_PATH_MAX); + if (GetFullPathName(path, _TINYDIR_PATH_MAX, &fullPath[0], nullptr) == 0) + { + int error = GetLastError(); + string errMsg = "Failed to get real path for \""; + errMsg += toUtf8(path); + errMsg += "\": "; + errMsg += toUtf8(getLastErrorAsString()); + return Result::Err(errMsg, error); + } + fullPath.resize(_tinydir_strlen(fullPath.c_str())); + return Result::Ok(fullPath); + } #endif } \ No newline at end of file diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp index d994a27..db85abd 100644 --- a/src/GlobalLib.cpp +++ b/src/GlobalLib.cpp @@ -9,23 +9,27 @@ using namespace std; namespace sibs { - Result GlobalLib::validatePackageExists(const string &globalLibRootDir, const string &name) + Result GlobalLib::validatePackageExists(const FileString &globalLibRootDir, const std::string &name) { - string packageDir = globalLibRootDir + "/"; + FileString packageDir = globalLibRootDir + TINYDIR_STRING("/"); +#if OS_FAMILY == OS_FAMILY_POSIX packageDir += name; +#else + packageDir += utf8To16(name); +#endif FileType packageDirFileType = getFileType(packageDir.c_str()); switch(packageDirFileType) { case FileType::FILE_NOT_FOUND: { string errMsg = "Global lib dependency not found: "; - errMsg += name; + errMsg += toUtf8(packageDir); return Result::Err(errMsg, DependencyError::DEPENDENCY_NOT_FOUND); } case FileType::REGULAR: { string errMsg = "Corrupt library directory. "; - errMsg += packageDir; + errMsg += toUtf8(packageDir); errMsg += " is a file, expected it to be a directory"; return Result::Err(errMsg); } @@ -40,13 +44,13 @@ namespace sibs } } - 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; @@ -55,29 +59,37 @@ namespace sibs return false; } - bool isPathSubPathOf(const char *path, const string &subPathOf) + bool isPathSubPathOf(const _tinydir_char_t *path, const FileString &subPathOf) { return _tinydir_strncmp(path, subPathOf.c_str(), subPathOf.size()) == 0; } - Result GlobalLib::getLibsLinkerFlags(const SibsConfig &parentConfig, const string &globalLibRootDir, const string &name, const string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc) + Result GlobalLib::getLibsLinkerFlags(const SibsConfig &parentConfig, const FileString &globalLibRootDir, const std::string &name, const std::string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc) { Result packageExistsResult = validatePackageExists(globalLibRootDir, name); if(packageExistsResult.isErr()) return Result::Err(packageExistsResult); - string packageDir = globalLibRootDir + "/"; - packageDir += name; +#if OS_FAMILY == OS_FAMILY_POSIX + FileString namePlatformNative = name; + FileString versionPlatformNative = version; +#else + FileString namePlatformNative = utf8To16(name); + FileString versionPlatformNative = utf8To16(version); +#endif + + FileString packageDir = globalLibRootDir + TINYDIR_STRING("/"); + packageDir += namePlatformNative; // TODO: Instead of checking if version is exact match, check if package has same major version // and same or newer minor version - string foundVersion; - walkDir(packageDir.c_str(), [&foundVersion, &version](tinydir_file *file) + FileString foundVersion; + walkDir(packageDir.c_str(), [&foundVersion, &versionPlatformNative](tinydir_file *file) { if(file->is_dir) { //printf("version: %s\n", file->name); - if(_tinydir_strcmp(version.c_str(), file->name) == 0) + if(_tinydir_strcmp(versionPlatformNative.c_str(), file->name) == 0) foundVersion = file->name; } }); @@ -85,11 +97,11 @@ namespace sibs if(foundVersion.empty()) return Result::Err("Global lib dependency found, but version doesn't match dependency version", DependencyError::DEPENDENCY_VERSION_NO_MATCH); - packageDir += "/"; - packageDir += version; + packageDir += TINYDIR_STRING("/"); + packageDir += versionPlatformNative; - string projectConfFilePath = packageDir; - projectConfFilePath += "/project.conf"; + FileString projectConfFilePath = packageDir; + projectConfFilePath += TINYDIR_STRING("/project.conf"); FileType projectConfFileType = getFileType(projectConfFilePath.c_str()); switch(projectConfFileType) @@ -97,20 +109,20 @@ namespace sibs case FileType::FILE_NOT_FOUND: { string errMsg = "Global lib dependency found: "; - errMsg += packageDir; + errMsg += toUtf8(packageDir); errMsg += ", but it's missing a project.conf file"; return Result::Err(errMsg); } case FileType::DIRECTORY: { string errMsg = "Global lib dependency found: "; - errMsg += packageDir; + errMsg += toUtf8(packageDir); errMsg += ", but it's corrupt (Found directory instead of file)"; return Result::Err(errMsg); } } - SibsConfig sibsConfig(packageDir, parentConfig.getOptimizationLevel()); + SibsConfig sibsConfig(parentConfig.getCompiler(), packageDir, parentConfig.getOptimizationLevel()); Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if(result.isErr()) return Result::Err(result.getErrMsg()); @@ -148,7 +160,8 @@ namespace sibs { if (isSourceFile(file)) { - ninja.addSourceFile(file->path + sibsConfig.getProjectPath().size() + 1); + string fileNameNative = toUtf8(file->path + sibsConfig.getProjectPath().size() + 1); + ninja.addSourceFile(fileNameNative.c_str()); } else { @@ -160,8 +173,11 @@ namespace sibs // 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(file->path, sibsConfig.getTestPath())) - ninja.addTestSourceDir(file->path); + if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(file->path, sibsConfig.getTestPath())) + { + string filePathUtf8 = toUtf8(file->path); + ninja.addTestSourceDir(filePathUtf8.c_str()); + } else walkDir(file->path, collectSourceFiles); } @@ -175,36 +191,64 @@ namespace sibs } else { - string buildPath = packageDir + "/sibs-build/"; + FileString buildPath = packageDir + TINYDIR_STRING("/sibs-build/"); switch(sibsConfig.getOptimizationLevel()) { case OPT_LEV_DEBUG: - buildPath += "debug"; + buildPath += TINYDIR_STRING("debug"); break; case OPT_LEV_RELEASE: - buildPath += "release"; + buildPath += TINYDIR_STRING("release"); break; } - - string libPath = buildPath; - libPath += "/lib"; - libPath += name; - if(libraryType == backend::Ninja::LibraryType::STATIC) - { - libPath += ".a"; - string libPathCmd = "'"; - libPathCmd += libPath; - libPathCmd += "'"; - staticLinkerFlagCallbackFunc(libPathCmd); - libPath += ".a"; - } - else + + string libPath = toUtf8(buildPath); + switch (sibsConfig.getCompiler()) { - libPath += ".so"; - string libPathCmd = "'"; - libPathCmd += libPath; - libPathCmd += "'"; - dynamicLinkerFlagCallbackFunc(libPathCmd); + case Compiler::GCC: + { + libPath += "/lib"; + libPath += name; + if (libraryType == backend::Ninja::LibraryType::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 += name; + if (libraryType == backend::Ninja::LibraryType::STATIC) + { + libPath += ".lib"; + string libPathCmd = "\""; + libPathCmd += libPath; + libPathCmd += "\""; + staticLinkerFlagCallbackFunc(libPathCmd); + } + else + { + libPath += ".lib"; + string libPathCmd = "\""; + libPathCmd += libPath; + libPathCmd += "\""; + dynamicLinkerFlagCallbackFunc(libPathCmd); + } + break; + } } // TODO: Use different directories depending on the project type, but .o build files should be in the same directory @@ -229,21 +273,24 @@ namespace sibs url += dependency.version; url += ".tar.gz"; - string libPath = getHomeDir(); - libPath += "/.sibs/lib/"; - libPath += dependency.name; - libPath += "/"; - libPath += dependency.version; + Result libPathResult = getHomeDir(); + if (!libPathResult) + return Result::Err(libPathResult); + FileString libPath = libPathResult.unwrap(); + libPath += TINYDIR_STRING("/.sibs/lib/"); + libPath += toFileString(dependency.name); + libPath += TINYDIR_STRING("/"); + libPath += toFileString(dependency.version); - string libArchivedFilePath = getHomeDir(); - libArchivedFilePath += "/.sibs/archive/"; - libArchivedFilePath += dependency.name; + FileString libArchivedFilePath = libPathResult.unwrap(); + libArchivedFilePath += TINYDIR_STRING("/.sibs/archive/"); + libArchivedFilePath += toFileString(dependency.name); Result createArchiveDirResult = createDirectoryRecursive(libArchivedFilePath.c_str()); if(createArchiveDirResult.isErr()) return createArchiveDirResult; - libArchivedFilePath += "/"; - libArchivedFilePath += dependency.version; + libArchivedFilePath += TINYDIR_STRING("/"); + libArchivedFilePath += toFileString(dependency.version); Result downloadResult = curl::downloadFile(url.c_str(), libArchivedFilePath.c_str()); if(downloadResult.isErr()) return downloadResult; diff --git a/src/PkgConfig.cpp b/src/PkgConfig.cpp index 620b1a7..a66d5b3 100644 --- a/src/PkgConfig.cpp +++ b/src/PkgConfig.cpp @@ -1,4 +1,5 @@ #include "../include/PkgConfig.hpp" +#if OS_FAMILY == OS_FAMILY_POSIX #include "../include/Exec.hpp" using namespace std; @@ -127,4 +128,5 @@ namespace sibs return Result::Err(errMsg); } } -} \ No newline at end of file +} +#endif // OS_FAMILY_POSIX diff --git a/src/curl.cpp b/src/curl.cpp index 56c19ec..a3c5e28 100644 --- a/src/curl.cpp +++ b/src/curl.cpp @@ -5,6 +5,12 @@ using namespace std; +#if OS_FAMILY == OS_FAMILY_WINDOWS +#pragma comment(lib, "Ws2_32.lib") +#pragma comment(lib, "Wldap32.lib") +#pragma comment(lib, "Crypt32.lib") +#endif + #ifdef DEBUG #define CURL_DEBUG #endif @@ -44,7 +50,7 @@ namespace sibs return size * nmemb; } - Result curl::downloadFile(const char *url, const char *filepath) + Result curl::downloadFile(const char *url, const _tinydir_char_t *filepath) { CURL *curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_URL, url); @@ -60,15 +66,19 @@ namespace sibs curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeToFile); curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, true); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SIBS"); - + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE); +#if OS_FAMILY == OS_FAMILY_POSIX FILE *file = fopen(filepath, "wb"); +#else + FILE *file = _wfopen(filepath, L"wb"); +#endif if(!file) { int error = errno; curl_easy_cleanup(curl_handle); string errMsg = "Failed to open file for writing: "; - errMsg += filepath; + errMsg += toUtf8(filepath); if(error != 0) { errMsg += "; Reason: "; @@ -131,8 +141,9 @@ namespace sibs curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, noProgressMeter); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeToString); curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, true); - curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Hacker"); - + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SIBS"); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &result.str); printf("Downloading from url: %s\n", url); CURLcode curlResponse = curl_easy_perform(curl_handle); diff --git a/src/main.cpp b/src/main.cpp index 0f20ea0..f49ba59 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,6 +20,12 @@ using namespace sibs; // TODO: Places that use PATH_MAX should be modified. A path CAN be longer than PATH_MAX... (does this include replacing tinydir.h?) +#if OS_FAMILY == OS_FAMILY_POSIX +#define ferr std::cerr +#else +#define ferr std::wcerr +#endif + void usage() { printf("Usage: sibs COMMAND\n\n"); @@ -59,47 +65,47 @@ void usageNew() exit(1); } -void validateDirectoryPath(const char *projectPath) +void validateDirectoryPath(const _tinydir_char_t *projectPath) { FileType projectPathFileType = getFileType(projectPath); if(projectPathFileType == FileType::FILE_NOT_FOUND) { string errMsg = "Invalid project path: "; - errMsg += projectPath; + errMsg += toUtf8(projectPath); perror(errMsg.c_str()); exit(2); } else if(projectPathFileType == FileType::REGULAR) { - cerr <<"Expected project path (" << projectPath << ") to be a directory, was a file" << endl; + ferr <<"Expected project path (" << projectPath << ") to be a directory, was a file" << endl; exit(3); } } -void validateFilePath(const char *projectConfPath) +void validateFilePath(const _tinydir_char_t *projectConfPath) { FileType projectConfFileType = getFileType(projectConfPath); if(projectConfFileType == FileType::FILE_NOT_FOUND) { string errMsg = "Invalid project.conf path: "; - errMsg += projectConfPath; + errMsg += toUtf8(projectConfPath); perror(errMsg.c_str()); exit(4); } else if(projectConfFileType == FileType::DIRECTORY) { - cerr << "Expected project path (" << projectConfPath << ") to be a file, was a directory" << endl; + ferr << "Expected project path (" << projectConfPath << ") to be a file, was a directory" << endl; exit(5); } } -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; @@ -108,36 +114,36 @@ bool isSourceFile(tinydir_file *file) return false; } -bool isPathSubPathOf(const string &path, const string &subPathOf) +bool isPathSubPathOf(const FileString &path, const FileString &subPathOf) { return _tinydir_strncmp(path.c_str(), subPathOf.c_str(), subPathOf.size()) == 0; } -int buildProject(int argc, const char **argv) +int buildProject(int argc, const _tinydir_char_t **argv) { if(argc > 2) usageBuild(); OptimizationLevel optimizationLevel = OPT_LEV_NONE; - string projectPath; + FileString projectPath; for(int i = 0; i < argc; ++i) { - const char *arg = argv[i]; - if(strcmp(arg, "--debug") == 0) + const _tinydir_char_t *arg = argv[i]; + if(_tinydir_strcmp(arg, TINYDIR_STRING("--debug")) == 0) { if(optimizationLevel != OPT_LEV_NONE) { - fprintf(stderr, "Error: Optimization level defined more than once. First defined as %s then as %s\n", asString(optimizationLevel), "debug"); + ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as debug" << endl; usageBuild(); } optimizationLevel = OPT_LEV_DEBUG; } - else if(strcmp(arg, "--release") == 0) + else if(_tinydir_strcmp(arg, TINYDIR_STRING("--release")) == 0) { if(optimizationLevel != OPT_LEV_NONE) { - fprintf(stderr, "Error: Optimization level defined more than once. First defined as %s then as %s\n", asString(optimizationLevel), "debug"); + ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as release" << endl; usageBuild(); } optimizationLevel = OPT_LEV_RELEASE; @@ -146,7 +152,7 @@ int buildProject(int argc, const char **argv) { if(!projectPath.empty()) { - fprintf(stderr, "Error: Project path was defined more than once. First defined as %s then as %s\n", projectPath.c_str(), arg); + ferr << "Error: Project path was defined more than once. First defined as " << projectPath << " then as " << arg << endl; usageBuild(); } projectPath = arg; @@ -158,35 +164,43 @@ int buildProject(int argc, const char **argv) // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found if(projectPath.empty()) - projectPath = "."; + projectPath = TINYDIR_STRING("."); validateDirectoryPath(projectPath.c_str()); if(projectPath.back() != '/') - projectPath += "/"; + projectPath += TINYDIR_STRING("/"); - Result projectRealPathResult = getRealPath(projectPath.c_str()); + Result projectRealPathResult = getRealPath(projectPath.c_str()); if(!projectRealPathResult) { - cerr << "Failed to get real path for: '" << projectPath << "': " << projectRealPathResult.getErrMsg() << endl; + ferr << "Failed to get real path for: '" << projectPath.c_str() << "': " << toFileString(projectRealPathResult.getErrMsg()) << endl; exit(40); } projectPath = projectRealPathResult.unwrap(); - string projectConfFilePath = projectPath; - projectConfFilePath += "/project.conf"; + FileString projectConfFilePath = projectPath; + projectConfFilePath += TINYDIR_STRING("/project.conf"); validateFilePath(projectConfFilePath.c_str()); - SibsConfig sibsConfig(projectPath, optimizationLevel); + // TODO: Detect compiler to use at runtime. Should also be configurable + // by passing argument to `sibs build` +#if OS_FAMILY == OS_FAMILY_POSIX + Compiler compiler = Compiler::GCC; +#else + Compiler compiler = Compiler::MSVC; +#endif + + SibsConfig sibsConfig(compiler, projectPath, optimizationLevel); Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if(result.isErr()) { - cerr << "Failed to read config: " << result.getErrMsg() << endl; + ferr << "Failed to read config: " << toFileString(result.getErrMsg()) << endl; exit(6); } if(sibsConfig.getPackageName().empty()) { - cerr << "project.conf is missing required field package.name" << endl; + ferr << "project.conf is missing required field package.name" << endl; exit(10); } @@ -216,7 +230,8 @@ int buildProject(int argc, const char **argv) { if (isSourceFile(file)) { - ninja.addSourceFile(file->path + sibsConfig.getProjectPath().size()); + string filePathUtf8 = toUtf8(file->path + sibsConfig.getProjectPath().size()); + ninja.addSourceFile(filePathUtf8.c_str()); } else { @@ -226,66 +241,69 @@ int buildProject(int argc, const char **argv) else { // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests - if(!sibsConfig.getTestPath().empty() && isPathSubPathOf(file->path, sibsConfig.getTestPath())) - ninja.addTestSourceDir(file->path); + if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(file->path, sibsConfig.getTestPath())) + { + string filePathUtf8 = toUtf8(file->path); + ninja.addTestSourceDir(filePathUtf8.c_str()); + } else walkDir(file->path, collectSourceFiles); } }; walkDir(projectPath.c_str(), collectSourceFiles); - string buildPath = projectPath + "/sibs-build/"; + FileString buildPath = projectPath + TINYDIR_STRING("/sibs-build/"); switch(sibsConfig.getOptimizationLevel()) { case OPT_LEV_DEBUG: - buildPath += "debug"; + buildPath += TINYDIR_STRING("debug"); break; case OPT_LEV_RELEASE: - buildPath += "release"; + buildPath += TINYDIR_STRING("release"); break; } Result buildFileResult = ninja.build(sibsConfig, buildPath.c_str()); if(buildFileResult.isErr()) { - cerr << "Failed to build ninja file: " << buildFileResult.getErrMsg() << endl; + ferr << "Failed to build ninja file: " << toFileString(buildFileResult.getErrMsg()) << endl; exit(7); } return 0; } -void newProjectCreateMainDir(const string &projectPath) +void newProjectCreateMainDir(const FileString &projectPath) { Result createProjectDirResult = createDirectoryRecursive(projectPath.c_str()); if(createProjectDirResult.isErr()) { - cerr << "Failed to create project main directory: " << createProjectDirResult.getErrMsg() << endl; + ferr << "Failed to create project main directory: " << toFileString(createProjectDirResult.getErrMsg()) << endl; exit(20); } } -void createProjectSubDir(const string &dir) +void createProjectSubDir(const FileString &dir) { Result createProjectDirResult = createDirectoryRecursive(dir.c_str()); if(createProjectDirResult.isErr()) { - cerr << "Failed to create directory in project: " << createProjectDirResult.getErrMsg() << endl; + ferr << "Failed to create directory in project: " << toFileString(createProjectDirResult.getErrMsg()) << endl; exit(20); } } -void createProjectFile(const string &projectFilePath, const string &fileContent) +void createProjectFile(const FileString &projectFilePath, const string &fileContent) { Result fileOverwriteResult = fileOverwrite(projectFilePath.c_str(), fileContent.c_str()); if(fileOverwriteResult.isErr()) { - cerr << "Failed to create project file: " << fileOverwriteResult.getErrMsg() << endl; + ferr << "Failed to create project file: " << toFileString(fileOverwriteResult.getErrMsg()) << endl; exit(20); } } -void newProjectCreateConf(const string &projectName, const string &projectType, const string &projectPath) +void newProjectCreateConf(const string &projectName, const string &projectType, const FileString &projectPath) { string projectConfStr = "[package]\n"; projectConfStr += "name = \"" + projectName + "\"\n"; @@ -293,98 +311,102 @@ void newProjectCreateConf(const string &projectName, const string &projectType, projectConfStr += "version = \"0.1.0\"\n\n"; projectConfStr += "[dependencies]\n"; - string projectConfPath = projectPath; - projectConfPath += "/project.conf"; + FileString projectConfPath = projectPath; + projectConfPath += TINYDIR_STRING("/project.conf"); Result fileOverwriteResult = fileOverwrite(projectConfPath.c_str(), projectConfStr.c_str()); if(fileOverwriteResult.isErr()) { - cerr << "Failed to create project.conf: " << fileOverwriteResult.getErrMsg() << endl; + ferr << "Failed to create project.conf: " << toFileString(fileOverwriteResult.getErrMsg()) << endl; exit(20); } } // This can be replaced with createDirectory and fileOverwrite, but it's not important // so there is no reason to do it (right now) -Result gitInitProject(const string &projectPath) +Result gitInitProject(const FileString &projectPath) { - string cmd = "git init '"; + FileString cmd = TINYDIR_STRING("git init \""); cmd += projectPath; - cmd += "'"; + cmd += TINYDIR_STRING("\""); return exec(cmd.c_str()); } -int newProject(int argc, const char **argv) +int newProject(int argc, const _tinydir_char_t **argv) { if(argc != 2) { - cerr << "Expected 'new' command to be followed by two arguments - project name and type of project (--exec, --static or --dynamic)" << endl << endl; + ferr << "Expected 'new' command to be followed by two arguments - project name and type of project (--exec, --static or --dynamic)" << endl << endl; usageNew(); } - Result cwdResult = getCwd(); + Result cwdResult = getCwd(); if(cwdResult.isErr()) { - cerr << "Failed to get current working directory: " << cwdResult.getErrMsg() << endl; + ferr << "Failed to get current working directory: " << toFileString(cwdResult.getErrMsg()) << endl; exit(20); } - string projectName = argv[0]; - string projectPath = cwdResult.unwrap(); - projectPath += "/"; - projectPath += projectName; + string projectName = toUtf8(argv[0]); + FileString projectPath = cwdResult.unwrap(); + projectPath += TINYDIR_STRING("/"); + projectPath += toFileString(projectName); bool projectPathExists = getFileType(projectPath.c_str()) != FileType::FILE_NOT_FOUND; if(projectPathExists) { - cerr << "Unable to create a new project at path '" << projectPath << "'. A file or directory already exists in the same location" << endl; + ferr << "Unable to create a new project at path '" << projectPath << "'. A file or directory already exists in the same location" << endl; exit(20); } - const char *projectType = argv[1]; + const _tinydir_char_t *projectType = argv[1]; string projectTypeConf; - if(strcmp(projectType, "--exec") == 0) + if(_tinydir_strcmp(projectType, TINYDIR_STRING("--exec")) == 0) projectTypeConf = "executable"; - else if(strcmp(projectType, "--static") == 0) + else if(_tinydir_strcmp(projectType, TINYDIR_STRING("--static")) == 0) projectTypeConf = "static"; - else if(strcmp(projectType, "--dynamic") == 0) + else if(_tinydir_strcmp(projectType, TINYDIR_STRING("--dynamic")) == 0) projectTypeConf = "dynamic"; else { - cerr << "Expected project type to be either --exec, --static or --dynamic; was: " << projectType << endl << endl; + ferr << "Expected project type to be either --exec, --static or --dynamic; was: " << projectType << endl << endl; usageNew(); } newProjectCreateMainDir(projectPath); newProjectCreateConf(projectName, projectTypeConf, projectPath); - createProjectSubDir(projectPath + "/src"); - createProjectSubDir(projectPath + "/include"); - createProjectFile(projectPath + "/src/main.cpp", "#include \n\nint main()\n{\n return 0;\n}\n"); + createProjectSubDir(projectPath + TINYDIR_STRING("/src")); + createProjectSubDir(projectPath + TINYDIR_STRING("/include")); + createProjectFile(projectPath + TINYDIR_STRING("/src/main.cpp"), "#include \n\nint main()\n{\n return 0;\n}\n"); // We are ignoring git init result on purpose. If it fails, just ignore it; not important gitInitProject(projectPath); return 0; } -int main(int argc, const char **argv) +#if OS_FAMILY == OS_FAMILY_POSIX +int main(int argc, const _tinydir_char_t **argv) +#else +int wmain(int argc, const _tinydir_char_t **argv) +#endif { unordered_map param; unordered_set flags; for(int i = 1; i < argc; ++i) { - const char *arg = argv[i]; + const _tinydir_char_t *arg = argv[i]; int subCommandArgCount = argc - i - 1; - const char **subCommandArgPtr = argv + i + 1; - if(strcmp(arg, "build") == 0) + const _tinydir_char_t **subCommandArgPtr = argv + i + 1; + if(_tinydir_strcmp(arg, TINYDIR_STRING("build")) == 0) { return buildProject(subCommandArgCount, subCommandArgPtr); } - else if(strcmp(arg, "new") == 0) + else if(_tinydir_strcmp(arg, TINYDIR_STRING("new")) == 0) { return newProject(subCommandArgCount, subCommandArgPtr); } else { - cerr << "Expected command to be either 'build' or 'new', was: " << arg << endl << endl; + ferr << "Expected command to be either 'build' or 'new', was: " << arg << endl << endl; usage(); } } -- cgit v1.2.3