BASIS  version 1.2.3 (revision 2104)
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_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_&lt;a&gt;, may be preferred
00146 #         over IMPORTED_LOCATION_&lt;b&gt;.
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_&lt;config&gt;, where &lt;config&gt;
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