From: Andrew Wilkins Date: Thu, 7 Jan 2016 00:18:56 +0000 (+0000) Subject: tools/llvm-config: improve shared library support X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=ecd5a90fab59c72b1b9c26495646a81ce977c6fc tools/llvm-config: improve shared library support Summary: r252532 added support for reporting the monolithic library when LLVM_BUILD_LLVM_DYLIB is used. This would only be done if the individual components were not found, and the dynamic library is found. This diff extends this as follows: - If LLVM_LINK_LLVM_DYLIB is set, then prefer the shared library, even if all component libraries exist. - Two flags, --link-shared and --link-static are introduced to provide explicit guidance. If --link-shared is passed and the shared library does not exist, an error results. Additionally, changed the expected shared library names from (e.g.) LLVM-3.8.0 to LLVM-3.8. The former exists only in an installation (and then only in CMake builds I think?), and not in the build tree; this breaks usage of llvm-config during builds, e.g. by llvm-go. Reviewers: DiamondLovesYou, beanz Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D15033 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257003 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake index bed81b28426..d2564516a29 100644 --- a/cmake/modules/AddLLVM.cmake +++ b/cmake/modules/AddLLVM.cmake @@ -911,13 +911,8 @@ function(llvm_add_go_executable binary pkgpath) set(cppflags "${cppflags} -I${d}") endforeach(d) set(ldflags "${CMAKE_EXE_LINKER_FLAGS}") - if (LLVM_LINK_LLVM_DYLIB) - set(linkmode "dylib") - else() - set(linkmode "component-libs") - endif() add_custom_command(OUTPUT ${binpath} - COMMAND ${CMAKE_BINARY_DIR}/bin/llvm-go "go=${GO_EXECUTABLE}" "cc=${cc}" "cxx=${cxx}" "cppflags=${cppflags}" "ldflags=${ldflags}" "linkmode=${linkmode}" + COMMAND ${CMAKE_BINARY_DIR}/bin/llvm-go "go=${GO_EXECUTABLE}" "cc=${cc}" "cxx=${cxx}" "cppflags=${cppflags}" "ldflags=${ldflags}" ${ARG_GOFLAGS} build -o ${binpath} ${pkgpath} DEPENDS llvm-config ${CMAKE_BINARY_DIR}/bin/llvm-go${CMAKE_EXECUTABLE_SUFFIX} ${llvmlibs} ${ARG_DEPENDS} diff --git a/tools/llvm-config/BuildVariables.inc.in b/tools/llvm-config/BuildVariables.inc.in index 345f47e91b4..952c2a8a127 100644 --- a/tools/llvm-config/BuildVariables.inc.in +++ b/tools/llvm-config/BuildVariables.inc.in @@ -29,5 +29,7 @@ #define LLVM_BUILD_SYSTEM "@LLVM_BUILD_SYSTEM@" #define LLVM_HAS_RTTI "@LLVM_HAS_RTTI@" #define LLVM_ENABLE_DYLIB "@LLVM_BUILD_LLVM_DYLIB@" +#define LLVM_LINK_DYLIB "@LLVM_LINK_LLVM_DYLIB@" #define LLVM_ENABLE_SHARED "@LLVM_ENABLE_SHARED@" #define LLVM_DYLIB_COMPONENTS "@LLVM_DYLIB_COMPONENTS@" +#define LLVM_DYLIB_VERSION "@LLVM_DYLIB_VERSION@" diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index 83794bb3fdd..46f97e53679 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -26,6 +26,7 @@ set(LLVM_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} set(LLVM_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${COMPILE_FLAGS} ${LLVM_DEFINITIONS}") set(LLVM_BUILD_SYSTEM cmake) set(LLVM_HAS_RTTI ${LLVM_CONFIG_HAS_RTTI}) +set(LLVM_DYLIB_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX}") # Use the C++ link flags, since they should be a superset of C link flags. set(LLVM_LDFLAGS "${CMAKE_CXX_LINK_FLAGS}") diff --git a/tools/llvm-config/Makefile b/tools/llvm-config/Makefile index d2fe2cfa34a..1376e1a922b 100644 --- a/tools/llvm-config/Makefile +++ b/tools/llvm-config/Makefile @@ -44,6 +44,8 @@ else LLVM_HAS_RTTI := YES endif +LLVM_DYLIB_VERSION := $(LLVM_VERSION_MAJOR).$(LLVM_VERSION_MINOR)$(LLVM_VERSION_SUFFIX) + # This is blank for now. We need to be careful about adding stuff here: # LDFLAGS tend not to be portable, and we don't currently require the # user to use libtool when linking against LLVM. @@ -83,6 +85,8 @@ $(ObjDir)/BuildVariables.inc: $(BUILDVARIABLES_SRCPATH) Makefile $(ObjDir)/.dir >> temp.sed $(Verb) $(ECHO) 's/@LLVM_HAS_RTTI@/$(LLVM_HAS_RTTI)/' \ >> temp.sed + $(Verb) $(ECHO) 's/@LLVM_DYLIB_VERSION@/$(LLVM_DYLIB_VERSION)/' \ + >> temp.sed $(Verb) $(SED) -f temp.sed < $< > $@ $(Verb) $(RM) temp.sed diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp index 80f627936d0..7c3ad76509f 100644 --- a/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp @@ -29,8 +29,8 @@ #include "llvm/Support/raw_ostream.h" #include #include -#include #include +#include using namespace llvm; @@ -46,6 +46,22 @@ using namespace llvm; // create entries for pseudo groups like x86 or all-targets. #include "LibraryDependencies.inc" +// LinkMode determines what libraries and flags are returned by llvm-config. +enum LinkMode { + // LinkModeAuto will link with the default link mode for the installation, + // which is dependent on the value of LLVM_LINK_LLVM_DYLIB, and fall back + // to the alternative if the required libraries are not available. + LinkModeAuto = 0, + + // LinkModeDyLib will link with the single dynamic library if it exists, + // and return an error if it does not exist. + LinkModeDyLib = 1, + + // LinkModeStatic will link with the individual component static libraries + // if they exist, and fail if any one does not exist. + LinkModeStatic = 2, +}; + /// \brief Traverse a single component adding to the topological ordering in /// \arg RequiredLibs. /// @@ -56,12 +72,13 @@ using namespace llvm; /// libraries. /// \param GetComponentNames - Get the component names instead of the /// library name. -static void VisitComponent(const std::string& Name, - const StringMap &ComponentMap, - std::set &VisitedComponents, +static void VisitComponent(const std::string &Name, + const StringMap &ComponentMap, + std::set &VisitedComponents, std::vector &RequiredLibs, bool IncludeNonInstalled, bool GetComponentNames, - const std::string *ActiveLibDir, bool *HasMissing) { + const std::string *ActiveLibDir, + std::vector *Missing) { // Lookup the component. AvailableComponent *AC = ComponentMap.lookup(Name); assert(AC && "Invalid component name!"); @@ -80,7 +97,7 @@ static void VisitComponent(const std::string& Name, for (unsigned i = 0; AC->RequiredLibraries[i]; ++i) { VisitComponent(AC->RequiredLibraries[i], ComponentMap, VisitedComponents, RequiredLibs, IncludeNonInstalled, GetComponentNames, - ActiveLibDir, HasMissing); + ActiveLibDir, Missing); } if (GetComponentNames) { @@ -90,8 +107,10 @@ static void VisitComponent(const std::string& Name, // Add to the required library list. if (AC->Library) { - if (!IncludeNonInstalled && HasMissing && !*HasMissing && ActiveLibDir) { - *HasMissing = !sys::fs::exists(*ActiveLibDir + "/" + AC->Library); + if (Missing && ActiveLibDir) { + std::string path = *ActiveLibDir + "/" + AC->Library; + if (!sys::fs::exists(path)) + Missing->push_back(path); } RequiredLibs.push_back(AC->Library); } @@ -108,12 +127,13 @@ static void VisitComponent(const std::string& Name, static std::vector ComputeLibsForComponents(const std::vector &Components, bool IncludeNonInstalled, bool GetComponentNames, - const std::string *ActiveLibDir, bool *HasMissing) { + const std::string *ActiveLibDir, + std::vector *Missing) { std::vector RequiredLibs; std::set VisitedComponents; // Build a map of component names to information. - StringMap ComponentMap; + StringMap ComponentMap; for (unsigned i = 0; i != array_lengthof(AvailableComponents); ++i) { AvailableComponent *AC = &AvailableComponents[i]; ComponentMap[AC->Name] = AC; @@ -133,7 +153,7 @@ ComputeLibsForComponents(const std::vector &Components, VisitComponent(ComponentLower, ComponentMap, VisitedComponents, RequiredLibs, IncludeNonInstalled, GetComponentNames, - ActiveLibDir, HasMissing); + ActiveLibDir, Missing); } // The list is now ordered with leafs first, we want the libraries to printed @@ -179,6 +199,8 @@ Options:\n\ --build-system Print the build system used to build LLVM (autoconf or cmake).\n\ --has-rtti Print whether or not LLVM was built with rtti (YES or NO).\n\ --shared-mode Print how the provided components can be collectively linked (`shared` or `static`).\n\ + --link-shared Link the components as a shared library.\n\ + --link-static Link the components as a static libraries.\n\ Typical components:\n\ all All LLVM libraries (default).\n\ engine Either a native JIT or a bitcode interpreter.\n"; @@ -189,7 +211,7 @@ Typical components:\n\ std::string GetExecutablePath(const char *Argv0) { // This just needs to be some symbol in the binary; C++ doesn't // allow taking the address of ::main however. - void *P = (void*) (intptr_t) GetExecutablePath; + void *P = (void *)(intptr_t)GetExecutablePath; return llvm::sys::fs::getMainExecutable(Argv0, P); } @@ -243,8 +265,8 @@ int main(int argc, char **argv) { // Create an absolute path, and pop up one directory (we expect to be inside a // bin dir). sys::fs::make_absolute(CurrentPath); - CurrentExecPrefix = sys::path::parent_path( - sys::path::parent_path(CurrentPath)).str(); + CurrentExecPrefix = + sys::path::parent_path(sys::path::parent_path(CurrentPath)).str(); // Check to see if we are inside a development tree by comparing to possible // locations (prefix style or CMake style). @@ -305,8 +327,8 @@ int main(int argc, char **argv) { } // We need to include files from both the source and object trees. - ActiveIncludeOption = ("-I" + ActiveIncludeDir + " " + - "-I" + ActiveObjRoot + "/include"); + ActiveIncludeOption = + ("-I" + ActiveIncludeDir + " " + "-I" + ActiveObjRoot + "/include"); } else { ActivePrefix = CurrentExecPrefix; ActiveIncludeDir = ActivePrefix + "/include"; @@ -323,25 +345,25 @@ int main(int argc, char **argv) { /// in the first place. This can't be done at configure/build time. StringRef SharedExt, SharedVersionedExt, SharedDir, SharedPrefix, StaticExt, - StaticPrefix, StaticDir = "lib"; + StaticPrefix, StaticDir = "lib"; const Triple HostTriple(Triple::normalize(LLVM_DEFAULT_TARGET_TRIPLE)); if (HostTriple.isOSWindows()) { SharedExt = "dll"; - SharedVersionedExt = PACKAGE_VERSION ".dll"; + SharedVersionedExt = LLVM_DYLIB_VERSION ".dll"; StaticExt = "a"; SharedDir = ActiveBinDir; StaticDir = ActiveLibDir; StaticPrefix = SharedPrefix = "lib"; } else if (HostTriple.isOSDarwin()) { SharedExt = "dylib"; - SharedVersionedExt = PACKAGE_VERSION ".dylib"; + SharedVersionedExt = LLVM_DYLIB_VERSION ".dylib"; StaticExt = "a"; StaticDir = SharedDir = ActiveLibDir; StaticPrefix = SharedPrefix = "lib"; } else { // default to the unix values: SharedExt = "so"; - SharedVersionedExt = PACKAGE_VERSION ".so"; + SharedVersionedExt = LLVM_DYLIB_VERSION ".so"; StaticExt = "a"; StaticDir = SharedDir = ActiveLibDir; StaticPrefix = SharedPrefix = "lib"; @@ -362,11 +384,22 @@ int main(int argc, char **argv) { bool DyLibExists = false; const std::string DyLibName = - (SharedPrefix + "LLVM-" + SharedVersionedExt).str(); + (SharedPrefix + "LLVM-" + SharedVersionedExt).str(); + + // If LLVM_LINK_DYLIB is ON, the single shared library will be returned + // for "--libs", etc, if they exist. This behaviour can be overridden with + // --link-static or --link-shared. + bool LinkDyLib = (std::strcmp(LLVM_LINK_DYLIB, "ON") == 0); if (BuiltDyLib) { DyLibExists = sys::fs::exists(SharedDir + "/" + DyLibName); + if (!DyLibExists) { + // The shared library does not exist: don't error unless the user + // explicitly passes --link-shared. + LinkDyLib = false; + } } + LinkMode LinkMode = LinkDyLib ? LinkModeDyLib : LinkModeAuto; /// Get the component's library name without the lib prefix and the /// extension. Returns true if Lib is in a recognized format. @@ -501,6 +534,10 @@ int main(int argc, char **argv) { OS << ActivePrefix << '\n'; } else if (Arg == "--src-root") { OS << LLVM_SRC_ROOT << '\n'; + } else if (Arg == "--link-shared") { + LinkMode = LinkModeDyLib; + } else if (Arg == "--link-static") { + LinkMode = LinkModeStatic; } else { usage(); } @@ -512,6 +549,11 @@ int main(int argc, char **argv) { if (!HasAnyOption) usage(); + if (LinkMode == LinkModeDyLib && !DyLibExists) { + errs() << "llvm-config: error: " << DyLibName << " is missing\n\n"; + usage(); + } + if (PrintLibs || PrintLibNames || PrintLibFiles || PrintSystemLibs || PrintSharedMode) { @@ -525,11 +567,31 @@ int main(int argc, char **argv) { Components.push_back("all"); // Construct the list of all the required libraries. - bool HasMissing = false; + std::vector MissingLibs; std::vector RequiredLibs = ComputeLibsForComponents(Components, /*IncludeNonInstalled=*/IsInDevelopmentTree, - false, &ActiveLibDir, &HasMissing); + false, &ActiveLibDir, &MissingLibs); + if (!MissingLibs.empty()) { + switch (LinkMode) { + case LinkModeDyLib: + break; + case LinkModeAuto: + if (DyLibExists) { + LinkMode = LinkModeDyLib; + break; + } + errs() + << "llvm-config: error: component libraries and shared library\n\n"; + // fall through + case LinkModeStatic: + for (auto &Lib : MissingLibs) + errs() << "llvm-config: error: missing: " << Lib << "\n"; + return 1; + } + } else if (LinkMode == LinkModeAuto) { + LinkMode = LinkModeStatic; + } if (PrintSharedMode) { std::unordered_set FullDyLibComponents; @@ -549,7 +611,7 @@ int main(int argc, char **argv) { } FullDyLibComponents.clear(); - if (HasMissing && DyLibExists) { + if (LinkMode == LinkModeDyLib) { OS << "shared\n"; return 0; } else { @@ -581,7 +643,7 @@ int main(int argc, char **argv) { } }; - if (HasMissing && DyLibExists) { + if (LinkMode == LinkModeDyLib) { PrintForLib(DyLibName, true); } else { for (unsigned i = 0, e = RequiredLibs.size(); i != e; ++i) { diff --git a/tools/llvm-go/llvm-go.go b/tools/llvm-go/llvm-go.go index ed79ca67b89..d0f794177bb 100644 --- a/tools/llvm-go/llvm-go.go +++ b/tools/llvm-go/llvm-go.go @@ -88,17 +88,8 @@ func llvmConfig(args ...string) string { return outstr } -func llvmFlags(linkmode string) compilerFlags { - ldflags := llvmConfig("--ldflags") - switch linkmode { - case linkmodeComponentLibs: - ldflags += " " + llvmConfig(append([]string{"--libs"}, components...)...) - case linkmodeDylib: - ldflags += " -lLLVM" - default: - panic("invalid linkmode: " + linkmode) - } - ldflags += " " + llvmConfig("--system-libs") +func llvmFlags() compilerFlags { + ldflags := llvmConfig("--ldflags", "--libs", "--system-libs") if runtime.GOOS != "darwin" { // OS X doesn't like -rpath with cgo. See: // https://code.google.com/p/go/issues/detail?id=7293 @@ -133,8 +124,8 @@ func printComponents() { fmt.Println(strings.Join(components, " ")) } -func printConfig(linkmode string) { - flags := llvmFlags(linkmode) +func printConfig() { + flags := llvmFlags() fmt.Printf(`// +build !byollvm @@ -153,7 +144,7 @@ type (run_build_sh int) `, flags.cpp, flags.cxx, flags.ld) } -func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags, linkmode string) { +func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string) { args = addTag(args, "byollvm") srcdir := llvmConfig("--src-root") @@ -182,7 +173,7 @@ func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, l newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...) newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator)) - flags := llvmFlags(linkmode) + flags := llvmFlags() newenv := []string{ "CC=" + cc, @@ -250,7 +241,6 @@ func main() { ldflags := os.Getenv("CGO_LDFLAGS") gocmd := "go" llgo := "" - linkmode := linkmodeComponentLibs flags := []struct { name string @@ -262,7 +252,6 @@ func main() { {"llgo", &llgo}, {"cppflags", &cppflags}, {"ldflags", &ldflags}, - {"linkmode", &linkmode}, } args := os.Args[1:] @@ -283,11 +272,11 @@ LOOP: switch args[0] { case "build", "get", "install", "run", "test": - runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags, linkmode) + runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags) case "print-components": printComponents() case "print-config": - printConfig(linkmode) + printConfig() default: usage() }