CMakeAddFortranSubdirectory.cmake 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. # - Use MinGW gfortran from VS if a fortran compiler is not found.
  2. # The 'add_fortran_subdirectory' function adds a subdirectory
  3. # to a project that contains a fortran only sub-project. The module
  4. # will check the current compiler and see if it can support fortran.
  5. # If no fortran compiler is found and the compiler is MSVC, then
  6. # this module will find the MinGW gfortran. It will then use
  7. # an external project to build with the MinGW tools. It will also
  8. # create imported targets for the libraries created. This will only
  9. # work if the fortran code is built into a dll, so BUILD_SHARED_LIBS
  10. # is turned on in the project. In addition the GNUtoMS option is set
  11. # to on, so that the MS .lib files are created.
  12. # Usage is as follows:
  13. # cmake_add_fortran_subdirectory(
  14. # <subdir> # name of subdirectory
  15. # PROJECT <project_name> # project name in sbudir toplevel CMakeLists.txt
  16. # ARCHIVE_DIR <dir> # dir where project places .lib files
  17. # RUNTIME_DIR <dir> # dir where project places .dll files
  18. # LIBRARIES lib2 lib2 # names of libraries created and exported
  19. # LINK_LIBRARIES # link interface libraries for LIBRARIES
  20. # LINK_LIBS <lib1> <dep1> <dep2> ... <depN>
  21. # LINK_LIBS <lib2> <dep1> <dep2> ... <depN>
  22. # CMAKE_COMMAND_LINE # extra command line flags to pass to cmake
  23. # )
  24. # Relative paths in ARCHIVE_DIR and RUNTIME_DIR are interpreted with respect
  25. # to the build directory corresponding to the source directory in which the
  26. # function is invoked.
  27. #
  28. #=============================================================================
  29. # Copyright 2002-2009 Kitware, Inc.
  30. #
  31. # Distributed under the OSI-approved BSD License (the "License");
  32. # see accompanying file Copyright.txt for details.
  33. #
  34. # This software is distributed WITHOUT ANY WARRANTY; without even the
  35. # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  36. # See the License for more information.
  37. #=============================================================================
  38. # (To distribute this file outside of CMake, substitute the full
  39. # License text for the above reference.)
  40. set(_MS_MINGW_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
  41. include(CheckLanguage)
  42. include(ExternalProject)
  43. include(CMakeParseArguments)
  44. function(_setup_mingw_config_and_build source_dir)
  45. find_program(MINGW_GFORTRAN NAMES gfortran
  46. HINTS
  47. c:/MinGW/bin
  48. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin" )
  49. if(NOT MINGW_GFORTRAN)
  50. message(FATAL_ERROR
  51. "gfortran not found, please install MinGW with the gfortran option."
  52. "Or set the cache variable MINGW_GFORTRAN to the full path. "
  53. " This is required to build")
  54. endif()
  55. execute_process(COMMAND ${MINGW_GFORTRAN} -v ERROR_VARIABLE out)
  56. if(NOT "${out}" MATCHES "Target:.*mingw32")
  57. message(FATAL_ERROR "Non-MinGW gfortran found: ${MINGW_GFORTRAN}\n"
  58. "output from -v [${out}]\n"
  59. "set MINGW_GFORTRAN to the path to MinGW fortran.")
  60. endif()
  61. get_filename_component(MINGW_PATH ${MINGW_GFORTRAN} PATH)
  62. file(TO_NATIVE_PATH "${MINGW_PATH}" MINGW_PATH)
  63. string(REPLACE "\\" "\\\\" MINGW_PATH "${MINGW_PATH}")
  64. configure_file(
  65. ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in
  66. ${CMAKE_CURRENT_BINARY_DIR}/config_mingw.cmake
  67. @ONLY)
  68. configure_file(
  69. ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in
  70. ${CMAKE_CURRENT_BINARY_DIR}/build_mingw.cmake
  71. @ONLY)
  72. endfunction()
  73. function(_add_fortran_library_link_interface library depend_library)
  74. set_target_properties(${library} PROPERTIES
  75. IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "${depend_library}")
  76. endfunction()
  77. function(cmake_add_fortran_subdirectory subdir)
  78. # if we are not using MSVC without fortran support
  79. # then just use the usual add_subdirectory to build
  80. # the fortran library
  81. check_language(Fortran)
  82. if(NOT (MSVC AND (NOT CMAKE_Fortran_COMPILER)))
  83. add_subdirectory(${subdir})
  84. return()
  85. endif()
  86. # if we have MSVC without Intel fortran then setup
  87. # external projects to build with mingw fortran
  88. # Parse arguments to function
  89. set(oneValueArgs PROJECT ARCHIVE_DIR RUNTIME_DIR)
  90. set(multiValueArgs LIBRARIES LINK_LIBRARIES CMAKE_COMMAND_LINE)
  91. cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  92. set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
  93. set(project_name "${ARGS_PROJECT}")
  94. set(library_dir "${ARGS_ARCHIVE_DIR}")
  95. set(binary_dir "${ARGS_RUNTIME_DIR}")
  96. set(libraries ${ARGS_LIBRARIES})
  97. # use the same directory that add_subdirectory would have used
  98. set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}")
  99. foreach(dir_var library_dir binary_dir)
  100. if(NOT IS_ABSOLUTE "${${dir_var}}")
  101. get_filename_component(${dir_var}
  102. "${CMAKE_CURRENT_BINARY_DIR}/${${dir_var}}" ABSOLUTE)
  103. endif()
  104. endforeach()
  105. # create build and configure wrapper scripts
  106. _setup_mingw_config_and_build(${source_dir})
  107. # create the external project
  108. externalproject_add(${project_name}_build
  109. SOURCE_DIR ${source_dir}
  110. BINARY_DIR ${build_dir}
  111. CONFIGURE_COMMAND ${CMAKE_COMMAND}
  112. -P ${CMAKE_CURRENT_BINARY_DIR}/config_mingw.cmake
  113. BUILD_COMMAND ${CMAKE_COMMAND}
  114. -P ${CMAKE_CURRENT_BINARY_DIR}/build_mingw.cmake
  115. INSTALL_COMMAND ""
  116. )
  117. # make the external project always run make with each build
  118. externalproject_add_step(${project_name}_build forcebuild
  119. COMMAND ${CMAKE_COMMAND}
  120. -E remove
  121. ${CMAKE_CURRENT_BUILD_DIR}/${project_name}-prefix/src/${project_name}-stamp/${project_name}-build
  122. DEPENDEES configure
  123. DEPENDERS build
  124. ALWAYS 1
  125. )
  126. # create imported targets for all libraries
  127. foreach(lib ${libraries})
  128. add_library(${lib} SHARED IMPORTED)
  129. set_property(TARGET ${lib} APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
  130. set_target_properties(${lib} PROPERTIES
  131. IMPORTED_IMPLIB_NOCONFIG "${library_dir}/lib${lib}.lib"
  132. IMPORTED_LOCATION_NOCONFIG "${binary_dir}/lib${lib}.dll"
  133. )
  134. add_dependencies(${lib} ${project_name}_build)
  135. endforeach()
  136. # now setup link libraries for targets
  137. set(start FALSE)
  138. set(target)
  139. foreach(lib ${ARGS_LINK_LIBRARIES})
  140. if("${lib}" STREQUAL "LINK_LIBS")
  141. set(start TRUE)
  142. else()
  143. if(start)
  144. if(DEFINED target)
  145. # process current target and target_libs
  146. _add_fortran_library_link_interface(${target} "${target_libs}")
  147. # zero out target and target_libs
  148. set(target)
  149. set(target_libs)
  150. endif()
  151. # save the current target and set start to FALSE
  152. set(target ${lib})
  153. set(start FALSE)
  154. else()
  155. # append the lib to target_libs
  156. list(APPEND target_libs "${lib}")
  157. endif()
  158. endif()
  159. endforeach()
  160. # process anything that is left in target and target_libs
  161. if(DEFINED target)
  162. _add_fortran_library_link_interface(${target} "${target_libs}")
  163. endif()
  164. endfunction()