From 1f583ebb6e3973c992d59886659bf53ff87f41de Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 28 Dec 2017 16:57:06 +0100 Subject: Add optimization level option to building --- backend/ninja/Ninja.cpp | 22 ++++++++++---- backend/ninja/Ninja.hpp | 2 +- include/Conf.hpp | 17 ++++++++++- include/GlobalLib.hpp | 3 +- src/Conf.cpp | 10 +++++++ src/GlobalLib.cpp | 22 ++++++++++---- src/main.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 131 insertions(+), 25 deletions(-) diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 3c2b848..ddc20dd 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -121,8 +121,9 @@ namespace backend // 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 vector &dependencies, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const + Result Ninja::getLinkerFlags(const SibsConfig &config, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const { + const vector &dependencies = config.getDependencies(); if(dependencies.empty()) return Result::Ok(true); string globalLibDir = getHomeDir(); @@ -166,7 +167,7 @@ namespace backend for(const Dependency &globalLibDependency : globalLibDependencies) { printf("Dependency %s is missing from pkg-config, trying global lib\n", globalLibDependency.name.c_str()); - Result globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); + Result globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); if(globalLibLinkerFlagsResult.isErr()) { if(globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_NOT_FOUND || globalLibLinkerFlagsResult.getErrorCode() == GlobalLib::DependencyError::DEPENDENCY_VERSION_NO_MATCH) @@ -185,7 +186,7 @@ namespace backend if(downloadDependencyResult.isErr()) return downloadDependencyResult; - globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); + globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(config, globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); if(globalLibLinkerFlagsResult.isErr()) return Result::Err(globalLibLinkerFlagsResult); } @@ -271,6 +272,17 @@ namespace backend return Result::Err("Unexpected error"); } + string optimizationFlags; + switch(config.getOptimizationLevel()) + { + case OPT_LEV_DEBUG: + optimizationFlags = "'-O0'"; + break; + case OPT_LEV_RELEASE: + optimizationFlags = "'-O3' '-DNDEBUG'"; + break; + } + vector objectNames; objectNames.reserve(sourceFiles.size()); for(const string &sourceFile : sourceFiles) @@ -283,7 +295,7 @@ namespace backend 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' '-O0' '-g'\n\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"; objectNames.emplace_back(objectName); } @@ -314,7 +326,7 @@ namespace backend allLinkerFlags += linkerFlag; }; - Result linkerFlags = getLinkerFlags(config.getDependencies(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); + Result linkerFlags = getLinkerFlags(config, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); if(linkerFlags.isErr()) return Result::Err(linkerFlags.getErrMsg()); diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index ea73c81..fddcaf3 100644 --- a/backend/ninja/Ninja.hpp +++ b/backend/ninja/Ninja.hpp @@ -34,7 +34,7 @@ namespace backend 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 std::vector &dependencies, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const; + sibs::Result getLinkerFlags(const sibs::SibsConfig &config, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const; sibs::Result build(const char *buildFilePath); private: std::vector sourceFiles; diff --git a/include/Conf.hpp b/include/Conf.hpp index b893d3a..1f680e8 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -84,10 +84,19 @@ namespace sibs static Result readFromFile(const char *filepath, const ConfigCallback &callback); }; + enum OptimizationLevel + { + OPT_LEV_NONE, + OPT_LEV_DEBUG, + OPT_LEV_RELEASE + }; + + const char* asString(OptimizationLevel optLevel); + class SibsConfig : public ConfigCallback { public: - SibsConfig(const std::string &_projectPath) : projectPath(_projectPath), finishedProcessing(false), packageType((PackageType)-1) {} + SibsConfig(const std::string &_projectPath, OptimizationLevel _optimizationLevel = OPT_LEV_DEBUG) : projectPath(_projectPath), packageType((PackageType)-1), optimizationLevel(_optimizationLevel), finishedProcessing(false) {} virtual ~SibsConfig(){} virtual const std::string& getPackageName() const @@ -121,6 +130,11 @@ namespace sibs { return includeDirs; } + + virtual OptimizationLevel getOptimizationLevel() const + { + return optimizationLevel; + } protected: virtual void processObject(StringView name) override; virtual void processField(StringView name, const ConfigValue &value) override; @@ -133,6 +147,7 @@ namespace sibs PackageType packageType; std::vector dependencies; std::vector includeDirs; + OptimizationLevel optimizationLevel; bool finishedProcessing; }; diff --git a/include/GlobalLib.hpp b/include/GlobalLib.hpp index 78511c3..c67027e 100644 --- a/include/GlobalLib.hpp +++ b/include/GlobalLib.hpp @@ -4,6 +4,7 @@ #include "Result.hpp" #include "Linker.hpp" #include "Dependency.hpp" +#include "Conf.hpp" namespace sibs { @@ -17,7 +18,7 @@ namespace sibs }; static Result validatePackageExists(const std::string &globalLibRootDir, const std::string &name); - static Result getLibsLinkerFlags(const std::string &globalLibRootDir, const std::string &name, const std::string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc); + static Result getLibsLinkerFlags(const SibsConfig &parentConfig, const std::string &globalLibRootDir, const std::string &name, const std::string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc); static Result downloadDependency(const Dependency &dependency); }; } diff --git a/src/Conf.cpp b/src/Conf.cpp index 97d562c..d6aee2c 100644 --- a/src/Conf.cpp +++ b/src/Conf.cpp @@ -332,6 +332,16 @@ namespace sibs return Parser::parse(code, callback); } + const char* asString(OptimizationLevel optLevel) + { + switch(optLevel) + { + case OPT_LEV_NONE: return "none"; + case OPT_LEV_DEBUG: return "debug"; + case OPT_LEV_RELEASE: return "release"; + } + } + void SibsConfig::processObject(StringView name) { currentObject = name; diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp index 30a044f..d994a27 100644 --- a/src/GlobalLib.cpp +++ b/src/GlobalLib.cpp @@ -60,7 +60,7 @@ namespace sibs return _tinydir_strncmp(path, subPathOf.c_str(), subPathOf.size()) == 0; } - Result GlobalLib::getLibsLinkerFlags(const string &globalLibRootDir, const string &name, const string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc) + Result GlobalLib::getLibsLinkerFlags(const SibsConfig &parentConfig, const string &globalLibRootDir, const string &name, const string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc) { Result packageExistsResult = validatePackageExists(globalLibRootDir, name); if(packageExistsResult.isErr()) @@ -110,7 +110,7 @@ namespace sibs } } - SibsConfig sibsConfig(packageDir); + SibsConfig sibsConfig(packageDir, parentConfig.getOptimizationLevel()); Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if(result.isErr()) return Result::Err(result.getErrMsg()); @@ -175,8 +175,18 @@ namespace sibs } else { - string debugBuildPath = packageDir + "/sibs-build/debug"; - string libPath = debugBuildPath; + string buildPath = packageDir + "/sibs-build/"; + switch(sibsConfig.getOptimizationLevel()) + { + case OPT_LEV_DEBUG: + buildPath += "debug"; + break; + case OPT_LEV_RELEASE: + buildPath += "release"; + break; + } + + string libPath = buildPath; libPath += "/lib"; libPath += name; if(libraryType == backend::Ninja::LibraryType::STATIC) @@ -199,11 +209,11 @@ namespace sibs // TODO: Use different directories depending on the project type, but .o build files should be in the same directory // no matter what project type, since they are used for executables, static/dynamic libraries - Result createBuildDirResult = createDirectoryRecursive(debugBuildPath.c_str()); + Result createBuildDirResult = createDirectoryRecursive(buildPath.c_str()); if(createBuildDirResult.isErr()) return Result::Err(createBuildDirResult); - Result buildFileResult = ninja.build(sibsConfig, debugBuildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc); + Result buildFileResult = ninja.build(sibsConfig, buildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc); if (buildFileResult.isErr()) return Result::Err(buildFileResult.getErrMsg()); diff --git a/src/main.cpp b/src/main.cpp index 79d4d9d..0f20ea0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,21 @@ void usage() exit(1); } +void usageBuild() +{ + printf("Usage: sibs build [project_path] [--debug|--release]\n\n"); + printf("Build a sibs project\n\n"); + printf("Options:\n"); + printf(" project_path\t\t The directory containing a project.conf file - Optional (default: current working directory)\n"); + printf(" --debug|--release\t\tOptimization level to build project and dependencies with (if not a system package) - Optional (default: --debug)\n"); + printf("Examples:\n"); + printf(" sibs build\n"); + printf(" sibs build dirA/dirB\n"); + printf(" sibs build --release\n"); + printf(" sibs build dirA --release\n"); + exit(1); +} + void usageNew() { printf("Usage: sibs new <--exec|--static|--dynamic>\n\n"); @@ -100,17 +115,50 @@ bool isPathSubPathOf(const string &path, const string &subPathOf) int buildProject(int argc, const char **argv) { - if(argc > 1) + if(argc > 2) + usageBuild(); + + OptimizationLevel optimizationLevel = OPT_LEV_NONE; + string projectPath; + + for(int i = 0; i < argc; ++i) { - cerr << "Expected 'build' command to only be followed by one argument which is the path to a directory that contains a project.conf file, "; - cerr << "or none; in which case build would use the working directory as target directory" << endl << endl; - usage(); + const char *arg = argv[i]; + if(strcmp(arg, "--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"); + usageBuild(); + } + optimizationLevel = OPT_LEV_DEBUG; + } + else if(strcmp(arg, "--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"); + usageBuild(); + } + optimizationLevel = OPT_LEV_RELEASE; + } + else + { + 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); + usageBuild(); + } + projectPath = arg; + } } - // TODO: If argc == 0 and working directory does not contain project.conf, then search every parent directory until one is found - string projectPath = "."; - if(argc == 1) - projectPath = argv[0]; + if(optimizationLevel == OPT_LEV_NONE) + optimizationLevel = OPT_LEV_DEBUG; + + // 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 = "."; validateDirectoryPath(projectPath.c_str()); if(projectPath.back() != '/') @@ -128,7 +176,7 @@ int buildProject(int argc, const char **argv) projectConfFilePath += "/project.conf"; validateFilePath(projectConfFilePath.c_str()); - SibsConfig sibsConfig(projectPath); + SibsConfig sibsConfig(projectPath, optimizationLevel); Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if(result.isErr()) { @@ -186,8 +234,18 @@ int buildProject(int argc, const char **argv) }; walkDir(projectPath.c_str(), collectSourceFiles); - string debugBuildPath = projectPath + "/sibs-build/debug"; - Result buildFileResult = ninja.build(sibsConfig, debugBuildPath.c_str()); + string buildPath = projectPath + "/sibs-build/"; + switch(sibsConfig.getOptimizationLevel()) + { + case OPT_LEV_DEBUG: + buildPath += "debug"; + break; + case OPT_LEV_RELEASE: + buildPath += "release"; + break; + } + + Result buildFileResult = ninja.build(sibsConfig, buildPath.c_str()); if(buildFileResult.isErr()) { cerr << "Failed to build ninja file: " << buildFileResult.getErrMsg() << endl; -- cgit v1.2.3