From 14f7a043e3686a6a2b821e759e391c54f3239479 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 24 Aug 2009 08:49:07 -0400 Subject: [PATCH] Teach FortranCInterface to load outside results We split the main detection logic into a Detect.cmake support module and load it only when detection results are not already available. This allows results computed by the main project to be used in try-compile projects without recomputing them. The call to try_compile() need only to pass FortranCInterface_BINARY_DIR through the CMAKE_FLAGS option. --- Modules/FortranCInterface.cmake | 166 +------------------------ Modules/FortranCInterface/Detect.cmake | 165 ++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 162 deletions(-) create mode 100644 Modules/FortranCInterface/Detect.cmake diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake index eba97c634..126b117cc 100644 --- a/Modules/FortranCInterface.cmake +++ b/Modules/FortranCInterface.cmake @@ -85,170 +85,12 @@ foreach(lang C Fortran) endforeach() #----------------------------------------------------------------------------- -# Set up an interface detection project. set(FortranCInterface_SOURCE_DIR ${CMAKE_ROOT}/Modules/FortranCInterface) -set(FortranCInterface_BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterface) -configure_file(${FortranCInterface_SOURCE_DIR}/Input.cmake.in - ${FortranCInterface_BINARY_DIR}/Input.cmake @ONLY) -# Detect the Fortran/C interface on the first run or when the -# configuration changes. -if(${FortranCInterface_BINARY_DIR}/Input.cmake - IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake - OR ${FortranCInterface_SOURCE_DIR}/Output.cmake.in - IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake - OR ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt - IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake - OR ${CMAKE_CURRENT_LIST_FILE} - IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake - ) - message(STATUS "Detecting Fortran/C Interface") - set(_result) - - # Build a sample project which reports symbols. - try_compile(FortranCInterface_COMPILED - ${FortranCInterface_BINARY_DIR} - ${FortranCInterface_SOURCE_DIR} - FortranCInterface - OUTPUT_VARIABLE FortranCInterface_OUTPUT) - set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED}) - unset(FortranCInterface_COMPILED CACHE) - - # Locate the sample project executable. - if(FortranCInterface_COMPILED) - find_program(FortranCInterface_EXE - NAMES FortranCInterface - PATHS ${FortranCInterface_BINARY_DIR} ${FortranCInterface_BINARY_DIR}/Debug - NO_DEFAULT_PATH - ) - set(FortranCInterface_EXE ${FortranCInterface_EXE}) - unset(FortranCInterface_EXE CACHE) - else() - set(_result "Failed to compile") - set(FortranCInterface_EXE) - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Fortran/C interface test project failed with the following output:\n" - "${FortranCInterface_OUTPUT}\n") - endif() - - # Load symbols from INFO:symbol[] strings in the executable. - set(FortranCInterface_SYMBOLS) - if(FortranCInterface_EXE) - file(STRINGS "${FortranCInterface_EXE}" _info_strings - LIMIT_COUNT 8 REGEX "INFO:[^[]*\\[") - foreach(info ${_info_strings}) - if("${info}" MATCHES ".*INFO:symbol\\[([^]]*)\\].*") - string(REGEX REPLACE ".*INFO:symbol\\[([^]]*)\\].*" "\\1" symbol "${info}") - list(APPEND FortranCInterface_SYMBOLS ${symbol}) - endif() - endforeach() - elseif(NOT _result) - set(_result "Failed to load sample executable") - endif() - - set(_case_mysub "LOWER") - set(_case_my_sub "LOWER") - set(_case_MYSUB "UPPER") - set(_case_MY_SUB "UPPER") - set(_global_regex "^(_*)(mysub|MYSUB)([_$]*)$") - set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$") - set(_module_regex "^(_*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$") - set(_module__regex "^(_*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$") - - # Parse the symbol names. - foreach(symbol ${FortranCInterface_SYMBOLS}) - foreach(form "" "_") - # Look for global symbols. - string(REGEX REPLACE "${_global_${form}regex}" - "\\1;\\2;\\3" pieces "${symbol}") - list(LENGTH pieces len) - if(len EQUAL 3) - set(FortranCInterface_GLOBAL_${form}SYMBOL "${symbol}") - list(GET pieces 0 FortranCInterface_GLOBAL_${form}PREFIX) - list(GET pieces 1 name) - list(GET pieces 2 FortranCInterface_GLOBAL_${form}SUFFIX) - set(FortranCInterface_GLOBAL_${form}CASE "${_case_${name}}") - endif() - - # Look for module symbols. - string(REGEX REPLACE "${_module_${form}regex}" - "\\1;\\2;\\3;\\4;\\5" pieces "${symbol}") - list(LENGTH pieces len) - if(len EQUAL 5) - set(FortranCInterface_MODULE_${form}SYMBOL "${symbol}") - list(GET pieces 0 FortranCInterface_MODULE_${form}PREFIX) - list(GET pieces 1 module) - list(GET pieces 2 FortranCInterface_MODULE_${form}MIDDLE) - list(GET pieces 3 name) - list(GET pieces 4 FortranCInterface_MODULE_${form}SUFFIX) - set(FortranCInterface_MODULE_${form}CASE "${_case_${name}}") - endif() - endforeach() - endforeach() - - # Construct mangling macro definitions. - set(_name_LOWER "name") - set(_name_UPPER "NAME") - foreach(form "" "_") - if(FortranCInterface_GLOBAL_${form}SYMBOL) - if(FortranCInterface_GLOBAL_${form}PREFIX) - set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##") - else() - set(_prefix "") - endif() - if(FortranCInterface_GLOBAL_${form}SUFFIX) - set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}") - else() - set(_suffix "") - endif() - set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}") - set(FortranCInterface_GLOBAL${form}_MACRO - "(name,NAME) ${_prefix}${_name}${_suffix}") - endif() - if(FortranCInterface_MODULE_${form}SYMBOL) - if(FortranCInterface_MODULE_${form}PREFIX) - set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##") - else() - set(_prefix "") - endif() - if(FortranCInterface_MODULE_${form}SUFFIX) - set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}") - else() - set(_suffix "") - endif() - set(_name "${_name_${FortranCInterface_MODULE_${form}CASE}}") - set(_middle "##${FortranCInterface_MODULE_${form}MIDDLE}##") - set(FortranCInterface_MODULE${form}_MACRO - "(mod_name,name, mod_NAME,NAME) ${_prefix}mod_${_name}${_middle}${_name}${_suffix}") - endif() - endforeach() - - # Summarize what is available. - foreach(scope GLOBAL MODULE) - if(FortranCInterface_${scope}_SYMBOL AND - FortranCInterface_${scope}__SYMBOL) - set(FortranCInterface_${scope}_FOUND 1) - else() - set(FortranCInterface_${scope}_FOUND 0) - endif() - endforeach() - - # Record the detection results. - configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in - ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY) - file(APPEND ${FortranCInterface_BINARY_DIR}/Output.cmake "\n") - - # Report the results. - if(FortranCInterface_GLOBAL_FOUND) - if(FortranCInterface_MODULE_FOUND) - set(_result "Found GLOBAL and MODULE mangling") - else(FortranCInterface_MODULE_FOUND) - set(_result "Found GLOBAL but not MODULE mangling") - endif() - elseif(NOT _result) - set(_result "Failed to recognize symbols") - endif() - message(STATUS "Detecting Fortran/C Interface - ${_result}") +# 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. diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake new file mode 100644 index 000000000..b848d3392 --- /dev/null +++ b/Modules/FortranCInterface/Detect.cmake @@ -0,0 +1,165 @@ +configure_file(${FortranCInterface_SOURCE_DIR}/Input.cmake.in + ${FortranCInterface_BINARY_DIR}/Input.cmake @ONLY) + +# Detect the Fortran/C interface on the first run or when the +# configuration changes. +if(${FortranCInterface_BINARY_DIR}/Input.cmake + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + OR ${FortranCInterface_SOURCE_DIR}/Output.cmake.in + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + OR ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + OR ${CMAKE_CURRENT_LIST_FILE} + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + ) + message(STATUS "Detecting Fortran/C Interface") +else() + return() +endif() + +set(_result) + +# Build a sample project which reports symbols. +try_compile(FortranCInterface_COMPILED + ${FortranCInterface_BINARY_DIR} + ${FortranCInterface_SOURCE_DIR} + FortranCInterface + OUTPUT_VARIABLE FortranCInterface_OUTPUT) +set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED}) +unset(FortranCInterface_COMPILED CACHE) + +# Locate the sample project executable. +if(FortranCInterface_COMPILED) + find_program(FortranCInterface_EXE + NAMES FortranCInterface + PATHS ${FortranCInterface_BINARY_DIR} ${FortranCInterface_BINARY_DIR}/Debug + NO_DEFAULT_PATH + ) + set(FortranCInterface_EXE ${FortranCInterface_EXE}) + unset(FortranCInterface_EXE CACHE) +else() + set(_result "Failed to compile") + set(FortranCInterface_EXE) + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Fortran/C interface test project failed with the following output:\n" + "${FortranCInterface_OUTPUT}\n") +endif() + +# Load symbols from INFO:symbol[] strings in the executable. +set(FortranCInterface_SYMBOLS) +if(FortranCInterface_EXE) + file(STRINGS "${FortranCInterface_EXE}" _info_strings + LIMIT_COUNT 8 REGEX "INFO:[^[]*\\[") + foreach(info ${_info_strings}) + if("${info}" MATCHES ".*INFO:symbol\\[([^]]*)\\].*") + string(REGEX REPLACE ".*INFO:symbol\\[([^]]*)\\].*" "\\1" symbol "${info}") + list(APPEND FortranCInterface_SYMBOLS ${symbol}) + endif() + endforeach() +elseif(NOT _result) + set(_result "Failed to load sample executable") +endif() + +set(_case_mysub "LOWER") +set(_case_my_sub "LOWER") +set(_case_MYSUB "UPPER") +set(_case_MY_SUB "UPPER") +set(_global_regex "^(_*)(mysub|MYSUB)([_$]*)$") +set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$") +set(_module_regex "^(_*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$") +set(_module__regex "^(_*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$") + +# Parse the symbol names. +foreach(symbol ${FortranCInterface_SYMBOLS}) + foreach(form "" "_") + # Look for global symbols. + string(REGEX REPLACE "${_global_${form}regex}" + "\\1;\\2;\\3" pieces "${symbol}") + list(LENGTH pieces len) + if(len EQUAL 3) + set(FortranCInterface_GLOBAL_${form}SYMBOL "${symbol}") + list(GET pieces 0 FortranCInterface_GLOBAL_${form}PREFIX) + list(GET pieces 1 name) + list(GET pieces 2 FortranCInterface_GLOBAL_${form}SUFFIX) + set(FortranCInterface_GLOBAL_${form}CASE "${_case_${name}}") + endif() + + # Look for module symbols. + string(REGEX REPLACE "${_module_${form}regex}" + "\\1;\\2;\\3;\\4;\\5" pieces "${symbol}") + list(LENGTH pieces len) + if(len EQUAL 5) + set(FortranCInterface_MODULE_${form}SYMBOL "${symbol}") + list(GET pieces 0 FortranCInterface_MODULE_${form}PREFIX) + list(GET pieces 1 module) + list(GET pieces 2 FortranCInterface_MODULE_${form}MIDDLE) + list(GET pieces 3 name) + list(GET pieces 4 FortranCInterface_MODULE_${form}SUFFIX) + set(FortranCInterface_MODULE_${form}CASE "${_case_${name}}") + endif() + endforeach() +endforeach() + +# Construct mangling macro definitions. +set(_name_LOWER "name") +set(_name_UPPER "NAME") +foreach(form "" "_") + if(FortranCInterface_GLOBAL_${form}SYMBOL) + if(FortranCInterface_GLOBAL_${form}PREFIX) + set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##") + else() + set(_prefix "") + endif() + if(FortranCInterface_GLOBAL_${form}SUFFIX) + set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}") + else() + set(_suffix "") + endif() + set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}") + set(FortranCInterface_GLOBAL${form}_MACRO + "(name,NAME) ${_prefix}${_name}${_suffix}") + endif() + if(FortranCInterface_MODULE_${form}SYMBOL) + if(FortranCInterface_MODULE_${form}PREFIX) + set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##") + else() + set(_prefix "") + endif() + if(FortranCInterface_MODULE_${form}SUFFIX) + set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}") + else() + set(_suffix "") + endif() + set(_name "${_name_${FortranCInterface_MODULE_${form}CASE}}") + set(_middle "##${FortranCInterface_MODULE_${form}MIDDLE}##") + set(FortranCInterface_MODULE${form}_MACRO + "(mod_name,name, mod_NAME,NAME) ${_prefix}mod_${_name}${_middle}${_name}${_suffix}") + endif() +endforeach() + +# Summarize what is available. +foreach(scope GLOBAL MODULE) + if(FortranCInterface_${scope}_SYMBOL AND + FortranCInterface_${scope}__SYMBOL) + set(FortranCInterface_${scope}_FOUND 1) + else() + set(FortranCInterface_${scope}_FOUND 0) + endif() +endforeach() + +# Record the detection results. +configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in + ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY) +file(APPEND ${FortranCInterface_BINARY_DIR}/Output.cmake "\n") + +# Report the results. +if(FortranCInterface_GLOBAL_FOUND) + if(FortranCInterface_MODULE_FOUND) + set(_result "Found GLOBAL and MODULE mangling") + else(FortranCInterface_MODULE_FOUND) + set(_result "Found GLOBAL but not MODULE mangling") + endif() +elseif(NOT _result) + set(_result "Failed to recognize symbols") +endif() +message(STATUS "Detecting Fortran/C Interface - ${_result}")