From 7c24c5d0de4d3584d6d2f9f3c26b4d757b0a0df2 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 10 Oct 2018 07:59:51 +0200 Subject: Fix sibs test not including parent library correctly Refactor config parsing to reduce number of changes when introducing a new platform to support --- backend/BackendUtils.cpp | 2 +- backend/ninja/Ninja.cpp | 264 +++++++++++---------- backend/ninja/Ninja.hpp | 10 +- include/Conf.hpp | 139 +---------- include/Platform.hpp | 17 +- include/StringView.hpp | 7 + src/Conf.cpp | 190 +++++++++------ src/Platform.cpp | 38 ++- src/main.cpp | 4 +- tests/src/confTest/confTest.cpp | 12 +- .../src/confTest/linux/x86/static/debug/libcool.a | 0 .../confTest/linux/x86/static/release/libcool.a | 0 12 files changed, 335 insertions(+), 348 deletions(-) create mode 100644 tests/src/confTest/linux/x86/static/debug/libcool.a create mode 100644 tests/src/confTest/linux/x86/static/release/libcool.a diff --git a/backend/BackendUtils.cpp b/backend/BackendUtils.cpp index d5fad04..b724f51 100644 --- a/backend/BackendUtils.cpp +++ b/backend/BackendUtils.cpp @@ -91,7 +91,7 @@ namespace backend if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath())) { string filePathUtf8 = toUtf8(pathNative.c_str()); - ninjaProject->addTestSourceDir(filePathUtf8.c_str()); + ninjaProject->setTestSourceDir(filePathUtf8.c_str()); } else if(recursive && !directoryToIgnore(pathNative, sibsConfig.getIgnoreDirs()) && _tinydir_strcmp(file->name, TINYDIR_STRING("sibs-build")) != 0) { diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index ef6c365..3a2fa0f 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -252,11 +252,11 @@ namespace backend sourceFiles.push_back({ language, filePathStr }); } - void Ninja::addTestSourceDir(const char *dir) + void Ninja::setTestSourceDir(const char *dir) { string dirStr = dir ? dir : ""; - if(dir && !containsTestSourceDir(dirStr)) - testSourceDirs.emplace_back(dirStr); + if(dir) + testSourceDir = dirStr; } void Ninja::addDependency(const std::string &binaryFile) @@ -264,6 +264,12 @@ namespace backend if(!containsDependency(binaryFile)) binaryDependencies.emplace_back(binaryFile); } + + void Ninja::addDynamicDependency(const std::string &dependency) + { + if(!containsDynamicDependency(dependency)) + dynamicDependencies.push_back(dependency); + } void Ninja::addSubProject(Ninja *subProject, SibsConfig *config, sibs::FileString &&buildPath) { @@ -285,21 +291,21 @@ namespace backend return false; } - bool Ninja::containsTestSourceDir(const string &dir) const + bool Ninja::containsDependency(const string &dependency) const { - for(const string &testSourceDir : testSourceDirs) + for(const string &binaryDependency : binaryDependencies) { - if(testSourceDir == dir) + if(binaryDependency == dependency) return true; } return false; } - bool Ninja::containsDependency(const string &dependency) const + bool Ninja::containsDynamicDependency(const std::string &dependency) const { - for(const string &binaryDependency : binaryDependencies) + for(const string &dynamicDependency : dynamicDependencies) { - if(binaryDependency == dependency) + if(dynamicDependency == dependency) return true; } return false; @@ -672,32 +678,41 @@ namespace backend return filepath.substr(0, it.base().base() - &filepath[0]); } - static string extractDynamicLibDirsFromLinkerFlags(const vector &linkerFlags) + static string extractDynamicLibDirsFromLinkerFlag(const string &linkerFlag) { string result; - for(const string &flag : linkerFlags) + + FileString flagNative; + if(linkerFlag.size() >= 2 && (linkerFlag[0] == '\'' || linkerFlag[0] == '"') && (linkerFlag.back() == '\'' || linkerFlag.back() == '"')) + flagNative = toFileString(StringView(&linkerFlag[1], linkerFlag.size() - 2)); + else + flagNative = toFileString(linkerFlag); + + if(getFileType(flagNative.c_str()) == FileType::REGULAR) { - FileString flagNative; - if(flag.size() >= 2 && (flag[0] == '\'' || flag[0] == '"') && (flag.back() == '\'' || flag.back() == '"')) - flagNative = toFileString(StringView(&flag[1], flag.size() - 2)); - else - flagNative = toFileString(flag); - - if(getFileType(flagNative.c_str()) == FileType::REGULAR) + Result libFullPath = getRealPath(flagNative.c_str()); + if(libFullPath) { - Result libFullPath = getRealPath(flagNative.c_str()); - if(libFullPath) + FileString libDir = getFileParentDirectory(libFullPath.unwrap()); + if(!libDir.empty()) { - FileString libDir = getFileParentDirectory(libFullPath.unwrap()); - if(!libDir.empty()) - { - if(!result.empty()); - result += ":"; - result += toUtf8(libDir); - } + result = toUtf8(libDir); } } } + + return result; + } + + static string extractDynamicLibDirsFromLinkerFlags(const vector &linkerFlags) + { + string result; + for(const string &flag : linkerFlags) + { + if(!result.empty()) + result += ":"; + result += extractDynamicLibDirsFromLinkerFlag(flag); + } return result; } @@ -866,6 +881,11 @@ namespace backend dynamicLinkerFlags.push_back(linkerFlag); }; } + + for(const string &dynamicDependency : dynamicDependencies) + { + dynamicLinkerFlagCallback(dynamicDependency); + } vector cflags; auto cflagsCallbackFunc = [&cflags](const string &dependencyCflags) @@ -1256,7 +1276,9 @@ namespace backend // TODO: For now zig projects (zig object files) are built with c/c++ compiler, // they should be built with zig if project only contains zig files. // But how to combine object files with zig? build-exe only wants to accept .zig files - string projectGeneratedBinaryFlags; + string projectGeneratedBinary = "\""; + projectGeneratedBinary += savePathUtf8; + projectGeneratedBinary += "/"; if (!sourceFiles.empty() && !zigTest) { string noUndefinedFlag; @@ -1268,10 +1290,6 @@ namespace backend noUndefinedFlag = isCCompilerClang ? "-Wl,-undefined,error" : "-Wl,--no-undefined,--as-needed"; } - string projectGeneratedBinary = "\""; - projectGeneratedBinary += savePathUtf8; - projectGeneratedBinary += "/"; - ninja::NinjaVariable zigObjectArgs("object_args"); string objectZigArgs; if(onlyZigFiles) @@ -1633,8 +1651,6 @@ namespace backend assert(false); return Result::Err("Unexpected error"); } - - projectGeneratedBinaryFlags = allLinkerFlags + " " + projectGeneratedBinary; } if(!sourceFiles.empty()) @@ -1656,16 +1672,16 @@ namespace backend } } - Result buildTestResult = buildTests(projectGeneratedBinaryFlags, config, savePath, dependencyExportIncludeDirs); + Result buildTestResult = buildTests(allLinkerFlags, projectGeneratedBinary, config, savePath, dependencyExportIncludeDirs); if(!buildTestResult) return buildTestResult; return Result::Ok(true); } - Result Ninja::buildTests(const std::string &projectGeneratedBinaryFlags, const SibsConfig &config, const _tinydir_char_t *savePath, const string &parentDependencyExportIncludeDirs) + Result Ninja::buildTests(const std::string &parentLinkerFlags, const std::string &parentGeneratedLib, const SibsConfig &config, const _tinydir_char_t *savePath, const string &parentDependencyExportIncludeDirs) { - if(testSourceDirs.empty() || !config.shouldBuildTests()) + if(testSourceDir.empty() || !config.shouldBuildTests()) return Result::Ok(true); assert(getNinjaLibraryType(config.getPackageType()) != LibraryType::EXECUTABLE); @@ -1682,105 +1698,115 @@ namespace backend parentExportIncludeDirs += getIncludeOptionFlag(config.getCompiler(), parentExportIncludeDir); } - for(const string &testSourceDir : testSourceDirs) - { #if OS_FAMILY == OS_FAMILY_POSIX - FileString testSourceDirNative = testSourceDir; - FileString projectConfFilePath = testSourceDir; + FileString testSourceDirNative = testSourceDir; + FileString projectConfFilePath = testSourceDir; #else - FileString testSourceDirNative = utf8To16(testSourceDir); - FileString projectConfFilePath = testSourceDirNative; + FileString testSourceDirNative = utf8To16(testSourceDir); + FileString projectConfFilePath = testSourceDirNative; #endif - projectConfFilePath += TINYDIR_STRING("/project.conf"); - - FileType projectConfFileType = getFileType(projectConfFilePath.c_str()); - SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative, config.getOptimizationLevel()); - sibsTestConfig.platform = config.platform; - sibsTestConfig.setSanitize(config.getSanitize()); - sibsTestConfig.zigTestFiles = move(config.zigTestFiles); - sibsTestConfig.zigTestAllFiles = config.zigTestAllFiles; - if(projectConfFileType == FileType::REGULAR) - { - Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig); - if(!result) - return result; - } + projectConfFilePath += TINYDIR_STRING("/project.conf"); + + FileType projectConfFileType = getFileType(projectConfFilePath.c_str()); + SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative, config.getOptimizationLevel()); + sibsTestConfig.platform = config.platform; + sibsTestConfig.setSanitize(config.getSanitize()); + sibsTestConfig.zigTestFiles = move(config.zigTestFiles); + sibsTestConfig.zigTestAllFiles = config.zigTestAllFiles; + if(projectConfFileType == FileType::REGULAR) + { + Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig); + if(!result) + return result; + } + + backend::Ninja ninja; + ninja.addGlobalIncludeDirs(parentExportIncludeDirs); + if(!parentLinkerFlags.empty()) + ninja.addDependency(parentLinkerFlags); - backend::Ninja ninja; - ninja.addGlobalIncludeDirs(parentExportIncludeDirs); - if(!projectGeneratedBinaryFlags.empty()) - ninja.addDependency(projectGeneratedBinaryFlags); + switch(config.getPackageType()) + { + case PackageType::STATIC: + ninja.addDependency(parentGeneratedLib); + break; + case PackageType::LIBRARY: + case PackageType::DYNAMIC: + ninja.addDynamicDependency(parentGeneratedLib); + break; + default: + break; + } - bool zigTest = false; - if(config.zigTestAllFiles) + bool zigTest = false; + if(config.zigTestAllFiles) + { + backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig); + // TODO: This can be optimized as well. No need to insert non-zig files if we are going to remove them. + // Maybe pass a filter callback function to @collectSourceFiles. + for(auto it = ninja.sourceFiles.begin(); it != ninja.sourceFiles.end(); ) { - backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig); - // TODO: This can be optimized as well. No need to insert non-zig files if we are going to remove them. - // Maybe pass a filter callback function to @collectSourceFiles. - for(auto it = ninja.sourceFiles.begin(); it != ninja.sourceFiles.end(); ) + if(it->language != sibs::Language::ZIG) { - if(it->language != sibs::Language::ZIG) - { - it = ninja.sourceFiles.erase(it); - } - else - { - ++it; - } + it = ninja.sourceFiles.erase(it); } - zigTest = true; - } - else if(!config.zigTestFiles.empty()) - { - ninja.sourceFiles.reserve(config.zigTestFiles.size()); - for(const sibs::FileString &testFile : config.zigTestFiles) + else { - ninja.addSourceFile(sibs::Language::ZIG, toUtf8(testFile.c_str()).c_str()); + ++it; } - zigTest = true; } - else + zigTest = true; + } + else if(!config.zigTestFiles.empty()) + { + ninja.sourceFiles.reserve(config.zigTestFiles.size()); + for(const sibs::FileString &testFile : config.zigTestFiles) { - backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig); + ninja.addSourceFile(sibs::Language::ZIG, toUtf8(testFile.c_str()).c_str()); } + zigTest = true; + } + else + { + backend::BackendUtils::collectSourceFiles(testSourceDirNative.c_str(), &ninja, sibsTestConfig); + } - if(!ninja.getSourceFiles().empty()) + if(!ninja.getSourceFiles().empty()) + { + FileString buildPath = testSourceDirNative; + switch(sibsTestConfig.getOptimizationLevel()) { - FileString buildPath = testSourceDirNative; - switch(sibsTestConfig.getOptimizationLevel()) - { - case OPT_LEV_DEBUG: - buildPath += TINYDIR_STRING("/sibs-build/debug"); - break; - case OPT_LEV_RELEASE: - buildPath += TINYDIR_STRING("/sibs-build/release"); - break; - } - - Result buildFileResult = ninja.build(sibsTestConfig, buildPath.c_str()); - if (!buildFileResult) + case OPT_LEV_DEBUG: + buildPath += TINYDIR_STRING("/sibs-build/debug"); + break; + case OPT_LEV_RELEASE: + buildPath += TINYDIR_STRING("/sibs-build/release"); + break; + } + + Result buildFileResult = ninja.build(sibsTestConfig, buildPath.c_str()); + if (!buildFileResult) + return buildFileResult; + + // Main projects test should also have compilation database, so we can use it inside IDE + if(config.isMainProject()) + { + buildFileResult = buildCompilationDatabase(buildPath.c_str(), testSourceDirNative); + if(!buildFileResult) return buildFileResult; - - // Main projects test should also have compilation database, so we can use it inside IDE - if(config.isMainProject()) - { - buildFileResult = buildCompilationDatabase(buildPath.c_str(), testSourceDirNative); - if(!buildFileResult) - return buildFileResult; - } + } - if(!zigTest) - { - FileString testExecutableName = buildPath; - testExecutableName += TINYDIR_STRING("/"); - testExecutableName += toFileString(sibsTestConfig.getPackageName()); - Result runTestResult = exec(testExecutableName.c_str(), true); - if(!runTestResult) - return Result::Err(runTestResult); - - if(runTestResult.unwrap().exitCode != 0) - return Result::Err("Tests failed", runTestResult.unwrap().exitCode); - } + if(!zigTest) + { + FileString testExecutableName = buildPath; + testExecutableName += TINYDIR_STRING("/"); + testExecutableName += toFileString(sibsTestConfig.getPackageName()); + Result runTestResult = exec(testExecutableName.c_str(), true); + if(!runTestResult) + return Result::Err(runTestResult); + + if(runTestResult.unwrap().exitCode != 0) + return Result::Err("Tests failed", runTestResult.unwrap().exitCode); } } diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index 8606708..2928fb3 100644 --- a/backend/ninja/Ninja.hpp +++ b/backend/ninja/Ninja.hpp @@ -43,25 +43,27 @@ namespace backend void addGlobalIncludeDirs(const std::string &globalIncludeDirs); void addSourceFile(sibs::Language language, const char *filepath); - void addTestSourceDir(const char *dir); + void setTestSourceDir(const char *dir); void addDependency(const std::string &binaryFile); + void addDynamicDependency(const std::string &dependency); void addSubProject(Ninja *subProject, sibs::SibsConfig *config, sibs::FileString &&buildPath); const std::vector& getSourceFiles() const; sibs::Result build(const sibs::SibsConfig &config, const _tinydir_char_t *savePath, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc = nullptr, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback = nullptr, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback = nullptr); private: sibs::Result buildSubProjects(sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback); - sibs::Result buildTests(const std::string &projectGeneratedBinaryFlags, const sibs::SibsConfig &config, const _tinydir_char_t *savePath, const std::string &parentDependencyExportIncludeDirs); + sibs::Result buildTests(const std::string &parentLinkerFlags, const std::string &parentGeneratedLib, const sibs::SibsConfig &config, const _tinydir_char_t *savePath, const std::string &parentDependencyExportIncludeDirs); bool containsSourceFile(const std::string &filepath) const; - bool containsTestSourceDir(const std::string &dir) const; bool containsDependency(const std::string &dependency) const; + bool containsDynamicDependency(const std::string &dependency) const; sibs::Result getLinkerFlags(const sibs::SibsConfig &config, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback, sibs::GlobalIncludeDirCallbackFunc globalIncludeDirCallback, sibs::CflagsCallbackFunc cflagsCallbackFunc) const; sibs::Result compile(const _tinydir_char_t *buildFilePath); sibs::Result buildCompilationDatabase(const _tinydir_char_t *buildFilePath, const sibs::FileString &savePath); private: std::string customGlobalIncludeDirs; + std::string testSourceDir; std::vector sourceFiles; - std::vector testSourceDirs; std::vector binaryDependencies; + std::vector dynamicDependencies; std::vector subProjects; }; } diff --git a/include/Conf.hpp b/include/Conf.hpp index bae0153..a60bc36 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -138,181 +138,47 @@ namespace sibs Language language; std::string filepath; }; - - const StringView CONFIGS[] = { - "config.win", - "config.win.static.debug", - "config.win.static.release", - - "config.linux", - "config.linux.static.debug", - "config.linux.static.release", - - "config.macos", - "config.macos.static.debug", - "config.macos.static.release", - - "config.bsd", - "config.bsd.static.debug", - "config.bsd.static.release", - - "config.openbsd", - "config.openbsd.static.debug", - "config.openbsd.static.release", - - "config.haiku", - "config.haiku.static.debug", - "config.haiku.static.release", - - "config.win32", - "config.win32.static.debug", - "config.win32.static.release", - - "config.win64", - "config.win64.static.debug", - "config.win64.static.release", - - "config.linux32", - "config.linux32.static.debug", - "config.linux32.static.release", - - "config.linux64", - "config.linux64.static.debug", - "config.linux64.static.release", - - "config.macos32", - "config.macos32.static.debug", - "config.macos32.static.release" - - "config.macos64", - "config.macos64.static.debug", - "config.macos64.static.release", - - "config.openbsd32", - "config.openbsd32.static.debug", - "config.openbsd32.static.release", - - "config.openbsd64", - "config.openbsd64.static.debug", - "config.openbsd64.static.release", - - "config.haiku32", - "config.haiku32.static.debug", - "config.haiku32.static.release", - - "config.haiku64", - "config.haiku64.static.debug", - "config.haiku64.static.release" - }; - const int NUM_CONFIGS = 3 * 16; - const int CONFIGS_GENERIC_OFFSET = 3 * 6; #if OS_TYPE == OS_TYPE_WINDOWS #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_WIN32; - #define SYSTEM_PLATFORM_NAME L"win32" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 0 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 1 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 2 #else const Platform SYSTEM_PLATFORM = PLATFORM_WIN64; - #define SYSTEM_PLATFORM_NAME L"win64" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 3 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 4 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 5 #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION L"lib" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION L"dll" - - #define SYSTEM_GENERIC_PLATFORM_NAME "win" - #define CONFIG_GENERIC_SYSTEM_PLATFORM 0 - #define CONFIG_GENERIC_STATIC_DEBUG_PLATFORM 1 - #define CONFIG_GENERIC_STATIC_RELEASE_PLATFORM 2 #elif OS_TYPE == OS_TYPE_LINUX #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_LINUX32; - #define SYSTEM_PLATFORM_NAME "linux32" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 6 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 7 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 8 #else const Platform SYSTEM_PLATFORM = PLATFORM_LINUX64; - #define SYSTEM_PLATFORM_NAME "linux64" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 9 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 10 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 11 #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "so" - - #define SYSTEM_GENERIC_PLATFORM_NAME "linux" - #define CONFIG_GENERIC_SYSTEM_PLATFORM 3 - #define CONFIG_GENERIC_STATIC_DEBUG_PLATFORM 4 - #define CONFIG_GENERIC_STATIC_RELEASE_PLATFORM 5 #elif OS_TYPE == OS_TYPE_APPLE #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_MACOS32; - #define SYSTEM_PLATFORM_NAME "macos32" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 12 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 13 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 14 #else const Platform SYSTEM_PLATFORM = PLATFORM_MACOS64; - #define SYSTEM_PLATFORM_NAME "macos64" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 15 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 16 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 17 #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "dylib" - - #define SYSTEM_GENERIC_PLATFORM_NAME "macos" - #define CONFIG_GENERIC_SYSTEM_PLATFORM 6 - #define CONFIG_GENERIC_STATIC_DEBUG_PLATFORM 7 - #define CONFIG_GENERIC_STATIC_RELEASE_PLATFORM 8 #elif OS_TYPE == OS_TYPE_OPENBSD #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_OPENBSD32; - #define SYSTEM_PLATFORM_NAME "openbsd32" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 18 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 19 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 20 #else const Platform SYSTEM_PLATFORM = PLATFORM_OPENBSD64; - #define SYSTEM_PLATFORM_NAME "openbsd64" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 21 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 22 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 23 #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "so" - - // TODO: Also add "bsd" platform - #define SYSTEM_GENERIC_PLATFORM_NAME "openbsd" - #define CONFIG_GENERIC_SYSTEM_PLATFORM 12 - #define CONFIG_GENERIC_STATIC_DEBUG_PLATFORM 13 - #define CONFIG_GENERIC_STATIC_RELEASE_PLATFORM 14 #elif OS_TYPE == OS_TYPE_HAIKU #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_HAIKU32; - #define SYSTEM_PLATFORM_NAME "haiku32" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 24 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 25 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 26 #else const Platform SYSTEM_PLATFORM = PLATFORM_HAIKU64; - #define SYSTEM_PLATFORM_NAME "haiku64" - #define CONFIG_SYSTEM_PLATFORM CONFIGS_GENERIC_OFFSET + 27 - #define CONFIG_STATIC_DEBUG_PLATFORM CONFIGS_GENERIC_OFFSET + 28 - #define CONFIG_STATIC_RELEASE_PLATFORM CONFIGS_GENERIC_OFFSET + 29 #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "so" - - #define SYSTEM_GENERIC_PLATFORM_NAME "haiku" - #define CONFIG_GENERIC_SYSTEM_PLATFORM 15 - #define CONFIG_GENERIC_STATIC_DEBUG_PLATFORM 16 - #define CONFIG_GENERIC_STATIC_RELEASE_PLATFORM 17 #endif const char* asString(OptimizationLevel optLevel); @@ -365,13 +231,11 @@ namespace sibs virtual const std::string& getPackageName() const { - assert(finishedProcessing); return packageName; } virtual PackageType getPackageType() const { - assert(finishedProcessing); return packageType; } @@ -543,6 +407,7 @@ namespace sibs protected: virtual void processObject(StringView name) override; virtual void processField(StringView name, const ConfigValue &value) override; + void parseConfig(const StringView &name, const ConfigValue &value); void parseDependencies(const StringView &name, const ConfigValue &value); virtual void finished() override; void failInvalidFieldUnderObject(const StringView &fieldName) const; @@ -550,7 +415,7 @@ namespace sibs private: void parseCLang(const StringView &fieldName, const ConfigValue &fieldValue); void parseCppLang(const StringView &fieldName, const ConfigValue &fieldValue); - void parsePlatformBuildTypeConfigs(const StringView &fieldName, const ConfigValue &fieldValue); + void parsePlatformConfig(const StringView &fieldName, const ConfigValue &fieldValue); std::string parsePlatformConfigStatic(const StringView &fieldName, const ConfigValue &fieldValue); void parsePlatformConfigStaticDebug(const StringView &fieldName, const ConfigValue &fieldValue); void parsePlatformConfigStaticRelease(const StringView &fieldName, const ConfigValue &fieldValue); diff --git a/include/Platform.hpp b/include/Platform.hpp index ffe7038..3ae3d24 100644 --- a/include/Platform.hpp +++ b/include/Platform.hpp @@ -29,9 +29,9 @@ namespace sibs PLATFORM_OPENBSD32 = 1 << 12 | PLATFORM_OPENBSD, PLATFORM_OPENBSD64 = 1 << 13 | PLATFORM_OPENBSD, - PLATFORM_HAIKU = 1 << 20, - PLATFORM_HAIKU32 = 1 << 21 | PLATFORM_HAIKU, - PLATFORM_HAIKU64 = 1 << 22 | PLATFORM_HAIKU + PLATFORM_HAIKU = 1 << 20, + PLATFORM_HAIKU32 = 1 << 21 | PLATFORM_HAIKU, + PLATFORM_HAIKU64 = 1 << 22 | PLATFORM_HAIKU }; const StringViewMap PLATFORM_BY_NAME = { @@ -49,13 +49,18 @@ namespace sibs { "openbsd", PLATFORM_OPENBSD }, { "openbsd32", PLATFORM_OPENBSD32 }, { "openbsd64", PLATFORM_OPENBSD64 }, - { "haiku", PLATFORM_HAIKU }, - { "haiku32", PLATFORM_HAIKU32 }, - { "haiku64", PLATFORM_HAIKU64 }, + { "haiku", PLATFORM_HAIKU }, + { "haiku32", PLATFORM_HAIKU32 }, + { "haiku64", PLATFORM_HAIKU64 }, }; bool containsPlatform(const std::vector &platforms, Platform platform); const char* asString(Platform platform); Platform getPlatformByName(StringView name); + // Return true if both platforms are of same type, for example if platform @a is either win, win32, win64 and @b is either win, win32, win64 bool isSamePlatformFamily(Platform a, Platform b); + // Returns true if platform @base is a base platform for platform @platform, for example if @platform is win64 and @base is either win64 or win, then this function return true. + // If for example @platform is win64 and @base is win32, then this function returns false. + bool isBaseForPlatform(Platform base, Platform platform); + Platform getPlatformGenericType(Platform platform); } diff --git a/include/StringView.hpp b/include/StringView.hpp index adfa237..4d87d8a 100644 --- a/include/StringView.hpp +++ b/include/StringView.hpp @@ -7,6 +7,7 @@ #include "env.hpp" #include #include +#include namespace sibs { @@ -47,6 +48,12 @@ namespace sibs return XXH32(data, size, 0xdec05eba); #endif } + + char operator [] (size_t index) const + { + assert(index < size); + return data[index]; + } const char *data; usize size; diff --git a/src/Conf.cpp b/src/Conf.cpp index 38774e0..0307bc0 100644 --- a/src/Conf.cpp +++ b/src/Conf.cpp @@ -80,8 +80,12 @@ namespace sibs char *startOfIdentifier = code.base(); ++code; c = *code; + char prevChar = '\0'; while(isIdentifierChar(c)) { + if(c == '.' && prevChar == '.') + throw UnexpectedTokenException("Identifier can't have two dots in a row"); + prevChar = c; ++code; c = *code; } @@ -863,59 +867,12 @@ namespace sibs } else if(currentObject.size >= 6 && strncmp(currentObject.data, "config", 6) == 0) { - bool platformConfig = currentObject.equals(CONFIGS[CONFIG_SYSTEM_PLATFORM]); - if(currentObject.size == 6 || platformConfig) // [config] + if(currentObject.size == 6) // [config] { - if(name.equals("expose_include_dirs")) - { - if (value.isList()) - { - for (const StringView &includeDir : value.asList()) - { - exposeIncludeDirs.emplace_back(string(includeDir.data, includeDir.size)); - } - } - else - { - string errMsg = "Expected "; - errMsg += string(currentObject.data, currentObject.size); - errMsg += " to be a list, was a single value"; - throw ParserException(errMsg); - } - } - else if(name.equals("include_dirs")) - { - if(value.isList()) - { - for(const StringView &includeDir : value.asList()) - { - includeDirs.emplace_back(string(includeDir.data, includeDir.size)); - } - } - else - throw ParserException("Expected " + string(currentObject.data, currentObject.size) + ".include_dirs to be a list, was a single value"); - } - else if(name.equals("ignore_dirs")) - { - if (value.isList()) - { - string projectPathUtf8 = toUtf8(projectPath); - for (const StringView &ignoreDir : value.asList()) - { - string ignoreDirFull = projectPathUtf8; - ignoreDirFull += "/"; - ignoreDirFull += string(ignoreDir.data, ignoreDir.size); - ignoreDirs.emplace_back(move(ignoreDirFull)); - } - } - else - throw ParserException("Expected " + string(currentObject.data, currentObject.size) + ".ignore_dirs to be a list, was a single value"); - } - else - failInvalidFieldUnderObject(name); + parseConfig(name, value); } else - parsePlatformBuildTypeConfigs(name, value); + parsePlatformConfig(name, value); } else if(currentObject.equals("dependencies")) { @@ -1012,6 +969,57 @@ namespace sibs throw ParserException(errMsg); } } + + void SibsConfig::parseConfig(const StringView &name, const ConfigValue &value) + { + if(name.equals("expose_include_dirs")) + { + if (value.isList()) + { + for (const StringView &includeDir : value.asList()) + { + exposeIncludeDirs.emplace_back(string(includeDir.data, includeDir.size)); + } + } + else + { + string errMsg = "Expected "; + errMsg += string(currentObject.data, currentObject.size); + errMsg += " to be a list, was a single value"; + throw ParserException(errMsg); + } + } + else if(name.equals("include_dirs")) + { + if(value.isList()) + { + for(const StringView &includeDir : value.asList()) + { + includeDirs.emplace_back(string(includeDir.data, includeDir.size)); + } + } + else + throw ParserException("Expected " + string(currentObject.data, currentObject.size) + ".include_dirs to be a list, was a single value"); + } + else if(name.equals("ignore_dirs")) + { + if (value.isList()) + { + string projectPathUtf8 = toUtf8(projectPath); + for (const StringView &ignoreDir : value.asList()) + { + string ignoreDirFull = projectPathUtf8; + ignoreDirFull += "/"; + ignoreDirFull += string(ignoreDir.data, ignoreDir.size); + ignoreDirs.emplace_back(move(ignoreDirFull)); + } + } + else + throw ParserException("Expected " + string(currentObject.data, currentObject.size) + ".ignore_dirs to be a list, was a single value"); + } + else + failInvalidFieldUnderObject(name); + } void SibsConfig::parseDependencies(const StringView &name, const ConfigValue &value) { @@ -1171,39 +1179,75 @@ namespace sibs else failInvalidFieldUnderObject(fieldName); } - - void SibsConfig::parsePlatformBuildTypeConfigs(const StringView &fieldName, const ConfigValue &fieldValue) + + static bool isObjectIdentifierSymbol(char c) { - bool validConfig = false; - for(int i = 0; i < NUM_CONFIGS; ++i) + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-'; + } + + static StringView getNextIdentifierInObject(const StringView &objectName) + { + size_t identifierStart = -1; + for(size_t i = 0; i < objectName.size; ++i) { - const StringView &config = CONFIGS[i]; - if(currentObject.equals(config)) + char c = objectName[i]; + if(c == '.') { - validConfig = true; - switch(i) - { - case CONFIG_GENERIC_STATIC_DEBUG_PLATFORM: - case CONFIG_STATIC_DEBUG_PLATFORM: - parsePlatformConfigStaticDebug(fieldName, fieldValue); - break; - case CONFIG_GENERIC_STATIC_RELEASE_PLATFORM: - case CONFIG_STATIC_RELEASE_PLATFORM: - parsePlatformConfigStaticRelease(fieldName, fieldValue); - break; - default: - break; - } + if(identifierStart == -1) + identifierStart = i + 1; + else + return { objectName.data + identifierStart, i - identifierStart }; } } - - if(!validConfig) + + if(identifierStart == -1) + return { objectName.data + objectName.size, 0 }; + else + return { objectName.data + identifierStart, objectName.size - identifierStart }; + } + + void SibsConfig::parsePlatformConfig(const StringView &fieldName, const ConfigValue &fieldValue) + { + StringView platformName = getNextIdentifierInObject(currentObject); + Platform platform = getPlatformByName(platformName); + + if(platform == PLATFORM_INVALID) { string errMsg = "Invalid config object \""; errMsg += string(currentObject.data, currentObject.size); - errMsg += "\""; + errMsg += "\", invalid platform: "; + errMsg += string(platformName.data, platformName.size); throw ParserException(errMsg); } + + if(!isBaseForPlatform(platform, SYSTEM_PLATFORM)) + return; + + const char *start = platformName.data + platformName.size; + const char *currentObjEnd = currentObject.data + currentObject.size; + if(start < currentObjEnd) + { + size_t size = currentObjEnd - start; + StringView platformConfigType = { start, size }; + + if(size == 13 && strncmp(platformConfigType.data, ".static.debug", 13) == 0) + { + parsePlatformConfigStaticDebug(fieldName, fieldValue); + } + else if(size == 15 && strncmp(platformConfigType.data, ".static.release", 15) == 0) + { + parsePlatformConfigStaticRelease(fieldName, fieldValue); + } + else + { + string errMsg = "Invalid config object \""; + errMsg += string(currentObject.data, currentObject.size); + errMsg += "\""; + throw ParserException(errMsg); + } + } + else + parseConfig(fieldName, fieldValue); } string SibsConfig::parsePlatformConfigStatic(const StringView &fieldName, const ConfigValue &fieldValue) diff --git a/src/Platform.cpp b/src/Platform.cpp index 9b02ca5..dd81667 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -1,7 +1,31 @@ #include "../include/Platform.hpp" +#include namespace sibs { + static int countSetBits(u32 value) + { + int count = 0; + while(value) + { + count += (value & 1U); + value >>= 1U; + } + return count; + } + + // Returns -1 if no bit is set + static int getLeastSignificantBitSetPosition(u32 value) + { + for(u32 i = 0; i < sizeof(u32); ++i) + { + if(value & 1U) + return i; + value >>= 1U; + } + return -1; + } + bool containsPlatform(const std::vector &platforms, Platform platform) { for (Platform vecPlatform : platforms) @@ -33,7 +57,7 @@ namespace sibs case PLATFORM_HAIKU: return "haiku"; case PLATFORM_HAIKU32: return "haiku32"; case PLATFORM_HAIKU64: return "haiku64"; - default: return nullptr; + default: assert(false); return nullptr; } } @@ -49,4 +73,16 @@ namespace sibs { return a & b; } + + bool isBaseForPlatform(Platform base, Platform platform) + { + return base == PLATFORM_ANY || base == platform || (isSamePlatformFamily(platform, base) && countSetBits(base) < countSetBits(platform)); + } + + Platform getPlatformGenericType(Platform platform) + { + if(platform == PLATFORM_INVALID || platform == PLATFORM_ANY) + return PLATFORM_INVALID; + return (Platform)(1U << (u32)getLeastSignificantBitSetPosition(platform)); + } } diff --git a/src/main.cpp b/src/main.cpp index b05cded..b3a8f40 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -503,7 +503,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv) optimizationLevel = OPT_LEV_DEBUG; if(!platformName) - platformName = SYSTEM_PLATFORM_NAME; + platformName = asString(SYSTEM_PLATFORM); string platformUtf8 = toUtf8(platformName); Platform platform = getPlatformByName(StringView(platformUtf8.data(), platformUtf8.size())); @@ -718,7 +718,7 @@ static Result newProjectCreateConf(const string &projectName, const string projectConfStr += "name = \"" + projectName + "\"\n"; projectConfStr += "type = \"" + projectType + "\"\n"; projectConfStr += "version = \"0.1.0\"\n"; - projectConfStr += "platforms = [\"" + string(SYSTEM_GENERIC_PLATFORM_NAME) + "\"]\n\n"; + projectConfStr += "platforms = [\"" + string(asString(getPlatformGenericType(SYSTEM_PLATFORM))) + "\"]\n\n"; projectConfStr += "[dependencies]\n"; FileString projectConfPath = projectPath; diff --git a/tests/src/confTest/confTest.cpp b/tests/src/confTest/confTest.cpp index b5d5ae1..8dab691 100644 --- a/tests/src/confTest/confTest.cpp +++ b/tests/src/confTest/confTest.cpp @@ -83,11 +83,13 @@ TEST_CASE("parse config - use different config for different platforms") } #if OS_TYPE == OS_TYPE_LINUX and defined(SIBS_ENV_64BIT) - #ifdef DEBUG - REQUIRE(sibsConfig.getDebugStaticLibs()[0] == TINYDIR_STRING("tests/src/confTest/linux/x64/static/debug/libcool.a")); - #else - REQUIRE(sibsConfig.getDebugStaticLibs()[0] == TINYDIR_STRING("tests/src/confTest/linux/x64/static/release/libcool.a")); - #endif + REQUIRE(sibsConfig.getDebugStaticLibs()[0] == TINYDIR_STRING("tests/src/confTest/linux/x64/static/debug/libcool.a")); + REQUIRE(sibsConfig.getReleaseStaticLibs()[0] == TINYDIR_STRING("tests/src/confTest/linux/x64/static/release/libcool.a")); + REQUIRE(sibsConfig.getGlobalIncludeDirs()[0] == "include_linux64"); + #elif OS_TYPE == OS_TYPE_LINUX and defined(SIBS_ENV_32BIT) + REQUIRE(sibsConfig.getDebugStaticLibs()[0] == TINYDIR_STRING("tests/src/confTest/linux/x86/static/debug/libcool.a")); + REQUIRE(sibsConfig.getReleaseStaticLibs()[0] == TINYDIR_STRING("tests/src/confTest/linux/x86/static/release/libcool.a")); + REQUIRE(sibsConfig.getGlobalIncludeDirs()[0] == "include_linux32"); #endif } diff --git a/tests/src/confTest/linux/x86/static/debug/libcool.a b/tests/src/confTest/linux/x86/static/debug/libcool.a new file mode 100644 index 0000000..e69de29 diff --git a/tests/src/confTest/linux/x86/static/release/libcool.a b/tests/src/confTest/linux/x86/static/release/libcool.a new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3