diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h --- a/clang/include/clang/Driver/Multilib.h +++ b/clang/include/clang/Driver/Multilib.h @@ -31,19 +31,39 @@ public: using flags_list = std::vector; + /// When -print-multi-lib is used, this defines how the printed options must + /// be calculated. + enum class PrintOptionsType { + /// Use the options stored in PrintOptionsList + List, + /// Print flags in the Flags list that begin with '+', but with the initial + /// '+' replaced with '-'. e.g. "+fno-rtti" becomes "-fno-rtti" + PlusFlags, + }; + private: std::string GCCSuffix; std::string OSSuffix; std::string IncludeSuffix; flags_list Flags; + flags_list PrintOptionsList; + PrintOptionsType PrintOptions; public: /// GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the /// sysroot string so they must either be empty or begin with a '/' character. /// This is enforced with an assert in the constructor. + /// Flags is the set of flags that indicate this multilib's use. See the + /// flags() method for more information. + /// If PrintOptions is something other than PrintOptionsType::List then + /// PrintOptionsList must be empty. This is enforced with an assert in the + /// constructor. + /// Each value in PrintOptionsList should be a complete valid Clang option, + /// for example "-fno-exceptions", but the constructor does not enforce this. Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {}, - StringRef IncludeSuffix = {}, - const flags_list &Flags = flags_list()); + StringRef IncludeSuffix = {}, const flags_list &Flags = flags_list(), + PrintOptionsType PrintOptions = PrintOptionsType::PlusFlags, + const flags_list &PrintOptionsList = flags_list()); /// Get the detected GCC installation path suffix for the multi-arch /// target variant. Always starts with a '/', unless empty @@ -57,10 +77,15 @@ /// empty const std::string &includeSuffix() const { return IncludeSuffix; } - /// Get the flags that indicate or contraindicate this multilib's use - /// All elements begin with either '+' or '-' + /// Get the set of flags that indicate this multilib's use. + /// Flags are arbitrary strings although typically they will look similar to + /// command line options. A multilib is considered compatible if its flags are + /// a subset of the flags derived from the Clang command line options. const flags_list &flags() const { return Flags; } + /// Returns the options that should be used for clang -print-multi-lib + flags_list getPrintOptions() const; + LLVM_DUMP_METHOD void dump() const; /// print summary of the Multilib void print(raw_ostream &OS) const; diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -26,15 +26,43 @@ using namespace llvm::sys; Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, - StringRef IncludeSuffix, const flags_list &Flags) + StringRef IncludeSuffix, const flags_list &Flags, + PrintOptionsType PrintOptions, + const flags_list &PrintOptionsList) : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), - Flags(Flags) { + Flags(Flags), PrintOptionsList(PrintOptionsList), + PrintOptions(PrintOptions) { assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); assert(OSSuffix.empty() || (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); assert(IncludeSuffix.empty() || (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); + // If PrintOptions is something other than List then PrintOptionsList must be + // empty. + assert(PrintOptions == PrintOptionsType::List || PrintOptionsList.empty()); +} + +static Multilib::flags_list +getPrintOptionsFromPlusFlags(const Multilib::flags_list &Flags) { + // Derive print options from flags beginning '+', replacing the first + // character with '-'. + Multilib::flags_list PrintOptions; + for (StringRef Flag : Flags) { + if (Flag.front() == '+') + PrintOptions.push_back(("-" + Flag.substr(1)).str()); + } + return PrintOptions; +} + +Multilib::flags_list Multilib::getPrintOptions() const { + switch (PrintOptions) { + case PrintOptionsType::List: + return PrintOptionsList; + case PrintOptionsType::PlusFlags: + return getPrintOptionsFromPlusFlags(Flags); + } + llvm_unreachable("Unknown Multilib::PrintOptionsType"); } LLVM_DUMP_METHOD void Multilib::dump() const { @@ -44,14 +72,11 @@ void Multilib::print(raw_ostream &OS) const { if (GCCSuffix.empty()) OS << "."; - else { + else OS << StringRef(GCCSuffix).drop_front(); - } OS << ";"; - for (StringRef Flag : Flags) { - if (Flag.front() == '+') - OS << "@" << Flag.substr(1); - } + for (StringRef Option : getPrintOptions()) + OS << "@" << Option.substr(1); } bool Multilib::operator==(const Multilib &Other) const { diff --git a/clang/unittests/Driver/MultilibBuilderTest.cpp b/clang/unittests/Driver/MultilibBuilderTest.cpp --- a/clang/unittests/Driver/MultilibBuilderTest.cpp +++ b/clang/unittests/Driver/MultilibBuilderTest.cpp @@ -207,3 +207,14 @@ << "Selection picked " << Selection << " which was not expected "; } } + +TEST(MultilibBuilderTest, PrintOptions) { + Multilib M = MultilibBuilder() + .flag("+x") + .flag("-y") + .flag("+a") + .flag("-b") + .flag("+c") + .makeMultilib(); + ASSERT_EQ(Multilib::flags_list({"-x", "-a", "-c"}), M.getPrintOptions()); +} diff --git a/clang/unittests/Driver/MultilibTest.cpp b/clang/unittests/Driver/MultilibTest.cpp --- a/clang/unittests/Driver/MultilibTest.cpp +++ b/clang/unittests/Driver/MultilibTest.cpp @@ -187,3 +187,19 @@ EXPECT_EQ("/a", Selection[0].gccSuffix()); EXPECT_EQ("/b", Selection[1].gccSuffix()); } + +TEST(MultilibBuilder, PrintOptions) { + ASSERT_EQ(Multilib::flags_list(), Multilib().getPrintOptions()); + ASSERT_EQ(Multilib::flags_list({"-x"}), + Multilib({}, {}, {}, {"+x"}).getPrintOptions()); + ASSERT_EQ(Multilib::flags_list({"-x"}), + Multilib({}, {}, {}, {"+x"}, Multilib::PrintOptionsType::PlusFlags) + .getPrintOptions()); + ASSERT_EQ( + Multilib::flags_list({"-x", "-a", "-c"}), + Multilib({}, {}, {}, {"+x", "-y", "+a", "-b", "+c"}).getPrintOptions()); + ASSERT_EQ( + Multilib::flags_list({"-y"}), + Multilib({}, {}, {}, {"+x"}, Multilib::PrintOptionsType::List, {"-y"}) + .getPrintOptions()); +}