BASIS  r3148
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_&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 (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_&lt;config&gt;, where &lt;config&gt;
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