From c206fd07db07dc6271185dabac822e10d78b4443 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 2 Oct 2018 00:52:30 +0200 Subject: Add sibs package command Currently in testing phase. Builds a redistributable binary by statically linking libraries (including standard library). --- backend/ninja/Ninja.cpp | 26 ++++++++++++++++-- include/Conf.hpp | 4 ++- src/CmakeModule.cpp | 4 +++ src/Conf.cpp | 25 ++++++++++++----- src/GlobalLib.cpp | 1 + src/main.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 120 insertions(+), 11 deletions(-) diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 53b1667..943e090 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -316,8 +316,8 @@ namespace backend vector pkgConfigDependencies; for(PackageListDependency *dependency : packageListDependencies) { - Result pkgConfigDependencyValidation = PkgConfig::validatePkgConfigPackageVersionExists(dependency); - if(pkgConfigDependencyValidation.isOk()) + // PkgConfig libraries, even the static ones are most likely not built statically against libgcc/libc++, so we don't use them + if(!config.packaging && PkgConfig::validatePkgConfigPackageVersionExists(dependency)) { pkgConfigDependencies.push_back(dependency); } @@ -662,6 +662,11 @@ namespace backend string generatedZigHeaderDirUtf8 = toUtf8(generatedZigHeadersDir); LibraryType libraryType = getNinjaLibraryType(config.getPackageType()); + // TODO: Instead of statically linking everything, maybe we should build everything as they prefer to be built + // and then copy the files if they are shared libraries to the same directory as the root project executable + // so they can be packaged into an archive that can be distributed? + if(config.packaging && !config.isMainProject()) + libraryType = LibraryType::STATIC; string savePathUtf8 = toUtf8(savePath); string projectPathUtf8 = toUtf8(config.getProjectPath()); @@ -1077,6 +1082,23 @@ namespace backend objectNames.emplace_back(move(objectName)); } + if(config.packaging) + { + switch(config.getCompiler()) + { + case Compiler::GCC: + { + allLinkerFlags += " -static-libgcc -static-libstdc++"; + break; + } + case Compiler::MSVC: + { + // We always statically link using /MT so there is no need to do it here + break; + } + } + } + // 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 diff --git a/include/Conf.hpp b/include/Conf.hpp index 87f4fad..7a29624 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -301,7 +301,8 @@ namespace sibs mainProject(false), sanitize(false), showWarnings(false), - zigTestAllFiles(false) + zigTestAllFiles(false), + packaging(false) { cmakeDirGlobal = projectPath; cmakeDirStatic = cmakeDirGlobal; @@ -499,6 +500,7 @@ namespace sibs std::vector zigTestFiles; bool showWarnings; bool zigTestAllFiles; + bool packaging; protected: virtual void processObject(StringView name) override; virtual void processField(StringView name, const ConfigValue &value) override; diff --git a/src/CmakeModule.cpp b/src/CmakeModule.cpp index c512f87..1e873cd 100644 --- a/src/CmakeModule.cpp +++ b/src/CmakeModule.cpp @@ -15,6 +15,10 @@ namespace sibs { Result CmakeModule::compile(const SibsConfig &config, const FileString &buildPath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) { + // TODO: Make packaging work with cmake projects + if(config.packaging) + return Result::Err("Project " + config.getPackageName() + " is a cmake project, such projects are currently not supported when building a package"); + Result globalLibDirResult = getHomeDir(); if (!globalLibDirResult) return Result::Err(globalLibDirResult); diff --git a/src/Conf.cpp b/src/Conf.cpp index 090e1e1..d981794 100644 --- a/src/Conf.cpp +++ b/src/Conf.cpp @@ -487,6 +487,9 @@ namespace sibs else fprintf(stderr, "Warning: Project contains tests directory but we got an error while retrieving the full path to it\n"); } + + if(config.packaging && (!config.getDebugStaticLibs().empty() || !config.getReleaseStaticLibs().empty())) + return Result::Err("Project " + config.getPackageName() + " contains external static libraries, such projects are not supported when building a package"); } return parseResult; @@ -502,14 +505,21 @@ namespace sibs } buildPath = projectPath + TINYDIR_STRING("/sibs-build/"); - switch(sibsConfig.getOptimizationLevel()) + if(sibsConfig.packaging) + { + buildPath += TINYDIR_STRING("package"); + } + else { - case OPT_LEV_DEBUG: - buildPath += TINYDIR_STRING("debug"); - break; - case OPT_LEV_RELEASE: - buildPath += TINYDIR_STRING("release"); - break; + switch(sibsConfig.getOptimizationLevel()) + { + case OPT_LEV_DEBUG: + buildPath += TINYDIR_STRING("debug"); + break; + case OPT_LEV_RELEASE: + buildPath += TINYDIR_STRING("release"); + break; + } } } @@ -1163,6 +1173,7 @@ namespace sibs string SibsConfig::parsePlatformConfigStatic(const StringView &fieldName, const ConfigValue &fieldValue) { + // TODO: Verify the library is actually a static library if (fieldName.equals("lib")) { if (fieldValue.isSingle()) diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp index 916ba3e..99c783a 100644 --- a/src/GlobalLib.cpp +++ b/src/GlobalLib.cpp @@ -201,6 +201,7 @@ namespace sibs } SibsConfig sibsConfig(parentConfig.getCompiler(), packageDir, parentConfig.getOptimizationLevel(), false); + sibsConfig.packaging = parentConfig.packaging; Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if (result.isErr()) return result; diff --git a/src/main.cpp b/src/main.cpp index 290ed9e..eae90d0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -108,6 +108,7 @@ static void usage() printf(" new\t\tCreate a new project\n"); printf(" init\t\tInitialize project in an existing directory\n"); printf(" test\t\tBuild and run tests for a sibs project\n"); + printf(" package\t\tCreate a redistributable package from a sibs project. Note: Redistributable packages can't use system packages to build\n"); exit(1); } @@ -155,6 +156,9 @@ static void usageTest() printf("Examples:\n"); printf(" sibs test\n"); printf(" sibs test dirA/dirB\n"); + printf(" sibs test --no-sanitize\n"); + printf(" sibs test --all-files\n"); + printf(" sibs test --file src/foo.zig --file src/bar.zig\n"); exit(1); } @@ -163,7 +167,7 @@ static void usageInit() printf("Usage: sibs init [project_path] <--exec|--static|--dynamic> [--lang c|c++|zig]\n\n"); printf("Create sibs project structure in an existing directory\n\n"); printf("Options:\n"); - printf(" project_path\t\tThe directory where you want to initialize sibs project - Optional (default: current directory)\n"); + printf(" project_path\t\tThe directory where you want to initialize sibs project - Optional (default: current directory)\n"); printf(" --exec\t\t\tProject compiles to an executable\n"); printf(" --static\t\t\tProject compiles to a static library\n"); printf(" --dynamic\t\t\tProject compiles to a dynamic library\n"); @@ -174,6 +178,18 @@ static void usageInit() exit(1); } +static void usagePackage() +{ + printf("Usage: sibs package [project_path]\n\n"); + printf("Create a redistributable package from a sibs project. Note: Redistributable packages can't use system packages to build\n\n"); + printf("Options:\n"); + printf(" project_path\t\tThe directory containiung a project.conf file - Optional (default: current directory)\n"); + printf("Examples:\n"); + printf(" sibs package\n"); + printf(" sibs package dirA/dirB"); + exit(1); +} + static void validateDirectoryPath(const _tinydir_char_t *projectPath) { FileType projectPathFileType = getFileType(projectPath); @@ -911,6 +927,55 @@ static int initProject(int argc, const _tinydir_char_t **argv) return 0; } +static int packageProject(int argc, const _tinydir_char_t **argv) +{ + if(argc > 1) + usagePackage(); + + FileString projectPath; + if(argc == 1) + projectPath = argv[0]; + + // 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 = TINYDIR_STRING("."); + + validateDirectoryPath(projectPath.c_str()); + if(projectPath.back() != '/') + projectPath += TINYDIR_STRING("/"); + + Result projectRealPathResult = getRealPath(projectPath.c_str()); + if(!projectRealPathResult) + { + ferr << "Failed to get real path for: '" << projectPath.c_str() << "': " << toFileString(projectRealPathResult.getErrMsg()) << endl; + exit(40); + } + projectPath = projectRealPathResult.unwrap(); + + FileString projectConfFilePath = projectPath; + projectConfFilePath += TINYDIR_STRING("/project.conf"); + validateFilePath(projectConfFilePath.c_str()); + + // TODO: Detect compiler to use at runtime. Should also be configurable + // by passing argument to `sibs package` +#if OS_FAMILY == OS_FAMILY_POSIX + Compiler compiler = Compiler::GCC; +#else + Compiler compiler = Compiler::MSVC; +#endif + + SibsConfig sibsConfig(compiler, projectPath, OPT_LEV_RELEASE, false); + sibsConfig.showWarnings = true; + sibsConfig.packaging = true; + int result = buildProject(projectPath, projectConfFilePath, sibsConfig); + if(result != 0) + return result; + + string packagePath = toUtf8(projectPath + TINYDIR_STRING("/sibs-build/package")); + printf("Project %s was successfully packaged and can be found at %s\n", sibsConfig.getPackageName().c_str(), packagePath.c_str()); + return 0; +} + static void newProjectCreateMainDir(const FileString &projectPath) { Result createProjectDirResult = createDirectoryRecursive(projectPath.c_str()); @@ -1138,6 +1203,10 @@ int wmain(int argc, const _tinydir_char_t **argv) { return initProject(subCommandArgCount, subCommandArgPtr); } + else if(_tinydir_strcmp(arg, TINYDIR_STRING("package")) == 0) + { + return packageProject(subCommandArgCount, subCommandArgPtr); + } else { ferr << "Expected command to be either 'build', 'new' or 'test', was: " << arg << endl << endl; -- cgit v1.2.3