Dogfood summary

In dogfood parts 1-4,I was able to create a native llvm-project within the <arch>-<vendor>-linux-gnu environment with a clear dependency path:

  1. build a functional clang++
  2. build a functional compiler-rt (libclang_rt.builtins.a)
  3. build native libraries (libc++, libc++abi, libunwind)
  4. build native compiler-rt
    in order to return to step 1 which this time builds a native clang.

Unfortunately this method consumes more resources (time and space) than it needs to, because each build installs to a staging area, sometimes installing over what came before. I do this because clang often looks for its resources relative to its own position. If anyone can show me how to avoid using a staging area (to achieve the same outcome) I would be grateful.
I am currently looking into the fact that:

  • I can override the location of headerfiles and isystem files
  • I can override the location of libc++
  • If I specify the full path of clang then I can use a compiler flag -resource-path to point to the compiler-rt files. Then because this messes up everything else, I need to use the other two :frowning:

Quite reasonably, I do not have access rights to make the code changes in order to use this technique. If someone could take a look and suggest changes or commit them I would be grateful:

diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index dc9901010737..ab825cb9a66c 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -515,28 +515,33 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
 
     if (IsIAMCU)
       CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
-    else if (HasCRTBeginEndFiles) {
-      std::string P;
-      if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT &&
-          !isAndroid) {
-        std::string crtbegin = ToolChain.getCompilerRT(Args, "crtbegin",
-                                                       ToolChain::FT_Object);
-        if (ToolChain.getVFS().exists(crtbegin))
-          P = crtbegin;
-      }
-      if (P.empty()) {
+    else {
+      std::string path;
+      if (isAndroid) {
         const char *crtbegin;
         if (Args.hasArg(options::OPT_shared))
-          crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
+          crtbegin = "crtbegin_so.o";
         else if (IsStatic)
-          crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
+          crtbegin = "crtbegin_static.o";
         else if (IsPIE || IsStaticPIE)
-          crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
+          crtbegin = "crtbegin_dynamic.o";
         else
-          crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
-        P = ToolChain.GetFilePath(crtbegin);
+          crtbegin = "crtbegin_dynamic.o";
+        path = ToolChain.GetFilePath(crtbegin);
+      } else if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_Libgcc) {
+        const char *crtbegin;
+        if (Args.hasArg(options::OPT_shared))
+          crtbegin = "crtbeginS.o";
+        else if (IsStatic)
+          crtbegin = "crtbeginT.o";
+        else if (IsPIE || IsStaticPIE)
+          crtbegin = "crtbeginS.o";
+        else
+          crtbegin = "crtbegin.o";
+        path = ToolChain.GetFilePath(crtbegin);
       }
-      CmdArgs.push_back(Args.MakeArgString(P));
+      if (!path.empty())
+        CmdArgs.push_back(Args.MakeArgString(path));
     }
 
     // Add crtfastmath.o if available and fast math is enabled.
@@ -658,29 +663,32 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
     }
 
     if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) {
-      if (HasCRTBeginEndFiles) {
-        std::string P;
-        if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT &&
-            !isAndroid) {
-          std::string crtend = ToolChain.getCompilerRT(Args, "crtend",
-                                                       ToolChain::FT_Object);
-          if (ToolChain.getVFS().exists(crtend))
-            P = crtend;
-        }
-        if (P.empty()) {
-          const char *crtend;
-          if (Args.hasArg(options::OPT_shared))
-            crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
-          else if (IsPIE || IsStaticPIE)
-            crtend = isAndroid ? "crtend_android.o" : "crtendS.o";
-          else
-            crtend = isAndroid ? "crtend_android.o" : "crtend.o";
-          P = ToolChain.GetFilePath(crtend);
-        }
-        CmdArgs.push_back(Args.MakeArgString(P));
+      std::string path;
+      if (isAndroid) {
+        const char *crtend;
+        if (Args.hasArg(options::OPT_shared))
+          crtend = "crtend_so.o";
+        else if (IsPIE || IsStaticPIE)
+          crtend = "crtend_android.o";
+        else
+          crtend = "crtend_android.o";
+        path = ToolChain.GetFilePath(crtend);
+      } else if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_Libgcc) {
+        const char *crtend;
+        if (Args.hasArg(options::OPT_shared))
+          crtend = "crtendS.o";
+        else if (IsPIE || IsStaticPIE)
+          crtend = "crtendS.o";
+        else
+          crtend = "crtend.o";
+        path = ToolChain.GetFilePath(crtend);
       }
