[libc-commits] [libc] 4f9c10e - [libc] Add support for standalone cross compilation of libc.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Mon Dec 19 16:33:45 PST 2022


Author: Siva Chandra Reddy
Date: 2022-12-20T00:33:35Z
New Revision: 4f9c10eb48a3725ecfd844d44ccf3068fbadbb85

URL: https://github.com/llvm/llvm-project/commit/4f9c10eb48a3725ecfd844d44ccf3068fbadbb85
DIFF: https://github.com/llvm/llvm-project/commit/4f9c10eb48a3725ecfd844d44ccf3068fbadbb85.diff

LOG: [libc] Add support for standalone cross compilation of libc.

One should be able to do a cross build of the libc now. For example, using
clang on a x86_64 linux host, one can build for an aarch64 linux target by
specifying -DLIBC_TARGET_TRIPLE=aarch64-linux-gnu.

Follow up changes will add a baremetal config and also appropriate
documentation about cross compiling the libc for CPU targets.

Reviewed By: jhuber6

Differential Revision: https://reviews.llvm.org/D140351

Added: 
    

Modified: 
    libc/CMakeLists.txt
    libc/cmake/modules/LLVMLibCArchitectures.cmake
    libc/cmake/modules/prepare_libc_gpu_build.cmake
    libc/docs/gpu_mode.rst

Removed: 
    


