Michael Kruse 7675fc79c8
[Flang] Move builtin .mod generation into runtimes (Reapply #137828) (#169638)
Reapplication of #137828, changes:
* Workaround CMAKE_Fortran_PREPROCESS_SOURCE issue for CMake < 2.24: The
issue is that `try_compile` does not forward manually-defined compiler
flang variables to the test build environment; instead of just a
negative test result, it aborts the configuration step itself. To be
fair, manually defining these variables is deprecated since at least
CMake 3.6.
* Missing flang cmd line flags for CMake < 3.28 `-target=`, `-O2`, `-O3`
* It is now possible to set FLANG_RT_ENABLED_STATIC=OFF and
FLANG_RT_ENABLE_SHARED=OFF at the same and is the default for amdgpu and
nvptx targets. In this mode, only the .mod files are compiled --
necessary for module files in
lib/clang/22/finclude/flang/(nvptx64-nvidia-cuda|amdgpu-amd-amdhsa)/*.mod
to be available.
* For compiling omp_lib.mod for nvptx and amdgpu, the module build
functionality must be hoisted out if openmp's runtime/ directory which
is only included for host targets. This PR now requires #169909.
 

Move building the .mod files from openmp/flang to openmp/flang-rt using
a shared mechanism. Motivations to do so are:

1. Most modules are target-dependent and need to be re-compiled for each
target separately, which is something the LLVM_ENABLE_RUNTIMES system
already does. Prime example is `iso_c_binding.mod` which encodes the
target's ABI. Constants such as [`c_long_double` also have different
values](d748c81218/flang-rt/lib/runtime/iso_c_binding.f90 (L77-L81)).
Most other modules have `#ifdef`-enclosed code as well. For instance
this caused offload targets nvptx64-nvidia-cuda/amdgpu-amd-amdhsa to use
the modules files compiled for the host which may contrain uses of the
types REAL(10) or REAL(16) not available for nvptx/amdgpu.

#146876
#128015
#129742
#158790

3. CMake has support for Fortran that we should use. Among other things,
it automatically determines module dependencies so there is no need to
hardcode them in the CMakeLists.txt.

4. It allows using Fortran itself to implement Flang-RT. Currently, only
`iso_fortran_env_impl.f90` emits object files that are needed by Fortran
applications (#89403). The workaround of #95388 could be reverted (PR
#169525).


If using Flang for cross-compilation or target-offloading, flang-rt must
now be compiled for each target not only for the library, but also to
get the target-specific module files. For instance in a bootstrapping
runtime build, this can be done by adding:
`-DLLVM_RUNTIME_TARGETS=default;nvptx64-nvidia-cuda;amdgpu-amd-amdhsa`.


Some new dependencies come into play:
* openmp depends on flang-rt for building `lib_omp.mod` and
`lib_omp_kinds.mod`. Currently, if flang-rt is not found then the
modules are not built.
* check-flang depends on flang-rt: If not found, the majority of tests
are disabled. If not building in a bootstrpping build, the location of
the module files can be pointed to using
`-DFLANG_INTRINSIC_MODULES_DIR=<path>`, e.g. in a flang-standalone
build. Alternatively, the test needing any of the intrinsic modules
could be marked with `REQUIRES: flangrt-modules`.
* check-flang depends on openmp: Not a change; tests requiring
`lib_omp.mod` and `lib_omp_kinds.mod` those are already marked with
`openmp_runtime`.

As intrinsic are now specific to the target, their location is moved
from `include/flang` to `<resource-dir>/finclude/flang/<triple>`. The
mechnism to compute the location have been moved from flang-rt
(previously used to compute the location of `libflang_rt.*.a`) to common
locations in `cmake/GetToolchainDirs.cmake` and
`runtimes/CMakeLists.txt` so they can be used by both, openmp and
flang-rt. Potentially the mechnism could also be shared by other
libraries such as compiler-rt.

`finclude` was chosen because `gfortran` uses it as well and avoids
misuse such as `#include <flang/iso_c_binding.mod>`. The search location
is now determined by `ToolChain` in the driver, instead of by the
frontend. Another subdirectory `flang` avoids accidental inclusion of
gfortran-modules which due to compression would result in
user-unfriendly errors. Now the driver adds `-fintrinsic-module-path`
for that location to the frontend call (Just like gfortran does).
`-fintrinsic-module-path` had to be fixed for this because ironically it
was only added to `searchDirectories`, but not
`intrinsicModuleDirectories_`. Since the driver determines the location,
tests invoking `flang -fc1` and `bbc` must also be passed the location
by llvm-lit. This works like llvm-lit does for finding the include dirs
for Clang using `-print-file-name=...`.
2025-12-09 12:54:26 +01:00
..

Fortran Runtime (Flang-RT)

Flang-RT is the runtime library for code emitted by the Flang compiler (https://flang.llvm.org).

Getting Started

There are two build modes for the Flang-RT. The bootstrap build, also called the in-tree build, and the runtime-only build, also called the out-of-tree build. Not to be confused with the terms in-source and out-of-source builds as defined by CMake. In an in-source build, the source directory and the build directory are identical, whereas with an out-of-source build the build artifacts are stored somewhere else, possibly in a subdirectory of the source directory. LLVM does not support in-source builds.

Requirements

Requirements:

Bootstrapping Runtimes Build

The bootstrapping build will first build Clang and Flang, then use these compilers to compile Flang-RT. CMake will create a secondary build tree configured to use these just-built compilers. The secondary build will reuse the same build options (Flags, Debug/Release, ...) as the primary build. It will also ensure that once built, Flang-RT is found by Flang from either the build- or install-prefix. To enable, add flang-rt to LLVM_ENABLE_RUNTIMES:

cmake -S <path-to-llvm-project-source>/llvm \
  -GNinja                                   \
  -DLLVM_ENABLE_PROJECTS="clang;flang"      \
  -DLLVM_ENABLE_RUNTIMES=flang-rt           \
  ...

It is recommended to enable building OpenMP alongside Flang and Flang-RT as well. This will build omp_lib.mod required to use OpenMP from Fortran. Building Compiler-RT may also be required, particularly on platforms that do not provide all C-ABI functionality (such as Windows).

cmake -S <path-to-llvm-project-source>/llvm     \
  -GNinja                                       \
  -DCMAKE_BUILD_TYPE=Release                    \
  -DLLVM_ENABLE_PROJECTS="clang;flang;openmp"   \
  -DLLVM_ENABLE_RUNTIMES="compiler-rt;flang-rt" \
  ...

By default, the enabled runtimes will only be built for the host platform (-DLLVM_RUNTIME_TARGETS=default). To add additional targets to support cross-compilation via flang --target=<target-triple>, add more triples to LLVM_RUNTIME_TARGETS, such as -DLLVM_RUNTIME_TARGETS="default;aarch64-linux-gnu".

After configuration, build, test, and install the runtime(s) via

$ ninja flang-rt
$ ninja check-flang-rt
$ ninja install

Standalone Runtimes Build

Instead of building Clang and Flang from scratch, the standalone Runtime build uses CMake's environment introspection to find a C, C++, and Fortran compiler. The compiler to be used can be controlled using CMake's standard mechanisms such as CMAKE_CXX_COMPILER, CMAKE_CXX_COMPILER, and CMAKE_Fortran_COMPILER. CMAKE_Fortran_COMPILER must be flang built from the same Git commit as Flang-RT to ensure they are using the same ABI. The C and C++ compiler can be any compiler supporting the same ABI.

In addition to the compiler, the build must be able to find LLVM development tools such as lit and FileCheck that are not found in an LLVM's install directory. Use CMAKE_BINARY_DIR to point to directory where LLVM has been built. When building Flang as part of a bootstrapping build (LLVM_ENABLE_PROJECTS=flang), Flang-RT is automatically added unless configured with -DFLANG_ENABLE_FLANG_RT=OFF. Add that option to avoid having two conflicting versions of the same library.

A simple build configuration might look like the following:

cmake -S <path-to-llvm-project-source>/runtimes              \
  -GNinja                                                    \
  -DLLVM_BINARY_DIR=<path-to-llvm-builddir>                  \
  -DCMAKE_Fortran_COMPILER=<path-to-llvm-builddir>/bin/flang \
  -DCMAKE_Fortran_COMPILER_WORKS=yes                         \
  -DLLVM_ENABLE_RUNTIMES=flang-rt                            \
  ...

The CMAKE_Fortran_COMPILER_WORKS parameter must be set because otherwise CMake will test whether the Fortran compiler can compile and link programs which will obviously fail without a runtime library available yet.

Building Flang-RT for cross-compilation triple, the target triple can be selected using LLVM_DEFAULT_TARGET_TRIPLE AND LLVM_RUNTIMES_TARGET. Of course, Flang-RT can be built multiple times with different build configurations, but have to be located manually when using with the Flang driver using the -L option.

After configuration, build, test, and install the runtime via

$ ninja
$ ninja check-flang-rt
$ ninja install

Configuration Option Reference

Flang-RT has the followign configuration options. This is in addition to the build options the LLVM_ENABLE_RUNTIMES mechanism and CMake itself provide.

  • FLANG_RT_INCLUDE_TESTS (boolean; default: ON)

    When OFF, does not add any tests and unittests. The check-flang-rt build target will do nothing.

  • FLANG_RUNTIME_F128_MATH_LIB (default: "")

    Determines the implementation of REAL(16) math functions. If set to libquadmath, uses quadmath.h and -lquadmath typically distributed with gcc. If empty, disables REAL(16) support. For any other value, introspects the compiler for __float128 or 128-bit long double support. More details.

  • FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT (values: "CUDA","OpenMP", "" default: "")

    When set to CUDA, builds Flang-RT with experimental support for GPU accelerators using CUDA. CMAKE_CUDA_COMPILER must be set if not automatically detected by CMake. nvcc as well as clang are supported.

    When set to OpenMP, builds Flang-RT with experimental support for GPU accelerators using OpenMP offloading. Only Clang is supported for CMAKE_C_COMPILER and CMAKE_CXX_COMPILER.

  • FLANG_RT_INCLUDE_CUF (bool, default: OFF)

    Compiles the libflang_rt.cuda_<CUDA-version>.a/.so library. This is independent of FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT=CUDA and only requires a CUDA Toolkit installation (no CMAKE_CUDA_COMPILER).

Experimental CUDA Support

With -DFLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT=CUDA, the following additional configuration options become available.

  • FLANG_RT_LIBCUDACXX_PATH (path, default: "")

    Path to libcu++ package installation.

  • FLANG_RT_CUDA_RUNTIME_PTX_WITHOUT_GLOBAL_VARS (boolean, default: OFF)

    Do not compile global variables' definitions when producing PTX library. Default is OFF, meaning global variable definitions are compiled by default.

Experimental OpenMP Offload Support

With -DFLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT=OpenMP, the following additional configuration options become available.

  • FLANG_RT_DEVICE_ARCHITECTURES (default: "all")

    A list of device architectures that Flang-RT is going to support. If "all" uses a pre-defined list of architectures. Same purpose as LIBOMPTARGET_DEVICE_ARCHITECTURES from liboffload.