mirror of
https://github.com/reactos/CMake.git
synced 2024-12-15 07:41:15 +00:00
86578eccf2
Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
392 lines
14 KiB
CMake
392 lines
14 KiB
CMake
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
|
|
|
#[=======================================================================[.rst:
|
|
FortranCInterface
|
|
-----------------
|
|
|
|
Fortran/C Interface Detection
|
|
|
|
This module automatically detects the API by which C and Fortran
|
|
languages interact.
|
|
|
|
Module Variables
|
|
^^^^^^^^^^^^^^^^
|
|
|
|
Variables that indicate if the mangling is found:
|
|
|
|
``FortranCInterface_GLOBAL_FOUND``
|
|
Global subroutines and functions.
|
|
|
|
``FortranCInterface_MODULE_FOUND``
|
|
Module subroutines and functions (declared by "MODULE PROCEDURE").
|
|
|
|
This module also provides the following variables to specify
|
|
the detected mangling, though a typical use case does not need
|
|
to reference them and can use the `Module Functions`_ below.
|
|
|
|
``FortranCInterface_GLOBAL_PREFIX``
|
|
Prefix for a global symbol without an underscore.
|
|
|
|
``FortranCInterface_GLOBAL_SUFFIX``
|
|
Suffix for a global symbol without an underscore.
|
|
|
|
``FortranCInterface_GLOBAL_CASE``
|
|
The case for a global symbol without an underscore,
|
|
either ``UPPER`` or ``LOWER``.
|
|
|
|
``FortranCInterface_GLOBAL__PREFIX``
|
|
Prefix for a global symbol with an underscore.
|
|
|
|
``FortranCInterface_GLOBAL__SUFFIX``
|
|
Suffix for a global symbol with an underscore.
|
|
|
|
``FortranCInterface_GLOBAL__CASE``
|
|
The case for a global symbol with an underscore,
|
|
either ``UPPER`` or ``LOWER``.
|
|
|
|
``FortranCInterface_MODULE_PREFIX``
|
|
Prefix for a module symbol without an underscore.
|
|
|
|
``FortranCInterface_MODULE_MIDDLE``
|
|
Middle of a module symbol without an underscore that appears
|
|
between the name of the module and the name of the symbol.
|
|
|
|
``FortranCInterface_MODULE_SUFFIX``
|
|
Suffix for a module symbol without an underscore.
|
|
|
|
``FortranCInterface_MODULE_CASE``
|
|
The case for a module symbol without an underscore,
|
|
either ``UPPER`` or ``LOWER``.
|
|
|
|
``FortranCInterface_MODULE__PREFIX``
|
|
Prefix for a module symbol with an underscore.
|
|
|
|
``FortranCInterface_MODULE__MIDDLE``
|
|
Middle of a module symbol with an underscore that appears
|
|
between the name of the module and the name of the symbol.
|
|
|
|
``FortranCInterface_MODULE__SUFFIX``
|
|
Suffix for a module symbol with an underscore.
|
|
|
|
``FortranCInterface_MODULE__CASE``
|
|
The case for a module symbol with an underscore,
|
|
either ``UPPER`` or ``LOWER``.
|
|
|
|
Module Functions
|
|
^^^^^^^^^^^^^^^^
|
|
|
|
.. command:: FortranCInterface_HEADER
|
|
|
|
The ``FortranCInterface_HEADER`` function is provided to generate a
|
|
C header file containing macros to mangle symbol names::
|
|
|
|
FortranCInterface_HEADER(<file>
|
|
[MACRO_NAMESPACE <macro-ns>]
|
|
[SYMBOL_NAMESPACE <ns>]
|
|
[SYMBOLS [<module>:]<function> ...])
|
|
|
|
It generates in ``<file>`` definitions of the following macros::
|
|
|
|
#define FortranCInterface_GLOBAL (name,NAME) ...
|
|
#define FortranCInterface_GLOBAL_(name,NAME) ...
|
|
#define FortranCInterface_MODULE (mod,name, MOD,NAME) ...
|
|
#define FortranCInterface_MODULE_(mod,name, MOD,NAME) ...
|
|
|
|
These macros mangle four categories of Fortran symbols, respectively:
|
|
|
|
* Global symbols without '_': ``call mysub()``
|
|
* Global symbols with '_' : ``call my_sub()``
|
|
* Module symbols without '_': ``use mymod; call mysub()``
|
|
* Module symbols with '_' : ``use mymod; call my_sub()``
|
|
|
|
If mangling for a category is not known, its macro is left undefined.
|
|
All macros require raw names in both lower case and upper case.
|
|
|
|
The options are:
|
|
|
|
``MACRO_NAMESPACE``
|
|
Replace the default ``FortranCInterface_`` prefix with a given
|
|
namespace ``<macro-ns>``.
|
|
|
|
``SYMBOLS``
|
|
List symbols to mangle automatically with C preprocessor definitions::
|
|
|
|
<function> ==> #define <ns><function> ...
|
|
<module>:<function> ==> #define <ns><module>_<function> ...
|
|
|
|
If the mangling for some symbol is not known then no preprocessor
|
|
definition is created, and a warning is displayed.
|
|
|
|
``SYMBOL_NAMESPACE``
|
|
Prefix all preprocessor definitions generated by the ``SYMBOLS``
|
|
option with a given namespace ``<ns>``.
|
|
|
|
.. command:: FortranCInterface_VERIFY
|
|
|
|
The ``FortranCInterface_VERIFY`` function is provided to verify
|
|
that the Fortran and C/C++ compilers work together::
|
|
|
|
FortranCInterface_VERIFY([CXX] [QUIET])
|
|
|
|
It tests whether a simple test executable using Fortran and C (and C++
|
|
when the CXX option is given) compiles and links successfully. The
|
|
result is stored in the cache entry ``FortranCInterface_VERIFIED_C``
|
|
(or ``FortranCInterface_VERIFIED_CXX`` if ``CXX`` is given) as a boolean.
|
|
If the check fails and ``QUIET`` is not given the function terminates with a
|
|
fatal error message describing the problem. The purpose of this check
|
|
is to stop a build early for incompatible compiler combinations. The
|
|
test is built in the ``Release`` configuration.
|
|
|
|
Example Usage
|
|
^^^^^^^^^^^^^
|
|
|
|
.. code-block:: cmake
|
|
|
|
include(FortranCInterface)
|
|
FortranCInterface_HEADER(FC.h MACRO_NAMESPACE "FC_")
|
|
|
|
This creates a "FC.h" header that defines mangling macros ``FC_GLOBAL()``,
|
|
``FC_GLOBAL_()``, ``FC_MODULE()``, and ``FC_MODULE_()``.
|
|
|
|
.. code-block:: cmake
|
|
|
|
include(FortranCInterface)
|
|
FortranCInterface_HEADER(FCMangle.h
|
|
MACRO_NAMESPACE "FC_"
|
|
SYMBOL_NAMESPACE "FC_"
|
|
SYMBOLS mysub mymod:my_sub)
|
|
|
|
This creates a "FCMangle.h" header that defines the same ``FC_*()``
|
|
mangling macros as the previous example plus preprocessor symbols
|
|
``FC_mysub`` and ``FC_mymod_my_sub``.
|
|
|
|
Additional Manglings
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
FortranCInterface is aware of possible ``GLOBAL`` and ``MODULE`` manglings
|
|
for many Fortran compilers, but it also provides an interface to specify
|
|
new possible manglings. Set the variables::
|
|
|
|
FortranCInterface_GLOBAL_SYMBOLS
|
|
FortranCInterface_MODULE_SYMBOLS
|
|
|
|
before including FortranCInterface to specify manglings of the symbols
|
|
``MySub``, ``My_Sub``, ``MyModule:MySub``, and ``My_Module:My_Sub``.
|
|
For example, the code:
|
|
|
|
.. code-block:: cmake
|
|
|
|
set(FortranCInterface_GLOBAL_SYMBOLS mysub_ my_sub__ MYSUB_)
|
|
# ^^^^^ ^^^^^^ ^^^^^
|
|
set(FortranCInterface_MODULE_SYMBOLS
|
|
__mymodule_MOD_mysub __my_module_MOD_my_sub)
|
|
# ^^^^^^^^ ^^^^^ ^^^^^^^^^ ^^^^^^
|
|
include(FortranCInterface)
|
|
|
|
tells FortranCInterface to try given ``GLOBAL`` and ``MODULE`` manglings.
|
|
(The carets point at raw symbol names for clarity in this example but
|
|
are not needed.)
|
|
#]=======================================================================]
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Execute at most once in a project.
|
|
if(FortranCInterface_SOURCE_DIR)
|
|
return()
|
|
endif()
|
|
|
|
cmake_policy(PUSH)
|
|
cmake_policy(SET CMP0007 NEW)
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Verify that C and Fortran are available.
|
|
foreach(lang C Fortran)
|
|
if(NOT CMAKE_${lang}_COMPILER_LOADED)
|
|
message(FATAL_ERROR
|
|
"FortranCInterface requires the ${lang} language to be enabled.")
|
|
endif()
|
|
endforeach()
|
|
|
|
#-----------------------------------------------------------------------------
|
|
set(FortranCInterface_SOURCE_DIR ${CMAKE_ROOT}/Modules/FortranCInterface)
|
|
|
|
# MinGW's make tool does not always like () in the path
|
|
if("${CMAKE_GENERATOR}" MATCHES "MinGW" AND
|
|
"${FortranCInterface_SOURCE_DIR}" MATCHES "[()]")
|
|
file(COPY ${FortranCInterface_SOURCE_DIR}/
|
|
DESTINATION ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterfaceMinGW)
|
|
set(FortranCInterface_SOURCE_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterfaceMinGW)
|
|
endif()
|
|
|
|
# Create the interface detection project if it does not exist.
|
|
if(NOT FortranCInterface_BINARY_DIR)
|
|
set(FortranCInterface_BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterface)
|
|
include(${FortranCInterface_SOURCE_DIR}/Detect.cmake)
|
|
endif()
|
|
|
|
# Load the detection results.
|
|
include(${FortranCInterface_BINARY_DIR}/Output.cmake)
|
|
|
|
#-----------------------------------------------------------------------------
|
|
function(FortranCInterface_HEADER file)
|
|
# Parse arguments.
|
|
if(IS_ABSOLUTE "${file}")
|
|
set(FILE "${file}")
|
|
else()
|
|
set(FILE "${CMAKE_CURRENT_BINARY_DIR}/${file}")
|
|
endif()
|
|
set(MACRO_NAMESPACE "FortranCInterface_")
|
|
set(SYMBOL_NAMESPACE)
|
|
set(SYMBOLS)
|
|
set(doing)
|
|
foreach(arg ${ARGN})
|
|
if("x${arg}" MATCHES "^x(SYMBOLS|SYMBOL_NAMESPACE|MACRO_NAMESPACE)$")
|
|
set(doing "${arg}")
|
|
elseif("x${doing}" MATCHES "^x(SYMBOLS)$")
|
|
list(APPEND "${doing}" "${arg}")
|
|
elseif("x${doing}" MATCHES "^x(SYMBOL_NAMESPACE|MACRO_NAMESPACE)$")
|
|
set("${doing}" "${arg}")
|
|
set(doing)
|
|
else()
|
|
message(AUTHOR_WARNING "Unknown argument: \"${arg}\"")
|
|
endif()
|
|
endforeach()
|
|
|
|
# Generate macro definitions.
|
|
set(HEADER_CONTENT)
|
|
set(_desc_GLOBAL "/* Mangling for Fortran global symbols without underscores. */")
|
|
set(_desc_GLOBAL_ "/* Mangling for Fortran global symbols with underscores. */")
|
|
set(_desc_MODULE "/* Mangling for Fortran module symbols without underscores. */")
|
|
set(_desc_MODULE_ "/* Mangling for Fortran module symbols with underscores. */")
|
|
foreach(macro GLOBAL GLOBAL_ MODULE MODULE_)
|
|
if(FortranCInterface_${macro}_MACRO)
|
|
string(APPEND HEADER_CONTENT "
|
|
${_desc_${macro}}
|
|
#define ${MACRO_NAMESPACE}${macro}${FortranCInterface_${macro}_MACRO}
|
|
")
|
|
endif()
|
|
endforeach()
|
|
|
|
# Generate symbol mangling definitions.
|
|
if(SYMBOLS)
|
|
string(APPEND HEADER_CONTENT "
|
|
/*--------------------------------------------------------------------------*/
|
|
/* Mangle some symbols automatically. */
|
|
")
|
|
endif()
|
|
foreach(f ${SYMBOLS})
|
|
if("${f}" MATCHES ":")
|
|
# Module symbol name. Parse "<module>:<function>" syntax.
|
|
string(REPLACE ":" ";" pieces "${f}")
|
|
list(GET pieces 0 module)
|
|
list(GET pieces 1 function)
|
|
string(TOUPPER "${module}" m_upper)
|
|
string(TOLOWER "${module}" m_lower)
|
|
string(TOUPPER "${function}" f_upper)
|
|
string(TOLOWER "${function}" f_lower)
|
|
if("${function}" MATCHES "_")
|
|
set(form "_")
|
|
else()
|
|
set(form "")
|
|
endif()
|
|
if(FortranCInterface_MODULE${form}_MACRO)
|
|
string(APPEND HEADER_CONTENT "#define ${SYMBOL_NAMESPACE}${module}_${function} ${MACRO_NAMESPACE}MODULE${form}(${m_lower},${f_lower}, ${m_upper},${f_upper})\n")
|
|
else()
|
|
message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
|
|
endif()
|
|
else()
|
|
# Global symbol name.
|
|
if("${f}" MATCHES "_")
|
|
set(form "_")
|
|
else()
|
|
set(form "")
|
|
endif()
|
|
string(TOUPPER "${f}" f_upper)
|
|
string(TOLOWER "${f}" f_lower)
|
|
if(FortranCInterface_GLOBAL${form}_MACRO)
|
|
string(APPEND HEADER_CONTENT "#define ${SYMBOL_NAMESPACE}${f} ${MACRO_NAMESPACE}GLOBAL${form}(${f_lower}, ${f_upper})\n")
|
|
else()
|
|
message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
# Store the content.
|
|
configure_file(${FortranCInterface_SOURCE_DIR}/Macro.h.in ${FILE} @ONLY)
|
|
endfunction()
|
|
|
|
function(FortranCInterface_VERIFY)
|
|
# Check arguments.
|
|
|
|
set(lang C)
|
|
set(quiet 0)
|
|
set(verify_cxx 0)
|
|
foreach(arg ${ARGN})
|
|
if("${arg}" STREQUAL "QUIET")
|
|
set(quiet 1)
|
|
elseif("${arg}" STREQUAL "CXX")
|
|
set(lang CXX)
|
|
set(verify_cxx 1)
|
|
else()
|
|
message(FATAL_ERROR
|
|
"FortranCInterface_VERIFY - called with unknown argument:\n ${arg}")
|
|
endif()
|
|
endforeach()
|
|
|
|
if(NOT CMAKE_${lang}_COMPILER_LOADED)
|
|
message(FATAL_ERROR
|
|
"FortranCInterface_VERIFY(${lang}) requires ${lang} to be enabled.")
|
|
endif()
|
|
|
|
# Build the verification project if not yet built.
|
|
if(NOT DEFINED FortranCInterface_VERIFIED_${lang})
|
|
set(_desc "Verifying Fortran/${lang} Compiler Compatibility")
|
|
message(STATUS "${_desc}")
|
|
|
|
# Build a sample project which reports symbols.
|
|
set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
|
|
try_compile(FortranCInterface_VERIFY_${lang}_COMPILED
|
|
${FortranCInterface_BINARY_DIR}/Verify${lang}
|
|
${FortranCInterface_SOURCE_DIR}/Verify
|
|
VerifyFortranC
|
|
CMAKE_FLAGS -DVERIFY_CXX=${verify_cxx}
|
|
-DCMAKE_VERBOSE_MAKEFILE=ON
|
|
"-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
|
|
"-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}"
|
|
"-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
|
|
"-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}"
|
|
"-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}"
|
|
"-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
|
|
OUTPUT_VARIABLE _output)
|
|
file(WRITE "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" "${_output}")
|
|
|
|
# Report results.
|
|
if(FortranCInterface_VERIFY_${lang}_COMPILED)
|
|
message(STATUS "${_desc} - Success")
|
|
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
|
|
"${_desc} passed with the following output:\n${_output}\n\n")
|
|
set(FortranCInterface_VERIFIED_${lang} 1 CACHE INTERNAL "Fortran/${lang} compatibility")
|
|
else()
|
|
message(STATUS "${_desc} - Failed")
|
|
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
|
"${_desc} failed with the following output:\n${_output}\n\n")
|
|
set(FortranCInterface_VERIFIED_${lang} 0 CACHE INTERNAL "Fortran/${lang} compatibility")
|
|
endif()
|
|
unset(FortranCInterface_VERIFY_${lang}_COMPILED CACHE)
|
|
endif()
|
|
|
|
# Error if compilers are incompatible.
|
|
if(NOT FortranCInterface_VERIFIED_${lang} AND NOT quiet)
|
|
file(READ "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" _output)
|
|
string(REPLACE "\n" "\n " _output "${_output}")
|
|
message(FATAL_ERROR
|
|
"The Fortran compiler:\n ${CMAKE_Fortran_COMPILER}\n"
|
|
"and the ${lang} compiler:\n ${CMAKE_${lang}_COMPILER}\n"
|
|
"failed to compile a simple test project using both languages. "
|
|
"The output was:\n ${_output}")
|
|
endif()
|
|
endfunction()
|
|
|
|
# Restore including context policies.
|
|
cmake_policy(POP)
|