BASIS  version 1.2.3 (revision 2104)
MatlabTools.cmake
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  MatlabTools.cmake
00003 # @brief Enables use of MATLAB Compiler and build of MEX-files.
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_MATLABTOOLS_INCLUDED)
00014   return ()
00015 else ()
00016   set (__BASIS_MATLABTOOLS_INCLUDED TRUE)
00017 endif ()
00018 
00019 
00020 # ============================================================================
00021 # options
00022 # ============================================================================
00023 
00024 ## @addtogroup BasisSettings
00025 #  @{
00026 
00027 
00028 ## @brief Enable/Disable invocation of MATLAB Compiler in MATLAB mode.
00029 option (
00030   BASIS_MCC_MATLAB_MODE
00031   "Prefer MATLAB mode over standalone mode to invoke MATLAB Compiler."
00032   "ON" # prefer as it releases the license immediately once done
00033 )
00034 
00035 mark_as_advanced (BASIS_MCC_MATLAB_MODE)
00036 
00037 
00038 ## @}
00039 # end of Doxygen group
00040 
00041 
00042 # ============================================================================
00043 # build configuration
00044 # ============================================================================
00045 
00046 ## @addtogroup BasisSettings
00047 #  @{
00048 
00049 
00050 ## @brief Script used to invoke the MATLAB Compiler in MATLAB mode.
00051 set (BASIS_SCRIPT_MCC "${CMAKE_CURRENT_LIST_DIR}/runmcc.m")
00052 
00053 ## @brief Compile flags used to build MATLAB Compiler targets.
00054 set (
00055   BASIS_MCC_FLAGS
00056     "-v -R -singleCompThread"
00057   CACHE STRING
00058     "Common MATLAB Compiler flags (separated by ' '; use '\\' to mask ' ')."
00059 )
00060 
00061 ## @brief Compile flags used to build MEX-files using the MEX script.
00062 set (
00063   BASIS_MEX_FLAGS
00064     "-v"
00065   CACHE STRING
00066     "Common MEX switches (separated by ' '; use '\\' to mask ' ')."
00067 )
00068 
00069 ## @brief Timeout for building MATLAB Compiler targets.
00070 set (BASIS_MCC_TIMEOUT "600" CACHE STRING "Timeout for MATLAB Compiler execution")
00071 ## @brief Maximum number of retries on MATLAB Compiler license checkout.
00072 set (BASIS_MCC_RETRY_ATTEMPTS "4" CACHE STRING "Maximum number of retries on MATLAB Compiler license checkout error.")
00073 ## @brief Delay between retries to build MATLAB Compiler compiled targets on license checkout errors.
00074 set (BASIS_MCC_RETRY_DELAY "30" CACHE STRING "Delay between retries to build MATLAB Compiler compiled targets on license checkout error.")
00075 ## @brief Timeout for building MEX-file targets.
00076 set (BASIS_MEX_TIMEOUT "600" CACHE STRING "Timeout for MEX script execution")
00077 
00078 mark_as_advanced (BASIS_MCC_FLAGS)
00079 mark_as_advanced (BASIS_MCC_TIMEOUT)
00080 mark_as_advanced (BASIS_MCC_RETRY_ATTEMPTS)
00081 mark_as_advanced (BASIS_MCC_RETRY_DELAY)
00082 mark_as_advanced (BASIS_MEX_FLAGS)
00083 mark_as_advanced (BASIS_MEX_TIMEOUT)
00084 
00085 
00086 ## @}
00087 # end of Doxygen group
00088 
00089 
00090 # ============================================================================
00091 # utilities
00092 # ============================================================================
00093 
00094 # ----------------------------------------------------------------------------
00095 ## @brief Determine version of MATLAB installation.
00096 #
00097 # @param [out] VERSION Value returned by the "version" command of MATLAB or
00098 #                      an empty string if execution of MATLAB failed.
00099 #
00100 # @returns Sets the variable named by @p VERSION to the full MATLAB version.
00101 #
00102 # @ingroup CMakeUtilities
00103 function (basis_get_full_matlab_version VERSION)
00104   if (NOT MATLAB_EXECUTABLE)
00105     message (FATAL_ERROR "MATLAB_EXECUTABLE not found. Forgot to add MATLAB as dependency?")
00106   endif ()
00107 
00108   set (OUTPUT_FILE "${CMAKE_BINARY_DIR}/MatlabVersion.txt")
00109   # run matlab command to write return value of "version" command to text file
00110   if (NOT EXISTS "${OUTPUT_FILE}")
00111     set (CMD "${MATLAB_EXECUTABLE}" "-nodesktop" "-nosplash")
00112     if (WIN32)
00113       list (APPEND CMD "-automation")
00114     endif ()
00115     list (APPEND CMD "-r")
00116     set (MATLAB_CMD
00117       "fid = fopen ('${OUTPUT_FILE}', 'w')"
00118       "fprintf (fid, '%s', version)"
00119       "fclose (fid)"
00120       "exit"
00121     )
00122     message (STATUS "Determining MATLAB version...")
00123     execute_process (
00124       COMMAND         ${CMD} "${MATLAB_CMD}"
00125       RESULT_VARIABLE RETVAL
00126       OUTPUT_QUIET
00127       ERROR_QUIET
00128     )
00129     if (NOT RETVAL EQUAL 0)
00130       set (VERSION "" PARENT_SCOPE)
00131       message (STATUS "Determining MATLAB version... - failed")
00132       return ()
00133     endif ()
00134     message (STATUS "Determining MATLAB version... - done")
00135   endif ()
00136   # read MATLAB version from text file
00137   file (READ "${OUTPUT_FILE}" VERSION)
00138   # return
00139   set (VERSION "${VERSION}" PARENT_SCOPE)
00140 endfunction ()
00141 
00142 # ----------------------------------------------------------------------------
00143 ## @brief Determine version of MATLAB installation.
00144 #
00145 # @param [out] ARGN The first argument ARGV0 is set to the version of the
00146 #                   MATLAB installation, i.e., "7.9.0", for example, or an
00147 #                   empty string if execution of MATLAB failed.
00148 #                   If no output variable name is specified, the variable
00149 #                   MATLAB_VERSION is added to the cache if not present yet.
00150 #                   Note that if no output variable is given and MATLAB_VERSION
00151 #                   is already set, nothing is done.
00152 #
00153 # @returns Sets the variable named by the first argument to the determined
00154 #          MATLAB version.
00155 #
00156 # @ingroup CMakeUtilities
00157 function (basis_get_matlab_version)
00158   if (ARGC GREATER 1)
00159     message (FATAL_ERROR "basis_get_matlab_version (): Invalid number of arguments.")
00160   endif ()
00161   if (ARGC EQUAL 0 AND MATLAB_VERSION)
00162     return ()
00163   endif ()
00164   basis_get_full_matlab_version (VERSION)
00165   if (VERSION MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)")
00166     set (VERSION "${CMAKE_MATCH_1}")
00167   else ()
00168     set (VERSION "")
00169   endif ()
00170   if (ARGC EQUAL 1)
00171     set (${ARGV0} "${VERSION}" PARENT_SCOPE)
00172   else ()
00173     set (MATLAB_VERSION "${VERSION}" CACHE STRING "The version string of the MATLAB installation." FORCE)
00174     mark_as_advanced (MATLAB_VERSION)
00175   endif ()
00176 endfunction ()
00177 
00178 # ----------------------------------------------------------------------------
00179 ## @brief Determine release version of MATLAB installation.
00180 #
00181 # @param [out] ARGN The first argument ARGV0 is set to the release version of
00182 #                   the MATLAB installation, i.e., "R2009b", for example,
00183 #                   or an empty string if execution of MATLAB failed.
00184 #                   If no output variable name is specified, the variable
00185 #                   MATLAB_RELEASE is added to the cache if not present yet.
00186 #                   Note that if no output variable is given and MATLAB_RELEASE
00187 #                   is already set, nothing is done.
00188 #
00189 # @returns Sets the variable named by the first argument to the release version
00190 #          of MATLAB.
00191 #
00192 # @ingroup CMakeUtilities
00193 function (basis_get_matlab_release)
00194   if (ARGC GREATER 1)
00195     message (FATAL_ERROR "basis_get_matlab_release (): Invalid number of arguments.")
00196   endif ()
00197   if (ARGC EQUAL 0 AND MATLAB_RELEASE)
00198     return ()
00199   endif ()
00200   basis_get_full_matlab_version (VERSION)
00201   if (VERSION MATCHES ".*\\\((.+)\\\)")
00202     set (RELEASE "${CMAKE_MATCH_1}")
00203   else ()
00204     set (RELEASE "")
00205   endif ()
00206   if (ARGC EQUAL 1)
00207     set (${ARGV0} "${RELEASE}" PARENT_SCOPE)
00208   else ()
00209     set (MATLAB_RELEASE "${RELEASE}" CACHE STRING "The release version of the MATLAB installation." FORCE)
00210     mark_as_advanced (MATLAB_RELEASE)
00211   endif ()
00212 endfunction ()
00213 
00214 # ----------------------------------------------------------------------------
00215 ## @brief Determine extension of MEX-files for this architecture.
00216 #
00217 # @param [out] ARGN The first argument ARGV0 is set to the extension of
00218 #                   MEX-files (excluding '.'). If the CMake variable MEX_EXT
00219 #                   is set, its value is returned. Otherwise, this function
00220 #                   tries to determine it from the system information.
00221 #                   If the extension could not be determined, an empty string
00222 #                   is returned. If no argument is given, the extension is
00223 #                   cached as the variable MEX_EXT.
00224 #
00225 # @returns Sets the variable named by the first argument to the
00226 #          platform-specific extension of MEX-files.
00227 #
00228 # @ingroup CMakeUtilities
00229 function (basis_mexext)
00230   # default return value
00231   set (MEXEXT "${MEX_EXT}")
00232 
00233   # use MEXEXT if possible
00234   if (NOT MEXEXT AND MATLAB_MEXEXT_EXECUTABLE)
00235     execute_process (
00236       COMMAND         "${MATLAB_MEXEXT_EXECUTABLE}"
00237       RESULT_VARIABLE RETVAL
00238       OUTPUT_VARIABLE MEXEXT
00239       ERROR_QUIET
00240       OUTPUT_STRIP_TRAILING_WHITESPACE
00241     )
00242 
00243     if (RETVAL)
00244       set (MEXEXT "")
00245     endif ()
00246   endif ()
00247 
00248   # otherwise, determine extension given CMake variables describing the system
00249   if (NOT MEXEXT)
00250     if (CMAKE_SYSTEM_NAME MATCHES "Linux")
00251       if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
00252         set (MEXEXT "mexa64")
00253       elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "x86" OR
00254               CMAKE_SYSTEM_PROCESSOR MATCHES "i686")
00255         set (MEXEXT "mexglx")
00256       endif ()
00257     elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
00258       if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
00259         set (MEXEXT "mexw64")
00260       elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "x86" OR
00261               CMAKE_SYSTEM_PROCESSOR MATCHES "i686")
00262         set (MEXEXT "mexw32")
00263       endif ()
00264     elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
00265       if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
00266         set (MEXEXT "mexaci64")
00267       else ()
00268         set (MEXEXT "mexaci")
00269       endif ()
00270     elseif (CMAKE_SYSTEM_NAME MATCHES "SunOS")
00271       set (MEXEXT "mexs64")
00272     endif ()
00273   endif ()
00274 
00275   # return value
00276   if (ARGC GREATER 0)
00277     set ("${ARGV0}" "${MEXEXT}" PARENT_SCOPE)
00278   else ()
00279     if (NOT DEFINED MEX_EXT)
00280       set (MARKIT 1)
00281     else ()
00282       set (MARKIT 0)
00283     endif ()
00284     set (MEX_EXT "${MEXEXT}" CACHE STRING "The extension of MEX-files for this architecture." FORCE)
00285     if (MARKIT)
00286       mark_as_advanced (MEX_EXT)
00287     endif ()
00288   endif ()
00289 endfunction ()
00290 
00291 # ----------------------------------------------------------------------------
00292 ## @brief This function writes a MATLAB M-file with addpath() statements.
00293 #
00294 # This function writes an MATLAB M-file into the top directory of the build
00295 # tree which contains an addpath() statement for each directory that was added
00296 # via basis_include_directories().
00297 #
00298 # @returns Creates file add_<project>_paths.m in the current binary directory.
00299 #
00300 # @ingroup CMakeUtilities
00301 function (basis_create_addpaths_mfile)
00302   set (MFILE "${CMAKE_CURRENT_BINARY_DIR}/add_${PROJECT_NAME_LOWER}_paths.m")
00303   file (WRITE "${MFILE}" "% DO NOT edit. This file is automatically generated by BASIS.\n")
00304   basis_get_project_property (INCLUDE_DIRS PROPERTY PROJECT_INCLUDE_DIRS)
00305   foreach (P IN LISTS INCLUDE_DIRS)
00306     file (APPEND "${MFILE}" "addpath ('${P}');\n")
00307   endforeach ()
00308 endfunction ()
00309 
00310 # ============================================================================
00311 # MEX target
00312 # ============================================================================
00313 
00314 # ----------------------------------------------------------------------------
00315 ## @brief Add MEX target.
00316 #
00317 # This function is used to add a shared library target which is built
00318 # using the MATLAB MEX script (mex). It is invoked by basis_add_library().
00319 # Thus, it is recommended to use this function instead.
00320 #
00321 # An install command for the added library target is added by this function
00322 # as well. The MEX-file will be installed as part of the @p COMPONENT
00323 # in the directory INSTALL_LIBRARY_DIR on UNIX systems and INSTALL_RUNTIME_DIR
00324 # on Windows.
00325 #
00326 # @note The custom build command is not added yet by this function.
00327 #       Only a custom target which stores all the information required to
00328 #       setup this build command is added. The custom command is added
00329 #       by either basis_project_finalize() or basis_superproject_finalize().
00330 #       This way, the properties such as the OUTPUT_NAME of the custom
00331 #       target can be still modified.
00332 #
00333 # @param [in] TARGET_NAME Name of the target. If a source file is given
00334 #                         as first argument, the build target name is derived
00335 #                         from the name of this source file.
00336 # @param [in] ARGN        Remaining arguments such as in particular the
00337 #                         input source files. Moreover, the following arguments
00338 #                         are parsed:
00339 # @par
00340 # <table border="0">
00341 #   <tr>
00342 #     @tp @b COMPONENT name @endtp
00343 #     <td>Name of the component. Default: @c BASIS_LIBRARY_COMPONENT.</td>
00344 #   </tr>
00345 #   <tr>
00346 #     @tp @b MFILE file @endtp
00347 #     <td>MATLAB source file with function prototype and documentation of MEX-file.</td>
00348 #   </tr>
00349 #   <tr>
00350 #     @tp @b NO_EXPORT @endtp
00351 #     <td>Do not export the target.</td>
00352 #   </tr>
00353 # </table>
00354 #
00355 # @returns Adds custom target to build MEX-file using the MEX script.
00356 #
00357 # @sa basis_add_library()
00358 #
00359 # @ingroup CMakeUtilities
00360 function (basis_add_mex_target TARGET_NAME)
00361   # parse arguments
00362   CMAKE_PARSE_ARGUMENTS (
00363     ARGN
00364       "NO_EXPORT"
00365       "COMPONENT;MFILE"
00366       ""
00367     ${ARGN}
00368   )
00369 
00370   if (NOT ARGN_NO_EXPORT)
00371     set (ARGN_NO_EXPORT FALSE)
00372   endif ()
00373 
00374   if (NOT ARGN_COMPONENT)
00375     set (ARGN_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
00376   endif ()
00377   if (NOT ARGN_COMPONENT)
00378     set (ARGN_COMPONENT "Unspecified")
00379   endif ()
00380 
00381   if (ARGN_MFILE)
00382     get_filename_component (ARGN_MFILE "${ARGN_MFILE}" ABSOLUTE)
00383   endif ()
00384 
00385   set (SOURCES)
00386   get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
00387   if (NOT ARGN_UNPARSED_ARGUMENTS OR EXISTS "${S}")
00388     list (APPEND ARGN_UNPARSED_ARGUMENTS "${TARGET_NAME}")
00389     basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
00390   endif ()
00391   foreach (SOURCE ${ARGN_UNPARSED_ARGUMENTS})
00392     get_filename_component (P "${SOURCE}" ABSOLUTE)
00393     list (APPEND SOURCES "${P}")
00394   endforeach ()
00395 
00396   # check target name
00397   basis_check_target_name ("${TARGET_NAME}")
00398   basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
00399 
00400   if (BASIS_VERBOSE)
00401     message (STATUS "Adding MEX-file ${TARGET_UID}...")
00402   endif ()
00403 
00404   # required commands available ?
00405   if (NOT MATLAB_MEX_EXECUTABLE)
00406     message (FATAL_ERROR "MATLAB MEX script (mex) not found. It is required to build target ${TARGET_UID}."
00407                          " Forgot to add MATLAB as dependency? Otherwise, set MATLAB_MEX_EXECUTABLE manually and try again.")
00408   endif ()
00409  
00410   # MEX flags
00411   basis_mexext (MEXEXT)
00412 
00413   # configure .in source files
00414   basis_configure_sources (SOURCES ${SOURCES})
00415 
00416   # add custom target
00417   add_custom_target (${TARGET_UID} ALL SOURCES ${SOURCES})
00418 
00419   # set target properties required by basis_add_mex_target_finalize ()
00420   get_directory_property (INCLUDE_DIRS INCLUDE_DIRECTORIES)
00421   get_directory_property (LINK_DIRS LINK_DIRECTORIES)
00422 
00423   _set_target_properties (
00424     ${TARGET_UID}
00425     PROPERTIES
00426       BASIS_TYPE                "MEX"
00427       PREFIX                    ""
00428       SUFFIX                    ".${MEXEXT}"
00429       VERSION                   "${PROJECT_VERSION}"
00430       SOVERSION                 "${PROJECT_SOVERSION}"
00431       SOURCE_DIRECTORY          "${CMAKE_CURRENT_SOURCE_DIR}"
00432       BINARY_DIRECTORY          "${CMAKE_CURRENT_BINARY_DIR}"
00433       RUNTIME_OUTPUT_DIRECTORY  "${BINARY_RUNTIME_DIR}"
00434       LIBRARY_OUTPUT_DIRECTORY  "${BINARY_LIBRARY_DIR}"
00435       RUNTIME_INSTALL_DIRECTORY "${RUNTIME_INSTALL_DIR}"
00436       LIBRARY_INSTALL_DIRECTORY "${INSTALL_LIBRARY_DIR}"
00437       BASIS_INCLUDE_DIRECTORIES "${INCLUDE_DIRS}"
00438       BASIS_LINK_DIRECTORIES    "${LINK_DIRS}"
00439       COMPILE_FLAGS             "${BASIS_MEX_FLAGS}"
00440       LINK_FLAGS                ""
00441       LINK_DEPENDS              ""
00442       LIBRARY_COMPONENT         "${ARGN_COMPONENT}"
00443       MFILE                     "${ARGN_MFILE}"
00444       TEST                      "0" # MEX-files cannot be used for testing only yet
00445       NO_EXPORT                 "${ARGN_NO_EXPORT}"
00446   )
00447 
00448   # add target to list of targets
00449   basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
00450 
00451   if (BASIS_VERBOSE)
00452     message (STATUS "Adding MEX-file ${TARGET_UID}... - done")
00453   endif ()
00454 endfunction ()
00455 
00456 # ----------------------------------------------------------------------------
00457 ## @brief Finalize addition of MEX target.
00458 #
00459 # This function uses the properties of the custom MEX-file target added by
00460 # basis_add_mex_target() to create the custom build command and adds this
00461 # build command as dependency of this added target.
00462 #
00463 # @param [in] TARGET_UID "Global" target name. If this function is used
00464 #                        within the same project as basis_add_mex_target(),
00465 #                        the "local" target name may be given alternatively.
00466 #
00467 # @returns Adds custom targets corresponding to the custom target added by
00468 #          basis_add_mex_target() which actually perform the invocation of
00469 #          the MEX script.
00470 #
00471 # @sa basis_add_mex_target()
00472 #
00473 # @ingroup CMakeUtilities
00474 function (basis_add_mex_target_finalize TARGET_UID)
00475   # if used within (sub-)project itself, allow user to specify "local" target name
00476   basis_get_target_uid (TARGET_UID "${TARGET_UID}")
00477 
00478   # finalized before ?
00479   if (TARGET "_${TARGET_UID}")
00480     return ()
00481   endif ()
00482 
00483   # does this target exist ?
00484   if (NOT TARGET "${TARGET_UID}")
00485     message (FATAL_ERROR "Unknown target ${TARGET_UID}.")
00486     return ()
00487   endif ()
00488 
00489   # get target properties
00490   basis_get_target_name (TARGET_NAME ${TARGET_UID})
00491 
00492   set (
00493     PROPERTIES
00494       "BASIS_TYPE"
00495       "SOURCE_DIRECTORY"
00496       "BINARY_DIRECTORY"
00497       "RUNTIME_OUTPUT_DIRECTORY"
00498       "LIBRARY_OUTPUT_DIRECTORY"
00499       "RUNTIME_INSTALL_DIRECTORY"
00500       "LIBRARY_INSTALL_DIRECTORY"
00501       "PREFIX"
00502       "OUTPUT_NAME"
00503       "SUFFIX"
00504       "VERSION"
00505       "SOVERSION"
00506       "BASIS_INCLUDE_DIRECTORIES"
00507       "BASIS_LINK_DIRECTORIES"
00508       "SOURCES"
00509       "COMPILE_FLAGS"
00510       "LINK_DEPENDS"
00511       "LINK_FLAGS"
00512       "LIBRARY_COMPONENT"
00513       "MFILE"
00514       "TEST"
00515       "NO_EXPORT"
00516   )
00517 
00518   foreach (PROPERTY ${PROPERTIES})
00519     get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
00520   endforeach ()
00521 
00522   if (NOT BASIS_TYPE MATCHES "^MEX$")
00523     message (FATAL_ERROR "Target ${TARGET_UID} has invalid BASIS_TYPE: ${BASIS_TYPE}")
00524   endif ()
00525 
00526   if (BASIS_VERBOSE)
00527     message (STATUS "Adding build command for MEX-file ${TARGET_UID}...")
00528   endif ()
00529 
00530   # build directory
00531   list (GET SOURCES 0 BUILD_DIR)
00532   set (BUILD_DIR "${BUILD_DIR}.dir")
00533 
00534   list (REMOVE_AT SOURCES 0)
00535 
00536   # output name
00537   if (NOT OUTPUT_NAME)
00538     set (OUTPUT_NAME "${TARGET_NAME}")
00539   endif ()
00540   if (PREFIX)
00541     set (OUTPUT_NAME "${PREFIX}${OUTPUT_NAME}")
00542   endif ()
00543   if (SUFFIX)
00544     set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
00545   endif ()
00546 
00547   # initialize dependencies of custom build command
00548   set (DEPENDS ${SOURCES})
00549 
00550   # get list of libraries to link to
00551   set (LINK_LIBS)
00552 
00553   foreach (LIB ${LINK_DEPENDS})
00554     basis_get_target_uid (UID "${LIB}")
00555     if (TARGET ${UID})
00556       basis_get_target_location (LIB_FILE ${UID} ABSOLUTE)
00557       list (APPEND DEPENDS ${UID})
00558     else ()
00559       set (LIB_FILE "${LIB}")
00560     endif ()
00561     list (APPEND LINK_LIBS "${LIB_FILE}")
00562   endforeach ()
00563 
00564   get_filename_component (OUTPUT_NAME_WE "${OUTPUT_NAME}" NAME_WE)
00565 
00566   # decompose user supplied MEX switches
00567   macro (extract VAR)
00568     string (REGEX REPLACE "${VAR}=\"([^\"]+)\"|${VAR}=([^\" ])*" "" COMPILE_FLAGS "${COMPILE_FLAGS}")
00569     if (CMAKE_MATCH_1)
00570       set (${VAR} "${CMAKE_MATCH_1}")
00571     elseif (CMAKE_MATCH_2)
00572       set (${VAR} "${CMAKE_MATCH_2}")
00573     else ()
00574       set (${VAR})
00575     endif ()
00576   endmacro ()
00577 
00578   extract (CC)
00579   extract (CFLAGS)
00580   extract (CXX)
00581   extract (CXXFLAGS)
00582   extract (CLIBS)
00583   extract (CXXLIBS)
00584   extract (LD)
00585   extract (LDXX)
00586   extract (LDFLAGS)
00587   extract (LDCXXFLAGS)
00588 
00589   if (LINK_FLAGS)
00590     set (LDFLAGS "${LDFLAGS} ${LINK_FLAGS}")
00591   endif ()
00592 
00593   # set defaults for not provided options
00594   if (NOT CC)
00595     set (CC "${CMAKE_C_COMPILER}")
00596   endif ()
00597   if (NOT CFLAGS)
00598     set (CFLAGS "${CMAKE_C_FLAGS}")
00599   endif ()
00600   if (NOT CFLAGS MATCHES "( |^)-fPIC( |$)")
00601     set (CFLAGS "-fPIC ${CFLAGS}")
00602   endif ()
00603   if (NOT CXX)
00604     set (CXX "${CMAKE_CXX_COMPILER}")
00605   endif ()
00606   if (NOT CXXFLAGS)
00607     set (CXXFLAGS "${CMAKE_CXX_FLAGS}")
00608   endif ()
00609   if (NOT CXXFLAGS MATCHES "( |^)-fPIC( |$)")
00610     set (CXXFLAGS "-fPIC ${CXXFLAGS}")
00611   endif ()
00612   if (NOT LD)
00613     set (LD "${CMAKE_CXX_COMPILER}") # do not use CMAKE_LINKER here
00614   endif ()
00615   if (NOT LDFLAGS)
00616     set (LDFLAGS "\$LDFLAGS ${CMAKE_SHARED_LINKER_FLAGS}")
00617   endif ()
00618 
00619   # We chose to use CLIBS and CXXLIBS instead of the -L and -l switches
00620   # to add also link libraries added via basis_target_link_libraries ()
00621   # because the MEX script will not use these arguments if CLIBS or CXXLIBS
00622   # is set. Moreover, the -l switch can only be used to link to a shared
00623   # library and not a static one (on UNIX).
00624   #foreach (LIB ${LINK_LIBS})
00625   #  if (LIB MATCHES "[/\\\.]")
00626   #    set (CXXLIBS "${CXXLIBS} ${LIB}")
00627   #  endif ()
00628   #endforeach ()
00629 
00630   # get remaining switches
00631   basis_string_to_list (MEX_USER_ARGS "${COMPILE_FLAGS}")
00632 
00633   # assemble MEX switches
00634   set (MEX_ARGS)
00635 
00636   list (APPEND MEX_ARGS "CC=${CC}" "CFLAGS=${CFLAGS}")           # C compiler and flags
00637   if (CLIBS)
00638     list (APPEND MEX_ARGS "CLIBS=${CLIBS}")                      # C link libraries
00639   endif ()
00640   list (APPEND MEX_ARGS "CXX=${CXX}" "CXXFLAGS=${CXXFLAGS}")     # C++ compiler and flags
00641   if (CXXLIBS)
00642     list (APPEND MEX_ARGS "CXXLIBS=${CXXLIBS}")                  # C++ link libraries
00643   endif ()
00644   if (LD)
00645     list (APPEND MEX_ARGS "LD=${LD}")                            # C linker
00646   endif ()
00647   if (LDFLAGS)
00648     list (APPEND MEX_ARGS "LDFLAGS=${LDFLAGS}")                  # C link flags
00649   endif ()
00650   if (LDCXX)
00651     list (APPEND MEX_ARGS "LDCXX=${LDCXX}")                      # C++ linker
00652   endif ()
00653   if (LDCXXFLAGS)
00654     list (APPEND MEX_ARGS "LDCXXFLAGS=${LDCXXFLAGS}")            # C++ link flags
00655   endif ()
00656   list (APPEND MEX_ARGS "-outdir" "${BUILD_DIR}")                # output directory
00657   list (APPEND MEX_ARGS "-output" "${OUTPUT_NAME_WE}")           # output name (w/o extension)
00658   foreach (INCLUDE_PATH ${BASIS_INCLUDE_DIRECTORIES})            # include directories
00659     list (FIND MEX_ARGS "-I${INCLUDE_PATH}" IDX)                 # as specified via
00660     if (INCLUDE_PATH AND IDX EQUAL -1)                           # basis_include_directories ()
00661       list (APPEND MEX_ARGS "-I${INCLUDE_PATH}")
00662     endif ()
00663   endforeach ()
00664   foreach (LIBRARY_PATH ${BASIS_LINK_DIRECTORIES})               # link directories
00665     list (FIND MEX_ARGS "-L${LIBRARY_PATH}" IDX)                 # as specified via
00666     if (LIBRARY_PATH AND IDX EQUAL -1)                           # basis_link_directories ()
00667       list (APPEND MEX_ARGS "-L${LIBRARY_PATH}")
00668     endif ()
00669   endforeach ()
00670   foreach (LIBRARY ${LINK_LIBS})                                 # link libraries
00671     get_filename_component (LINK_DIR "${LIBRARY}" PATH)         # as specified via
00672     get_filename_component (LINK_LIB "${LIBRARY}" NAME_WE)      # basis_target_link_libraries ()
00673     string (REGEX REPLACE "^-l" "" LINK_LIB "${LINK_LIB}")
00674     if (UNIX)
00675       string (REGEX REPLACE "^lib" "" LINK_LIB "${LINK_LIB}")
00676     endif ()
00677     list (FIND MEX_ARGS "-L${LINK_DIR}" IDX)
00678     if (LINK_DIR AND IDX EQUAL -1)
00679       list (APPEND MEX_ARGS "-L${LINK_DIR}")
00680     endif ()
00681     list (FIND MEX_ARGS "-l${LINK_LIB}" IDX)
00682     if (LINK_LIB AND IDX EQUAL -1)
00683       list (APPEND MEX_ARGS "-l${LINK_LIB}")
00684     endif ()
00685   endforeach ()
00686   list (APPEND MEX_ARGS ${MEX_USER_ARGS})                        # other user switches
00687   list (APPEND MEX_ARGS ${SOURCES})                              # source files
00688 
00689   # build command for invocation of MEX script
00690   set (BUILD_CMD     "${MATLAB_MEX_EXECUTABLE}" ${MEX_ARGS})
00691   set (BUILD_LOG     "${BUILD_DIR}/mexBuild.log")
00692   set (BUILD_OUTPUT  "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
00693   set (BUILD_OUTPUTS "${BUILD_OUTPUT}")
00694 
00695   if (MFILE)
00696     set (BUILD_MFILE "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME_WE}.m")
00697     list (APPEND BUILD_OUTPUTS "${BUILD_MFILE}")
00698   else ()
00699     set (BUILD_MFILE)
00700   endif ()
00701 
00702   # relative paths used for comments of commands
00703   file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${BUILD_DIR}/${OUTPUT_NAME}")
00704 
00705   # add custom command to build executable using MEX script
00706   add_custom_command (
00707     OUTPUT "${BUILD_OUTPUT}"
00708     # rebuild when input sources were modified
00709     DEPENDS ${DEPENDS}
00710     # invoke MEX script, wrapping the command in CMake execute_process()
00711     # command allows for inspection of command output for error messages
00712     # and specification of timeout
00713     COMMAND "${CMAKE_COMMAND}"
00714             "-DCOMMAND=${BUILD_CMD}"
00715             "-DWORKING_DIRECTORY=${BUILD_DIR}"
00716             "-DTIMEOUT=${BASIS_MEX_TIMEOUT}"
00717             "-DERROR_EXPRESSION=[E|e]rror"
00718             "-DOUTPUT_FILE=${BUILD_LOG}"
00719             "-DERROR_FILE=${BUILD_LOG}"
00720             "-DVERBOSE=OFF"
00721             "-DLOG_ARGS=ON"
00722             "-P" "${BASIS_SCRIPT_EXECUTE_PROCESS}"
00723     # post-build command
00724     COMMAND "${CMAKE_COMMAND}" -E copy   "${BUILD_DIR}/${OUTPUT_NAME}" "${BUILD_OUTPUT}"
00725     COMMAND "${CMAKE_COMMAND}" -E remove "${BUILD_DIR}/${OUTPUT_NAME}"
00726     # inform user where build log can be found
00727     COMMAND "${CMAKE_COMMAND}" -E echo "Build log written to ${BUILD_LOG}"
00728     # comment
00729     COMMENT "Building MEX-file ${REL}..."
00730     VERBATIM
00731   )
00732 
00733   if (BUILD_MFILE)
00734     add_custom_command (
00735       OUTPUT  "${BUILD_MFILE}"
00736       DEPENDS "${MFILE}"
00737       COMMAND "${CMAKE_COMMAND}" -E copy "${MFILE}" "${BUILD_MFILE}"
00738       COMMENT "Copying M-file of MEX-file ${REL}..."
00739     )
00740   endif ()
00741 
00742   # add custom target
00743   if (TARGET "_${TARGET_UID}")
00744     message (FATAL_ERROR "There is another target named _${TARGET_UID}. "
00745                          "BASIS uses target names starting with an underscore "
00746                          "for custom targets which are required to build MEX-files. "
00747                          "Do not use leading underscores in target names.")
00748   endif ()
00749 
00750   add_custom_target (
00751     _${TARGET_UID}
00752     DEPENDS ${BUILD_OUTPUTS}
00753     SOURCES ${SOURCES}
00754   )
00755 
00756   add_dependencies (${TARGET_UID} _${TARGET_UID})
00757 
00758   # cleanup on "make clean"
00759   set_property (
00760     DIRECTORY
00761     APPEND PROPERTY
00762       ADDITIONAL_MAKE_CLEAN_FILES
00763         "${BUILD_DIR}/${OUTPUT_NAME}"
00764         "${BUILD_OUTPUTS}"
00765         "${BUILD_LOG}"
00766   )
00767 
00768   # install MEX-file
00769   if (NOT NO_EXPORT)
00770     if (TEST)
00771       basis_set_project_property (APPEND PROPERTY TEST_EXPORT_TARGETS "${TARGET_UID}")
00772     else ()
00773       basis_set_project_property (APPEND PROPERTY CUSTOM_EXPORT_TARGETS "${TARGET_UID}")
00774     endif ()
00775   endif ()
00776 
00777   install (
00778     FILES       ${BUILD_OUTPUTS}
00779     DESTINATION "${LIBRARY_INSTALL_DIRECTORY}"
00780     COMPONENT   "${LIBRARY_COMPONENT}"
00781   )
00782 
00783   if (BASIS_VERBOSE)
00784     message (STATUS "Adding build command for MEX-file ${TARGET_UID}... - done")
00785   endif ()
00786 endfunction ()
00787 
00788 # ============================================================================
00789 # MATLAB Compiler target
00790 # ============================================================================
00791 
00792 # ----------------------------------------------------------------------------
00793 ## @brief Add MATLAB Compiler target.
00794 #
00795 # This function is used to add an executable or library target which is built
00796 # using the MATLAB Compiler (MCC). It is invoked by basis_add_executable()
00797 # or basis_add_library(), respectively, when at least one M-file is given
00798 # as source file. Thus, it is recommended to use these functions instead.
00799 #
00800 # An install command for the added executable or library target is added by
00801 # this function as well. The executable will be installed as part of the
00802 # @p RUNTIME_COMPONENT in the directory @c INSTALL_RUNTIME_DIR. The runtime
00803 # library will be installed as part of the @p RUNTIME_COMPONENT in the directory
00804 # @c INSTALL_LIBRARY_DIR on UNIX systems and @c INSTALL_RUNTIME_DIR on Windows.
00805 # Static/import libraries will be installed as part of the @p LIBRARY_COMPONENT
00806 # in the directory @c INSTALL_ARCHIVE_DIR.
00807 #
00808 # @note The custom build command is not added yet by this function.
00809 #       Only a custom target which stores all the information required to
00810 #       setup this build command is added. The custom command is added
00811 #       by either basis_project_finalize() or basis_superproject_finalize().
00812 #       This way, the properties such as the @c OUTPUT_NAME of the custom
00813 #       target can be still modified.
00814 #
00815 # @note If this function is used within the @c PROJECT_TESTING_DIR, the built
00816 #       executable is output to the @c BINARY_TESTING_DIR directory tree instead.
00817 #       Moreover, no installation rules are added. Test executables are further
00818 #       not exported, regardless of whether NO_EXPORT is given or not.
00819 #
00820 # @param [in] TARGET_NAME Name of the target. If a source file is given
00821 #                         as first argument, the build target name is derived
00822 #                         from the name of this source file.
00823 # @param [in] ARGN        Remaining arguments such as in particular the
00824 #                         input source files. Moreover, the following arguments
00825 #                         are parsed:
00826 # @par
00827 # <table border="0">
00828 #   <tr>
00829 #     @tp @b TYPE type @endtp
00830 #     <td>Type of the target. Either @c EXECUTABLE (default) or @c LIBRARY.</td>
00831 #   </tr>
00832 #   <tr>
00833 #     @tp @b COMPONENT name @endtp
00834 #     <td>Name of the component. Default: @c BASIS_RUNTIME_COMPONENT if
00835 #         @p TYPE is @c EXECUTABLE or @c BASIS_LIBRARY_COMPONENT, otherwise.</td>
00836 #   </tr>
00837 #   <tr>
00838 #     @tp @b RUNTIME_COMPONENT name @endtp
00839 #     <td>Name of runtime component. Default: @p COMPONENT if specified or
00840 #         @c BASIS_RUNTIME_COMPONENT, otherwise.</td>
00841 #   </tr>
00842 #   <tr>
00843 #     @tp @b LIBRARY_COMPONENT name @endtp
00844 #     <td>Name of library component. Default: @p COMPONENT if specified or
00845 #         @c BASIS_LIBRARY_COMPONENT, otherwise.</td>
00846 #   </tr>
00847 #   <tr>
00848 #     @tp @b LIBEXEC @endtp
00849 #     <td>Specifies that the built executable is an auxiliary executable
00850 #         called by other executables only.</td>
00851 #   </tr>
00852 #   <tr>
00853 #     @tp @b NO_EXPORT @endtp
00854 #     <td>Do not export the target.</td>
00855 #   </tr>
00856 # </table>
00857 #
00858 # @returns Adds custom target which builds depending on the @p TYPE argument
00859 #          either an executable or a shared library using the MATLAB Compiler.
00860 #
00861 # @sa basis_add_executable()
00862 # @sa basis_add_library()
00863 #
00864 # @ingroup CMakeUtilities
00865 function (basis_add_mcc_target TARGET_NAME)
00866   # parse arguments
00867   CMAKE_PARSE_ARGUMENTS (
00868     ARGN
00869       "LIBEXEC;TEST;NO_EXPORT"
00870       "TYPE;COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT"
00871       ""
00872     ${ARGN}
00873   )
00874 
00875   basis_sanitize_for_regex (R "${PROJECT_TESTING_DIR}")
00876   if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${R}")
00877     set (ARGN_TEST TRUE)
00878   else ()
00879     if (ARGN_TEST)
00880       message (FATAL_ERROR "Executable ${TARGET_NAME} cannot have TEST property!"
00881                            "If it is a test executable, put it in ${PROJECT_TESTING_DIR}.")
00882     endif ()
00883     set (ARGN_TEST FALSE)
00884   endif ()
00885 
00886   if (ARGN_TEST)
00887     set (ARGN_NO_EXPORT TRUE)
00888   endif ()
00889   if (NOT ARGN_NO_EXPORT)
00890     set (ARGN_NO_EXPORT FALSE)
00891   endif ()
00892 
00893   if (NOT ARGN_TYPE)
00894     set (ARGN_TYPE "EXECUTABLE")
00895   else ()
00896     string (TOUPPER "${ARGN_TYPE}" ARGN_TYPE)
00897   endif ()
00898 
00899   if (NOT ARGN_TYPE MATCHES "^EXECUTABLE$|^LIBRARY$")
00900     message (FATAL_ERROR "Invalid type for MCC target ${TARGET_NAME}: ${ARGN_TYPE}")
00901   endif ()
00902 
00903   if (NOT ARGN_LIBRARY_COMPONENT AND ARGN_COMPONENT)
00904     set (ARGN_LIBRARY_COMPONENT "${ARGN_COMPONENT}")
00905   endif ()
00906   if (NOT ARGN_RUNTIME_COMPONENT AND ARGN_COMPONENT)
00907     set (ARGN_RUNTIME_COMPONENT "${ARGN_COMPONENT}")
00908   endif ()
00909 
00910   if (NOT ARGN_COMPONENT)
00911     if (ARGN_TYPE MATCHES "EXECUTABLE")
00912       set (ARGN_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
00913     else ()
00914       set (ARGN_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
00915     endif ()
00916   endif ()
00917   if (NOT ARGN_COMPONENT)
00918     set (ARGN_COMPONENT "Unspecified")
00919   endif ()
00920 
00921   if (NOT ARGN_LIBRARY_COMPONENT)
00922     set (ARGN_LIBRARY_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
00923   endif ()
00924   if (NOT ARGN_LIBRARY_COMPONENT)
00925     set (ARGN_LIBRARY_COMPONENT "Unspecified")
00926   endif ()
00927 
00928   if (NOT ARGN_RUNTIME_COMPONENT)
00929     set (ARGN_RUNTIME_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
00930   endif ()
00931   if (NOT ARGN_RUNTIME_COMPONENT)
00932     set (ARGN_RUNTIME_COMPONENT "Unspecified")
00933   endif ()
00934 
00935   set (SOURCES)
00936   get_filename_component (S "${TARGET_NAME}" ABSOLUTE)
00937   if (NOT ARGN_UNPARSED_ARGUMENTS OR EXISTS "${S}")
00938     list (APPEND ARGN_UNPARSED_ARGUMENTS "${TARGET_NAME}")
00939     basis_get_source_target_name (TARGET_NAME "${TARGET_NAME}" NAME_WE)
00940   endif ()
00941   foreach (ARG ${ARGN_UNPARSED_ARGUMENTS})
00942     get_filename_component (SOURCE "${ARG}" ABSOLUTE)
00943     list (APPEND SOURCES "${SOURCE}")
00944   endforeach ()
00945 
00946   # check target name
00947   basis_check_target_name ("${TARGET_NAME}")
00948   basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
00949 
00950   if (BASIS_VERBOSE)
00951     if (ARGN_TYPE MATCHES "LIBRARY")
00952       message (STATUS "Adding MATLAB library ${TARGET_UID}...")
00953       message (FATAL_ERROR "Build of MATLAB library from M-files not yet supported.")
00954       message (STATUS "Adding MATLAB library ${TARGET_UID}... - failed")
00955     else ()
00956       message (STATUS "Adding MATLAB executable ${TARGET_UID}...")
00957     endif ()
00958   endif ()
00959 
00960   # required commands available ?
00961   if (NOT MATLAB_MCC_EXECUTABLE)
00962     message (FATAL_ERROR "MATLAB Compiler not found. It is required to build target ${TARGET_UID}."
00963                          " Forgot to add MATLAB as dependency? Otherwise, set MATLAB_MCC_EXECUTABLE manually and try again.")
00964   endif ()
00965  
00966   # MCC flags
00967   set (COMPILE_FLAGS)
00968 
00969   if (BASIS_MCC_FLAGS)
00970     string (REPLACE "\\ "    "&nbsp;" COMPILE_FLAGS "${BASIS_MCC_FLAGS}")
00971     string (REPLACE " "      ";"      COMPILE_FLAGS "${COMPILE_FLAGS}")
00972     string (REPLACE "&nbsp;" " "      COMPILE_FLAGS "${COMPILE_FLAGS}")
00973   endif ()
00974 
00975   # configure .in source files
00976   basis_configure_sources (SOURCES ${SOURCES})
00977 
00978   # add custom target
00979   add_custom_target (${TARGET_UID} ALL SOURCES ${SOURCES})
00980 
00981   # set target properties required by basis_add_mcc_target_finalize ()
00982   if (ARGN_TYPE MATCHES "LIBRARY")
00983     set (TYPE "MCC_LIBRARY")
00984   else ()
00985     set (TYPE "MCC_EXECUTABLE")
00986     if (ARGN_TEST)
00987       set (RUNTIME_INSTALL_DIR "")
00988       set (RUNTIME_OUTPUT_DIR  "${TESTING_RUNTIME_DIR}")
00989     elseif (ARGN_LIBEXEC)
00990       set (RUNTIME_INSTALL_DIR "${INSTALL_LIBEXEC_DIR}")
00991       set (RUNTIME_OUTPUT_DIR  "${BINARY_LIBEXEC_DIR}")
00992     else ()
00993       set (RUNTIME_INSTALL_DIR "${INSTALL_RUNTIME_DIR}")
00994       set (RUNTIME_OUTPUT_DIR  "${BINARY_RUNTIME_DIR}")
00995     endif ()
00996   endif ()
00997 
00998   get_directory_property (INCLUDE_DIRS INCLUDE_DIRECTORIES)
00999   get_directory_property (LINK_DIRS LINK_DIRECTORIES)
01000 
01001   _set_target_properties (
01002     ${TARGET_UID}
01003     PROPERTIES
01004       BASIS_TYPE                "${TYPE}"
01005       VERSION                   "${PROJECT_VERSION}"
01006       SOVERSION                 "${PROJECT_SOVERSION}"
01007       SOURCE_DIRECTORY          "${CMAKE_CURRENT_SOURCE_DIR}"
01008       BINARY_DIRECTORY          "${CMAKE_CURRENT_BINARY_DIR}"
01009       RUNTIME_OUTPUT_DIRECTORY  "${RUNTIME_OUTPUT_DIR}"
01010       LIBRARY_OUTPUT_DIRECTORY  "${BINARY_LIBRARY_DIR}"
01011       RUNTIME_INSTALL_DIRECTORY "${RUNTIME_INSTALL_DIR}"
01012       LIBRARY_INSTALL_DIRECTORY "${INSTALL_LIBRARY_DIR}"
01013       BASIS_INCLUDE_DIRECTORIES "${INCLUDE_DIRS}"
01014       BASIS_LINK_DIRECTORIES    "${LINK_DIRS}"
01015       COMPILE_FLAGS             "${COMPILE_FLAGS}"
01016       LINK_DEPENDS              ""
01017       RUNTIME_COMPONENT         "${ARGN_RUNTIME_COMPONENT}"
01018       LIBRARY_COMPONENT         "${ARGN_LIBRARY_COMPONENT}"
01019       NO_EXPORT                 "${ARGN_NO_EXPORT}"
01020   )
01021 
01022   if (ARGN_LIBEXEC)
01023     _set_target_properties (${TARGET_UID} PROPERTIES LIBEXEC 1)
01024   else ()
01025     _set_target_properties (${TARGET_UID} PROPERTIES LIBEXEC 0)
01026   endif ()
01027 
01028   if (ARGN_TEST)
01029     _set_target_properties (${TARGET_UID} PROPERTIES TEST 1)
01030   else ()
01031     _set_target_properties (${TARGET_UID} PROPERTIES TEST 0)
01032   endif ()
01033 
01034   # add target to list of targets
01035   basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
01036 
01037   if (BASIS_VERBOSE)
01038     if (ARGN_TYPE MATCHES "LIBRARY")
01039       message (STATUS "Adding MATLAB library ${TARGET_UID}... - done")
01040     else ()
01041       message (STATUS "Adding MATLAB executable ${TARGET_UID}... - done")
01042     endif ()
01043   endif ()
01044 endfunction ()
01045 
01046 # ----------------------------------------------------------------------------
01047 ## @brief Finalize addition of MATLAB Compiler target.
01048 #
01049 # This function uses the properties of the custom MATLAB Compiler target
01050 # added by basis_add_mcc_target() to create the custom build command and
01051 # adds this build command as dependency of this added target.
01052 #
01053 # @param [in] TARGET_UID "Global" target name. If this function is used
01054 #                        within the same project as basis_add_mcc_target(),
01055 #                        the "local" target name may be given alternatively.
01056 #
01057 # @returns Adds custom target(s) which actually performs the invocation
01058 #          of the MATLAB Compiler using the values of the properties of
01059 #          the target with UID @p TARGET_UID.
01060 #
01061 # @sa basis_add_mcc_target()
01062 #
01063 # @ingroup CMakeUtilities
01064 function (basis_add_mcc_target_finalize TARGET_UID)
01065   # if used within (sub-)project itself, allow user to specify "local" target name
01066   basis_get_target_uid (TARGET_UID "${TARGET_UID}")
01067 
01068   # finalized before ?
01069   if (TARGET "_${TARGET_UID}")
01070     return ()
01071   endif ()
01072 
01073   # does this target exist ?
01074   if (NOT TARGET "${TARGET_UID}")
01075     message (FATAL_ERROR "Unknown target ${TARGET_UID}.")
01076     return ()
01077   endif ()
01078 
01079   # get target properties
01080   basis_get_target_name (TARGET_NAME ${TARGET_UID})
01081 
01082   set (
01083     PROPERTIES
01084       "BASIS_TYPE"
01085       "SOURCE_DIRECTORY"
01086       "BINARY_DIRECTORY"
01087       "RUNTIME_OUTPUT_DIRECTORY"
01088       "LIBRARY_OUTPUT_DIRECTORY"
01089       "RUNTIME_INSTALL_DIRECTORY"
01090       "LIBRARY_INSTALL_DIRECTORY"
01091       "PREFIX"
01092       "OUTPUT_NAME"
01093       "SUFFIX"
01094       "VERSION"
01095       "SOVERSION"
01096       "BASIS_INCLUDE_DIRECTORIES"
01097       "BASIS_LINK_DIRECTORIES"
01098       "SOURCES"
01099       "COMPILE_FLAGS"
01100       "LINK_DEPENDS"
01101       "RUNTIME_COMPONENT"
01102       "LIBRARY_COMPONENT"
01103       "LIBEXEC"
01104       "TEST"
01105       "NO_EXPORT"
01106   )
01107 
01108   foreach (PROPERTY ${PROPERTIES})
01109     get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
01110   endforeach ()
01111 
01112   if (NOT BASIS_TYPE MATCHES "^MCC_")
01113     message (FATAL_ERROR "Target ${TARGET_UID} has invalid BASIS_TYPE: ${BASIS_TYPE}")
01114   endif ()
01115 
01116   if (BASIS_TYPE MATCHES "MCC_LIBRARY")
01117     set (TYPE "LIBRARY")
01118   else ()
01119     set (TYPE "EXECUTABLE")
01120   endif ()
01121 
01122   if (BASIS_VERBOSE)
01123     if (TYPE MATCHES "LIBRARY")
01124       message (STATUS "Adding build command for MATLAB library ${TARGET_UID}...")
01125     elseif (TYPE MATCHES "EXECUTABLE")
01126       message (STATUS "Adding build command for MATLAB executable ${TARGET_UID}...")
01127     else ()
01128       message (FATAL_ERROR "Target ${TARGET_UID} has invalid TYPE: ${TYPE}")
01129     endif ()
01130   endif ()
01131 
01132   # build directory
01133   list (GET SOURCES 0 BUILD_DIR)
01134   set (BUILD_DIR "${BUILD_DIR}.dir")
01135 
01136   list (REMOVE_AT SOURCES 0)
01137 
01138   # output name
01139   if (NOT OUTPUT_NAME)
01140     set (OUTPUT_NAME "${TARGET_NAME}")
01141   endif ()
01142   if (PREFIX)
01143     set (OUTPUT_NAME "${PREFIX}${OUTPUT_NAME}")
01144   endif ()
01145   if (SUFFIX)
01146     set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
01147   endif ()
01148 
01149   # initialize dependencies of custom build command
01150   set (DEPENDS ${SOURCES})
01151 
01152   # get list of libraries to link to (e.g., MEX-file)
01153   set (LINK_LIBS)
01154 
01155   foreach (LIB ${LINK_DEPENDS})
01156     basis_get_target_uid (UID "${LIB}")
01157     if (TARGET ${UID})
01158       basis_get_target_location (LIB_FILE ${UID} ABSOLUTE)
01159       list (APPEND DEPENDS ${UID})
01160     else ()
01161       set (LIB_FILE "${LIB}")
01162     endif ()
01163     list (APPEND LINK_LIBS "${LIB_FILE}")
01164   endforeach ()
01165 
01166   # assemble build command
01167   set (MCC_ARGS ${COMPILE_FLAGS})                     # user specified flags
01168   foreach (INCLUDE_PATH ${BASIS_INCLUDE_DIRECTORIES}) # add directories added via
01169     list (FIND MCC_ARGS "${INCLUDE_PATH}" IDX)        # basis_include_directories ()
01170     if (EXISTS "${INCLUDE_PATH}" AND IDX EQUAL -1)    # function to search path
01171       list (APPEND MCC_ARGS "-I" "${INCLUDE_PATH}")
01172     endif ()
01173   endforeach ()
01174   list (FIND BASIS_INCLUDE_DIRECTORIES "${SOURCE_DIRECTORY}" IDX)
01175   if (IDX EQUAL -1)
01176     # add current source directory to search path,
01177     # needed for build in MATLAB mode as working directory
01178     # differs from the current source directory then
01179     list (APPEND MCC_ARGS "-I" "${SOURCE_DIRECTORY}")
01180   endif ()
01181   if (TYPE MATCHES "LIBRARY")
01182     list (APPEND MCC_ARGS "-l")                       # build library
01183   else ()
01184     list (APPEND MCC_ARGS "-m")                       # build standalone application
01185   endif ()
01186   list (APPEND MCC_ARGS "-d" "${BUILD_DIR}")          # output directory
01187   list (APPEND MCC_ARGS "-o" "${OUTPUT_NAME}")        # output name
01188   list (APPEND MCC_ARGS ${SOURCES})                   # source (M-)files
01189   foreach (LIB ${LINK_LIBS})                          # link libraries, e.g. MEX-files
01190     list (FIND MCC_ARGS "${LIB}" IDX)
01191     if (LIB AND IDX EQUAL -1)
01192       list (APPEND MCC_ARGS "-a" "${LIB}")
01193     endif ()
01194   endforeach ()
01195   #list (APPEND MCC_ARGS ${LINK_LIBS})                 # link libraries, e.g. MEX-files
01196 
01197   # build command for invocation of MATLAB Compiler in standalone mode
01198   set (BUILD_CMD   "${MATLAB_MCC_EXECUTABLE}" ${MCC_ARGS})
01199   set (BUILD_LOG   "${BUILD_DIR}/mccBuild.log")
01200   set (WORKING_DIR "${SOURCE_DIRECTORY}")
01201   set (MATLAB_MODE OFF)
01202 
01203   # build command for invocation of MATLAB Compiler in MATLAB mode
01204   if (BASIS_MCC_MATLAB_MODE)
01205     set (MATLAB_MODE ON)
01206 
01207     if (NOT MATLAB_EXECUTABLE)
01208       message (WARNING "MATLAB executable not found. It is required to build target ${TARGET_UID} in MATLAB mode."
01209                        " Forgot to MATLAB as dependency? Otherwise, set MATLAB_EXECUTABLE manually and try again or set BASIS_MCC_MATLAB_MODE to OFF."
01210                        " Will build target ${TARGET_UID} in standalone mode instead.")
01211       set (MATLAB_MODE OFF)
01212     endif ()
01213 
01214     if (MATLAB_MODE)
01215       get_filename_component (WORKING_DIR "${BASIS_SCRIPT_MCC}" PATH)
01216       get_filename_component (MFUNC       "${BASIS_SCRIPT_MCC}" NAME_WE)
01217 
01218       set (MATLAB_CMD "${MFUNC} -q") # -q option quits MATLAB when build is finished
01219       foreach (MCC_ARG ${MCC_ARGS})
01220         set (MATLAB_CMD "${MATLAB_CMD} ${MCC_ARG}")
01221       endforeach ()
01222 
01223       set (
01224         BUILD_CMD
01225           "${MATLAB_EXECUTABLE}" # run MATLAB
01226           "-nosplash"            # do not display splash screen on start up
01227           "-nodesktop"           # run in command line mode
01228           #"-nojvm"              # we do not need the Java Virtual Machine
01229           "-r" "${MATLAB_CMD}"   # MATLAB command which invokes MATLAB Compiler
01230        )
01231     endif ()
01232   endif ()
01233 
01234   # relative paths used for comments of commands
01235   file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${BUILD_DIR}/${OUTPUT_NAME}")
01236 
01237   # output files of build command
01238   if (TYPE MATCHES "LIBRARY")
01239     set (BUILD_OUTPUT "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
01240 
01241     set (
01242       POST_BUILD_COMMAND
01243         COMMAND "${CMAKE_COMMAND}" -E copy
01244                 "${BUILD_DIR}/${OUTPUT_NAME}"
01245                 "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
01246     )
01247 
01248     set (BUILD_COMMENT "Building MATLAB library ${REL}...")
01249   else ()
01250     set (BUILD_OUTPUT "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
01251 
01252     set (
01253       POST_BUILD_COMMAND
01254         COMMAND "${CMAKE_COMMAND}" -E copy
01255                 "${BUILD_DIR}/${OUTPUT_NAME}"
01256                 "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
01257     )
01258 
01259     set (BUILD_COMMENT "Building MATLAB executable ${REL}...")
01260   endif ()
01261 
01262   # add custom command to build executable using MATLAB Compiler
01263   add_custom_command (
01264     OUTPUT ${BUILD_OUTPUT}
01265     # rebuild when input sources were modified
01266     DEPENDS ${DEPENDS}
01267     # invoke MATLAB Compiler in either MATLAB or standalone mode
01268     # wrapping command in CMake execute_process () command allows for inspection
01269     # parsing of command output for error messages and specification of timeout
01270     COMMAND "${CMAKE_COMMAND}"
01271             "-DCOMMAND=${BUILD_CMD}"
01272             "-DWORKING_DIRECTORY=${WORKING_DIR}"
01273             "-DTIMEOUT=${BASIS_MCC_TIMEOUT}"
01274             "-DRETRY_EXPRESSION=License checkout failed"
01275             "-DRETRY_ATTEMPTS=${BASIS_MCC_RETRY_ATTEMPTS}"
01276             "-DRETRY_DELAY=${BASIS_MCC_RETRY_DELAY}"
01277             "-DERROR_EXPRESSION=[E|e]rror"
01278             "-DOUTPUT_FILE=${BUILD_LOG}"
01279             "-DERROR_FILE=${BUILD_LOG}"
01280             "-DVERBOSE=OFF"
01281             "-DLOG_ARGS=ON"
01282             "-P" "${BASIS_SCRIPT_EXECUTE_PROCESS}"
01283     # post build command(s)
01284     ${POST_BUILD_COMMAND}
01285     # inform user where build log can be found
01286     COMMAND "${CMAKE_COMMAND}" -E echo "Build log written to ${BUILD_LOG}"
01287     # comment
01288     COMMENT "${BUILD_COMMENT}"
01289     VERBATIM
01290   )
01291 
01292   # add custom target
01293   if (TARGET "_${TARGET_UID}")
01294     message (FATAL_ERROR "There is another target named _${TARGET_UID}. "
01295                          "BASIS uses target names starting with an underscore "
01296                          "for custom targets which are required to build executables or "
01297                          "shared libraries from MATLAB source files. "
01298                          "Do not use leading underscores in target names.")
01299   endif ()
01300 
01301   add_custom_target (
01302     _${TARGET_UID}
01303     DEPENDS ${BUILD_OUTPUT}
01304     SOURCES ${SOURCES}
01305   )
01306 
01307   add_dependencies (${TARGET_UID} _${TARGET_UID})
01308 
01309   # cleanup on "make clean"
01310   set_property (
01311     DIRECTORY
01312     APPEND PROPERTY
01313       ADDITIONAL_MAKE_CLEAN_FILES
01314         ${BUILD_OUTPUT}
01315         "${BUILD_DIR}/${OUTPUT_NAME}.prj"
01316         "${BUILD_DIR}/mccExcludedFiles.log"
01317         "${BUILD_DIR}/mccBuild.log"
01318         "${BUILD_DIR}/readme.txt"
01319   )
01320 
01321   if (TYPE MATCHES "LIBRARY")
01322   else ()
01323     set_property (
01324       DIRECTORY
01325       APPEND PROPERTY
01326         ADDITIONAL_MAKE_CLEAN_FILES
01327           "${BUILD_DIR}/${OUTPUT_NAME}"
01328           "${BUILD_DIR}/run_${OUTPUT_NAME}.sh"
01329           "${BUILD_DIR}/${OUTPUT_NAME}_main.c"
01330           "${BUILD_DIR}/${OUTPUT_NAME}_mcc_component_data.c"
01331     )
01332   endif ()
01333 
01334   # export target
01335   if (NOT NO_EXPORT)
01336     if (TEST)
01337       basis_set_project_property (APPEND PROPERTY TEST_EXPORT_TARGETS "${TARGET_UID}")
01338     else ()
01339       basis_set_project_property (APPEND PROPERTY CUSTOM_EXPORT_TARGETS "${TARGET_UID}")
01340     endif ()
01341   endif ()
01342 
01343   # install executable or library
01344   if (TYPE MATCHES "LIBRARY")
01345     # TODO
01346   else ()
01347     if (TEST)
01348       # TODO Install (selected?) test executables
01349     else ()
01350       install (
01351         PROGRAMS    ${BUILD_OUTPUT}
01352         DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
01353         COMPONENT   "${RUNTIME_COMPONENT}"
01354       )
01355     endif ()
01356   endif ()
01357 
01358   if (BASIS_VERBOSE)
01359     if (TYPE MATCHES "LIBRARY")
01360       message (STATUS "Adding build command for MATLAB library ${TARGET_UID}... - done")
01361     else ()
01362       message (STATUS "Adding build command for MATLAB executable ${TARGET_UID}... - done")
01363     endif ()
01364   endif ()
01365 endfunction ()