diff options
author | dec05eba <dec05eba@protonmail.com> | 2017-12-14 15:22:06 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2017-12-14 15:22:12 +0100 |
commit | 28d6b571139998915bce147abb58617884431192 (patch) | |
tree | 1b79ab0b85973beac33d833db5bc9be472a4dedd | |
parent | c244361b8ae743bcb326b9a1a168f2fdcab491e8 (diff) |
Add support for dynamic libraries (shared objects)
-rw-r--r-- | backend/ninja/Ninja.cpp | 116 | ||||
-rw-r--r-- | backend/ninja/Ninja.hpp | 6 | ||||
-rw-r--r-- | include/GlobalLib.hpp | 2 | ||||
-rw-r--r-- | include/Result.hpp | 2 | ||||
-rw-r--r-- | src/GlobalLib.cpp | 52 | ||||
-rw-r--r-- | src/PkgConfig.cpp | 4 |
6 files changed, 132 insertions, 50 deletions
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index ede150c..d8345a4 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -81,7 +81,7 @@ 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<bool> Ninja::getLinkerFlags(const vector<Dependency> &dependencies, LinkerFlagCallbackFunc linkerFlagCallbackFunc) const + Result<bool> Ninja::getLinkerFlags(const vector<Dependency> &dependencies, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const { if(dependencies.empty()) return Result<bool>::Ok(true); @@ -120,13 +120,13 @@ namespace backend else { if(!pkgConfigLinkerFlagsResult.unwrap().empty()) - linkerFlagCallbackFunc(pkgConfigLinkerFlagsResult.unwrap()); + dynamicLinkerFlagCallback(pkgConfigLinkerFlagsResult.unwrap()); } for(const Dependency &globalLibDependency : globalLibDependencies) { printf("Dependency %s is missing from pkg-config, trying global lib\n", globalLibDependency.name.c_str()); - Result<string> globalLibLinkerFlagsResult = GlobalLib::getStaticLibsLinkerFlags(globalLibDir, globalLibDependency.name, globalLibDependency.version, linkerFlagCallbackFunc); + Result<string> globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(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) @@ -142,7 +142,7 @@ namespace backend if(downloadDependencyResult.isErr()) return downloadDependencyResult; - globalLibLinkerFlagsResult = GlobalLib::getStaticLibsLinkerFlags(globalLibDir, globalLibDependency.name, globalLibDependency.version, linkerFlagCallbackFunc); + globalLibLinkerFlagsResult = GlobalLib::getLibsLinkerFlags(globalLibDir, globalLibDependency.name, globalLibDependency.version, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); if(globalLibLinkerFlagsResult.isErr()) return Result<bool>::Err(globalLibLinkerFlagsResult); } @@ -156,8 +156,9 @@ namespace backend return Result<bool>::Ok(true); } - Result<bool> Ninja::createBuildFile(const std::string &packageName, const vector<Dependency> &dependencies, const char *savePath, LinkerFlagCallbackFunc linkerFlagCallbackFunc) + Result<bool> Ninja::createBuildFile(const std::string &packageName, const vector<Dependency> &dependencies, const char *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()) return Result<bool>::Err("No source files provided"); @@ -178,35 +179,50 @@ namespace backend result += globalLibDir; result += "'\n\n"; - result += "rule cpp_COMPILER\n"; - result += " command = ccache c++ $ARGS -c $in -o $out\n\n"; - - string linkerJob; + string buildJob; switch(libraryType) { case LibraryType::EXECUTABLE: { - result += "rule cpp_EXEC_LINKER\n"; + 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"; - linkerJob = "cpp_EXEC_LINKER"; + buildJob = "cpp_BUILD_EXEC"; break; } case LibraryType::STATIC: { - result += "rule cpp_STATIC_LINKER\n"; + result += "rule cpp_COMPILER\n"; + result += " command = ccache c++ $ARGS -c -fPIC $in -o $out\n\n"; + + result += "rule cpp_BUILD_STATIC\n"; result += " command = ar rcs lib"; result += packageName; result += ".a"; result += " $in\n\n"; - linkerJob = "cpp_STATIC_LINKER"; + buildJob = "cpp_BUILD_STATIC"; + break; + } + case LibraryType::DYNAMIC: + { + 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"; + buildJob = "cpp_BUILD_DYNAMIC"; break; } default: assert(false); - return Result<bool>::Err("Building a dynamic library is not supported yet"); + return Result<bool>::Err("Unexpected error"); } vector<string> objectNames; + objectNames.reserve(sourceFiles.size()); for(const string &sourceFile : sourceFiles) { // TODO: Handle tests differently. @@ -227,46 +243,80 @@ namespace backend objectNames.emplace_back(objectName); } + string allLinkerFlags; + if(!staticLinkerFlagCallbackFunc || libraryType == LibraryType::DYNAMIC) + { + staticLinkerFlagCallbackFunc = [&allLinkerFlags](const string &linkerFlag) + { + allLinkerFlags += " "; + allLinkerFlags += linkerFlag; + }; + } + + // TODO: If project contains no source files, then we shouldn't override this function + dynamicLinkerFlagCallback = [&allLinkerFlags](const string &linkerFlag) + { + allLinkerFlags += " "; + allLinkerFlags += linkerFlag; + }; + switch(libraryType) { case LibraryType::EXECUTABLE: { - string allLinkerFlags; - Result<bool> linkerFlags = getLinkerFlags(dependencies, [&allLinkerFlags](const string &linkerFlag) - { - allLinkerFlags += " "; - allLinkerFlags += linkerFlag; - }); + Result<bool> linkerFlags = getLinkerFlags(dependencies, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); if(linkerFlags.isErr()) return Result<bool>::Err(linkerFlags.getErrMsg()); result += "build "; result += packageName; - result += ": " + linkerJob + " "; + result += ": " + buildJob + " "; result += join(objectNames, " "); result += "\n"; - result += " LINK_ARGS = '-Wl,--no-undefined' '-Wl,--as-needed' "; - result += allLinkerFlags; + result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' "; + if(!allLinkerFlags.empty()) + { + result += allLinkerFlags; + } result += "\n\n"; break; } case LibraryType::STATIC: { - string allLinkerFlags; - Result<bool> linkerFlags = getLinkerFlags(dependencies, linkerFlagCallbackFunc); + Result<bool> linkerFlags = getLinkerFlags(dependencies, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); if(linkerFlags.isErr()) return linkerFlags; result += "build "; result += packageName; - result += ": " + linkerJob + " "; + result += ": " + buildJob + " "; result += join(objectNames, " "); result += "\n\n"; break; } + case LibraryType::DYNAMIC: + { + Result<bool> linkerFlags = getLinkerFlags(dependencies, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); + if(linkerFlags.isErr()) + return Result<bool>::Err(linkerFlags.getErrMsg()); + + result += "build lib"; + result += packageName; + result += ".so: " + buildJob + " "; + result += join(objectNames, " "); + result += "\n"; + result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' "; + if(!allLinkerFlags.empty()) + { + result += allLinkerFlags; + //result += " '-Wl,--no-whole-archive'"; + } + result += "\n\n"; + break; + } default: assert(false); - return Result<bool>::Err("Building a dynamic library is not supported yet"); + return Result<bool>::Err("Unexpected error"); } Result<bool> fileOverwriteResult = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size())); @@ -282,9 +332,17 @@ namespace backend string command = "ninja -C '"; command += buildFilePath; command += "'"; - Result<ExecResult> execResult = exec(command.c_str(), true); + Result<ExecResult> execResult = exec(command.c_str()); if(execResult.isOk()) - return Result<bool>::Ok(true); + { + if(execResult.unwrap().exitCode == 0) + { + printf("%s", execResult.unwrap().execStdout.c_str()); + return Result<bool>::Ok(true); + } + else + return Result<bool>::Err(execResult.unwrap().execStdout); + } else return Result<bool>::Err(execResult.getErrMsg()); } diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index b82139c..a0239d2 100644 --- a/backend/ninja/Ninja.hpp +++ b/backend/ninja/Ninja.hpp @@ -17,19 +17,19 @@ namespace backend enum class LibraryType { EXECUTABLE, + STATIC, DYNAMIC, - STATIC }; Ninja(LibraryType libraryType = LibraryType::EXECUTABLE); void addSourceFile(const char *filepath); const std::vector<std::string>& getSourceFiles() const; - sibs::Result<bool> createBuildFile(const std::string &packageName, const std::vector<sibs::Dependency> &dependencies, const char *savePath, sibs::LinkerFlagCallbackFunc linkerFlagCallbackFunc = nullptr); + sibs::Result<bool> createBuildFile(const std::string &packageName, const std::vector<sibs::Dependency> &dependencies, const char *savePath, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc = nullptr, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback = nullptr); sibs::Result<bool> build(const char *buildFilePath); private: bool containsSourceFile(const char *filepath) const; - sibs::Result<bool> getLinkerFlags(const std::vector<sibs::Dependency> &dependencies, sibs::LinkerFlagCallbackFunc linkerFlagCallbackFunc) const; + sibs::Result<bool> getLinkerFlags(const std::vector<sibs::Dependency> &dependencies, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const; private: std::vector<std::string> sourceFiles; LibraryType libraryType; diff --git a/include/GlobalLib.hpp b/include/GlobalLib.hpp index ca542f9..78511c3 100644 --- a/include/GlobalLib.hpp +++ b/include/GlobalLib.hpp @@ -17,7 +17,7 @@ namespace sibs }; static Result<bool> validatePackageExists(const std::string &globalLibRootDir, const std::string &name); - static Result<std::string> getStaticLibsLinkerFlags(const std::string &globalLibRootDir, const std::string &name, const std::string &version, LinkerFlagCallbackFunc linkerFlagCallbackFunc); + static Result<std::string> getLibsLinkerFlags(const std::string &globalLibRootDir, const std::string &name, const std::string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc); static Result<bool> downloadDependency(const Dependency &dependency); }; } diff --git a/include/Result.hpp b/include/Result.hpp index eb0aa01..e8f4d12 100644 --- a/include/Result.hpp +++ b/include/Result.hpp @@ -53,6 +53,8 @@ namespace sibs { return errorCode; } + + operator bool () { return isOk(); } private: Result(const T &_value = T()) : value(_value) {} private: diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp index 617f993..a07e23d 100644 --- a/src/GlobalLib.cpp +++ b/src/GlobalLib.cpp @@ -55,7 +55,7 @@ namespace sibs return false; } - Result<string> GlobalLib::getStaticLibsLinkerFlags(const string &globalLibRootDir, const string &name, const string &version, LinkerFlagCallbackFunc linkerFlagCallbackFunc) + Result<string> GlobalLib::getLibsLinkerFlags(const string &globalLibRootDir, const string &name, const string &version, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallbackFunc) { Result<bool> packageExistsResult = validatePackageExists(globalLibRootDir, name); if(packageExistsResult.isErr()) @@ -121,7 +121,22 @@ namespace sibs return Result<string>::Err(errMsg); } - backend::Ninja ninja(backend::Ninja::LibraryType::STATIC); + backend::Ninja::LibraryType libraryType; + switch(sibsConfig.getPackageType()) + { + case PackageType::STATIC: + libraryType = backend::Ninja::LibraryType::STATIC; + break; + case PackageType::DYNAMIC: + case PackageType::LIBRARY: + libraryType = backend::Ninja::LibraryType::DYNAMIC; + break; + default: + assert(false); + return Result<string>::Err("Unexpected error"); + } + + backend::Ninja ninja(libraryType); walkDirFilesRecursive(packageDir.c_str(), [&ninja, &packageDir](tinydir_file *file) { if (isSourceFile(file)) @@ -141,15 +156,26 @@ namespace sibs else { string debugBuildPath = packageDir + "/sibs-build/debug"; - string staticLibPath = debugBuildPath; - staticLibPath += "/lib"; - staticLibPath += name; - staticLibPath += ".a"; - - string staticLibPathCmd = "'"; - staticLibPathCmd += staticLibPath; - staticLibPathCmd += "'"; - linkerFlagCallbackFunc(staticLibPathCmd); + string libPath = debugBuildPath; + libPath += "/lib"; + libPath += name; + if(libraryType == backend::Ninja::LibraryType::STATIC) + { + libPath += ".a"; + string libPathCmd = "'"; + libPathCmd += libPath; + libPathCmd += "'"; + staticLinkerFlagCallbackFunc(libPathCmd); + libPath += ".a"; + } + else + { + libPath += ".so"; + string libPathCmd = "'"; + libPathCmd += libPath; + libPathCmd += "'"; + dynamicLinkerFlagCallbackFunc(libPathCmd); + } // 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 @@ -157,7 +183,7 @@ namespace sibs if(createBuildDirResult.isErr()) return Result<string>::Err(createBuildDirResult); - Result<bool> buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), debugBuildPath.c_str(), linkerFlagCallbackFunc); + Result<bool> buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), debugBuildPath.c_str(), staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallbackFunc); if (buildFileResult.isErr()) return Result<string>::Err(buildFileResult.getErrMsg()); @@ -165,7 +191,7 @@ namespace sibs if (buildResult.isErr()) return Result<string>::Err(buildResult.getErrMsg()); - return Result<string>::Ok(staticLibPath); + return Result<string>::Ok(libPath); } } diff --git a/src/PkgConfig.cpp b/src/PkgConfig.cpp index 5f85549..620b1a7 100644 --- a/src/PkgConfig.cpp +++ b/src/PkgConfig.cpp @@ -25,9 +25,7 @@ namespace sibs command += "'"; Result<ExecResult> execResult = exec(command.c_str()); if(execResult.isErr()) - { return Result<bool>::Err(execResult.getErrMsg()); - } if(execResult.unwrap().exitCode == 1) { @@ -63,9 +61,7 @@ namespace sibs command += "'"; Result<ExecResult> execResult = exec(command.c_str()); if(execResult.isErr()) - { return Result<bool>::Err(execResult.getErrMsg()); - } if(execResult.unwrap().exitCode == 1) { |