ImportTools.cmake
Go to the documentation of this file.
00001 ############################################################################## 00002 # @file ImportTools.cmake 00003 # @brief Functions and macros for the import of targets. 00004 # 00005 # Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br /> 00006 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file. 00007 # 00008 # Contact: SBIA Group <sbia-software at uphs.upenn.edu> 00009 # 00010 # @ingroup CMakeTools 00011 ############################################################################## 00012 00013 if (__BASIS_IMPORTTOOLS_INCLUDED) 00014 return () 00015 else () 00016 set (__BASIS_IMPORTTOOLS_INCLUDED TRUE) 00017 endif () 00018 00019 00020 ## @addtogroup CMakeUtilities 00021 # @{ 00022 00023 # ---------------------------------------------------------------------------- 00024 ## @brief Set target property. 00025 # 00026 # This function is overwritten by BASIS in order to update the information 00027 # about imported build targets. 00028 # 00029 # @note Do not use this function in your CMakeLists.txt configuration files. 00030 # Use basis_set_target_properties() instead. 00031 # 00032 # @note Due to a bug in CMake (http://www.cmake.org/Bug/view.php?id=12303), 00033 # except of the first property given directly after the @c PROPERTIES keyword, 00034 # only properties listed in @c BASIS_PROPERTIES_ON_TARGETS can be set. 00035 # 00036 # @param [in] ARGN List of arguments for 00037 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties"> 00038 # set_target_properties()</a>. 00039 # 00040 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties 00041 function (set_target_properties) 00042 # target names 00043 list (FIND ARGN "PROPERTIES" IDX) 00044 if (IDX EQUAL -1) 00045 message (FATAL_ERROR "Missing PROPERTIES argument!") 00046 elseif (IDX EQUAL 0) 00047 message (FATAL_ERROR "No targets specified!") 00048 endif () 00049 set (INDICES) 00050 set (I 0) 00051 while (I LESS IDX) 00052 list (APPEND INDICES ${I}) 00053 math (EXPR I "${I} + 1") 00054 endwhile () 00055 list (GET ARGN ${INDICES} TARGETS) 00056 # remaining arguments are property value pairs 00057 list (REMOVE_AT ARGN ${INDICES} ${IDX}) 00058 # set target properties 00059 # 00060 # Note: By iterating over the properties, the empty property values 00061 # are correctly passed on to CMake's set_target_properties() 00062 # command, while 00063 # _set_target_properties(${TARGET_UIDS} PROPERTIES ${ARGN}) 00064 # (erroneously) discards the empty elements in ARGN. 00065 if (BASIS_DEBUG) 00066 message ("** set_target_properties:") 00067 message ("** Target(s): ${TARGETS}") 00068 message ("** Properties: [${ARGN}]") 00069 endif () 00070 list (LENGTH ARGN N) 00071 while (N GREATER 1) 00072 list (GET ARGN 0 PROPERTY) 00073 list (GET ARGN 1 VALUE) 00074 list (REMOVE_AT ARGN 0 1) 00075 list (LENGTH ARGN N) 00076 # The following loop is only required b/c CMake's ARGV and ARGN 00077 # lists do not support arguments which are themselves lists. 00078 # Therefore, we need a way to decide when the list of values for a 00079 # property is terminated. Hence, we only allow known properties 00080 # to be set, except for the first property where the name follows 00081 # directly after the PROPERTIES keyword. 00082 while (N GREATER 0) 00083 list (GET ARGN 0 ARG) 00084 if (ARG MATCHES "${BASIS_PROPERTIES_ON_TARGETS_RE}") 00085 break () 00086 endif () 00087 list (APPEND VALUE "${ARG}") 00088 list (REMOVE_AT ARGN 0) 00089 list (LENGTH ARGN N) 00090 endwhile () 00091 if (BASIS_DEBUG) 00092 message ("** -> ${PROPERTY} = [${VALUE}]") 00093 endif () 00094 # check property name 00095 if (PROPERTY MATCHES "^$") 00096 message (FATAL_ERROR "Empty property name given!") 00097 # if property is related to the location of an imported target, 00098 # update corresponding project properties 00099 elseif (PROPERTY MATCHES "^IMPORTED_LOCATION") 00100 list (GET TARGETS 0 TARGET) 00101 basis_update_imported_location (${TARGET} ${PROPERTY} "${VALUE}") 00102 # if property is related to the type of an imported target, 00103 # update corresponding project properties 00104 elseif (PROPERTY MATCHES "^BASIS_TYPE$") 00105 list (GET TARGETS 0 TARGET) 00106 basis_update_imported_type (${TARGET} "${VALUE}") 00107 endif () 00108 # set target property 00109 _set_target_properties (${TARGETS} PROPERTIES ${PROPERTY} "${VALUE}") 00110 endwhile () 00111 # make sure that every property had a corresponding value 00112 if (NOT N EQUAL 0) 00113 message (FATAL_ERROR "No value given for target property ${ARGN}") 00114 endif () 00115 endfunction () 00116 00117 # ---------------------------------------------------------------------------- 00118 ## @brief Add imported target. 00119 # 00120 # Imported targets are only valid in the scope where they were imported. 00121 # In order to be able to add the information of the imported executable targets 00122 # to the ExecutableTargetInfo modules of the BASIS utilities which are configured 00123 # during the finalization of the (top-level) project, the information of 00124 # imported targets has to be stored in the global scope. Therefore, internal 00125 # cache variables prefixed by the name of the project are used 00126 # (see basis_set_project_property()): 00127 # 00128 # <table border="0"> 00129 # <tr> 00130 # @tp @b IMPORTED_TARGETS @endtp 00131 # <td>List of imported targets.</td> 00132 # </tr> 00133 # <tr> 00134 # @tp @b IMPORTED_TYPES @endtp 00135 # <td>Types of imported targets.</td> 00136 # </tr> 00137 # <tr> 00138 # @tp @b IMPORTED_LOCATIONS @endtp 00139 # <td>Locations of imported target files.</td> 00140 # </tr> 00141 # <tr> 00142 # @tp @b IMPORTED_RANKS @endtp 00143 # <td>Rank of current imported locations. This rank value is used to decide 00144 # whether the current location takes precedence over another imported 00145 # location. For example, IMPORTED_LOCATION_<a>, may be preferred 00146 # over IMPORTED_LOCATION_<b>. 00147 # </tr> 00148 # </table> 00149 # 00150 # @param [in] TARGET Name (UID) of the imported target. 00151 # @param [in] TYPE Type of the imported target. 00152 # 00153 # @sa basis_update_imported_location() 00154 function (basis_add_imported_target TARGET TYPE) 00155 if (BASIS_DEBUG AND BASIS_VERBOSE) 00156 message ("** basis_add_imported_target:") 00157 message ("** Target: ${TARGET}") 00158 message ("** Type: ${TYPE}") 00159 message ("** Bundled: ${BUNDLE_PROJECT}") 00160 endif () 00161 if (BUNDLE_PROJECT) 00162 _set_target_properties (${TARGET} PROPERTIES BUNDLED TRUE) 00163 else () 00164 _set_target_properties (${TARGET} PROPERTIES BUNDLED FALSE) 00165 endif () 00166 # if target was added before 00167 basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS) 00168 if (TARGETS) 00169 list (FIND TARGETS "${TARGET}" IDX) 00170 if (NOT IDX EQUAL -1) 00171 # do nothing 00172 return () 00173 endif () 00174 endif () 00175 # otherwise, add it to the project properties 00176 basis_set_project_property (APPEND PROPERTY IMPORTED_TARGETS "${TARGET}") 00177 basis_set_project_property (APPEND PROPERTY IMPORTED_TYPES "${TYPE}") 00178 basis_set_project_property (APPEND PROPERTY IMPORTED_LOCATIONS "NOTFOUND") 00179 basis_set_project_property (APPEND PROPERTY IMPORTED_RANKS 10) 00180 endfunction () 00181 00182 # ---------------------------------------------------------------------------- 00183 ## @brief Update location of imported target. 00184 # 00185 # @param [in] TARGET Name (UID) of the imported target. 00186 # @param [in] PROPERTY Target location property. Either IMPORTED_LOCATION 00187 # or IMPORTED_LOCATION_<config>, where <config> 00188 # is one of the imported build configurations. 00189 # This argument is used to decide whether to keep 00190 # the current target information or to replace it 00191 # by the new one. 00192 # @param [in] LOCATION Location of imported target. 00193 function (basis_update_imported_location TARGET PROPERTY LOCATION) 00194 if (BASIS_DEBUG) 00195 message ("** basis_update_imported_location:") 00196 message ("** Target: ${TARGET}") 00197 message ("** Location: ${LOCATION}") 00198 endif () 00199 # get index of imported target 00200 basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS) 00201 list (FIND TARGETS "${TARGET}" IDX) 00202 if (IDX EQUAL -1) 00203 # imported targets have to be added via basis_add_imported_target() first 00204 # otherwise, ignore target here and do not update the non-existent information 00205 return () 00206 endif () 00207 # get current information of target 00208 basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES) 00209 basis_get_project_property (LOCATIONS PROPERTY IMPORTED_LOCATIONS) 00210 basis_get_project_property (RANKS PROPERTY IMPORTED_RANKS) 00211 list (GET TYPES ${IDX} TYPE) 00212 list (GET RANKS ${IDX} CURRENT_RANK) 00213 # decide whether current information shall be overwritten 00214 if (CMAKE_BUILD_TYPE) 00215 string (TOUPPER "${CMAKE_BUILD_TYPE}" C) 00216 else () 00217 set (C "NOCONFIG") 00218 endif () 00219 set ( 00220 RANKING 00221 # first pick 00222 "IMPORTED_LOCATION_${C}" # 0) prefer location corresponding to current configuration 00223 "IMPORTED_LOCATION" # 1) then use non-configuration specific location 00224 "IMPORTED_LOCATION_RELEASE" # 2) otherwise use RELEASE version if available 00225 # 3) last pick, use first imported executable 00226 ) 00227 list (FIND RANKING "${PROPERTY}" RANK) 00228 if (RANK EQUAL -1) 00229 set (RANK 3) 00230 endif () 00231 # bail out if current information shall be kept 00232 if (NOT "${RANK}" LESS "${CURRENT_RANK}") 00233 return () 00234 endif () 00235 # remove current information 00236 list (REMOVE_AT TYPES ${IDX}) 00237 list (REMOVE_AT LOCATIONS ${IDX}) 00238 list (REMOVE_AT RANKS ${IDX}) 00239 # add imported information 00240 list (LENGTH TYPES N) 00241 if (IDX LESS N) 00242 list (INSERT TYPES ${IDX} "${TYPE}") 00243 list (INSERT LOCATIONS ${IDX} "${LOCATION}") 00244 list (INSERT RANKS ${IDX} "${RANK}") 00245 else () 00246 list (APPEND TYPES "${TYPE}") 00247 list (APPEND LOCATIONS "${LOCATION}") 00248 list (APPEND RANKS "${RANK}") 00249 endif () 00250 # update project properties 00251 basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}") 00252 basis_set_project_property (PROPERTY IMPORTED_LOCATIONS "${LOCATIONS}") 00253 basis_set_project_property (PROPERTY IMPORTED_RANKS "${RANKS}") 00254 endfunction () 00255 00256 # ---------------------------------------------------------------------------- 00257 ## @brief Update type of imported target. 00258 # 00259 # This function is in particular called in basis_set_target_properties() 00260 # if the BASIS_TYPE property of custom BASIS targets is set after the 00261 # imported target was added with the initial type UNKNOWN. 00262 # 00263 # @param [in] TARGET Name (UID) of the imported target. 00264 # @param [in] TYPE Type of imported target. 00265 function (basis_update_imported_type TARGET TYPE) 00266 # get index of imported target 00267 basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS) 00268 list (FIND TARGETS "${TARGET}" IDX) 00269 if (IDX EQUAL -1) 00270 # imported targets have to be added via basis_add_imported_target() first 00271 # otherwise, ignore target here and do not update the non-existent information 00272 return () 00273 endif () 00274 # get current type of imported target 00275 basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES) 00276 list (GET TYPES ${IDX} CURRENT_TYPE) 00277 # bail out if current type shall be kept 00278 if (NOT CURRENT_TYPE MATCHES "^UNKNOWN$") 00279 return () 00280 endif () 00281 # replace current type 00282 list (REMOVE_AT TYPES ${IDX}) 00283 list (LENGTH TYPES N) 00284 if (IDX LESS N) 00285 list (INSERT TYPES ${IDX} ${TYPE}) 00286 else () 00287 list (APPEND TYPES ${TYPE}) 00288 endif () 00289 # update project property 00290 basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}") 00291 endfunction () 00292 00293 00294 ## @} 00295 # end of Doxygen group