CMakeAddFortranSubdirectory.cmake 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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> # .lib location relative to root binary tree (lib)
  17. # RUNTIME_DIR <dir> # .dll location relative to root binary tree (bin)
  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. #
  25. #=============================================================================
  26. # Copyright 2002-2009 Kitware, Inc.
  27. #
  28. # Distributed under the OSI-approved BSD License (the "License");
  29. # see accompanying file Copyright.txt for details.
  30. #
  31. # This software is distributed WITHOUT ANY WARRANTY; without even the
  32. # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  33. # See the License for more information.
  34. #=============================================================================
  35. # (To distribute this file outside of CMake, substitute the full
  36. # License text for the above reference.)
  37. set(_MS_MINGW_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
  38. include(CheckLanguage)
  39. include(ExternalProject)
  40. include(CMakeParseArguments)
  41. function(_setup_mingw_config_and_build source_dir)
  42. find_program(MINGW_GFORTRAN NAMES gfortran
  43. HINTS
  44. c:/MinGW/bin
  45. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin" )
  46. if(NOT MINGW_GFORTRAN)
  47. message(FATAL_ERROR
  48. "gfortran not found, please install MinGW with the gfortran option."
  49. "Or set the cache variable MINGW_GFORTRAN to the full path. "
  50. " This is required to build")
  51. endif()
  52. execute_process(COMMAND ${MINGW_GFORTRAN} -v ERROR_VARIABLE out)
  53. if(NOT "${out}" MATCHES "Target:.*mingw32")
  54. message(FATAL_ERROR "Non-MinGW gfortran found: ${MINGW_GFORTRAN}\n"
  55. "output from -v [${out}]\n"
  56. "set MINGW_GFORTRAN to the path to MinGW fortran.")
  57. endif()
  58. get_filename_component(MINGW_PATH ${MINGW_GFORTRAN} PATH)
  59. file(TO_NATIVE_PATH "${MINGW_PATH}" MINGW_PATH)
  60. string(REPLACE "\\" "\\\\" MINGW_PATH "${MINGW_PATH}")
  61. configure_file(
  62. ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in
  63. ${CMAKE_CURRENT_BINARY_DIR}/config_mingw.cmake
  64. @ONLY)
  65. configure_file(
  66. ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in
  67. ${CMAKE_CURRENT_BINARY_DIR}/build_mingw.cmake
  68. @ONLY)
  69. endfunction()
  70. function(_add_fortran_library_link_interface library depend_library)
  71. set_target_properties(${library} PROPERTIES
  72. IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "${depend_library}")
  73. endfunction()
  74. function(cmake_add_fortran_subdirectory subdir)
  75. # if we are not using MSVC without fortran support
  76. # then just use the usual add_subdirectory to build
  77. # the fortran library
  78. check_language(Fortran)
  79. if(NOT (MSVC AND (NOT CMAKE_Fortran_COMPILER)))
  80. add_subdirectory(${subdir})
  81. return()
  82. endif()
  83. # if we have MSVC without Intel fortran then setup
  84. # external projects to build with mingw fortran
  85. # Parse arguments to function
  86. set(oneValueArgs PROJECT ARCHIVE_DIR RUNTIME_DIR)
  87. set(multiValueArgs LIBRARIES LINK_LIBRARIES CMAKE_COMMAND_LINE)
  88. cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  89. set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
  90. set(project_name "${ARGS_PROJECT}")
  91. set(library_dir "${ARGS_ARCHIVE_DIR}")
  92. set(binary_dir "${ARGS_RUNTIME_DIR}")
  93. set(libraries ${ARGS_LIBRARIES})
  94. # use the same directory that add_subdirectory would have used
  95. set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}")
  96. # create build and configure wrapper scripts
  97. _setup_mingw_config_and_build(${source_dir})
  98. # create the external project
  99. externalproject_add(${project_name}_build
  100. SOURCE_DIR ${source_dir}
  101. BINARY_DIR ${build_dir}
  102. CONFIGURE_COMMAND ${CMAKE_COMMAND}
  103. -P ${CMAKE_CURRENT_BINARY_DIR}/config_mingw.cmake
  104. BUILD_COMMAND ${CMAKE_COMMAND}
  105. -P ${CMAKE_CURRENT_BINARY_DIR}/build_mingw.cmake
  106. INSTALL_COMMAND ""
  107. )
  108. # make the external project always run make with each build
  109. externalproject_add_step(${project_name}_build forcebuild
  110. COMMAND ${CMAKE_COMMAND}
  111. -E remove
  112. ${CMAKE_CURRENT_BUILD_DIR}/${project_name}-prefix/src/${project_name}-stamp/${project_name}-build
  113. DEPENDEES configure
  114. DEPENDERS build
  115. ALWAYS 1
  116. )
  117. # create imported targets for all libraries
  118. foreach(lib ${libraries})
  119. add_library(${lib} SHARED IMPORTED)
  120. set_property(TARGET ${lib} APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
  121. set_target_properties(${lib} PROPERTIES
  122. IMPORTED_IMPLIB_NOCONFIG
  123. "${build_dir}/${library_dir}/lib${lib}.lib"
  124. IMPORTED_LOCATION_NOCONFIG
  125. "${build_dir}/${binary_dir}/lib${lib}.dll"
  126. )
  127. add_dependencies(${lib} ${project_name}_build)
  128. endforeach()
  129. # now setup link libraries for targets
  130. set(start FALSE)
  131. set(target)
  132. foreach(lib ${ARGS_LINK_LIBRARIES})
  133. if("${lib}" STREQUAL "LINK_LIBS")
  134. set(start TRUE)
  135. else()
  136. if(start)
  137. if(DEFINED target)
  138. # process current target and target_libs
  139. _add_fortran_library_link_interface(${target} "${target_libs}")
  140. # zero out target and target_libs
  141. set(target)
  142. set(target_libs)
  143. endif()
  144. # save the current target and set start to FALSE
  145. set(target ${lib})
  146. set(start FALSE)
  147. else()
  148. # append the lib to target_libs
  149. list(APPEND target_libs "${lib}")
  150. endif()
  151. endif()
  152. endforeach()
  153. # process anything that is left in target and target_libs
  154. if(DEFINED target)
  155. _add_fortran_library_link_interface(${target} "${target_libs}")
  156. endif()
  157. endfunction()