ImportTools.cmake
Go to the documentation of this file.
1 # ============================================================================
2 # Copyright (c) 2011-2012 University of Pennsylvania
3 # Copyright (c) 2013-2016 Andreas Schuh
4 # All rights reserved.
5 #
6 # See COPYING file for license information or visit
7 # https://cmake-basis.github.io/download.html#license
8 # ============================================================================
9 
10 ##############################################################################
11 # @file ImportTools.cmake
12 # @brief Functions and macros for the import of targets.
13 #
14 # @ingroup CMakeTools
15 ##############################################################################
16 
18  return ()
19 else ()
21 endif ()
22 
23 
24 ## @addtogroup CMakeUtilities
25 # @{
26 
27 # ----------------------------------------------------------------------------
28 ## @brief Set target property.
29 #
30 # This function is overwritten by BASIS in order to update the information
31 # about imported build targets.
32 #
33 # @note Do not use this function in your CMakeLists.txt configuration files.
34 # Use basis_set_target_properties() instead.
35 #
36 # @note Due to a bug in CMake (http://www.cmake.org/Bug/view.php?id=12303),
37 # except of the first property given directly after the @c PROPERTIES keyword,
38 # only properties listed in @c BASIS_PROPERTIES_ON_TARGETS can be set.
39 #
40 # @param [in] ARGN List of arguments for
41 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
42 # set_target_properties()</a>.
43 #
44 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties
45 function (set_target_properties)
46  # target names
47  list (FIND ARGN "PROPERTIES" IDX)
48  if (IDX EQUAL -1)
49  message (FATAL_ERROR "Missing PROPERTIES argument!")
50  elseif (IDX EQUAL 0)
51  message (FATAL_ERROR "No targets specified!")
52  endif ()
53  set (INDICES)
54  set (I 0)
55  while (I LESS IDX)
56  list (APPEND INDICES ${I})
57  math (EXPR I "${I} + 1")
58  endwhile ()
59  list (GET ARGN ${INDICES} TARGETS)
60  # remaining arguments are property value pairs
61  list (REMOVE_AT ARGN ${INDICES} ${IDX})
62  # set target properties
63  #
64  # Note: By iterating over the properties, the empty property values
65  # are correctly passed on to CMake's set_target_properties()
66  # command, while
67  # _set_target_properties(${TARGET_UIDS} PROPERTIES ${ARGN})
68  # (erroneously) discards the empty elements in ARGN.
69  if (BASIS_DEBUG)
70  message ("** set_target_properties:")
71  message ("** Target(s): ${TARGETS}")
72  message ("** Properties: [${ARGN}]")
73  endif ()
74  list (LENGTH ARGN N)
75  while (N GREATER 1)
76  list (GET ARGN 0 PROPERTY)
77  list (GET ARGN 1 VALUE)
78  list (REMOVE_AT ARGN 0 1)
79  list (LENGTH ARGN N)
80  # The following loop is only required b/c CMake's ARGV and ARGN
81  # lists do not support arguments which are themselves lists.
82  # Therefore, we need a way to decide when the list of values for a
83  # property is terminated. Hence, we only allow known properties
84  # to be set, except for the first property where the name follows
85  # directly after the PROPERTIES keyword.
86  while (N GREATER 0)
87  list (GET ARGN 0 ARG)
88  if (ARG MATCHES "${BASIS_PROPERTIES_ON_TARGETS_RE}")
89  break ()
90  endif ()
91  list (APPEND VALUE "${ARG}")
92  list (REMOVE_AT ARGN 0)
93  list (LENGTH ARGN N)
94  endwhile ()
95  if (BASIS_DEBUG)
96  message ("** -> ${PROPERTY} = [${VALUE}]")
97  endif ()
98  # check property name
99  if (PROPERTY MATCHES "^$")
100  message (FATAL_ERROR "Empty property name given!")
101  # if property is related to the location of an imported target,
102  # update corresponding project properties
103  elseif (PROPERTY MATCHES "^IMPORTED_LOCATION")
104  list (GET TARGETS 0 TARGET)
105  basis_update_imported_location (${TARGET} ${PROPERTY} "${VALUE}")
106  # if property is related to the type of an imported target,
107  # update corresponding project properties
108  elseif (PROPERTY MATCHES "^BASIS_TYPE$")
109  list (GET TARGETS 0 TARGET)
110  basis_update_imported_type (${TARGET} "${VALUE}")
111  endif ()
112  # set target property
113  _set_target_properties (${TARGETS} PROPERTIES ${PROPERTY} "${VALUE}")
114  endwhile ()
115  # make sure that every property had a corresponding value
116  if (NOT N EQUAL 0)
117  message (FATAL_ERROR "No value given for target property ${ARGN}")
118  endif ()
119 endfunction ()
120 
121 # ----------------------------------------------------------------------------
122 ## @brief Add imported target.
123 #
124 # Imported targets are only valid in the scope where they were imported.
125 # In order to be able to add the information of the imported executable targets
126 # to the ExecutableTargetInfo modules of the BASIS utilities which are configured
127 # during the finalization of the (top-level) project, the information of
128 # imported targets has to be stored in the global scope. Therefore, internal
129 # cache variables prefixed by the name of the project are used
130 # (see basis_set_project_property()):
131 #
132 # <table border="0">
133 # <tr>
134 # @tp @b IMPORTED_TARGETS @endtp
135 # <td>List of imported targets.</td>
136 # </tr>
137 # <tr>
138 # @tp @b IMPORTED_TYPES @endtp
139 # <td>Types of imported targets.</td>
140 # </tr>
141 # <tr>
142 # @tp @b IMPORTED_LOCATIONS @endtp
143 # <td>Locations of imported target files.</td>
144 # </tr>
145 # <tr>
146 # @tp @b IMPORTED_RANKS @endtp
147 # <td>Rank of current imported locations. This rank value is used to decide
148 # whether the current location takes precedence over another imported
149 # location. For example, IMPORTED_LOCATION_&lt;a&gt;, may be preferred
150 # over IMPORTED_LOCATION_&lt;b&gt;.
151 # </tr>
152 # </table>
153 #
154 # @param [in] TARGET Name (UID) of the imported target.
155 # @param [in] TYPE Type of the imported target.
156 #
157 # @sa basis_update_imported_location()
158 function (basis_add_imported_target TARGET TYPE)
159  if (BASIS_DEBUG AND BASIS_VERBOSE)
160  message ("** basis_add_imported_target:")
161  message ("** Target: ${TARGET}")
162  message ("** Type: ${TYPE}")
163  message ("** Bundled: ${BUNDLE_PROJECT}")
164  endif ()
165  if (NOT TYPE STREQUAL "INTERFACE")
166  if (BUNDLE_PROJECT)
167  _set_target_properties (${TARGET} PROPERTIES BUNDLED TRUE)
168  else ()
169  _set_target_properties (${TARGET} PROPERTIES BUNDLED FALSE)
170  endif ()
171  endif ()
172  # if target was added before
173  basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
174  if (TARGETS)
175  list (FIND TARGETS "${TARGET}" IDX)
176  if (NOT IDX EQUAL -1)
177  # do nothing
178  return ()
179  endif ()
180  endif ()
181  # otherwise, add it to the project properties
182  basis_set_project_property (APPEND PROPERTY IMPORTED_TARGETS "${TARGET}")
183  basis_set_project_property (APPEND PROPERTY IMPORTED_TYPES "${TYPE}")
184  basis_set_project_property (APPEND PROPERTY IMPORTED_LOCATIONS "NOTFOUND")
185  basis_set_project_property (APPEND PROPERTY IMPORTED_RANKS 10)
186 endfunction ()
187 
188 # ----------------------------------------------------------------------------
189 ## @brief Update location of imported target.
190 #
191 # @param [in] TARGET Name (UID) of the imported target.
192 # @param [in] PROPERTY Target location property. Either IMPORTED_LOCATION
193 # or IMPORTED_LOCATION_&lt;config&gt;, where &lt;config&gt;
194 # is one of the imported build configurations.
195 # This argument is used to decide whether to keep
196 # the current target information or to replace it
197 # by the new one.
198 # @param [in] LOCATION Location of imported target.
199 function (basis_update_imported_location TARGET PROPERTY LOCATION)
200  if (BASIS_DEBUG)
201  message ("** basis_update_imported_location:")
202  message ("** Target: ${TARGET}")
203  message ("** Location: ${LOCATION}")
204  endif ()
205  # get index of imported target
206  basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
207  list (FIND TARGETS "${TARGET}" IDX)
208  if (IDX EQUAL -1)
209  # imported targets have to be added via basis_add_imported_target() first
210  # otherwise, ignore target here and do not update the non-existent information
211  return ()
212  endif ()
213  # get current information of target
214  basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES)
215  basis_get_project_property (LOCATIONS PROPERTY IMPORTED_LOCATIONS)
216  basis_get_project_property (RANKS PROPERTY IMPORTED_RANKS)
217  list (GET TYPES ${IDX} TYPE)
218  list (GET RANKS ${IDX} CURRENT_RANK)
219  # decide whether current information shall be overwritten
220  if (CMAKE_BUILD_TYPE)
221  string (TOUPPER "${CMAKE_BUILD_TYPE}" C)
222  else ()
223  set (C "NOCONFIG")
224  endif ()
225  set (
226  RANKING
227  # first pick
228  "IMPORTED_LOCATION_${C}" # 0) prefer location corresponding to current configuration
229  "IMPORTED_LOCATION" # 1) then use non-configuration specific location
230  "IMPORTED_LOCATION_RELEASE" # 2) otherwise use RELEASE version if available
231  # 3) last pick, use first imported executable
232  )
233  list (FIND RANKING "${PROPERTY}" RANK)
234  if (RANK EQUAL -1)
235  set (RANK 3)
236  endif ()
237  # bail out if current information shall be kept
238  if (NOT "${RANK}" LESS "${CURRENT_RANK}")
239  return ()
240  endif ()
241  # remove current information
242  list (REMOVE_AT TYPES ${IDX})
243  list (REMOVE_AT LOCATIONS ${IDX})
244  list (REMOVE_AT RANKS ${IDX})
245  # add imported information
246  list (LENGTH TYPES N)
247  if (IDX LESS N)
248  list (INSERT TYPES ${IDX} "${TYPE}")
249  list (INSERT LOCATIONS ${IDX} "${LOCATION}")
250  list (INSERT RANKS ${IDX} "${RANK}")
251  else ()
252  list (APPEND TYPES "${TYPE}")
253  list (APPEND LOCATIONS "${LOCATION}")
254  list (APPEND RANKS "${RANK}")
255  endif ()
256  # update project properties
257  basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}")
258  basis_set_project_property (PROPERTY IMPORTED_LOCATIONS "${LOCATIONS}")
259  basis_set_project_property (PROPERTY IMPORTED_RANKS "${RANKS}")
260 endfunction ()
261 
262 # ----------------------------------------------------------------------------
263 ## @brief Update type of imported target.
264 #
265 # This function is in particular called in basis_set_target_properties()
266 # if the BASIS_TYPE property of custom BASIS targets is set after the
267 # imported target was added with the initial type UNKNOWN.
268 #
269 # @param [in] TARGET Name (UID) of the imported target.
270 # @param [in] TYPE Type of imported target.
271 function (basis_update_imported_type TARGET TYPE)
272  # get index of imported target
273  basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
274  list (FIND TARGETS "${TARGET}" IDX)
275  if (IDX EQUAL -1)
276  # imported targets have to be added via basis_add_imported_target() first
277  # otherwise, ignore target here and do not update the non-existent information
278  return ()
279  endif ()
280  # get current type of imported target
281  basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES)
282  list (GET TYPES ${IDX} CURRENT_TYPE)
283  # bail out if current type shall be kept
284  if (NOT CURRENT_TYPE MATCHES "^UNKNOWN$")
285  return ()
286  endif ()
287  # replace current type
288  list (REMOVE_AT TYPES ${IDX})
289  list (LENGTH TYPES N)
290  if (IDX LESS N)
291  list (INSERT TYPES ${IDX} ${TYPE})
292  else ()
293  list (APPEND TYPES ${TYPE})
294  endif ()
295  # update project property
296  basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}")
297 endfunction ()
298 
299 
300 ## @}
301 # end of Doxygen group
function set_target_properties(in ARGN)
Set target property.
cmake __BASIS_IMPORTTOOLS_INCLUDED
function is(in result, in expected, in name)
Test whether a given result is equal to the expected result.
def which(command, path=None, verbose=0, exts=None)
Definition: which.py:257
function basis_get_project_property(out VARIABLE, in ARGN)
Get project-global property value.
function basis_set_project_property()
Set project-global property.
function basis_update_imported_type(in TARGET, in TYPE)
Update type of imported target.
string CMAKE_BUILD_TYPE
function basis_update_imported_location(in TARGET, in PROPERTY, in LOCATION)
Update location of imported target.
string RELEASE
Project release.
Definition: utilities.sh:89
option BASIS_DEBUG
Request debugging messages from BASIS functions.
cmake VALUE
option BASIS_VERBOSE
Default Sphinx theme options.
function basis_add_imported_target(in TARGET, in TYPE)
Add imported target.