[cfe-dev] --gcc-toolchain (GCC_INSTALL_PREFIX) and --prefix(-B)

Fāng-ruì Sòng via cfe-dev cfe-dev at lists.llvm.org
Thu Mar 4 00:19:10 PST 2021


If --gcc-toolchain is specified, its value overrides the cmake variable
GCC_INSTALL_PREFIX.
When the value is non-empty: the value is appended to the --prefix list and
is used to detect GCC installations.
The GCC installation is used to provide include directories/library
directories and some startup files (e.g. crtbegin).

Problem 1.

--prefix(-B) does more than --gcc-toolchain:
clang::driver::Driver::GetProgramPath basically searches for
$prefix/$triple-$file and $prefix$file,
where $prefix is taken from the list of --prefix(-B). --gcc-toolchain does
not participate in the search. <have attached a summary of the algorithm at
the bottom>
The result is that 'ld' and 'as' may come from the system (more precisely,
sysroot):

cd clang/test/Driver
# Make sure Inputs/opensuse_42.2_aarch64_tree/usr/bin/ld exists.
clang -target aarch64-suse-linux
--gcc-toolchain=Inputs/opensuse_42.2_aarch64_tree/usr '-###'
gcc-toolchain.cpp -v

   # I have ld in my /usr/local/bin and it takes precedence over /usr/bin/ld
 "/usr/local/bin/ld" "-EL" "--eh-frame-hdr" "-m" "aarch64linux"
"-dynamic-linker" "/lib/ld-linux-aarch64.so.1" "-o" "a.out"
"Inputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8/../../../../lib64/crt1.o"
"Inputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8/../../../../lib64/crti.o"
"Inputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8/crtbegin.o"
"-LInputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8"
"-LInputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8/../../../../lib64"
"-L/lib/aarch64-linux-gnu" "-L/lib/../lib64" "-L/usr/lib/aarch64-linux-gnu"
"-L/usr/lib/../lib64"
"-LInputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8/../../.."
"-L/tmp/RelA/bin/../lib" "-L/lib" "-L/usr/lib"
"/tmp/gcc-toolchain-f87f08.o" "-lgcc" "--as-needed" "-lgcc_s"
"--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
"Inputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8/crtend.o"
"Inputs/opensuse_42.2_aarch64_tree/usr/lib64/gcc/aarch64-suse-linux/4.8/../../../../lib64/crtn.o"

The -L and crt* files are indeed from
Inputs/opensuse_42.2_aarch64_tree/usr, but ld (and as if
-fno-integrated-as) is from the system.
On many Linux distributions you can normally assume that the system ld and
as only support the host architecture.
This means --gcc-toolchain can only be used to specify a GCC installation
with the same architecture.
--prefix can make as and ld paths correct, but: if another --prefix is
needed, why do we use --gcc-toolchain?

I have sent a patch to document the current state:
https://reviews.llvm.org/D97902


Problem 2.

Non-empty --gcc-toolchain has one nicer property: it suppresses GCC
installation detection in the sysroot.
Now let me alter the command a bit:

 "/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../../../aarch64-linux-gnu/bin/ld"
"-EL" "--eh-frame-hdr" "-m" "aarch64linux" "-dynamic-linker"
"/lib/ld-linux-aarch64.so.1" "-o" "a.out"
"/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../..
/../aarch64-linux-gnu/lib/crt1.o"
"/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../../../aarch64-linux-gnu/lib/crti.o"
"/usr/lib/gcc-cross/aarch64-linux-gnu/10/crtbegin.o"
"-L/usr/lib/gcc-cross/aarch64-linux-gnu/10"
"-L/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../../aarch64-linux-gnu"
"-L/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../../../lib64"
"-L/lib/aarch64-linux-gnu" "-L/lib/../lib64" "-L/usr/lib/aarch64-linux-gnu"
"-L/usr/lib/../lib64" "-L/usr/lib/aarch64-linux-gnu/../../lib64"
"-L/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../../../aarch64-linux-gnu/lib"
"-L/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../.."
"-L/tmp/RelA/bin/../lib" "-L/lib" "-L/usr/lib"
"/tmp/gcc-toolchain-b491cd.o" "-lgcc" "--as-needed" "-lgcc_s"
"--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
"/usr/lib/gcc-cross/aarch64-linux-gnu/10/crtend.o"
"/usr/lib/gcc-cross/aarch64-linux-gnu/10/../../../../aarch64-linux-gnu/lib/crtn.o"

