BASIS  version 1.2.3 (revision 2104)
TargetTools.cmake
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  TargetTools.cmake
00003 # @brief Functions and macros to add executable and library 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_TARGETTOOLS_INCLUDED)
00014   return ()
00015 else ()
00016   set (__BASIS_TARGETTOOLS_INCLUDED TRUE)
00017 endif ()
00018 
00019 
00020 ## @addtogroup CMakeUtilities
00021 #  @{
00022 
00023 
00024 # ============================================================================
00025 # properties
00026 # ============================================================================
00027 
00028 # ----------------------------------------------------------------------------
00029 ## @brief Set properties on a target.
00030 #
00031 # This function replaces CMake's
00032 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
00033 # set_target_properties()</a> command and extends its functionality.
00034 # In particular, it maps the given target names to the corresponding target UIDs.
00035 #
00036 # @note Due to a bug in CMake (http://www.cmake.org/Bug/view.php?id=12303),
00037 #       except of the first property given directly after the @c PROPERTIES keyword,
00038 #       only properties listed in @c BASIS_PROPERTIES_ON_TARGETS can be set.
00039 #
00040 # @param [in] ARGN List of arguments. See
00041 #                  <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
00042 #                  set_target_properties()</a>.
00043 #
00044 # @returns Sets the specified properties on the given target.
00045 #
00046 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties
00047 #
00048 # @ingroup CMakeAPI
00049 function (basis_set_target_properties)
00050   # convert target names to UIDs
00051   set (TARGET_UIDS)
00052   list (LENGTH ARGN N)
00053   if (N EQUAL 0)
00054     message (FATAL_ERROR "basis_set_target_properties(): Missing arguments!")
00055   endif ()
00056   list (GET ARGN 0 ARG)
00057   while (NOT ARG MATCHES "^PROPERTIES$")
00058     basis_get_target_uid (TARGET_UID "${ARG}")
00059     list (APPEND TARGET_UIDS "${TARGET_UID}")
00060     list (REMOVE_AT ARGN 0)
00061     list (LENGTH ARGN N)
00062     if (N EQUAL 0)
00063       break ()
00064     else ()
00065       list (GET ARGN 0 ARG)
00066     endif ()
00067   endwhile ()
00068   if (NOT ARG MATCHES "^PROPERTIES$")
00069     message (FATAL_ERROR "Missing PROPERTIES argument!")
00070   elseif (NOT TARGET_UIDS)
00071     message (FATAL_ERROR "No target specified!")
00072   endif ()
00073   # remove PROPERTIES keyword
00074   list (REMOVE_AT ARGN 0)
00075   math (EXPR N "${N} - 1")
00076   # set targets properties
00077   #
00078   # Note: By iterating over the properties, the empty property values
00079   #       are correctly passed on to CMake's set_target_properties()
00080   #       command, while
00081   #       _set_target_properties(${TARGET_UIDS} PROPERTIES ${ARGN})
00082   #       (erroneously) discards the empty elements in ARGN.
00083   if (BASIS_DEBUG)
00084     message ("** basis_set_target_properties:")
00085     message ("**   Target(s):  ${TARGET_UIDS}")
00086     message ("**   Properties: [${ARGN}]")
00087   endif ()
00088   while (N GREATER 1)
00089     list (GET ARGN 0 PROPERTY)
00090     list (GET ARGN 1 VALUE)
00091     list (REMOVE_AT ARGN 0 1)
00092     list (LENGTH ARGN N)
00093     # The following loop is only required b/c CMake's ARGV and ARGN
00094     # lists do not support arguments which are themselves lists.
00095     # Therefore, we need a way to decide when the list of values for a
00096     # property is terminated. Hence, we only allow known properties
00097     # to be set, except for the first property where the name follows
00098     # directly after the PROPERTIES keyword.
00099     while (N GREATER 0)
00100       list (GET ARGN 0 ARG)
00101       if (ARG MATCHES "${BASIS_PROPERTIES_ON_TARGETS_REGEX}")
00102         break ()
00103       endif ()
00104       list (APPEND VALUE "${ARG}")
00105       list (REMOVE_AT ARGN 0)
00106       list (LENGTH ARGN N)
00107     endwhile ()
00108     if (BASIS_DEBUG)
00109       message ("**   -> ${PROPERTY} = [${VALUE}]")
00110     endif ()
00111     # check property name
00112     if (PROPERTY MATCHES "^$") # remember: STREQUAL is buggy and evil!
00113       message (FATAL_ERROR "Empty property name given!")
00114     endif ()
00115     # set target property
00116     _set_target_properties (${TARGET_UIDS} PROPERTIES ${PROPERTY} "${VALUE}")
00117   endwhile ()
00118   # make sure that every property had a corresponding value
00119   if (NOT N EQUAL 0)
00120     message (FATAL_ERROR "No value given for target property ${ARGN}")
00121   endif ()
00122 endfunction ()
00123 
00124 # ----------------------------------------------------------------------------
00125 ## @brief Get value of property set on target.
00126 #
00127 # This function replaces CMake's
00128 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_target_properties">
00129 # get_target_properties()</a> command and extends its functionality.
00130 # In particular, it maps the given @p TARGET_NAME to the corresponding target UID.
00131 #
00132 # @param [out] VAR         Name of output variable.
00133 # @param [in]  TARGET_NAME Name of build target.
00134 # @param [in]  ARGN        Remaining arguments for
00135 #                          <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_target_properties">
00136 #                          get_target_properties()</a>.
00137 #
00138 # @returns Sets @p VAR to the value of the requested property.
00139 #
00140 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_target_property
00141 #
00142 # @ingroup CMakeAPI
00143 function (basis_get_target_property VAR TARGET_NAME)
00144   basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
00145   get_target_property (VALUE "${TARGET_UID}" ${ARGN})
00146   set (${VAR} "${VALUE}" PARENT_SCOPE)
00147 endfunction ()
00148 
00149 # ============================================================================
00150 # definitions
00151 # ============================================================================
00152 
00153 # ----------------------------------------------------------------------------
00154 ## @brief Add compile definitions.
00155 #
00156 # This function replaces CMake's
00157 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions">
00158 # add_definitions()</a> command.
00159 #
00160 # @param [in] ARGN List of arguments for
00161 #                  <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions">
00162 #                  add_definitions()</a>.
00163 #
00164 # @returns Adds the given definitions.
00165 #
00166 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_definitions
00167 #
00168 # @ingroup CMakeAPI
00169 function (basis_add_definitions)
00170   add_definitions (${ARGN})
00171 endfunction ()
00172 
00173 # ----------------------------------------------------------------------------
00174 ## @brief Remove previously added compile definitions.
00175 #
00176 # This function replaces CMake's
00177 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definitions">
00178 # remove_definitions()</a> command.
00179 #
00180 # @param [in] ARGN List of arguments for
00181 #                  <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definitions">
00182 #                  remove_definitions()</a>.
00183 #
00184 # @returns Removes the specified definitions.
00185 #
00186 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:remove_definition
00187 #
00188 # @ingroup CMakeAPI
00189 function (basis_remove_definitions)
00190   remove_definitions (${ARGN})
00191 endfunction ()
00192 
00193 # ============================================================================
00194 # directories
00195 # ============================================================================
00196 
00197 # ----------------------------------------------------------------------------
00198 ## @brief Add directories to search path for include files.
00199 #
00200 # Overwrites CMake's
00201 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
00202 # include_directories()</a> command. This is required because the
00203 # basis_include_directories() function is not used by other projects in their
00204 # package use files. Therefore, this macro is an alias for
00205 # basis_include_directories().
00206 #
00207 # @param [in] ARGN List of arguments for basis_include_directories().
00208 #
00209 # @returns Adds the given paths to the search path for include files.
00210 #
00211 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
00212 macro (include_directories)
00213   basis_include_directories (${ARGN})
00214 endmacro ()
00215 
00216 # ----------------------------------------------------------------------------
00217 ## @brief Add directories to search path for include files.
00218 #
00219 # This function replaces CMake's
00220 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
00221 # include_directories()</a> command. Besides invoking CMake's internal command
00222 # with the given arguments, it updates the @c PROJECT_INCLUDE_DIRECTORIES
00223 # property on the current project (see basis_set_project_property()). This list
00224 # contains a list of all include directories used by a project, regardless of
00225 # the directory in which the basis_include_directories() function was used.
00226 #
00227 # @param ARGN List of arguments for
00228 #             <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories">
00229 #             include_directories()</a> command.
00230 #
00231 # @returns Nothing.
00232 #
00233 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
00234 #
00235 # @ingroup CMakeAPI
00236 function (basis_include_directories)
00237   # CMake's include_directories ()
00238   _include_directories (${ARGN})
00239 
00240   # parse arguments
00241   CMAKE_PARSE_ARGUMENTS (ARGN "AFTER;BEFORE;SYSTEM" "" "" ${ARGN})
00242 
00243   # make relative paths absolute
00244   set (DIRS)
00245   foreach (P IN LISTS ARGN_UNPARSED_ARGUMENTS)
00246     get_filename_component (P "${P}" ABSOLUTE)
00247     list (APPEND DIRS "${P}")
00248   endforeach ()
00249 
00250   if (NOT DIRS)
00251     message (WARNING "basis_include_directories(): No directories given to add!")
00252   endif ()
00253 
00254   # append directories to "global" list of include directories
00255   basis_get_project_property (INCLUDE_DIRS PROPERTY PROJECT_INCLUDE_DIRS)
00256   if (BEFORE)
00257     list (INSERT INCLUDE_DIRS 0 ${DIRS})
00258   else ()
00259     list (APPEND INCLUDE_DIRS ${DIRS})
00260   endif ()
00261   if (INCLUDE_DIRS)
00262     list (REMOVE_DUPLICATES INCLUDE_DIRS)
00263   endif ()
00264   if (BASIS_DEBUG)
00265     message ("** basis_include_directories():")
00266     if (BEFORE)
00267       message ("**    Add before:  ${DIRS}")
00268     else ()
00269       message ("**    Add after:   ${DIRS}")
00270     endif ()
00271     if (BASIS_VERBOSE)
00272       message ("**    Directories: ${INCLUDE_DIRS}")
00273     endif ()
00274   endif ()
00275   basis_set_project_property (PROPERTY PROJECT_INCLUDE_DIRS ${INCLUDE_DIRS})
00276 endfunction ()
00277 
00278 # ----------------------------------------------------------------------------
00279 ## @brief Add directories to search path for libraries.
00280 #
00281 # Overwrites CMake's
00282 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
00283 # link_directories()</a> command. This is required because the
00284 # basis_link_directories() function is not used by other projects in their
00285 # package use files. Therefore, this macro is an alias for
00286 # basis_link_directories().
00287 #
00288 # @param [in] ARGN List of arguments for basis_link_directories().
00289 #
00290 # @returns Adds the given paths to the search path for libraries.
00291 #
00292 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories
00293 macro (link_directories)
00294   basis_link_directories (${ARGN})
00295 endmacro ()
00296 
00297 # ----------------------------------------------------------------------------
00298 ## @brief Add directories to search path for libraries.
00299 #
00300 # This function replaces CMake's
00301 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
00302 # link_directories()</a> command. Even though this function yet only invokes
00303 # CMake's internal command, it should be used in BASIS projects to enable the
00304 # extension of this command's functionality as part of BASIS if required.
00305 #
00306 # @param [in] ARGN List of arguments for
00307 #                  <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories">
00308 #                  link_directories()</a>.
00309 #
00310 # @returns Adds the given paths to the search path for libraries.
00311 #
00312 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:link_directories
00313 #
00314 # @ingroup CMakeAPI
00315 function (basis_link_directories)
00316   # CMake's link_directories() command
00317   _link_directories (${ARGN})
00318 endfunction ()
00319 
00320 # ============================================================================
00321 # dependencies
00322 # ============================================================================
00323 
00324 # ----------------------------------------------------------------------------
00325 ## @brief Add dependencies to build target.
00326 #
00327 # This function replaces CMake's
00328 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies">
00329 # add_dependencies()</a> command and extends its functionality.
00330 # In particular, it maps the given target names to the corresponding target UIDs.
00331 #
00332 # @param [in] ARGN Arguments for
00333 #                  <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies">
00334 #                  add_dependencies()</a>.
00335 #
00336 # @returns Adds the given dependencies of the specified build target.
00337 #
00338 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_dependencies
00339 #
00340 # @ingroup CMakeAPI
00341 function (basis_add_dependencies)
00342   set (ARGS)
00343   foreach (ARG ${ARGN})
00344     basis_get_target_uid (UID "${ARG}")
00345     if (TARGET "${UID}")
00346       list (APPEND ARGS "${UID}")
00347     else ()
00348       list (APPEND ARGS "${ARG}")
00349     endif ()
00350   endforeach ()
00351   add_dependencies (${ARGS})
00352 endfunction ()
00353 
00354 # ----------------------------------------------------------------------------
00355 ## @brief Add link dependencies to build target.
00356 #
00357 # This function replaces CMake's
00358 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:target_link_libraries">
00359 # target_link_libraries()</a> command.
00360 #
00361 # The main reason for replacing this function is to treat libraries such as
00362 # MEX-files which are supposed to be compiled into a MATLAB executable added
00363 # by basis_add_executable() special. In this case, these libraries are added
00364 # to the LINK_DEPENDS property of the given MATLAB Compiler target.
00365 #
00366 # Another reason is the mapping of build target names to fully-qualified
00367 # build target names as used by BASIS (see basis_get_target_uid()).
00368 #
00369 # Example:
00370 # @code
00371 # basis_add_library (MyMEXFunc MEX myfunc.c)
00372 # basis_add_executable (MyMATLABApp main.m)
00373 # basis_target_link_libraries (MyMATLABApp MyMEXFunc OtherMEXFunc.mexa64)
00374 # @endcode
00375 #
00376 # @param [in] TARGET_NAME Name of the target.
00377 # @param [in] ARGN        Link libraries.
00378 #
00379 # @returns Adds link dependencies to the specified build target.
00380 #          For custom targets, the given libraries are added to the
00381 #          @c DEPENDS property of these target, in particular.
00382 #
00383 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:target_link_libraries
00384 #
00385 # @ingroup CMakeAPI
00386 function (basis_target_link_libraries TARGET_NAME)
00387   basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
00388 
00389   if (NOT TARGET "${TARGET_UID}")
00390     message (FATAL_ERROR "basis_target_link_libraries(): Unknown target ${TARGET_UID}.")
00391   endif ()
00392 
00393   # get type of named target
00394   get_target_property (BASIS_TYPE ${TARGET_UID} "BASIS_TYPE")
00395 
00396   # substitute non-fully qualified target names
00397   set (ARGS)
00398   foreach (ARG ${ARGN})
00399     basis_get_target_uid (UID "${ARG}")
00400     if (TARGET "${UID}")
00401       list (APPEND ARGS "${UID}")
00402     else ()
00403       list (APPEND ARGS "${ARG}")
00404     endif ()
00405   endforeach ()
00406 
00407   # MATLAB Compiler or MEX target
00408   if (BASIS_TYPE MATCHES "MCC|MEX")
00409     get_target_property (DEPENDS ${TARGET_UID} "LINK_DEPENDS")
00410 
00411     if (NOT DEPENDS)
00412       set (DEPENDS)
00413     endif ()
00414     list (APPEND DEPENDS ${ARGS})
00415  
00416     # pull implicit dependencies (e.g., ITK uses this)
00417     # note that MCC does itself a dependency check
00418     if (NOT BASIS_TYPE MATCHES "MCC")
00419       set (DEPENDENCY_ADDED 1)
00420       while (DEPENDENCY_ADDED)
00421         set (DEPENDENCY_ADDED 0)
00422         foreach (LIB ${DEPENDS})
00423           foreach (LIB_DEPEND ${${LIB}_LIB_DEPENDS})
00424             if (NOT LIB_DEPEND MATCHES "^general$")
00425               string (REGEX REPLACE "^-l" "" LIB_DEPEND "${LIB_DEPEND}")
00426               list (FIND DEPENDS ${LIB_DEPEND} IDX)
00427               if (IDX EQUAL -1)
00428                 list (APPEND DEPENDS ${LIB_DEPEND})
00429                 set (DEPENDENCY_ADDED 1)
00430               endif ()
00431             endif ()
00432           endforeach ()
00433         endforeach ()
00434       endwhile ()
00435     endif ()
00436 
00437     _set_target_properties (${TARGET_UID} PROPERTIES LINK_DEPENDS "${DEPENDS}")
00438   # other
00439   else ()
00440     target_link_libraries (${TARGET_UID} ${ARGS})
00441   endif ()
00442 endfunction ()
00443 
00444 # ============================================================================
00445 # add targets
00446 # ============================================================================
00447 
00448 # ----------------------------------------------------------------------------
00449 ## @brief Add executable target.
00450 #
00451 # This is the main function to add an executable target to the build system,
00452 # where an executable can be a binary file or a script written in a scripting
00453 # language. In general we refer to any output file which is part of the software
00454 # (i.e., excluding configuration files) and which can be executed
00455 # (e.g., a binary file in the ELF format) or interpreted (e.g., a BASH script)
00456 # directly, as executable file. Natively, CMake supports only executables build
00457 # from C/C++ source code files. This function extends CMake's capabilities
00458 # by adding custom build commands for non-natively supported programming
00459 # languages and further standardizes the build of executable targets.
00460 # For example, by default, it is not necessary to specify installation rules
00461 # separately as these are added by this function already (see below).
00462 #
00463 # @par Programming languages
00464 # Besides adding usual executable targets build by the set <tt>C/CXX</tt>
00465 # language compiler, this function inspects the list of source files given and
00466 # detects whether this list contains sources which need to be build using a
00467 # different compiler. In particular, it supports the following languages:
00468 # @n
00469 # <table border="0">
00470 #   <tr>
00471 #     @tp @b CXX @endtp
00472 #     <td>The default behavior, adding an executable target build from C/C++
00473 #         source code. The target is added via CMake's add_executable() command.</td>
00474 #   </tr>
00475 #   <tr>
00476 #     @tp <b>PYTHON</b>|<b>PERL</b>|<b>BASH</b> @endtp
00477 #     <td>Executables written in one of the named scripting languages are built by
00478 #         configuring and/or copying the script files to the build tree and
00479 #         installation tree, respectively. During the build step, certain strings
00480 #         of the form \@VARIABLE\@ are substituted by the values set during the
00481 #         configure step. How these CMake variables are set is specified by a
00482 #         so-called script configuration file, which itself is a CMake script.</td>
00483 #   </tr>
00484 #   <tr>
00485 #     @tp @b MATLAB @endtp
00486 #     <td>Standalone application build from MATLAB sources using the
00487 #         MATLAB Compiler (mcc). This language option is used when the list
00488 #         of source files contains one or more *.m files. A custom target is
00489 #         added which depends on custom command(s) that build the executable.</td>
00490 #         @n@n
00491 #         Attention: The *.m file with the entry point/main function of the
00492 #                    executable has to be given before any other *.m file.
00493 #   </tr>
00494 # </table>
00495 #
00496 # @par Helper functions
00497 # If the programming language of the input source files is not specified
00498 # explicitly by providing the @p LANGUAGE argument, the extensions of the
00499 # source files are inspected using basis_get_source_language(). Once the
00500 # programming language is known, this function invokes the proper subcommand.
00501 # In particular, it calls basis_add_executable_target() for C++ sources (.cxx),
00502 # basis_add_mcc_target() for MATLAB scripts (.m), and basis_add_script() for all
00503 # other source files.
00504 #
00505 # @note DO NOT use the mentioned subcommands directly. Always use
00506 #       basis_add_library() to add a library target to your project. Only refer
00507 #       to the documentation of the subcommands to learn about the available
00508 #       options of the particular subcommand.
00509 #
00510 # @par Output directories
00511 # The built executable file is output to the @c BINARY_RUNTIME_DIR or
00512 # @c BINARY_LIBEXEC_DIR if the @p LIBEXEC option is given.
00513 # If this function is used within the @c PROJECT_TESTING_DIR, however,
00514 # the built executable is output to the @c TESTING_RUNTIME_DIR or
00515 # @c TESTING_LIBEXEC_DIR instead.
00516 #
00517 # @par Installation
00518 # An install command for the added executable target is added by this function
00519 # as well. The executable will be installed as part of the component @p COMPONENT
00520 # in the directory @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR if the option
00521 # @p LIBEXEC is given. Executable targets are exported such that they can be
00522 # imported by other CMake-aware projects by including the CMake configuration file
00523 # of this package (&lt;Package&gt;Config.cmake file). No installation rules are
00524 # added, however, if this function is used within the @c PROJECT_TESTING_DIR.
00525 # Test executables are further only exported as part of the build tree.
00526 #
00527 # @note If this function is used within the @c PROJECT_TESTING_DIR, the built
00528 #       executable is output to the @c TESTING_RUNTIME_DIR or
00529 #       @c TESTING_LIBEXEC_DIR instead. Moreover, no installation rules are added.
00530 #       Test executables are further only exported as part of the build tree.
00531 #
00532 # @param [in] TARGET_NAME Name of the target. If a source file is given
00533 #                         as first argument, the build target name is derived
00534 #                         from the name of this source file.
00535 # @param [in] ARGN        This argument list is parsed and the following
00536 #                         arguments are extracted, all other arguments are passed
00537 #                         on to add_executable() or the respective custom
00538 #                         commands used to build the executable.
00539 # @par
00540 # <table border="0">
00541 #   <tr>
00542 #     @tp @b COMPONENT name @endtp
00543 #     <td>Name of the component. Default: @c BASIS_RUNTIME_COMPONENT.</td>
00544 #   </tr>
00545 #   <tr>
00546 #     @tp @b DESTINATION dir @endtp
00547 #     <td>Installation directory relative to @c INSTALL_PREFIX.
00548 #         If "none" (the case is ignored) is given as argument,
00549 #         no installation rules are added for this executable target.
00550 #         Default: @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR
00551 #                  (if @p LIBEXEC is given).</td>
00552 #   </tr>
00553 #   <tr>
00554 #     @tp @b LANGUAGE lang @endtp
00555 #     <td>Source code language. By default determined from the extensions of
00556 #         the given source files.</td>
00557 #   </tr>
00558 #   <tr>
00559 #     @tp @b LIBEXEC @endtp
00560 #     <td>Specifies that the built executable is an auxiliary executable
00561 #         which is only called by other executables.</td>
00562 #   </tr>
00563 #   <tr>
00564 #     @tp @b NO_BASIS_UTILITIES @endtp
00565 #     <td>Do not add the BASIS C++ utilities as link dependency.</td>
00566 #   </tr>
00567 #   <tr>
00568 #     @tp @b NO_EXPORT @endtp
00569 #     <td>Do not export the target.</td>
00570 #   </tr>
00571 #   <tr>
00572 #     @tp @b WITH_PATH , @b WITH_EXT @endtp
00573 #     <td>See documentation of basis_add_script().</td>
00574 #   </tr>
00575 #   <tr>
00576 #     @tp @b CONFIG , @b CONFIG_FILE @endtp
00577 #     <td>See documentation of basis_add_script().</td>
00578 #   </tr>
00579 # </table>
00580 #
00581 # @returns Adds an executable build target. In case of an executable which is
00582 #          not build from C++ source files, the function basis_add_custom_finalize()
00583 #          has to be invoked to finalize the addition of the custom build target.
00584 #          This is done automatically by the basis_project_impl() macro.
00585 #
00586 # @sa basis_add_executable_target()
00587 # @sa basis_add_script()
00588 # @sa basis_add_mcc_target()
00589 #
00590 # @ingroup CMakeAPI
00591 function (basis_add_executable TARGET_NAME)
00592   # --------------------------------------------------------------------------
00593   # determine language
00594   CMAKE_PARSE_ARGUMENTS (
00595     ARGN
00596       "TEST" # discard deprecated TEST option
00597       "LANGUAGE"
00598       ""
00599     ${ARGN}
00600   )
00601 
00602   if (NOT ARGN_LANGUAGE)
00603 
00604     CMAKE_PARSE_ARGUMENTS (
00605       TMP
00606       "LIBEXEC;MODULE;WITH_PATH;WITH_EXT;NO_BASIS_UTILITIES;NO_EXPORT"
00607       "BINARY_DIRECTORY;DESTINATION;COMPONENT;CONFIG;CONFIG_FILE"
00608       ""
00609       ${ARGN_UNPARSED_ARGUMENTS}
00610     )
00611 
00612     if (NOT TMP_UNPARSED_ARGUMENTS)
00613       set (TMP_UNPARSED_ARGUMENTS "${TARGET_NAME}")
00614     endif ()
00615 
00616     basis_get_source_language (ARGN_LANGUAGE "${TMP_UNPARSED_ARGUMENTS}")
00617     if (ARGN_LANGUAGE MATCHES "AMBIGUOUS|UNKNOWN")
00618       message ("basis_add_executable(${TARGET_NAME}): Given source code files: ${TMP_UNPARSED_ARGUMENTS}")
00619       if (ARGN_LANGUAGE MATCHES "AMBIGUOUS")
00620         message (FATAL_ERROR "basis_add_executable(${TARGET_NAME}): Ambiguous source code files! Try to set LANGUAGE manually and make sure that no unknown option was given.")
00621       elseif (ARGN_LANGUAGE MATCHES "UNKNOWN")
00622         message (FATAL_ERROR "basis_add_executable(${TARGET_NAME}): Unknown source code language! Try to set LANGUAGE manually and make sure that no unknown option was given.")
00623       endif ()
00624     endif ()
00625   endif ()
00626   string (TOUPPER "${ARGN_LANGUAGE}" ARGN_LANGUAGE)
00627 
00628   # --------------------------------------------------------------------------
00629   # C++
00630   if (ARGN_LANGUAGE MATCHES "CXX")
00631 
00632     basis_add_executable_target (${TARGET_NAME} ${ARGN_UNPARSED_ARGUMENTS})
00633 
00634   # --------------------------------------------------------------------------
00635   # MATLAB
00636   elseif (ARGN_LANGUAGE MATCHES "MATLAB")
00637 
00638     basis_add_mcc_target (${TARGET_NAME} ${ARGN_UNPARSED_ARGUMENTS} TYPE EXECUTABLE)
00639 
00640   # --------------------------------------------------------------------------
00641   # scripting language
00642   else ()
00643     CMAKE_PARSE_ARGUMENTS (ARGN "MODULE" "" "" ${ARGN_UNPARSED_ARGUMENTS})
00644     if (ARGN_MODULE)
00645       message (FATAL_ERROR "basis_add_executable(${TARGET_UID}): A MODULE cannot be an executable! Use basis_add_library() instead.")
00646     endif ()
00647     basis_add_script (${TARGET_NAME} ${ARGN_UNPARSED_ARGUMENTS})
00648   endif ()
00649 endfunction ()
00650 
00651 # ----------------------------------------------------------------------------
00652 ## @brief Add library target.
00653 #
00654 # This is the main function to add a library target to the build system, where
00655 # a library can be a binary archive, shared library, a MEX-file or a module
00656 # written in a scripting language. In general we refer to any output file which
00657 # is part of the software (i.e., excluding configuration files), but cannot be
00658 # executed (e.g., a binary file in the ELF format) or interpreted
00659 # (e.g., a BASH script) directly, as library file. Natively, CMake supports only
00660 # libraries build from C/C++ source code files. This function extends CMake's
00661 # capabilities by adding custom build commands for non-natively supported
00662 # programming languages and further standardizes the build of library targets.
00663 # For example, by default, it is not necessary to specify installation rules
00664 # separately as these are added by this function already (see below).
00665 #
00666 # @par Programming languages
00667 # Besides adding usual library targets built from C/C++ source code files,
00668 # this function can also add custom build targets for libraries implemented
00669 # in other programming languages. It therefore tries to detect the programming
00670 # language of the given source code files and delegates the addition of the
00671 # build target to the proper helper functions. It in particular supports the
00672 # following languages:
00673 # @n
00674 # <table border="0">
00675 #   <tr>
00676 #     @tp @b CXX @endtp
00677 #     <td>Source files written in C/C++ are by default built into either
00678 #         @p STATIC, @p SHARED, or @p MODULE libraries. If the @p MEX option
00679 #         is given, however, a MEX-file (a shared library) is build using
00680 #         the MEX script instead of using the default C++ compiler directly.</td>
00681 #   </tr>
00682 #   <tr>
00683 #     @tp <b>PYTHON</b>|<b>PERL</b>|<b>BASH</b> @endtp
00684 #     <td>Modules written in one of the named scripting languages are built similar
00685 #         to executable scripts except that the file name extension is preserved
00686 #         and no executable file permission is set on Unix. These modules are
00687 #         intended for import/inclusion in other modules or executables written
00688 #         in the particular scripting language only.</td>
00689 #   </tr>
00690 #   <tr>
00691 #     @tp @b MATLAB @endtp
00692 #     <td>Shared libraries built from MATLAB sources using the MATLAB Compiler (mcc).
00693 #         This language option is used when the list of source files contains one or
00694 #         more *.m files. A custom target is added which depends on custom command(s)
00695 #         that build the library.</td>
00696 #   </tr>
00697 # </table>
00698 #
00699 # @par Helper functions
00700 # If the programming language of the input source files is not specified
00701 # explicitly by providing the @p LANGUAGE argument, the extensions of the
00702 # source files are inspected using basis_get_source_language(). Once the
00703 # programming language is known, this function invokes the proper subcommand.
00704 # In particular, it calls basis_add_library_target() for C++ sources (.cxx)
00705 # if the target is not a MEX-file target, basis_add_mex_target() for C++ sources
00706 # if the @p MEX option is given, basis_add_mcc_target() for MATLAB scripts (.m),
00707 # and basis_add_script() for all other source files.
00708 #
00709 # @note DO NOT use the mentioned subcommands directly. Always use
00710 #       basis_add_library() to add a library target to your project. Only refer
00711 #       to the documentation of the subcommands to learn about the available
00712 #       options of the particular subcommand.
00713 #
00714 # @par Output directories
00715 # The built libraries are output to the @c BINARY_RUNTIME_DIR, @c BINARY_LIBRARY_DIR,
00716 # and/or @c BINARY_ARCHIVE_DIR. Python modules are output to subdirectories in
00717 # the @c BINARY_PYTHON_LIBRARY_DIR. Perl modules are output to subdirectories in
00718 # the @c BINARY_PERL_LIBRARY_DIR. If this command is used within the
00719 # @c PROJECT_TESTING_DIR, however, the files are output to the
00720 # @c TESTING_RUNTIME_DIR, @c TESTING_LIBRARY_DIR, @c TESTING_ARCHIVE_DIR,
00721 # @c TESTING_PYTHON_LIBRARY_DIR, or @c TESTING_PERL_LIBRARY_DIR instead.
00722 #
00723 # @par Installation
00724 # An install command for the added library target is added by this function
00725 # as well. Runtime libraries are installed as part of the @p RUNTIME_COMPONENT
00726 # to the @p RUNTIME_DESTINATION. Library components are installed as part of
00727 # the @p LIBRARY_COMPONENT to the @p LIBRARY_DESTINATION. Library targets are
00728 # exported such that they can be imported by other CMake-aware projects by
00729 # including the CMake configuration file of this package
00730 # (&lt;Package&gt;Config.cmake file). If this function is used within the
00731 # @c PROJECT_TESTING_DIR, however, no installation rules are added.
00732 # Test library targets are further only exported as part of the build tree.
00733 #
00734 # @par Example
00735 # @code
00736 # basis_add_library (MyLib1 STATIC mylib.cxx)
00737 # basis_add_library (MyLib2 STATIC mylib.cxx COMPONENT dev)
00738 #
00739 # basis_add_library (
00740 #   MyLib3 SHARED mylib.cxx
00741 #   RUNTIME_COMPONENT bin
00742 #   LIBRARY_COMPONENT dev
00743 # )
00744 #
00745 # basis_add_library (MyMex MEX mymex.cxx)
00746 # basis_add_library (PythonModule MyModule.py.in)
00747 # basis_add_library (ShellModule MODULE MyModule.sh.in)
00748 # @endcode
00749 #
00750 # @param [in] TARGET_NAME Name of the target. If a source file is given
00751 #                         as first argument, the build target name is derived
00752 #                         from the name of this source file.
00753 # @param [in] ARGN        This argument list is parsed and the following
00754 #                         arguments are extracted:
00755 # @par
00756 # <table border="0">
00757 #   <tr>
00758 #     @tp @b LANGUAGE lang @endtp
00759 #     <td>Source code language. By default determined from the extensions of
00760 #         the given source code files.</td>
00761 #   </tr>
00762 #   <tr>
00763 #     @tp <b>STATIC</b>|<b>SHARED</b>|<b>MODULE</b>|<b>MEX</b> @endtp
00764 #     <td>Type of the library.</td>
00765 #   </tr>
00766 #   <tr>
00767 #     @tp @b COMPONENT name @endtp
00768 #     <td>Name of the component. Default: @c BASIS_LIBRARY_COMPONENT.</td>
00769 #   </tr>
00770 #   <tr>
00771 #     @tp @b RUNTIME_COMPONENT name @endtp
00772 #     <td>Name of runtime component. Default: @c COMPONENT if specified or
00773 #         @c BASIS_RUNTIME_COMPONENT, otherwise.</td>
00774 #   </tr>
00775 #   <tr>
00776 #     @tp @b LIBRARY_COMPONENT name @endtp
00777 #     <td>Name of library component. Default: @c COMPONENT if specified or
00778 #         @c BASIS_LIBRARY_COMPONENT, otherwise.</td>
00779 #   </tr>
00780 #   <tr>
00781 #     @tp @b NO_EXPORT @endtp
00782 #     <td>Do not export build target.</td>
00783 #   </tr>
00784 # </table>
00785 #
00786 # @returns Adds a library build target. In case of a library not written in C++
00787 #          or MEX-file targets, basis_add_custom_finalize() has to be invoked
00788 #          to finalize the addition of the build target(s). This is done
00789 #          automatically by the basis_project_impl() macro.
00790 #
00791 # @sa basis_add_library_target()
00792 # @sa basis_add_script()
00793 # @sa basis_add_mex_target()
00794 # @sa basis_add_mcc_target()
00795 #
00796 # @ingroup CMakeAPI
00797 function (basis_add_library TARGET_NAME)
00798   # --------------------------------------------------------------------------
00799   # determine language
00800   CMAKE_PARSE_ARGUMENTS (
00801     ARGN
00802       "TEST" # discard deprecated TEST option
00803       "LANGUAGE"
00804       ""
00805     ${ARGN}
00806   )
00807 
00808   if (NOT ARGN_LANGUAGE)
00809 
00810     CMAKE_PARSE_ARGUMENTS (
00811       TMP
00812       "STATIC;SHARED;MODULE;MEX;WITH_PATH;NO_EXPORT"
00813       "BINARY_DIRECTORY;DESTINATION;RUNTIME_DESTINATION;LIBRARY_DESTINATION;COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT;CONFIG;CONFIG_SCRIPT;MFILE"
00814       ""
00815       ${ARGN_UNPARSED_ARGUMENTS}
00816     )
00817 
00818     if (NOT TMP_UNPARSED_ARGUMENTS)
00819       set (TMP_UNPARSED_ARGUMENTS "${TARGET_NAME}")
00820     endif ()
00821 
00822     basis_get_source_language (ARGN_LANGUAGE "${TMP_UNPARSED_ARGUMENTS}")
00823     if (ARGN_LANGUAGE MATCHES "AMBIGUOUS|UNKNOWN")
00824       message ("basis_add_library(${TARGET_NAME}): Given source code files: ${TMP_UNPARSED_ARGUMENTS}")
00825       if (ARGN_LANGUAGE MATCHES "AMBIGUOUS")
00826         message (FATAL_ERROR "basis_add_library(${TARGET_NAME}): Ambiguous source code files! Try to set LANGUAGE manually and make sure that no unknown option was given.")
00827       elseif (ARGN_LANGUAGE MATCHES "UNKNOWN")
00828         message (FATAL_ERROR "basis_add_library(${TARGET_NAME}): Unknown source code language! Try to set LANGUAGE manually and make sure that no unknown option was given.")
00829       endif ()
00830     endif ()
00831   endif ()
00832   string (TOUPPER "${ARGN_LANGUAGE}" ARGN_LANGUAGE)
00833 
00834   # --------------------------------------------------------------------------
00835   # C++
00836   if (ARGN_LANGUAGE MATCHES "CXX")
00837 
00838     CMAKE_PARSE_ARGUMENTS (
00839       ARGN
00840       "MEX"
00841       ""
00842       ""
00843       ${ARGN_UNPARSED_ARGUMENTS}
00844     )
00845 
00846     # MEX-file
00847     if (ARGN_MEX)
00848 
00849       CMAKE_PARSE_ARGUMENTS (
00850         ARGN
00851         ""
00852         "DESTINATION;RUNTIME_DESTINATION;LIBRARY_DESTINATION;COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT"
00853         ""
00854         ${ARGN_UNPARSED_ARGUMENTS}
00855       )
00856 
00857       set (OPTS)
00858       if (ARGN_CXX_DESTINATION)
00859         list (APPEND OPTS "DESTINATION" "${ARGN_DESTINATION}")
00860       elseif (ARGN_RUNTIME_DESTINATION)
00861         list (APPEND OPTS "DESTINATION" "${ARGN_RUNTIME_DESTINATION}")
00862       endif ()
00863       if (ARGN_COMPONENT)
00864         list (APPEND OPTS "COMPONENT" "${ARGN_COMPONENT}")
00865       elseif (ARGN_RUNTIME_COMPONENT)
00866         list (APPEND OPTS "COMPONENT" "${ARGN_RUNTIME_COMPONENT}")
00867       endif ()
00868 
00869       basis_add_mex_target (${TARGET_NAME} ${ARGN_UNPARSED_ARGUMENTS} ${OPTS})
00870 
00871     # library
00872     else ()
00873 
00874       basis_add_library_target (${TARGET_NAME} ${ARGN_UNPARSED_ARGUMENTS})
00875 
00876     endif ()
00877 
00878   # --------------------------------------------------------------------------
00879   # MATLAB
00880   elseif (ARGN_LANGUAGE MATCHES "MATLAB")
00881 
00882     CMAKE_PARSE_ARGUMENTS (
00883       ARGN
00884       "STATIC;SHARED;MODULE;MEX"
00885       ""
00886       ""
00887       ${ARGN_UNPARSED_ARGUMENTS}
00888     )
00889 
00890     if (ARGN_STATIC OR ARGN_MODULE OR ARGN_MEX)
00891       message (FATAL_ERROR "basis_add_library(${TARGET_UID}): Invalid library type! Only shared libraries can be built by the MATLAB Compiler.")
00892     endif ()
00893 
00894     basis_add_mcc_target (${TARGET_NAME} ${ARGN_UNPARSED_ARGUMENTS} TYPE LIBRARY)
00895 
00896   # --------------------------------------------------------------------------
00897   # scripting language
00898   else ()
00899 
00900     CMAKE_PARSE_ARGUMENTS (
00901       ARGN
00902       "STATIC;SHARED;MODULE;MEX"
00903       ""
00904       ""
00905       ${ARGN_UNPARSED_ARGUMENTS}
00906     )
00907 
00908     if (ARGN_STATIC OR ARGN_SHARED OR ARGN_MEX)
00909       message (FATAL_ERROR "basis_add_library(${TARGET_UID}): Invalid library type! Only modules can be built from scripts.")
00910     endif ()
00911 
00912     basis_add_script (${TARGET_NAME} ${ARGN_UNPARSED_ARGUMENTS} MODULE)
00913   endif ()
00914 endfunction ()
00915 
00916 # ============================================================================
00917 # internal helpers
00918 # ============================================================================
00919 
00920 # ----------------------------------------------------------------------------
00921 ## @brief Add executable target.
00922 #
00923 # This BASIS function overwrites CMake's
00924 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_executable">
00925 # add_executable()</a> command in order to store information of imported targets
00926 # which is in particular used to generate the source code of the ExecutableTargetInfo
00927 # modules which are part of the BASIS utilities.
00928 #
00929 # @note Use basis_add_executable() instead where possible!
00930 #
00931 # @param [in] TARGET Name of the target.
00932 # @param [in] ARGN   Further arguments of CMake's add_executable().
00933 #
00934 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_executable
00935 function (add_executable TARGET)
00936   if (ARGC EQUAL 2 AND ARGV1 MATCHES "^IMPORTED$")
00937     _add_executable (${TARGET} IMPORTED)
00938     basis_add_imported_target ("${TARGET}" EXECUTABLE)
00939   else ()
00940     _add_executable (${TARGET} ${ARGN})
00941     basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET}")
00942   endif ()
00943 endfunction ()
00944 
00945 # ----------------------------------------------------------------------------
00946 ## @brief Add library target.
00947 #
00948 # This BASIS function overwrites CMake's
00949 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_library">
00950 # add_library()</a> command in order to store information of imported targets.
00951 #
00952 # @note Use basis_add_library() instead where possible!
00953 #
00954 # @param [in] TARGET Name of the target.
00955 # @param [in] ARGN   Further arguments of CMake's add_library().
00956 #
00957 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_library
00958 function (add_library TARGET)
00959   if (ARGC EQUAL 3 AND ARGV2 MATCHES "^IMPORTED$")
00960     _add_library (${TARGET} "${ARGV1}" IMPORTED)
00961     basis_add_imported_target ("${TARGET}" "${ARGV1}")
00962   else ()
00963     _add_library (${TARGET} ${ARGN})
00964     basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET}")
00965   endif ()
00966 endfunction ()
00967 
00968 # ----------------------------------------------------------------------------
00969 ## @brief Adds an executable target built from C++ source code.
00970 #
00971 # This function adds an executable target for the build of an executable from
00972 # C++ source code files. Refer to the documentation of basis_add_executable()
00973 # for a description of general options for adding an executable target.
00974 #
00975 # By default, the BASIS C++ utilities library is added as link dependency of
00976 # the executable target. If none of the BASIS C++ utilities are used by the
00977 # executable, the option NO_BASIS_UTILITIES can be given. To enable this option
00978 # by default, set the variable @c BASIS_NO_BASIS_UTILITIES to TRUE before the
00979 # basis_add_executable() commands, i.e., best in the Settings.cmake file located
00980 # in the @c PROJECT_CONFIG_DIR. Note, however, that the utilities library is a
00981 # static library and thus the linker would simply not include any of the BASIS
00982 # utilities object code in the final binary executable file if not used.
00983 #
00984 # @note This function should not be used directly. Instead, it is called
00985 #       by basis_add_executable() if the (detected) programming language
00986 #       of the given source code files is @c CXX (i.e., C/C++).
00987 #
00988 # @param [in] TARGET_NAME Name of the target. If a source file is given
00989 #                         as first argument, the build target name is derived
00990 #                         from the name of this source file.
00991 # @param [in] ARGN        This argument list is parsed and the following
00992 #                         arguments are extracted, all other arguments are
00993 #                         considered to be source code files and simply passed
00994 #                         on to CMake's add_executable() command.
00995 # @par
00996 # <table border="0">
00997 #   <tr>
00998 #     @tp @b DESTINATION dir @endtp
00999 #     <td>Installation directory relative to @c INSTALL_PREFIX.
01000 #         If "none" (the case is ignored) is given as argument,
01001 #         no installation rules are added for this executable target.
01002 #         Default: @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR
01003 #                  (if @p LIBEXEC is given).</td>
01004 #   </tr>
01005 #   <tr>
01006 #     @tp @b COMPONENT name @endtp
01007 #     <td>Name of the component. Default: @c BASIS_RUNTIME_COMPONENT.</td>
01008 #   </tr>
01009 #   <tr>
01010 #     @tp @b LIBEXEC @endtp
01011 #     <td>Specifies that the built executable is an auxiliary executable
01012 #         which is only called by other executable.</td>
01013 #   </tr>
01014 #   <tr>
01015 #     @tp @b NO_BASIS_UTILITIES @endtp
01016 #     <td>Do not add the BASIS C++ utilities as link dependency.</td>
01017 #   </tr>
01018 #   <tr>
01019 #     @tp @b NO_EXPORT @endtp
01020 #     <td>Do not export the target.</td>
01021 #   </tr>
01022 # </table>
01023 #
01024 # @returns Adds an executable build target built from C++ sources.
01025 #
01026 # @sa basis_add_executable()
01027 # @sa basis_install()
01028 function (basis_add_executable_target TARGET_NAME)
01029   # parse arguments
01030   CMAKE_PARSE_ARGUMENTS (
01031     ARGN
01032     "LIBEXEC;TEST;BASIS_UTILITIES;NO_BASIS_UTILITIES;NO_EXPORT"
01033     "DESTINATION;COMPONENT"
01034     ""
01035     ${ARGN}
01036   )
01037 
01038   basis_sanitize_for_regex (R "${PROJECT_TESTING_DIR}")
01039   if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${R}")
01040     set (ARGN_TEST TRUE)
01041   else ()
01042     if (ARGN_TEST)
01043       message (FATAL_ERROR "Executable ${TARGET_NAME} cannot have TEST property!"
01044                            "If it is a test executable, put it in ${PROJECT_TESTING_DIR}.")
01045     endif ()
01046     set (ARGN_TEST FALSE)
01047   endif ()
01048 
01049   set (SOURCES ${ARGN_UNPARSED_ARGUMENTS})
01050 
01051   get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
01052   if (NOT SOURCES OR EXISTS "${S}" OR EXISTS "${S}.in")
01053     list (APPEND SOURCES "${TARGET_NAME}")
01054     basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
01055   endif ()
01056 
01057   # check target name
01058   basis_check_target_name (${TARGET_NAME})
01059   basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
01060 
01061   # whether or not to link to BASIS utilities
01062   set (NO_BASIS_UTILITIES "${BASIS_NO_BASIS_UTILITIES}")
01063   if (ARGN_NO_BASIS_UTILITIES)
01064     set (NO_BASIS_UTILITIES TRUE)
01065   endif ()
01066   if (ARGN_BASIS_UTILITIES)
01067     set (NO_BASIS_UTILITIES FALSE)
01068   endif ()
01069 
01070   # component
01071   if (NOT ARGN_COMPONENT)
01072     set (ARGN_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
01073   endif ()
01074 
01075   # installation directory
01076   if (NOT ARGN_DESTINATION)
01077     if (ARGN_LIBEXEC)
01078       set (ARGN_DESTINATION "${INSTALL_LIBEXEC_DIR}")
01079     else ()
01080       set (ARGN_DESTINATION "${INSTALL_RUNTIME_DIR}")
01081     endif ()
01082   endif ()
01083 
01084   if (BASIS_VERBOSE)
01085     message (STATUS "Adding executable ${TARGET_UID}...")
01086   endif ()
01087 
01088   # add standard auxiliary library
01089   if (NOT NO_BASIS_UTILITIES)
01090     if (NOT BASIS_UTILITIES_ENABLED MATCHES "CXX")
01091       message (FATAL_ERROR "Target ${TARGET_UID} makes use of the BASIS C++ utilities"
01092                            " but BASIS was build without C++ utilities enabled."
01093                            " Either specify the option NO_BASIS_UTILITIES or rebuild"
01094                            " BASIS with C++ utilities enabled.")
01095     endif ()
01096     set (BASIS_UTILITIES_TARGET "basis")
01097     if (BASIS_USE_FULLY_QUALIFIED_UIDS)
01098       set (BASIS_UTILITIES_TARGET "${BASIS_PROJECT_NAMESPACE_CMAKE}.${BASIS_UTILITIES_TARGET}")
01099     endif ()
01100     if (NOT TARGET ${BASIS_UTILITIES_TARGET} AND BASIS_UTILITIES_SOURCES)
01101       add_library (${BASIS_UTILITIES_TARGET} STATIC ${BASIS_UTILITIES_SOURCES})
01102       string (REGEX REPLACE "^.*\\." "" OUTPUT_NAME "${BASIS_UTILITIES_TARGET}")
01103 
01104       # define dependency on non-project specific utilities as the order in
01105       # which static libraries are listed on the command-line for the linker
01106       # matters; this will tell CMake to get the order right
01107       target_link_libraries (${BASIS_UTILITIES_TARGET} ${BASIS_UTILITIES_LIBRARY})
01108 
01109       _set_target_properties (
01110         ${BASIS_UTILITIES_TARGET}
01111         PROPERTIES
01112           BASIS_TYPE  "STATIC_LIBRARY"
01113           OUTPUT_NAME "${OUTPUT_NAME}"
01114           # make sure that this library is always output to the 'lib' directory
01115           # even if only test executables use it; see CMakeLists.txt in 'test'
01116           # subdirectory, which (re-)sets the CMAKE_*_OUTPUT_DIRECTORY variables.
01117           ARCHIVE_OUTPUT_DIRECTORY "${BASIS_BINARY_ARCHIVE_DIR}"
01118       )
01119 
01120       install (
01121         TARGETS ${BASIS_UTILITIES_TARGET}
01122         EXPORT  ${BASIS_PROJECT_NAME}
01123         ARCHIVE
01124           DESTINATION "${BASIS_INSTALL_ARCHIVE_DIR}"
01125           COMPONENT   "${BASIS_LIBRARY_COMPONENT}"
01126       )
01127 
01128       if (BASIS_DEBUG)
01129         message ("** Added BASIS utilities library ${BASIS_UTILITIES_TARGET}")
01130       endif ()
01131     endif ()
01132   endif ()
01133 
01134   # configure .in source files
01135   basis_configure_sources (SOURCES ${SOURCES})
01136 
01137   # add executable target
01138   add_executable (${TARGET_UID} ${SOURCES})
01139 
01140   basis_make_target_uid (HEADERS_TARGET headers)
01141   if (TARGET "${HEADERS_TARGET}")
01142     add_dependencies (${TARGET_UID} ${HEADERS_TARGET})
01143   endif ()
01144 
01145   # target properties
01146   _set_target_properties (
01147     ${TARGET_UID}
01148     PROPERTIES
01149       BASIS_TYPE  "EXECUTABLE"
01150       OUTPUT_NAME "${TARGET_NAME}"
01151   )
01152 
01153   if (ARGN_LIBEXEC)
01154     _set_target_properties (
01155       ${TARGET_UID}
01156       PROPERTIES
01157         LIBEXEC             1
01158         COMPILE_DEFINITIONS "LIBEXEC"
01159     )
01160   else ()
01161     _set_target_properties (${TARGET_UID} PROPERTIES LIBEXEC 0)
01162   endif ()
01163   if (ARGN_TEST)
01164     _set_target_properties (${TARGET_UID} PROPERTIES TEST 1)
01165   else ()
01166     _set_target_properties (${TARGET_UID} PROPERTIES TEST 0)
01167   endif ()
01168 
01169   # output directory
01170   if (ARGN_TEST)
01171     if (ARGN_LIBEXEC)
01172       _set_target_properties (
01173         ${TARGET_UID}
01174         PROPERTIES
01175           RUNTIME_OUTPUT_DIRECTORY "${TESTING_LIBEXEC_DIR}"
01176       )
01177     else ()
01178       _set_target_properties (
01179         ${TARGET_UID}
01180         PROPERTIES
01181           RUNTIME_OUTPUT_DIRECTORY "${TESTING_RUNTIME_DIR}"
01182       )
01183     endif ()
01184   elseif (ARGN_LIBEXEC)
01185     _set_target_properties (
01186       ${TARGET_UID}
01187       PROPERTIES
01188         RUNTIME_OUTPUT_DIRECTORY "${BINARY_LIBEXEC_DIR}"
01189     )
01190   else ()
01191     _set_target_properties (
01192       ${TARGET_UID}
01193       PROPERTIES
01194         LIBEXEC 0
01195         RUNTIME_OUTPUT_DIRECTORY "${BINARY_RUNTIME_DIR}"
01196     )
01197   endif ()
01198 
01199   # add default link dependencies
01200   if (NOT ARGN_NO_BASIS_UTILITIES)
01201     # non-project specific utilities build as part of BASIS
01202     basis_target_link_libraries (${TARGET_UID} ${BASIS_UTILITIES_LIBRARY})
01203     # project specific utilities build as part of this project
01204     basis_target_link_libraries (${TARGET_UID} ${BASIS_UTILITIES_TARGET})
01205   endif ()
01206 
01207   # install executable and/or export target
01208   if (ARGN_TEST)
01209 
01210     # TODO install (selected?) tests
01211 
01212     if (NOT ARGN_NO_EXPORT)
01213       basis_set_project_property (APPEND PROPERTY TEST_EXPORT_TARGETS "${TARGET_UID}")
01214     endif ()
01215 
01216   else ()
01217 
01218     if (ARGN_NO_EXPORT)
01219       set (EXPORT_OPT)
01220     else ()
01221       set (EXPORT_OPT "EXPORT" "${PROJECT_NAME}")
01222       basis_set_project_property (APPEND PROPERTY EXPORT_TARGETS "${TARGET_UID}")
01223     endif ()
01224 
01225     install (
01226       TARGETS     ${TARGET_UID} ${EXPORT_OPT}
01227       DESTINATION "${ARGN_DESTINATION}"
01228       COMPONENT   "${ARGN_COMPONENT}"
01229     )
01230 
01231     _set_target_properties (
01232       ${TARGET_UID}
01233       PROPERTIES
01234         RUNTIME_INSTALL_DIRECTORY "${ARGN_DESTINATION}"
01235     )
01236   endif ()
01237 
01238   if (BASIS_VERBOSE)
01239     message (STATUS "Adding executable ${TARGET_UID}... - done")
01240   endif ()
01241 endfunction ()
01242 
01243 # ----------------------------------------------------------------------------
01244 ## @brief Add build target for library built from C++ source code.
01245 #
01246 # This function adds a library target which builds a library from C++ source
01247 # code files. Refer to the documentation of basis_add_library() for a
01248 # description of the general options for adding a library target.
01249 #
01250 # @note This function should not be used directly. Instead, it is called
01251 #       by basis_add_library() if the (detected) programming language
01252 #       of the given source code files is @c CXX (i.e., C/C++) and the
01253 #       option @c MEX is not given.
01254 #
01255 # @param [in] TARGET_NAME Name of the target. If a source file is given
01256 #                         as first argument, the build target name is derived
01257 #                         from the name of this source file.
01258 # @param [in] ARGN        This argument list is parsed and the following
01259 #                         arguments are extracted. All other arguments are
01260 #                         considered to be source code files and simply
01261 #                         passed on to CMake's add_library() command.
01262 # @par
01263 # <table border="0">
01264 #   <tr>
01265 #     @tp <b>STATIC</b>|<b>SHARED</b>|<b>MODULE</b> @endtp
01266 #     <td>Type of the library.</td>
01267 #   </tr>
01268 #   <tr>
01269 #     @tp @b DESTINATION dir @endtp
01270 #     <td>Installation directory for runtime and library component
01271 #         relative to @c INSTALL_PREFIX. See @p RUNTIME_DESTINATION
01272 #         and @p LIBRARY_DESTINATION.</td>
01273 #   </tr>
01274 #   <tr>
01275 #     @tp @b RUNTIME_DESTINATION dir @endtp
01276 #     <td>Installation directory of the runtime component relative to
01277 #         @c INSTALL_PREFIX. If "none" (case ignored) is given as argument,
01278 #         no installation rule for the runtime library is not added.
01279 #         Default: @c INSTALL_LIBRARY_DIR on Unix or @c INSTALL_RUNTIME_DIR
01280 #         on Windows.</td>
01281 #   </tr>
01282 #   <tr>
01283 #     @tp @b LIBRARY_DESTINATION dir @endtp
01284 #     <td>Installation directory of the library component relative to
01285 #         @c INSTALL_PREFIX. If "none" (case ignored) is given as argument,
01286 #         no installation rule for the library component is added.
01287 #         Default: @c INSTALL_ARCHIVE_DIR.</td>
01288 #   </tr>
01289 #   <tr>
01290 #     @tp @b COMPONENT name @endtp
01291 #     <td>Name of the component. Default: @c BASIS_LIBRARY_COMPONENT.</td>
01292 #   </tr>
01293 #   <tr>
01294 #     @tp @b RUNTIME_COMPONENT name @endtp
01295 #     <td>Name of runtime component. Default: @c COMPONENT if specified or
01296 #         @c BASIS_RUNTIME_COMPONENT, otherwise.</td>
01297 #   </tr>
01298 #   <tr>
01299 #     @tp @b LIBRARY_COMPONENT name @endtp
01300 #     <td>Name of library component. Default: @c COMPONENT if specified or
01301 #         @c BASIS_LIBRARY_COMPONENT, otherwise.</td>
01302 #   </tr>
01303 #   <tr>
01304 #     @tp @b NO_EXPORT @endtp
01305 #     <td>Do not export build target.</td>
01306 #   </tr>
01307 # </table>
01308 #
01309 # @returns Adds a library build target.
01310 function (basis_add_library_target TARGET_NAME)
01311   # parse arguments
01312   CMAKE_PARSE_ARGUMENTS (
01313     ARGN
01314       "STATIC;SHARED;MODULE;NO_EXPORT"
01315       "DESTINATION;RUNTIME_DESTINATION;LIBRARY_DESTINATION;COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT"
01316       ""
01317     ${ARGN}
01318   )
01319 
01320   basis_sanitize_for_regex (R "${PROJECT_TESTING_DIR}")
01321   if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${R}")
01322     set (ARGN_TEST TRUE)
01323   else ()
01324     set (ARGN_TEST FALSE)
01325   endif ()
01326 
01327   set (SOURCES ${ARGN_UNPARSED_ARGUMENTS})
01328 
01329   get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
01330   if (NOT SOURCES OR EXISTS "${S}")
01331     list (APPEND SOURCES "${TARGET_NAME}")
01332     basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
01333   endif ()
01334 
01335   # check target name
01336   basis_check_target_name (${TARGET_NAME})
01337   basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
01338 
01339   # library type
01340   if (NOT ARGN_SHARED AND NOT ARGN_STATIC AND NOT ARGN_MODULE)
01341     if (BUILD_SHARED_LIBS)
01342       set (ARGN_SHARED 1)
01343     else ()
01344       set (ARGN_STATIC 1)
01345     endif ()
01346   endif ()
01347 
01348   # installation directories
01349   if (ARGN_DESTINATION)
01350     if (NOT ARGN_STATIC AND NOT ARGN_RUNTIME_DESTINATION)
01351       set (ARGN_RUNTIME_DESTINATION "${ARGN_DESTINATION}")
01352     endif ()
01353     if (NOT ARGN_LIBRARY_DESTINATION)
01354       set (ARGN_LIBRARY_DESTINATION "${ARGN_DESTINATION}")
01355     endif ()
01356   endif ()
01357   if (NOT ARGN_RUNTIME_DESTINATION)
01358     set (ARGN_RUNTIME_DESTINATION "${INSTALL_RUNTIME_DIR}")
01359   endif ()
01360   if (NOT ARGN_LIBRARY_DESTINATION)
01361     set (ARGN_LIBRARY_DESTINATION "${INSTALL_LIBRARY_DIR}")
01362   endif ()
01363 
01364   if (ARGN_STATIC OR ARGN_RUNTIME_DESTINATION MATCHES "^none$|^None$|^NONE$")
01365     set (ARGN_RUNTIME_DESTINATION)
01366   endif ()
01367   if (ARGN_NO_EXPORT OR ARGN_LIBRARY_DESTINATION MATCHES "^none$|^None$|^NONE$")
01368     set (ARGN_LIBRARY_DESTINATION)
01369   endif ()
01370 
01371   # component
01372   if (ARGN_COMPONENT)
01373     if (NOT ARGN_RUNTIME_COMPONENT)
01374       set (ARGN_RUNTIME_COMPONENT "${ARGN_COMPONENT}")
01375     endif ()
01376     if (NOT ARGN_LIBRARY_COMPONENT)
01377       set (ARGN_LIBRARY_COMPONENT "${ARGN_COMPONENT}")
01378     endif ()
01379   endif ()
01380   if (NOT ARGN_RUNTIME_COMPONENT)
01381     set (ARGN_RUNTIME_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
01382   endif ()
01383   if (NOT ARGN_LIBRARY_COMPONENT)
01384     set (ARGN_LIBRARY_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
01385   endif ()
01386 
01387   # status message
01388   if (ARGN_STATIC)
01389     if (BASIS_VERBOSE)
01390       message (STATUS "Adding static library ${TARGET_UID}...")
01391     endif ()
01392     if (TYPE)
01393       message (FATAL_ERROR "More than one library type specified for target ${TARGET_UID}.")
01394     endif ()
01395     set (TYPE "STATIC")
01396   endif ()
01397   if (ARGN_SHARED)
01398     if (BASIS_VERBOSE)
01399       message (STATUS "Adding shared library ${TARGET_UID}...")
01400     endif ()
01401     if (TYPE)
01402       message (FATAL_ERROR "More than one library type specified for target ${TARGET_UID}.")
01403     endif ()
01404     set (TYPE "SHARED")
01405   endif ()
01406   if (ARGN_MODULE)
01407     if (BASIS_VERBOSE)
01408       message (STATUS "Adding module ${TARGET_UID}...")
01409     endif ()
01410     if (TYPE)
01411       message (FATAL_ERROR "More than one library type specified for target ${TARGET_UID}.")
01412     endif ()
01413     set (TYPE "MODULE")
01414   endif ()
01415 
01416   # configure .in source files
01417   basis_configure_sources (SOURCES ${SOURCES})
01418 
01419   # add library target
01420   add_library (${TARGET_UID} ${TYPE} ${SOURCES})
01421 
01422   basis_make_target_uid (HEADERS_TARGET headers)
01423   if (TARGET ${HEADERS_TARGET})
01424     add_dependencies (${TARGET_UID} ${HEADERS_TARGET})
01425   endif ()
01426 
01427   _set_target_properties (
01428     ${TARGET_UID}
01429     PROPERTIES
01430       BASIS_TYPE "${TYPE}_LIBRARY"
01431       OUTPUT_NAME "${TARGET_NAME}"
01432   )
01433 
01434   # output directory
01435   if (ARGN_TEST)
01436     _set_target_properties (
01437       ${TARGET_UID}
01438       PROPERTIES
01439         RUNTIME_OUTPUT_DIRECTORY "${TESTING_RUNTIME_DIR}"
01440         LIBRARY_OUTPUT_DIRECTORY "${TESTING_LIBRARY_DIR}"
01441         ARCHIVE_OUTPUT_DIRECTORY "${TESTING_ARCHIVE_DIR}"
01442     )
01443   else ()
01444     _set_target_properties (
01445       ${TARGET_UID}
01446       PROPERTIES
01447         RUNTIME_OUTPUT_DIRECTORY "${BINARY_RUNTIME_DIR}"
01448         LIBRARY_OUTPUT_DIRECTORY "${BINARY_LIBRARY_DIR}"
01449         ARCHIVE_OUTPUT_DIRECTORY "${BINARY_ARCHIVE_DIR}"
01450     )
01451   endif ()
01452 
01453   # target version information
01454   #
01455   # Note:      On UNIX-based systems this only creates annoying files with the
01456   #            version string as suffix.
01457   # Attention: MEX-files may NEVER have a suffix after the MEX extension!
01458   #            Otherwise, the MATLAB Compiler when using the symbolic link
01459   #            without this suffix will create code that fails on runtime
01460   #            with an .auth file missing error.
01461   #
01462   # Thus, do NOT set VERSION and SOVERSION properties.
01463 
01464   # install library
01465   if (ARGN_TEST)
01466     # TODO At the moment, no tests are installed. Once there is a way to
01467     #      install selected tests, the shared libraries they depend on
01468     #      need to be installed as well.
01469 
01470     if (NOT ARGN_NO_EXPORT)
01471       basis_set_project_property (APPEND PROPERTY TEST_EXPORT_TARGETS "${TARGET_UID}")
01472     endif ()
01473   else ()
01474     if (ARGN_NO_EXPORT)
01475       set (EXPORT_OPT)
01476     else ()
01477       set (EXPORT_OPT "EXPORT" "${PROJECT_NAME}")
01478       basis_set_project_property (APPEND PROPERTY EXPORT_TARGETS "${TARGET_UID}")
01479     endif ()
01480 
01481     if (ARGN_RUNTIME_DESTINATION)
01482       install (
01483         TARGETS ${TARGET_UID} ${EXPORT_OPT}
01484         RUNTIME
01485           DESTINATION "${ARGN_RUNTIME_DESTINATION}"
01486           COMPONENT   "${ARGN_RUNTIME_COMPONENT}"
01487       )
01488     endif ()
01489 
01490     if (ARGN_LIBRARY_DESTINATION)
01491       install (
01492         TARGETS ${TARGET_UID} ${EXPORT_OPT}
01493         LIBRARY
01494           DESTINATION "${ARGN_LIBRARY_DESTINATION}"
01495           COMPONENT   "${ARGN_LIBRARY_COMPONENT}"
01496         ARCHIVE
01497           DESTINATION "${ARGN_LIBRARY_DESTINATION}"
01498           COMPONENT   "${ARGN_LIBRARY_COMPONENT}"
01499       )
01500     endif ()
01501   endif ()
01502 
01503   # done
01504   if (BASIS_VERBOSE)
01505     if (ARGN_STATIC)
01506       message (STATUS "Adding static library ${TARGET_UID}... - done")
01507     elseif (ARGN_SHARED)
01508       message (STATUS "Adding shared library ${TARGET_UID}... - done")
01509     elseif (ARGN_MODULE)
01510       message (STATUS "Adding module ${TARGET_UID}... - done")
01511     endif ()
01512   endif ()
01513 endfunction ()
01514 
01515 # ----------------------------------------------------------------------------
01516 ## @brief Add script target.
01517 #
01518 # If the script name ends in ".in", the ".in" suffix is removed from the
01519 # output name. Further, the extension of the script such as .sh or .py is
01520 # removed from the output filename of executable scripts. On Unix, a shebang
01521 # directive is added to executable scripts at the top of the script files
01522 # instead if such directive is not given yet. In order to enable the convenient
01523 # execution of Python and Perl scripts on Windows as well, some Batch code
01524 # is added at the top and bottom of executable Python and Perl scripts which
01525 # calls the Python or Perl interpreter with the script file and the given
01526 # script arguments as command-line arguments. The file name extension of
01527 # such modified scripts is by default set to <tt>.cmd</tt>, the common
01528 # extension for Windows NT Command Scripts. Scripts in other languages are
01529 # not specifically modified. In case of script modules, the script file name
01530 # extension is preserved in any case. When the @c WITH_EXT option is given,
01531 # executable scripts are not modified as described and their file name
01532 # extension is preserved.
01533 #
01534 # Example:
01535 # @code
01536 # basis_add_script (MyShellScript.sh.in)
01537 # basis_add_script (Script Script1.sh)
01538 # @endcode
01539 #
01540 # Certain CMake variables within the script are replaced during the configure step.
01541 # See @ref ScriptTargets for details.
01542 #
01543 # Note that this function only configures the script file if it ends in the ".in"
01544 # suffix and adds a custom target which stores all information required to setup
01545 # the actual custom build command as properties. The custom build command itself
01546 # is added by basis_add_script_finalize(), which is supposed to be called once at
01547 # the end of the root CMakeLists.txt file. This way properties such as the
01548 # @c OUTPUT_NAME can still be modified after adding the script target.
01549 #
01550 # @note If this function is used within the @c PROJECT_TESTING_DIR, the built
01551 #       executable is output to the @c BINARY_TESTING_DIR directory tree instead.
01552 #       Moreover, no installation rules are added. Test executables are further
01553 #       not exported, regardless of whether NO_EXPORT is given or not.
01554 #
01555 # @note This function should not be used directly. Instead, the functions
01556 #       basis_add_executable() and basis_add_library() should be used which in
01557 #       turn make use of this function if the (detected) programming language
01558 #       is a (supported) scripting language.
01559 #
01560 # @param [in] TARGET_NAME Name of the target. If the target is build from a
01561 #                         single source file, the file path of this source file
01562 #                         can be given as first argument. The build target name
01563 #                         is then derived from the name of the source file.
01564 # @param [in] ARGN        This argument list is parsed and the following
01565 #                         arguments are extracted:
01566 # @par
01567 # <table border="0">
01568 #   <tr>
01569 #      @tp @b COMPONENT name @endtp
01570 #      <td>Name of the component. Default: @c BASIS_RUNTIME_COMPONENT for
01571 #          executable scripts or @c BASIS_LIBRARY_COMPONENT for modules.</td>
01572 #   </tr>
01573 #   <tr>
01574 #      @tp @b CONFIG config @endtp
01575 #      <td>Additional script configuration given directly as string argument.
01576 #          This string is included in the CMake build script before configuring
01577 #          the script file after the script configuration files have been included.</td>
01578 #   </tr>
01579 #   <tr>
01580 #      @tp @b CONFIG_FILE file @endtp
01581 #      <td>Additional script configuration file. This file is included after
01582 #          the default script configuration file of BASIS and after the default
01583 #          script configuration file which is located in @c PROJECT_BINARY_DIR,
01584 #          but before the script configuration code given by @p CONFIG.</td>
01585 #   </tr>
01586 #   <tr>
01587 #      @tp @b DESTINATION dir @endtp
01588 #      <td>The installation directory relative to @c INSTALL_PREFIX.
01589 #          Default: @c INSTALL_RUNTIME_DIR or @c INSTALL_LIBEXEC_DIR if
01590 #                   the @p LIBEXEC option is given or @c INSTALL_LIBRARY_DIR
01591 #                   if the @p MODULE option is given.</td>
01592 #   </tr>
01593 #   <tr>
01594 #     @tp @b LIBEXEC @endtp
01595 #     <td>Specifies that the built executable is an auxiliary executable
01596 #         which is only called by other executable.</td>
01597 #   </tr>
01598 #   <tr>
01599 #      @tp @b MODULE @endtp
01600 #      <td>Specifies that the script is a module file which is included by
01601 #          other scripts. Implies @p LIBEXEC regarding installation directory and
01602 #          preserves file name extension on all platforms. It can be used,
01603 #          for example, for Python modules that are to be imported only by other
01604 #          Python scripts.
01605 #
01606 #          Note that this option can also be used for arbitrary text files
01607 #          which are used as input to a program, not only actual modules written
01608 #          in a scripting language.</td>
01609 #   </tr>
01610 #   <tr>
01611 #     @tp @b WITH_PATH @endtp
01612 #     <td>Preserve relative path of module. Required for example for
01613 #         Python and Perl packages where the directory hierarchy is important.</td>
01614 #   </tr>
01615 #   <tr>
01616 #     @tp @b WITH_EXT @endtp
01617 #     <td>Specify that the existing filename extension should be kept also
01618 #         in case of an executable script. No shebang directive is added to
01619 #         the top of the script automatically if this option is given.
01620 #         On Windows, on the other side, this prevents the addition of Batch
01621 #         code to execute the script and no <tt>.cmd</tt> file name extension
01622 #         is used for executable scripts build with this option.</td>
01623 #   </tr>
01624 #   <tr>
01625 #     @tp @b NO_EXPORT @endtp
01626 #     <td>Do not export build target.</td>
01627 #   </tr>
01628 #   <tr>
01629 #     @tp @b COMPILE | @b NOCOMPILE @endtp
01630 #     <td>Enable/disable compilation of script if supported by scripting
01631 #         language as well as BASIS. In particular, Python modules can be
01632 #         compiled. If a script could be compiled by BASIS, only the
01633 #         compiled file is installed. Default: @c BASIS_COMPILE_SCRIPTS</td>
01634 #   </tr>
01635 # </table>
01636 #
01637 # @returns Adds custom build target @p TARGET_NAME. In order to add the
01638 #          custom target that actually builds the script file,
01639 #          basis_add_script_finalize() has to be invoked.
01640 #
01641 # @sa basis_add_executable()
01642 # @sa basis_add_library()
01643 # @sa basis_add_script_finalize()
01644 # @sa basis_add_custom_finalize()
01645 function (basis_add_script TARGET_NAME)
01646   # parse arguments
01647   CMAKE_PARSE_ARGUMENTS (
01648     ARGN
01649       "LIBEXEC;TEST;MODULE;WITH_PATH;WITH_EXT;NO_EXPORT;COMPILE;NOCOMPILE"
01650       "BINARY_DIRECTORY;CONFIG;CONFIG_FILE;COMPONENT;DESTINATION"
01651       ""
01652     ${ARGN}
01653   )
01654 
01655   basis_sanitize_for_regex (R "${PROJECT_TESTING_DIR}")
01656   if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${R}")
01657     set (ARGN_TEST TRUE)
01658   else ()
01659     if (ARGN_TEST)
01660       message (FATAL_ERROR "Executable ${TARGET_NAME} cannot have TEST property!"
01661                            "If it is a test executable, put it in ${PROJECT_TESTING_DIR}.")
01662     endif ()
01663     set (ARGN_TEST FALSE)
01664   endif ()
01665 
01666   if (ARGN_COMPILE)
01667     set (COMPILE TRUE)
01668   elseif (ARGN_NOCOMPILE)
01669     set (COMPILE FALSE)
01670   else ()
01671     set (COMPILE "${BASIS_COMPILE_SCRIPTS}")
01672   endif ()
01673 
01674   if (ARGN_TEST)
01675     set (ARGN_NO_EXPORT TRUE)
01676   endif ()
01677   if (NOT ARGN_NO_EXPORT)
01678     set (ARGN_NO_EXPORT FALSE)
01679   endif ()
01680 
01681   if (NOT ARGN_COMPONENT)
01682     if (ARGN_MODULE)
01683       set (ARGN_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
01684     else ()
01685       set (ARGN_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
01686     endif ()
01687   endif ()
01688   if (NOT ARGN_COMPONENT)
01689     set (ARGN_COMPONENT "Unspecified")
01690   endif ()
01691 
01692   # get script file and script name
01693   list (LENGTH ARGN_UNPARSED_ARGUMENTS LEN)
01694   if (LEN EQUAL 0)
01695     set (ARGN_SCRIPT)
01696   elseif (LEN EQUAL 1)
01697     list (GET ARGN_UNPARSED_ARGUMENTS 0 ARGN_SCRIPT)
01698   else ()
01699     message (FATAL_ERROR "basis_add_script(${TARGET_UID}): Too many arguments! Only one script can be built by a script target.")
01700   endif ()
01701   if (NOT ARGN_SCRIPT)
01702     set (ARGN_SCRIPT "${TARGET_NAME}")
01703     set (TARGET_NAME) # set below from ARGN_SCRIPT
01704   endif ()
01705   get_filename_component (ARGN_SCRIPT "${ARGN_SCRIPT}" ABSOLUTE)
01706   if (NOT EXISTS "${ARGN_SCRIPT}")
01707     set (ARGN_SCRIPT "${ARGN_SCRIPT}.in")
01708   endif ()
01709   if (NOT EXISTS "${ARGN_SCRIPT}")
01710     string (REGEX REPLACE "\\.in$" "" ARGN_SCRIPT "${ARGN_SCRIPT}")
01711     message (FATAL_ERROR "basis_add_script(): Missing script file ${ARGN_SCRIPT}[.in]!")
01712   endif ()
01713   get_filename_component (SCRIPT_NAME "${ARGN_SCRIPT}" NAME)
01714   string (REGEX REPLACE "\\.in$" "" SCRIPT_NAME "${SCRIPT_NAME}")
01715   get_filename_component (SCRIPT_NAME_WE "${SCRIPT_NAME}" NAME_WE)
01716   get_filename_component (SCRIPT_EXT "${SCRIPT_NAME}" EXT)
01717 
01718   # determine path part which is optionally prepended to the binary directory
01719   if (ARGN_WITH_PATH)
01720     get_filename_component (SCRIPT_PATH "${ARGN_SCRIPT}" PATH)
01721     if (IS_ABSOLUTE "${SCRIPT_PATH}")
01722       if (SCRIPT_PATH MATCHES "^${PROJECT_SOURCE_DIR}")
01723         basis_get_relative_path (SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}" "${SCRIPT_PATH}")
01724       else ()
01725         set (SCRIPT_PATH)
01726       endif ()
01727     endif ()
01728   endif ()
01729 
01730   # get script language
01731   basis_get_source_language (SCRIPT_LANGUAGE "${ARGN_SCRIPT}")
01732 
01733   # set output name and target name (if not set yet)
01734   set (OUTPUT_PREFIX "")
01735   set (OUTPUT_NAME   "")
01736   set (OUTPUT_SUFFIX "")
01737   if (TARGET_NAME)
01738     set (OUTPUT_NAME "${TARGET_NAME}")
01739   else ()
01740     set (OUTPUT_NAME "${SCRIPT_NAME_WE}")
01741     if (ARGN_MODULE)
01742       basis_get_source_target_name (TARGET_NAME "${SCRIPT_NAME}" NAME)
01743     else ()
01744       basis_get_source_target_name (TARGET_NAME "${SCRIPT_NAME}" NAME_WE)
01745     endif ()
01746   endif ()
01747   # use output name extension for modules,
01748   # for executables also on Windows, and if WITH_EXT option is given
01749   if (ARGN_MODULE OR ARGN_WITH_EXT)
01750     set (OUTPUT_SUFFIX "${SCRIPT_EXT}")
01751   elseif (WIN32)
01752     if (SCRIPT_LANGUAGE MATCHES "PYTHON|PERL")
01753       set (OUTPUT_SUFFIX ".cmd")
01754     else ()
01755       set (OUTPUT_SUFFIX "${SCRIPT_EXT}")
01756     endif ()
01757   endif ()
01758   # SUFFIX and PREFIX used by CMake only for libraries
01759   if (NOT ARGN_MODULE)
01760     set (OUTPUT_NAME "${OUTPUT_PREFIX}${OUTPUT_NAME}${OUTPUT_SUFFIX}")
01761     set (OUTPUT_PREFIX "")
01762     set (OUTPUT_SUFFIX "")
01763   endif ()
01764   # check target name
01765   basis_check_target_name ("${TARGET_NAME}")
01766   basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
01767 
01768   if (BASIS_VERBOSE)
01769     if (ARGN_MODULE)
01770       message (STATUS "Adding module script ${TARGET_UID}...")
01771     else ()
01772       message (STATUS "Adding executable script ${TARGET_UID}...")
01773     endif ()
01774   endif ()
01775 
01776   if (ARGN_MODULE AND ARGN_LIBEXEC)
01777     message (FATAL_ERROR "basis_add_script(${TARGET_UID}): Script cannot be MODULE and LIBEXEC at the same time!")
01778   endif ()
01779 
01780   # directory for build system files
01781   set (BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}.dir")
01782 
01783   # dump CMake variables for "build" of script
01784   basis_dump_variables ("${BUILD_DIR}/variables.cmake")
01785 
01786   # "parse" script to check if BASIS utilities are used and hence required
01787   file (READ "${ARGN_SCRIPT}" SCRIPT)
01788   if (SCRIPT MATCHES "@BASIS_([A-Z]+)_UTILITIES@")
01789     if (BASIS_DEBUG)
01790       message ("** Target ${TARGET_UID} uses BASIS ${CMAKE_MATCH_1} utilities.")
01791     endif ()
01792     basis_set_project_property (PROPERTY PROJECT_USES_${CMAKE_MATCH_1}_UTILITIES TRUE)
01793   endif ()
01794   set (SCRIPT)
01795 
01796   # binary directory
01797   if (ARGN_BINARY_DIRECTORY)
01798     set (BINARY_DIRECTORY "${ARGN_BINARY_DIRECTORY}")
01799   else ()
01800     set (BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
01801   endif ()
01802 
01803   # output directory
01804   if (ARGN_TEST)
01805     if (ARGN_MODULE)
01806       if (SCRIPT_LANGUAGE MATCHES "PYTHON")
01807         set (OUTPUT_DIRECTORY "${TESTING_PYTHON_LIBRARY_DIR}/sbia/${PROJECT_NAME_LOWER}")
01808       elseif (SCRIPT_LANGUAGE MATCHES "PERL")
01809         set (OUTPUT_DIRECTORY "${TESTING_PERL_LIBRARY_DIR}/SBIA/${PROJECT_NAME}")
01810       else ()
01811         set (OUTPUT_DIRECTORY "${TESTING_LIBRARY_DIR}")
01812       endif ()
01813     elseif (ARGN_LIBEXEC)
01814       set (OUTPUT_DIRECTORY "${TESTING_LIBEXEC_DIR}")
01815     else ()
01816       set (OUTPUT_DIRECTORY "${TESTING_RUNTIME_DIR}")
01817     endif ()
01818   elseif (ARGN_MODULE)
01819     if (SCRIPT_LANGUAGE MATCHES "PYTHON")
01820       set (OUTPUT_DIRECTORY "${BINARY_PYTHON_LIBRARY_DIR}/sbia/${PROJECT_NAME_LOWER}")
01821     elseif (SCRIPT_LANGUAGE MATCHES "PERL")
01822       set (OUTPUT_DIRECTORY "${BINARY_PERL_LIBRARY_DIR}/SBIA/${PROJECT_NAME}")
01823     else ()
01824       set (OUTPUT_DIRECTORY "${BINARY_LIBRARY_DIR}")
01825     endif ()
01826   elseif (ARGN_LIBEXEC)
01827     set (OUTPUT_DIRECTORY "${BINARY_LIBEXEC_DIR}")
01828   else ()
01829     set (OUTPUT_DIRECTORY "${BINARY_RUNTIME_DIR}")
01830   endif ()
01831   if (SCRIPT_PATH AND ARGN_WITH_PATH)
01832     set (OUTPUT_DIRECTORY "${OUTPUT_DIRECTORY}/${SCRIPT_PATH}")
01833   endif ()
01834 
01835   # installation directory
01836   if (ARGN_DESTINATION)
01837     if (IS_ABSOLUTE "${ARGN_DESTINATION}")
01838       file (RELATIVE_PATH ARGN_DESTINATION "${INSTALL_PREFIX}" "${ARGN_DESTINATION}")
01839     endif ()
01840   else ()
01841     if (ARGN_TEST)
01842       set (ARGN_DESTINATION)
01843     elseif (ARGN_MODULE)
01844       if (SCRIPT_LANGUAGE MATCHES "^PYTHON$")
01845         set (ARGN_DESTINATION "${INSTALL_PYTHON_LIBRARY_DIR}/sbia/${PROJECT_NAME_LOWER}")
01846       elseif (SCRIPT_LANGUAGE MATCHES "^PERL$")
01847         set (ARGN_DESTINATION "${INSTALL_PERL_LIBRARY_DIR}/SBIA/${PROJECT_NAME}")
01848       else ()
01849         set (ARGN_DESTINATION "${INSTALL_LIBRARY_DIR}")
01850       endif ()
01851     elseif (ARGN_LIBEXEC)
01852       set (ARGN_DESTINATION "${INSTALL_LIBEXEC_DIR}")
01853     else ()
01854       set (ARGN_DESTINATION "${INSTALL_RUNTIME_DIR}")
01855     endif ()
01856     if (ARGN_DESTINATION AND SCRIPT_PATH AND ARGN_WITH_PATH)
01857       set (ARGN_DESTINATION "${ARGN_DESTINATION}/${SCRIPT_PATH}")
01858     endif ()
01859   endif ()
01860 
01861   # script configuration (only if script file name ends in ".in")
01862   set (INSTALL_DIR "${ARGN_DESTINATION}")
01863 
01864   if (ARGN_SCRIPT MATCHES "\\.in$")
01865     # reference to BASIS doxygen page documenting the script configuration
01866     if (PROJECT_NAME MATCHES "^BASIS$")
01867       set (BuildOfScriptTargetsPageRef "@ref BuildOfScriptTargets")
01868     else ()
01869       set (BuildOfScriptTargetsPageRef "Build of Script Targets")
01870     endif ()
01871     # Configure script configuration files using configure_file()
01872     # to have CMake create build rules to update the configured
01873     # file if the script configuration was modified.
01874     # The configured files are included by the build script that is
01875     # generated by basis_add_script_finalize().
01876     configure_file ("${BASIS_SCRIPT_CONFIG_FILE}" "${BINARY_CONFIG_DIR}/BasisScriptConfig.cmake" @ONLY)
01877     if (EXISTS "${PROJECT_CONFIG_DIR}/ScriptConfig.cmake.in")
01878       configure_file ("${PROJECT_CONFIG_DIR}/ScriptConfig.cmake.in" "${BINARY_CONFIG_DIR}/ScriptConfig.cmake" @ONLY)
01879     endif ()
01880     if (ARGN_CONFIG_FILE)
01881       if (NOT EXISTS "${ARGN_CONFIG_FILE}")
01882         message (FATAL_ERROR "Script configuration file \"${ARGN_CONFIG_FILE}\" does not exist. It is required to build the script ${TARGET_UID}.")
01883       endif ()
01884       configure_file ("${ARGN_CONFIG_FILE}" "${BUILD_DIR}/ScriptConfig.cmake" @ONLY)
01885     endif ()
01886     # configure script configuration given as string
01887     if (ARGN_CONFIG)
01888       string (CONFIGURE ARGN_CONFIG "${ARGN_CONFIG}" @ONLY)
01889     endif ()
01890   elseif (ARGN_CONFIG OR ARGN_CONFIG_FILE)
01891     message (WARNING "Provided script configuration for ${TARGET_UID} but the script file "
01892                      "is missing a .in suffix. Will ignore script configuration and just "
01893                      "copy the script file as is without configuring it.")
01894     set (ARGN_CONFIG)
01895     set (ARGN_CONFIG_FILE)
01896   endif ()
01897 
01898   # add custom target
01899   add_custom_target (${TARGET_UID} ALL SOURCES ${ARGN_SCRIPT})
01900 
01901   # set target properties required by basis_add_script_finalize ()
01902   if (ARGN_MODULE)
01903     set (TYPE "MODULE_SCRIPT")
01904   else ()
01905     set (TYPE "EXECUTABLE_SCRIPT")
01906   endif ()
01907 
01908   _set_target_properties (
01909     ${TARGET_UID}
01910     PROPERTIES
01911       BASIS_TYPE                "${TYPE}"
01912       BASIS_LANGUAGE            "${SCRIPT_LANGUAGE}"
01913       SOURCE_DIRECTORY          "${CMAKE_CURRENT_SOURCE_DIR}"
01914       BINARY_DIRECTORY          "${BINARY_DIRECTORY}"
01915       RUNTIME_OUTPUT_DIRECTORY  "${OUTPUT_DIRECTORY}"
01916       LIBRARY_OUTPUT_DIRECTORY  "${OUTPUT_DIRECTORY}"
01917       RUNTIME_INSTALL_DIRECTORY "${ARGN_DESTINATION}"
01918       LIBRARY_INSTALL_DIRECTORY "${ARGN_DESTINATION}"
01919       OUTPUT_NAME               "${OUTPUT_NAME}"
01920       PREFIX                    "${OUTPUT_PREFIX}"
01921       SUFFIX                    "${OUTPUT_SUFFIX}"
01922       COMPILE_DEFINITIONS       "${ARGN_CONFIG}"
01923       LINK_DEPENDS              "${ARGN_CONFIG_FILE}"
01924       RUNTIME_COMPONENT         "${ARGN_COMPONENT}"
01925       LIBRARY_COMPONENT         "${ARGN_COMPONENT}"
01926       NO_EXPORT                 "${ARGN_NO_EXPORT}"
01927       COMPILE                   "${COMPILE}"
01928       WITH_EXT                  "${ARGN_WITH_EXT}"
01929   )
01930 
01931   if (ARGN_TEST)
01932     _set_target_properties (${TARGET_UID} PROPERTIES TEST 1)
01933   else ()
01934     _set_target_properties (${TARGET_UID} PROPERTIES TEST 0)
01935   endif ()
01936 
01937   if (ARGN_LIBEXEC)
01938     _set_target_properties (${TARGET_UID} PROPERTIES LIBEXEC 1)
01939   else ()
01940     _set_target_properties (${TARGET_UID} PROPERTIES LIBEXEC 0)
01941   endif ()
01942 
01943   # add target to list of targets
01944   basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
01945 
01946   if (BASIS_VERBOSE)
01947     if (ARGN_MODULE)
01948       message (STATUS "Adding module script ${TARGET_UID}... - done")
01949     else ()
01950       message (STATUS "Adding executable script ${TARGET_UID}... - done")
01951     endif ()
01952   endif ()
01953 endfunction ()
01954 
01955 # ----------------------------------------------------------------------------
01956 ## @brief Finalize addition of script.
01957 #
01958 # This function uses the properties of the custom script target added by
01959 # basis_add_script() to create the custom build command and adds this build
01960 # command as dependency of this added target.
01961 #
01962 # @param [in] TARGET_UID "Global" target name. If this function is used
01963 #                        within the same project as basis_add_script(),
01964 #                        the "local" target name may be given alternatively.
01965 #
01966 # @returns Adds custom target(s) to actually build the script target
01967 #          @p TARGET_UID added by basis_add_script().
01968 #
01969 # @sa basis_add_script()
01970 # @sa basis_add_custom_finalize()
01971 function (basis_add_script_finalize TARGET_UID)
01972   # if used within (sub-)project itself, allow user to specify "local" target name
01973   basis_get_target_uid (TARGET_UID "${TARGET_UID}")
01974 
01975   # already finalized before ?
01976   if (TARGET "_${TARGET_UID}")
01977     return ()
01978   endif ()
01979 
01980   # does this target exist ?
01981   if (NOT TARGET "${TARGET_UID}")
01982     message (FATAL_ERROR "Unknown target ${TARGET_UID}.")
01983     return ()
01984   endif ()
01985 
01986   if (BASIS_VERBOSE)
01987     message (STATUS "Adding build command for script ${TARGET_UID}...")
01988   endif ()
01989 
01990   # get target properties
01991   basis_get_target_name (TARGET_NAME ${TARGET_UID})
01992 
01993   set (
01994     PROPERTIES
01995       "BASIS_TYPE"
01996       "BASIS_LANGUAGE"
01997       "SOURCE_DIRECTORY"
01998       "BINARY_DIRECTORY"
01999       "RUNTIME_OUTPUT_DIRECTORY"
02000       "RUNTIME_INSTALL_DIRECTORY"
02001       "LIBRARY_OUTPUT_DIRECTORY"
02002       "LIBRARY_INSTALL_DIRECTORY"
02003       "PREFIX"
02004       "OUTPUT_NAME"
02005       "SUFFIX"
02006       "VERSION"
02007       "SOVERSION"
02008       "SOURCES"
02009       "COMPILE_DEFINITIONS"
02010       "LINK_DEPENDS"
02011       "RUNTIME_COMPONENT"
02012       "LIBRARY_COMPONENT"
02013       "LIBEXEC"
02014       "TEST"
02015       "NO_EXPORT"
02016       "COMPILE"
02017       "WITH_EXT"
02018   )
02019 
02020   foreach (PROPERTY ${PROPERTIES})
02021     get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
02022   endforeach ()
02023 
02024   # check target type
02025   if (NOT BASIS_TYPE MATCHES "^EXECUTABLE_SCRIPT$|^MODULE_SCRIPT$")
02026     message (FATAL_ERROR "Target ${TARGET_UID} has invalid BASIS_TYPE: ${BASIS_TYPE}")
02027   endif ()
02028 
02029   if (BASIS_TYPE MATCHES "^MODULE_SCRIPT$")
02030     set (MODULE 1)
02031   else ()
02032     set (MODULE 0)
02033   endif ()
02034 
02035   # build directory (note that CMake returns basename of build directory as first element of SOURCES list)
02036   list (GET SOURCES 0 BUILD_DIR)
02037   set (BUILD_DIR "${BUILD_DIR}.dir")
02038 
02039   # binary directory
02040   if (NOT BINARY_DIRECTORY)
02041     message (FATAL_ERROR "basis_add_script_finalize(${TARGET_UID}): BINARY_DIRECTORY property not set!")
02042   endif ()
02043   if (NOT BINARY_DIRECTORY MATCHES "^${PROJECT_BINARY_DIR}")
02044     message (FATAL_ERROR "basis_add_script_finalize(${TARGET_UID}): BINARY_DIRECTORY must be inside of build tree!")
02045   endif ()
02046 
02047   # extract script file from SOURCES
02048   list (GET SOURCES 1 SCRIPT_FILE)
02049 
02050   # get script name without ".in"
02051   get_filename_component (SCRIPT_NAME "${SCRIPT_FILE}" NAME)
02052   string (REGEX REPLACE "\\.in$" "" SCRIPT_NAME "${SCRIPT_NAME}")
02053 
02054   # output name
02055   if (NOT OUTPUT_NAME)
02056     set (OUTPUT_NAME "${TARGET_NAME}")
02057   endif ()
02058   if (PREFIX)
02059     set (OUTPUT_NAME "${PREFIX}${OUTPUT_NAME}")
02060   endif ()
02061   if (SUFFIX)
02062     set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
02063   endif ()
02064 
02065   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02066   # create build script
02067   #
02068   # Note: If the script is configured, this is done twice, once for the build tree
02069   #       and once for the installation. The build tree version of the configured
02070   #       script is written to the runtime output directory in the build tree.
02071   #       The version configured for the installation, is written to the binary
02072   #       directory that corresponds to the source directory of the script.
02073   #       If a documentation is generated automatically from the sources, the
02074   #       latter, i.e., the script which will be installed is used as input file.
02075   set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
02076   # configured script file for build tree
02077   if (MODULE)
02078     set (CONFIGURED_FILE "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
02079   else ()
02080     set (CONFIGURED_FILE "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
02081   endif ()
02082   # final output script file for build tree
02083   set (OUTPUT_FILE "${CONFIGURED_FILE}")
02084   # configured script file for install tree
02085   set (CONFIGURED_INSTALL_FILE "${CONFIGURED_FILE}")
02086   # final output script file for install tree
02087   set (INSTALL_FILE "${CONFIGURED_INSTALL_FILE}")
02088   set (INSTALL_NAME "${OUTPUT_NAME}")
02089   # output files of build command
02090   set (OUTPUT_FILES "${OUTPUT_FILE}")
02091   # files this script and its build depends on
02092   set (DEPENDS ${LINK_DEPENDS} "${BUILD_SCRIPT}")
02093 
02094   set (C "# DO NOT edit. This file was automatically generated by BASIS.\n")
02095 
02096   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02097   # look for required interpreter executable
02098   if (BASIS_LANGUAGE MATCHES "PYTHON")
02099     find_package (PythonInterp QUIET)
02100     if (NOT PYTHONINTERP_FOUND)
02101       message (FATAL_ERROR "Python interpreter not found. It is required to"
02102                            " execute the script file target ${TARGET_UID}.")
02103     endif ()
02104   elseif (BASIS_LANGUAGE MATCHES "PERL")
02105     find_package (Perl QUIET)
02106     if (NOT PERL_FOUND)
02107       message (FATAL_ERROR "Perl interpreter not found. It is required to"
02108                            " execute the script file target ${TARGET_UID}.")
02109     endif ()
02110   elseif (BASIS_LANGUAGE MATCHES "BASH")
02111     find_package (BASH QUIET)
02112     if (NOT BASH_FOUND)
02113       message (FATAL_ERROR "BASH interpreter not found. It is required to"
02114                            " execute the script file target ${TARGET_UID}.")
02115     endif ()
02116   endif ()
02117 
02118   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02119   # common variables and functions used by build scripts
02120   set (C "${C}\n")
02121   set (C "${C}# set script attributes\n")
02122   set (C "${C}set (LANGUAGE \"${BASIS_LANGUAGE}\")\n")
02123   set (C "${C}set (NAME \"${OUTPUT_NAME}\")\n")
02124   set (C "${C}string (TOUPPER \"\${NAME}\" NAME_UPPER)\n")
02125   set (C "${C}string (TOLOWER \"\${NAME}\" NAME_LOWER)\n")
02126   set (C "${C}get_filename_component (NAMESPACE \"\${NAME}\" NAME_WE)\n")
02127   set (C "${C}string (REGEX REPLACE \"[^a-zA-Z0-9]\" \"_\" NAMESPACE \"\${NAMESPACE}\")\n")
02128   set (C "${C}string (TOUPPER \"\${NAMESPACE}\" NAMESPACE_UPPER)\n")
02129   set (C "${C}string (TOLOWER \"\${NAMESPACE}\" NAMESPACE_LOWER)\n")
02130   set (C "${C}\n")
02131   set (C "${C}# function used by build script to generate script for this platform\n")
02132   set (C "${C}function (basis_configure_script SCRIPT_FILE CONFIGURED_FILE MODE)\n")
02133   set (C "${C}  file (READ \"\${SCRIPT_FILE}\" SCRIPT)\n")
02134   set (C "${C}  if (NOT MODE MATCHES \"COPYONLY\")\n")
02135   set (C "${C}    string (CONFIGURE \"\${SCRIPT}\" SCRIPT \${MODE})\n")
02136   set (C "${C}    string (CONFIGURE \"\${SCRIPT}\" SCRIPT \${MODE})\n")
02137   set (C "${C}  endif ()\n")
02138   if (NOT MODULE AND NOT WITH_EXT)
02139   set (C "${C}  if (WIN32)\n")
02140   set (C "${C}    if (LANGUAGE MATCHES \"PYTHON\")\n")
02141   set (C "${C}      set (SCRIPT \"@setlocal enableextensions & ${PYTHON_EXECUTABLE} -x %~f0 %* & goto :EOF\\n\${SCRIPT}\")\n")
02142   set (C "${C}    elseif (LANGUAGE MATCHES \"PERL\")\n")
02143   set (C "${C}      set (SCRIPT \"@goto = \\\"START_OF_BATCH\\\" ;\\n@goto = ();\\n\\n\${SCRIPT}\")\n")
02144   set (C "${C}      set (SCRIPT \"\${SCRIPT}\\n\\n__END__\\n\\n:\\\"START_OF_BATCH\\\"\\n@${PERL_EXECUTABLE} -w -S %~f0 %*\")\n")
02145   set (C "${C}    endif ()\n")
02146   set (C "${C}  elseif (NOT SCRIPT MATCHES \"^#!\")\n")
02147   set (C "${C}    if (LANGUAGE MATCHES \"PYTHON\")\n")
02148   set (C "${C}      set (SCRIPT \"#! ${PYTHON_EXECUTABLE}\\n\${SCRIPT}\")\n")
02149   set (C "${C}    elseif (LANGUAGE MATCHES \"PERL\")\n")
02150   set (C "${C}      set (SCRIPT \"#! ${PERL_EXECUTABLE} -w\\n\${SCRIPT}\")\n")
02151   set (C "${C}    elseif (LANGUAGE MATCHES \"BASH\")\n")
02152   set (C "${C}      set (SCRIPT \"#! ${BASH_EXECUTABLE}\\n\${SCRIPT}\")\n")
02153   set (C "${C}    endif ()\n")
02154   set (C "${C}  endif ()\n")
02155   endif ()
02156   set (C "${C}  file (WRITE \"\${CONFIGURED_FILE}\" \"\${SCRIPT}\")\n")
02157   set (C "${C}endfunction ()\n")
02158 
02159   if (SCRIPT_FILE MATCHES "\\.in$")
02160     # make (configured) script configuration files a dependency
02161     list (APPEND DEPENDS "${BUILD_DIR}/variables.cmake")
02162     if (EXISTS "${BINARY_CONFIG_DIR}/BasisScriptConfig.cmake")
02163       list (APPEND DEPENDS "${BINARY_CONFIG_DIR}/BasisScriptConfig.cmake")
02164     endif ()
02165     if (EXISTS "${BINARY_CONFIG_DIR}/ScriptConfig.cmake")
02166       list (APPEND DEPENDS "${BINARY_CONFIG_DIR}/ScriptConfig.cmake")
02167     endif ()
02168     if (EXISTS "${BUILD_DIR}/ScriptConfig.cmake")
02169       list (APPEND DEPENDS "${BUILD_DIR}/ScriptConfig.cmake")
02170     endif ()
02171 
02172     # additional output files
02173     if (RUNTIME_INSTALL_DIRECTORY)
02174       set (CONFIGURED_INSTALL_FILE "${BINARY_DIRECTORY}/${SCRIPT_NAME}")
02175       set (INSTALL_FILE "${CONFIGURED_INSTALL_FILE}")
02176       list (APPEND OUTPUT_FILES "${CONFIGURED_INSTALL_FILE}")
02177     endif ()
02178     if (MODULE AND COMPILE AND BASIS_LANGUAGE MATCHES "PYTHON")
02179       # Python modules get optionally compiled
02180       get_filename_component (MODULE_PATH "${CONFIGURED_FILE}" PATH)
02181       get_filename_component (MODULE_NAME "${CONFIGURED_FILE}" NAME_WE)
02182       set (OUTPUT_FILE "${MODULE_PATH}/${MODULE_NAME}.pyc")
02183       list (APPEND OUTPUT_FILES "${OUTPUT_FILE}")
02184       # and the compiled module installed
02185       if (RUNTIME_INSTALL_DIRECTORY)
02186         get_filename_component (MODULE_PATH "${CONFIGURED_INSTALL_FILE}" PATH)
02187         get_filename_component (MODULE_NAME "${CONFIGURED_INSTALL_FILE}" NAME_WE)
02188         set (INSTALL_FILE "${MODULE_PATH}/${MODULE_NAME}.pyc")
02189         list (APPEND OUTPUT_FILES "${INSTALL_FILE}")
02190       endif ()
02191     endif ()
02192 
02193     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02194     # common code for build of build tree and install tree version
02195 
02196     # tools for use in script configuration
02197     set (C "${C}\n")
02198     set (C "${C}# definitions of utility functions\n")
02199     set (C "${C}include (\"${BASIS_MODULE_PATH}/CommonTools.cmake\")\n")
02200     set (C "${C}\n")
02201     set (C "${C}function (basis_set_script_path VAR PATH)\n")
02202     set (C "${C}  if (ARGC GREATER 3)\n")
02203     set (C "${C}    message (FATAL_ERROR \"Too many arguments given for function basis_set_script_path()\")\n")
02204     set (C "${C}  endif ()\n")
02205     set (C "${C}  if (ARGC EQUAL 3 AND BUILD_INSTALL_SCRIPT)\n")
02206     set (C "${C}    set (PREFIX \"${INSTALL_PREFIX}\")\n")
02207     set (C "${C}    set (PATH   \"\${ARGV2}\")\n")
02208     set (C "${C}  else ()\n")
02209     set (C "${C}    set (PREFIX \"${PROJECT_SOURCE_DIR}\")\n")
02210     set (C "${C}  endif ()\n")
02211     set (C "${C}  if (NOT IS_ABSOLUTE \"\${PATH}\")\n")
02212     set (C "${C}    set (PATH \"\${PREFIX}/\${PATH}\")\n")
02213     set (C "${C}  endif ()\n")
02214     set (C "${C}  basis_get_relative_path (PATH \"\${DIR}\" \"\${PATH}\")\n")
02215     set (C "${C}  if (NOT PATH)\n")
02216     set (C "${C}    set (PATH \".\")\n")
02217     set (C "${C}  endif ()\n")
02218     set (C "${C}  string (REGEX REPLACE \"/$\" \"\" PATH \"\${PATH}\")\n")
02219     set (C "${C}  set (\${VAR} \"\${PATH}\" PARENT_SCOPE)\n")
02220     set (C "${C}endfunction ()\n")
02221 
02222     # variables dumped by basis_add_script()
02223     set (C "${C}\n")
02224     set (C "${C}# dumped CMake variables\n")
02225     set (C "${C}include (\"\${CMAKE_CURRENT_LIST_DIR}/variables.cmake\")\n")
02226 
02227     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02228     # build script for build tree
02229 
02230     # script configuration code
02231     set (C "${C}\n")
02232     set (C "${C}# build script for use in build tree\n")
02233     set (C "${C}set (BUILD_INSTALL_SCRIPT 0)\n")
02234     if (MODULE)
02235       set (C "${C}set (DIR \"${LIBRARY_OUTPUT_DIRECTORY}\")\n")
02236     else ()
02237       set (C "${C}set (DIR \"${RUNTIME_OUTPUT_DIRECTORY}\")\n")
02238     endif ()
02239     set (C "${C}set (FILE \"\${DIR}/\${NAME}\")\n")
02240     set (C "${C}\n")
02241     set (C "${C}include (\"${BINARY_CONFIG_DIR}/BasisScriptConfig.cmake\")\n")
02242     set (C "${C}include (\"${BINARY_CONFIG_DIR}/ScriptConfig.cmake\" OPTIONAL)\n")
02243     set (C "${C}include (\"${BUILD_DIR}/ScriptConfig.cmake\" OPTIONAL)\n")
02244     set (C "${C}\n")
02245     if (COMPILE_DEFINITIONS)
02246       set (C "${C}${COMPILE_DEFINITIONS}\n")
02247     endif ()
02248     # configure script for build tree
02249     set (C "${C}basis_configure_script (\"${SCRIPT_FILE}\" \"${CONFIGURED_FILE}\" @ONLY)\n")
02250     if (MODULE)
02251       # compile module if applicable
02252       if (COMPILE AND BASIS_LANGUAGE MATCHES "PYTHON")
02253         set (C "${C}execute_process (COMMAND \"${PYTHON_EXECUTABLE}\" -c \"import py_compile;py_compile.compile('${CONFIGURED_FILE}')\")\n")
02254         get_filename_component (MODULE_PATH "${CONFIGURED_FILE}" PATH)
02255         get_filename_component (MODULE_NAME "${CONFIGURED_FILE}" NAME_WE)
02256         set (OUTPUT_FILE "${MODULE_PATH}/${MODULE_NAME}.pyc")
02257         list (APPEND OUTPUT_FILES "${OUTPUT_FILE}")
02258       endif ()
02259     else ()
02260       # or set executable bit on Unix
02261       set (C "${C}\n")
02262       set (C "${C}if (UNIX)\n")
02263       set (C "${C}  execute_process (COMMAND /bin/chmod +x \"${CONFIGURED_FILE}\")\n")
02264       set (C "${C}endif ()\n")
02265     endif ()
02266 
02267     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02268     # build script for installation tree (optional)
02269 
02270     if (MODULE)
02271       set (INSTALL_DIR "${LIBRARY_INSTALL_DIRECTORY}")
02272     else ()
02273       set (INSTALL_DIR "${RUNTIME_INSTALL_DIRECTORY}")
02274     endif ()
02275 
02276     if (INSTALL_DIR)
02277       # script configuration code
02278       set (C "${C}\n")
02279       set (C "${C}# build script for use in installation tree\n")
02280       set (C "${C}set (BUILD_INSTALL_SCRIPT 1)\n")
02281       set (C "${C}set (DIR \"${INSTALL_PREFIX}/${INSTALL_DIR}\")\n")
02282       set (C "${C}set (FILE \"\${DIR}/\${NAME}\")\n")
02283       set (C "${C}\n")
02284       set (C "${C}include (\"${BINARY_CONFIG_DIR}/BasisScriptConfig.cmake\")\n")
02285       set (C "${C}include (\"${BINARY_CONFIG_DIR}/ScriptConfig.cmake\" OPTIONAL)\n")
02286       set (C "${C}include (\"${BUILD_DIR}/ScriptConfig.cmake\" OPTIONAL)\n")
02287       set (C "${C}\n")
02288       if (COMPILE_DEFINITIONS)
02289         set (C "${C}${COMPILE_DEFINITIONS}\n")
02290       endif ()
02291       # configure script for installation tree
02292       set (C "${C}basis_configure_script (\"${SCRIPT_FILE}\" \"${CONFIGURED_INSTALL_FILE}\" @ONLY)\n")
02293       # compile module if applicable
02294       if (MODULE AND COMPILE AND BASIS_LANGUAGE MATCHES "PYTHON")
02295         set (C "${C}execute_process (COMMAND \"${PYTHON_EXECUTABLE}\" -c \"import py_compile;py_compile.compile('${CONFIGURED_INSTALL_FILE}')\")\n")
02296         get_filename_component (MODULE_PATH "${CONFIGURED_INSTALL_FILE}" PATH)
02297         get_filename_component (MODULE_NAME "${CONFIGURED_INSTALL_FILE}" NAME_WE)
02298         set (INSTALL_FILE "${MODULE_PATH}/${MODULE_NAME}.pyc")
02299         string (REGEX REPLACE "\\.py$" ".pyc" INSTALL_NAME "${INSTALL_NAME}")
02300         list (APPEND OUTPUT_FILES "${INSTALL_FILE}")
02301       endif ()
02302     endif ()
02303 
02304   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02305   # otherwise, just copy script file
02306   else ()
02307 
02308     set (C "${C}\nbasis_configure_script (\"${SCRIPT_FILE}\" \"${CONFIGURED_FILE}\" COPYONLY)\n")
02309     # compile module if applicable
02310     if (MODULE)
02311       if (COMPILE AND BASIS_LANGUAGE MATCHES "PYTHON")
02312         set (C "${C}execute_process (COMMAND \"${PYTHON_EXECUTABLE}\" -c \"import py_compile;py_compile.compile('${CONFIGURED_FILE}')\")\n")
02313         get_filename_component (MODULE_PATH "${CONFIGURED_FILE}" PATH)
02314         get_filename_component (MODULE_NAME "${CONFIGURED_FILE}" NAME_WE)
02315         set (OUTPUT_FILE  "${MODULE_PATH}/${MODULE_NAME}.pyc")
02316         list (APPEND OUTPUT_FILES "${OUTPUT_FILE}")
02317         set (INSTALL_FILE "${OUTPUT_FILE}")
02318         string (REGEX REPLACE "\\.py$" ".pyc" INSTALL_NAME "${INSTALL_NAME}")
02319       endif ()
02320     # or set executable bit on Unix
02321     else ()
02322       set (C "${C}\n")
02323       set (C "${C}if (UNIX)\n")
02324       set (C "${C}  execute_process (COMMAND /bin/chmod +x \"${CONFIGURED_FILE}\")\n")
02325       set (C "${C}endif ()\n")
02326     endif ()
02327 
02328   endif ()
02329 
02330   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02331   # setup build commands
02332 
02333   # write/update build script
02334   if (EXISTS "${BUILD_SCRIPT}")
02335     file (WRITE "${BUILD_SCRIPT}.tmp" "${C}")
02336     execute_process (
02337       COMMAND "${CMAKE_COMMAND}" -E copy_if_different
02338           "${BUILD_SCRIPT}.tmp" "${BUILD_SCRIPT}"
02339     )
02340     file (REMOVE "${BUILD_SCRIPT}.tmp")
02341   else ()
02342     file (WRITE "${BUILD_SCRIPT}" "${C}")
02343   endif ()
02344 
02345   # add custom target to execute build script
02346   file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${OUTPUT_FILE}")
02347 
02348   add_custom_command (
02349     OUTPUT  ${OUTPUT_FILES}
02350     MAIN_DEPENDENCY "${SCRIPT_FILE}"
02351     DEPENDS ${DEPENDS}
02352     COMMAND "${CMAKE_COMMAND}" -P "${BUILD_SCRIPT}"
02353     COMMENT "Building script ${REL}..."
02354   )
02355 
02356   if (TARGET "_${TARGET_UID}")
02357     message (FATAL_ERROR "There is another target named _${TARGET_UID}. "
02358                          "BASIS uses target names starting with an underscore "
02359                          "for custom targets which are required to build script files. "
02360                          "Do not use leading underscores in target names.")
02361   endif ()
02362 
02363   # add custom target which triggers execution of build script
02364   add_custom_target (_${TARGET_UID} DEPENDS ${OUTPUT_FILES})
02365   add_dependencies (${TARGET_UID} _${TARGET_UID})
02366 
02367   # Provide target to build all scripts. In particular, scripts need to be build
02368   # before the doc target which thus depends on this target.
02369   if (NOT TARGET scripts)
02370     add_custom_target (scripts)
02371   endif ()
02372   add_dependencies (scripts _${TARGET_UID})
02373 
02374   # cleanup on "make clean"
02375   set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${OUTPUT_FILES})
02376 
02377   # install script
02378   if (NOT ARGN_NO_EXPORT)
02379     if (TEST)
02380       basis_set_project_property (APPEND PROPERTY TEST_EXPORT_TARGETS "${TARGET_UID}")
02381     else ()
02382       basis_set_project_property (APPEND PROPERTY CUSTOM_EXPORT_TARGETS "${TARGET_UID}")
02383     endif ()
02384   endif ()
02385 
02386   if (MODULE)
02387     if (LIBRARY_INSTALL_DIRECTORY)
02388       install (
02389         FILES       "${INSTALL_FILE}"
02390         RENAME      "${INSTALL_NAME}"
02391         DESTINATION "${LIBRARY_INSTALL_DIRECTORY}"
02392         COMPONENT   "${LIBRARY_COMPONENT}"
02393       )
02394     endif ()
02395   else ()
02396     if (RUNTIME_INSTALL_DIRECTORY)
02397       install (
02398         PROGRAMS    "${INSTALL_FILE}"
02399         RENAME      "${INSTALL_NAME}"
02400         DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
02401         COMPONENT   "${RUNTIME_COMPONENT}"
02402       )
02403     endif ()
02404   endif ()
02405 
02406   if (BASIS_VERBOSE)
02407     message (STATUS "Adding build command for script ${TARGET_UID}... - done")
02408   endif ()
02409 endfunction ()
02410 
02411 # ----------------------------------------------------------------------------
02412 # @brief Add target to build/install __init__.py files.
02413 function (basis_add_init_py_target)
02414   # constants
02415   set (BUILD_DIR "${PROJECT_BINARY_DIR}/CMakeFiles/_initpy.dir")
02416   basis_sanitize_for_regex (BINARY_PYTHON_LIBRARY_DIR_REGEX  "${BINARY_PYTHON_LIBRARY_DIR}")
02417   basis_sanitize_for_regex (TESTING_PYTHON_LIBRARY_DIR_REGEX "${TESTING_PYTHON_LIBRARY_DIR}")
02418   basis_sanitize_for_regex (INSTALL_PYTHON_LIBRARY_DIR_REGEX "${INSTALL_PYTHON_LIBRARY_DIR}")
02419   # collect build tree directories requiring a __init__.py file
02420   set (DIRS)            # directories for which to generate a __init__.py file
02421   set (EXCLUDE)         # exclude these directories
02422   set (INSTALL_EXCLUDE) # exclude these directories on installation
02423   set (COMPONENTS)      # installation components
02424   basis_get_project_property (TARGETS PROPERTY TARGETS)
02425   foreach (TARGET_UID ${TARGETS})
02426     get_target_property (BASIS_TYPE     ${TARGET_UID} "BASIS_TYPE")
02427     get_target_property (BASIS_LANGUAGE ${TARGET_UID} "BASIS_LANGUAGE")
02428     if (BASIS_TYPE MATCHES "^MODULE_SCRIPT$" AND BASIS_LANGUAGE MATCHES "PYTHON")
02429       # get absolute path of built Python module
02430       basis_get_target_location (LOCATION         ${TARGET_UID} ABSOLUTE)
02431       basis_get_target_location (INSTALL_LOCATION ${TARGET_UID} POST_INSTALL_RELATIVE)
02432       # get component (used by installation rule)
02433       get_target_property (COMPONENT ${TARGET_UID} "LIBRARY_COMPONENT")
02434       list (FIND COMPONENTS "${COMPONENT}" IDX)
02435       if (IDX EQUAL -1)
02436         list (APPEND COMPONENTS "${COMPONENT}")
02437         set (INSTALL_DIRS_${COMPONENT}) # list of directories for which to install
02438                                         # __init__.py for this component
02439       endif ()
02440       # directories for which to build a __init__.py file
02441       basis_get_filename_component (DIR "${LOCATION}" PATH)
02442       if (LOCATION MATCHES "/__init__.py$")
02443         list (APPEND EXCLUDE "${DIR}")
02444       else ()
02445         if (DIR MATCHES "^${BINARY_PYTHON_LIBRARY_DIR_REGEX}/.+")
02446           while (NOT "${DIR}" MATCHES "^${BINARY_PYTHON_LIBRARY_DIR_REGEX}$")
02447             list (APPEND DIRS "${DIR}")
02448             get_filename_component (DIR "${DIR}" PATH)
02449           endwhile ()
02450         elseif (DIR MATCHES "^${TESTING_PYTHON_LIBRARY_DIR_REGEX}/.+")
02451           while (NOT "${DIR}" MATCHES "^${TESTING_PYTHON_LIBRARY_DIR_REGEX}$")
02452             list (APPEND DIRS "${DIR}")
02453             get_filename_component (DIR "${DIR}" PATH)
02454           endwhile ()
02455         endif ()
02456       endif ()
02457       # directories for which to install a __init__.py file
02458       basis_get_filename_component (DIR "${INSTALL_LOCATION}" PATH)
02459       if (INSTALL_LOCATION MATCHES "/__init__.py$")
02460         list (APPEND INSTALL_EXCLUDE "${DIR}")
02461       else ()
02462         if (DIR MATCHES "^${INSTALL_PYTHON_LIBRARY_DIR_REGEX}/.+")
02463           while (NOT "${DIR}" MATCHES "^${INSTALL_PYTHON_LIBRARY_DIR_REGEX}$")
02464             list (APPEND INSTALL_DIRS_${COMPONENT} "${DIR}")
02465             get_filename_component (DIR "${DIR}" PATH)
02466           endwhile ()
02467         endif ()
02468       endif ()
02469     endif ()
02470   endforeach ()
02471   # return if no Python module is being build
02472   if (NOT DIRS)
02473     return ()
02474   endif ()
02475   list (REMOVE_DUPLICATES DIRS)
02476   if (EXCLUDE)
02477     list (REMOVE_DUPLICATES EXCLUDE)
02478   endif ()
02479   if (INSTALL_EXCLUDE)
02480     list (REMOVE_DUPLICATES INSTALL_EXCLUDE)
02481   endif ()
02482   # generate build script
02483   set (C)
02484   set (OUTPUT_FILES)
02485   foreach (DIR IN LISTS DIRS)
02486     list (FIND EXCLUDE "${DIR}" IDX)
02487     if (IDX EQUAL -1)
02488       set (C "${C}configure_file (\"${BASIS_PYTHON_TEMPLATES_DIR}/__init__.py.in\" \"${DIR}/__init__.py\" @ONLY)\n")
02489       list (APPEND OUTPUT_FILES "${DIR}/__init__.py")
02490       if (BASIS_COMPILE_SCRIPTS)
02491         set (C "${C}execute_process (COMMAND \"${PYTHON_EXECUTABLE}\" -c \"import py_compile;py_compile.compile('${DIR}/__init__.py')\")\n")
02492         list (APPEND OUTPUT_FILES "${DIR}/__init__.pyc")
02493       endif ()
02494     endif ()
02495   endforeach ()
02496   set (C "${C}configure_file (\"${BASIS_PYTHON_TEMPLATES_DIR}/__init__.py.in\" \"${BUILD_DIR}/__init__.py\" @ONLY)\n")
02497   list (APPEND OUTPUT_FILES "${BUILD_DIR}/__init__.py")
02498   if (BASIS_COMPILE_SCRIPTS)
02499     set (C "${C}execute_process (COMMAND \"${PYTHON_EXECUTABLE}\" -c \"import py_compile;py_compile.compile('${BUILD_DIR}/__init__.py')\")\n")
02500     list (APPEND OUTPUT_FILES "${BUILD_DIR}/__init__.pyc")
02501   endif ()
02502   # write/update build script
02503   set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
02504   if (EXISTS "${BUILD_SCRIPT}")
02505     file (WRITE "${BUILD_SCRIPT}.tmp" "${C}")
02506     execute_process (
02507       COMMAND "${CMAKE_COMMAND}" -E copy_if_different
02508           "${BUILD_SCRIPT}.tmp" "${BUILD_SCRIPT}"
02509     )
02510     file (REMOVE "${BUILD_SCRIPT}.tmp")
02511   else ()
02512     file (WRITE "${BUILD_SCRIPT}" "${C}")
02513   endif ()
02514   # add custom build command
02515   add_custom_command (
02516     OUTPUT  ${OUTPUT_FILES}
02517     COMMAND "${CMAKE_COMMAND}" -P "${BUILD_SCRIPT}"
02518     COMMENT "Building __init__.py modules..."
02519   )
02520   # add custom target which triggers execution of build script
02521   add_custom_target (_initpy ALL DEPENDS ${OUTPUT_FILES})
02522   if (TARGET scripts)
02523     add_dependencies (scripts _initpy)
02524   endif ()
02525   # cleanup on "make clean"
02526   set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${OUTPUT_FILES})
02527   # add install rules
02528   if (BASIS_COMPILE_SCRIPTS)
02529     set (INSTALL_INIT_FILE "${BUILD_DIR}/__init__.pyc")
02530   else ()
02531     set (INSTALL_INIT_FILE "${BUILD_DIR}/__init__.py")
02532   endif ()
02533   foreach (COMPONENT IN LISTS COMPONENTS)
02534     if (INSTALL_DIRS_${COMPONENT})
02535       list (REMOVE_DUPLICATES INSTALL_DIRS_${COMPONENT})
02536     endif ()
02537     foreach (DIR IN LISTS INSTALL_DIRS_${COMPONENT})
02538       list (FIND INSTALL_EXCLUDE "${DIR}" IDX)
02539       if (IDX EQUAL -1)
02540         install (
02541           FILES       "${INSTALL_INIT_FILE}"
02542           DESTINATION "${DIR}"
02543           COMPONENT   "${COMPONENT}"
02544         )
02545       endif ()
02546     endforeach ()
02547   endforeach ()
02548 endfunction ()
02549 
02550 # ----------------------------------------------------------------------------
02551 ## @brief Finalize addition of custom targets.
02552 #
02553 # This function is called by basis_add_project_finalize() to finalize the
02554 # addition of the custom build targets such as, for example, build targets
02555 # to build script files, MATLAB Compiler targets, and MEX script generated
02556 # MEX-files.
02557 #
02558 # @returns Adds custom targets that actually build the executables and
02559 #          libraries for which custom build targets where added by
02560 #          basis_add_executable(), basis_add_library(), and basis_add_script().
02561 #
02562 # @sa basis_add_script_finalize()
02563 # @sa basis_add_mcc_target_finalize()
02564 # @sa basis_add_mex_target_finalize()
02565 function (basis_add_custom_finalize)
02566   basis_get_project_property (TARGETS PROPERTY TARGETS)
02567   foreach (TARGET_UID ${TARGETS})
02568     get_target_property (BASIS_TYPE ${TARGET_UID} "BASIS_TYPE")
02569     if (BASIS_TYPE MATCHES "SCRIPT")
02570       basis_add_script_finalize (${TARGET_UID})
02571     elseif (BASIS_TYPE MATCHES "MEX")
02572       basis_add_mex_target_finalize (${TARGET_UID})
02573     elseif (BASIS_TYPE MATCHES "MCC")
02574       basis_add_mcc_target_finalize (${TARGET_UID})
02575     endif ()
02576   endforeach ()
02577 endfunction ()
02578 
02579 
02580 ## @}
02581 # end of Doxygen group