-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAddExternalDependency.cmake
202 lines (182 loc) · 10.1 KB
/
AddExternalDependency.cmake
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#
# File: AddExternalDependency.cmake
# Mark J. Olah (mjo AT cs.unm.edu)
# date: 2017-2018
# copyright: Licensed under the Apache License, Version 2.0. See LICENSE file.
#
# Function: AddExternalDependency
#
# Allows a cmake package dependency to be automatically added as a cmake ExternalProject, then built and installed
# to CMAKE_INSTALL_PREFIX. All this happens before configure time for the client package, so that the dependency will be
# automatically found through the cmake PackageConfig system and the normal find_package() mechanism.
#
# This approach eliminates the need for an explicit git submodule for the external package, and it allows the client package to
# be quickly built on systems where the ExternalProject is already installed.
#
# useage: AddExternalDependency(<package-name> <package-git-clone-url> [SHARED] [STATIC])
# Options:
# DISABLE_TESTING - Attempt to build testing functionality. [default=OFF]
# Single-Value arguments:
# NAME - [required] Name of PROJECT_NAME of the external cmake project
# URL - URL of git repository or local path to git repository (can be overwritten with ${PROJECT_NAME}URL environment variable giving alternate URL
# GIT_TAG - git tag to use
# VERSION - [optional] Version number of dependency required. Leave empty for any version with appropriate BUILD_TYPE_COMPATABILITY
# INSTALL_PREFIX - [optional] install location for package [defaults to CMAKE_INSTALL_PREFIX]
# CMAKELISTS_TEMPLATE - [optional] Template file for the CMakeLists.txt to the building and installing via ExternalProject_Add [default: Templates/External.CMakeLists.txt.in]
# BUILD_TYPE_COMPATABILITY - [optional] Default: Exact Options: Exact, Any
# TOOLCHAIN_FILE - [optional] [Only used if CMAKE_CROSSCOMPILING is true. Uses CMAKE_TOOLCHAIN_FILE as the default.]
#Multi-arguments
# VARS - [optional] List of cache variables to pass-through
# COMPONENTS - [optional] List of required components for find_package
#
# CMAKE options respected. (These can be enabled from the command line
# - OPT_AddExternalDependency_VERBOSE - Enable verbose output
# - OPT_AddExternalDependency_DISABLE_TESTING - Disable recursive BUILD_TESTING.
#
set(AddExternalDependency_include_path ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "Path of AddExternalDependency.cmake")
macro(add_external_dependency)
set(options SHARED STATIC TESTING)
set(oneArgOpts NAME URL GIT_TAG VERSION INSTALL_PREFIX CMAKELISTS_TEMPLATE BUILD_TYPE_COMPATABILITY TOOLCHAIN_FILE)
set(multiArgOpts VARS COMPONENTS)
cmake_parse_arguments(_EXT "${options}" "${oneArgOpts}" "${multiArgOpts}" ${ARGN})
if(NOT _EXT_NAME)
message(FATAL_ERROR "No package name given")
endif()
if(_EXT_UNPARSED_ARGUMENTS)
message(WARNING "[add_external_dependency] UNPARSED ARGUMENTS:${_EXT_UNPARSED_ARGUMENTS}")
endif()
if(NOT _EXT_INSTALL_PREFIX)
set(_EXT_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
endif()
#override _EXT_URL passed in with environment variable
set(_EXT_URL_ENV $ENV{${_EXT_NAME}URL})
if(_EXT_URL_ENV)
set(_EXT_URL $ENV{${_EXT_NAME}URL})
endif()
if(NOT _EXT_GIT_TAG)
set(_EXT_GIT_TAG master)
endif()
if(NOT _EXT_BUILD_TYPE_COMPATABILITY)
set(_EXT_BUILD_TYPE_COMPATABILITY Exact)
endif()
if(CMAKE_CROSSCOMPILING AND NOT _EXT_TOOLCHAIN_FILE)
set(_EXT_TOOLCHAIN_FILE ${CMAKE_TOOLCHAIN_FILE})
endif()
#PASS_CACHE_VARIABLES is a list of CMake variables to pass on command line.
# Fornat is <Var> or <Var>=<val>. If no <val> is specified, the current value of that CMake variable
# is passed.
set(_EXT_CMAKE_VARS BUILD_STATIC_LIBS BUILD_SHARED_LIBS)
if(_EXT_VARS)
list(APPEND _EXT_CMAKE_VARS ${_EXT_VARS})
endif()
list(APPEND _EXT_CMAKE_VARS CMAKE_INSTALL_PREFIX)
list(APPEND _EXT_CMAKE_VARS CMAKE_CXX_COMPILER CMAKE_C_COMPILER CMAKE_Fortran_COMPILER)
if(OPT_AddExternalDependency_DISABLE_TESTING)
list(APPEND _EXT_CMAKE_VARS BUILD_TESTING=Off) #Disable recursive testing if OPT_AddExternalDependency_DISABLE_TESTING
else()
list(APPEND _EXT_CMAKE_VARS BUILD_TESTING)
endif()
list(APPEND _EXT_CMAKE_VARS CMAKE_EXPORT_NO_PACKAGE_REGISTRY=On)
#Fixup each passed cache variable accepts Names and Name=val
if(_EXT_CMAKE_VARS)
set(_pass_vars)
foreach(_var IN LISTS _EXT_CMAKE_VARS)
if(${_var} MATCHES "([A-Za-z0-9_]+)=([A-Za-z0-9_/+-]+)")
set(_var ${CMAKE_MATCH_1})
set(_val ${CMAKE_MATCH_2})
if(DEFINED ${_var})
list(APPEND _pass_vars "-D${_var}=${_val}") # Use defined value
endif()
elseif(DEFINED ${_var})
list(APPEND _pass_vars "-D${_var}=${${_var}}") # Use current value
endif()
endforeach()
set(_EXT_CMAKE_VARS ${_pass_vars})
unset(_pass_vars)
endif()
set(_EXT_FIND_PACKAGE_ARGS)
if(NOT _EXT_VERSION)
list(APPEND _EXT_FIND_PACKAGE_ARGS CONFIG)
else()
list(APPEND _EXT_FIND_PACKAGE_ARGS ${_EXT_VERSION} CONFIG)
endif()
if(_EXT_COMPONENTS)
list(APPEND _EXT_FIND_PACKAGE_ARGS COMPONENTS ${_EXT_COMPONENTS})
endif()
find_package(${_EXT_NAME} ${_EXT_FIND_PACKAGE_ARGS} CMAKE_FIND_ROOT_PATH_BOTH)
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
if( (NOT ${_EXT_NAME}_FOUND) OR
(${_EXT_NAME}_BUILD_TYPES AND (NOT ${BUILD_TYPE} IN_LIST ${_EXT_NAME}_BUILD_TYPES)) )
set(_EXT_Dir ${CMAKE_BINARY_DIR}/External/${_EXT_NAME})
message(STATUS "[add_external_dependency] Not found: ${_EXT_NAME}")
if(${_EXT_BUILD_TYPE_COMPATABILITY} STREQUAL Exact AND ${_EXT_NAME}_BUILD_TYPES AND (NOT ${BUILD_TYPE} IN_LIST ${_EXT_NAME}_BUILD_TYPES))
message(STATUS "[add_external_dependency] ${_EXT_NAME} Build types: {${${_EXT_NAME}_BUILD_TYPES}}; Does not provide current build type: ${BUILD_TYPE}.")
endif()
if(NOT _EXT_INSTALL_PREFIX)
message(FATAL_ERROR "[add_external_dependency] CMAKE_INSTALL_PREFIX is not set and INSTALL_PREFIX argument is not set."
" Cannot use AddExternalDependency to autoinstall ${_EXT_NAME}"
" Recommend: (1) Set CMAKE_INSTALL_PREFIX to a valid directory. This can be a local directory if this package is to be exported"
" directly from the build tree."
" (2) Install dependency ${_EXT_NAME} from URL: ${_EXT_URL} to a user or system location cmake can find.")
endif()
if(NOT _EXT_URL)
message(FATAL_ERROR "[add_external_autotools_dependency] No URL provided.")
endif()
message(STATUS "[add_external_dependency] Initializing as ExternalProject URL:${_EXT_URL}")
if(NOT _EXT_CMAKELISTS_TEMPLATE)
find_file(_EXT_CMAKELISTS_TEMPLATE NAME External.CMakeLists.txt.in PATHS ${AddExternalDependency_include_path}/Templates NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
mark_as_advanced(_EXT_CMAKELISTS_TEMPLATE)
if(NOT _EXT_CMAKELISTS_TEMPLATE)
message(FATAL_ERROR "[add_external_dependency] Could not locate template file External.CMakeLists.txt.in in path ${AddExternalDependency_include_path}/Templates")
endif()
endif()
if(CMAKE_CROSSCOMPILING)
set(_EXT_TOOLCHAIN_ARGS -DCMAKE_TOOLCHAIN_FILE=${_EXT_TOOLCHAIN_FILE})
else()
set(_EXT_TOOLCHAIN_ARGS)
endif()
if(OPT_AddExternalDependency_VERBOSE)
message(STATUS "[add_external_dependency] CMAKE_ARGS:${_EXT_CMAKE_VARS}")
endif()
configure_file(${_EXT_CMAKELISTS_TEMPLATE} ${_EXT_Dir}/CMakeLists.txt @ONLY)
execute_process(COMMAND ${CMAKE_COMMAND} . WORKING_DIRECTORY ${_EXT_Dir})
message(STATUS "[add_external_dependency] Downloading Building and Installing: ${_EXT_NAME}")
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${_EXT_Dir})
find_package(${_EXT_NAME} ${_EXT_FIND_PACKAGE_ARGS} PATHS ${_EXT_INSTALL_PREFIX}/lib/cmake/${_EXT_NAME} NO_CMAKE_FIND_ROOT_PATH)
if(NOT ${_EXT_NAME}_FOUND)
message(FATAL_ERROR "[add_external_dependency] Install of ${_EXT_NAME} failed.")
endif()
message(STATUS "[add_external_dependency] Installed: ${_EXT_NAME} Ver:${${_EXT_NAME}_VERSION} Location:${PACKAGE_PREFIX_DIR}")
else()
message(STATUS "[add_external_dependency] Found:${_EXT_NAME} Ver:${${_EXT_NAME}_VERSION} Location:${PACKAGE_PREFIX_DIR}")
endif()
if(OPT_AddExternalDependency_VERBOSE)
#Debugging
message(STATUS "[add_external_dependency] FIND_PACKAGE_CONSIDERED_CONFIGS: ${${_EXT_NAME}_CONSIDERED_CONFIGS}")
message(STATUS "[add_external_dependency] FIND_PACKAGE_CONSIDERED_VERSIONS: ${${_EXT_NAME}_CONSIDERED_VERSIONS}")
if(${_EXT_NAME}_TARGETS)
set(_EXT_Targets ${${_EXT_NAME}_TARGETS})
elseif(TARGET ${_EXT_NAME}::${_EXT_NAME})
set(_EXT_Targets ${_EXT_NAME}::${_EXT_NAME})
elseif(${_EXT_NAME}_LIBRARIES)
set(_EXT_Targets ${_EXT_NAME}_LIBRARIES)
endif()
message(STATUS "[add_external_dependency] Imported Targets: ${_EXT_Targets}")
set(_EXT_Print_Properties TYPE IMPORTED_CONFIGURATIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_LINK_DIRECTORIES INTERFACE_COMPILE_FEATURES)
set(_EXT_Config_Properties IMPORTED_LOCATION IMPORTED_LINK_DEPENDENT_LIBRARIES IMPORTED_LINK_INTERFACE_LIBRARIES)
set(_EXT_Config_Types RELEASE DEBUG RELWITHDEBINFO MINSIZEREL)
foreach(prop IN LISTS _EXT_Config_Properties)
foreach(type IN LISTS _EXT_Config_Types)
list(APPEND _EXT_Print_Properties ${prop}_${type})
endforeach()
endforeach()
foreach(target IN LISTS _EXT_Targets)
foreach(prop IN LISTS _EXT_Print_Properties)
get_target_property(v ${target} ${prop})
if(v)
message(STATUS "[add_external_dependency] [${target}] ${prop}: ${v}")
endif()
endforeach()
endforeach()
endif()
endmacro()