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