@@ -97,9 +97,23 @@ static bool findRISCVMultilibs(const Driver &D,
9797 return false ;
9898}
9999
100+ static std::string computeBaseSysRoot (const Driver &D, bool IncludeTriple) {
101+ if (!D.SysRoot .empty ())
102+ return D.SysRoot ;
103+
104+ SmallString<128 > SysRootDir (D.Dir );
105+ llvm::sys::path::append (SysRootDir, " .." , " lib" , " clang-runtimes" );
106+
107+ if (IncludeTriple)
108+ llvm::sys::path::append (SysRootDir, D.getTargetTriple ());
109+
110+ return std::string (SysRootDir);
111+ }
112+
100113BareMetal::BareMetal (const Driver &D, const llvm::Triple &Triple,
101114 const ArgList &Args)
102- : ToolChain(D, Triple, Args) {
115+ : ToolChain(D, Triple, Args),
116+ SysRoot(computeBaseSysRoot(D, /* IncludeTriple=*/ true )) {
103117 getProgramPaths ().push_back (getDriver ().Dir );
104118
105119 findMultilibs (D, Triple, Args);
@@ -186,45 +200,62 @@ static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
186200 return ;
187201 D.Diag (clang::diag::warn_drv_missing_multilib) << llvm::join (Flags, " " );
188202 std::stringstream ss;
203+
204+ // If multilib selection didn't complete successfully, report a list
205+ // of all the configurations the user could have provided.
189206 for (const Multilib &Multilib : Result.Multilibs )
190- if (!Multilib.isFatalError ())
207+ if (!Multilib.isError ())
191208 ss << " \n " << llvm::join (Multilib.flags (), " " );
192209 D.Diag (clang::diag::note_drv_available_multilibs) << ss.str ();
210+
211+ // Now report any custom error messages requested by the YAML. We do
212+ // this after displaying the list of available multilibs, because
213+ // that list is probably large, and (in interactive use) risks
214+ // scrolling the useful error message off the top of the user's
215+ // terminal.
216+ for (const Multilib &Multilib : Result.SelectedMultilibs )
217+ if (Multilib.isError ())
218+ D.Diag (clang::diag::err_drv_multilib_custom_error)
219+ << Multilib.getErrorMessage ();
220+
221+ // If there was an error, clear the SelectedMultilibs vector, in
222+ // case it contains partial data.
223+ Result.SelectedMultilibs .clear ();
193224}
194225
195226static constexpr llvm::StringLiteral MultilibFilename = " multilib.yaml" ;
196227
197- // Get the sysroot, before multilib takes effect.
198- static std::string computeBaseSysRoot (const Driver &D,
199- const llvm::Triple &Triple) {
200- if (!D.SysRoot .empty ())
201- return D.SysRoot ;
202-
203- SmallString<128 > SysRootDir (D.Dir );
204- llvm::sys::path::append (SysRootDir, " .." , " lib" , " clang-runtimes" );
205-
206- SmallString<128 > MultilibPath (SysRootDir);
207- llvm::sys::path::append (MultilibPath, MultilibFilename);
208-
209- // New behaviour: if multilib.yaml is found then use clang-runtimes as the
210- // sysroot.
211- if (D.getVFS ().exists (MultilibPath))
212- return std::string (SysRootDir);
213-
214- // Otherwise fall back to the old behaviour of appending the target triple.
215- llvm::sys::path::append (SysRootDir, D.getTargetTriple ());
216- return std::string (SysRootDir);
228+ static std::optional<llvm::SmallString<128 >>
229+ getMultilibConfigPath (const Driver &D, const llvm::Triple &Triple,
230+ const ArgList &Args) {
231+ llvm::SmallString<128 > MultilibPath;
232+ if (Arg *ConfigFileArg = Args.getLastArg (options::OPT_multi_lib_config)) {
233+ MultilibPath = ConfigFileArg->getValue ();
234+ if (!D.getVFS ().exists (MultilibPath)) {
235+ D.Diag (clang::diag::err_drv_no_such_file) << MultilibPath.str ();
236+ return {};
237+ }
238+ } else {
239+ MultilibPath = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
240+ llvm::sys::path::append (MultilibPath, MultilibFilename);
241+ }
242+ return MultilibPath;
217243}
218244
219245void BareMetal::findMultilibs (const Driver &D, const llvm::Triple &Triple,
220246 const ArgList &Args) {
221247 DetectedMultilibs Result;
222248 // Look for a multilib.yaml before trying target-specific hardwired logic.
223249 // If it exists, always do what it specifies.
224- llvm::SmallString<128 > MultilibPath (computeBaseSysRoot (D, Triple));
225- llvm::sys::path::append (MultilibPath, MultilibFilename);
226- if (D.getVFS ().exists (MultilibPath)) {
227- findMultilibsFromYAML (*this , D, MultilibPath, Args, Result);
250+ std::optional<llvm::SmallString<128 >> MultilibPath =
251+ getMultilibConfigPath (D, Triple, Args);
252+ if (!MultilibPath)
253+ return ;
254+ if (D.getVFS ().exists (*MultilibPath)) {
255+ // If multilib.yaml is found, update sysroot so it doesn't use a target
256+ // specific suffix
257+ SysRoot = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
258+ findMultilibsFromYAML (*this , D, *MultilibPath, Args, Result);
228259 SelectedMultilibs = Result.SelectedMultilibs ;
229260 Multilibs = Result.Multilibs ;
230261 } else if (isRISCVBareMetal (Triple)) {
@@ -248,9 +279,7 @@ Tool *BareMetal::buildStaticLibTool() const {
248279 return new tools::baremetal::StaticLibTool (*this );
249280}
250281
251- std::string BareMetal::computeSysRoot () const {
252- return computeBaseSysRoot (getDriver (), getTriple ());
253- }
282+ std::string BareMetal::computeSysRoot () const { return SysRoot; }
254283
255284BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs () const {
256285 // Get multilibs in reverse order because they're ordered most-specific last.
0 commit comments