################################################################################
diff  --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index fa0ce829a168a..8eb45838f954a 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -55,17 +55,18 @@ option(LLVM_LIBC_FULL_BUILD "Build and test LLVM libc as if it is the full libc"
 option(LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR "Build LLVM libc tests assuming our implementation-defined behavior" ON)
 option(LLVM_LIBC_ENABLE_LINTING "Enables linting of libc source files" OFF)
 
-set(LLVM_LIBC_TARGET_OS ${CMAKE_SYSTEM_NAME} CACHE STRING "Target operating system for LLVM libc")
-string(TOLOWER ${LLVM_LIBC_TARGET_OS} LIBC_TARGET_OS)
+option(LIBC_GPU_BUILD "Build libc for the GPU. All CPU build options will be ignored." OFF)
+set(LIBC_TARGET_TRIPLE "" CACHE STRING "The target triple for the libc build.")
 
 # Defines LIBC_TARGET_ARCHITECTURE and associated macros.
 include(LLVMLibCArchitectures)
-include(LLVMLibCCheckMPFR)
 
 if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
   include(prepare_libc_gpu_build)
 endif()
 
+include(LLVMLibCCheckMPFR)
+
 if(LLVM_LIBC_CLANG_TIDY)
   set(LLVM_LIBC_ENABLE_LINTING ON)
 endif()

diff  --git a/libc/cmake/modules/LLVMLibCArchitectures.cmake b/libc/cmake/modules/LLVMLibCArchitectures.cmake
index 9da74c4410d84..3c99f645e4867 100644
--- a/libc/cmake/modules/LLVMLibCArchitectures.cmake
+++ b/libc/cmake/modules/LLVMLibCArchitectures.cmake
@@ -1,25 +1,139 @@
 # ------------------------------------------------------------------------------
-# Architecture definitions
+# Architecture and OS definitions.
+#
+# The correct target OS and architecture to build the libc for is deduced here.
+# When possible, we also setup appropriate compile options for the target
+# platform.
 # ------------------------------------------------------------------------------
 
-if(LIBC_TARGET_OS MATCHES "gpu")
+if(LIBC_GPU_BUILD)
+  # We set the generic target and OS to "gpu" here. More specific defintions
+  # for the exact target GPU are set up in prepare_libc_gpu_build.cmake.
+  set(LIBC_TARGET_OS "gpu")
   set(LIBC_TARGET_ARCHITECTURE_IS_GPU TRUE)
   set(LIBC_TARGET_ARCHITECTURE "gpu")
-elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
-  set(LIBC_TARGET_ARCHITECTURE_IS_MIPS TRUE)
-  set(LIBC_TARGET_ARCHITECTURE "mips")
-elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
-  set(LIBC_TARGET_ARCHITECTURE_IS_ARM TRUE)
-  set(LIBC_TARGET_ARCHITECTURE "arm")
-elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
-  set(LIBC_TARGET_ARCHITECTURE_IS_AARCH64 TRUE)
-  set(LIBC_TARGET_ARCHITECTURE "aarch64")
-elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)")
-  set(LIBC_TARGET_ARCHITECTURE_IS_X86 TRUE)
-  set(LIBC_TARGET_ARCHITECTURE "x86_64")
-elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
-  set(LIBC_TARGET_ARCHITECTURE_IS_POWER TRUE)
-  set(LIBC_TARGET_ARCHITECTURE "power")
+  if(LIBC_TARGET_TRIPLE)
+    message(WARNING "LIBC_TARGET_TRIPLE is ignored as LIBC_GPU_BUILD is on. ")
+  endif()
+  return()
+endif()
+
+if(MSVC)
+  # If the compiler is visual c++ or equivalent, we will assume a host build.
+  set(LIBC_TARGET_OS ${CMAKE_HOST_SYSTEM_NAME})
+  string(TOLOWER ${LIBC_TARGET_OS} LIBC_TARGET_OS)
+  set(LIBC_TARGET_ARCHITECTURE ${CMAKE_HOST_SYSTEM_PROCESSOR})
+  if(LIBC_TARGET_TRIPLE)
+    message(WARNING "libc build: Detected MSVC or equivalent compiler; "
+                    "LIBC_TARGET_TRIPLE is ignored and a host build is assumed.")
+  endif()
+  return()
+endif()
+
+# A helper function to get the architecture and system components from a target
+# triple.
+function(get_arch_and_system_from_triple triple arch_var sys_var)
+  string(REPLACE "-" ";" triple_comps ${triple})
+  list(LENGTH triple_comps triple_size)
+  if(triple_size LESS "3")
+    return()
+  endif()
+  math(EXPR system_index "${triple_size} - 2")
+  list(GET triple_comps 0 target_arch)
+  # The target_arch string can have sub-architecture suffixes which we want to
+  # remove. So, we regex-match the string and set target_arch to a cleaner
+  # value.
+  if(target_arch MATCHES "^mips")
+    set(target_arch "mips")
+  elseif(target_arch MATCHES "^arm")
+    set(target_arch "arm")
+  elseif(target_arch MATCHES "^aarch64")
+    set(target_arch "aarch64")
+  elseif(target_arch MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)")
+    set(target_arch "x86_64")
+  elseif(target_arch MATCHES "^(powerpc|ppc)")
+    set(target_arch "power")
+  else()
+    return()
+  endif()
+
+  set(${arch_var} ${target_arch} PARENT_SCOPE)
+  list(GET triple_comps ${system_index} target_sys)
+  set(${sys_var} ${target_sys} PARENT_SCOPE)
+endfunction(get_arch_and_system_from_triple)
+
+# Query the default target triple of the compiler.
+set(target_triple_option "-print-target-triple")
+if(CMAKE_COMPILER_IS_GNUCXX)
+  # GCC does not support the "-print-target-triple" option but supports
+  # "-print-multiarch" which clang does not support for all targets.
+  set(target_triple_option "-print-multiarch")
+endif()
+execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${target_triple_option}
+                RESULT_VARIABLE libc_compiler_triple_check
+                OUTPUT_VARIABLE libc_compiler_triple)
+if(NOT (libc_compiler_triple_check EQUAL "0"))
+  message(FATAL_ERROR "libc build: error querying target triple from the "
+                      "compiler: ${libc_compiler_triple}")
+endif()
+get_arch_and_system_from_triple(${libc_compiler_triple}
+                                compiler_arch compiler_sys)
+if(NOT compiler_arch)
+  message(FATAL_ERROR
+          "libc build: Invalid or unknown libc compiler target triple: "
+          "${libc_compiler_triple}")
+endif()
+
+set(LIBC_TARGET_ARCHITECTURE ${compiler_arch})
+set(LIBC_TARGET_OS ${compiler_sys})
+
+# The libc's target architecture and OS are set to match the compiler's default
+# target triple above. However, one can explicitly set LIBC_TARGET_TRIPLE. If it
+# is and does not match the compiler's target triple, then we will use it set up
+# libc's target architecture and OS.
+if(LIBC_TARGET_TRIPLE)
+  get_arch_and_system_from_triple(${LIBC_TARGET_TRIPLE} libc_arch libc_sys)
+  if(NOT libc_arch)
+    message(FATAL_ERROR
+            "libc build: Invalid or unknown triple in LIBC_TARGET_TRIPLE: "
+            "${LIBC_TARGET_TRIPLE}")
+  endif()
+  set(LIBC_TARGET_ARCHITECTURE ${libc_arch})
+  set(LIBC_TARGET_OS ${libc_sys})
+endif()
+
+if((LIBC_TARGET_OS STREQUAL "unknown") OR (LIBC_TARGET_OS STREQUAL "none"))
+  # We treat "unknown" and "none" systems as baremetal targets.
+  set(LIBC_TARGET_OS "baremetal")
+endif()
+
+# Set up some convenient vars to make conditionals easy to use in other parts of
+# the libc CMake infrastructure. Also, this is where we also check if the target
+# architecture is currently supported.
+if(LIBC_TARGET_ARCHITECTURE STREQUAL "arm")
+  set(LIBC_LIBC_TARGET_ARCHITECTUREITECTURE_IS_ARM TRUE)
+elseif(LIBC_TARGET_ARCHITECTURE STREQUAL "aarch64")
+  set(LIBC_LIBC_TARGET_ARCHITECTUREITECTURE_IS_AARCH64 TRUE)
+elseif(LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
+  set(LIBC_LIBC_TARGET_ARCHITECTUREITECTURE_IS_X86 TRUE)
 else()
-  message(FATAL_ERROR "Unsupported processor ${CMAKE_SYSTEM_PROCESSOR}")
+  message(FATAL_ERROR
+          "Unsupported libc target architecture ${LIBC_TARGET_ARCHITECTURE}")
+endif()
+
+# If the compiler target triple is not the same as the triple specified by
+# LIBC_TARGET_TRIPLE, we will add a --target option if the compiler is clang.
+# If the compiler is GCC we just error out as there is no equivalent of an
+# option like --target.
+if(LIBC_TARGET_TRIPLE AND
+   (NOT (libc_compiler_triple STREQUAL LIBC_TARGET_TRIPLE)))
+  if(CMAKE_COMPILER_IS_GNUCXX)
+    message(FATAL_ERROR
+            "GCC target triple and LIBC_TARGET_TRIPLE do not match.")
+  else()
+    list(APPEND LIBC_COMPILE_OPTIONS_DEFAULT "--target=${LIBC_TARGET_TRIPLE}")
+  endif()
 endif()
+
+message(STATUS
+        "Building libc for ${LIBC_TARGET_ARCHITECTURE} on ${LIBC_TARGET_OS}")

diff  --git a/libc/cmake/modules/prepare_libc_gpu_build.cmake b/libc/cmake/modules/prepare_libc_gpu_build.cmake
index 62090948f8d40..20fa57f26872f 100644
--- a/libc/cmake/modules/prepare_libc_gpu_build.cmake
+++ b/libc/cmake/modules/prepare_libc_gpu_build.cmake
@@ -1,3 +1,8 @@
+if(NOT LIBC_TARGET_ARCHITECTURE_IS_GPU)
+  message(FATAL_ERROR
+          "libc build: Invalid attempt to set up GPU architectures.")
+endif()
+
 # Set up the target architectures to build the GPU libc for.
 set(all_gpu_architectures "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62;"
                           "sm_70;sm_72;sm_75;sm_80;sm_86;gfx700;gfx701;gfx801;"
@@ -13,9 +18,8 @@ endif()
 
 # Ensure the compiler is a valid clang when building the GPU target.
 set(req_ver "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
-if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND
-   NOT (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" AND
-       ${CMAKE_CXX_COMPILER_VERSION} VERSION_EQUAL "${req_ver}"))
+if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" AND
+        ${CMAKE_CXX_COMPILER_VERSION} VERSION_EQUAL "${req_ver}"))
   message(FATAL_ERROR "Cannot build libc for GPU. CMake compiler "
                       "'${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}' "
                       " is not `Clang ${req_ver}.")

diff  --git a/libc/docs/gpu_mode.rst b/libc/docs/gpu_mode.rst
index b95dba3184cfd..b71b6eec5daee 100644
--- a/libc/docs/gpu_mode.rst
+++ b/libc/docs/gpu_mode.rst
@@ -44,7 +44,7 @@ configuration will look like this:
      -DLLVM_ENABLE_RUNTIMES="libc;openmp"                  \
      -DCMAKE_BUILD_TYPE=<Debug|Release>  \ # Select build type
      -DLLVM_LIBC_FULL_BUILD=ON           \ # We need the full libc
-     -DLLVM_LIBC_TARGET_OS=gpu           \ # Build in GPU mode
+     -DLIBC_GPU_BUILD=ON                 \ # Build in GPU mode
      -DLLVM_LIBC_GPU_ARCHITECTURES=all   \ # Build all supported architectures
      -DCMAKE_INSTALL_PREFIX=<PATH>       \ # Where 'libcgpu.a' will live
   $> ninja install


        


More information about the libc-commits mailing list