From 28d6b571139998915bce147abb58617884431192 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 14 Dec 2017 15:22:06 +0100 Subject: Add support for dynamic libraries (shared objects) --- backend/ninja/Ninja.cpp | 116 ++++++++++++++++++++++++++++++++++++------------ backend/ninja/Ninja.hpp | 6 +-- 2 files changed, 90 insertions(+), 32 deletions(-) (limited to 'backend') 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 Ninja::getLinkerFlags(const vector &dependencies, LinkerFlagCallbackFunc linkerFlagCallbackFunc) const + Result Ninja::getLinkerFlags(const vector &dependencies, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const { if(dependencies.empty()) return Result::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 globalLibLinkerFlagsResult = GlobalLib::getStaticLibsLinkerFlags(globalLibDir, globalLibDependency.name, globalLibDependency.version, linkerFlagCallbackFunc); + Result 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::Err(globalLibLinkerFlagsResult); } @@ -156,8 +156,9 @@ namespace backend return Result::Ok(true); } - Result Ninja::createBuildFile(const std::string &packageName, const vector &dependencies, const char *savePath, LinkerFlagCallbackFunc linkerFlagCallbackFunc) + Result Ninja::createBuildFile(const std::string &packageName, const vector &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::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::Err("Building a dynamic library is not supported yet"); + return Result::Err("Unexpected error"); } vector 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 linkerFlags = getLinkerFlags(dependencies, [&allLinkerFlags](const string &linkerFlag) - { - allLinkerFlags += " "; - allLinkerFlags += linkerFlag; - }); + Result linkerFlags = getLinkerFlags(dependencies, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); if(linkerFlags.isErr()) return Result::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 linkerFlags = getLinkerFlags(dependencies, linkerFlagCallbackFunc); + Result 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 linkerFlags = getLinkerFlags(dependencies, staticLinkerFlagCallbackFunc, dynamicLinkerFlagCallback); + if(linkerFlags.isErr()) + return Result::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::Err("Building a dynamic library is not supported yet"); + return Result::Err("Unexpected error"); } Result 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 = exec(command.c_str(), true); + Result execResult = exec(command.c_str()); if(execResult.isOk()) - return Result::Ok(true); + { + if(execResult.unwrap().exitCode == 0) + { + printf("%s", execResult.unwrap().execStdout.c_str()); + return Result::Ok(true); + } + else + return Result::Err(execResult.unwrap().execStdout); + } else return Result::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& getSourceFiles() const; - sibs::Result createBuildFile(const std::string &packageName, const std::vector &dependencies, const char *savePath, sibs::LinkerFlagCallbackFunc linkerFlagCallbackFunc = nullptr); + sibs::Result createBuildFile(const std::string &packageName, const std::vector &dependencies, const char *savePath, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc = nullptr, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback = nullptr); sibs::Result build(const char *buildFilePath); private: bool containsSourceFile(const char *filepath) const; - sibs::Result getLinkerFlags(const std::vector &dependencies, sibs::LinkerFlagCallbackFunc linkerFlagCallbackFunc) const; + sibs::Result getLinkerFlags(const std::vector &dependencies, sibs::LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, sibs::LinkerFlagCallbackFunc dynamicLinkerFlagCallback) const; private: std::vector sourceFiles; LibraryType libraryType; -- cgit v1.2.3