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_REGEX}")
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}" STREQUAL "")
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 target was added before
00156 basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
00157 if (TARGETS)
00158 list (FIND TARGETS "${TARGET}" IDX)
00159 if (NOT IDX EQUAL -1)
00160 # do nothing
00161 return ()
00162 endif ()
00163 endif ()
00164 # otherwise, add it to the project properties
00165 basis_set_project_property (APPEND PROPERTY IMPORTED_TARGETS "${TARGET}")
00166 basis_set_project_property (APPEND PROPERTY IMPORTED_TYPES "${TYPE}")
00167 basis_set_project_property (APPEND PROPERTY IMPORTED_LOCATIONS "NOTFOUND")
00168 basis_set_project_property (APPEND PROPERTY IMPORTED_RANKS 10)
00169 endfunction ()
00170
00171 # ----------------------------------------------------------------------------
00172 ## @brief Update location of imported target.
00173 #
00174 # @param [in] TARGET Name (UID) of the imported target.
00175 # @param [in] PROPERTY Target location property. Either IMPORTED_LOCATION
00176 # or IMPORTED_LOCATION_<config>, where <config>
00177 # is one of the imported build configurations.
00178 # This argument is used to decide whether to keep
00179 # the current target information or to replace it
00180 # by the new one.
00181 # @param [in] LOCATION Location of imported target.
00182 function (basis_update_imported_location TARGET PROPERTY LOCATION)
00183 if (BASIS_DEBUG)
00184 message ("** basis_update_imported_location:")
00185 message ("** Target: ${TARGET}")
00186 message ("** Location: ${LOCATION}")
00187 endif ()
00188 # get index of imported target
00189 basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
00190 list (FIND TARGETS "${TARGET}" IDX)
00191 if (IDX EQUAL -1)
00192 # imported targets have to be added via basis_add_imported_target() first
00193 # otherwise, ignore target here and do not update the non-existent information
00194 return ()
00195 endif ()
00196 # get current information of target
00197 basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES)
00198 basis_get_project_property (LOCATIONS PROPERTY IMPORTED_LOCATIONS)
00199 basis_get_project_property (RANKS PROPERTY IMPORTED_RANKS)
00200 list (GET TYPES ${IDX} TYPE)
00201 list (GET RANKS ${IDX} CURRENT_RANK)
00202 # decide whether current information shall be overwritten
00203 if (CMAKE_BUILD_TYPE)
00204 string (TOUPPER "${CMAKE_BUILD_TYPE}" C)
00205 else ()
00206 set (C "NOCONFIG")
00207 endif ()
00208 set (
00209 RANKING
00210 # first pick
00211 "IMPORTED_LOCATION_${C}" # 0) prefer location corresponding to current configuration
00212 "IMPORTED_LOCATION" # 1) then use non-configuration specific location
00213 "IMPORTED_LOCATION_RELEASE" # 2) otherwise use RELEASE version if available
00214 # 3) last pick, use first imported executable
00215 )
00216 list (FIND RANKING "${PROPERTY}" RANK)
00217 if (RANK EQUAL -1)
00218 set (RANK 3)
00219 endif ()
00220 # bail out if current information shall be kept
00221 if (NOT "${RANK}" LESS "${CURRENT_RANK}")
00222 return ()
00223 endif ()
00224 # remove current information
00225 list (REMOVE_AT TYPES ${IDX})
00226 list (REMOVE_AT LOCATIONS ${IDX})
00227 list (REMOVE_AT RANKS ${IDX})
00228 # add imported information
00229 list (LENGTH TYPES N)
00230 if (IDX LESS N)
00231 list (INSERT TYPES ${IDX} "${TYPE}")
00232 list (INSERT LOCATIONS ${IDX} "${LOCATION}")
00233 list (INSERT RANKS ${IDX} "${RANK}")
00234 else ()
00235 list (APPEND TYPES "${TYPE}")
00236 list (APPEND LOCATIONS "${LOCATION}")
00237 list (APPEND RANKS "${RANK}")
00238 endif ()
00239 # update project properties
00240 basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}")
00241 basis_set_project_property (PROPERTY IMPORTED_LOCATIONS "${LOCATIONS}")
00242 basis_set_project_property (PROPERTY IMPORTED_RANKS "${RANKS}")
00243 endfunction ()
00244
00245 # ----------------------------------------------------------------------------
00246 ## @brief Update type of imported target.
00247 #
00248 # This function is in particular called in basis_set_target_properties()
00249 # if the BASIS_TYPE property of custom BASIS targets is set after the
00250 # imported target was added with the initial type UNKNOWN.
00251 #
00252 # @param [in] TARGET Name (UID) of the imported target.
00253 # @param [in] TYPE Type of imported target.
00254 function (basis_update_imported_type TARGET TYPE)
00255 # get index of imported target
00256 basis_get_project_property (TARGETS PROPERTY IMPORTED_TARGETS)
00257 list (FIND TARGETS "${TARGET}" IDX)
00258 if (IDX EQUAL -1)
00259 # imported targets have to be added via basis_add_imported_target() first
00260 # otherwise, ignore target here and do not update the non-existent information
00261 return ()
00262 endif ()
00263 # get current type of imported target
00264 basis_get_project_property (TYPES PROPERTY IMPORTED_TYPES)
00265 list (GET TYPES ${IDX} CURRENT_TYPE)
00266 # bail out if current type shall be kept
00267 if (NOT CURRENT_TYPE MATCHES "^UNKNOWN$")
00268 return ()
00269 endif ()
00270 # replace current type
00271 list (REMOVE_AT TYPES ${IDX})
00272 list (LENGTH TYPES N)
00273 if (IDX LESS N)
00274 list (INSERT TYPES ${IDX} ${TYPE})
00275 else ()
00276 list (APPEND TYPES ${TYPE})
00277 endif ()
00278 # update project property
00279 basis_set_project_property (PROPERTY IMPORTED_TYPES "${TYPES}")
00280 endfunction ()
00281
00282
00283 ## @}
00284 # end of Doxygen group