diff options
Diffstat (limited to 'tools/llvm-config/llvm-config.cpp')
-rw-r--r-- | tools/llvm-config/llvm-config.cpp | 285 |
1 files changed, 254 insertions, 31 deletions
diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp index 879b9ab0945b..80f627936d0c 100644 --- a/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp @@ -30,6 +30,7 @@ #include <cstdlib> #include <set> #include <vector> +#include <unordered_set> using namespace llvm; @@ -51,12 +52,16 @@ using namespace llvm; /// \param Name - The component to traverse. /// \param ComponentMap - A prebuilt map of component names to descriptors. /// \param VisitedComponents [in] [out] - The set of already visited components. -/// \param RequiredLibs [out] - The ordered list of required libraries. -static void VisitComponent(StringRef Name, +/// \param RequiredLibs [out] - The ordered list of required +/// libraries. +/// \param GetComponentNames - Get the component names instead of the +/// library name. +static void VisitComponent(const std::string& Name, const StringMap<AvailableComponent*> &ComponentMap, std::set<AvailableComponent*> &VisitedComponents, - std::vector<StringRef> &RequiredLibs, - bool IncludeNonInstalled) { + std::vector<std::string> &RequiredLibs, + bool IncludeNonInstalled, bool GetComponentNames, + const std::string *ActiveLibDir, bool *HasMissing) { // Lookup the component. AvailableComponent *AC = ComponentMap.lookup(Name); assert(AC && "Invalid component name!"); @@ -74,12 +79,22 @@ static void VisitComponent(StringRef Name, // Otherwise, visit all the dependencies. for (unsigned i = 0; AC->RequiredLibraries[i]; ++i) { VisitComponent(AC->RequiredLibraries[i], ComponentMap, VisitedComponents, - RequiredLibs, IncludeNonInstalled); + RequiredLibs, IncludeNonInstalled, GetComponentNames, + ActiveLibDir, HasMissing); + } + + if (GetComponentNames) { + RequiredLibs.push_back(Name); + return; } // Add to the required library list. - if (AC->Library) + if (AC->Library) { + if (!IncludeNonInstalled && HasMissing && !*HasMissing && ActiveLibDir) { + *HasMissing = !sys::fs::exists(*ActiveLibDir + "/" + AC->Library); + } RequiredLibs.push_back(AC->Library); + } } /// \brief Compute the list of required libraries for a given list of @@ -87,14 +102,15 @@ static void VisitComponent(StringRef Name, /// appear prior to their dependencies). /// /// \param Components - The names of the components to find libraries for. -/// \param RequiredLibs [out] - On return, the ordered list of libraries that -/// are required to link the given components. /// \param IncludeNonInstalled - Whether non-installed components should be /// reported. -static void ComputeLibsForComponents(const std::vector<StringRef> &Components, - std::vector<StringRef> &RequiredLibs, - bool IncludeNonInstalled) { - std::set<AvailableComponent*> VisitedComponents; +/// \param GetComponentNames - True if one would prefer the component names. +static std::vector<std::string> +ComputeLibsForComponents(const std::vector<StringRef> &Components, + bool IncludeNonInstalled, bool GetComponentNames, + const std::string *ActiveLibDir, bool *HasMissing) { + std::vector<std::string> RequiredLibs; + std::set<AvailableComponent *> VisitedComponents; // Build a map of component names to information. StringMap<AvailableComponent*> ComponentMap; @@ -116,12 +132,15 @@ static void ComputeLibsForComponents(const std::vector<StringRef> &Components, } VisitComponent(ComponentLower, ComponentMap, VisitedComponents, - RequiredLibs, IncludeNonInstalled); + RequiredLibs, IncludeNonInstalled, GetComponentNames, + ActiveLibDir, HasMissing); } // The list is now ordered with leafs first, we want the libraries to printed // in the reverse order of dependency. std::reverse(RequiredLibs.begin(), RequiredLibs.end()); + + return RequiredLibs; } /* *** */ @@ -157,6 +176,9 @@ Options:\n\ --host-target Target triple used to configure LLVM.\n\ --build-mode Print build mode of LLVM tree (e.g. Debug or Release).\n\ --assertion-mode Print assertion mode of LLVM tree (ON or OFF).\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\ Typical components:\n\ all All LLVM libraries (default).\n\ engine Either a native JIT or a bitcode interpreter.\n"; @@ -171,10 +193,34 @@ std::string GetExecutablePath(const char *Argv0) { return llvm::sys::fs::getMainExecutable(Argv0, P); } +/// \brief Expand the semi-colon delimited LLVM_DYLIB_COMPONENTS into +/// the full list of components. +std::vector<std::string> GetAllDyLibComponents(const bool IsInDevelopmentTree, + const bool GetComponentNames) { + std::vector<StringRef> DyLibComponents; + + StringRef DyLibComponentsStr(LLVM_DYLIB_COMPONENTS); + size_t Offset = 0; + while (true) { + const size_t NextOffset = DyLibComponentsStr.find(';', Offset); + DyLibComponents.push_back(DyLibComponentsStr.substr(Offset, NextOffset)); + if (NextOffset == std::string::npos) { + break; + } + Offset = NextOffset + 1; + } + + assert(!DyLibComponents.empty()); + + return ComputeLibsForComponents(DyLibComponents, + /*IncludeNonInstalled=*/IsInDevelopmentTree, + GetComponentNames, nullptr, nullptr); +} + int main(int argc, char **argv) { std::vector<StringRef> Components; bool PrintLibs = false, PrintLibNames = false, PrintLibFiles = false; - bool PrintSystemLibs = false; + bool PrintSystemLibs = false, PrintSharedMode = false; bool HasAnyOption = false; // llvm-config is designed to support being run both from a development tree @@ -269,6 +315,108 @@ int main(int argc, char **argv) { ActiveIncludeOption = "-I" + ActiveIncludeDir; } + /// We only use `shared library` mode in cases where the static library form + /// of the components provided are not available; note however that this is + /// skipped if we're run from within the build dir. However, once installed, + /// we still need to provide correct output when the static archives are + /// removed or, as in the case of CMake's `BUILD_SHARED_LIBS`, never present + /// in the first place. This can't be done at configure/build time. + + StringRef SharedExt, SharedVersionedExt, SharedDir, SharedPrefix, StaticExt, + StaticPrefix, StaticDir = "lib"; + const Triple HostTriple(Triple::normalize(LLVM_DEFAULT_TARGET_TRIPLE)); + if (HostTriple.isOSWindows()) { + SharedExt = "dll"; + SharedVersionedExt = PACKAGE_VERSION ".dll"; + StaticExt = "a"; + SharedDir = ActiveBinDir; + StaticDir = ActiveLibDir; + StaticPrefix = SharedPrefix = "lib"; + } else if (HostTriple.isOSDarwin()) { + SharedExt = "dylib"; + SharedVersionedExt = PACKAGE_VERSION ".dylib"; + StaticExt = "a"; + StaticDir = SharedDir = ActiveLibDir; + StaticPrefix = SharedPrefix = "lib"; + } else { + // default to the unix values: + SharedExt = "so"; + SharedVersionedExt = PACKAGE_VERSION ".so"; + StaticExt = "a"; + StaticDir = SharedDir = ActiveLibDir; + StaticPrefix = SharedPrefix = "lib"; + } + + const bool BuiltDyLib = (std::strcmp(LLVM_ENABLE_DYLIB, "ON") == 0); + + enum { CMake, AutoConf } ConfigTool; + if (std::strcmp(LLVM_BUILD_SYSTEM, "cmake") == 0) { + ConfigTool = CMake; + } else { + ConfigTool = AutoConf; + } + + /// CMake style shared libs, ie each component is in a shared library. + const bool BuiltSharedLibs = + (ConfigTool == CMake && std::strcmp(LLVM_ENABLE_SHARED, "ON") == 0); + + bool DyLibExists = false; + const std::string DyLibName = + (SharedPrefix + "LLVM-" + SharedVersionedExt).str(); + + if (BuiltDyLib) { + DyLibExists = sys::fs::exists(SharedDir + "/" + DyLibName); + } + + /// Get the component's library name without the lib prefix and the + /// extension. Returns true if Lib is in a recognized format. + auto GetComponentLibraryNameSlice = [&](const StringRef &Lib, + StringRef &Out) { + if (Lib.startswith("lib")) { + unsigned FromEnd; + if (Lib.endswith(StaticExt)) { + FromEnd = StaticExt.size() + 1; + } else if (Lib.endswith(SharedExt)) { + FromEnd = SharedExt.size() + 1; + } else { + FromEnd = 0; + } + + if (FromEnd != 0) { + Out = Lib.slice(3, Lib.size() - FromEnd); + return true; + } + } + + return false; + }; + /// Maps Unixizms to the host platform. + auto GetComponentLibraryFileName = [&](const StringRef &Lib, + const bool ForceShared) { + std::string LibFileName = Lib; + StringRef LibName; + if (GetComponentLibraryNameSlice(Lib, LibName)) { + if (BuiltSharedLibs || ForceShared) { + LibFileName = (SharedPrefix + LibName + "." + SharedExt).str(); + } else { + // default to static + LibFileName = (StaticPrefix + LibName + "." + StaticExt).str(); + } + } + + return LibFileName; + }; + /// Get the full path for a possibly shared component library. + auto GetComponentLibraryPath = [&](const StringRef &Name, + const bool ForceShared) { + auto LibFileName = GetComponentLibraryFileName(Name, ForceShared); + if (BuiltSharedLibs || ForceShared) { + return (SharedDir + "/" + LibFileName).str(); + } else { + return (StaticDir + "/" + LibFileName).str(); + } + }; + raw_ostream &OS = outs(); for (int i = 1; i != argc; ++i) { StringRef Arg = argv[i]; @@ -302,13 +450,33 @@ int main(int argc, char **argv) { } else if (Arg == "--libfiles") { PrintLibFiles = true; } else if (Arg == "--components") { + /// If there are missing static archives and a dylib was + /// built, print LLVM_DYLIB_COMPONENTS instead of everything + /// in the manifest. + std::vector<std::string> Components; for (unsigned j = 0; j != array_lengthof(AvailableComponents); ++j) { // Only include non-installed components when in a development tree. if (!AvailableComponents[j].IsInstalled && !IsInDevelopmentTree) continue; - OS << ' '; - OS << AvailableComponents[j].Name; + Components.push_back(AvailableComponents[j].Name); + if (AvailableComponents[j].Library && !IsInDevelopmentTree) { + if (DyLibExists && + !sys::fs::exists(GetComponentLibraryPath( + AvailableComponents[j].Library, false))) { + Components = GetAllDyLibComponents(IsInDevelopmentTree, true); + std::sort(Components.begin(), Components.end()); + break; + } + } + } + + for (unsigned I = 0; I < Components.size(); ++I) { + if (I) { + OS << ' '; + } + + OS << Components[I]; } OS << '\n'; } else if (Arg == "--targets-built") { @@ -323,6 +491,12 @@ int main(int argc, char **argv) { #else OS << "ON\n"; #endif + } else if (Arg == "--build-system") { + OS << LLVM_BUILD_SYSTEM << '\n'; + } else if (Arg == "--has-rtti") { + OS << LLVM_HAS_RTTI << '\n'; + } else if (Arg == "--shared-mode") { + PrintSharedMode = true; } else if (Arg == "--obj-root") { OS << ActivePrefix << '\n'; } else if (Arg == "--src-root") { @@ -338,35 +512,84 @@ int main(int argc, char **argv) { if (!HasAnyOption) usage(); - if (PrintLibs || PrintLibNames || PrintLibFiles || PrintSystemLibs) { + if (PrintLibs || PrintLibNames || PrintLibFiles || PrintSystemLibs || + PrintSharedMode) { + + if (PrintSharedMode && BuiltSharedLibs) { + OS << "shared\n"; + return 0; + } + // If no components were specified, default to "all". if (Components.empty()) Components.push_back("all"); // Construct the list of all the required libraries. - std::vector<StringRef> RequiredLibs; - ComputeLibsForComponents(Components, RequiredLibs, - /*IncludeNonInstalled=*/IsInDevelopmentTree); + bool HasMissing = false; + std::vector<std::string> RequiredLibs = + ComputeLibsForComponents(Components, + /*IncludeNonInstalled=*/IsInDevelopmentTree, + false, &ActiveLibDir, &HasMissing); + + if (PrintSharedMode) { + std::unordered_set<std::string> FullDyLibComponents; + std::vector<std::string> DyLibComponents = + GetAllDyLibComponents(IsInDevelopmentTree, false); + + for (auto &Component : DyLibComponents) { + FullDyLibComponents.insert(Component); + } + DyLibComponents.clear(); + + for (auto &Lib : RequiredLibs) { + if (!FullDyLibComponents.count(Lib)) { + OS << "static\n"; + return 0; + } + } + FullDyLibComponents.clear(); + + if (HasMissing && DyLibExists) { + OS << "shared\n"; + return 0; + } else { + OS << "static\n"; + return 0; + } + } if (PrintLibs || PrintLibNames || PrintLibFiles) { - for (unsigned i = 0, e = RequiredLibs.size(); i != e; ++i) { - StringRef Lib = RequiredLibs[i]; - if (i) - OS << ' '; + auto PrintForLib = [&](const StringRef &Lib, const bool ForceShared) { if (PrintLibNames) { - OS << Lib; + OS << GetComponentLibraryFileName(Lib, ForceShared); } else if (PrintLibFiles) { - OS << ActiveLibDir << '/' << Lib; + OS << GetComponentLibraryPath(Lib, ForceShared); } else if (PrintLibs) { // If this is a typical library name, include it using -l. - if (Lib.startswith("lib") && Lib.endswith(".a")) { - OS << "-l" << Lib.slice(3, Lib.size()-2); - continue; + StringRef LibName; + if (Lib.startswith("lib")) { + if (GetComponentLibraryNameSlice(Lib, LibName)) { + OS << "-l" << LibName; + } else { + OS << "-l:" << GetComponentLibraryFileName(Lib, ForceShared); + } + } else { + // Otherwise, print the full path. + OS << GetComponentLibraryPath(Lib, ForceShared); } + } + }; + + if (HasMissing && DyLibExists) { + PrintForLib(DyLibName, true); + } else { + for (unsigned i = 0, e = RequiredLibs.size(); i != e; ++i) { + auto Lib = RequiredLibs[i]; + if (i) + OS << ' '; - // Otherwise, print the full path. - OS << ActiveLibDir << '/' << Lib; + PrintForLib(Lib, false); } } OS << '\n'; |