-      if (!isAndroid)
-        CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+      if (!path.empty())
+        CmdArgs.push_back(Args.MakeArgString(path));
+    }
+
+    if (!isAndroid) {
+      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
     }
   }

In the original code, if the crtbegin or crtend file found in getCompilerRT did not exist
then it would attempt to use the ones associated with libgcc which is a bug.
I first modified this code into 3 clear sections, but then realised that neither of these files are neccessary for compiler-rt and to fail a compile because clang cannot find two files that are not required was a bigger bug.

Also in the original code, a variable ‘HasCRTBeginEndFiles’ is used. This variable checks to see if the triple has an environment (presumably GNU) or if the vendor was MipsTechnologies. I presumed that if the environment was not GNU then the code was misplaced in this GNU driver.

diff --git a/compiler-rt/cmake/base-config-ix.cmake b/compiler-rt/cmake/base-config-ix.cmake
index 8a6219568b3f..f9cff1f44027 100644
--- a/compiler-rt/cmake/base-config-ix.cmake
+++ b/compiler-rt/cmake/base-config-ix.cmake
@@ -32,20 +32,15 @@ set_property(
 
 # Setting these variables from an LLVM build is sufficient that compiler-rt can
 # construct the output paths, so it can behave as if it were in-tree here.
-if (LLVM_LIBRARY_OUTPUT_INTDIR AND LLVM_RUNTIME_OUTPUT_INTDIR AND PACKAGE_VERSION)
+if (LLVM_LIBRARY_OUTPUT_INTDIR AND LLVM_RUNTIME_OUTPUT_INTDIR AND CMAKE_C_COMPILER_VERSION)
   set(LLVM_TREE_AVAILABLE On)
 endif()
 
 if (LLVM_TREE_AVAILABLE)
-  # Compute the Clang version from the LLVM version.
-  # FIXME: We should be able to reuse CLANG_VERSION variable calculated
-  #        in Clang cmake files, instead of copying the rules here.
-  string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
-         ${PACKAGE_VERSION})
   # Setup the paths where compiler-rt runtimes and headers should be stored.
-  set(COMPILER_RT_OUTPUT_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION})
+  set(COMPILER_RT_OUTPUT_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CMAKE_C_COMPILER_VERSION})
   set(COMPILER_RT_EXEC_OUTPUT_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
-  set(COMPILER_RT_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
+  set(COMPILER_RT_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CMAKE_C_COMPILER_VERSION})
   option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests."
          ${LLVM_INCLUDE_TESTS})
   option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered"

Here LLVM_TREE_AVAILABLE was failing because the PACKAGE_VERSION flag was unavailable. This caused the compiler-rt files to be stored in the wrong place. I replaced it with the more generally available CMAKE_C_COMPILER_VERSION to fix it.

I thought about replacing the word clang with CMAKE_COMPILER_ID just in case someone tried to use a different compiler but decided it could create problems beyond my understanding.

diff --git a/libcxx/cmake/config-ix.cmake b/libcxx/cmake/config-ix.cmake
index 209e6214a471..8a619b2647c1 100644
--- a/libcxx/cmake/config-ix.cmake
+++ b/libcxx/cmake/config-ix.cmake
@@ -125,5 +125,9 @@ else()
   check_library_exists(m ccos "" LIBCXX_HAS_M_LIB)
   check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB)
   set(LIBCXX_HAS_SYSTEM_LIB NO)
-  check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB)
+  if (LIBCXX_USE_COMPILER_RT)
+    set(LIBCXX_HAS_ATOMIC_LIB NO)
+  else()
+    check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB)
+  endif()
 endif()

Even if we are asking the to use compiler-rt, the code looks for the GNU Compiler Collection’s libatomic which is probably a bug.
I fixed it by making the check dependent on LIBCXX_USE_COMPILER_RT

I wan’t sure if this fix was also required for Fuchsia a few lines up.

You should put your code changes on Phabricator to get a review. See: Code Reviews with Phabricator — LLVM 16.0.0git documentation