浏览代码

Create FortranCInterface_VERIFY function

This function builds a simple test project using a combination of
Fortran and C (and optionally C++) to verify that the compilers are
compatible.  The idea is to help projects report very early to users
that the compilers specified cannot mix languages.
Brad King 16 年之前
父节点
当前提交
a9be85da2e

+ 76 - 0
Modules/FortranCInterface.cmake

@@ -51,6 +51,18 @@
 # macros as the previous example plus preprocessor symbols FC_mysub
 # and FC_mymod_my_sub.
 #
+# Another 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.
+#
 # 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
@@ -183,3 +195,67 @@ ${_desc_${macro}}
   # 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.
+    try_compile(FortranCInterface_VERIFY_${lang}_COMPILED
+      ${FortranCInterface_BINARY_DIR}/Verify${lang}
+      ${FortranCInterface_SOURCE_DIR}/Verify
+      VerifyFortranC
+      CMAKE_FLAGS -DVERIFY_CXX=${verify_cxx}
+      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(REGEX 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()

+ 4 - 0
Modules/FortranCInterface/Detect.cmake

@@ -17,6 +17,10 @@ else()
   return()
 endif()
 
+# Invalidate verification results.
+unset(FortranCInterface_VERIFIED_C CACHE)
+unset(FortranCInterface_VERIFIED_CXX CACHE)
+
 set(_result)
 
 # Build a sample project which reports symbols.

+ 16 - 0
Modules/FortranCInterface/Verify/CMakeLists.txt

@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 2.7)
+project(VerifyFortranC C Fortran)
+
+option(VERIFY_CXX "Whether to verify C++ and Fortran" OFF)
+if(VERIFY_CXX)
+  enable_language(CXX)
+  set(VerifyCXX VerifyCXX.cxx)
+  add_definitions(-DVERIFY_CXX)
+endif()
+
+include(FortranCInterface)
+
+FortranCInterface_HEADER(VerifyFortran.h SYMBOLS VerifyFortran)
+include_directories(${VerifyFortranC_BINARY_DIR})
+
+add_executable(VerifyFortranC main.c VerifyC.c VerifyFortran.f ${VerifyCXX})

+ 5 - 0
Modules/FortranCInterface/Verify/VerifyC.c

@@ -0,0 +1,5 @@
+#include <stdio.h>
+void VerifyC(void)
+{
+  printf("VerifyC\n");
+}

+ 4 - 0
Modules/FortranCInterface/Verify/VerifyCXX.cxx

@@ -0,0 +1,4 @@
+extern "C" void VerifyCXX(void)
+{
+  delete new int;
+}

+ 3 - 0
Modules/FortranCInterface/Verify/VerifyFortran.f

@@ -0,0 +1,3 @@
+      subroutine VerifyFortran
+        print *, 'VerifyFortran'
+      end

+ 16 - 0
Modules/FortranCInterface/Verify/main.c

@@ -0,0 +1,16 @@
+extern void VerifyC(void);
+#ifdef VERIFY_CXX
+extern void VerifyCXX(void);
+#endif
+#include "VerifyFortran.h"
+extern void VerifyFortran(void);
+
+int main(void)
+{
+  VerifyC();
+#ifdef VERIFY_CXX
+  VerifyCXX();
+#endif
+  VerifyFortran();
+  return 0;
+}

+ 2 - 0
Tests/Fortran/CMakeLists.txt

@@ -14,6 +14,8 @@ function(test_fortran_c_interface_module)
   message(STATUS "Testing FortranCInterface module")
   # test the C to Fortran interface module
   include(FortranCInterface)
+  FortranCInterface_VERIFY(QUIET)
+  FortranCInterface_VERIFY(QUIET CXX)
   if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
     if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|MIPSpro")
       set(module_expected 1)