MatlabTools.cmake
Go to the documentation of this file.
1 # ============================================================================
2 # Copyright (c) 2011-2012 University of Pennsylvania
3 # Copyright (c) 2013-2016 Andreas Schuh
4 # All rights reserved.
5 #
6 # See COPYING file for license information or visit
7 # https://cmake-basis.github.io/download.html#license
8 # ============================================================================
9 
10 ##############################################################################
11 # @file MatlabTools.cmake
12 # @brief Enables use of MATLAB Compiler and build of MEX-files.
13 #
14 # @ingroup CMakeTools
15 ##############################################################################
16 
18  return ()
19 else ()
21 endif ()
22 
23 
24 # ============================================================================
25 # modules
26 # ============================================================================
27 
28 # Note: Required because generate_matlab_executable.cmake uses this module.
29 
30 include (CMakeParseArguments)
31 include ("${CMAKE_CURRENT_LIST_DIR}/CommonTools.cmake")
32 include ("${CMAKE_CURRENT_LIST_DIR}/UtilitiesTools.cmake")
33 
34 # ============================================================================
35 # options
36 # ============================================================================
37 
38 ## @addtogroup BasisSettings
39 # @{
40 
41 ## @brief Enable/Disable compilation of MATLAB sources if the MATLAB Compiler is available.
42 option (BASIS_COMPILE_MATLAB "Enable compilation of MATLAB sources if MATLAB Compiler (mcc) is available." ON)
43 mark_as_advanced (BASIS_COMPILE_MATLAB)
44 
45 # ----------------------------------------------------------------------------
46 ## @brief Add global MATLAB MEX-script options to CMake cache
47 #
48 # @par MATLAB MEX-script options:
49 # <table border="0">
50 # <tr>
51 # @tp @b BASIS_MEX_TIMEOUT @endtp
52 # <td>Timeout for MEX script execution.</td>
53 # </tr>
54 # <tr>
55 # @tp @b BASIS_MEX_FLAGS @endtp
56 # <td>Compile flags used to build MEX-files using the MEX script.</td>
57 # </tr>
58 # </table>
60  if (MATLAB_MEX_EXECUTABLE)
61  set (BASIS_MEX_TIMEOUT "600" CACHE STRING "Timeout for MEX script execution")
62  set (BASIS_MEX_FLAGS "" CACHE STRING "Common MEX switches (separated by ' '; use '\\' to mask ' ').")
63  mark_as_advanced (BASIS_MEX_FLAGS)
64  mark_as_advanced (BASIS_MEX_TIMEOUT)
65  endif ()
66 endmacro ()
67 
68 # ----------------------------------------------------------------------------
69 ## @brief Add global MATLAB Compiler (mcc) options to CMake cache
70 #
71 # @par MATLAB Compiler options:
72 # <table border="0">
73 # <tr>
74 # @tp @b BASIS_MCC_MATLAB_MODE @endtp
75 # <td>Enable/Disable invocation of MATLAB Compiler in MATLAB mode.</td>
76 # </tr>
77 # <tr>
78 # @tp @b BASIS_MCC_FLAGS @endtp
79 # <td>Compile flags used to build MATLAB Compiler targets.</td>
80 # </tr>
81 # <tr>
82 # @tp @b BASIS_MCC_TIMEOUT @endtp
83 # <td>Timeout for building MATLAB Compiler targets.</td>
84 # </tr>
85 # <tr>
86 # @tp @b BASIS_MCC_RETRY_ATTEMPTS @endtp
87 # <td>Maximum number of retries on MATLAB Compiler license checkout.</td>
88 # </tr>
89 # <tr>
90 # @tp @b BASIS_MCC_RETRY_DELAY @endtp
91 # <td>Delay between retries to build MATLAB Compiler compiled targets on license checkout errors.</td>
92 # </tr>
93 # </table>
95  option (
96  BASIS_MCC_MATLAB_MODE
97  "Prefer MATLAB mode over standalone mode to invoke MATLAB Compiler to release MCC licence ASAP."
98  OFF # using MATLAB mode is preferred when the license is shared
99  # among users as it releases the license immediately once done
100  )
101  set (
102  BASIS_MCC_FLAGS
103  "-R -singleCompThread"
104  CACHE STRING
105  "Common MATLAB Compiler flags (separated by ' '; use '\\' to mask ' ')."
106  )
107  set (BASIS_MCC_TIMEOUT "1800" CACHE STRING "Timeout for MATLAB Compiler execution")
108  set (BASIS_MCC_RETRY_ATTEMPTS "4" CACHE STRING "Maximum number of retries on MATLAB Compiler license checkout error.")
109  set (BASIS_MCC_RETRY_DELAY "30" CACHE STRING "Delay between retries to build MATLAB Compiler compiled targets on license checkout error.")
110  mark_as_advanced (BASIS_MCC_MATLAB_MODE)
111  mark_as_advanced (BASIS_MCC_FLAGS)
112  mark_as_advanced (BASIS_MCC_TIMEOUT)
113  mark_as_advanced (BASIS_MCC_RETRY_ATTEMPTS)
114  mark_as_advanced (BASIS_MCC_RETRY_DELAY)
115 endmacro ()
116 
117 ## @}
118 # end of Doxygen group
119 
120 # ============================================================================
121 # utilities
122 # ============================================================================
123 
124 # ----------------------------------------------------------------------------
125 ## @brief Determine version of MATLAB installation.
126 #
127 # @param [out] VERSION Value returned by the "version" command of MATLAB or
128 # an empty string if execution of MATLAB failed.
129 #
130 # @returns Sets the variable named by @p VERSION to the full MATLAB version.
131 #
132 # @ingroup CMakeUtilities
134  if (NOT MATLAB_EXECUTABLE)
135  set (${VERSION} "" PARENT_SCOPE)
136  return ()
137  endif ()
138  set (WORKING_DIR "${CMAKE_BINARY_DIR}/CMakeFiles")
139  set (OUTPUT_FILE "${WORKING_DIR}/MatlabVersion.txt")
140  # read MATLAB version from existing output file
141  set (_MATLAB_VERSION)
142  if (EXISTS "${OUTPUT_FILE}")
143  file (READ "${OUTPUT_FILE}" LINES)
144  string (REGEX REPLACE "\n" ";" LINES "${LINES}")
145  string (REGEX REPLACE "^;|;$" "" LINES "${LINES}")
146  list (LENGTH LINES NLINES)
147  if (NLINES EQUAL 2)
148  list (GET LINES 0 _MATLAB_EXECUTABLE)
149  list (GET LINES 1 _MATLAB_VERSION)
150  basis_sanitize_for_regex (RE "${MATLAB_EXECUTABLE}")
151  if (NOT _MATLAB_EXECUTABLE MATCHES "^${RE}$")
152  set (_MATLAB_VERSION)
153  endif ()
154  unset (RE)
155  endif ()
156  endif ()
157  # run matlab command to write return value of "version" command to text file
158  if (NOT _MATLAB_VERSION)
159  message (STATUS "Determining MATLAB version...")
160  set (CMD "${MATLAB_EXECUTABLE}" -nodesktop -nosplash -singleCompThread)
161  if (WIN32)
162  list (APPEND CMD -automation)
163  else ()
164  list (APPEND CMD -nojvm)
165  endif ()
166  file (WRITE "${WORKING_DIR}/basis_get_full_matlab_version.m"
167 "% DO NOT EDIT. Automatically created by BASIS (basis_get_full_matlab_version).
168 fid = fopen ('${OUTPUT_FILE}', 'w')
169 if fid == -1, fprintf(2, '??? Error: Failed to open file ${OUTPUT_FILE} for writing!'), quit force, end
170 fprintf (fid, '${MATLAB_EXECUTABLE}\\n%s\\n', version)
171 fclose (fid)
172 quit force
173 "
174  )
175  execute_process (
176  COMMAND ${CMD} -r "cd('${WORKING_DIR}');basis_get_full_matlab_version;"
177  WORKING_DIRECTORY "${WORKING_DIR}"
178  RESULT_VARIABLE RETVAL
179  TIMEOUT 600 # MATLAB startup can be *very* slow the first time
180  ERROR_VARIABLE STDERR
181  OUTPUT_QUIET
182  )
183  if (NOT RETVAL EQUAL 0 OR STDERR MATCHES "\\?\\?\\? Error")
184  set (${VERSION} "" PARENT_SCOPE)
185  if (RETVAL MATCHES "timeout")
186  set (REASON ": ${RETVAL}")
187  elseif (NOT RETVAL EQUAL 0)
188  set (REASON " with exit code: ${RETVAL}")
189  else ()
190  set (REASON ": Failed to open file ${OUTPUT_FILE} for writing")
191  endif ()
192  message (STATUS "Determining MATLAB version... - failed${REASON}")
193  return ()
194  endif ()
195  # wait until MATLAB process terminated entirely and wrote the (buffered?) file
196  set (nsleep_count 0)
197  set (nsleep_max 30)
198  while (NOT EXISTS "${OUTPUT_FILE}")
199  math (EXPR nsleep_count "${nsleep_count}+1")
200  if (nsleep_count GREATER nsleep_max)
201  message (STATUS "Determining MATLAB version... - failed: File ${OUTPUT_FILE} still non-existent after ${nsleep_max}s of successful MATLAB termination")
202  return ()
203  endif ()
204  if (WIN32)
205  execute_process (COMMAND ping 1.1.1.1 -n 1 -w 1000 OUTPUT_QUIET)
206  else ()
207  execute_process (COMMAND sleep 1 OUTPUT_QUIET)
208  endif ()
209  endwhile ()
210  # read MATLAB version from text file
211  file (READ "${OUTPUT_FILE}" LINES)
212  string (REGEX REPLACE "\n" ";" LINES "${LINES}")
213  string (REGEX REPLACE "^;|;$" "" LINES "${LINES}")
214  list (LENGTH LINES NLINES)
215  if (NLINES EQUAL 2)
216  list (GET LINES 1 _MATLAB_VERSION)
217  else ()
218  set (${VERSION} "" PARENT_SCOPE)
219  message (STATUS "Determining MATLAB version... - failed")
220  return ()
221  endif ()
222  if (BASIS_VERBOSE)
223  message (STATUS "Determining MATLAB version... - done: ${_MATLAB_VERSION}")
224  else ()
225  message (STATUS "Determining MATLAB version... - done")
226  endif ()
227  endif ()
228  # return
229  set (${VERSION} "${_MATLAB_VERSION}" PARENT_SCOPE)
230 endfunction ()
231 
232 # ----------------------------------------------------------------------------
233 ## @brief Get version of MATLAB installation.
234 #
235 # @param [out] ARGV1 If given, the named variable is set to the version string
236 # ("<major>.<minor>.<patch>") of the MATLAB installation.
237 # Otherwise, the variables @c MATLAB_VERSION_STRING,
238 # @c MATLAB_VERSION_MAJOR, @c MATLAB_VERSION_MINOR,
239 # @c MATLAB_VERSION_PATCH, and @c MATLAB_RELEASE are set
240 # in the scope of the caller.
241 #
242 # @ingroup CMakeUtilities
243 function (basis_get_matlab_version)
244  if (ARGC GREATER 1)
245  message (FATAL_ERROR "basis_get_matlab_version(): Too many arguments!")
246  endif ()
248  if (VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
249  set (VERSION_STRING "${CMAKE_MATCH_0}")
250  set (VERSION_MAJOR "${CMAKE_MATCH_1}")
251  set (VERSION_MINOR "${CMAKE_MATCH_2}")
252  set (VERSION_PATCH "${CMAKE_MATCH_3}")
253  else ()
254  set (VERSION_STRING "0.0")
255  set (VERSION_MAJOR "0")
256  set (VERSION_MINOR "0")
257  set (VERSION_PATCH "0")
258  endif ()
259  if (ARGC EQUAL 1)
260  set (${ARGV0} "${VERSION_STRING}" PARENT_SCOPE)
261  else ()
262  set (MATLAB_VERSION_STRING "${VERSION_STRING}" PARENT_SCOPE)
263  set (MATLAB_VERSION_MAJOR "${VERSION_MAJOR}" PARENT_SCOPE)
264  set (MATLAB_VERSION_MINOR "${VERSION_MINOR}" PARENT_SCOPE)
265  set (MATLAB_VERSION_PATCH "${VERSION_PATCH}" PARENT_SCOPE)
266  if (VERSION MATCHES ".*\\\((.+)\\\)")
267  set (MATLAB_RELEASE "${CMAKE_MATCH_1}" PARENT_SCOPE)
268  else ()
269  set (MATLAB_RELEASE "" PARENT_SCOPE)
270  endif ()
271  endif ()
272 endfunction ()
273 
274 # ----------------------------------------------------------------------------
275 ## @brief Get release version of MATLAB installation.
276 #
277 # @param [out] ARGV1 If given, the named variable is set to the release string
278 # of the MATLAB installation, e.g., "R2009b". Otherwise,
279 # the variable @c MATLAB_RELEASE is set in the scope of the
280 # caller.
281 #
282 # @ingroup CMakeUtilities
283 function (basis_get_matlab_release)
284  if (ARGC GREATER 1)
285  message (FATAL_ERROR "basis_get_matlab_release(): Too many arguments!")
286  endif ()
288  if (VERSION MATCHES ".*\\\((.+)\\\)")
289  set (RELEASE "${CMAKE_MATCH_1}")
290  else ()
291  set (RELEASE "")
292  endif ()
293  if (ARGC EQUAL 1)
294  set (${ARGV0} "${RELEASE}" PARENT_SCOPE)
295  else ()
296  set (MATLAB_RELEASE "${RELEASE}")
297  endif ()
298 endfunction ()
299 
300 # ----------------------------------------------------------------------------
301 ## @brief Determine extension of MEX-files for this architecture.
302 #
303 # @param [out] ARGN The first argument ARGV0 is set to the extension of
304 # MEX-files (excluding '.'). If the CMake variable MEX_EXT
305 # is set, its value is returned. Otherwise, this function
306 # tries to determine it from the system information.
307 # If the extension could not be determined, an empty string
308 # is returned. If no argument is given, the extension is
309 # cached as the variable MEX_EXT.
310 #
311 # @returns Sets the variable named by the first argument to the
312 # platform-specific extension of MEX-files.
313 #
314 # @ingroup CMakeUtilities
315 function (basis_mexext)
316  # default return value
317  set (MEXEXT "${MEX_EXT}")
318  # use MEXEXT if possible
319  if (NOT MEXEXT AND MATLAB_MEXEXT_EXECUTABLE)
320  execute_process (
321  COMMAND "${MATLAB_MEXEXT_EXECUTABLE}"
322  RESULT_VARIABLE RETVAL
323  OUTPUT_VARIABLE MEXEXT
324  ERROR_QUIET
325  OUTPUT_STRIP_TRAILING_WHITESPACE
326  )
327  if (RETVAL)
328  set (MEXEXT "")
329  endif ()
330  endif ()
331  # otherwise, determine extension given CMake variables describing the system
332  if (NOT MEXEXT)
333  if (CMAKE_SYSTEM_NAME MATCHES "Linux")
334  if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR
335  CMAKE_SIZEOF_VOID_P MATCHES 8)
336  set (MEXEXT "mexa64")
337  elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "x86" OR
338  CMAKE_SYSTEM_PROCESSOR MATCHES "i686")
339  set (MEXEXT "mexglx")
340  endif ()
341  elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
342  if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR
343  CMAKE_SIZEOF_VOID_P MATCHES 8)
344  set (MEXEXT "mexw64")
345  elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "x86" OR
346  CMAKE_SYSTEM_PROCESSOR MATCHES "i686")
347  set (MEXEXT "mexw32")
348  endif ()
349  elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
350  if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR
351  CMAKE_SIZEOF_VOID_P MATCHES 8)
352  set (MEXEXT "mexmaci64")
353  else ()
354  set (MEXEXT "mexmaci")
355  endif ()
356  elseif (CMAKE_SYSTEM_NAME MATCHES "SunOS")
357  set (MEXEXT "mexs64")
358  endif ()
359  endif ()
360  # return value
361  if (ARGC GREATER 0)
362  set ("${ARGV0}" "${MEXEXT}" PARENT_SCOPE)
363  else ()
364  if (NOT DEFINED MEX_EXT)
365  set (MARKIT 1)
366  else ()
367  set (MARKIT 0)
368  endif ()
369  set (MEX_EXT "${MEXEXT}" CACHE STRING "The extension of MEX-files for this architecture." FORCE)
370  if (MARKIT)
371  mark_as_advanced (MEX_EXT)
372  endif ()
373  endif ()
374 endfunction ()
375 
376 # ----------------------------------------------------------------------------
377 ## @brief This function writes a MATLAB M-file with addpath() statements.
378 #
379 # This function writes an MATLAB M-file into the top directory of the build
380 # tree which contains an addpath() statement for each directory that was added
381 # via basis_include_directories().
382 #
383 # @returns Creates file add_\<project\>_paths.m in the current binary directory.
384 #
385 # @ingroup CMakeUtilities
387  basis_get_project_property (INCLUDE_DIRS PROPERTY PROJECT_INCLUDE_DIRS)
388  basis_write_addpaths_mfile ("${CMAKE_CURRENT_BINARY_DIR}/add_${PROJECT_NAME_L}_paths.m" ${INCLUDE_DIRS})
389 endfunction ()
390 
391 # ----------------------------------------------------------------------------
392 ## @brief This function writes a MATLAB M-file with addpath() statements.
393 #
394 # @param [in] MFILE Name of M-file.
395 # @param [in] ARGN The remaining arguments are the paths which should be added
396 # to the search path of MATLAB when this M-file is being
397 # executed. If the option APPEND is given, the paths are
398 # appended to the specified M-file. Otherwise, any existing
399 # file will be overwritten. The given directory paths can
400 # be relative, in which case they are interpreted relative
401 # to the location of the written M-file using the mfilename()
402 # function of MATLAB.
403 #
404 # @ingroup CMakeUtilities
405 macro (basis_write_addpaths_mfile MFILE)
406  CMAKE_PARSE_ARGUMENTS (ARGN "APPEND" "" "" ${ARGN})
407  if (NOT ARGN_APPEND)
408  file (WRITE "${MFILE}" "% DO NOT edit. This file is automatically generated by BASIS.
409 [mfiledir, ~, ~, ~] = fileparts(mfilename('fullpath'));\n")
410  endif ()
411  foreach (P IN LISTS ARGN_UNPARSED_ARGUMENTS)
412  if (P MATCHES "^\\.?$")
413  file (APPEND "${MFILE}" "addpath(mfiledir);\n")
414  elseif (IS_ABSOLUTE "${P}")
415  file (APPEND "${MFILE}" "addpath('${P}');\n")
416  else ()
417  file (APPEND "${MFILE}" "addpath([mfiledir '/${P}']);\n")
418  endif ()
419  endforeach ()
420 endmacro ()
421 
422 # ----------------------------------------------------------------------------
423 ## @brief Generate MATLAB wrapper executable.
424 #
425 # This function writes a Bash script on Unix or a Windows Command script on
426 # Windows platforms which execute the specified MATLAB command using the -r
427 # option of the matlab executable and the -nodesktop and -nosplash options.
428 # It is used by the build scripts generated by the basis_build_mcc_target()
429 # in order to build an executable from MATLAB source files without the use
430 # of the MATLAB Compiler. In this case, the MATLAB source files are simply
431 # copied to the installation directory and the wrapper script written by
432 # this function used to execute the main function with the command-line
433 # arguments passed on to this executable.
434 #
435 # @param [in] OUTPUT_FILE Name of the output executable file.
436 # @param [in] ARGN The remaining options
437 # @par
438 # <table border=0>
439 # <tr>
440 # @tp @b DESTINATION dir @endtp
441 # <td>Installation destination. (default: directory of @c OUTPUT_FILE)</td>
442 # </tr>
443 # <tr>
444 # @tp @b COMMAND name @endtp
445 # <td>Name of the MATLAB command to execute, i.e.,
446 # the name of the main function.</td>
447 # </tr>
448 # <tr>
449 # @tp @b STARTUP mfile @endtp
450 # <td>Absolute path of a startup M-file.</td>
451 # </tr>
452 # <tr>
453 # @tp @b MATLABPATH dir1[ dir2...]
454 # <td>List of directories to be added to the MATLAB search path.</td>
455 # </tr>
456 # <tr>
457 # @tp @b OPTIONS opt1[ opt2...]
458 # <td>Additional options to pass on to the <tt>matlab</tt> executable.</td>
459 # </tr>
460 # </table>
461 function (basis_generate_matlab_executable OUTPUT_FILE)
462  CMAKE_PARSE_ARGUMENTS (ARGN "" "COMMAND;STARTUP;DESTINATION" "OPTIONS;MATLABPATH" ${ARGN})
463  if (NOT MATLAB_EXECUTABLE)
464  set (MATLAB_EXECUTABLE matlab)
465  endif ()
466  if (NOT OUTPUT_FILE)
467  message ("basis_generate_matlab_executable(): Missing OUTPUT_FILE argument!")
468  endif ()
469  if (NOT ARGN_DESTINATION)
470  get_filename_component (ARGN_DESTINATION "${OUTPUT_FILE}" PATH)
471  endif ()
472  # source path
473  set (MATLABPATH)
474  foreach (P IN LISTS ARGN_MATLABPATH)
475  if (P MATCHES "^\\.?$")
476  set (P "$__DIR__")
477  elseif (NOT IS_ABSOLUTE "${P}")
478  set (P "$__DIR__/${P}")
479  endif ()
480  list (APPEND MATLABPATH "${P}")
481  endforeach ()
482  if (MATLABPATH)
483  list (REMOVE_DUPLICATES MATLABPATH)
484  endif ()
485  # startup script
486  if (ARGN_STARTUP)
487  get_filename_component (STARTUP_COMMAND "${ARGN_STARTUP}" NAME_WE)
488  get_filename_component (STARTUP_DIR "${ARGN_STARTUP}" PATH)
489  get_filename_component (STARTUP_PKG "${STARTUP_DIR}" NAME)
490  if (STARTUP_PKG MATCHES "^\\+")
491  get_filename_component (STARTUP_DIR "${STARTUP_DIR}" PATH)
492  string (REGEX REPLACE "^\\+" "" STARTUP_PKG "${STARTUP_PKG}")
493  set (STARTUP_COMMAND "${STARTUP_PKG}.${STARTUP_COMMAND}")
494  endif ()
495  if (IS_ABSOLUTE "${STARTUP_DIR}")
496  file (RELATIVE_PATH STARTUP_DIR "${ARGN_DESTINATION}" "${STARTUP_DIR}")
497  endif ()
498  if (STARTUP_DIR)
499  set (STARTUP_DIR "$__DIR__/${STARTUP_DIR}")
500  else ()
501  set (STARTUP_DIR "$__DIR__")
502  endif ()
503  list (FIND MATLABPATH "${STARTUP_DIR}" IDX)
504  if (IDX EQUAL -1)
505  set (STARTUP_CODE ", addpath('${STARTUP_DIR}')")
506  else ()
507  set (STARTUP_CODE)
508  endif ()
509  set (STARTUP_CODE "${STARTUP_CODE}, ${STARTUP_COMMAND}")
510  else ()
511  set (STARTUP_CODE)
512  endif ()
513  # write wrapper executable
514  if (MATLABPATH)
515  basis_list_to_delimited_string (MATLABPATH "', '" NOAUTOQUOTE ${MATLABPATH})
516  set (MATLABPATH ", addpath('${MATLABPATH}', '-begin')")
517  else ()
518  set (MATLABPATH)
519  endif ()
520  file (WRITE "${OUTPUT_FILE}"
521  # note that Bash variables within the script are denoted by $var
522  # instead of ${var} to prevent CMake from substituting these patterns
523  "#! /bin/bash
524 
525 readonly __DIR__=\"${BASIS_BASH___DIR__}\"
526 
527 errlog=
528 finish()
529 {
530  local status=0
531  if [[ -n \"$errlog\" ]]; then
532  grep '??? Error' \"$errlog\" &> /dev/null
533  [[ $? -ne 0 ]] || status=1
534  /bin/rm \"$errlog\"
535  fi
536  exit $status
537 }
538 
539 if [[ -d \"$TMPDIR\" ]]; then
540  tmpdir=$TMPDIR
541 else
542  tmpdir=/tmp
543 fi
544 
545 errlog=`mktemp \"$tmpdir/${ARGN_COMMAND}-log.XXXXXX\"`
546 [[ $? -eq 0 ]] || {
547  echo \"Failed to create temporary log file in '$tmpdir'!\" 1>&2
548  exit 1
549 }
550 
551 args=
552 while [[ $# -gt 0 ]]; do
553  [[ -z \"$args\" ]] || args=\"$args, \"
554  args=\"$args'$1'\"
555  shift
556 done
557 
558 echo 'Launching MATLAB to execute ${ARGN_COMMAND} function...'
559 trap finish EXIT # DO NOT install trap earlier !
560 '${MATLAB_EXECUTABLE}' -nodesktop -nosplash ${ARGN_OPTIONS} \\
561  -r \"try${MATLABPATH}${STARTUP_CODE}, ${ARGN_COMMAND}($args), catch err, fprintf(2, ['??? Error executing ${ARGN_COMMAND}\\n' err.message '\\n']), end, quit force\" \\
562  2> >(tee \"$errlog\" >&2)"
563  ) # end of file(WRITE) command
564  if (UNIX)
565  execute_process (COMMAND /bin/chmod +x "${OUTPUT_FILE}")
566  endif ()
567 endfunction ()
568 
569 # ============================================================================
570 # MEX-file target
571 # ============================================================================
572 
573 # ----------------------------------------------------------------------------
574 ## @brief Add MEX-file target.
575 #
576 # @note This function should not be used directly. Instead, it is called
577 # by basis_add_library() if the (detected) programming language
578 # of the given source code files is @c CXX (i.e., C/C++) and the @c MEX
579 # type option is given.
580 #
581 # This function is used to add a shared library target which is built
582 # using the MATLAB MEX script (mex).
583 #
584 # By default, the BASIS C++ utilities library is added as link dependency.
585 # If none of the BASIS C++ utilities are used by this target, the option
586 # NO_BASIS_UTILITIES can be given. To enable this option by default, set the
587 # variable @c BASIS_UTILITIES to @c FALSE, best in the <tt>Settings.cmake</tt>
588 # file located in the @c PROJECT_CONFIG_DIR (add such file if missing).
589 # If the use of the BASIS C++ utilities is disabled by default, the
590 # @c USE_BASIS_UTILITIES option can be used to enable them for this target
591 # only. Note that the utilities library is a static library and thus the linker
592 # would simply not include any of the BASIS utility functions in the final
593 # binary file if not used. The only advantage of setting @c BASIS_UTILITIES to
594 # @c FALSE or to always specify @c NO_BASIS_UTILITIES if no target uses the
595 # utilities is that the BASIS utilities library will not be build in this case.
596 #
597 # A custom CMake build target with the following properties is added by this
598 # function to the build system. These properties are used by
599 # basis_build_mex_target() to generate a build script written in CMake
600 # code which is executed by a custom CMake command. Before the invokation of
601 # basis_build_mex_target(), the target properties can be modified using
602 # basis_set_target_properties().
603 #
604 # @note Custom BASIS build targets are finalized by BASIS using basis_project_end(),
605 # i.e., the end of the root CMake configuration file of the (sub-)project.
606 #
607 # @par Properties on script library targets
608 # <table border=0>
609 # <tr>
610 # @tp @b MFILE file @endtp
611 # <td>MATLAB source file with function prototype and documentation of MEX-file.
612 # (default: none)</td>
613 # </tr>
614 # <tr>
615 # @tp @b PREFIX prefix @endtp
616 # <td>Output prefix of build MEX-file such as package name
617 # (the prefix must include the leading + and trailing /).</td>
618 # </tr>
619 # </table>
620 #
621 # @attention Properties documented as read-only must not be modified.
622 #
623 # An install command for the added library target is added by this function
624 # as well. The MEX-file will be installed as part of the specified @p COMPONENT
625 # in the @c INSTALL_LIBRARY_DIR on Unix and @c INSTALL_RUNTIME_DIR on Windows.
626 #
627 # @param [in] TARGET_NAME Name of build target.
628 # @param [in] ARGN The remaining arguments are parsed and the following
629 # arguments extracted. All unparsed arguments are treated
630 # as the source files of the MEX-file.
631 # @par
632 # <table border="0">
633 # <tr>
634 # @tp @b COMPONENT name @endtp
635 # <td>Name of installation component as part of which this MEX-file is being
636 # installed if the @c LIBRARY_INSTALL_DIRECTORY property is not "none".
637 # (default: @c BASIS_LIBRARY_COMPONENT)</td>
638 # </tr>
639 # <tr>
640 # @tp @b [NO]EXPORT @endtp
641 # <td>Whether to export this target. (default: @c TRUE)</td>
642 # </tr>
643 # <tr>
644 # @tp @b NO_BASIS_UTILITIES @endtp
645 # <td>Specify that the BASIS utilities are not used by this MEX-file and
646 # hence no link dependency on the BASIS utilities shall be added.
647 # (default: @c NOT BASIS_UTILITIES)</td>
648 # </tr>
649 # <tr>
650 # @tp @b USE_BASIS_UTILITIES @endtp
651 # <td>Specify that the BASIS utilities are used and required by this MEX-file
652 # and hence a link dependency on the BASIS utilities must be added.
653 # (default: @c BASIS_UTILITIES)</td>
654 # </tr>
655 # <tr>
656 # @tp @b FINAL @endtp
657 # <td>Finalize custom targets immediately. Any following target property changes
658 # will have no effect. When this option is used, the custom target which
659 # executes the custom build command is added in the current working directory.
660 # Otherwise it will be added in the top-level source directory of the project.
661 # Which with the Visual Studio generators adds the corresponding Visual Studio
662 # Project files directly to the top-level build directory. This can be avoided
663 # using this option or calling basis_finalize_targets() at the end of each
664 # CMakeLists.txt file.</td>
665 # </tr>
666 # </table>
667 #
668 # @returns Adds custom target to build MEX-file using the MEX script.
669 #
670 # @sa basis_add_library()
671 #
672 # @ingroup CMakeUtilities
673 function (basis_add_mex_file TARGET_NAME)
674  # check target name
675  basis_check_target_name ("${TARGET_NAME}")
676  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
677  message (STATUS "Adding MEX-file ${TARGET_UID}...")
678  # required commands available ?
679  if (NOT MATLAB_MEX_EXECUTABLE)
680  message (FATAL_ERROR "MATLAB MEX script (mex) not found! It is required to build target ${TARGET_UID}."
681  " Forgot to add MATLAB{mex} as dependency? Otherwise, set MATLAB_MEX_EXECUTABLE manually and try again.")
682  endif ()
684  # parse arguments
685  CMAKE_PARSE_ARGUMENTS (
686  ARGN
687  "USE_BASIS_UTILITIES;NO_BASIS_UTILITIES;EXPORT;NOEXPORT;FINAL"
688  "COMPONENT;DESTINATION"
689  ""
690  ${ARGN}
691  )
692  set (SOURCES ${ARGN_UNPARSED_ARGUMENTS})
693  basis_set_flag (ARGN EXPORT ${BASIS_EXPORT_DEFAULT})
694  if (ARGN_USE_BASIS_UTILITIES AND ARGN_NO_BASIS_UTILITIES)
695  message (FATAL_ERROR "Target ${TARGET_UID}: Options USE_BASIS_UTILITIES and NO_BASIS_UTILITIES are mutually exclusive!")
696  endif ()
697  if (ARGN_USE_BASIS_UTILITIES)
698  set (USES_BASIS_UTILITIES TRUE)
699  elseif (ARGN_NO_BASIS_UTILITIES)
700  set (USES_BASIS_UTILITIES FALSE)
701  else ()
702  set (USES_BASIS_UTILITIES ${BASIS_UTILITIES})
703  endif ()
704  basis_mexext (MEXEXT)
705  # IS_TEST flag
706  basis_sanitize_for_regex (RE "${PROJECT_TESTING_DIR}")
707  if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${RE}")
708  set (IS_TEST TRUE)
709  else ()
710  set (IS_TEST FALSE)
711  endif ()
712  # installation component
713  if (NOT ARGN_COMPONENT)
714  set (ARGN_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
715  endif ()
716  if (NOT ARGN_COMPONENT)
717  set (ARGN_COMPONENT "Unspecified")
718  endif ()
719  # installation directory
720  if (ARGN_DESTINATION)
721  if (ARGN_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
722  set (ARGN_DESTINATION)
723  elseif (IS_ABSOLUTE "${ARGN_DESTINATION}")
724  file (RELATIVE_PATH ARGN_DESTINATION "${CMAKE_INSTALL_PREFIX}" "${ARGN_DESTINATION}")
725  endif ()
726  else ()
727  set (ARGN_DESTINATION "${INSTALL_MATLAB_LIBRARY_DIR}")
728  endif ()
729  # configure (.in) source files
731  # add custom target
732  add_custom_target (${TARGET_UID} ALL SOURCES ${SOURCES})
733  get_directory_property (INCLUDE_DIRS INCLUDE_DIRECTORIES)
734  get_directory_property (LINK_DIRS LINK_DIRECTORIES)
735  if (MATLAB_LIBRARY_DIR)
736  list (INSERT LINK_DIRS 0 "${MATLAB_LIBRARY_DIR}")
737  endif ()
739  ${TARGET_UID}
740  PROPERTIES
741  LANGUAGE "CXX"
742  BASIS_TYPE MEX
743  BASIS_UTILITIES ${USES_BASIS_UTILITIES}
744  BASIS_INCLUDE_DIRECTORIES "${INCLUDE_DIRS}"
745  BASIS_LINK_DIRECTORIES "${LINK_DIRS}"
746  BUILD_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}"
747  SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
748  BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
749  LIBRARY_OUTPUT_DIRECTORY "${BINARY_MATLAB_LIBRARY_DIR}"
750  LIBRARY_INSTALL_DIRECTORY "${ARGN_DESTINATION}"
751  LIBRARY_COMPONENT "${ARGN_COMPONENT}"
752  COMPILE_FLAGS "${BASIS_MEX_FLAGS}"
753  LINK_FLAGS ""
754  LINK_DEPENDS "${LINK_DEPENDS}"
755  PREFIX ""
756  OUTPUT_NAME ""
757  SUFFIX ".${MEXEXT}"
758  MFILE ""
759  TEST ${IS_TEST}
760  EXPORT ${EXPORT}
761  )
762  # link to BASIS utilities
763  if (USES_BASIS_UTILITIES)
764  basis_target_link_libraries (.${TARGET_UID} basis)
765  endif ()
766  # finalize target
767  if (ARGN_FINAL)
768  basis_finalize_targets (${TARGET_UID})
769  endif ()
770  # add target to list of targets
771  basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
772  message (STATUS "Adding MEX-file ${TARGET_UID}... - done")
773 endfunction ()
774 
775 # ============================================================================
776 # MATLAB Compiler target
777 # ============================================================================
778 
779 # ----------------------------------------------------------------------------
780 ## @brief Add MATLAB Compiler target.
781 #
782 # @note This function should not be used directly. Instead, it is called
783 # by either basis_add_executable() or basis_add_library() if the
784 # (detected) programming language of the given source code files is
785 # @c MATLAB.
786 #
787 # This function is used to add an executable or shared library target which is
788 # built using the MATLAB Compiler (MCC).
789 #
790 # A custom CMake build target with the following properties is added by this
791 # function to the build system. These properties are used by
792 # basis_build_mcc_target() to generate a build script written in CMake
793 # code which is executed by a custom CMake command. Before the invokation of
794 # basis_build_mcc_target(), the target properties can be modified using
795 # basis_set_target_properties().
796 #
797 # @note Custom BASIS build targets are finalized by BASIS using basis_project_end(),
798 # i.e., the end of the root CMake configuration file of the (sub-)project.
799 #
800 # @par Properties on MATLAB Compiler targets
801 # <table border=0>
802 # <tr><td>TODO</td></tr>
803 # </table>
804 #
805 # An install command for the added executable or library target is added by
806 # this function as well. The executable will be installed as part of the
807 # @p RUNTIME_COMPONENT in the directory @c INSTALL_RUNTIME_DIR. The runtime
808 # library will be installed as part of the @p RUNTIME_COMPONENT in the directory
809 # @c INSTALL_LIBRARY_DIR on Unix and @c INSTALL_RUNTIME_DIR on Windows.
810 # Static/import libraries will be installed as part of the @p LIBRARY_COMPONENT
811 # in the directory @c INSTALL_ARCHIVE_DIR.
812 #
813 # @note If this function is used within the @c PROJECT_TESTING_DIR, the built
814 # executable is output to the @c BINARY_TESTING_DIR directory tree instead.
815 # Moreover, no installation rules are added. Test executables are further
816 # not exported, regardless of the value of the @c EXPORT property.
817 #
818 # @param [in] TARGET_NAME Name of build target.
819 # @param [in] ARGN The remaining arguments are parsed and the following
820 # arguments extracted. All unparsed arguments are treated
821 # as the MATLAB or C/C++ source files, respectively.
822 # @par
823 # <table border="0">
824 # <tr>
825 # @tp <b>EXECUTABLE</b>|<b>LIBEXEC</b>|<b>SHARED</b> @endtp
826 # <td>Type of the MATLAB Compiler target which can be either a stand-alone
827 # executable, an auxiliary executable, or a shared library.
828 # (default: @c EXECUTABLE)</td>
829 # </tr>
830 # <tr>
831 # @tp @b COMPONENT name @endtp
832 # <td>Name of component as part of which this executable or library will be
833 # installed if the @c RUNTIME_INSTALL_DIRECTORY or @c LIBRARY_INSTALL_DIRECTORY
834 # property is not "none". Used only if @p RUNTIME_COMPONENT or
835 # @p LIBRARY_COMPONENT not specified.
836 # (default: see @p RUNTIME_COMPONENT and @p LIBRARY_COMPONENT arguments)</td>
837 # </tr>
838 # <tr>
839 # @tp @b DESTINATION dir @endtp
840 # <td>Installation directory for executable or runtime and library component
841 # of shared library relative to @c CMAKE_INSTALL_PREFIX. Used only if
842 # @p RUNTIME_DESTINATION or @p LIBRARY_DESTINATION not specified.
843 # If "none" (case-insensitive) is given as argument, no default installation
844 # rules are added. (default: see @p RUNTIME_DESTINATION and
845 # @p LIBRARY_DESTINATION arguments)</td>
846 # </tr>
847 # <tr>
848 # @tp @b LIBRARY_COMPONENT name @endtp
849 # <td>Name of component as part of which import/static library will be intalled
850 # if a shared library is build and the @c LIBRARY_INSTALL_DIRECTORY property is
851 # not "none". (default: @c COMPONENT if specified or @c BASIS_LIBRARY_COMPONENT
852 # otherwise)</td>
853 # </tr>
854 # <tr>
855 # @tp @b LIBRARY_DESTINATION dir @endtp
856 # <td>Installation directory of the library component relative to
857 # @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument or
858 # an executable is build, no installation rule for the library component is added.
859 # (default: @c INSTALL_ARCHIVE_DIR)</td>
860 # </tr>
861 # <tr>
862 # @tp @b HEADER_DESTINATION dir @endtp
863 # <td>Installation directory of the library header file relative to
864 # @c INSTALL_INCLUDE_DIR. If "none" (case-insensitive) is given as argument or
865 # an executable is build, no installation rule for the library header file is added.
866 # (default: @c INSTALL_INCLUDE_DIR)</td>
867 # </tr>
868 # <tr>
869 # @tp @b RUNTIME_COMPONENT name @endtp
870 # <td>Name of component as part of which executable or runtime library, respectively,
871 # will be installed if the @c RUNTIME_INSTALL_DIRECTORY property is not "none".
872 # (default: @c COMPONENT if specified or @c BASIS_RUNTIME_COMPONENT otherwise)</td>
873 # </tr>
874 # <tr>
875 # @tp @b RUNTIME_DESTINATION dir @endtp
876 # <td>Installation directory of the executable or runtime component of the shared library
877 # relative to @c CMAKE_INSTALL_PREFIX. If "none" (case-insensitive) is given as argument,
878 # no installation rule for the runtime library is added.
879 # (default: @c INSTALL_LIBRARY_DIR for shared libraries on Unix or
880 # @c INSTALL_RUNTIME_DIR otherwise)</td>
881 # </tr>
882 # <tr>
883 # @tp @b [NO]EXPORT @endtp
884 # <td>Whether to export this target. (default: @c TRUE)</td>
885 # </tr>
886 # <tr>
887 # @tp @b NO_BASIS_UTILITIES @endtp
888 # <td>Specify that the BASIS utilities are not used by this executable or shared library
889 # and hence no link dependency on the BASIS utilities shall be added.
890 # (default: @c NOT BASIS_UTILITIES)</td>
891 # </tr>
892 # <tr>
893 # @tp @b USE_BASIS_UTILITIES @endtp
894 # <td>Specify that the BASIS utilities are used and required by this executable
895 # or shared library, respectively, and hence a link dependency on the BASIS utilities
896 # must be added.
897 # (default: @c BASIS_UTILITIES)</td>
898 # </tr>
899 # <tr>
900 # @tp @b FINAL @endtp
901 # <td>Finalize custom targets immediately. Any following target property changes
902 # will have no effect. When this option is used, the custom target which
903 # executes the custom build command is added in the current working directory.
904 # Otherwise it will be added in the top-level source directory of the project.
905 # Which with the Visual Studio generators adds the corresponding Visual Studio
906 # Project files directly to the top-level build directory. This can be avoided
907 # using this option or calling basis_finalize_targets() at the end of each
908 # CMakeLists.txt file.</td>
909 # </tr>
910 # </table>
911 #
912 # @todo Consider NO_BASIS_UTILITIES and USE_BASIS_UTILITIES options after the BASIS
913 # utilities for MATLAB have been implemented.
914 #
915 # @returns Adds custom target which builds depending on the @p BASIS_TYPE property
916 # either an executable or a shared library using the MATLAB Compiler.
917 #
918 # @sa basis_add_executable()
919 # @sa basis_add_library()
920 #
921 # @ingroup CMakeUtilities
922 function (basis_add_mcc_target TARGET_NAME)
923  # check target name
924  basis_check_target_name ("${TARGET_NAME}")
925  basis_make_target_uid (TARGET_UID "${TARGET_NAME}")
926  # parse arguments
927  CMAKE_PARSE_ARGUMENTS (
928  ARGN
929  "SHARED;EXECUTABLE;LIBEXEC;USE_BASIS_UTILITIES;NO_BASIS_UTILITIES;EXPORT;NOEXPORT;FINAL"
930  "COMPONENT;RUNTIME_COMPONENT;LIBRARY_COMPONENT;DESTINATION;RUNTIME_DESTINATION;LIBRARY_DESTINATION;HEADER_DESTINATION"
931  ""
932  ${ARGN}
933  )
934  set (SOURCES "${ARGN_UNPARSED_ARGUMENTS}")
935  basis_set_flag (ARGN EXPORT ${BASIS_EXPORT_DEFAULT})
936  if (ARGN_USE_BASIS_UTILITIES AND ARGN_NO_BASIS_UTILITIES)
937  message (FATAL_ERROR "Target ${TARGET_UID}: Options USE_BASIS_UTILITIES and NO_BASIS_UTILITIES are mutually exclusive!")
938  endif ()
939  if (ARGN_USE_BASIS_UTILITIES)
940  set (USES_BASIS_UTILITIES TRUE)
941  elseif (ARGN_NO_BASIS_UTILITIES)
942  set (USES_BASIS_UTILITIES FALSE)
943  else ()
944  set (USES_BASIS_UTILITIES ${BASIS_UTILITIES})
945  endif ()
946  if (ARGN_SHARED AND (ARGN_EXECUTABLE OR ARGN_LIBEXEC))
947  message (FATAL_ERROR "Target ${TARGET_UID}: Options SHARED and EXECUTABLE or LIBEXEC are mutually exclusive!")
948  endif ()
949  if (ARGN_SHARED)
950  set (TYPE LIBRARY)
951  else ()
952  set (TYPE EXECUTABLE)
953  endif ()
954  string (TOLOWER "${TYPE}" type)
955  message (STATUS "Adding MATLAB ${type} ${TARGET_UID}...")
956  # IS_TEST flag
957  basis_sanitize_for_regex (RE "${PROJECT_TESTING_DIR}")
958  if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${RE}")
959  set (IS_TEST TRUE)
960  else ()
961  set (IS_TEST FALSE)
962  endif ()
963  # output directory
964  if (IS_TEST)
965  set (LIBRARY_OUTPUT_DIRECTORY "${TESTING_LIBRARY_DIR}")
966  if (ARGN_LIBEXEC)
967  set (RUNTIME_OUTPUT_DIRECTORY "${TESTING_LIBEXEC_DIR}")
968  else ()
969  set (RUNTIME_OUTPUT_DIRECTORY "${TESTING_RUNTIME_DIR}")
970  endif ()
971  else ()
972  set (LIBRARY_OUTPUT_DIRECTORY "${BINARY_LIBRARY_DIR}")
973  if (ARGN_LIBEXEC)
974  set (RUNTIME_OUTPUT_DIRECTORY "${BINARY_LIBEXEC_DIR}")
975  else ()
976  set (RUNTIME_OUTPUT_DIRECTORY "${BINARY_RUNTIME_DIR}")
977  endif ()
978  endif ()
979  # installation component
980  if (ARGN_COMPONENT)
981  if (NOT ARGN_LIBRARY_COMPONENT)
982  set (ARGN_LIBRARY_COMPONENT "${ARGN_COMPONENT}")
983  endif ()
984  if (NOT ARGN_RUNTIME_COMPONENT)
985  set (ARGN_RUNTIME_COMPONENT "${ARGN_COMPONENT}")
986  endif ()
987  endif ()
988  if (NOT ARGN_RUNTIME_COMPONENT)
989  set (ARGN_RUNTIME_COMPONENT "${BASIS_RUNTIME_COMPONENT}")
990  endif ()
991  if (NOT ARGN_RUNTIME_COMPONENT)
992  set (ARGN_RUNTIME_COMPONENT "Unspecified")
993  endif ()
994  if (NOT ARGN_LIBRARY_COMPONENT)
995  set (ARGN_LIBRARY_COMPONENT "${BASIS_LIBRARY_COMPONENT}")
996  endif ()
997  if (NOT ARGN_LIBRARY_COMPONENT)
998  set (ARGN_LIBRARY_COMPONENT "Unspecified")
999  endif ()
1000  # installation directories
1001  if (ARGN_DESTINATION)
1002  if (NOT ARGN_RUNTIME_DESTINATION)
1003  set (ARGN_RUNTIME_DESTINATION "${ARGN_DESTINATION}")
1004  endif ()
1005  if (NOT ARGN_LIBRARY_DESTINATION)
1006  set (ARGN_LIBRARY_DESTINATION "${ARGN_DESTINATION}")
1007  endif ()
1008  if (NOT ARGN_HEADER_DESTINATION)
1009  set (ARGN_HEADER_DESTINATION "${ARGN_DESTINATION}")
1010  endif ()
1011  endif ()
1012  if (NOT ARGN_RUNTIME_DESTINATION AND NOT IS_TEST)
1013  if (ARGN_LIBEXEC)
1014  set (ARGN_RUNTIME_DESTINATION "${INSTALL_LIBEXEC_DIR}")
1015  else ()
1016  set (ARGN_RUNTIME_DESTINATION "${INSTALL_RUNTIME_DIR}")
1017  endif ()
1018  endif ()
1019  if (NOT ARGN_LIBRARY_DESTINATION AND NOT IS_TEST)
1020  set (ARGN_LIBRARY_DESTINATION "${INSTALL_LIBRARY_DIR}")
1021  endif ()
1022  if (NOT ARGN_HEADER_DESTINATION AND NOT IS_TEST)
1023  set (ARGN_HEADER_DESTINATION ".")
1024  endif ()
1025  if (ARGN_RUNTIME_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
1026  set (ARGN_RUNTIME_DESTINATION)
1027  endif ()
1028  if (ARGN_LIBRARY_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
1029  set (ARGN_LIBRARY_DESTINATION)
1030  endif ()
1031  if (ARGN_HEADER_DESTINATION MATCHES "^[nN][oO][nN][eE]$")
1032  set (ARGN_HEADER_DESTINATION)
1033  elseif (NOT IS_ABSOLUTE ARGN_HEADER_DESTINATION)
1034  set (ARGN_HEADER_DESTINATION "${BINARY_INCLUDE_DIR}/${ARGN_HEADER_DESTINATION}")
1035  endif ()
1036  # whether to compile and compilation flags (for mcc)
1037  if ("^${TYPE}$" STREQUAL "^LIBRARY$")
1038  set (COMPILE TRUE)
1039  elseif (BASIS_COMPILE_MATLAB)
1040  if (MATLAB_MCC_EXECUTABLE)
1041  set (COMPILE TRUE)
1042  else ()
1043  set (COMPILE FALSE)
1044  message (WARNING "MATLAB Compiler not found. Will generate a wrapper script for target"
1045  " ${TARGET_UID} which executes the MATLAB code using the -r option of"
1046  " the MATLAB interpreter. It is recommended to compile the MATLAB code"
1047  " using the MATLAB Compiler if possible, however. Therefore, make sure"
1048  " that the MATLAB Compiler is available and check the value of the"
1049  " advanced MATLAB_MCC_EXECUTABLE variable in CMake."
1050  "\nMake sure to include MATLAB{mcc} as project dependency.")
1051  endif ()
1052  else ()
1053  set (COMPILE FALSE)
1054  endif ()
1055  if (WIN32 AND NOT COMPILE)
1056  # TODO implement generation of Windows Command on Windows
1057  set (CONTACT)
1058  if (PROJECT_CONTACT)
1059  set (CONTACT "\n\nYou may further want to contact ${PROJECT_CONTACT} in order to ask"
1060  " for a binary distribution package which contains pre-build binaries"
1061  " created using the MATLAB Compiler and download the MATLAB Compiler"
1062  " Runtime only if no MATLAB Compiler license is available to you.")
1064  endif ()
1065  if (NOT BASIS_COMPILE_MATLAB)
1066  basis_update_value (BASIS_COMPILE_MATLAB ON)
1067  endif ()
1068  message (FATAL_ERROR "The optional generation of a Windows Command which executes"
1069  " the MATLAB code using the -r option of the MATLAB interpreter"
1070  " as an alternative to the build of the MATLAB sources using"
1071  " the MATLAB Compiler is not yet implemented. You will have"
1072  " to obtain a MATLAB Compiler license and set the advanced"
1073  " MATLAB_MCC_EXECUTABLE variable in CMake or use this package"
1074  " on a Unix system instead.${CONTACT}")
1075  endif ()
1076  if (COMPILE)
1077  if (NOT MATLAB_MCC_EXECUTABLE)
1078  message (FATAL_ERROR "MATLAB Compiler not found! It is required to build target ${TARGET_UID}."
1079  " Ensure that MATLAB{mcc} is declared as project dependency"
1080  " and check the setting of MATLAB_DIR and/or MATLAB_MCC_EXECUTABLE.")
1081  endif ()
1083  else ()
1084  if (NOT MATLAB_EXECUTABLE)
1085  message (FATAL_ERROR "MATLAB not found! It is required to build target ${TARGET_UID}."
1086  " Ensure that MATLAB{matlab} is declared as project dependency"
1087  " and check the setting of MATLAB_DIR and/or MATLAB_EXECUTABLE.")
1088  endif ()
1089  endif ()
1090  if ("^${TYPE}$" STREQUAL "^EXECUTABLE$")
1091  set (COMPILE_FLAGS "${BASIS_MCC_FLAGS}")
1092  else ()
1093  set (COMPILE_FLAGS "")
1094  endif ()
1095  # output file name prefix/suffix
1096  if ("^${TYPE}$" STREQUAL "^EXECUTABLE$")
1097  set (PREFIX)
1098  if (WIN32 AND "^${COMPILE_FLAGS}$" STREQUAL "^NOMCC$")
1099  set (SUFFIX ".cmd")
1100  else ()
1101  set (SUFFIX)
1102  endif ()
1103  else ()
1104  if (WIN32)
1105  set (PREFIX)
1106  set (SUFFIX .lib) # link library file extension
1107  elseif (APPLE)
1108  set (PREFIX lib)
1109  set (SUFFIX .dylib)
1110  else ()
1111  set (PREFIX lib)
1112  set (SUFFIX .so)
1113  endif ()
1114  endif ()
1115  # configure (.in) source files
1117  # add custom target
1118  add_custom_target (${TARGET_UID} ALL SOURCES ${SOURCES})
1119  basis_get_target_name (OUTPUT_NAME "${TARGET_UID}")
1120  get_directory_property (INCLUDE_DIRS INCLUDE_DIRECTORIES)
1121  get_directory_property (LINK_DIRS LINK_DIRECTORIES)
1123  ${TARGET_UID}
1124  PROPERTIES
1125  LANGUAGE "MATLAB"
1126  BASIS_TYPE "MCC_${TYPE}"
1127  BASIS_UTILITIES FALSE # TODO Implement utilities for MATLAB
1128  BASIS_INCLUDE_DIRECTORIES "${INCLUDE_DIRS}"
1129  BASIS_LINK_DIRECTORIES "${LINK_DIRS}"
1130  BUILD_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET_UID}"
1131  SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
1132  BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
1133  LIBRARY_OUTPUT_DIRECTORY "${LIBRARY_OUTPUT_DIRECTORY}"
1134  LIBRARY_INSTALL_DIRECTORY "${ARGN_LIBRARY_DESTINATION}"
1135  LIBRARY_HEADER_DIRECTORY "${ARGN_HEADER_DESTINATION}"
1136  LIBRARY_COMPONENT "${ARGN_LIBRARY_COMPONENT}"
1137  RUNTIME_OUTPUT_DIRECTORY "${RUNTIME_OUTPUT_DIRECTORY}"
1138  RUNTIME_INSTALL_DIRECTORY "${ARGN_RUNTIME_DESTINATION}"
1139  RUNTIME_COMPONENT "${ARGN_RUNTIME_COMPONENT}"
1140  PREFIX "${PREFIX}"
1141  OUTPUT_NAME "${OUTPUT_NAME}"
1142  SUFFIX "${SUFFIX}"
1143  COMPILE_FLAGS "${COMPILE_FLAGS}"
1144  COMPILE "${COMPILE}"
1145  LINK_DEPENDS ""
1146  EXPORT ${EXPORT}
1147  LIBEXEC ${ARGN_LIBEXEC}
1148  TEST ${IS_TEST}
1149  )
1150  # finalize target
1151  if (ARGN_FINAL)
1152  basis_finalize_targets (${TARGET_UID})
1153  endif ()
1154  # add target to list of targets
1155  basis_set_project_property (APPEND PROPERTY TARGETS "${TARGET_UID}")
1156  message (STATUS "Adding MATLAB ${type} ${TARGET_UID}... - done")
1157 endfunction ()
1158 
1159 # ============================================================================
1160 # custom build commands
1161 # ============================================================================
1162 
1163 # ----------------------------------------------------------------------------
1164 ## @brief Add custom command for build of MEX-file.
1165 #
1166 # This function is called by basis_finalize_targets() which in turn is called
1167 # by basis_project_end(), i.e., the end of the root CMake configuration file
1168 # of the (sub-)project.
1169 #
1170 # @param [in] TARGET_UID Name/UID of custom target added by basis_add_mex_file().
1171 #
1172 # @sa basis_add_mex_file()
1173 #
1174 # @ingroup CMakeUtilities
1175 function (basis_build_mex_file TARGET_UID)
1176  # does this target exist ?
1177  basis_get_target_uid (TARGET_UID "${TARGET_UID}")
1178  if (NOT TARGET "${TARGET_UID}")
1179  message (FATAL_ERROR "Unknown build target: ${TARGET_UID}")
1180  endif ()
1181  if (BASIS_VERBOSE)
1182  message (STATUS "Adding build command for target ${TARGET_UID}...")
1183  endif ()
1184  # get target properties
1185  basis_get_target_name (TARGET_NAME ${TARGET_UID})
1186  set (
1187  PROPERTIES
1188  BASIS_TYPE
1190  BASIS_INCLUDE_DIRECTORIES
1191  BASIS_LINK_DIRECTORIES
1192  BUILD_DIRECTORY
1193  SOURCE_DIRECTORY
1194  BINARY_DIRECTORY
1195  LIBRARY_OUTPUT_DIRECTORY
1196  LIBRARY_INSTALL_DIRECTORY
1197  LIBRARY_COMPONENT
1198  PREFIX
1199  OUTPUT_NAME
1200  SUFFIX
1201  COMPILE_FLAGS
1202  LINK_DEPENDS
1203  LINK_FLAGS
1204  MFILE
1205  EXPORT
1206  SOURCES
1207  )
1208  get_target_property (IS_TEST ${TARGET_UID} TEST)
1209  foreach (PROPERTY ${PROPERTIES})
1210  get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
1211  if (NOT ${PROPERTY})
1212  set (${PROPERTY})
1213  endif ()
1214  endforeach ()
1215  # sanity check of property values
1216  if (NOT BASIS_TYPE MATCHES "^MEX$")
1217  message (FATAL_ERROR "Target ${TARGET_UID}: Invalid BASIS_TYPE: ${BASIS_TYPE}")
1218  endif ()
1219  list (GET SOURCES 0 BUILD_DIR) # CMake <3.1 stores path to internal build directory here
1220  if (BUILD_DIR MATCHES "CMakeFiles")
1221  list (REMOVE_AT SOURCES 0)
1222  endif ()
1223  set (BUILD_DIR "${BUILD_DIRECTORY}.dir")
1224  if (NOT SOURCES)
1225  message (FATAL_ERROR "Target ${TARGET_UID}: Empty SOURCES list!"
1226  " Have you accidentally modified this read-only property or"
1227  " is your (newer) CMake version not compatible with BASIS?")
1228  endif ()
1229  if (NOT LIBRARY_COMPONENT)
1230  set (LIBRARY_COMPONENT "Unspecified")
1231  endif ()
1232  if (MFILE)
1233  if (NOT IS_ABSOLUTE "${MFILE}")
1234  set (MFILE "${SOURCE_DIRECTORY}/${MFILE}")
1235  endif ()
1236  if (NOT EXISTS "${MFILE}")
1237  message (FATAL_ERROR "M-file ${MFILE} of MEX-file target ${TARGET_UID} does not exist!")
1238  endif ()
1239  endif ()
1240  # output name
1241  if (NOT OUTPUT_NAME)
1242  set (OUTPUT_NAME "${TARGET_NAME}")
1243  endif ()
1244  if (SUFFIX)
1245  set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
1246  endif ()
1247  string (REGEX REPLACE "/+" "/" PREFIX "${PREFIX}")
1248  string (REGEX REPLACE "/$" "" PREFIX "${PREFIX}")
1249  if (PREFIX AND NOT PREFIX MATCHES "^/")
1250  set (PREFIX "/${PREFIX}")
1251  endif ()
1252  # initialize dependencies of custom build command
1253  set (DEPENDS ${SOURCES})
1254  # get list of libraries to link to
1255  set (LINK_LIBS)
1256  foreach (LIB ${LINK_DEPENDS})
1257  basis_get_target_uid (UID "${LIB}")
1258  if (TARGET ${UID})
1259  basis_get_target_location (LIB_FILE ${UID} ABSOLUTE)
1260  string (REPLACE "<${BASIS_GE_CONFIG}>" "{CONFIG}" LIB_FILE "${LIB_FILE}")
1261  list (APPEND DEPENDS ${UID})
1262  else ()
1263  set (LIB_FILE "${LIB}")
1264  endif ()
1265  list (APPEND LINK_LIBS "${LIB_FILE}")
1266  endforeach ()
1267  get_filename_component (OUTPUT_NAME_WE "${OUTPUT_NAME}" NAME_WE)
1268  # decompose user supplied MEX switches
1269  macro (extract VAR)
1270  string (REGEX REPLACE "${VAR}=\"([^\"]+)\"|${VAR}=([^\" ])*" "" COMPILE_FLAGS "${COMPILE_FLAGS}")
1271  if (CMAKE_MATCH_1)
1272  set (${VAR} "${CMAKE_MATCH_1}")
1273  elseif (CMAKE_MATCH_2)
1274  set (${VAR} "${CMAKE_MATCH_2}")
1275  else ()
1276  set (${VAR})
1277  endif ()
1278  endmacro ()
1279  if (UNIX)
1280  extract (CC)
1281  extract (CFLAGS)
1282  extract (CXX)
1283  extract (CXXFLAGS)
1284  extract (CLIBS)
1285  extract (CXXLIBS)
1286  extract (LD)
1287  extract (LDXX)
1288  extract (LDFLAGS)
1289  extract (LDCXXFLAGS)
1290  if (LINK_FLAGS)
1291  set (LDFLAGS "${LDFLAGS} ${LINK_FLAGS}")
1292  endif ()
1293  # set defaults for not provided options
1294  if (NOT CC)
1295  set (CC "${CMAKE_C_COMPILER}")
1296  endif ()
1297  if (NOT CFLAGS)
1298  set (CFLAGS "${CMAKE_C_FLAGS}")
1299  endif ()
1300  if (NOT CFLAGS MATCHES "( |^)-fPIC( |$)")
1301  set (CFLAGS "-fPIC ${CFLAGS}")
1302  endif ()
1303  if (NOT CXX)
1304  set (CXX "${CMAKE_CXX_COMPILER}")
1305  endif ()
1306  if (NOT CXXFLAGS)
1307  set (CXXFLAGS "${CMAKE_CXX_FLAGS}")
1308  endif ()
1309  if (NOT CXXFLAGS MATCHES "( |^)-fPIC( |$)")
1310  set (CXXFLAGS "-fPIC ${CXXFLAGS}")
1311  endif ()
1312  if (NOT LD)
1313  set (LD "${CMAKE_CXX_COMPILER}") # do not use CMAKE_LINKER here
1314  endif ()
1315  if (NOT LDFLAGS)
1316  set (LDFLAGS "\$LDFLAGS ${CMAKE_SHARED_LINKER_FLAGS}")
1317  endif ()
1318  # We chose to use CLIBS and CXXLIBS instead of the -L and -l switches
1319  # to add also link libraries added via basis_target_link_libraries()
1320  # because the MEX script will not use these arguments if CLIBS or CXXLIBS
1321  # is set. Moreover, the -l switch can only be used to link to a shared
1322  # library and not a static one (on UNIX).
1323  #foreach (LIB ${LINK_LIBS})
1324  # if (LIB MATCHES "[/\\\.]")
1325  # set (CXXLIBS "${CXXLIBS} ${LIB}")
1326  # endif ()
1327  #endforeach ()
1328  endif ()
1329  # get remaining switches
1330  basis_string_to_list (MEX_USER_ARGS "${COMPILE_FLAGS}")
1331  # assemble MEX switches
1332  set (MEX_ARGS)
1333  if (UNIX)
1334  list (APPEND MEX_ARGS "CC=${CC}" "CFLAGS=${CFLAGS}") # C compiler and flags
1335  if (CLIBS)
1336  list (APPEND MEX_ARGS "CLIBS=${CLIBS}") # C link libraries
1337  endif ()
1338  list (APPEND MEX_ARGS "CXX=${CXX}" "CXXFLAGS=${CXXFLAGS}") # C++ compiler and flags
1339  if (CXXLIBS)
1340  list (APPEND MEX_ARGS "CXXLIBS=${CXXLIBS}") # C++ link libraries
1341  endif ()
1342  if (LD)
1343  list (APPEND MEX_ARGS "LD=${LD}") # C linker
1344  endif ()
1345  if (LDFLAGS)
1346  list (APPEND MEX_ARGS "LDFLAGS=${LDFLAGS}") # C link flags
1347  endif ()
1348  if (LDCXX)
1349  list (APPEND MEX_ARGS "LDCXX=${LDCXX}") # C++ linker
1350  endif ()
1351  if (LDCXXFLAGS)
1352  list (APPEND MEX_ARGS "LDCXXFLAGS=${LDCXXFLAGS}") # C++ link flags
1353  endif ()
1354  endif ()
1355  list (APPEND MEX_ARGS "-outdir" "${BUILD_DIR}") # output directory
1356  list (APPEND MEX_ARGS "-output" "${OUTPUT_NAME_WE}") # output name (w/o extension)
1357  foreach (INCLUDE_PATH ${BASIS_INCLUDE_DIRECTORIES}) # include directories
1358  list (FIND MEX_ARGS "-I${INCLUDE_PATH}" IDX) # as specified via
1359  if (INCLUDE_PATH AND IDX EQUAL -1) # basis_include_directories()
1360  list (APPEND MEX_ARGS "-I${INCLUDE_PATH}")
1361  endif ()
1362  endforeach ()
1363  set (MEX_LIBPATH)
1364  set (MEX_LIBS)
1365  foreach (LINK_DIR ${BASIS_LINK_DIRECTORIES}) # link directories
1366  if (WIN32)
1367  string (REPLACE "/" "\\" LINK_DIR "${LINK_DIR}")
1368  set (LINK_DIR "/LIBPATH:\\\"${LINK_DIR}\\\"")
1369  else ()
1370  set (LINK_DIR "-L${LINK_DIR}")
1371  endif ()
1372  list (APPEND MEX_LIBPATH "${LINK_DIR}") # as specified via basis_link_directories()
1373  endforeach ()
1374  foreach (LIBRARY ${LINK_LIBS}) # link libraries
1375  get_filename_component (LINK_DIR "${LIBRARY}" PATH) # as specified via basis_target_link_libraries()
1376  get_filename_component (LINK_LIB "${LIBRARY}" NAME)
1377  string (REGEX REPLACE "\\.(so|dylib)(\\.[0-9]+)*$" "" LINK_LIB "${LINK_LIB}")
1378  if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
1379  # cf. https://github.com/cmake-basis/BASIS/issues/443
1380  string (REGEX REPLACE "\\.a(\\.[0-9]+)*$" "" LINK_LIB "${LINK_LIB}")
1381  endif ()
1382  string (REGEX REPLACE "^-l" "" LINK_LIB "${LINK_LIB}")
1383  if (LINK_DIR)
1384  if (WIN32)
1385  string (REPLACE "/" "\\" LINK_DIR "${LINK_DIR}")
1386  set (LINK_DIR "/LIBPATH:\\\"${LINK_DIR}\\\"")
1387  else ()
1388  set (LINK_DIR "-L${LINK_DIR}")
1389  endif ()
1390  list (APPEND MEX_LIBPATH "${LINK_DIR}")
1391  endif ()
1392  if (WIN32)
1393  if (NOT LINK_LIB MATCHES "\\.lib$")
1394  set (LINK_LIB "${LINK_LIB}.lib")
1395  endif ()
1396  else ()
1397  string (REGEX REPLACE "^lib" "" LINK_LIB "${LINK_LIB}")
1398  set (LINK_LIB "-l${LINK_LIB}")
1399  endif ()
1400  list (APPEND MEX_LIBS "${LINK_LIB}")
1401  endforeach ()
1402  if (MEX_LIBPATH)
1403  list (REMOVE_DUPLICATES MEX_LIBPATH)
1404  endif ()
1405  # do not remove duplicate entries in MEX_LIBS which may be needed
1406  # to resolve (cyclic) dependencies between statically linked libraries
1407  # (cf. https://github.com/cmake-basis/BASIS/issues/444)
1408  if (MEX_LIBPATH OR MEX_LIBS)
1409  if (WIN32)
1410  basis_list_to_delimited_string (MEX_LIBPATH " " NOAUTOQUOTE ${MEX_LIBPATH})
1411  basis_list_to_delimited_string (MEX_LIBS " " ${MEX_LIBS})
1412  list (APPEND MEX_ARGS "LINKFLAGS#$LINKFLAGS ${MEX_LIBPATH} ${MEX_LIBS}")
1413  else ()
1414  list (APPEND MEX_ARGS ${MEX_LIBPATH} ${MEX_LIBS})
1415  endif ()
1416  endif ()
1417  # other user switches
1418  list (APPEND MEX_ARGS ${MEX_USER_ARGS})
1419  # source files
1420  list (APPEND MEX_ARGS ${SOURCES})
1421  # build command for invocation of MEX script
1422  set (BUILD_CMD "${MATLAB_MEX_EXECUTABLE}" -v ${MEX_ARGS})
1423  set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
1424  set (BUILD_LOG "${BUILD_DIR}/build.log")
1425  set (BUILD_OUTPUT "${LIBRARY_OUTPUT_DIRECTORY}${PREFIX}/${OUTPUT_NAME}")
1426  set (BUILD_OUTPUTS "${BUILD_OUTPUT}")
1427  if (MFILE)
1428  set (BUILD_MFILE "${LIBRARY_OUTPUT_DIRECTORY}${PREFIX}/${OUTPUT_NAME_WE}.m")
1429  list (APPEND BUILD_OUTPUTS "${BUILD_MFILE}")
1430  else ()
1431  set (BUILD_MFILE)
1432  endif ()
1433  # configure build script
1434  configure_file ("${BASIS_SCRIPT_EXECUTE_PROCESS}" "${BUILD_SCRIPT}" @ONLY)
1435  # relative paths used for comments of commands
1436  file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${BUILD_OUTPUT}")
1437  # add custom command to build executable using MEX script
1438  add_custom_command (
1439  OUTPUT "${BUILD_OUTPUT}"
1440  # rebuild when input sources were modified
1441  DEPENDS "${BUILD_SCRIPT}" "${CMAKE_CURRENT_LIST_FILE}" ${DEPENDS}
1442  # invoke MEX script, wrapping the command in CMake execute_process()
1443  # command allows for inspection of command output for error messages
1444  # and specification of timeout
1445  COMMAND "${CMAKE_COMMAND}"
1446  "-DCONFIG=$<${BASIS_GE_CONFIG}>"
1447  "-DWORKING_DIRECTORY=${BUILD_DIR}"
1448  "-DTIMEOUT=${BASIS_MEX_TIMEOUT}"
1449  "-DERROR_EXPRESSION=[E|e]rror:"
1450  "-DOUTPUT_FILE=${BUILD_LOG}"
1451  "-DERROR_FILE=${BUILD_LOG}"
1452  "-DVERBOSE=OFF"
1453  "-DLOG_ARGS=ON"
1454  "-P" "${BUILD_SCRIPT}"
1455  # post-build command
1456  COMMAND "${CMAKE_COMMAND}" -E copy "${BUILD_DIR}/${OUTPUT_NAME}" "${BUILD_OUTPUT}"
1457  COMMAND "${CMAKE_COMMAND}" -E remove "${BUILD_DIR}/${OUTPUT_NAME}"
1458  # inform user where build log can be found
1459  COMMAND "${CMAKE_COMMAND}" -E echo "Build log written to ${BUILD_LOG}"
1460  # comment
1461  COMMENT "Building MEX-file ${REL}..."
1462  VERBATIM
1463  )
1464  if (BUILD_MFILE)
1465  add_custom_command (
1466  OUTPUT "${BUILD_MFILE}"
1467  DEPENDS "${MFILE}"
1468  COMMAND "${CMAKE_COMMAND}" -E copy "${MFILE}" "${BUILD_MFILE}"
1469  COMMENT "Copying M-file of ${REL}..."
1470  )
1471  endif ()
1472  # add custom target
1473  add_custom_target (_${TARGET_UID} DEPENDS ${BUILD_OUTPUTS} SOURCES ${SOURCES})
1474  add_dependencies (${TARGET_UID} _${TARGET_UID})
1475  # cleanup on "make clean"
1476  set_property (
1477  DIRECTORY
1478  APPEND PROPERTY
1479  ADDITIONAL_MAKE_CLEAN_FILES
1480  "${BUILD_DIR}/${OUTPUT_NAME}"
1481  "${BUILD_OUTPUTS}"
1482  "${BUILD_LOG}"
1483  )
1484  # export target
1485  if (EXPORT)
1486  basis_add_custom_export_target (${TARGET_UID} "${IS_TEST}")
1487  endif ()
1488  # install MEX-file
1489  if (LIBRARY_INSTALL_DIRECTORY)
1490  install (
1491  FILES ${BUILD_OUTPUTS}
1492  DESTINATION "${LIBRARY_INSTALL_DIRECTORY}${PREFIX}"
1493  COMPONENT "${LIBRARY_COMPONENT}"
1494  )
1495  endif ()
1496  if (BASIS_VERBOSE)
1497  message (STATUS "Adding build command for target ${TARGET_UID}... - done")
1498  endif ()
1499 endfunction ()
1500 
1501 # ----------------------------------------------------------------------------
1502 ## @brief Add custom command for build of MATLAB Compiler target.
1503 #
1504 # This function is called by basis_finalize_targets() which in turn is called
1505 # by basis_project_end(), i.e., the end of the root CMake configuration file
1506 # of the (sub-)project.
1507 #
1508 # @param [in] TARGET_UID Name/UID of custom target added by basis_add_mcc_target().
1509 #
1510 # @sa basis_add_mcc_target()
1511 #
1512 # @ingroup CMakeUtilities
1513 function (basis_build_mcc_target TARGET_UID)
1514  # does this target exist ?
1515  basis_get_target_uid (TARGET_UID "${TARGET_UID}")
1516  if (NOT TARGET "${TARGET_UID}")
1517  message (FATAL_ERROR "Unknown target ${TARGET_UID}!")
1518  endif ()
1519  if (BASIS_VERBOSE)
1520  message (STATUS "Adding build command for target ${TARGET_UID}...")
1521  endif ()
1522  # get target properties
1523  basis_get_target_name (TARGET_NAME ${TARGET_UID})
1524  set (
1525  PROPERTIES
1526  BASIS_TYPE
1528  BASIS_INCLUDE_DIRECTORIES
1529  BASIS_LINK_DIRECTORIES
1530  BUILD_DIRECTORY
1531  SOURCE_DIRECTORY
1532  BINARY_DIRECTORY
1533  LIBRARY_OUTPUT_DIRECTORY
1534  LIBRARY_INSTALL_DIRECTORY
1535  LIBRARY_HEADER_DIRECTORY
1536  LIBRARY_COMPONENT
1537  RUNTIME_OUTPUT_DIRECTORY
1538  RUNTIME_INSTALL_DIRECTORY
1539  RUNTIME_COMPONENT
1540  PREFIX
1541  OUTPUT_NAME
1542  SUFFIX
1543  SOURCES
1544  COMPILE_FLAGS
1545  COMPILE
1546  LINK_DEPENDS
1547  EXPORT
1548  )
1549  get_target_property (IS_TEST ${TARGET_UID} TEST)
1550  foreach (PROPERTY ${PROPERTIES})
1551  get_target_property (${PROPERTY} ${TARGET_UID} ${PROPERTY})
1552  if (NOT ${PROPERTY})
1553  set (${PROPERTY})
1554  endif ()
1555  endforeach ()
1556  # sanity checks of property values
1557  set (EXECUTABLE FALSE)
1558  set (LIBEXEC FALSE)
1559  set (LIBRARY FALSE)
1560  if (BASIS_TYPE MATCHES "^MCC_(EXECUTABLE|LIBEXEC|LIBRARY)$")
1561  set (${CMAKE_MATCH_1} TRUE)
1562  if (LIBEXEC)
1563  set (EXECUTABLE TRUE)
1564  endif ()
1565  else ()
1566  message (FATAL_ERROR "Target ${TARGET_UID}: Invalid BASIS_TYPE: ${BASIS_TYPE}")
1567  endif ()
1568  list (GET SOURCES 0 BUILD_DIR) # CMake <3.1 stores path to internal build directory here
1569  if (BUILD_DIR MATCHES "CMakeFiles")
1570  list (REMOVE_AT SOURCES 0)
1571  endif ()
1572  set (BUILD_DIR "${BUILD_DIRECTORY}.dir")
1573  if (NOT SOURCES)
1574  message (FATAL_ERROR "Target ${TARGET_UID}: Empty SOURCES list!"
1575  " Have you accidentally modified this read-only property or"
1576  " is your (newer) CMake version not compatible with BASIS?")
1577  endif ()
1578  list (GET SOURCES 0 MAIN_SOURCE) # entry point
1579  if (NOT RUNTIME_COMPONENT)
1580  set (RUNTIME_COMPONENT "Unspecified")
1581  endif ()
1582  if (NOT LIBRARY_COMPONENT)
1583  set (LIBRARY_COMPONENT "Unspecified")
1584  endif ()
1585  # output name
1586  if (NOT OUTPUT_NAME)
1587  set (OUTPUT_NAME "${TARGET_NAME}")
1588  endif ()
1589  if (PREFIX)
1590  set (OUTPUT_NAME "${PREFIX}${OUTPUT_NAME}")
1591  endif ()
1592  if (SUFFIX)
1593  set (OUTPUT_NAME "${OUTPUT_NAME}${SUFFIX}")
1594  endif ()
1595  get_filename_component (OUTPUT_NAME_WE "${OUTPUT_NAME}" NAME_WE)
1596  # MCC only allows alpha-numeric characters and underscores
1597  # TODO: Figure out how to build a shared library without this restriction
1598  # (cf. https://github.com/cmake-basis/BASIS/issues/410).
1599  if (NOT OUTPUT_NAME MATCHES "[a-zA-Z][_a-zA-Z0-9]*")
1600  message (FATAL_ERROR "Target ${TARGET_UID} has invalid output name ${OUTPUT_NAME}."
1601  "MCC only allows alpha-numeric characters and underscores. "
1602  "See GitHub issue #410 for updates on this restriction at\n"
1603  "https://github.com/cmake-basis/BASIS/issues/410")
1604  endif ()
1605  set (MCC_OUTPUT_NAME "${OUTPUT_NAME}")
1606  set (MCC_OUTPUT_NAME_WE "${OUTPUT_NAME_WE}")
1607  #string (REGEX REPLACE "\\+|-" "_" MCC_OUTPUT_NAME "${OUTPUT_NAME}")
1608  #get_filename_component (MCC_OUTPUT_NAME_WE "${MCC_OUTPUT_NAME}" NAME_WE)
1609  # initialize dependencies of custom build command
1610  set (DEPENDS ${SOURCES})
1611  # build output file and comment
1612  file (RELATIVE_PATH REL "${CMAKE_BINARY_DIR}" "${BUILD_DIR}/${OUTPUT_NAME}")
1613  if (LIBRARY)
1614  set (BUILD_OUTPUT "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
1615  set (BUILD_COMMENT "Building MATLAB library ${REL}...")
1616  else ()
1617  set (BUILD_OUTPUT "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}")
1618  set (BUILD_COMMENT "Building MATLAB executable ${REL}...")
1619  endif ()
1620  # --------------------------------------------------------------------------
1621  # assemble build command for build of executable wrapper script
1622  if (EXECUTABLE AND NOT COMPILE)
1623  # used to recognize source files which are located in the build tree
1624  basis_sanitize_for_regex (BINARY_CODE_DIR_RE "${BINARY_CODE_DIR}")
1625  # main MATLAB function and search path
1626  get_filename_component (MATLAB_COMMAND "${MAIN_SOURCE}" NAME_WE)
1627  get_filename_component (SOURCE_DIR "${MAIN_SOURCE}" PATH)
1628  get_filename_component (SOURCE_PACKAGE "${SOURCE_DIR}" NAME)
1629  if (SOURCE_PACKAGE MATCHES "^\\+")
1630  get_filename_component (SOURCE_DIR "${SOURCE_DIR}" PATH)
1631  set (MATLAB_COMMAND "${SOURCE_PACKAGE}.${MATLAB_COMMAND}")
1632  string (REGEX REPLACE "^\\+" "" MATLAB_COMMAND "${MATLAB_COMMAND}")
1633  else ()
1634  set (SOURCE_PACKAGE "${MATLAB_COMMAND}")
1635  endif ()
1636  basis_get_relative_path (DIR "${PROJECT_SOURCE_DIR}" "${SOURCE_DIR}")
1637  set (BINARY_DIR "${PROJECT_BINARY_DIR}/${DIR}") # location of configured sources
1638  # output file
1639  set (OUTPUT_FILE "${BUILD_OUTPUT}")
1640  get_filename_component (OUTPUT_DIR "${OUTPUT_FILE}" PATH)
1641  # installation
1642  set (INSTALL_FILE "${BUILD_DIR}/${OUTPUT_NAME}") # file to be installed
1643  set (INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${RUNTIME_INSTALL_DIRECTORY}") # location of installed wrapper
1644  set (INSTALL_SOURCE_DIR "${INSTALL_MATLAB_LIBRARY_DIR}") # location of installed MATLAB sources
1645  if (NOT SOURCE_PACKAGE MATCHES "^\\+")
1646  set (INSTALL_SOURCE_DIR "${INSTALL_SOURCE_DIR}/${SOURCE_PACKAGE}")
1647  endif ()
1648  # startup file
1649  if (SOURCE_PACKAGE MATCHES "^\\+")
1650  set (BUILD_STARTUP_FILE "${BINARY_DIR}/${SOURCE_PACKAGE}/startup.m")
1651  set (INSTALL_STARTUP_FILE "${BUILD_DIR}/startup.m")
1652  set (INSTALL_STARTUP_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_SOURCE_DIR}/${SOURCE_PACKAGE}")
1653  else ()
1654  set (BUILD_STARTUP_FILE "${BINARY_DIR}/startup.m")
1655  set (INSTALL_STARTUP_FILE "${BUILD_DIR}/startup.m")
1656  set (INSTALL_STARTUP_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_SOURCE_DIR}")
1657  endif ()
1658  get_filename_component (BUILD_STARTUP_DIR "${BUILD_STARTUP_FILE}" PATH)
1659  list (APPEND BUILD_OUTPUT "${BUILD_STARTUP_FILE}")
1660  list (APPEND BUILD_OUTPUT "${INSTALL_STARTUP_FILE}")
1661  # MATLAB search path
1662  #
1663  # The following paths are written to the startup M-file such
1664  # that they can conveniently be added to the search path within an
1665  # interactive MATLAB sesssion. The path to this startup file is
1666  # added to the search path by the wrapper executable first, and
1667  # then this startup file is evaluated which adds all additional
1668  # paths. If no startup file is specified, all paths are added
1669  # to the search path on the command-line in the wrapper script.
1670  set (BUILD_MATLABPATH)
1671  set (INSTALL_MATLABPATH)
1672  # if any source file was configured and hence is located in the
1673  # build tree instead of the source tree, add corresponding build
1674  # tree path to BUILD_MATLABPATH as well
1675  if (SOURCES MATCHES "^${BINARY_CODE_DIR_RE}")
1676  file (RELATIVE_PATH REL "${BUILD_STARTUP_DIR}" "${BINARY_DIR}")
1677  if (REL)
1678  list (APPEND BUILD_MATLABPATH "${REL}")
1679  else ()
1680  list (APPEND BUILD_MATLABPATH ".")
1681  endif ()
1682  endif ()
1683  list (APPEND BUILD_MATLABPATH "${SOURCE_DIR}")
1684  # The following is not required because startup script is located
1685  # in the same directory as the other sources and basis_generate_matlab_executable()
1686  # adds this path automatically in order to run the startup script.
1687  # Moreover, if anyone wants to run the startup script, they have to
1688  # add this path manually or make it the current directory first.
1689  #file (RELATIVE_PATH REL "${INSTALL_STARTUP_DIR}" "${CMAKE_INSTALL_PREFIX}/${INSTALL_SOURCE_DIR}")
1690  #if (REL)
1691  # list (APPEND INSTALL_MATLABPATH "${REL}")
1692  #else ()
1693  # list (APPEND INSTALL_MATLABPATH ".")
1694  #endif ()
1695  # link dependencies, i.e., MEX-files
1696  foreach (LINK_DEPEND ${LINK_DEPENDS})
1697  basis_get_target_uid (UID "${LINK_DEPEND}")
1698  if (TARGET ${UID})
1699  basis_get_target_location (LINK_DEPEND ${UID} ABSOLUTE)
1700  if (LINK_DEPEND MATCHES "\\.mex")
1701  get_filename_component (LINK_PATH "${LINK_DEPEND}" PATH)
1702  list (APPEND BUILD_MATLABPATH "${LINK_PATH}")
1703  list (APPEND DEPENDS ${UID})
1704  endif ()
1705  basis_get_target_location (LINK_DEPEND ${UID} POST_INSTALL)
1706  basis_get_target_property (BUNDLED ${UID} BUNDLED)
1707  basis_get_target_property (IMPORTED ${UID} IMPORTED)
1708  if (NOT IMPORTED OR BUNDLED)
1709  file (RELATIVE_PATH REL "${INSTALL_STARTUP_DIR}" "${LINK_DEPEND}")
1710  if (REL)
1711  set (LINK_DEPEND "${REL}")
1712  else ()
1713  set (LINK_DEPEND ".")
1714  endif ()
1715  endif ()
1716  if (LINK_DEPEND MATCHES "\\.mex")
1717  get_filename_component (LINK_PATH "${LINK_DEPEND}" PATH)
1718  list (APPEND INSTALL_MATLABPATH "${LINK_PATH}")
1719  endif ()
1720  elseif (IS_ABSOLUTE "${LINK_DEPEND}")
1721  if (IS_DIRECTORY "${LINK_DEPEND}")
1722  list (APPEND BUILD_MATLABPATH "${LINK_DEPEND}")
1723  list (APPEND INSTALL_MATLABPATH "${LINK_DEPEND}")
1724  elseif (EXISTS "${LINK_DEPEND}" AND LINK_DEPEND MATCHES "\\.mex")
1725  get_filename_component (LINK_PATH "${LINK_DEPEND}" PATH)
1726  list (APPEND BUILD_MATLABPATH "${LINK_PATH}")
1727  list (APPEND INSTALL_MATLABPATH "${LINK_PATH}")
1728  endif ()
1729  endif ()
1730  endforeach ()
1731  # cleanup directory paths
1732  string (REGEX REPLACE "/+" "/" BUILD_MATLABPATH "${BUILD_MATLABPATH}")
1733  string (REGEX REPLACE "/+" "/" INSTALL_MATLABPATH "${INSTALL_MATLABPATH}")
1734  string (REGEX REPLACE "/(;|$)" "\\1" BUILD_MATLABPATH "${BUILD_MATLABPATH}")
1735  string (REGEX REPLACE "/(;|$)" "\\1" INSTALL_MATLABPATH "${INSTALL_MATLABPATH}")
1736  # remove duplicates
1737  if (BUILD_MATLABPATH)
1738  list (REMOVE_DUPLICATES BUILD_MATLABPATH)
1739  endif ()
1740  if (INSTALL_MATLABPATH)
1741  list (REMOVE_DUPLICATES INSTALL_MATLABPATH)
1742  endif ()
1743  # configure build script
1744  set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
1745  configure_file ("${BASIS_MODULE_PATH}/generate_matlab_executable.cmake.in" "${BUILD_SCRIPT}" @ONLY)
1746  # add custom command to build wrapper executable
1747  add_custom_command (
1748  OUTPUT ${BUILD_OUTPUT}
1749  # rebuild when input sources were modified
1750  MAIN_DEPENDENCY "${MAIN_SOURCE}"
1751  DEPENDS "${BUILD_SCRIPT}" "${CMAKE_CURRENT_LIST_FILE}" ${DEPENDS}
1752  # invoke MATLAB Compiler in either MATLAB or standalone mode
1753  # wrapping command in CMake execute_process () command allows for inspection
1754  # parsing of command output for error messages and specification of timeout
1755  COMMAND "${CMAKE_COMMAND}" "-P" "${BUILD_SCRIPT}"
1756  # comment
1757  COMMENT "${BUILD_COMMENT}"
1758  )
1759  # install source files - preserving relative paths in SOURCE_DIR
1760  foreach (SOURCE IN LISTS SOURCES)
1761  get_filename_component (REL "${SOURCE}" PATH)
1762  if (SOURCE MATCHES "^${BINARY_CODE_DIR_RE}")
1763  basis_get_relative_path (REL "${BINARY_DIR}" "${REL}")
1764  else ()
1765  basis_get_relative_path (REL "${SOURCE_DIR}" "${REL}")
1766  endif ()
1767  if (REL MATCHES "^\\.?$|^\\.\\./")
1768  install (
1769  FILES "${SOURCE}"
1770  DESTINATION "${INSTALL_SOURCE_DIR}"
1771  COMPONENT "${RUNTIME_COMPONENT}"
1772  )
1773  else ()
1774  install (
1775  FILES "${SOURCE}"
1776  DESTINATION "${INSTALL_SOURCE_DIR}/${REL}"
1777  COMPONENT "${RUNTIME_COMPONENT}"
1778  )
1779  endif ()
1780  endforeach ()
1781  # --------------------------------------------------------------------------
1782  # assemble build command for build using MATLAB Compiler
1783  else ()
1784  set (INSTALL_FILE "${BUILD_OUTPUT}") # file to be installed
1785  # get list of libraries to link to (e.g., MEX-file)
1786  set (LINK_LIBS)
1787  foreach (LIB ${LINK_DEPENDS})
1788  basis_get_target_uid (UID "${LIB}")
1789  if (TARGET ${UID})
1790  basis_get_target_location (LIB_FILE ${UID} ABSOLUTE)
1791  string (REPLACE "<${BASIS_GE_CONFIG}>" "{CONFIG}" LIB_FILE "${LIB_FILE}")
1792  list (APPEND DEPENDS ${UID})
1793  else ()
1794  set (LIB_FILE "${LIB}")
1795  endif ()
1796  list (APPEND LINK_LIBS "${LIB_FILE}")
1797  endforeach ()
1798  # MATLAB search path
1799  foreach (P ${SOURCES})
1800  get_filename_component (P "${P}" PATH)
1801  list (APPEND MATLABPATH "${P}")
1802  endforeach ()
1803  list (APPEND MATLABPATH ${BASIS_INCLUDE_DIRECTORIES})
1804  # MATLAB Compiler arguments
1805  string (REGEX REPLACE " +" ";" MCC_ARGS "${COMPILE_FLAGS}") # user specified flags
1806  foreach (P IN LISTS MATLABPATH) # search path, -I options
1807  string (REGEX REPLACE "/(\\+|@).*$" "" P "${P}") # remove package/class subdirectories
1808  list (FIND MCC_ARGS "${P}" IDX) # skip if already added
1809  if (IDX GREATER 0)
1810  math (EXPR IDX "${IDX} - 1")
1811  list (GET MCC_ARGS ${IDX} OPT)
1812  if (NOT OPT MATCHES "^-I$")
1813  set (IDX -1)
1814  endif ()
1815  endif ()
1816  if (EXISTS "${P}" AND IDX EQUAL -1)
1817  list (APPEND MCC_ARGS -I "${P}")
1818  endif ()
1819  endforeach ()
1820  if (LIBRARY)
1821  list (APPEND MCC_ARGS -W "cpplib:${MCC_OUTPUT_NAME_WE}" -T link:lib) # build library
1822  else () # or
1823  list (APPEND MCC_ARGS -m -o "${MCC_OUTPUT_NAME_WE}") # build standalone application
1824  endif ()
1825  list (APPEND MCC_ARGS -d "${BUILD_DIR}") # (temp) output directory
1826  list (APPEND MCC_ARGS ${SOURCES}) # source M-files
1827  foreach (LIB ${LINK_LIBS}) # link libraries, e.g. MEX-files
1828  list (FIND MCC_ARGS "${LIB}" IDX)
1829  if (LIB AND IDX EQUAL -1)
1830  list (APPEND MCC_ARGS "-a" "${LIB}")
1831  endif ()
1832  endforeach ()
1833  # build command for invocation of MATLAB Compiler in standalone mode
1834  set (BUILD_CMD "${MATLAB_MCC_EXECUTABLE}" ${MCC_USER_ARGS} ${MCC_ARGS})
1835  set (BUILD_LOG "${BUILD_DIR}/build.log")
1836  set (BUILD_SCRIPT "${BUILD_DIR}/build.cmake")
1837  set (WORKING_DIR "${SOURCE_DIRECTORY}")
1838  set (MATLAB_MODE OFF)
1839  # build command for invocation of MATLAB Compiler in MATLAB mode
1840  if (BASIS_MCC_MATLAB_MODE)
1841  set (MATLAB_MODE ON)
1842  if (NOT MATLAB_EXECUTABLE)
1843  message (WARNING "MATLAB executable not found. It is required to build target ${TARGET_UID} in MATLAB mode."
1844  " Either set the advanced option BASIS_MCC_MATLAB_MODE to OFF or add MATLAB{matlab} as dependency."
1845  " Will build target ${TARGET_UID} in standalone mode instead.")
1846  set (MATLAB_MODE OFF)
1847  endif ()
1848  if (MATLAB_MODE)
1849  basis_list_to_delimited_string (ARGS "', '" NOAUTOQUOTE ${MCC_USER_ARGS} ${MCC_ARGS})
1850  set (
1851  BUILD_CMD
1852  "${MATLAB_EXECUTABLE}" # run MATLAB
1853  "-nosplash" # do not display splash screen on start up
1854  "-nodesktop" # run in command line mode
1855  "-nojvm" # we do not need the Java Virtual Machine
1856  "-r" "try, mcc('-v', '${ARGS}'), catch err, fprintf(2, err.message), end, quit force"
1857  )
1858  endif ()
1859  endif ()
1860  # post-build command
1861  set (POST_BUILD_COMMAND)
1862  if (NOT "^${MCC_OUTPUT_NAME}$" STREQUAL "^${OUTPUT_NAME}$")
1863  list (APPEND POST_BUILD_COMMAND
1864  COMMAND "${CMAKE_COMMAND}" -E copy
1865  "${BUILD_DIR}/${MCC_OUTPUT_NAME}"
1866  "${BUILD_DIR}/${OUTPUT_NAME}"
1867  COMMAND "${CMAKE_COMMAND}" -E copy
1868  "${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.h"
1869  "${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
1870  )
1871  endif ()
1872  if (LIBRARY)
1873  list (APPEND POST_BUILD_COMMAND
1874  COMMAND "${CMAKE_COMMAND}" -E copy
1875  "${BUILD_DIR}/${OUTPUT_NAME}"
1876  "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
1877  COMMAND "${CMAKE_COMMAND}" -E copy
1878  "${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
1879  "${LIBRARY_HEADER_DIRECTORY}/${OUTPUT_NAME_WE}.h"
1880  )
1881  if (WIN32)
1882  list (APPEND POST_BUILD_COMMAND
1883  COMMAND "${CMAKE_COMMAND}" -E copy
1884  "${BUILD_DIR}/${OUTPUT_NAME_WE}.dll"
1885  "${LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT_NAME_WE}.dll")
1886  endif ()
1887  else ()
1888  if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
1889  # TODO: This file should be regenerated if it is missing.
1890  file (WRITE "${BUILD_DIR}/${OUTPUT_NAME}" "#!/bin/bash\nexec $(dirname $BASH_SOURCE)/${OUTPUT_NAME_WE}.app/Contents/MacOS/${MCC_OUTPUT_NAME_WE}")
1891  execute_process (COMMAND chmod +x "${BUILD_DIR}/${OUTPUT_NAME}")
1892  list (APPEND POST_BUILD_COMMAND
1893  COMMAND "${CMAKE_COMMAND}" -E copy_directory
1894  "${BUILD_DIR}/${OUTPUT_NAME_WE}.app"
1895  "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME_WE}.app"
1896  COMMAND "${CMAKE_COMMAND}" -E copy
1897  "${BUILD_DIR}/${OUTPUT_NAME}"
1898  "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
1899  )
1900  else ()
1901  list (APPEND POST_BUILD_COMMAND
1902  COMMAND "${CMAKE_COMMAND}" -E copy
1903  "${BUILD_DIR}/${OUTPUT_NAME}"
1904  "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}"
1905  )
1906  endif ()
1907  endif ()
1908  # configure build script
1909  configure_file ("${BASIS_SCRIPT_EXECUTE_PROCESS}" "${BUILD_SCRIPT}" @ONLY)
1910  # add custom command to build executable using MATLAB Compiler
1911  add_custom_command (
1912  OUTPUT ${BUILD_OUTPUT}
1913  # rebuild when input sources were modified
1914  MAIN_DEPENDENCY "${MAIN_SOURCE}"
1915  DEPENDS ${DEPENDS}
1916  # invoke MATLAB Compiler in either MATLAB or standalone mode
1917  # wrapping command in CMake execute_process() command allows for inspection
1918  # of command output for error messages and specification of timeout
1919  COMMAND "${CMAKE_COMMAND}"
1920  "-DCONFIG=$<${BASIS_GE_CONFIG}>"
1921  "-DWORKING_DIRECTORY=${WORKING_DIR}"
1922  "-DTIMEOUT=${BASIS_MCC_TIMEOUT}"
1923  "-DRETRY_EXPRESSION=License checkout failed"
1924  "-DRETRY_ATTEMPTS=${BASIS_MCC_RETRY_ATTEMPTS}"
1925  "-DRETRY_DELAY=${BASIS_MCC_RETRY_DELAY}"
1926  "-DERROR_EXPRESSION=[E|e]rror:|Illegal output name"
1927  "-DOUTPUT_FILE=${BUILD_LOG}"
1928  "-DERROR_FILE=${BUILD_LOG}"
1929  "-DVERBOSE=OFF"
1930  "-DLOG_ARGS=ON"
1931  "-P" "${BUILD_SCRIPT}"
1932  # post build command(s)
1933  ${POST_BUILD_COMMAND}
1934  # inform user where build log can be found
1935  COMMAND "${CMAKE_COMMAND}" -E echo "Build log written to ${BUILD_LOG}"
1936  # comment
1937  COMMENT "${BUILD_COMMENT}"
1938  VERBATIM
1939  )
1940  endif ()
1941  # --------------------------------------------------------------------------
1942  # add custom target
1943  add_custom_target (_${TARGET_UID} DEPENDS ${BUILD_OUTPUT} SOURCES ${SOURCES})
1944  add_dependencies (${TARGET_UID} _${TARGET_UID})
1945  # cleanup on "make clean"
1946  set (ADDITIONAL_MAKE_CLEAN_FILES "${BUILD_OUTPUT}")
1947  if (COMPILE)
1948  list (APPEND ADDITIONAL_MAKE_CLEAN_FILES
1949  "${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.prj"
1950  "${BUILD_DIR}/mccExcludedFiles.log"
1951  "${BUILD_DIR}/mccBuild.log"
1952  "${BUILD_DIR}/readme.txt"
1953  )
1954  if (LIBRARY)
1955  list (APPEND ADDITIONAL_MAKE_CLEAN_FILES
1956  "${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
1957  "${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.h"
1958  "${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.c"
1959  "${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}.exports"
1960  )
1961  else ()
1962  list (APPEND ADDITIONAL_MAKE_CLEAN_FILES
1963  "${BUILD_DIR}/${OUTPUT_NAME}"
1964  "${BUILD_DIR}/${MCC_OUTPUT_NAME}"
1965  "${BUILD_DIR}/run_${MCC_OUTPUT_NAME_WE}.sh"
1966  "${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}_main.c"
1967  "${BUILD_DIR}/${MCC_OUTPUT_NAME_WE}_mcc_component_data.c"
1968  )
1969  endif ()
1970  endif ()
1971  set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${ADDITIONAL_MAKE_CLEAN_FILES}")
1972  unset (ADDITIONAL_MAKE_CLEAN_FILES)
1973  # export target
1974  if (EXPORT)
1975  basis_add_custom_export_target (${TARGET_UID} "${IS_TEST}")
1976  endif ()
1977  # install executable or library
1978  if (LIBRARY)
1979  if (LIBRARY_HEADER_DIRECTORY)
1980  file (RELATIVE_PATH INCLUDE_DIR_SUFFIX "${BINARY_INCLUDE_DIR}" "${LIBRARY_HEADER_DIRECTORY}")
1981  if (NOT INCLUDE_DIR_SUFFIX MATCHES "^../")
1982  string (REGEX REPLACE "/$" "" INCLUDE_DIR_SUFFIX "${INCLUDE_DIR_SUFFIX}")
1983  if (INCLUDE_DIR_SUFFIX STREQUAL ".")
1984  set (INCLUDE_DIR_SUFFIX)
1985  else ()
1986  set (INCLUDE_DIR_SUFFIX "/${INCLUDE_DIR_SUFFIX}")
1987  endif ()
1988  install (
1989  FILES "${BUILD_DIR}/${OUTPUT_NAME_WE}.h"
1990  DESTINATION "${INSTALL_INCLUDE_DIR}${INCLUDE_DIR_SUFFIX}"
1991  COMPONENT "${LIBRARY_COMPONENT}"
1992  )
1993  endif ()
1994  endif ()
1995  if (LIBRARY_INSTALL_DIRECTORY)
1996  if (WIN32)
1997  install (
1998  FILES "${BUILD_DIR}/${OUTPUT_NAME_WE}.dll"
1999  DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
2000  COMPONENT "${RUNTIME_COMPONENT}"
2001  )
2002  endif ()
2003  install (
2004  FILES "${INSTALL_FILE}"
2005  DESTINATION "${LIBRARY_INSTALL_DIRECTORY}"
2006  COMPONENT "${LIBRARY_COMPONENT}"
2007  )
2008  endif ()
2009  else ()
2010  if (RUNTIME_INSTALL_DIRECTORY)
2011  if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
2012  install (
2013  DIRECTORY "${BUILD_DIR}/${OUTPUT_NAME_WE}.app"
2014  DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
2015  COMPONENT "${RUNTIME_COMPONENT}"
2016  USE_SOURCE_PERMISSIONS
2017  )
2018  endif ()
2019  install (
2020  PROGRAMS "${INSTALL_FILE}"
2021  DESTINATION "${RUNTIME_INSTALL_DIRECTORY}"
2022  COMPONENT "${RUNTIME_COMPONENT}"
2023  )
2024  endif ()
2025  endif ()
2026  # done
2027  if (BASIS_VERBOSE)
2028  message (STATUS "Adding build command for target ${TARGET_UID}... - done")
2029  endif ()
2030 endfunction ()
function basis_build_mex_file(in TARGET_UID)
Add custom command for build of MEX-file.
function basis_get_matlab_release(out ARGV1)
Get release version of MATLAB installation.
cmake LINK_LIB
cmake BUILD_CMD
const unsigned int VERSION_MAJOR
The major version number.
Definition: basis.cxx:41
function basis_get_target_uid(out TARGET_UID, in TARGET_NAME)
Get "global" target name, i.e., actual CMake target name.
cmake CC
cmake BASIS_UTILITIES
Enable the automatic detection of the use of the BASIS utilities.
function set_target_properties(in ARGN)
Set target property.
function basis_get_relative_path(out REL, in BASE, in PATH)
Get path relative to a given base directory.
function basis_target_link_libraries(in TARGET_NAME, in ARGN)
Add link dependencies to build target.
cmake CMD
function is(in result, in expected, in name)
Test whether a given result is equal to the expected result.
function basis_get_project_property(out VARIABLE, in ARGN)
Get project-global property value.
cmake PROJECT_INCLUDE_DIRS
Absolute paths to directories of public header files in source tree.
function basis_finalize_targets(in ARGN)
Finalize custom targets by adding the missing build commands.
cmake SOURCES
Definition: glob.cmake:52
macro basis_add_mex_options()
Add global MATLAB MEX-script options to CMake cache.
function basis_check_target_name(in TARGET_NAME)
Checks whether a given name is a valid target name.
macro basis_sanitize_for_regex(out OUT, in STR)
Sanitize string variable for use in regular expression.
cmake MATLAB_LIBRARY_DIR
Directory of MATLAB modules relative to script location.
cmake __BASIS_MATLABTOOLS_INCLUDED
function basis_get_matlab_version(out ARGV1)
Get version of MATLAB installation.
cmake LD
function basis_add_mcc_target(in TARGET_NAME, in ARGN)
Add MATLAB Compiler target.
Definition: basis.h:34
function basis_set_project_property()
Set project-global property.
cmake STDERR
cmake CXXFLAGS
cmake NAME
cmake BASIS_EXPORT_DEFAULT
Whether to export targets by default.
macro basis_write_addpaths_mfile(in MFILE, in ARGN)
This function writes a MATLAB M-file with addpath() statements.
macro basis_update_value(in VAR)
Update cache variable.
cmake BUILD_SCRIPT
string VERSION
Project version.
Definition: utilities.sh:81
macro basis_set_flag(in PREFIX, out FLAG, in DEFAULT)
Set flag given mutually exclusive ARGN_<FLAG> and ARGN_NO<FLAG> function arguments.
cmake LDFLAGS
cmake LINK_DIR
function basis_list_to_string(out STR, in ARGN)
Concatenates all list elements into a single string.
cmake RETVAL
macro basis_add_mcc_options()
Add global MATLAB Compiler (mcc) options to CMake cache.
function basis_add_mex_file(in TARGET_NAME, in ARGN)
Add MEX-file target.
string RELEASE
Project release.
Definition: utilities.sh:89
cmake BUILD_LOG
function basis_make_target_uid(out TARGET_UID, in TARGET_NAME)
Make target UID from given target name.
function basis_configure_sources(out LIST_NAME, in ARGN)
Configure .in source files.
cmake BUILD_OUTPUT
#define UNIX
Whether the sources are compiled on a Unix-based system.
Definition: config.h:60
cmake COMMAND
function basis_add_custom_export_target(in TARGET_UID, in IS_TEST)
Add target to custom export set.
function basis_mexext(out ARGN)
Determine extension of MEX-files for this architecture.
cmake DIR
function basis_string_to_list(out LST, in STR)
Splits a string at space characters into a list.
function basis_get_target_property(out VAR, in TARGET_NAME, in ARGN)
Get value of property set on target.
function basis_list_to_delimited_string(out STR, in DELIM, in ARGN)
Concatenates all list elements into a single delimited string.
cmake CXX
const unsigned int VERSION_MINOR
The minor version number.
Definition: basis.cxx:42
const unsigned int VERSION_PATCH
The patch number.
Definition: basis.cxx:43
function basis_get_full_matlab_version(out VERSION)
Determine version of MATLAB installation.
function basis_create_addpaths_mfile()
This function writes a MATLAB M-file with addpath() statements.
function basis_build_mcc_target(in TARGET_UID)
Add custom command for build of MATLAB Compiler target.
cmake MEX_EXT
cmake BUILD_OUTPUTS
option BASIS_COMPILE_MATLAB
Enable/Disable compilation of MATLAB sources if the MATLAB Compiler is available. ...
option BASIS_VERBOSE
Default Sphinx theme options.
cmake LANGUAGE
Detected scripting language or UNKNOWN.
function basis_generate_matlab_executable(in OUTPUT_FILE, in ARGN)
Generate MATLAB wrapper executable.
function basis_get_target_name(out TARGET_NAME, in TARGET_UID)
Get "local" target name, i.e., BASIS target name without check of UID.
cmake CFLAGS
if(oldcoutbuf)
cmake cmake ARGS
function get_filename_component(inout ARGN)
Fixes CMake&#39;s get_filename_component() command.
cmake BUILD_MFILE
function basis_get_target_location(out VAR, in TARGET_NAME, in PART)
Get location of build target output file(s).
string CONTACT
Default contact to use for help output of executables.
Definition: utilities.sh:95