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 /backend/ninja | |
parent | c244361b8ae743bcb326b9a1a168f2fdcab491e8 (diff) |
Add support for dynamic libraries (shared objects)
Diffstat (limited to 'backend/ninja')
-rw-r--r-- | backend/ninja/Ninja.cpp | 116 | ||||
-rw-r--r-- | backend/ninja/Ninja.hpp | 6 |
2 files changed, 90 insertions, 32 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; |