1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
# Create a library with c- and Fortran-bindings
#
# Usage of this module:
#
# bindgen_add_library(<library-name> SOURCES <sources>[...] [FORTRAN_OUTPUT_DIR fortran_dir] [C_OUTPUT_DIR c_dir] [FORTRAN_MODULE_NAME name])
#
# Arguments:
# SOURCES: sources of the library
# FORTRAN_OUTPUT_DIR: destination for generated Fortran files (default: ${CMAKE_CURRENT_LIST_DIR})
# C_OUTPUT_DIR: destination for generated C files (default: ${CMAKE_CURRENT_LIST_DIR})
# FORTRAN_MODULE_NAME: name for the Fortran module (default: <library-name>)
#
# Variables used by this module:
#
# GT_ENABLE_BINDINGS_GENERATION:
# If GT_ENABLE_BINDINGS_GENERATION=OFF, bindings will not be generated, but expected to be provided,
# as part of the user source code, e.g. by updating bindings with the bindings generator during development.
# If GT_ENABLE_BINDINGS_GENERATION is not defined already it will be made available after including this file.
#
# In the default case (GT_ENABLE_BINDINGS_GENERATION=ON), the bindings files are generated in the directory
# where the CMakeLists.txt with the call to bindgen_add_library() is located.
#
# Targets generated by bindgen_add_library(<library-name> ...):
# - <library_name> library build from <Sources...> without bindings (ususally this target is not used)
# - <library_name>_declarations will run the generator for this library
# - <library_name>_c the C-bindings with <library_name> linked to it
# - <library_name>_fortran the Fortran-bindings with <library_name> linked to it
include_guard(GLOBAL)
option(GT_ENABLE_BINDINGS_GENERATION "If turned off, bindings will not be generated." ON)
# in some conditions the include guard above doesn't work
if( NOT TARGET cpp_bindgen_interface )
# variables are unset after use for scoping, they need to be redefined in the macros
set(__CPP_BINDGEN_SOURCE_DIR @__CPP_BINDGEN_SOURCE_DIR@)
set(__CPP_BINDGEN_INCLUDE_DIR @__CPP_BINDGEN_INCLUDE_DIR@)
add_library(cpp_bindgen_interface INTERFACE)
target_include_directories(cpp_bindgen_interface INTERFACE $<BUILD_INTERFACE:${__CPP_BINDGEN_INCLUDE_DIR}> $<INSTALL_INTERFACE:include>)
target_compile_features(cpp_bindgen_interface INTERFACE cxx_std_11)
target_compile_definitions(cpp_bindgen_interface INTERFACE BOOST_PP_VARIADICS=1)
if(CPP_BINDGEN_GT_LEGACY)
target_compile_definitions(cpp_bindgen_interface INTERFACE CPP_BINDGEN_GT_LEGACY)
endif()
add_library(cpp_bindgen_generator STATIC ${__CPP_BINDGEN_SOURCE_DIR}/cpp_bindgen/generator.cpp)
# PUBLIC to make export.hpp available in the sources passed to add_bindings_library()
target_link_libraries(cpp_bindgen_generator PUBLIC Boost::boost)
target_link_libraries(cpp_bindgen_generator PUBLIC cpp_bindgen_interface)
add_library(cpp_bindgen_handle STATIC ${__CPP_BINDGEN_SOURCE_DIR}/cpp_bindgen/handle.cpp)
target_link_libraries(cpp_bindgen_handle PUBLIC cpp_bindgen_interface)
unset(__CPP_BINDGEN_SOURCE_DIR)
unset(__CPP_BINDGEN_INCLUDE_DIR)
endif()
# bindgen_enable_fortran_library()
#
# Create a target to compile the generated Fortran module.
# In the default case, when Fortran is enabled on the call to bindgen_add_library(), this target is automatically created.
# In case when the Fortran language was not enabled, we cannot create a library (add_library()) with Fortran files.
# However if the user wants to use the target at a later stage, e.g. in testing (with Fortran enabled), the target can
# be created by a call to bindgen_enable_fortran_library().
function(bindgen_enable_fortran_library target_name)
set(__CPP_BINDGEN_SOURCE_DIR @__CPP_BINDGEN_SOURCE_DIR@)
set(__CPP_BINDGEN_CMAKE_DIR @__CPP_BINDGEN_CMAKE_DIR@)
if(CMAKE_Fortran_COMPILER_LOADED)
if(NOT TARGET cpp_bindgen_fortran_handle)
add_library(cpp_bindgen_fortran_handle ${__CPP_BINDGEN_SOURCE_DIR}/cpp_bindgen/array_descriptor.f90 ${__CPP_BINDGEN_SOURCE_DIR}/cpp_bindgen/handle.f90)
# the following variable is used to install the .mod files in install_cpp_bindgen_targets() and
# therefore needs to be available project-wide
set(CPP_BINDGEN_Fortran_MODULES_DIRECTORY ${CMAKE_BINARY_DIR}/cpp_bindgen_modules
CACHE INTERNAL "Directory for Fortran modules of cpp_bindgen")
set_target_properties(cpp_bindgen_fortran_handle PROPERTIES Fortran_MODULE_DIRECTORY ${CPP_BINDGEN_Fortran_MODULES_DIRECTORY})
target_link_libraries(cpp_bindgen_fortran_handle PUBLIC cpp_bindgen_handle)
target_include_directories(cpp_bindgen_fortran_handle INTERFACE $<BUILD_INTERFACE:${CPP_BINDGEN_Fortran_MODULES_DIRECTORY}> $<INSTALL_INTERFACE:include/>)
include(${__CPP_BINDGEN_CMAKE_DIR}/cpp_bindgen_fortran_helpers.cmake)
bindgen_enable_fortran_preprocessing_on_target(cpp_bindgen_fortran_handle)
endif()
if(NOT TARGET ${target_name}_fortran)
set_source_files_properties(GT_${${target_name}_fortran_bindings_path} PROPERTIES GENERATED TRUE)
add_library(${target_name}_fortran EXCLUDE_FROM_ALL ${CPP_BINDGEN_${target_name}_fortran_bindings_path})
target_link_libraries(${target_name}_fortran PUBLIC ${target_name})
target_link_libraries(${target_name}_fortran PUBLIC cpp_bindgen_fortran_handle)
# location of .mod file (we cannot know the INSTALL_INTERFACE directory here)
target_include_directories(${target_name}_fortran PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
add_dependencies(${target_name}_fortran ${target_name}_declarations)
endif()
elseif(NOT ${ARGN}) # internal: the second (optional) parameter can be used to surpress this fatal error
message(FATAL_ERROR "Please enable_language(Fortran) to compile the Fortran bindings.")
endif()
endfunction()
function(bindgen_add_library target_name)
set(options)
set(one_value_args FORTRAN_OUTPUT_DIR C_OUTPUT_DIR FORTRAN_MODULE_NAME)
set(multi_value_args SOURCES)
cmake_parse_arguments(ARG "${options}" "${one_value_args};" "${multi_value_args}" ${ARGN})
set(__CPP_BINDGEN_SOURCE_DIR @__CPP_BINDGEN_SOURCE_DIR@)
set(__CPP_BINDGEN_CMAKE_DIR @__CPP_BINDGEN_CMAKE_DIR@)
if(NOT DEFINED ARG_FORTRAN_MODULE_NAME)
set(ARG_FORTRAN_MODULE_NAME ${target_name}) # default value
endif()
if(ARG_C_OUTPUT_DIR)
set(bindings_c_decl_filename ${ARG_C_OUTPUT_DIR}/${target_name}.h)
else()
set(bindings_c_decl_filename ${CMAKE_CURRENT_LIST_DIR}/${target_name}.h) # default value
endif()
if(ARG_FORTRAN_OUTPUT_DIR)
set(bindings_fortran_decl_filename ${ARG_FORTRAN_OUTPUT_DIR}/${target_name}.f90)
else()
set(bindings_fortran_decl_filename ${CMAKE_CURRENT_LIST_DIR}/${target_name}.f90) # default value
endif()
add_library(${target_name} STATIC ${ARG_SOURCES})
target_link_libraries(${target_name} PRIVATE cpp_bindgen_generator)
if(GT_ENABLE_BINDINGS_GENERATION)
# generator
add_executable(${target_name}_decl_generator
${__CPP_BINDGEN_SOURCE_DIR}/cpp_bindgen/generator_main.cpp)
set_target_properties(${target_name}_decl_generator PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/decl_generator")
target_link_libraries(${target_name}_decl_generator cpp_bindgen_generator)
if (${APPLE})
target_link_libraries(${target_name}_decl_generator
-Wl,-force_load ${target_name})
else()
target_link_libraries(${target_name}_decl_generator
-Xlinker --whole-archive ${target_name}
-Xlinker --no-whole-archive)
endif()
add_custom_target(${target_name}_declarations
ALL
COMMAND ${CMAKE_COMMAND}
-DGENERATOR=${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/decl_generator/${target_name}_decl_generator
-DBINDINGS_C_DECL_FILENAME=${bindings_c_decl_filename}
-DBINDINGS_FORTRAN_DECL_FILENAME=${bindings_fortran_decl_filename}
-DFORTRAN_MODULE_NAME=${ARG_FORTRAN_MODULE_NAME}
-P ${__CPP_BINDGEN_CMAKE_DIR}/cpp_bindgen_generate.cmake
BYPRODUCTS ${bindings_c_decl_filename} ${bindings_fortran_decl_filename}
DEPENDS $<TARGET_FILE:${target_name}_decl_generator>)
else()
if(EXISTS ${bindings_c_decl_filename} AND (EXISTS ${bindings_fortran_decl_filename}))
add_custom_target(${target_name}_declarations) # noop, the dependencies are satisfied if the files exist
else()
message(FATAL_ERROR "Cross-compilation for bindings is enabled: no bindings will be generated, but "
"${bindings_c_decl_filename} and/or "
"${bindings_fortran_decl_filename} "
"are missing. Generate the bindings and consider making them part of your repository.")
endif()
endif()
# bindings c library
add_library(${target_name}_c INTERFACE)
target_link_libraries(${target_name}_c INTERFACE ${target_name})
target_link_libraries(${target_name}_c INTERFACE cpp_bindgen_handle)
target_link_libraries(${target_name}_c INTERFACE cpp_bindgen_interface)
add_dependencies(${target_name}_c ${target_name}_declarations)
# bindings Fortran library
# Export the name of the generated file. The variable needs to exist in the whole cmake!
# Reason: see description of bindgen_enable_fortran_library().
set(CPP_BINDGEN_${target_name}_fortran_bindings_path ${bindings_fortran_decl_filename}
CACHE INTERNAL "Path to the generated Fortran file for ${target_name}")
bindgen_enable_fortran_library(${target_name} TRUE)
endfunction()
# install_cpp_bindgen_targets()
#
# cpp_bindgen contains some generic files which are being built on first use of bindgen_add_library().
# These libraries can be installed with this function which takes the same arguments
# as install(TARGETS targets... [other-options]), except
# - you must not specify "TARGETS targets..." but only all [other-options].
# - if Fortran is enabled Fortran_MODULE_DESTINATION needs to be set to the location where Fortran modules
# should be installed to (e.g. include)
function(install_cpp_bindgen_targets)
set(options)
set(oneValueArgs Fortran_MODULE_DESTINATION)
set(multiValueArgs TARGETS)
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(ARG_TARGETS)
message(FATAL_ERROR "install_cpp_bindgen_targets() must not be called with TARGETS argument.")
endif()
if(TARGET cpp_bindgen_fortran_handle) # Fortran is enabled, we need to install a mod file
if(ARG_Fortran_MODULE_DESTINATION)
install(DIRECTORY ${CPP_BINDGEN_Fortran_MODULES_DIRECTORY}/ DESTINATION ${ARG_Fortran_MODULE_DESTINATION})
else()
message(WARNING "Fortran_MODULE_DESTINATION was NOT specified, but Fortran was enabled. Modules files for
cpp_bindgen won't be installed.")
endif()
install(TARGETS cpp_bindgen_fortran_handle ${ARG_UNPARSED_ARGUMENTS})
else()
if(ARG_Fortran_MODULE_DESTINATION)
message(WARNING "Fortran_MODULE_DESTINATION was specified, but Fortran is disabled.")
endif()
endif()
install(TARGETS cpp_bindgen_generator cpp_bindgen_handle cpp_bindgen_interface ${ARG_UNPARSED_ARGUMENTS})
endfunction()
|