#
# @tp EXECUTABLE|LIBEXEC|SHARED @endtp
# Type of the MATLAB Compiler target which can be either a stand-alone
# executable, an auxiliary executable, or a shared library.
# (default: @c EXECUTABLE) |
#
#
# @tp @b COMPONENT name @endtp
# Name of component as part of which this executable or library will be
# installed if the @c RUNTIME_INSTALL_DIRECTORY or @c LIBRARY_INSTALL_DIRECTORY
# property is not "none". Used only if @p RUNTIME_COMPONENT or
# @p LIBRARY_COMPONENT not specified.
# (default: see @p RUNTIME_COMPONENT and @p LIBRARY_COMPONENT arguments) |
#
#
# @tp @b DESTINATION dir @endtp
# Installation directory for executable or runtime and library component
# of shared library relative to @c CMAKE_INSTALL_PREFIX. Used only if
# @p RUNTIME_DESTINATION or @p LIBRARY_DESTINATION not specified.
# If "none" (case-insensitive) is given as argument, no default installation
# rules are added. (default: see @p RUNTIME_DESTINATION and
# @p LIBRARY_DESTINATION arguments) |
#
#
# @tp @b LIBRARY_COMPONENT name @endtp
# Name of component as part of which import/static library will be intalled
# if a shared library is build and the @c LIBRARY_INSTALL_DIRECTORY property is
# not "none". (default: @c COMPONENT if specified or @c BASIS_LIBRARY_COMPONENT
# otherwise) |
#
#
# @tp @b LIBRARY_DESTINATION dir @endtp
# Installation directory of the library component relative to
# @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument or
# an executable is build, no installation rule for the library component is added.
# (default: @c INSTALL_ARCHIVE_DIR) |
#
#
# @tp @b HEADER_DESTINATION dir @endtp
# Installation directory of the library header file relative to
# @c INSTALL_INCLUDE_DIR. If "none" (case-insensitive) is given as argument or
# an executable is build, no installation rule for the library header file is added.
# (default: @c INSTALL_INCLUDE_DIR) |
#
#
# @tp @b RUNTIME_COMPONENT name @endtp
# Name of component as part of which executable or runtime library, respectively,
# will be installed if the @c RUNTIME_INSTALL_DIRECTORY property is not "none".
# (default: @c COMPONENT if specified or @c BASIS_RUNTIME_COMPONENT otherwise) |
#
#
# @tp @b RUNTIME_DESTINATION dir @endtp
# Installation directory of the executable or runtime component of the shared library
# relative to @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
# no installation rule for the runtime library is added.
# (default: @c INSTALL_LIBRARY_DIR for shared libraries on Unix or
# @c INSTALL_RUNTIME_DIR otherwise) |
#
#
# @tp @b [NO]EXPORT @endtp
# Whether to export this target. (default: @c TRUE) |
#
#
# @tp @b NO_BASIS_UTILITIES @endtp
# Specify that the BASIS utilities are not used by this executable or shared library
# and hence no link dependency on the BASIS utilities shall be added.
# (default: @c NOT BASIS_UTILITIES) |
#
#
# @tp @b USE_BASIS_UTILITIES @endtp
# Specify that the BASIS utilities are used and required by this executable
# or shared library, respectively, and hence a link dependency on the BASIS utilities
# must be added.
# (default: @c BASIS_UTILITIES) |
#
#
#
# @todo Consider NO_BASIS_UTILITIES and USE_BASIS_UTILITIES options after the BASIS
# utilities for MATLAB have been implemented.
#
# @returns Adds custom target which builds depending on the @p BASIS_TYPE property
# either an executable or a shared library using the MATLAB Compiler.
#
# @sa basis_add_executable()
# @sa basis_add_library()
#
# @ingroup CMakeUtilities
function (basis_add_mcc_target TARGET_NAME)
# check target name
basis_check_target_name ("${TARGET_NAME}")
basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
# parse arguments
CMAKE_PARSE_ARGUMENTS (
ARGN
"SHARED;EXECUTABLE;LIBEXEC;USE_BASIS_UTILITIES;NO_BASIS_UTILITIES;EXPORT;NOEXPORT"
"COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT;DESTINATION;RUNTIME_DESTINATION;LIBRARY_DESTINATION;HEADER_DESTINATION"
""
${ARGN}
)
set (SOURCES "${ARGN_UNPARSED_ARGUMENTS}")
basis_set_flag (ARGN EXPORT ${BASIS_EXPORT_DEFAULT})
if (ARGN_USE_BASIS_UTILITIES AND ARGN_NO_BASIS_UTILITIES)
message (FATAL_ERROR "Target ${TARGET_UID}: Options USE_BASIS_UTILITIES and NO_BASIS_UTILITIES are mutually exclusive!")
endif ()
if (ARGN_USE_BASIS_UTILITIES)
set (USES_BASIS_UTILITIES TRUE)
elseif (ARGN_NO_BASIS_UTILITIES)
set (USES_BASIS_UTILITIES FALSE)
else ()
set (USES_BASIS_UTILITIES ${BASIS_UTILITIES})
endif ()
if (ARGN_SHARED AND (ARGN_EXECUTABLE OR ARGN_LIBEXEC))
message (FATAL_ERROR "Target ${TARGET_UID}: Options SHARED and EXECUTABLE or LIBEXEC are mutually exclusive!")
endif ()
if (ARGN_SHARED)
set (TYPE LIBRARY)
else ()
set (TYPE EXECUTABLE)
endif ()
string (TOLOWER "${TYPE}" type)
message (STATUS "Adding MATLAB ${type} ${TARGET_UID}...")
# IS_TEST flag
basis_sanitize_for_regex (RE "${PROJECT_TESTING_DIR}")
if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${RE}")
set (IS_TEST TRUE)
else ()
set (IS_TEST FALSE)
endif ()
# output directory
if (IS_TEST)
set (LIBRARY_OUTPUT_DIRECTORY "${TESTING_LIBRARY_DIR}")
if (ARGN_LIBEXEC)
set (RUNTIME_OUTPUT_DIRECTORY "${TESTING_LIBEXEC_DIR}")
else ()
set (RUNTIME_OUTPUT_DIRECTORY "${TESTING_RUNTIME_DIR}")
endif ()
else ()
set (LIBRARY_OUTPUT_DIRECTORY "${BINARY_LIBRARY_DIR}")
if (ARGN_LIBEXEC)
set (RUNTIME_OUTPUT_DIRECTORY "${BINARY_LIBEXEC_DIR}")
else ()
set (RUNTIME_OUTPUT_DIRECTORY "${BINARY_RUNTIME_DIR}")
endif ()
endif ()
# installation component
if (ARGN_COMPONENT)
if (NOT ARGN_LIBRARY_COMPONENT)
set (ARGN_LIBRARY_COMPONENT "${ARGN_COMPONENT}")
endif ()
if (NOT ARGN_RUNTIME_COMPONENT)
set (ARGN_RUNTIME_COMPONENT "${ARGN_COMPONENT}")
endif ()
endif ()
if (NOT ARGN_RUNTIME_COMPONENT)
set (ARGN_RUNTIME_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
endif ()
if (NOT ARGN_RUNTIME_COMPONENT)
set (ARGN_RUNTIME_COMPONENT "Unspecified")
endif ()
if (NOT ARGN_LIBRARY_COMPONENT)
set (ARGN_LIBRARY_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
endif ()
if (NOT ARGN_LIBRARY_COMPONENT)
set (ARGN_LIBRARY_COMPONENT "Unspecified")
endif ()
# installation directories
if (ARGN_DESTINATION)
if (NOT ARGN_RUNTIME_DESTINATION)
set (ARGN_RUNTIME_DESTINATION "${ARGN_DESTINATION}")
endif ()
if (NOT ARGN_LIBRARY_DESTINATION)
set (ARGN_LIBRARY_DESTINATION "${ARGN_DESTINATION}")
endif ()
if (NOT ARGN_HEADER_DESTINATION)
set (ARGN_HEADER_DESTINATION "${ARGN_DESTINATION}")
endif ()
endif ()
if (NOT ARGN_RUNTIME_DESTINATION AND NOT IS_TEST)
if (ARGN_LIBEXEC)
set (ARGN_RUNTIME_DESTINATION "${INSTALL_LIBEXEC_DIR}")
else ()
set (ARGN_RUNTIME_DESTINATION "${INSTALL_RUNTIME_DIR}")
endif ()
endif ()
if (NOT ARGN_LIBRARY_DESTINATION AND NOT IS_TEST)
set (ARGN_LIBRARY_DESTINATION "${INSTALL_LIBRARY_DIR}")
endif ()
if (NOT ARGN_HEADER_DESTINATION AND NOT IS_TEST)
set (ARGN_HEADER_DESTINATION ".")
endif ()
if (ARGN_RUNTIME_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
set (ARGN_RUNTIME_DESTINATION)
endif ()
if (ARGN_LIBRARY_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
set (ARGN_LIBRARY_DESTINATION)
endif ()
if (ARGN_HEADER_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
set (ARGN_HEADER_DESTINATION)
elseif (NOT IS_ABSOLUTE ARGN_HEADER_DESTINATION)
set (ARGN_HEADER_DESTINATION "${BINARY_INCLUDE_DIR}/${ARGN_HEADER_DESTINATION}")
endif ()
# whether to compile and compilation flags (for mcc)
if ("^${TYPE}$" STREQUAL "^LIBRARY$")
set (COMPILE TRUE)
elseif (BASIS_COMPILE_MATLAB)
if (MATLAB_MCC_EXECUTABLE)
set (COMPILE TRUE)
else ()
set (COMPILE FALSE)
message (WARNING "MATLAB Compiler not found. Will generate a wrapper script for target"
" ${TARGET_UID} which executes the MATLAB code using the -r option of"
" the MATLAB interpreter. It is recommended to compile the MATLAB code"
" using the MATLAB Compiler if possible, however. Therefore, make sure"
" that the MATLAB Compiler is available and check the value of the"
" advanced MATLAB_MCC_EXECUTABLE variable in CMake."
"\nMake sure to include MATLAB{mcc} as project dependency.")
endif ()
else ()
set (COMPILE FALSE)
endif ()
if (WIN32 AND NOT COMPILE)
# TODO implement generation of Windows Command on Windows
set (CONTACT)
if (PROJECT_CONTACT)
set (CONTACT "\n\nYou may further want to contact ${PROJECT_CONTACT} in order to ask"
" for a binary distribution package which contains pre-build binaries"
" created using the MATLAB Compiler and download the MATLAB Compiler"
" Runtime only if no MATLAB Compiler license is available to you.")
basis_list_to_string (CONTACT ${CONTACT})
endif ()
if (NOT BASIS_COMPILE_MATLAB)
basis_update_value (BASIS_COMPILE_MATLAB ON)
endif ()
message (FATAL_ERROR "The optional generation of a Windows Command which executes"
" the MATLAB code using the -r option of the MATLAB interpreter"
" as an alternative to the build of the MATLAB sources using"
" the MATLAB Compiler is not yet implemented. You will have"
" to obtain a MATLAB Compiler license and set the advanced"
" MATLAB_MCC_EXECUTABLE variable in CMake or use this package"
" on a Unix system instead.${CONTACT}")
endif ()
if (COMPILE)
if (NOT MATLAB_MCC_EXECUTABLE)
message (FATAL_ERROR "MATLAB Compiler not found! It is required to build target ${TARGET_UID}."
" Ensure that MATLAB{mcc} is declared as project dependency"
" and check the setting of MATLAB_DIR and/or MATLAB_MCC_EXECUTABLE.")
endif ()
basis_add_mcc_options()
else ()
if (NOT MATLAB_EXECUTABLE)
message (FATAL_ERROR "MATLAB not found! It is required to build target ${TARGET_UID}."
" Ensure that MATLAB{matlab} is declared as project dependency"
" and check the setting of MATLAB_DIR and/or MATLAB_EXECUTABLE.")
endif ()
endif ()
if ("^${TYPE}$" STREQUAL "^EXECUTABLE$")
set (COMPILE_FLAGS "${BASIS_MCC_FLAGS}")
else ()
set (COMPILE_FLAGS "")
endif ()
# output file name prefix/suffix
if ("^${TYPE}$" STREQUAL "^EXECUTABLE$")
set (PREFIX)
if (WIN32 AND "^${COMPILE_FLAGS}$" STREQUAL "^NOMCC$")
set (SUFFIX ".cmd")
else ()
set (SUFFIX)
endif ()
else ()
if (WIN32)
set (PREFIX)
set (SUFFIX .lib) # link library file extension
elseif (APPLE)
set (PREFIX lib)
set (SUFFIX .dylib)
else ()
set (PREFIX lib)
set (SUFFIX .so)
endif ()
endif ()
# configure (.in) source files
basis_configure_sources (SOURCES ${SOURCES})
# add custom target
add_custom_target (${TARGET_UID} ALL SOURCES ${SOURCES})
basis_get_target_name (OUTPUT_NAME "${TARGET_UID}")
get_directory_property (INCLUDE_DIRS INCLUDE_DIRECTORIES)
get_directory_property (LINK_DIRS LINK_DIRECTORIES)
set_target_properties (
${TARGET_UID}
PROPERTIES
LANGUAGE "MATLAB"
BASIS_TYPE "MCC_${TYPE}"
BASIS_UTILITIES FALSE # TODO Implement utilities for MATLAB
BASIS_INCLUDE_DIRECTORIES "${INCLUDE_DIRS}"
BASIS_LINK_DIRECTORIES "${LINK_DIRS}"
BUILD_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}"
SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
LIBRARY_OUTPUT_DIRECTORY "${LIBRARY_OUTPUT_DIRECTORY}"
LIBRARY_INSTALL_DIRECTORY "${ARGN_LIBRARY_DESTINATION}"
LIBRARY_HEADER_DIRECTORY "${ARGN_HEADER_DESTINATION}"
LIBRARY_COMPONENT "${ARGN_LIBRARY_COMPONENT}"
RUNTIME_OUTPUT_DIRECTORY "${RUNTIME_OUTPUT_DIRECTORY}"
RUNTIME_INSTALL_DIRECTORY "${ARGN_RUNTIME_DESTINATION}"
RUNTIME_COMPONENT "${ARGN_RUNTIME_COMPONENT}"
PREFIX "${PREFIX}"
OUTPUT_NAME "${OUTPUT_NAME}"
SUFFIX "${SUFFIX}"
COMPILE_FLAGS "${COMPILE_FLAGS}"
COMPILE "${COMPILE}"
LINK_DEPENDS ""
EXPORT ${EXPORT}
LIBEXEC ${ARGN_LIBEXEC}
TEST ${IS_TEST}
)
# add target to list of targets
basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
message (STATUS "Adding MATLAB ${type} ${TARGET_UID}... - done")
endfunction ()
# ============================================================================
# custom build commands
# ============================================================================
# ----------------------------------------------------------------------------
## @brief Add custom command for build of MEX-file.
#
# This function is called by basis_finalize_targets() which in turn is called
# by basis_project_end(), i.e., the end of the root CMake configuration file
# of the (sub-)project.
#
# @param [in] TARGET_UID Name/UID of custom target added by basis_add_mex_file().
#
# @sa basis_add_mex_file()
#
# @ingroup CMakeUtilities
function (basis_build_mex_file TARGET_UID)
# does this target exist ?
basis_get_target_uid (TARGET_UID "${TARGET_UID}")
if (NOT TARGET "${TARGET_UID}")
message (FATAL_ERROR "Unknown build target: ${TARGET_UID}")
endif ()
if (BASIS_VERBOSE)
message (STATUS "Adding build command for target ${TARGET_UID}...")
endif ()
# get target properties
basis_get_target_name (TARGET_NAME ${TARGET_UID})
set (
PROPERTIES
BASIS_TYPE
BASIS_UTILITIES
BASIS_INCLUDE_DIRECTORIES
BASIS_LINK_DIRECTORIES
BUILD_DIRECTORY
SOURCE_DIRECTORY
BINARY_DIRECTORY
LIBRARY_OUTPUT_DIRECTORY
LIBRARY_INSTALL_DIRECTORY
LIBRARY_COMPONENT
PREFIX
OUTPUT_NAME
SUFFIX
COMPILE_FLAGS
LINK_DEPENDS
LINK_FLAGS
MFILE
EXPORT
SOURCES
)
get_target_property (IS_TEST ${TARGET_UID} TEST)
foreach (PROPERTY ${PROPERTIES})
get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
if (NOT ${PROPERTY})
set (${PROPERTY})
endif ()
endforeach ()
# sanity check of property values
if (NOT BASIS_TYPE MATCHES "^MEX$")
message (FATAL_ERROR "Target ${TARGET_UID}: Invalid BASIS_TYPE: ${BASIS_TYPE}")
endif ()
list (GET SOURCES 0 BUILD_DIR) # CMake <3.1 stores path to internal build directory here
if (BUILD_DIR MATCHES "CMakeFiles")
list (REMOVE_AT SOURCES 0)
endif ()
set (BUILD_DIR "${BUILD_DIRECTORY}.dir")
if (NOT SOURCES)
message (FATAL_ERROR "Target ${TARGET_UID}: Empty SOURCES list!"
" Have you accidentally modified this read-only property or"
" is your (newer) CMake version not compatible with BASIS?")
endif ()
if (NOT LIBRARY_COMPONENT)
set (LIBRARY_COMPONENT "Unspecified")
endif ()
if (MFILE)
if (NOT IS_ABSOLUTE "${MFILE}")
set (MFILE "${SOURCE_DIRECTORY}/${MFILE}")
endif ()
if (NOT EXISTS "${MFILE}")
message (FATAL_ERROR "M-file ${MFILE} of MEX-file target ${TARGET_UID} does not exist!")
endif ()
endif ()
# output name
if (NOT OUTPUT_NAME)
set (OUTPUT_NAME "${TARGET_NAME}")
endif ()
if (SUFFIX)
set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
endif ()
string (REGEX REPLACE "/+" "/" PREFIX "${PREFIX}")
string (REGEX REPLACE "/$" "" PREFIX "${PREFIX}")
if (PREFIX AND NOT PREFIX MATCHES "^/")
set (PREFIX "/${PREFIX}")
endif ()
# initialize dependencies of custom build command
set (DEPENDS ${SOURCES})
# get list of libraries to link to
set (LINK_LIBS)
foreach (LIB ${LINK_DEPENDS})
basis_get_target_uid (UID "${LIB}")
if (TARGET ${UID})
basis_get_target_location (LIB_FILE ${UID} ABSOLUTE)
string (REPLACE "<${BASIS_GE_CONFIG}>" "{CONFIG}" LIB_FILE "${LIB_FILE}")
list (APPEND DEPENDS ${UID})
else ()
set (LIB_FILE "${LIB}")
endif ()
list (APPEND LINK_LIBS "${LIB_FILE}")
endforeach ()
get_filename_component (OUTPUT_NAME_WE "${OUTPUT_NAME}" NAME_WE)
# decompose user supplied MEX switches
macro (extract VAR)
string (REGEX REPLACE "${VAR}=\"([^\"]+)\"|${VAR}=([^\" ])*" "" COMPILE_FLAGS "${COMPILE_FLAGS}")
if (CMAKE_MATCH_1)
set (${VAR} "${CMAKE_MATCH_1}")
elseif (CMAKE_MATCH_2)
set (${VAR} "${CMAKE_MATCH_2}")
else ()
set (${VAR})
endif ()
endmacro ()
if (UNIX)
extract (CC)
extract (CFLAGS)
extract (CXX)
extract (CXXFLAGS)
extract (CLIBS)
extract (CXXLIBS)
extract (LD)
extract (LDXX)
extract (LDFLAGS)
extract (LDCXXFLAGS)
if (LINK_FLAGS)
set (LDFLAGS "${LDFLAGS} ${LINK_FLAGS}")
endif ()
# set defaults for not provided options
if (NOT CC)
set (CC "${CMAKE_C_COMPILER}")
endif ()
if (NOT CFLAGS)
set (CFLAGS "${CMAKE_C_FLAGS}")
endif ()
if (NOT CFLAGS MATCHES "( |^)-fPIC( |$)")
set (CFLAGS "-fPIC ${CFLAGS}")
endif ()
if (NOT CXX)
set (CXX "${CMAKE_CXX_COMPILER}")
endif ()
if (NOT CXXFLAGS)
set (CXXFLAGS "${CMAKE_CXX_FLAGS}")
endif ()
if (NOT CXXFLAGS MATCHES "( |^)-fPIC( |$)")
set (CXXFLAGS "-fPIC ${CXXFLAGS}")
endif ()
if (NOT LD)
set (LD "${CMAKE_CXX_COMPILER}") # do not use CMAKE_LINKER here
endif ()
if (NOT LDFLAGS)
set (LDFLAGS "\$LDFLAGS ${CMAKE_SHARED_LINKER_FLAGS}")
endif ()
# We chose to use CLIBS and CXXLIBS instead of the -L and -l switches
# to add also link libraries added via basis_target_link_libraries()
# because the MEX script will not use these arguments if CLIBS or CXXLIBS
# is set. Moreover, the -l switch can only be used to link to a shared
# library and not a static one (on UNIX).
#foreach (LIB ${LINK_LIBS})
# if (LIB MATCHES "[/\\\.]")
# set (CXXLIBS "${CXXLIBS} ${LIB}")
# endif ()
#endforeach ()
endif ()
# get remaining switches
basis_string_to_list (MEX_USER_ARGS "${COMPILE_FLAGS}")
# assemble MEX switches
set (MEX_ARGS)
if (UNIX)
list (APPEND MEX_ARGS "CC=${CC}" "CFLAGS=${CFLAGS}") # C compiler and flags
if (CLIBS)
list (APPEND MEX_ARGS "CLIBS=${CLIBS}") # C link libraries
endif ()
list (APPEND MEX_ARGS "CXX=${CXX}" "CXXFLAGS=${CXXFLAGS}") # C++ compiler and flags
if (CXXLIBS)
list (APPEND MEX_ARGS "CXXLIBS=${CXXLIBS}") # C++ link libraries
endif ()
if (LD)
list (APPEND MEX_ARGS "LD=${LD}") # C linker
endif ()
if (LDFLAGS)
list (APPEND MEX_ARGS "LDFLAGS=${LDFLAGS}") # C link flags
endif ()
if (LDCXX)
list (APPEND MEX_ARGS "LDCXX=${LDCXX}") # C++ linker
endif ()
if (LDCXXFLAGS)
list (APPEND MEX_ARGS "LDCXXFLAGS=${LDCXXFLAGS}") # C++ link flags
endif ()
endif ()
list (APPEND MEX_ARGS "-outdir" "${BUILD_DIR}") # output directory
list (APPEND MEX_ARGS "-output" "${OUTPUT_NAME_WE}") # output name (w/o extension)
foreach (INCLUDE_PATH ${BASIS_INCLUDE_DIRECTORIES}) # include directories
list (FIND MEX_ARGS "-I${INCLUDE_PATH}" IDX) # as specified via
if (INCLUDE_PATH AND IDX EQUAL -1) # basis_include_directories()
list (APPEND MEX_ARGS "-I${INCLUDE_PATH}")
endif ()
endforeach ()
set (MEX_LIBPATH)
set (MEX_LIBS)
foreach (LINK_DIR ${BASIS_LINK_DIRECTORIES}) # link directories
if (WIN32)
string (REPLACE "/" "\\" LINK_DIR "${LINK_DIR}")
set (LINK_DIR "/LIBPATH:\\\"${LINK_DIR}\\\"")
else ()
set (LINK_DIR "-L${LINK_DIR}")
endif ()
list (APPEND MEX_LIBPATH "${LINK_DIR}") # as specified via basis_link_directories()
endforeach ()
foreach (LIBRARY ${LINK_LIBS}) # link libraries
get_filename_component (LINK_DIR "${LIBRARY}" PATH) # as specified via basis_target_link_libraries()
get_filename_component (LINK_LIB "${LIBRARY}" NAME)
string (REGEX REPLACE "\\.(so|dylib)(\\.[0-9]+)*$" "" LINK_LIB "${LINK_LIB}")
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
# cf. https://github.com/schuhschuh/cmake-basis/issues/443
string (REGEX REPLACE "\\.a(\\.[0-9]+)*$" "" LINK_LIB "${LINK_LIB}")
endif ()
string (REGEX REPLACE "^-l" "" LINK_LIB "${LINK_LIB}")
if (LINK_DIR)
if (WIN32)
string (REPLACE "/" "\\" LINK_DIR "${LINK_DIR}")
set (LINK_DIR "/LIBPATH:\\\"${LINK_DIR}\\\"")
else ()
set (LINK_DIR "-L${LINK_DIR}")
endif ()
list (APPEND MEX_LIBPATH "${LINK_DIR}")
endif ()
if (WIN32)
if (NOT LINK_LIB MATCHES "\\.lib$")
set (LINK_LIB "${LINK_LIB}.lib")
endif ()
else ()
string (REGEX REPLACE "^lib" "" LINK_LIB "${LINK_LIB}")
set (LINK_LIB "-l${LINK_LIB}")
endif ()
list (APPEND MEX_LIBS "${LINK_LIB}")
endforeach ()
if (MEX_LIBPATH)
list (REMOVE_DUPLICATES MEX_LIBPATH)
endif ()
# do not remove duplicate entries in MEX_LIBS which may be needed
# to resolve (cyclic) dependencies between statically linked libraries
# (cf. https://github.com/schuhschuh/cmake-basis/issues/444)
if (MEX_LIBPATH OR MEX_LIBS)
if (WIN32)
basis_list_to_delimited_string (MEX_LIBPATH " " NOAUTOQUOTE ${MEX_LIBPATH})
basis_list_to_delimited_string (MEX_LIBS " " ${MEX_LIBS})
list (APPEND MEX_ARGS "LINKFLAGS#$LINKFLAGS ${MEX_LIBPATH} ${MEX_LIBS}")
else ()
list (APPEND MEX_ARGS ${MEX_LIBPATH} ${MEX_LIBS})
endif ()
endif ()
# other user switches
list (APPEND MEX_ARGS ${MEX_USER_ARGS})
# source files
list (APPEND MEX_ARGS ${SOURCES})
# build command for invocation of MEX script
set (BUILD_CMD "${MATLAB_MEX_EXECUTABLE}" -v ${MEX_ARGS})
set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
set (BUILD_LOG "${BUILD_DIR}/build.log")
set (BUILD_OUTPUT "${LIBRARY_OUTPUT_DIRECTORY}${PREFIX}/${OUTPUT_NAME}")
set (BUILD_OUTPUTS "${BUILD_OUTPUT}")
if (MFILE)
set (BUILD_MFILE "${LIBRARY_OUTPUT_DIRECTORY}${PREFIX}/${OUTPUT_NAME_WE}.m")
list (APPEND BUILD_OUTPUTS "${BUILD_MFILE}")
else ()
set (BUILD_MFILE)
endif ()
# configure build script
configure_file ("${BASIS_SCRIPT_EXECUTE_PROCESS}" "${BUILD_SCRIPT}" @ONLY)
# relative paths used for comments of commands
file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${BUILD_OUTPUT}")
# add custom command to build executable using MEX script
add_custom_command (
OUTPUT "${BUILD_OUTPUT}"
# rebuild when input sources were modified
DEPENDS "${BUILD_SCRIPT}" "${CMAKE_CURRENT_LIST_FILE}" ${DEPENDS}
# invoke MEX script, wrapping the command in CMake execute_process()
# command allows for inspection of command output for error messages
# and specification of timeout
COMMAND "${CMAKE_COMMAND}"
"-DCONFIG=$<${BASIS_GE_CONFIG}>"
"-DWORKING_DIRECTORY=${BUILD_DIR}"
"-DTIMEOUT=${BASIS_MEX_TIMEOUT}"
"-DERROR_EXPRESSION=[E|e]rror:"
"-DOUTPUT_FILE=${BUILD_LOG}"
"-DERROR_FILE=${BUILD_LOG}"
"-DVERBOSE=OFF"
"-DLOG_ARGS=ON"
"-P" "${BUILD_SCRIPT}"
# post-build command
COMMAND "${CMAKE_COMMAND}" -E copy "${BUILD_DIR}/${OUTPUT_NAME}" "${BUILD_OUTPUT}"
COMMAND "${CMAKE_COMMAND}" -E remove "${BUILD_DIR}/${OUTPUT_NAME}"
# inform user where build log can be found
COMMAND "${CMAKE_COMMAND}" -E echo "Build log written to ${BUILD_LOG}"
# comment
COMMENT "Building MEX-file ${REL}..."
VERBATIM
)
if (BUILD_MFILE)
add_custom_command (
OUTPUT "${BUILD_MFILE}"
DEPENDS "${MFILE}"
COMMAND "${CMAKE_COMMAND}" -E copy "${MFILE}" "${BUILD_MFILE}"
COMMENT "Copying M-file of ${REL}..."
)
endif ()
# add custom target
add_custom_target (_${TARGET_UID} DEPENDS ${BUILD_OUTPUTS} SOURCES ${SOURCES})
add_dependencies (${TARGET_UID} _${TARGET_UID})
# cleanup on "make clean"
set_property (
DIRECTORY
APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${BUILD_DIR}/${OUTPUT_NAME}"
"${BUILD_OUTPUTS}"
"${BUILD_LOG}"
)
# export target
if (EXPORT)
basis_add_custom_export_target (${TARGET_UID} "${IS_TEST}")
endif ()
# install MEX-file
if (LIBRARY_INSTALL_DIRECTORY)
install (
FILES ${BUILD_OUTPUTS}
DESTINATION "${LIBRARY_INSTALL_DIRECTORY}${PREFIX}"
COMPONENT "${LIBRARY_COMPONENT}"
)
endif ()
if (BASIS_VERBOSE)
message (STATUS "Adding build command for target ${TARGET_UID}... - done")
endif ()
endfunction ()
# ----------------------------------------------------------------------------
## @brief Add custom command for build of MATLAB Compiler target.
#
# This function is called by basis_finalize_targets() which in turn is called
# by basis_project_end(), i.e., the end of the root CMake configuration file
# of the (sub-)project.
#
# @param [in] TARGET_UID Name/UID of custom target added by basis_add_mcc_target().
#
# @sa basis_add_mcc_target()
#
# @ingroup CMakeUtilities
function (basis_build_mcc_target TARGET_UID)
# does this target exist ?
basis_get_target_uid (TARGET_UID "${TARGET_UID}")
if (NOT TARGET "${TARGET_UID}")
message (FATAL_ERROR "Unknown target ${TARGET_UID}!")
endif ()
if (BASIS_VERBOSE)
message (STATUS "Adding build command for target ${TARGET_UID}...")
endif ()
# get target properties
basis_get_target_name (TARGET_NAME ${TARGET_UID})
set (
PROPERTIES
BASIS_TYPE
BASIS_UTILITIES
BASIS_INCLUDE_DIRECTORIES
BASIS_LINK_DIRECTORIES
BUILD_DIRECTORY
SOURCE_DIRECTORY
BINARY_DIRECTORY
LIBRARY_OUTPUT_DIRECTORY
LIBRARY_INSTALL_DIRECTORY
LIBRARY_HEADER_DIRECTORY
LIBRARY_COMPONENT
RUNTIME_OUTPUT_DIRECTORY
RUNTIME_INSTALL_DIRECTORY
RUNTIME_COMPONENT
PREFIX
OUTPUT_NAME
SUFFIX
SOURCES
COMPILE_FLAGS
COMPILE
LINK_DEPENDS
EXPORT
)
get_target_property (IS_TEST ${TARGET_UID} TEST)
foreach (PROPERTY ${PROPERTIES})
get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
if (NOT ${PROPERTY})
set (${PROPERTY})
endif ()
endforeach ()
# sanity checks of property values
set (EXECUTABLE FALSE)
set (LIBEXEC FALSE)
set (LIBRARY FALSE)
if (BASIS_TYPE MATCHES "^MCC_(EXECUTABLE|LIBEXEC|LIBRARY)$")
set (${CMAKE_MATCH_1} TRUE)
if (LIBEXEC)
set (EXECUTABLE TRUE)
endif ()
else ()
message (FATAL_ERROR "Target ${TARGET_UID}: Invalid BASIS_TYPE: ${BASIS_TYPE}")
endif ()
list (GET SOURCES 0 BUILD_DIR) # CMake <3.1 stores path to internal build directory here
if (BUILD_DIR MATCHES "CMakeFiles")
list (REMOVE_AT SOURCES 0)
endif ()
set (BUILD_DIR "${BUILD_DIRECTORY}.dir")
if (NOT SOURCES)
message (FATAL_ERROR "Target ${TARGET_UID}: Empty SOURCES list!"
" Have you accidentally modified this read-only property or"
" is your (newer) CMake version not compatible with BASIS?")
endif ()
list (GET SOURCES 0 MAIN_SOURCE) # entry point
if (NOT RUNTIME_COMPONENT)
set (RUNTIME_COMPONENT "Unspecified")
endif ()
if (NOT LIBRARY_COMPONENT)
set (LIBRARY_COMPONENT "Unspecified")
endif ()
# output name
if (NOT OUTPUT_NAME)
set (OUTPUT_NAME "${TARGET_NAME}")
endif ()
if (PREFIX)
set (OUTPUT_NAME "${PREFIX}${OUTPUT_NAME}")
endif ()
if (SUFFIX)
set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
endif ()
get_filename_component (OUTPUT_NAME_WE "${OUTPUT_NAME}" NAME_WE)
# MCC only allows alpha-numeric characters and underscores
# TODO: Figure out how to build a shared library without this restriction
# (cf. https://github.com/schuhschuh/cmake-basis/issues/410).
if (NOT OUTPUT_NAME MATCHES "[a-zA-Z][_a-zA-Z0-9]*")
message (FATAL_ERROR "Target ${TARGET_UID} has invalid output name ${OUTPUT_NAME}."
"MCC only allows alpha-numeric characters and underscores. "
"See GitHub issue #410 for updates on this restriction at\n"
"https://github.com/schuhschuh/cmake-basis/issues/410")
endif ()
set (MCC_OUTPUT_NAME "${OUTPUT_NAME}")
set (MCC_OUTPUT_NAME_WE "${OUTPUT_NAME_WE}")
#string (REGEX REPLACE "\\+|-" "_" MCC_OUTPUT_NAME "${OUTPUT_NAME}")
#get_filename_component (MCC_OUTPUT_NAME_WE "${MCC_OUTPUT_NAME}" NAME_WE)
# initialize dependencies of custom build command
set (DEPENDS ${SOURCES})
# build output file and comment
file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${BUILD_DIR}/${OUTPUT_NAME}")
if (LIBRARY)
set (BUILD_OUTPUT "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
set (BUILD_COMMENT "Building MATLAB library ${REL}...")
else ()
set (BUILD_OUTPUT "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
set (BUILD_COMMENT "Building MATLAB executable ${REL}...")
endif ()
# --------------------------------------------------------------------------
# assemble build command for build of executable wrapper script
if (EXECUTABLE AND NOT COMPILE)
# used to recognize source files which are located in the build tree
basis_sanitize_for_regex (BINARY_CODE_DIR_RE "${BINARY_CODE_DIR}")
# main MATLAB function and search path
get_filename_component (MATLAB_COMMAND "${MAIN_SOURCE}" NAME_WE)
get_filename_component (SOURCE_DIR "${MAIN_SOURCE}" PATH)
get_filename_component (SOURCE_PACKAGE "${SOURCE_DIR}" NAME)
if (SOURCE_PACKAGE MATCHES "^\\+")
get_filename_component (SOURCE_DIR "${SOURCE_DIR}" PATH)
set (MATLAB_COMMAND "${SOURCE_PACKAGE}.${MATLAB_COMMAND}")
string (REGEX REPLACE "^\\+" "" MATLAB_COMMAND "${MATLAB_COMMAND}")
else ()
set (SOURCE_PACKAGE "${MATLAB_COMMAND}")
endif ()
basis_get_relative_path (DIR "${PROJECT_SOURCE_DIR}" "${SOURCE_DIR}")
set (BINARY_DIR "${PROJECT_BINARY_DIR}/${DIR}") # location of configured sources
# output file
set (OUTPUT_FILE "${BUILD_OUTPUT}")
get_filename_component (OUTPUT_DIR "${OUTPUT_FILE}" PATH)
# installation
set (INSTALL_FILE "${BUILD_DIR}/${OUTPUT_NAME}") # file to be installed
set (INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${RUNTIME_INSTALL_DIRECTORY}") # location of installed wrapper
set (INSTALL_SOURCE_DIR "${INSTALL_MATLAB_LIBRARY_DIR}") # location of installed MATLAB sources
if (NOT SOURCE_PACKAGE MATCHES "^\\+")
set (INSTALL_SOURCE_DIR "${INSTALL_SOURCE_DIR}/${SOURCE_PACKAGE}")
endif ()
# startup file
if (SOURCE_PACKAGE MATCHES "^\\+")
set (BUILD_STARTUP_FILE "${BINARY_DIR}/${SOURCE_PACKAGE}/startup.m")
set (INSTALL_STARTUP_FILE "${BUILD_DIR}/startup.m")
set (INSTALL_STARTUP_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_SOURCE_DIR}/${SOURCE_PACKAGE}")
else ()
set (BUILD_STARTUP_FILE "${BINARY_DIR}/startup.m")
set (INSTALL_STARTUP_FILE "${BUILD_DIR}/startup.m")
set (INSTALL_STARTUP_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_SOURCE_DIR}")
endif ()
get_filename_component (BUILD_STARTUP_DIR "${BUILD_STARTUP_FILE}" PATH)
list (APPEND BUILD_OUTPUT "${BUILD_STARTUP_FILE}")
list (APPEND BUILD_OUTPUT "${INSTALL_STARTUP_FILE}")
# MATLAB search path
#
# The following paths are written to the startup M-file such
# that they can conveniently be added to the search path within an
# interactive MATLAB sesssion. The path to this startup file is
# added to the search path by the wrapper executable first, and
# then this startup file is evaluated which adds all additional
# paths. If no startup file is specified, all paths are added
# to the search path on the command-line in the wrapper script.
set (BUILD_MATLABPATH)
set (INSTALL_MATLABPATH)
# if any source file was configured and hence is located in the
# build tree instead of the source tree, add corresponding build
# tree path to BUILD_MATLABPATH as well
if (SOURCES MATCHES "^${BINARY_CODE_DIR_RE}")
file (RELATIVE_PATH REL "${BUILD_STARTUP_DIR}" "${BINARY_DIR}")
if (REL)
list (APPEND BUILD_MATLABPATH "${REL}")
else ()
list (APPEND BUILD_MATLABPATH ".")
endif ()
endif ()
list (APPEND BUILD_MATLABPATH "${SOURCE_DIR}")
# The following is not required because startup script is located
# in the same directory as the other sources and basis_generate_matlab_executable()
# adds this path automatically in order to run the startup script.
# Moreover, if anyone wants to run the startup script, they have to
# add this path manually or make it the current directory first.
#file (RELATIVE_PATH REL "${INSTALL_STARTUP_DIR}" "${CMAKE_INSTALL_PREFIX}/${INSTALL_SOURCE_DIR}")
#if (REL)
# list (APPEND INSTALL_MATLABPATH "${REL}")
#else ()
# list (APPEND INSTALL_MATLABPATH ".")
#endif ()
# link dependencies, i.e., MEX-files
foreach (LINK_DEPEND ${LINK_DEPENDS})
basis_get_target_uid (UID "${LINK_DEPEND}")
if (TARGET ${UID})
basis_get_target_location (LINK_DEPEND ${UID} ABSOLUTE)
if (LINK_DEPEND MATCHES "\\.mex")
get_filename_component (LINK_PATH "${LINK_DEPEND}" PATH)
list (APPEND BUILD_MATLABPATH "${LINK_PATH}")
list (APPEND DEPENDS ${UID})
endif ()
basis_get_target_location (LINK_DEPEND ${UID} POST_INSTALL)
basis_get_target_property (BUNDLED ${UID} BUNDLED)
basis_get_target_property (IMPORTED ${UID} IMPORTED)
if (NOT IMPORTED OR BUNDLED)
file (RELATIVE_PATH REL "${INSTALL_STARTUP_DIR}" "${LINK_DEPEND}")
if (REL)
set (LINK_DEPEND "${REL}")
else ()
set (LINK_DEPEND ".")
endif ()
endif ()
if (LINK_DEPEND MATCHES "\\.mex")
get_filename_component (LINK_PATH "${LINK_DEPEND}" PATH)
list (APPEND INSTALL_MATLABPATH "${LINK_PATH}")
endif ()
elseif (IS_ABSOLUTE "${LINK_DEPEND}")
if (IS_DIRECTORY "${LINK_DEPEND}")
list (APPEND BUILD_MATLABPATH "${LINK_DEPEND}")
list (APPEND INSTALL_MATLABPATH "${LINK_DEPEND}")
elseif (EXISTS "${LINK_DEPEND}" AND LINK_DEPEND MATCHES "\\.mex")
get_filename_component (LINK_PATH "${LINK_DEPEND}" PATH)
list (APPEND BUILD_MATLABPATH "${LINK_PATH}")
list (APPEND INSTALL_MATLABPATH "${LINK_PATH}")
endif ()
endif ()
endforeach ()
# cleanup directory paths
string (REGEX REPLACE "/+" "/" BUILD_MATLABPATH "${BUILD_MATLABPATH}")
string (REGEX REPLACE "/+" "/" INSTALL_MATLABPATH "${INSTALL_MATLABPATH}")
string (REGEX REPLACE "/(;|$)" "\\1" BUILD_MATLABPATH "${BUILD_MATLABPATH}")
string (REGEX REPLACE "/(;|$)" "\\1" INSTALL_MATLABPATH "${INSTALL_MATLABPATH}")
# remove duplicates
if (BUILD_MATLABPATH)
list (REMOVE_DUPLICATES BUILD_MATLABPATH)
endif ()
if (INSTALL_MATLABPATH)
list (REMOVE_DUPLICATES INSTALL_MATLABPATH)
endif ()
# configure build script
set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
configure_file ("${BASIS_MODULE_PATH}/generate_matlab_executable.cmake.in" "${BUILD_SCRIPT}" @ONLY)
# add custom command to build wrapper executable
add_custom_command (
OUTPUT ${BUILD_OUTPUT}
# rebuild when input sources were modified
MAIN_DEPENDENCY "${MAIN_SOURCE}"
DEPENDS "${BUILD_SCRIPT}" "${CMAKE_CURRENT_LIST_FILE}" ${DEPENDS}
# invoke MATLAB Compiler in either MATLAB or standalone mode
# wrapping command in CMake execute_process () command allows for inspection
# parsing of command output for error messages and specification of timeout
COMMAND "${CMAKE_COMMAND}" "-P" "${BUILD_SCRIPT}"
# comment
COMMENT "${BUILD_COMMENT}"
)
# install source files - preserving relative paths in SOURCE_DIR
foreach (SOURCE IN LISTS SOURCES)
get_filename_component (REL "${SOURCE}" PATH)
if (SOURCE MATCHES "^${BINARY_CODE_DIR_RE}")
basis_get_relative_path (REL "${BINARY_DIR}" "${REL}")
else ()
basis_get_relative_path (REL "${SOURCE_DIR}" "${REL}")
endif ()
if (REL MATCHES "^\\.?$|^\\.\\./")
install (
FILES "${SOURCE}"
DESTINATION "${INSTALL_SOURCE_DIR}"
COMPONENT "${RUNTIME_COMPONENT}"
)
else ()
install (
FILES "${SOURCE}"
DESTINATION "${INSTALL_SOURCE_DIR}/${REL}"
COMPONENT "${RUNTIME_COMPONENT}"
)
endif ()
endforeach ()
# --------------------------------------------------------------------------
# assemble build command for build using MATLAB Compiler
else ()
set (INSTALL_FILE "${BUILD_OUTPUT}") # file to be installed
# get list of libraries to link to (e.g., MEX-file)
set (LINK_LIBS)
foreach (LIB ${LINK_DEPENDS})
basis_get_target_uid (UID "${LIB}")
if (TARGET ${UID})
basis_get_target_location (LIB_FILE ${UID} ABSOLUTE)
string (REPLACE "<${BASIS_GE_CONFIG}>" "{CONFIG}" LIB_FILE "${LIB_FILE}")
list (APPEND DEPENDS ${UID})
else ()
set (LIB_FILE "${LIB}")
endif ()
list (APPEND LINK_LIBS "${LIB_FILE}")
endforeach ()
# MATLAB search path
foreach (P ${SOURCES})
get_filename_component (P "${P}" PATH)
list (APPEND MATLABPATH "${P}")
endforeach ()
list (APPEND MATLABPATH ${BASIS_INCLUDE_DIRECTORIES})
# MATLAB Compiler arguments
string (REGEX REPLACE " +" ";" MCC_ARGS "${COMPILE_FLAGS}") # user specified flags
foreach (P IN LISTS MATLABPATH) # search path, -I options
string (REGEX REPLACE "/(\\+|@).*$" "" P "${P}") # remove package/class subdirectories
list (FIND MCC_ARGS "${P}" IDX) # skip if already added
if (IDX GREATER 0)
math (EXPR IDX "${IDX} - 1")
list (GET MCC_ARGS ${IDX} OPT)
if (NOT OPT MATCHES "^-I$")
set (IDX -1)
endif ()
endif ()
if (EXISTS "${P}" AND IDX EQUAL -1)
list (APPEND MCC_ARGS -I "${P}")
endif ()
endforeach ()
if (LIBRARY)
list (APPEND MCC_ARGS -W "cpplib:${MCC_OUTPUT_NAME_WE}" -T link:lib) # build library
else () # or
list (APPEND MCC_ARGS -m -o "${MCC_OUTPUT_NAME_WE}") # build standalone application
endif ()
list (APPEND MCC_ARGS -d "${BUILD_DIR}") # (temp) output directory
list (APPEND MCC_ARGS ${SOURCES}) # source M-files
foreach (LIB ${LINK_LIBS}) # link libraries, e.g. MEX-files
list (FIND MCC_ARGS "${LIB}" IDX)
if (LIB AND IDX EQUAL -1)
list (APPEND MCC_ARGS "-a" "${LIB}")
endif ()
endforeach ()
# build command for invocation of MATLAB Compiler in standalone mode
set (BUILD_CMD "${MATLAB_MCC_EXECUTABLE}" ${MCC_USER_ARGS} ${MCC_ARGS})
set (BUILD_LOG "${BUILD_DIR}/build.log")
set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
set (WORKING_DIR "${SOURCE_DIRECTORY}")
set (MATLAB_MODE OFF)
# build command for invocation of MATLAB Compiler in MATLAB mode
if (BASIS_MCC_MATLAB_MODE)
set (MATLAB_MODE ON)
if (NOT MATLAB_EXECUTABLE)
message (WARNING "MATLAB executable not found. It is required to build target ${TARGET_UID} in MATLAB mode."
" Either set the advanced option BASIS_MCC_MATLAB_MODE to OFF or add MATLAB{matlab} as dependency."
" Will build target ${TARGET_UID} in standalone mode instead.")
set (MATLAB_MODE OFF)
endif ()
if (MATLAB_MODE)
basis_list_to_delimited_string (ARGS "', '" NOAUTOQUOTE ${MCC_USER_ARGS} ${MCC_ARGS})
set (
BUILD_CMD
"${MATLAB_EXECUTABLE}" # run MATLAB
"-nosplash" # do not display splash screen on start up
"-nodesktop" # run in command line mode
"-nojvm" # we do not need the Java Virtual Machine
"-r" "try, mcc('-v', '${ARGS}'), catch err, fprintf(2, err.message), end, quit force"
)
endif ()
endif ()
# post-build command
set (POST_BUILD_COMMAND)
if (NOT "^${MCC_OUTPUT_NAME}$" STREQUAL "^${OUTPUT_NAME}$")
list (APPEND POST_BUILD_COMMAND
COMMAND "${CMAKE_COMMAND}" -E copy
"${BUILD_DIR}/${MCC_OUTPUT_NAME}"
"${BUILD_DIR}/${OUTPUT_NAME}"
COMMAND "${CMAKE_COMMAND}" -E copy
"${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.h"
"${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
)
endif ()
if (LIBRARY)
list (APPEND POST_BUILD_COMMAND
COMMAND "${CMAKE_COMMAND}" -E copy
"${BUILD_DIR}/${OUTPUT_NAME}"
"${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
COMMAND "${CMAKE_COMMAND}" -E copy
"${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
"${LIBRARY_HEADER_DIRECTORY}/${OUTPUT_NAME_WE}.h"
)
if (WIN32)
list (APPEND POST_BUILD_COMMAND
COMMAND "${CMAKE_COMMAND}" -E copy
"${BUILD_DIR}/${OUTPUT_NAME_WE}.dll"
"${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME_WE}.dll")
endif ()
else ()
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# TODO: This file should be regenerated if it is missing.
file (WRITE "${BUILD_DIR}/${OUTPUT_NAME}" "#!/bin/bash\nexec $(dirname $BASH_SOURCE)/${OUTPUT_NAME_WE}.app/Contents/MacOS/${MCC_OUTPUT_NAME_WE}")
execute_process (COMMAND chmod +x "${BUILD_DIR}/${OUTPUT_NAME}")
list (APPEND POST_BUILD_COMMAND
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${BUILD_DIR}/${OUTPUT_NAME_WE}.app"
"${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME_WE}.app"
COMMAND "${CMAKE_COMMAND}" -E copy
"${BUILD_DIR}/${OUTPUT_NAME}"
"${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
)
else ()
list (APPEND POST_BUILD_COMMAND
COMMAND "${CMAKE_COMMAND}" -E copy
"${BUILD_DIR}/${OUTPUT_NAME}"
"${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
)
endif ()
endif ()
# configure build script
configure_file ("${BASIS_SCRIPT_EXECUTE_PROCESS}" "${BUILD_SCRIPT}" @ONLY)
# add custom command to build executable using MATLAB Compiler
add_custom_command (
OUTPUT ${BUILD_OUTPUT}
# rebuild when input sources were modified
MAIN_DEPENDENCY "${MAIN_SOURCE}"
DEPENDS ${DEPENDS}
# invoke MATLAB Compiler in either MATLAB or standalone mode
# wrapping command in CMake execute_process() command allows for inspection
# of command output for error messages and specification of timeout
COMMAND "${CMAKE_COMMAND}"
"-DCONFIG=$<${BASIS_GE_CONFIG}>"
"-DWORKING_DIRECTORY=${WORKING_DIR}"
"-DTIMEOUT=${BASIS_MCC_TIMEOUT}"
"-DRETRY_EXPRESSION=License checkout failed"
"-DRETRY_ATTEMPTS=${BASIS_MCC_RETRY_ATTEMPTS}"
"-DRETRY_DELAY=${BASIS_MCC_RETRY_DELAY}"
"-DERROR_EXPRESSION=[E|e]rror:|Illegal output name"
"-DOUTPUT_FILE=${BUILD_LOG}"
"-DERROR_FILE=${BUILD_LOG}"
"-DVERBOSE=OFF"
"-DLOG_ARGS=ON"
"-P" "${BUILD_SCRIPT}"
# post build command(s)
${POST_BUILD_COMMAND}
# inform user where build log can be found
COMMAND "${CMAKE_COMMAND}" -E echo "Build log written to ${BUILD_LOG}"
# comment
COMMENT "${BUILD_COMMENT}"
VERBATIM
)
endif ()
# --------------------------------------------------------------------------
# add custom target
add_custom_target (_${TARGET_UID} DEPENDS ${BUILD_OUTPUT} SOURCES ${SOURCES})
add_dependencies (${TARGET_UID} _${TARGET_UID})
# cleanup on "make clean"
set (ADDITIONAL_MAKE_CLEAN_FILES "${BUILD_OUTPUT}")
if (COMPILE)
list (APPEND ADDITIONAL_MAKE_CLEAN_FILES
"${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.prj"
"${BUILD_DIR}/mccExcludedFiles.log"
"${BUILD_DIR}/mccBuild.log"
"${BUILD_DIR}/readme.txt"
)
if (LIBRARY)
list (APPEND ADDITIONAL_MAKE_CLEAN_FILES
"${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
"${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.h"
"${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.c"
"${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.exports"
)
else ()
list (APPEND ADDITIONAL_MAKE_CLEAN_FILES
"${BUILD_DIR}/${OUTPUT_NAME}"
"${BUILD_DIR}/${MCC_OUTPUT_NAME}"
"${BUILD_DIR}/run_${MCC_OUTPUT_NAME_WE}.sh"
"${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}_main.c"
"${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}_mcc_component_data.c"
)
endif ()
endif ()
set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${ADDITIONAL_MAKE_CLEAN_FILES}")
unset (ADDITIONAL_MAKE_CLEAN_FILES)
# export target
if (EXPORT)
basis_add_custom_export_target (${TARGET_UID} "${IS_TEST}")
endif ()
# install executable or library
if (LIBRARY)
if (LIBRARY_HEADER_DIRECTORY)
file (RELATIVE_PATH INCLUDE_DIR_SUFFIX "${BINARY_INCLUDE_DIR}" "${LIBRARY_HEADER_DIRECTORY}")
if (NOT INCLUDE_DIR_SUFFIX MATCHES "^../")
string (REGEX REPLACE "/$" "" INCLUDE_DIR_SUFFIX "${INCLUDE_DIR_SUFFIX}")
if (INCLUDE_DIR_SUFFIX STREQUAL ".")
set (INCLUDE_DIR_SUFFIX)
else ()
set (INCLUDE_DIR_SUFFIX "/${INCLUDE_DIR_SUFFIX}")
endif ()
install (
FILES "${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
DESTINATION "${INSTALL_INCLUDE_DIR}${INCLUDE_DIR_SUFFIX}"
COMPONENT "${LIBRARY_COMPONENT}"
)
endif ()
endif ()
if (LIBRARY_INSTALL_DIRECTORY)
if (WIN32)
install (
FILES "${BUILD_DIR}/${OUTPUT_NAME_WE}.dll"
DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
COMPONENT "${RUNTIME_COMPONENT}"
)
endif ()
install (
FILES "${INSTALL_FILE}"
DESTINATION "${LIBRARY_INSTALL_DIRECTORY}"
COMPONENT "${LIBRARY_COMPONENT}"
)
endif ()
else ()
if (RUNTIME_INSTALL_DIRECTORY)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
install (
DIRECTORY "${BUILD_DIR}/${OUTPUT_NAME_WE}.app"
DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
COMPONENT "${RUNTIME_COMPONENT}"
USE_SOURCE_PERMISSIONS
)
endif ()
install (
PROGRAMS "${INSTALL_FILE}"
DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
COMPONENT "${RUNTIME_COMPONENT}"
)
endif ()
endif ()
# done
if (BASIS_VERBOSE)
message (STATUS "Adding build command for target ${TARGET_UID}... - done")
endif ()
endfunction ()