BASIS  r3148
UtilitiesTools.cmake
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  UtilitiesTools.cmake
00003 # @brief CMake functions related to configuration of BASIS utilities.
00004 #
00005 # Copyright (c) 2011, 2012, 2013 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 ## @addtogroup CMakeUtilities
00014 #  @{
00015 
00016 
00017 # ============================================================================
00018 # C++ utilities
00019 # ============================================================================
00020 
00021 # ----------------------------------------------------------------------------
00022 ## @brief Add build target for BASIS C++ utilities library.
00023 #
00024 # This function is called by the top-level project in order to add the "basis"
00025 # build target for the static project-specific BASIS utilities library for C++.
00026 # It is called by basis_project_impl() in the root CMakeLists.txt file of the
00027 # top-level project.
00028 #
00029 # The CMake function add_library() checks if the specified source code files
00030 # exist. If a source file is not found, an error is raised by CMake. The BASIS
00031 # utilities can, however, only be configured at the end of the configuration
00032 # step. Therefore, this function simply writes dummy C++ source files in order
00033 # to pass the existence check. The actual source files are configured by the
00034 # function basis_configure_utilities().
00035 #
00036 # After writing these dummy source files, a library build target for the
00037 # project-specific BASIS C++ utilities is added. This build target is not
00038 # being build as part of the ALL target in case it is never used by any of
00039 # the build targets of the project. Only if build target links to this
00040 # library, it will be build and installed.
00041 #
00042 # @param [out] UID UID of added build target.
00043 function (basis_add_utilities_library UID)
00044   # target UID of "basis" library target
00045   basis_make_target_uid (TARGET_UID basis)
00046   if (NOT TARGET ${TARGET_UID})
00047     if (PROJECT_IS_SUBPROJECT)
00048       # a subproject has it's own version of the project-specific BASIS utilities
00049       # as the targets and functions live in a separate namespace
00050       set (CODE_DIR    "${BINARY_CODE_DIR}")
00051       set (INCLUDE_DIR "${BINARY_INCLUDE_DIR}")
00052       set (OUTPUT_DIR  "${BINARY_ARCHIVE_DIR}")
00053       set (INSTALL_DIR "${INSTALL_ARCHIVE_DIR}")
00054     else ()
00055       # modules, on the other side, share the library with the top-level project
00056       # the addition of the utilities target is in this case only required because
00057       # of the install(TARGETS) and install(EXPORT) commands.
00058       set (CODE_DIR    "${BASIS_BINARY_CODE_DIR}")
00059       set (INCLUDE_DIR "${BASIS_BINARY_INCLUDE_DIR}")
00060       set (OUTPUT_DIR  "${BASIS_BINARY_ARCHIVE_DIR}")
00061       set (INSTALL_DIR "${BASIS_INSTALL_ARCHIVE_DIR}")
00062     endif ()
00063     # write dummy source files
00064     basis_library_prefix (PREFIX CXX)
00065     foreach (S IN ITEMS basis.h basis.cxx)
00066       if (S MATCHES "\\.h$")
00067         set (S "${INCLUDE_DIR}/${PREFIX}${S}")
00068       else ()
00069         set (S "${CODE_DIR}/${S}")
00070       endif ()
00071       if (NOT EXISTS "${S}")
00072         file (WRITE "${S}"
00073           "#error This dummy source file should have been replaced by the"
00074           " BASIS CMake function basis_configure_utilities()"
00075         )
00076       endif ()
00077     endforeach ()
00078     # add library target if not present yet - only build if required
00079     add_library (${TARGET_UID} STATIC "${CODE_DIR}/basis.cxx")
00080     # define dependency on non-project specific utilities as the order in
00081     # which static libraries are listed on the command-line for the linker
00082     # matters; this will help CMake to get the order right
00083     target_link_libraries (${TARGET_UID} ${BASIS_CXX_UTILITIES_LIBRARY})
00084     # set target properties
00085     _set_target_properties (
00086       ${TARGET_UID}
00087       PROPERTIES
00088         BASIS_TYPE                STATIC_LIBRARY
00089         OUTPUT_NAME               basis
00090         ARCHIVE_OUTPUT_DIRECTORY  "${OUTPUT_DIR}"
00091         ARCHIVE_INSTALL_DIRECTORY "${INSTALL_DIR}"
00092     )
00093     # add installation rule
00094     install (
00095       TARGETS ${TARGET_UID}
00096       EXPORT  ${PROJECT_NAME}
00097       ARCHIVE
00098         DESTINATION "${INSTALL_DIR}"
00099         COMPONENT   "${BASIS_LIBRARY_COMPONENT}"
00100     )
00101     basis_set_project_property (APPEND PROPERTY EXPORT_TARGETS         ${TARGET_UID})
00102     basis_set_project_property (APPEND PROPERTY INSTALL_EXPORT_TARGETS ${TARGET_UID})
00103     # debug message
00104     if (BASIS_DEBUG)
00105       message ("** Added BASIS utilities library ${TARGET_UID}")
00106     endif ()
00107   endif ()
00108   # done
00109   basis_set_project_property (PROPERTY PROJECT_USES_CXX_UTILITIES TRUE)
00110   set (${UID} "${TARGET_UID}" PARENT_SCOPE)
00111 endfunction ()
00112 
00113 # ============================================================================
00114 # BASH utilities
00115 # ============================================================================
00116 
00117 # ----------------------------------------------------------------------------
00118 ## @brief Absolute path of current BASH file.
00119 #
00120 # @note Does not resolve symbolic links.
00121 #
00122 # Example:
00123 # @code
00124 # readonly __MYMODULE=@BASIS_BASH___FILE__@
00125 # @endcode
00126 #
00127 # @ingroup BasisBashUtilities
00128 set (BASIS_BASH___FILE__ "$(cd -- \"$(dirname -- \"\${BASH_SOURCE}\")\" && pwd -P)/$(basename -- \"$BASH_SOURCE\")")
00129 
00130 # ----------------------------------------------------------------------------
00131 ## @brief Absolute path of directory of current BASH file.
00132 #
00133 # @note Does not resolve symbolic links.
00134 #
00135 # Example:
00136 # @code
00137 # readonly __MYMODULE_dir=@BASIS_BASH___DIR__@
00138 # @endcode
00139 #
00140 # @ingroup BasisBashUtilities
00141 set (BASIS_BASH___DIR__ "$(cd -- \"$(dirname -- \"\${BASH_SOURCE}\")\" && pwd -P)")
00142 
00143 # ============================================================================
00144 # determine which utilities are used
00145 # ============================================================================
00146 
00147 # ----------------------------------------------------------------------------
00148 ## @brief Check whether the BASIS utilities are used within a given source file.
00149 #
00150 # This function matches the source code against specific import patterns which
00151 # are all valid imports of the BASIS utilities for the respective programming
00152 # language of the specified file. If the BASIS utilities are used within the
00153 # specified source file, the variable named @p VAR is set to @c TRUE.
00154 # Otherwise, it is set to @c FALSE.
00155 #
00156 # @param [out] VAR         Whether the BASIS utilites are used.
00157 # @param [in]  SOURCE_FILE Path of source file to check.
00158 # @param [in]  ARGN        Source code language. If not specified, the
00159 #                          programming language is determined automatically.
00160 function (basis_utilities_check VAR SOURCE_FILE)
00161   set (UTILITIES_USED FALSE)
00162   if (ARGC EQUAL 2)
00163     basis_get_source_language (LANGUAGE "${SOURCE_FILE}")
00164   elseif (ARGC EQUAL 3)
00165     set (LANGUAGE "${ARGN}")
00166   else ()
00167     message (FATAL_ERROR "Too many arguments given!")
00168   endif ()
00169   # --------------------------------------------------------------------------
00170   # make file path absolute and append .in suffix if necessary
00171   get_filename_component (SOURCE_FILE "${SOURCE_FILE}" ABSOLUTE)
00172   if (NOT EXISTS "${SOURCE_FILE}" AND NOT SOURCE_FILE MATCHES "\\.in$" AND EXISTS "${SOURCE_FILE}.in")
00173     set (SOURCE_FILE "${SOURCE_FILE}.in")
00174   endif ()
00175   # --------------------------------------------------------------------------
00176   # C++
00177   if (LANGUAGE MATCHES "CXX")
00178     # read script file
00179     file (READ "${SOURCE_FILE}" SOURCE)
00180     # match use/require statements
00181     basis_library_prefix (PREFIX ${LANGUAGE})
00182     set (RE "[ \\t]*#[ \\t]*include[ \\t]+[<"](${PREFIX})?basis.h[">]") # e.g., #include "basis.h", #include <pkg/basis.h>
00183     if (SCRIPT MATCHES "(^|\n)[ \t]*${RE}([ \t]*//.*|[ \t]*)(\n|$)")
00184       set (UTILITIES_USED TRUE)
00185       break ()
00186     endif ()
00187   # --------------------------------------------------------------------------
00188   # Python/Jython
00189   elseif (LANGUAGE MATCHES "[JP]YTHON")
00190     # read script file
00191     file (READ "${SOURCE_FILE}" SCRIPT)
00192     # deprecated BASIS_PYTHON_UTILITIES macro
00193     if (SCRIPT MATCHES "(^|\n|;)[ \t]*\@BASIS_PYTHON_UTILITIES\@")
00194       message (FATAL_ERROR "Script ${SOURCE_FILE} uses the deprecated BASIS macro \@BASIS_PYTHON_UTILITIES\@!")
00195     endif ()
00196     basis_sanitize_for_regex (PYTHON_PACKAGE "${PROJECT_NAMESPACE_PYTHON}")
00197     # match use of package-specific utilities
00198     if (SCRIPT MATCHES "[^a-zA-Z._]${PYTHON_PACKAGE}.basis([.; \t\n]|$)") # e.g., basis = <package>.basis, <package>.basis.exedir()
00199       set (UTILITIES_USED TRUE)
00200     else ()
00201       # match import statements
00202       foreach (RE IN ITEMS
00203         "import[ \\t]+basis"                                      # e.g., import basis
00204         "import[ \\t]+${PYTHON_PACKAGE}\\.basis"                  # e.g., import <package>.basis
00205         "import[ \\t]+\\.\\.?basis"                               # e.g., import .basis, import ..basis
00206         "from[ \\t]+${PYTHON_PACKAGE}[ \\t]+import[ \\t]+basis"   # e.g., from <package> import basis
00207         "from[ \\t]+${PYTHON_PACKAGE}.basis[ \\t]+import[ \\t].*" # e.g., from <package>.basis import which
00208         "from[ \\t]+\\.\\.?[ \\t]+import[ \\t]+basis"             # e.g., from . import basis", "from .. import basis
00209         "from[ \\t]+\\.\\.?basis[ \\t]+import[ \\t].*"            # e.g., from .basis import which, WhichError, from ..basis import which
00210       ) # foreach RE
00211         if (SCRIPT MATCHES "(^|\n|;)[ \t]*${RE}([ \t]*as[ \t]+.*)?([ \t]*#.*|[ \t]*)(;|\n|$)")
00212           set (UTILITIES_USED TRUE)
00213           break ()
00214         endif ()
00215       endforeach ()
00216     endif ()
00217   # --------------------------------------------------------------------------
00218   # Perl
00219   elseif (LANGUAGE MATCHES "PERL")
00220     # read script file
00221     file (READ "${SOURCE_FILE}" SCRIPT)
00222     # deprecated BASIS_PERL_UTILITIES macro
00223     if (SCRIPT MATCHES "(^|\n|;)[ \t]*\@BASIS_PERL_UTILITIES\@")
00224       message (FATAL_ERROR "Script ${SOURCE_FILE} uses the deprecated BASIS macro \@BASIS_PERL_UTILITIES\@!")
00225     endif ()
00226     # match use/require statements
00227     basis_sanitize_for_regex (PERL_PACKAGE "${PROJECT_NAMESPACE_PERL}")
00228     set (RE "(use|require)[ \\t]+${PERL_PACKAGE}::Basis([ \\t]+.*)?") # e.g., use <Package>::Basis qw(:everything);
00229     if (SCRIPT MATCHES "(^|\n|;)[ \t]*${RE}([ \t]*#.*|[ \t]*)(;|\n|$)")
00230       set (UTILITIES_USED TRUE)
00231       break ()
00232     endif ()
00233   # --------------------------------------------------------------------------
00234   # Bash
00235   elseif (LANGUAGE MATCHES "BASH")
00236     # read script file
00237     file (READ "${SOURCE_FILE}" SCRIPT)
00238     # deprecated BASIS_BASH_UTILITIES macro
00239     if (SCRIPT MATCHES "(^|\n|;)[ \t]*\@BASIS_BASH_UTILITIES\@")
00240       message (FATAL_ERROR "Script ${SOURCE_FILE} uses the deprecated BASIS macro \@BASIS_BASH_UTILITIES\@!")
00241     endif ()
00242     # match source/. built-ins
00243     set (RE "(source|\\.)[ \\t]+\\\"?\\\${?BASIS_BASH_UTILITIES}?\\\"?[ \\t]*(\\|\\|.*|&&.*)?(#.*)?") # e.g., . ${BASIS_BASH_UTILITIES} || exit 1
00244     if (SCRIPT MATCHES "(^|\n|;)[ \t]*(${RE})[ \t]*(;|\n|$)")
00245       set (UTILITIES_USED TRUE)
00246     endif ()
00247   endif ()
00248   # return
00249   set (${VAR} "${UTILITIES_USED}" PARENT_SCOPE)
00250 endfunction ()
00251 
00252 # ============================================================================
00253 # configuration
00254 # ============================================================================
00255 
00256 # ----------------------------------------------------------------------------
00257 ## @brief Configure BASIS utilities.
00258 #
00259 # This function configures the following source files which can be used
00260 # within the source code of the project.
00261 #
00262 # <table border="0">
00263 #   <tr>
00264 #     @tp @b basis.h @endtp
00265 #     <td>Header file declaring the BASIS utilities for C++.</td>
00266 #   </tr>
00267 #   <tr>
00268 #     @tp @b basis.cxx @endtp
00269 #     <td>Definitions of the constants and functions declared in basis.h.</td>
00270 #   </tr>
00271 #   <tr>
00272 #     @tp @b basis.py @endtp
00273 #     <td>Module defining the BASIS utilities for Python.</td>
00274 #   </tr>
00275 #   <tr>
00276 #     @tp @b Basis.pm @endtp
00277 #     <td>Module defining the BASIS utilities for Perl.</td>
00278 #   </tr>
00279 #   <tr>
00280 #     @tp @b basis.sh @endtp
00281 #     <td>Module defining the BASIS utilities for Bash.</td>
00282 #   </tr>
00283 # </table>
00284 #
00285 # @note Dummy versions of the C++ source files have been written by the
00286 #       function basis_configure_auxiliary_sources() beforehand. This is
00287 #       necessary because CMake's add_executable() and add_library() commands
00288 #       raise an error if any of the specified source files does not exist.
00289 function (basis_configure_utilities)
00290   set (CXX TRUE)
00291   basis_get_project_property (PYTHON PROPERTY PROJECT_USES_PYTHON_UTILITIES)
00292   basis_get_project_property (PERL   PROPERTY PROJECT_USES_PERL_UTILITIES)
00293   basis_get_project_property (BASH   PROPERTY PROJECT_USES_BASH_UTILITIES)
00294   if (NOT CXX AND NOT PYTHON AND NOT PERL AND NOT BASH)
00295     return ()
00296   endif ()
00297   message (STATUS "Configuring BASIS utilities...")
00298   # --------------------------------------------------------------------------
00299   # executable target information
00300   _basis_generate_executable_target_info(${CXX} ${PYTHON} ${PERL} ${BASH})
00301   # --------------------------------------------------------------------------
00302   # project ID -- used by print_version() in particular
00303   set (PROJECT_ID "${PROJECT_PACKAGE}")
00304   if (NOT PROJECT_NAME MATCHES "${PROJECT_PACKAGE}")
00305     set (PROJECT_ID "${PROJECT_ID}, ${PROJECT_NAME}")
00306   endif ()
00307   # --------------------------------------------------------------------------
00308   # C++
00309   if (CXX)
00310     # paths - build tree
00311     set (BUILD_ROOT_PATH_CONFIG    "${CMAKE_BINARY_DIR}")
00312     set (RUNTIME_BUILD_PATH_CONFIG "${BINARY_RUNTIME_DIR}")
00313     set (LIBEXEC_BUILD_PATH_CONFIG "${BINARY_LIBEXEC_DIR}")
00314     set (LIBRARY_BUILD_PATH_CONFIG "${BINARY_LIBRARY_DIR}")
00315     set (DATA_BUILD_PATH_CONFIG    "${PROJECT_DATA_DIR}")
00316     # paths - installation
00317     file (RELATIVE_PATH RUNTIME_PATH_PREFIX_CONFIG "${CMAKE_INSTALL_PREFIX}/${INSTALL_RUNTIME_DIR}" "${CMAKE_INSTALL_PREFIX}")
00318     string (REGEX REPLACE "/$|\\$" "" RUNTIME_PATH_PREFIX_CONFIG "${RUNTIME_PATH_PREFIX_CONFIG}")
00319     file (RELATIVE_PATH LIBEXEC_PATH_PREFIX_CONFIG "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBEXEC_DIR}" "${CMAKE_INSTALL_PREFIX}")
00320     string (REGEX REPLACE "/$|\\$" "" LIBEXEC_PATH_PREFIX_CONFIG "${LIBEXEC_PATH_PREFIX_CONFIG}")
00321     set (RUNTIME_PATH_CONFIG "${INSTALL_RUNTIME_DIR}")
00322     set (LIBEXEC_PATH_CONFIG "${INSTALL_LIBEXEC_DIR}")
00323     set (LIBRARY_PATH_CONFIG "${INSTALL_LIBRARY_DIR}")
00324     set (DATA_PATH_CONFIG    "${INSTALL_DATA_DIR}")
00325     # namespace
00326     set (PROJECT_NAMESPACE_CXX_BEGIN "namespace ${PROJECT_PACKAGE_L} {")
00327     set (PROJECT_NAMESPACE_CXX_END   "}")
00328     if (PROJECT_IS_SUBPROJECT)
00329       set (PROJECT_NAMESPACE_CXX_BEGIN "${PROJECT_NAMESPACE_CXX_BEGIN} namespace ${PROJECT_NAME_L} {")
00330       set (PROJECT_NAMESPACE_CXX_END   "${PROJECT_NAMESPACE_CXX_END} }")
00331     endif ()
00332     # executable target information
00333     set (EXECUTABLE_TARGET_INFO "${EXECUTABLE_TARGET_INFO_CXX}")
00334     # configure source files
00335     basis_library_prefix (PREFIX CXX)
00336     configure_file ("${BASIS_CXX_TEMPLATES_DIR}/basis.h.in"   "${BINARY_INCLUDE_DIR}/${PREFIX}basis.h" @ONLY)
00337     configure_file ("${BASIS_CXX_TEMPLATES_DIR}/basis.cxx.in" "${BINARY_CODE_DIR}/basis.cxx"            @ONLY)
00338     source_group (BASIS FILES "${BINARY_INCLUDE_DIR}/${PREFIX}basis.h" "${BINARY_CODE_DIR}/basis.cxx")
00339   endif ()
00340   # --------------------------------------------------------------------------
00341   # Python
00342   if (PYTHON)
00343     # utilities available?
00344     if (NOT BASIS_UTILITIES_ENABLED MATCHES "PYTHON")
00345       message (FATAL_ERROR "BASIS Python utilities required by this package"
00346                            " but BASIS was built without Python utilities."
00347                            " Rebuild BASIS with Python utilities enabled.")
00348     endif ()
00349     # add project-specific utilities
00350     basis_library_prefix (PREFIX PYTHON)
00351     basis_add_library (basis_py "${BASIS_PYTHON_TEMPLATES_DIR}/basis.py")
00352     set (COMPILE_DEFINITIONS
00353       "if (BUILD_INSTALL_SCRIPT)
00354          set (EXECUTABLE_TARGET_INFO \"${EXECUTABLE_TARGET_INFO_PYTHON_I}\")
00355        else ()
00356          set (EXECUTABLE_TARGET_INFO \"${EXECUTABLE_TARGET_INFO_PYTHON_B}\")
00357        endif ()"
00358     )
00359     if (PROJECT_NAME MATCHES "^BASIS$")
00360       set (COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}\nbasis_set_script_path (_BASIS_PYTHONPATH \"${BINARY_PYTHON_LIBRARY_DIR}\" \"${INSTALL_PYTHON_LIBRARY_DIR}\")")
00361     elseif (BUNDLE_PROJECTS MATCHES "(^|;)BASIS(;|$)")
00362       set (COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}\nbasis_set_script_path (_BASIS_PYTHONPATH \"${BASIS_PYTHONPATH}\")")
00363     else ()
00364       set (COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}\nset (_BASIS_PYTHONPATH \"${BASIS_PYTHONPATH}\")")
00365     endif ()
00366     basis_set_target_properties (
00367       basis_py
00368       PROPERTIES
00369         SOURCE_DIRECTORY          "${BASIS_PYTHON_TEMPLATES_DIR}"
00370         BINARY_DIRECTORY          "${BINARY_CODE_DIR}"
00371         LIBRARY_OUTPUT_DIRECTORY  "${BINARY_PYTHON_LIBRARY_DIR}"
00372         LIBRARY_INSTALL_DIRECTORY "${INSTALL_PYTHON_LIBRARY_DIR}"
00373         PREFIX                    "${PREFIX}"
00374         COMPILE_DEFINITIONS       "${COMPILE_DEFINITIONS}"
00375     )
00376     # dependencies
00377     basis_target_link_libraries (basis_py ${BASIS_PYTHON_UTILITIES_LIBRARY})
00378   endif ()
00379   # --------------------------------------------------------------------------
00380   # Perl
00381   if (PERL)
00382     # utilities available?
00383     if (NOT BASIS_UTILITIES_ENABLED MATCHES "PERL")
00384       message (FATAL_ERROR "BASIS Perl utilities required by this package"
00385                            " but BASIS was built without Perl utilities."
00386                            " Rebuild BASIS with Perl utilities enabled.")
00387     endif ()
00388     # add project-specific utilities
00389     basis_library_prefix (PREFIX PERL)
00390     basis_add_library (Basis_pm "${BASIS_PERL_TEMPLATES_DIR}/Basis.pm")
00391     basis_set_target_properties (
00392       Basis_pm
00393       PROPERTIES
00394         SOURCE_DIRECTORY          "${BASIS_PERL_TEMPLATES_DIR}"
00395         BINARY_DIRECTORY          "${BINARY_CODE_DIR}"
00396         LIBRARY_OUTPUT_DIRECTORY  "${BINARY_PERL_LIBRARY_DIR}"
00397         LIBRARY_INSTALL_DIRECTORY "${INSTALL_PERL_LIBRARY_DIR}"
00398         PREFIX                    "${PREFIX}"
00399         COMPILE_DEFINITIONS
00400           "if (BUILD_INSTALL_SCRIPT)
00401              set (EXECUTABLE_TARGET_INFO \"${EXECUTABLE_TARGET_INFO_PERL_I}\")
00402            else ()
00403              set (EXECUTABLE_TARGET_INFO \"${EXECUTABLE_TARGET_INFO_PERL_B}\")
00404            endif ()"
00405     )
00406     # dependencies
00407     basis_target_link_libraries (Basis_pm ${BASIS_PERL_UTILITIES_LIBRARY})
00408   endif ()
00409   # --------------------------------------------------------------------------
00410   # Bash
00411   if (BASH)
00412     # utilities available?
00413     if (NOT UNIX)
00414       message (WARNING "Package uses BASIS Bash utilities but is build"
00415                        " on a non-Unix system.")
00416     endif ()
00417     # utilities available?
00418     if (NOT BASIS_UTILITIES_ENABLED MATCHES "BASH")
00419       message (FATAL_ERROR "BASIS Bash utilities required by this package"
00420                            " but BASIS was built without Bash utilities."
00421                            " Rebuild BASIS with Bash utilities enabled.")
00422     endif ()
00423     # add project-specific utilities
00424     basis_library_prefix (PREFIX BASH)
00425     basis_add_library (basis_sh "${BASIS_BASH_TEMPLATES_DIR}/basis.sh")
00426     set (COMPILE_DEFINITIONS
00427       "if (BUILD_INSTALL_SCRIPT)
00428          set (EXECUTABLE_TARGET_INFO \"${EXECUTABLE_TARGET_INFO_BASH_I}\")
00429        else ()
00430          set (EXECUTABLE_TARGET_INFO \"${EXECUTABLE_TARGET_INFO_BASH_B}\")
00431        endif ()
00432        set (EXECUTABLE_ALIASES \"${EXECUTABLE_TARGET_INFO_BASH_A}\n\n    # define short aliases for this project's targets\n    ${EXECUTABLE_TARGET_INFO_BASH_S}\")"
00433     )
00434     if (PROJECT_NAME MATCHES "^BASIS$")
00435       set (COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}\nbasis_set_script_path (_BASIS_BASH_LIBRARY_DIR \"${BINARY_BASH_LIBRARY_DIR}\" \"${INSTALL_BASH_LIBRARY_DIR}\")")
00436     elseif (BUNDLE_PROJECTS MATCHES "(^|;)BASIS(;|$)")
00437       set (COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}\nbasis_set_script_path (_BASIS_BASH_LIBRARY_DIR \"${BASIS_BASHPATH}\")")
00438     else ()
00439       set (COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS}\nset (_BASIS_BASH_LIBRARY_DIR \"${BASIS_BASHPATH}\")")
00440     endif ()
00441     basis_set_target_properties (
00442       basis_sh
00443       PROPERTIES
00444         SOURCE_DIRECTORY          "${BASIS_BASH_TEMPLATES_DIR}"
00445         BINARY_DIRECTORY          "${BINARY_CODE_DIR}"
00446         LIBRARY_OUTPUT_DIRECTORY  "${BINARY_BASH_LIBRARY_DIR}"
00447         LIBRARY_INSTALL_DIRECTORY "${INSTALL_BASH_LIBRARY_DIR}"
00448         PREFIX                    "${PREFIX}"
00449         COMPILE_DEFINITIONS       "${COMPILE_DEFINITIONS}"
00450     )
00451     # dependencies
00452     basis_target_link_libraries (basis_sh ${BASIS_BASH_UTILITIES_LIBRARY})
00453   endif ()
00454 
00455   message (STATUS "Configuring BASIS utilities... - done")
00456 endfunction ()
00457 
00458 # ----------------------------------------------------------------------------
00459 ## @brief Generate code for initialization of executable target information.
00460 #
00461 # This macro generates the initialization code of the executable target
00462 # information dictionaries for different supported programming languages.
00463 # In case of C++, the source file has been configured and copied to the binary
00464 # tree in a first configuration pass such that it could be used in basis_add_*()
00465 # commands which check the existence of the arguments immediately.
00466 # As the generation of the initialization code requires a complete list of
00467 # build targets (cached in @c BASIS_TARGETS), this function has to be called
00468 # after all targets have been added and finalized (in case of custom targets).
00469 #
00470 # @param [in] CXX    Request code for C++.
00471 # @param [in] PYTHON Request code for Python.
00472 # @param [in] PERL   Request code for Perl.
00473 # @param [in] BASH   Request code for Bash.
00474 #
00475 # @returns Sets the following variables for each requested language.
00476 #
00477 # @retval EXECUTABLE_TARGET_INFO_CXX      C++ code for both build tree and installation.
00478 # @retval EXECUTABLE_TARGET_INFO_PYTHON_B Python code for build tree.
00479 # @retval EXECUTABLE_TARGET_INFO_PYTHON_I Python code for installation.
00480 # @retval EXECUTABLE_TARGET_INFO_PERL_B   Perl code for build tree.
00481 # @retval EXECUTABLE_TARGET_INFO_PERL_I   Perl code for installation.
00482 # @retval EXECUTABLE_TARGET_INFO_BASH_B   Bash code for build tree.
00483 # @retval EXECUTABLE_TARGET_INFO_BASH_I   Bash code for installation.
00484 # @retval EXECUTABLE_TARGET_INFO_BASH_A   Bash code to set aliases.
00485 # @retval EXECUTABLE_TARGET_INFO_BASH_S   Bash code to set short aliases.
00486 function (_basis_generate_executable_target_info CXX PYTHON PERL BASH)
00487   # --------------------------------------------------------------------------
00488   if (NOT CXX AND NOT PYTHON AND NOT PERL AND NOT BASH)
00489     return ()
00490   endif ()
00491   # --------------------------------------------------------------------------
00492   # local constants
00493   basis_sanitize_for_regex (PROJECT_NAMESPACE_CMAKE_RE "${PROJECT_NAMESPACE_CMAKE}")
00494   # --------------------------------------------------------------------------
00495   # lists of executable targets and their location
00496   set (EXECUTABLE_TARGETS)
00497   set (BUILD_LOCATIONS)
00498   set (INSTALL_LOCATIONS)
00499   # project targets
00500   basis_get_project_property (TARGETS)
00501   foreach (TARGET IN LISTS TARGETS)
00502     basis_get_target_type (TYPE ${TARGET})
00503     if (TYPE MATCHES "EXECUTABLE")
00504       basis_get_target_location (BUILD_LOCATION   ${TARGET} ABSOLUTE)
00505       basis_get_target_location (INSTALL_LOCATION ${TARGET} POST_INSTALL)
00506       if (BUILD_LOCATION)
00507         list (APPEND EXECUTABLE_TARGETS "${TARGET}")
00508         list (APPEND BUILD_LOCATIONS    "${BUILD_LOCATION}")
00509         list (APPEND INSTALL_LOCATIONS  "${INSTALL_LOCATION}")
00510       else ()
00511         message (FATAL_ERROR "Failed to determine build location of target ${TARGET}!")
00512       endif ()
00513     endif ()
00514   endforeach ()
00515   # imported targets
00516   basis_get_project_property (IMPORTED_TARGETS)
00517   basis_get_project_property (IMPORTED_TYPES)
00518   basis_get_project_property (IMPORTED_LOCATIONS)
00519   set (I 0)
00520   list (LENGTH IMPORTED_TARGETS N)
00521   while (I LESS N)
00522     list (GET IMPORTED_TARGETS   ${I} TARGET)
00523     list (GET IMPORTED_TYPES     ${I} TYPE)
00524     list (GET IMPORTED_LOCATIONS ${I} LOCATION)
00525     if (TYPE MATCHES "EXECUTABLE")
00526       # get corresponding UID (target may be imported from other module)
00527       basis_get_target_uid (UID ${TARGET})
00528       # skip already considered executables
00529       list (FIND EXECUTABLE_TARGETS ${UID} IDX)
00530       if (IDX EQUAL -1)
00531         if (LOCATION MATCHES "^NOTFOUND$")
00532           message (WARNING "Imported target ${TARGET} has no location property!")
00533         else ()
00534           list (APPEND EXECUTABLE_TARGETS ${TARGET})
00535           list (APPEND BUILD_LOCATIONS    "${LOCATION}")
00536           list (APPEND INSTALL_LOCATIONS  "${LOCATION}")
00537         endif ()
00538       endif ()
00539     endif ()
00540     math (EXPR I "${I} + 1")
00541   endwhile ()
00542   # --------------------------------------------------------------------------
00543   # determine maximum length of target alias for prettier output
00544   set (MAX_ALIAS_LENGTH 0)
00545   foreach (TARGET_UID IN LISTS EXECUTABLE_TARGETS)
00546     if (TARGET_UID MATCHES "^\\.")
00547       string (LENGTH "${TARGET_UID}" LENGTH)
00548     else ()
00549       string (LENGTH "${BASIS_PROJECT_NAMESPACE_CMAKE}.${TARGET_UID}" LENGTH)
00550     endif ()
00551     if (LENGTH GREATER MAX_ALIAS_LENGTH)
00552       set (MAX_ALIAS_LENGTH ${LENGTH})
00553     endif ()
00554   endforeach ()
00555   # --------------------------------------------------------------------------
00556   # generate source code
00557   set (CC)   # C++    - build tree and install tree version, constructor block
00558   set (PY_B) # Python - build tree version
00559   set (PY_I) # Python - install tree version
00560   set (PL_B) # Perl   - build tree version, hash entries
00561   set (PL_I) # Perl   - install tree version, hash entries
00562   set (SH_B) # Bash   - build tree version
00563   set (SH_I) # Bash   - install tree version
00564   set (SH_A) # Bash   - aliases
00565   set (SH_S) # Bash   - short aliases
00566 
00567   if (CXX)
00568     set (CC            "// the following code was automatically generated by the BASIS")
00569     set (CC "${CC}\n    // CMake function basis_configure_ExecutableTargetInfo()")
00570   endif ()
00571 
00572   set (I 0)
00573   list (LENGTH EXECUTABLE_TARGETS N)
00574   while (I LESS N)
00575     # ------------------------------------------------------------------------
00576     # get executable information
00577     list (GET EXECUTABLE_TARGETS ${I} TARGET_UID)
00578     list (GET BUILD_LOCATIONS    ${I} BUILD_LOCATION)
00579     list (GET INSTALL_LOCATIONS  ${I} INSTALL_LOCATION)
00580     get_target_property (BUNDLED  ${TARGET_UID} BUNDLED)
00581     get_target_property (IMPORTED ${TARGET_UID} IMPORTED)
00582     # insert $(IntDir) for Visual Studio build location
00583     if (CMAKE_GENERATOR MATCHES "Visual Studio")
00584       basis_get_target_type (TYPE ${TARGET_UID})
00585       if (TYPE MATCHES "^EXECUTABLE$")
00586         get_filename_component (DIRECTORY "${BUILD_LOCATION}" PATH)
00587         get_filename_component (FILENAME  "${BUILD_LOCATION}" NAME)
00588         set (BUILD_LOCATION_WITH_INTDIR "${DIRECTORY}/$(IntDir)/${FILENAME}")
00589       else ()
00590         set (BUILD_LOCATION_WITH_INTDIR "${BUILD_LOCATION}")
00591       endif ()
00592     else ()
00593       set (BUILD_LOCATION_WITH_INTDIR "${BUILD_LOCATION}")
00594     endif ()
00595     # installation path (relative) to different library paths
00596     foreach (L LIBRARY PYTHON_LIBRARY PERL_LIBRARY BASH_LIBRARY)
00597       if (INSTALL_LOCATION AND (NOT IMPORTED OR BUNDLED))
00598         file (
00599           RELATIVE_PATH INSTALL_LOCATION_REL2${L}
00600             "${CMAKE_INSTALL_PREFIX}/${INSTALL_${L}_DIR}/<package>"
00601             "${INSTALL_LOCATION}"
00602         )
00603       else ()
00604         set (INSTALL_LOCATION_REL2${L} "${INSTALL_LOCATION}")
00605       endif ()
00606     endforeach ()
00607     # target UID including project namespace
00608     if (IMPORTED OR TARGET_UID MATCHES "^\\.")
00609       set (ALIAS "${TARGET_UID}")
00610     elseif (NOT BASIS_USE_FULLY_QUALIFIED_TARGET_UIDS AND BASIS_PROJECT_NAMESPACE_CMAKE)
00611       set (ALIAS "${BASIS_PROJECT_NAMESPACE_CMAKE}.${TARGET_UID}")
00612     endif ()
00613     # indentation after dictionary key, i.e., alias
00614     string (LENGTH "${ALIAS}" ALIAS_LENGTH)
00615     math (EXPR NUM "${MAX_ALIAS_LENGTH} - ${ALIAS_LENGTH} + 1")
00616     if (NUM GREATER 1)
00617       string (RANDOM LENGTH ${NUM} ALPHABET " " S)
00618     else ()
00619       set (S " ")
00620     endif ()
00621     # ------------------------------------------------------------------------
00622     # C++
00623     if (CXX)
00624       get_filename_component (EXEC_NAME   "${BUILD_LOCATION}"   NAME)
00625       get_filename_component (BUILD_DIR   "${BUILD_LOCATION}"   PATH)
00626       if (INSTALL_LOCATION)
00627         get_filename_component (INSTALL_DIR "${INSTALL_LOCATION}" PATH)
00628       endif ()
00629 
00630       set (CC "${CC}\n")
00631       set (CC "${CC}\n    // ${TARGET_UID}")
00632       set (CC "${CC}\n    _exec_names  [\"${ALIAS}\"]${S}= \"${EXEC_NAME}\";")
00633       set (CC "${CC}\n    _build_dirs  [\"${ALIAS}\"]${S}= \"${BUILD_DIR}\";")
00634       set (CC "${CC}\n    _install_dirs[\"${ALIAS}\"]${S}= \"${INSTALL_DIR}\";")
00635     endif ()
00636     # ------------------------------------------------------------------------
00637     # Python
00638     if (PYTHON)
00639       set (PY_B "${PY_B}    '${ALIAS}':${S}'${BUILD_LOCATION_WITH_INTDIR}',\n")
00640       if (INSTALL_LOCATION)
00641         set (PY_I "${PY_I}    '${ALIAS}':${S}'${INSTALL_LOCATION_REL2PYTHON_LIBRARY}',\n")
00642       else ()
00643         set (PY_I "${PY_I}    '${ALIAS}':${S}'',\n")
00644       endif ()
00645     endif ()
00646     # ------------------------------------------------------------------------
00647     # Perl
00648     if (PERL)
00649       if (PL_B)
00650         set (PL_B "${PL_B},\n")
00651       endif ()
00652       set (PL_B "${PL_B}        '${ALIAS}'${S}=> '${BUILD_LOCATION_WITH_INTDIR}'")
00653       if (PL_I)
00654         set (PL_I "${PL_I},\n")
00655       endif ()
00656       if (INSTALL_LOCATION)
00657         set (PL_I "${PL_I}        '${ALIAS}'${S}=> '${INSTALL_LOCATION_REL2PERL_LIBRARY}'")
00658       else ()
00659         set (PL_I "${PL_I}        '${ALIAS}'${S}=> ''")
00660       endif ()
00661     endif ()
00662     # ------------------------------------------------------------------------
00663     # Bash
00664     if (BASH)
00665       # hash entry
00666       set (SH_B "${SH_B}\n    _basis_executabletargetinfo_add '${ALIAS}'${S}LOCATION '${BUILD_LOCATION}'")
00667       if (INSTALL_LOCATION)
00668         set (SH_I "${SH_I}\n    _basis_executabletargetinfo_add '${ALIAS}'${S}LOCATION '${INSTALL_LOCATION_REL2BASH_LIBRARY}'")
00669       else ()
00670         set (SH_I "${SH_I}\n    _basis_executabletargetinfo_add '${ALIAS}'${S}LOCATION ''")
00671       endif ()
00672       # alias
00673       set (SH_A "${SH_A}\n    alias '${ALIAS}'=`get_executable_path '${ALIAS}'`")
00674       # short alias (if target belongs to this project)
00675       if (ALIAS MATCHES "^${PROJECT_NAMESPACE_CMAKE_RE}\\.")
00676         basis_get_target_name (TARGET_NAME "${ALIAS}")
00677         set (SH_S "${SH_S}\n    alias '${TARGET_NAME}'='${ALIAS}'")
00678       endif ()
00679     endif ()
00680     # ------------------------------------------------------------------------
00681     # next executable target
00682     math (EXPR I "${I} + 1")
00683   endwhile ()
00684   # --------------------------------------------------------------------------
00685   # remove unnecessary leading newlines
00686   string (STRIP "${CC}"   CC)
00687   string (STRIP "${PY_B}" PY_B)
00688   string (STRIP "${PY_I}" PY_I)
00689   string (STRIP "${PL_B}" PL_B)
00690   string (STRIP "${PL_I}" PL_I)
00691   string (STRIP "${SH_B}" SH_B)
00692   string (STRIP "${SH_I}" SH_I)
00693   string (STRIP "${SH_A}" SH_A)
00694   string (STRIP "${SH_S}" SH_S)
00695   # --------------------------------------------------------------------------
00696   # return
00697   set (EXECUTABLE_TARGET_INFO_CXX      "${CC}"   PARENT_SCOPE)
00698   set (EXECUTABLE_TARGET_INFO_PYTHON_B "${PY_B}" PARENT_SCOPE)
00699   set (EXECUTABLE_TARGET_INFO_PYTHON_I "${PY_I}" PARENT_SCOPE)
00700   set (EXECUTABLE_TARGET_INFO_PERL_B   "${PL_B}" PARENT_SCOPE)
00701   set (EXECUTABLE_TARGET_INFO_PERL_I   "${PL_I}" PARENT_SCOPE)
00702   set (EXECUTABLE_TARGET_INFO_BASH_B   "${SH_B}" PARENT_SCOPE)
00703   set (EXECUTABLE_TARGET_INFO_BASH_I   "${SH_I}" PARENT_SCOPE)
00704   set (EXECUTABLE_TARGET_INFO_BASH_A   "${SH_A}" PARENT_SCOPE)
00705   set (EXECUTABLE_TARGET_INFO_BASH_S   "${SH_S}" PARENT_SCOPE)
00706 endfunction ()
00707 
00708 
00709 ## @}
00710 # end of Doxygen group