[runtimes][CMake] Move Fortran support code from flang-rt (#171610)
Common CMake code to be used by flang-rt and openmp to emit Flang module files. Most of the code is not yet used within this PR. Extracted out of #171515 for review by @petrhosek.
This commit is contained in:
@@ -49,6 +49,17 @@ function (get_toolchain_fortran_module_subdir outvar)
|
|||||||
endfunction ()
|
endfunction ()
|
||||||
|
|
||||||
|
|
||||||
|
# Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
|
||||||
|
function (get_toolchain_module_subdir outvar)
|
||||||
|
set(outval "finclude/flang")
|
||||||
|
|
||||||
|
get_toolchain_target_dirname(arch_dirname)
|
||||||
|
set(outval "${outval}/${arch_dirname}")
|
||||||
|
|
||||||
|
set(${outvar} "${outval}" PARENT_SCOPE)
|
||||||
|
endfunction ()
|
||||||
|
|
||||||
|
|
||||||
# Corresponds to Clang's ToolChain::getOSLibName(). Adapted from Compiler-RT.
|
# Corresponds to Clang's ToolChain::getOSLibName(). Adapted from Compiler-RT.
|
||||||
function (get_toolchain_os_dirname outvar)
|
function (get_toolchain_os_dirname outvar)
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
|
|||||||
@@ -345,6 +345,20 @@ function (add_flangrt_library name)
|
|||||||
# directory. Otherwise it is part of testing and is not installed at all.
|
# directory. Otherwise it is part of testing and is not installed at all.
|
||||||
# TODO: Consider multi-configuration builds (MSVC_IDE, "Ninja Multi-Config")
|
# TODO: Consider multi-configuration builds (MSVC_IDE, "Ninja Multi-Config")
|
||||||
if (ARG_INSTALL_WITH_TOOLCHAIN)
|
if (ARG_INSTALL_WITH_TOOLCHAIN)
|
||||||
|
# FIXME: RUNTIMES_OUTPUT_RESOURCE_LIB_DIR is not a good location for
|
||||||
|
# shared libraries because it is not a ld.so default search path.
|
||||||
|
# Also, the machine where the executable is eventually executed may
|
||||||
|
# not be one where the compiler is installed, so even RPATH/RUNPATH
|
||||||
|
# will not help. The most appropriate location for shared libraries
|
||||||
|
# is /usr/lib/<triple>/lib<name>.so, like e.g. libgcc_s.so.
|
||||||
|
# Flang-RT also would require a library versioning scheme so
|
||||||
|
# executables compiled with different versions of Flang either use
|
||||||
|
# matching versions of Flang-RT, or use a newer backward-compatible
|
||||||
|
# version. Currently, Flang-RT has no ABI backwards-compatibility
|
||||||
|
# policy.
|
||||||
|
# Currently, we just emit it into RUNTIMES_OUTPUT_RESOURCE_LIB_DIR
|
||||||
|
# like the static library, which is already in the driver's and
|
||||||
|
# linker's search path.
|
||||||
set_target_properties(${tgtname}
|
set_target_properties(${tgtname}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
|
ARCHIVE_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
|
||||||
|
|||||||
@@ -270,6 +270,21 @@ cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
|
|||||||
cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
|
cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
# Code for Fortran support.
|
||||||
|
#
|
||||||
|
# Currently, only flang-rt and openmp contain Fortran sources. We assume that
|
||||||
|
# none of the public CMake variables defined in config-Fortran are used unless
|
||||||
|
# we enable one of these runtimes. Other runtimes would make used of undefined
|
||||||
|
# variables.
|
||||||
|
#
|
||||||
|
# config-Fortran.cmake makes use of
|
||||||
|
# RUNTIMES_OUTPUT_RESOURCE_DIR, RUNTIMES_INSTALL_RESOURCE_PATH,
|
||||||
|
# hence must be included after those variables are defined.
|
||||||
|
if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
|
||||||
|
include(config-Fortran)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
|
option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
|
||||||
option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
|
option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
|
||||||
option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)
|
option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)
|
||||||
|
|||||||
250
runtimes/cmake/config-Fortran.cmake
Normal file
250
runtimes/cmake/config-Fortran.cmake
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
# This file sets the following public CMake variables:
|
||||||
|
#
|
||||||
|
# RUNTIMES_ENABLE_FORTRAN - Whether support for Fortran code is available and
|
||||||
|
# enabled. This is currently not intended to be a user-configuration but
|
||||||
|
# derived from CMAKE_Fortran_COMPILER. Can also be OFF when Fortran support is
|
||||||
|
# not needed or is insufficient, e.g. if intrinsic modules are missing and
|
||||||
|
# cannot be compiled on-the-fly.
|
||||||
|
#
|
||||||
|
# RUNTIMES_FORTRAN_BUILD_DEPS - If RUNTIMES_ENABLE_FORTRAN is true, this is a
|
||||||
|
# list of dependencies that must be built before any Fortran source can be
|
||||||
|
# compiled. Contains the build targets for intrinsic modules, if necessary.
|
||||||
|
# Otherweise, it is empty.
|
||||||
|
#
|
||||||
|
# RUNTIMES_ENABLE_FLANG_MODULES - Whether to build Flang modules and emit them
|
||||||
|
# into Flang's search path. This is a CMake CACHE option defined in
|
||||||
|
# config-Fortran.cmake and default to ON iff the Fortran compiler is detected
|
||||||
|
# for be a (compatible) version of Flang. In the OFF setting, modules are still
|
||||||
|
# built, but not installed or emitted into a default path.
|
||||||
|
#
|
||||||
|
# RUNTIMES_OUTPUT_RESOURCE_MOD_DIR - Where to emit intrinsic module files in
|
||||||
|
# the build directory. Most relevant when RUNTIMES_ENABLE_FLANG_MODULES is ON.
|
||||||
|
#
|
||||||
|
# RUNTIMES_INSTALL_RESOURCE_MOD_PATH - Where to install intrinsic module files
|
||||||
|
# in the install prefix. Relative to CMAKE_INSTALL_PREFIX. Only used when
|
||||||
|
# RUNTIMES_ENABLE_FLANG_MODULES is ON.
|
||||||
|
|
||||||
|
|
||||||
|
# Check whether the Fortran compiler already has access to builtin modules. Sets
|
||||||
|
# HAVE_FORTRAN_INTRINSIC_MODS when returning.
|
||||||
|
#
|
||||||
|
# This must be wrapped in a function because
|
||||||
|
# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
|
||||||
|
# a compiler introspection environment, see
|
||||||
|
# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
|
||||||
|
function (check_fortran_builtins_available)
|
||||||
|
if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
|
||||||
|
# CMake's check_fortran_source_compiles/try_compile does not take a
|
||||||
|
# user-defined CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of
|
||||||
|
# test-compiling, ask Flang directly for the builtin module files.
|
||||||
|
# CMAKE_Fortran_PREPROCESS_SOURCE is defined for CMake < 3.24 because it
|
||||||
|
# does not natively recognize Flang (see below). Once we bump the required
|
||||||
|
# CMake version, and because setting CMAKE_Fortran_PREPROCESS_SOURCE has
|
||||||
|
# been deprecated by CMake, this workaround can be removed.
|
||||||
|
if (NOT DEFINED FORTRAN_HAS_ISO_C_BINDING_MOD)
|
||||||
|
message(STATUS "Performing Test ISO_C_BINDING_PATH")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
|
||||||
|
OUTPUT_VARIABLE ISO_C_BINDING_PATH
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
set(FORTRAN_HAS_ISO_C_BINDING_MOD "")
|
||||||
|
if (EXISTS "${ISO_C_BINDING_PATH}")
|
||||||
|
message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
|
||||||
|
set(FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
|
||||||
|
else ()
|
||||||
|
message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
|
||||||
|
set(FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
else ()
|
||||||
|
cmake_push_check_state(RESET)
|
||||||
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
|
||||||
|
check_fortran_source_compiles("
|
||||||
|
subroutine testroutine
|
||||||
|
use iso_c_binding
|
||||||
|
end subroutine
|
||||||
|
" FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
|
||||||
|
cmake_pop_check_state()
|
||||||
|
endif ()
|
||||||
|
set(HAVE_FORTRAN_INTRINSIC_MODS "${FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
|
||||||
|
endfunction ()
|
||||||
|
|
||||||
|
|
||||||
|
# Workarounds for older versions of CMake not recognizing FLang. Hence, we
|
||||||
|
# cannot use CMAKE_Fortran_COMPILER_ID.
|
||||||
|
cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
|
||||||
|
if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
|
||||||
|
# CMake 3.24 is the first version of CMake that directly recognizes Flang.
|
||||||
|
# LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
|
||||||
|
if (CMAKE_VERSION VERSION_LESS "3.24")
|
||||||
|
include(CMakeForceCompiler)
|
||||||
|
CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
|
||||||
|
set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_SUBMODULE_SEP "-")
|
||||||
|
set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_PREPROCESS_SOURCE
|
||||||
|
"<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
|
||||||
|
set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_MODDIR_FLAG "-J")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
|
||||||
|
set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
|
||||||
|
set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
|
||||||
|
set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_VERBOSE_FLAG "-v")
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_LINK_MODE DRIVER)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# Optimization flags are only passed after CMake 3.27.4
|
||||||
|
# https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
|
||||||
|
if (CMAKE_VERSION VERSION_LESS "3.27.4")
|
||||||
|
string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
|
||||||
|
string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
|
||||||
|
string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
|
||||||
|
# to nvptx amd amdgpu targets, passing the target triple is essential.
|
||||||
|
# https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
|
||||||
|
if (CMAKE_VERSION VERSION_LESS "3.28")
|
||||||
|
set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
set(RUNTIMES_ENABLE_FORTRAN OFF)
|
||||||
|
|
||||||
|
# Insert at least one element for
|
||||||
|
#
|
||||||
|
# add_dependencies(target ${RUNTIMES_FORTRAN_BUILD_DEPS})
|
||||||
|
#
|
||||||
|
# to not fail
|
||||||
|
add_custom_target(fortran-dummy-dep)
|
||||||
|
set(RUNTIMES_FORTRAN_BUILD_DEPS fortran-dummy-dep)
|
||||||
|
|
||||||
|
include(CheckLanguage)
|
||||||
|
check_language(Fortran)
|
||||||
|
if (CMAKE_Fortran_COMPILER)
|
||||||
|
enable_language(Fortran)
|
||||||
|
include(CheckFortranSourceCompiles)
|
||||||
|
|
||||||
|
if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
|
||||||
|
# In a bootstrapping build (or any runtimes-build that includes flang-rt),
|
||||||
|
# the intrinsic modules are not built yet. Targets can depend on
|
||||||
|
# flang-rt-mod to ensure that flang-rt's modules are built first.
|
||||||
|
list(APPEND RUNTIMES_FORTRAN_BUILD_DEPS flang-rt-mod)
|
||||||
|
set(RUNTIMES_ENABLE_FORTRAN ON)
|
||||||
|
message(STATUS "Fortran support enabled using just-built Flang-RT builtin modules")
|
||||||
|
else ()
|
||||||
|
# Check whether building modules works, avoid causing the entire build to
|
||||||
|
# fail because of Fortran. The primary situation we want to support here
|
||||||
|
# is Flang, or its intrinsic modules were built separately in a
|
||||||
|
# non-bootstrapping build.
|
||||||
|
check_fortran_builtins_available()
|
||||||
|
if (HAVE_FORTRAN_INTRINSIC_MODS)
|
||||||
|
set(RUNTIMES_ENABLE_FORTRAN ON)
|
||||||
|
message(STATUS "Fortran support enabled using compiler's own modules")
|
||||||
|
else ()
|
||||||
|
message(STATUS "Fortran support disabled: Not passing smoke check")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
else ()
|
||||||
|
message(STATUS "Fortran support disabled: not enabled in CMake; Use CMAKE_Fortran_COMPILER_WORKS=yes if the issues is missing builtin modules")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
# Check whether modules files are compatible with our version of Flang.
|
||||||
|
set(RUNTIMES_ENABLE_FLANG_MODULES_default OFF)
|
||||||
|
if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
|
||||||
|
set(RUNTIMES_ENABLE_FLANG_MODULES_default ON)
|
||||||
|
else ()
|
||||||
|
set(RUNTIMES_ENABLE_FLANG_MODULES_default OFF)
|
||||||
|
endif ()
|
||||||
|
option(RUNTIMES_ENABLE_FLANG_MODULES "Make Fortran .mod files available to Flang; should only be enabled if compiling with a matching version of Flang" "${RUNTIMES_ENABLE_FLANG_MODULES_default}")
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the paths for Fortran .mod files.
|
||||||
|
if (RUNTIMES_ENABLE_FLANG_MODULES)
|
||||||
|
# Flang expects its builtin modules in Clang's resource directory.
|
||||||
|
get_toolchain_module_subdir(toolchain_mod_subdir)
|
||||||
|
extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
|
||||||
|
extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
|
||||||
|
cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
|
||||||
|
|
||||||
|
# No way to find out which mod files are built by a target, so install the
|
||||||
|
# entire output directory. flang_module_target() will copy (only) the PUBLIC
|
||||||
|
# .mod file into the output directory.
|
||||||
|
# https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
|
||||||
|
set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
|
||||||
|
cmake_path(NORMAL_PATH destination)
|
||||||
|
install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
|
||||||
|
DESTINATION "${destination}"
|
||||||
|
)
|
||||||
|
else ()
|
||||||
|
# If Flang modules are disabled (e.g. because the compiler is not Flang), avoid the risk of Flang accidentally picking them up.
|
||||||
|
extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${CMAKE_CURRENT_BINARY_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
|
||||||
|
|
||||||
|
# We don't know how to install modules for other compilers. Do not install them at all.
|
||||||
|
set(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "")
|
||||||
|
endif ()
|
||||||
|
cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
# Set options to compile Fortran module files. Assumes the code above has run.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# flang_module_target(name
|
||||||
|
# PUBLIC
|
||||||
|
# Modules files are to be used by other Fortran sources. If a library is
|
||||||
|
# compiled multiple times (e.g. static/shared, or msvcrt variants), only
|
||||||
|
# one of those can be public module files; non-public modules are still
|
||||||
|
# generated but to be forgotten inside the build directory to not
|
||||||
|
# conflict with each other.
|
||||||
|
# Also, installs the module with the toolchain.
|
||||||
|
# )
|
||||||
|
function (flang_module_target tgtname)
|
||||||
|
set(options PUBLIC)
|
||||||
|
cmake_parse_arguments(ARG
|
||||||
|
"${options}"
|
||||||
|
""
|
||||||
|
""
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Let all modules find the public module files
|
||||||
|
target_compile_options(${tgtname} PRIVATE
|
||||||
|
"$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (CMAKE_Fortran_COMPILER_ID MATCHES "LLVM")
|
||||||
|
target_compile_options(${tgtname} PRIVATE
|
||||||
|
# Flang bug workaround: Reformating of cooked token buffer causes
|
||||||
|
# identifier to be split between lines
|
||||||
|
"$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (ARG_PUBLIC)
|
||||||
|
set_target_properties(${tgtname}
|
||||||
|
PROPERTIES
|
||||||
|
Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
|
||||||
|
)
|
||||||
|
else ()
|
||||||
|
# Keep non-public modules where CMake would put them normally;
|
||||||
|
# Modules of different target must not overwrite each other.
|
||||||
|
endif ()
|
||||||
|
endfunction ()
|
||||||
Reference in New Issue
Block a user