I have installed an aarch64 cross gcc. Because its version is larger than
the version of the GCC installation under --prefix, the system
gcc-cross/aarch64-linux-gnu takes precedence.
This behavior looks a bit unfortunate. Should we let the first --prefix win
and drop future --prefix and default system installations?



[1]:

The logic is around
https://github.com/llvm/llvm-project/blob/main/clang/lib/Driver/ToolChains/Gnu.cpp#L1910

   Prefixes = --prefix/-B list (only the directory subset is effective)
   StringRef GCCToolchainDir = --gcc-toolchain= or CMake variable
GCC_INSTALL_PREFIX
   if (GCCToolchainDir != "") {
     Prefixes.push_back(std::string(GCCToolchainDir));
   } else {
     if (!D.SysRoot.empty()) {
       Prefixes.push_back(D.SysRoot);
       // Add D.SysRoot+"/usr" to Prefixes. Some distributions add more
directories.
       AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot);
     }

     // D.InstalledDir is the directory of the clang executable, e.g.
/usr/bin
     Prefixes.push_back(D.InstalledDir + "/..");

     if (D.SysRoot.empty())
       AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot);
   }

   // Gentoo / ChromeOS specific logic.
   // I will move this block in https://reviews.llvm.org/D97894
   if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") {
     ...
   }

   // Loop over the various components which exist and select the best GCC
   // installation available. GCC installs are ranked by version number.
   Version = GCCVersion::Parse("0.0.0");
   for (const std::string &Prefix : Prefixes) {
     auto &VFS = D.getVFS();
     if (!VFS.exists(Prefix))
       continue;

     // CandidateLibDirs is a subset of {/lib64, /lib32, /lib}.
     for (StringRef Suffix : CandidateLibDirs) {
       const std::string LibDir = Prefix + Suffix.str();
       if (!VFS.exists(LibDir))
         continue;
       bool GCCDirExists = VFS.exists(LibDir + "/gcc");
       bool GCCCrossDirExists = VFS.exists(LibDir + "/gcc-cross");

       // Precise match. Detect $Prefix/lib/$--target
       ScanLibDirForGCCTriple(TargetTriple, Args, LibDir,
TargetTriple.str(),
                              false, GCCDirExists, GCCCrossDirExists);
       // Usually empty.
       for (StringRef Candidate : ExtraTripleAliases) // Try these first.
         ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate,
false,
                                GCCDirExists, GCCCrossDirExists);
       // CandidateTripleAliases is a set with "x86_64-linux-gnu",
"x86_64-unknown-linux-gnu", ...
       // This loop detects directories like $Prefix/lib/x86_64-linux-gnu.
       for (StringRef Candidate : CandidateTripleAliases)
         ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate,
false,
                                GCCDirExists, GCCCrossDirExists);
     }
     for (StringRef Suffix : CandidateBiarchLibDirs) {
       const std::string LibDir = Prefix + Suffix.str();
       if (!VFS.exists(LibDir))
         continue;
       bool GCCDirExists = VFS.exists(LibDir + "/gcc");
       bool GCCCrossDirExists = VFS.exists(LibDir + "/gcc-cross");
       for (StringRef Candidate : CandidateBiarchTripleAliases)
         ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, true,
                                GCCDirExists, GCCCrossDirExists);
     }
   }


-- 
宋方睿
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20210304/b02b6ba7/attachment.html>


More information about the cfe-dev mailing list