-
Notifications
You must be signed in to change notification settings - Fork 16
/
ImportTools.cmake
301 lines (291 loc) · 11.2 KB
/
ImportTools.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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# ============================================================================
# Copyright (c) 2011-2012 University of Pennsylvania
# Copyright (c) 2013-2014 Andreas Schuh
# All rights reserved.
#
# See COPYING file for license information or visit
# http://opensource.andreasschuh.com/cmake-basis/download.html#license
# ============================================================================
##############################################################################
# @file ImportTools.cmake
# @brief Functions and macros for the import of targets.
#
# @ingroup CMakeTools
##############################################################################
if (__BASIS_IMPORTTOOLS_INCLUDED)
return ()
else ()
set (__BASIS_IMPORTTOOLS_INCLUDED TRUE)
endif ()
## @addtogroup CMakeUtilities
# @{
# ----------------------------------------------------------------------------
## @brief Set target property.
#
# This function is overwritten by BASIS in order to update the information
# about imported build targets.
#
# @note Do not use this function in your CMakeLists.txt configuration files.
# Use basis_set_target_properties() instead.
#
# @note Due to a bug in CMake (http://www.cmake.org/Bug/view.php?id=12303),
# except of the first property given directly after the @c PROPERTIES keyword,
# only properties listed in @c BASIS_PROPERTIES_ON_TARGETS can be set.
#
# @param [in] ARGN List of arguments for
# <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
# set_target_properties()</a>.
#
# @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties
function (set_target_properties)
# target names
list (FIND ARGN "PROPERTIES" IDX)
if (IDX EQUAL -1)
message (FATAL_ERROR "Missing PROPERTIES argument!")
elseif (IDX EQUAL 0)
message (FATAL_ERROR "No targets specified!")
endif ()
set (INDICES)
set (I 0)
while (I LESS IDX)
list (APPEND INDICES ${I})
math (EXPR I "${I} + 1")
endwhile ()
list (GET ARGN ${INDICES} TARGETS)
# remaining arguments are property value pairs
list (REMOVE_AT ARGN ${INDICES} ${IDX})
# set target properties
#
# Note: By iterating over the properties, the empty property values
# are correctly passed on to CMake's set_target_properties()
# command, while
# _set_target_properties(${TARGET_UIDS} PROPERTIES ${ARGN})
# (erroneously) discards the empty elements in ARGN.
if (BASIS_DEBUG)
message ("** set_target_properties:")
message ("** Target(s): ${TARGETS}")
message ("** Properties: [${ARGN}]")
endif ()
list (LENGTH ARGN N)
while (N GREATER 1)
list (GET ARGN 0 PROPERTY)
list (GET ARGN 1 VALUE)
list (REMOVE_AT ARGN 0 1)
list (LENGTH ARGN N)
# The following loop is only required b/c CMake's ARGV and ARGN
# lists do not support arguments which are themselves lists.
# Therefore, we need a way to decide when the list of values for a
# property is terminated. Hence, we only allow known properties
# to be set, except for the first property where the name follows
# directly after the PROPERTIES keyword.
while (N GREATER 0)
list (GET ARGN 0 ARG)
if (ARG MATCHES "${BASIS_PROPERTIES_ON_TARGETS_RE}")
break ()
endif ()
list (APPEND VALUE "${ARG}")
list (REMOVE_AT ARGN 0)
list (LENGTH ARGN N)
endwhile ()
if (BASIS_DEBUG)
message ("** -> ${PROPERTY} = [${VALUE}]")
endif ()
# check property name
if (PROPERTY MATCHES "^$")
message (FATAL_ERROR "Empty property name given!")
# if property is related to the location of an imported target,
# update corresponding project properties
elseif (PROPERTY MATCHES "^IMPORTED_LOCATION")
list (GET TARGETS 0 TARGET)
basis_update_imported_location (${TARGET} ${PROPERTY} "${VALUE}")
# if property is related to the type of an imported target,
# update corresponding project properties
elseif (PROPERTY MATCHES "^BASIS_TYPE$")
list (GET TARGETS 0 TARGET)
basis_update_imported_type (${TARGET} "${VALUE}")
endif ()
# set target property
_set_target_properties (${TARGETS} PROPERTIES ${PROPERTY} "${VALUE}")
endwhile ()
# make sure that every property had a corresponding value
if (NOT N EQUAL 0)
message (FATAL_ERROR "No value given for target property ${ARGN}")
endif ()
endfunction ()
# ----------------------------------------------------------------------------
## @brief Add imported target.
#
# Imported targets are only valid in the scope where they were imported.
# In order to be able to add the information of the imported executable targets
# to the ExecutableTargetInfo modules of the BASIS utilities which are configured
# during the finalization of the (top-level) project, the information of
# imported targets has to be stored in the global scope. Therefore, internal
# cache variables prefixed by the name of the project are used
# (see basis_set_project_property()):
#
# <table border="0">
# <tr>
# @tp @b IMPORTED_TARGETS @endtp
# <td>List of imported targets.</td>
# </tr>
# <tr>
# @tp @b IMPORTED_TYPES @endtp
# <td>Types of imported targets.</td>
# </tr>
# <tr>
# @tp @b IMPORTED_LOCATIONS @endtp
# <td>Locations of imported target files.</td>
# </tr>
# <tr>
# @tp @b IMPORTED_RANKS @endtp
# <td>Rank of current imported locations. This rank value is used to decide
# whether the current location takes precedence over another imported
# location. For example, IMPORTED_LOCATION_<a>, may be preferred
# over IMPORTED_LOCATION_<b>.
# </tr>
# </table>
#
# @param [in] TARGET Name (UID) of the imported target.
# @param [in] TYPE Type of the imported target.
#
# @sa basis_update_imported_location()
function (basis_add_imported_target TARGET TYPE)
if (BASIS_DEBUG AND BASIS_VERBOSE)
message ("** basis_add_imported_target:")
message ("** Target: ${TARGET}")
message ("** Type: ${TYPE}")
message ("** Bundled: ${BUNDLE_PROJECT}")
endif ()
if (NOT TYPE STREQUAL "INTERFACE")
if (BUNDLE_PROJECT)
_set_target_properties (${TARGET} PROPERTIES BUNDLED TRUE)
else ()
_set_target_properties (${TARGET} PROPERTIES BUNDLED FALSE)
endif ()
endif ()
# if target was added before
basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
if (TARGETS)
list (FIND TARGETS "${TARGET}" IDX)
if (NOT IDX EQUAL -1)
# do nothing
return ()
endif ()
endif ()
# otherwise, add it to the project properties
basis_set_project_property (APPEND PROPERTY IMPORTED_TARGETS "${TARGET}")
basis_set_project_property (APPEND PROPERTY IMPORTED_TYPES "${TYPE}")
basis_set_project_property (APPEND PROPERTY IMPORTED_LOCATIONS "NOTFOUND")
basis_set_project_property (APPEND PROPERTY IMPORTED_RANKS 10)
endfunction ()
# ----------------------------------------------------------------------------
## @brief Update location of imported target.
#
# @param [in] TARGET Name (UID) of the imported target.
# @param [in] PROPERTY Target location property. Either IMPORTED_LOCATION
# or IMPORTED_LOCATION_<config>, where <config>
# is one of the imported build configurations.
# This argument is used to decide whether to keep
# the current target information or to replace it
# by the new one.
# @param [in] LOCATION Location of imported target.
function (basis_update_imported_location TARGET PROPERTY LOCATION)
if (BASIS_DEBUG)
message ("** basis_update_imported_location:")
message ("** Target: ${TARGET}")
message ("** Location: ${LOCATION}")
endif ()
# get index of imported target
basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
list (FIND TARGETS "${TARGET}" IDX)
if (IDX EQUAL -1)
# imported targets have to be added via basis_add_imported_target() first
# otherwise, ignore target here and do not update the non-existent information
return ()
endif ()
# get current information of target
basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES)
basis_get_project_property (LOCATIONS PROPERTY IMPORTED_LOCATIONS)
basis_get_project_property (RANKS PROPERTY IMPORTED_RANKS)
list (GET TYPES ${IDX} TYPE)
list (GET RANKS ${IDX} CURRENT_RANK)
# decide whether current information shall be overwritten
if (CMAKE_BUILD_TYPE)
string (TOUPPER "${CMAKE_BUILD_TYPE}" C)
else ()
set (C "NOCONFIG")
endif ()
set (
RANKING
# first pick
"IMPORTED_LOCATION_${C}" # 0) prefer location corresponding to current configuration
"IMPORTED_LOCATION" # 1) then use non-configuration specific location
"IMPORTED_LOCATION_RELEASE" # 2) otherwise use RELEASE version if available
# 3) last pick, use first imported executable
)
list (FIND RANKING "${PROPERTY}" RANK)
if (RANK EQUAL -1)
set (RANK 3)
endif ()
# bail out if current information shall be kept
if (NOT "${RANK}" LESS "${CURRENT_RANK}")
return ()
endif ()
# remove current information
list (REMOVE_AT TYPES ${IDX})
list (REMOVE_AT LOCATIONS ${IDX})
list (REMOVE_AT RANKS ${IDX})
# add imported information
list (LENGTH TYPES N)
if (IDX LESS N)
list (INSERT TYPES ${IDX} "${TYPE}")
list (INSERT LOCATIONS ${IDX} "${LOCATION}")
list (INSERT RANKS ${IDX} "${RANK}")
else ()
list (APPEND TYPES "${TYPE}")
list (APPEND LOCATIONS "${LOCATION}")
list (APPEND RANKS "${RANK}")
endif ()
# update project properties
basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}")
basis_set_project_property (PROPERTY IMPORTED_LOCATIONS "${LOCATIONS}")
basis_set_project_property (PROPERTY IMPORTED_RANKS "${RANKS}")
endfunction ()
# ----------------------------------------------------------------------------
## @brief Update type of imported target.
#
# This function is in particular called in basis_set_target_properties()
# if the BASIS_TYPE property of custom BASIS targets is set after the
# imported target was added with the initial type UNKNOWN.
#
# @param [in] TARGET Name (UID) of the imported target.
# @param [in] TYPE Type of imported target.
function (basis_update_imported_type TARGET TYPE)
# get index of imported target
basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
list (FIND TARGETS "${TARGET}" IDX)
if (IDX EQUAL -1)
# imported targets have to be added via basis_add_imported_target() first
# otherwise, ignore target here and do not update the non-existent information
return ()
endif ()
# get current type of imported target
basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES)
list (GET TYPES ${IDX} CURRENT_TYPE)
# bail out if current type shall be kept
if (NOT CURRENT_TYPE MATCHES "^UNKNOWN$")
return ()
endif ()
# replace current type
list (REMOVE_AT TYPES ${IDX})
list (LENGTH TYPES N)
if (IDX LESS N)
list (INSERT TYPES ${IDX} ${TYPE})
else ()
list (APPEND TYPES ${TYPE})
endif ()
# update project property
basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}")
endfunction ()
## @}
# end of Doxygen group