#ifndef SIBS_CONF_HPP #define SIBS_CONF_HPP #include "FileUtil.hpp" #include "Result.hpp" #include "StringView.hpp" #include "utils.hpp" #include "Dependency.hpp" #include "Package.hpp" #include "Platform.hpp" #include "Version.hpp" #include #include #include #include namespace sibs { class ConfigValue { public: enum class Type { NONE, SINGLE, LIST, OBJECT }; ConfigValue() : type(Type::NONE) {} ConfigValue(StringView value) : type(Type::SINGLE) { values.push_back(value); } ConfigValue(const std::vector &_values) : type(Type::LIST), values(_values) { } ConfigValue(const std::unordered_map &_map) : type(Type::OBJECT), map(_map) { } bool isSingle() const { return type == Type::SINGLE; } bool isList() const { return type == Type::LIST; } bool isObject() const { return type == Type::OBJECT; } StringView asSingle() const { assert(isSingle()); return values[0]; } const std::vector asList() const { assert(isList()); return values; } const std::unordered_map& asObject() const { assert(isObject()); return map; } private: Type type; std::vector values; std::unordered_map map; }; class Parser; class ParserException : public std::runtime_error { public: ParserException(const std::string &errMsg) : runtime_error(errMsg) { } }; class ConfigCallback { friend class Parser; public: virtual ~ConfigCallback(){} protected: virtual void processObject(StringView name) = 0; virtual void processField(StringView name, const ConfigValue &value) = 0; virtual void finished() = 0; }; enum OptimizationLevel { OPT_LEV_NONE, OPT_LEV_DEBUG, OPT_LEV_RELEASE }; enum class Compiler { GCC, MSVC, MINGW_W64 }; enum class CVersion { C89, // aka ansi C99, C11 }; enum class CPPVersion { CPP11, CPP14, CPP17 }; enum class Language { NONE, C, CPP, ZIG }; struct SourceFile { Language language; std::string filepath; }; #if OS_TYPE == OS_TYPE_WINDOWS #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_WIN32; #else const Platform SYSTEM_PLATFORM = PLATFORM_WIN64; #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION L"lib" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION L"dll" #elif OS_TYPE == OS_TYPE_LINUX #ifdef SIBS_ARCH_ARM #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_LINUX_ARM32; #else const Platform SYSTEM_PLATFORM = PLATFORM_LINUX_ARM64; #endif #elif defined(SIBS_ARCH_X86) #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_LINUX_X86_32; #else const Platform SYSTEM_PLATFORM = PLATFORM_LINUX_X86_64; #endif #else #error "non arm/x86 linux platform" #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #ifdef __CYGWIN__ #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "dll" #else #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "so" #endif #elif OS_TYPE == OS_TYPE_APPLE #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_MACOS32; #else const Platform SYSTEM_PLATFORM = PLATFORM_MACOS64; #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "dylib" #elif OS_TYPE == OS_TYPE_OPENBSD #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_OPENBSD32; #else const Platform SYSTEM_PLATFORM = PLATFORM_OPENBSD64; #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "so" #elif OS_TYPE == OS_TYPE_HAIKU #ifdef SIBS_ENV_32BIT const Platform SYSTEM_PLATFORM = PLATFORM_HAIKU32; #else const Platform SYSTEM_PLATFORM = PLATFORM_HAIKU64; #endif #define CONFIG_STATIC_LIB_FILE_EXTENSION "a" #define CONFIG_DYNAMIC_LIB_FILE_EXTENSION "so" #endif const char* asString(OptimizationLevel optLevel); bool directoryToIgnore(const FileString &dir, const std::vector &ignoreDirList); bool isProjectNameValid(const std::string &projectName); enum class Sanitize { NONE, ADDRESS, UNDEFINED, LEAK, THREAD }; const Sanitize SANITIZE_INVALID = (Sanitize)-1; class SibsConfig : public ConfigCallback { public: SibsConfig(Compiler _compiler, const FileString &_projectPath, OptimizationLevel _optimizationLevel, bool _buildTests) : compiler(_compiler), projectPath(_projectPath), packageType((PackageType)-1), optimizationLevel(_optimizationLevel), finishedProcessing(false), useCmake(false), buildTests(_buildTests), cVersion(CVersion::C11), cppVersion(CPPVersion::CPP14), mainProject(false), sanitize(Sanitize::NONE), showWarnings(false), errorOnWarning(false), zigTestAllFiles(false), packaging(false), bundling(false), platform(SYSTEM_PLATFORM), use_flto(false) { cmakeDirGlobal = projectPath; switch(optimizationLevel) { case OPT_LEV_DEBUG: cmakeArgsGlobal = TINYDIR_STRING("-G Ninja \"-DCMAKE_BUILD_TYPE=Debug\""); break; case OPT_LEV_RELEASE: cmakeArgsGlobal = TINYDIR_STRING("-G Ninja \"-DCMAKE_BUILD_TYPE=Release\""); break; } } SibsConfig operator=(SibsConfig &other) = delete; virtual ~SibsConfig(); Compiler getCompiler() const { return compiler; } virtual const std::string& getPackageName() const { return packageName; } virtual PackageType getPackageType() const { return packageType; } virtual const FileString& getTestPath() const { return testPath; } void setTestPath(const FileString &testPath) { this->testPath = testPath; } virtual const std::vector& getPackageListDependencies() const { return packageListDependencies; } virtual const FileString& getProjectPath() const { return projectPath; } virtual const std::vector& getIncludeDirs() const { return includeDirs; } virtual const std::vector& getGlobalIncludeDirs() const { return exposeIncludeDirs; } virtual const std::vector& getLibs() const { return libs; } virtual const std::vector& getPlatforms() const { return platforms; } virtual OptimizationLevel getOptimizationLevel() const { return optimizationLevel; } const std::vector& getDebugStaticLibs() const { return debugStaticLibs; } const std::vector& getReleaseStaticLibs() const { return releaseStaticLibs; } const std::vector& getIgnoreDirs() const { return ignoreDirs; } const FileString& getCmakeDir() const { return cmakeDirGlobal; } const FileString& getCmakeDirStatic() const { return !cmakeDirStatic.empty() ? cmakeDirStatic : cmakeDirGlobal; } const FileString& getCmakeDirDynamic() const { return !cmakeDirDynamic.empty() ? cmakeDirDynamic : cmakeDirGlobal; } // Get cmake args for all builds. This is args under [cmake] only const FileString& getCmakeArgs() const { return cmakeArgsGlobal; } // Get cmake args for static build. This is a combination of args under [cmake] and under [cmake.static] FileString getCmakeArgsStatic() const { FileString result; result.reserve(cmakeArgsGlobal.size() + 1 + cmakeArgsStatic.size()); result += cmakeArgsGlobal; result += TINYDIR_STRING(" "); result += cmakeArgsStatic; return result; } // Get cmake args for dynamic build. This is a combination of args under [cmake] and under [cmake.dynamic] FileString getCmakeArgsDynamic() const { FileString result; result.reserve(cmakeArgsGlobal.size() + 1 + cmakeArgsDynamic.size()); result += cmakeArgsGlobal; result += TINYDIR_STRING(" "); result += cmakeArgsDynamic; return result; } CVersion getCversion() const { return cVersion; } CPPVersion getCppVersion() const { return cppVersion; } bool shouldUseCmake() const { return useCmake; } bool shouldBuildTests() const { return buildTests; } void setPackageType(PackageType packageType) { this->packageType = packageType; } bool isMainProject() const { return mainProject; } void setMainProject(bool mainProject) { this->mainProject = mainProject; } Sanitize getSanitize() const { return sanitize; } void setSanitize(Sanitize sanitize) { this->sanitize = sanitize; } virtual bool isDefined(const std::string &name) const; virtual bool define(const std::string &name, const std::string &value); virtual const std::unordered_map& getDefines() const; virtual bool isTest() const { return false; } // Get define value by name. // Return empty string if the value is empty or if the defined value doesn't exist const std::string& getDefinedValue(const std::string &name) const; std::vector zigTestFiles; bool showWarnings; bool errorOnWarning; bool zigTestAllFiles; bool packaging; bool bundling; std::string versionStr; PackageVersion version; Platform platform; bool use_flto; std::vector includeDirs; std::vector exposeIncludeDirs; std::vector ignoreDirs; std::vector libs; 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; void validatePackageTypeDefined() const; private: void parseCLang(const StringView &fieldName, const ConfigValue &fieldValue); void parseCppLang(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); void parseCmake(const StringView &fieldName, const ConfigValue &fieldValue, FileString &cmakeDir, FileString &cmakeArgs); void validatePackageName() const; protected: StringView currentObject; Compiler compiler; FileString projectPath; std::string packageName; FileString testPath; PackageType packageType; std::vector packageListDependencies; std::vector platforms; std::unordered_map defines; OptimizationLevel optimizationLevel; std::vector debugStaticLibs; std::vector releaseStaticLibs; FileString cmakeDirGlobal; FileString cmakeDirStatic; FileString cmakeDirDynamic; FileString cmakeArgsGlobal; FileString cmakeArgsStatic; FileString cmakeArgsDynamic; CVersion cVersion; CPPVersion cppVersion; bool useCmake; bool buildTests; bool finishedProcessing; bool mainProject; Sanitize sanitize; }; class SibsTestConfig : public SibsConfig { public: SibsTestConfig(Compiler _compiler, const FileString &_projectPath, OptimizationLevel _optimizationLevel) : SibsConfig(_compiler, _projectPath, _optimizationLevel, false) { packageName = "test"; showWarnings = true; } virtual ~SibsTestConfig(){} bool isTest() const override { return true; } PackageType getPackageType() const override { return PackageType::EXECUTABLE; } protected: void processObject(StringView name) override; void processField(StringView name, const ConfigValue &value) override; void finished() override; }; class Config { public: static Result readFromFile(const _tinydir_char_t *filepath, SibsConfig &config); }; void readSibsConfig(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig, FileString &buildPath); } #endif //SIBS_CONF_HPP