diff options
Diffstat (limited to 'Modules/FortranCInterface')
-rw-r--r-- | Modules/FortranCInterface/Detect.cmake | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake new file mode 100644 index 0000000..b848d33 --- /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}") |