TEST(MultilibTest, SetSelection2) { MultilibSet MS2 = MultilibSet() .Maybe(Multilib("el").flag("+EL")) .Maybe(Multilib("sf").flag("+SF")); for (unsigned I = 0; I < 4; ++I) { bool IsEL = I & 0x1; bool IsSF = I & 0x2; Multilib::flags_list Flags; if (IsEL) Flags.push_back("+EL"); else Flags.push_back("-EL"); if (IsSF) Flags.push_back("+SF"); else Flags.push_back("-SF"); Multilib Selection; ASSERT_TRUE(MS2.select(Flags, Selection)) << "Selection failed for " << (IsEL ? "+EL" : "-EL") << " " << (IsSF ? "+SF" : "-SF"); std::string Suffix; if (IsEL) Suffix += "/el"; if (IsSF) Suffix += "/sf"; ASSERT_EQ(Selection.gccSuffix(), Suffix) << "Selection picked " << Selection << " which was not expected "; } }
MultilibSet &MultilibSet::Maybe(const Multilib &M) { Multilib Opposite; // Negate any '+' flags for (StringRef Flag : M.flags()) { if (Flag.front() == '+') Opposite.flags().push_back(("-" + Flag.substr(1)).str()); } return Either(M, Opposite); }
TEST(MultilibTest, Construction3) { Multilib M = Multilib().flag("+f1").flag("+f2").flag("-f3"); for (Multilib::flags_list::const_iterator I = M.flags().begin(), E = M.flags().end(); I != E; ++I) { ASSERT_TRUE(llvm::StringSwitch<bool>(*I) .Cases("+f1", "+f2", "-f3", true) .Default(false)); } }
static bool hasFlag(const Multilib &M, StringRef Flag) { for (Multilib::flags_list::const_iterator I = M.flags().begin(), E = M.flags().end(); I != E; ++I) { if (*I == Flag) return true; else if (StringRef(*I).substr(1) == Flag.substr(1)) return false; } return false; }
bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { llvm::StringMap<bool> FlagSet; // Stuff all of the flags into the FlagSet such that a true mappend indicates // the flag was enabled, and a false mappend indicates the flag was disabled. for (StringRef Flag : Flags) FlagSet[Flag.substr(1)] = isFlagEnabled(Flag); multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) { for (StringRef Flag : M.flags()) { llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1)); if (SI != FlagSet.end()) if (SI->getValue() != isFlagEnabled(Flag)) return true; } return false; }, Multilibs); if (Filtered.size() == 0) { return false; } else if (Filtered.size() == 1) { M = Filtered[0]; return true; } // TODO: pick the "best" multlib when more than one is suitable assert(false); return false; }
static Multilib compose(const Multilib &Base, const Multilib &New) { SmallString<128> GCCSuffix; llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); SmallString<128> OSSuffix; llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); SmallString<128> IncludeSuffix; llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), New.includeSuffix()); Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix); Multilib::flags_list &Flags = Composed.flags(); Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); return Composed; }
bool operator()(const Multilib &M) const override { for (StringRef Flag : M.flags()) { llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1)); if (SI != FlagSet.end()) if (SI->getValue() != isFlagEnabled(Flag)) return true; } return false; }
bool operator()(const Multilib &M) const override { std::string Error; if (!R.isValid(Error)) { llvm::errs() << Error; assert(false); return false; } return R.match(M.gccSuffix()); }
MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) { multilib_list Composed; if (Multilibs.empty()) Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), MultilibSegments.end()); else { for (const Multilib &New : MultilibSegments) { for (const Multilib &Base : *this) { Multilib MO = compose(Base, New); if (MO.isValid()) Composed.push_back(MO); } } Multilibs = Composed; } return *this; }
bool Multilib::operator==(const Multilib &Other) const { // Check whether the flags sets match // allowing for the match to be order invariant llvm::StringSet<> MyFlags; for (const auto &Flag : Flags) MyFlags.insert(Flag); for (const auto &Flag : Other.Flags) if (MyFlags.find(Flag) == MyFlags.end()) return false; if (osSuffix() != Other.osSuffix()) return false; if (gccSuffix() != Other.gccSuffix()) return false; if (includeSuffix() != Other.includeSuffix()) return false; return true; }
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); // Cross-compiling binutils and GCC installations (vanilla and openSUSE at // least) put various tools in a triple-prefixed directory off of the parent // of the GCC installation. We use the GCC triple here to ensure that we end // up with tools that support the same amount of cross compiling as the // detected GCC installation. For example, if we find a GCC installation // targeting x86_64, but it is a bi-arch GCC installation, it can also be // used to target i386. // FIXME: This seems unlikely to be Linux-specific. ToolChain::path_list &PPaths = getProgramPaths(); PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin") .str()); Distro Distro(D.getVFS()); if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); const bool IsAndroid = Triple.isAndroid(); const bool IsMips = tools::isMipsArch(Arch); const bool IsHexagon = Arch == llvm::Triple::hexagon; if (IsMips && !SysRoot.empty()) ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash // and the MIPS ABI require .dynsym to be sorted in different ways. // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. // Hexagon linker/loader does not support .gnu.hash if (!IsMips && !IsAndroid && !IsHexagon) { if (Distro.IsRedhat() || Distro.IsOpenSUSE() || (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); if (Distro.IsDebian() || Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid || Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); } if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6) ExtraOpts.push_back("--no-add-needed"); #ifdef ENABLE_LINKER_BUILD_ID ExtraOpts.push_back("--build-id"); #endif if (Distro.IsOpenSUSE()) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which // the GCC driver itself uses, as this is part of the GCC-compatible driver. // This was determined by running GCC in a fake filesystem, creating all // possible permutations of these directories, and seeing which ones it added // to the link paths. path_list &Paths = getFilePaths(); const std::string OSLibDir = getOSLibDir(Triple, Args); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = GCCInstallation.getParentLibPath(); const Multilib &Multilib = GCCInstallation.getMultilib(); const MultilibSet &Multilibs = GCCInstallation.getMultilibs(); // Add toolchain / multilib specific file paths. addMultilibsFilePaths(D, Multilibs, Multilib, GCCInstallation.getInstallPath(), Paths); // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(), Paths); // GCC cross compiling toolchains will install target libraries which ship // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as // any part of the GCC installation in // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat // debatable, but is the reality today. We need to search this tree even // when we have a sysroot somewhere else. It is the responsibility of // whomever is doing the cross build targeting a sysroot using a GCC // installation that is *not* within the system root to ensure two things: // // 1) Any DSOs that are linked in from this tree or from the install path // above must be present on the system root and found via an // appropriate rpath. // 2) There must not be libraries installed into // <prefix>/<triple>/<libdir> unless they should be preferred over // those within the system root. // // Note that this matches the GCC behavior. See the below comment for where // Clang diverges from GCC's behavior. addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + Multilib.osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to // prefer libraries installed in the parent prefix of the GCC installation. // It is important to *not* use these paths when the GCC installation is // outside of the system root as that can pick up unintended libraries. // This usually happens when there is an external cross compiler on the // host system, and a more minimal sysroot available that is the target of // the cross. Note that GCC does include some of these directories in some // configurations but this seems somewhere between questionable and simply // a bug. if (StringRef(LibPath).startswith(SysRoot)) { addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } // Similar to the logic for GCC above, if we currently running Clang inside // of the requested system root, add its parent library paths to // those searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) { addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); } addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); // Try walking via the GCC triple path in case of biarch or multiarch GCC // installations with strange symlinks. if (GCCInstallation.isValid()) { addPathIfExists(D, SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + "/../../" + OSLibDir, Paths); // Add the 'other' biarch variant path Multilib BiarchSibling; if (GCCInstallation.getBiarchSibling(BiarchSibling)) { addPathIfExists(D, GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(), Paths); } // See comments above on the multilib variant for details of why this is // included even from outside the sysroot. const std::string &LibPath = GCCInstallation.getParentLibPath(); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const Multilib &Multilib = GCCInstallation.getMultilib(); addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + Multilib.osSuffix(), Paths); // See comments above on the multilib variant for details of why this is // only included from within the sysroot. if (StringRef(LibPath).startswith(SysRoot)) addPathIfExists(D, LibPath, Paths); } // Similar to the logic for GCC above, if we are currently running Clang // inside of the requested system root, add its parent library path to those // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, SysRoot + "/lib", Paths); addPathIfExists(D, SysRoot + "/usr/lib", Paths); }
bool operator()(const Multilib &M) const override { return StringRef(M.gccSuffix()).startswith("/p"); }