470ebe0ea6693b6e31e04db45c2f55fa17a87174
[platform/upstream/cmake.git] / Modules / FindMatlab.cmake
1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
3
4 #[=======================================================================[.rst:
5 FindMatlab
6 ----------
7
8 Finds Matlab or Matlab Compiler Runtime (MCR) and provides Matlab tools,
9 libraries and compilers to CMake.
10
11 This package primary purpose is to find the libraries associated with Matlab
12 or the MCR in order to be able to build Matlab extensions (mex files). It
13 can also be used:
14
15 * to run specific commands in Matlab in case Matlab is available
16 * for declaring Matlab unit test
17 * to retrieve various information from Matlab (mex extensions, versions and
18   release queries, ...)
19
20 .. versionadded:: 3.12
21   Added Matlab Compiler Runtime (MCR) support.
22
23 The module supports the following components:
24
25 * ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the ``ENG`` and ``MAT``
26   libraries of Matlab
27 * ``MAIN_PROGRAM`` the Matlab binary program. Note that this component is not
28   available on the MCR version, and will yield an error if the MCR is found
29   instead of the regular Matlab installation.
30 * ``MEX_COMPILER`` the MEX compiler.
31 * ``MCC_COMPILER`` the MCC compiler, included with the Matlab Compiler add-on.
32 * ``SIMULINK`` the Simulink environment.
33
34 .. versionadded:: 3.7
35   Added the ``MAT_LIBRARY`` component.
36
37 .. versionadded:: 3.13
38   Added the ``ENGINE_LIBRARY``, ``DATAARRAY_LIBRARY`` and ``MCC_COMPILER``
39   components.
40
41 .. versionchanged:: 3.14
42   Removed the ``MX_LIBRARY``, ``ENGINE_LIBRARY`` and ``DATAARRAY_LIBRARY``
43   components.  These libraries are found unconditionally.
44
45 .. note::
46
47   The version given to the :command:`find_package` directive is the Matlab
48   **version**, which should not be confused with the Matlab *release* name
49   (eg. `R2014`).
50   The :command:`matlab_get_version_from_release_name` and
51   :command:`matlab_get_release_name_from_version` provide a mapping
52   between the release name and the version.
53
54 The variable :variable:`Matlab_ROOT_DIR` may be specified in order to give
55 the path of the desired Matlab version. Otherwise, the behavior is platform
56 specific:
57
58 * Windows: The installed versions of Matlab/MCR are retrieved from the
59   Windows registry
60 * OS X: The installed versions of Matlab/MCR are given by the MATLAB
61   default installation paths in ``/Application``. If no such application is
62   found, it falls back to the one that might be accessible from the ``PATH``.
63 * Unix: The desired Matlab should be accessible from the ``PATH``. This does
64   not work for MCR installation and :variable:`Matlab_ROOT_DIR` should be
65   specified on this platform.
66
67 Additional information is provided when :variable:`MATLAB_FIND_DEBUG` is set.
68 When a Matlab/MCR installation is found automatically and the ``MATLAB_VERSION``
69 is not given, the version is queried from Matlab directly (on Windows this
70 may pop up a Matlab window) or from the MCR installation.
71
72 The mapping of the release names and the version of Matlab is performed by
73 defining pairs (name, version).  The variable
74 :variable:`MATLAB_ADDITIONAL_VERSIONS` may be provided before the call to
75 the :command:`find_package` in order to handle additional versions.
76
77 A Matlab scripts can be added to the set of tests using the
78 :command:`matlab_add_unit_test`. By default, the Matlab unit test framework
79 will be used (>= 2013a) to run this script, but regular ``.m`` files
80 returning an exit code can be used as well (0 indicating a success).
81
82 Module Input Variables
83 ^^^^^^^^^^^^^^^^^^^^^^
84
85 Users or projects may set the following variables to configure the module
86 behavior:
87
88 :variable:`Matlab_ROOT_DIR`
89   the root of the Matlab installation.
90 :variable:`MATLAB_FIND_DEBUG`
91   outputs debug information
92 :variable:`MATLAB_ADDITIONAL_VERSIONS`
93   additional versions of Matlab for the automatic retrieval of the installed
94   versions.
95
96 Imported targets
97 ^^^^^^^^^^^^^^^^
98
99 .. versionadded:: 3.22
100
101 This module defines the following :prop_tgt:`IMPORTED` targets:
102
103 ``Matlab::mex``
104   The ``mex`` library, always available.
105
106 ``Matlab::mx``
107   The mx library of Matlab (arrays), always available.
108
109 ``Matlab::eng``
110   Matlab engine library. Available only if the ``ENG_LIBRARY`` component
111   is requested.
112
113 ``Matlab::mat``
114   Matlab matrix library. Available only if the ``MAT_LIBRARY`` component
115   is requested.
116
117 ``Matlab::MatlabEngine``
118   Matlab C++ engine library, always available for R2018a and newer.
119
120 ``Matlab::MatlabDataArray``
121   Matlab C++ data array library, always available for R2018a and newer.
122
123 Variables defined by the module
124 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
125
126 Result variables
127 """"""""""""""""
128
129 ``Matlab_FOUND``
130   ``TRUE`` if the Matlab installation is found, ``FALSE``
131   otherwise. All variable below are defined if Matlab is found.
132 ``Matlab_ROOT_DIR``
133   the final root of the Matlab installation determined by the FindMatlab
134   module.
135 ``Matlab_MAIN_PROGRAM``
136   the Matlab binary program. Available only if the component ``MAIN_PROGRAM``
137   is given in the :command:`find_package` directive.
138 ``Matlab_INCLUDE_DIRS``
139  the path of the Matlab libraries headers
140 ``Matlab_MEX_LIBRARY``
141   library for mex, always available.
142 ``Matlab_MX_LIBRARY``
143   mx library of Matlab (arrays), always available.
144 ``Matlab_ENG_LIBRARY``
145   Matlab engine library. Available only if the component ``ENG_LIBRARY``
146   is requested.
147 ``Matlab_MAT_LIBRARY``
148   Matlab matrix library. Available only if the component ``MAT_LIBRARY``
149   is requested.
150 ``Matlab_ENGINE_LIBRARY``
151   .. versionadded:: 3.13
152
153   Matlab C++ engine library, always available for R2018a and newer.
154 ``Matlab_DATAARRAY_LIBRARY``
155   .. versionadded:: 3.13
156
157   Matlab C++ data array library, always available for R2018a and newer.
158 ``Matlab_LIBRARIES``
159   the whole set of libraries of Matlab
160 ``Matlab_MEX_COMPILER``
161   the mex compiler of Matlab. Currently not used.
162   Available only if the component ``MEX_COMPILER`` is requested.
163 ``Matlab_MCC_COMPILER``
164   .. versionadded:: 3.13
165
166   the mcc compiler of Matlab. Included with the Matlab Compiler add-on.
167   Available only if the component ``MCC_COMPILER`` is requested.
168
169 Cached variables
170 """"""""""""""""
171
172 ``Matlab_MEX_EXTENSION``
173   the extension of the mex files for the current platform (given by Matlab).
174 ``Matlab_ROOT_DIR``
175   the location of the root of the Matlab installation found. If this value
176   is changed by the user, the result variables are recomputed.
177
178 Provided macros
179 ^^^^^^^^^^^^^^^
180
181 :command:`matlab_get_version_from_release_name`
182   returns the version from the release name
183 :command:`matlab_get_release_name_from_version`
184   returns the release name from the Matlab version
185
186 Provided functions
187 ^^^^^^^^^^^^^^^^^^
188
189 :command:`matlab_add_mex`
190   adds a target compiling a MEX file.
191 :command:`matlab_add_unit_test`
192   adds a Matlab unit test file as a test to the project.
193 :command:`matlab_extract_all_installed_versions_from_registry`
194   parses the registry for all Matlab versions. Available on Windows only.
195   The part of the registry parsed is dependent on the host processor
196 :command:`matlab_get_all_valid_matlab_roots_from_registry`
197   returns all the possible Matlab or MCR paths, according to a previously
198   given list. Only the existing/accessible paths are kept. This is mainly
199   useful for the searching all possible Matlab installation.
200 :command:`matlab_get_mex_suffix`
201   returns the suffix to be used for the mex files
202   (platform/architecture dependent)
203 :command:`matlab_get_version_from_matlab_run`
204   returns the version of Matlab/MCR, given the full directory of the Matlab/MCR
205   installation path.
206
207
208 Known issues
209 ^^^^^^^^^^^^
210
211 **Symbol clash in a MEX target**
212   By default, every symbols inside a MEX
213   file defined with the command :command:`matlab_add_mex` have hidden
214   visibility, except for the entry point. This is the default behavior of
215   the MEX compiler, which lowers the risk of symbol collision between the
216   libraries shipped with Matlab, and the libraries to which the MEX file is
217   linking to. This is also the default on Windows platforms.
218
219   However, this is not sufficient in certain case, where for instance your
220   MEX file is linking against libraries that are already loaded by Matlab,
221   even if those libraries have different SONAMES.
222   A possible solution is to hide the symbols of the libraries to which the
223   MEX target is linking to. This can be achieved in GNU GCC compilers with
224   the linker option ``-Wl,--exclude-libs,ALL``.
225
226 **Tests using GPU resources**
227   in case your MEX file is using the GPU and
228   in order to be able to run unit tests on this MEX file, the GPU resources
229   should be properly released by Matlab. A possible solution is to make
230   Matlab aware of the use of the GPU resources in the session, which can be
231   performed by a command such as ``D = gpuDevice()`` at the beginning of
232   the test script (or via a fixture).
233
234
235 Reference
236 ^^^^^^^^^
237
238 .. variable:: Matlab_ROOT_DIR
239
240    The root folder of the Matlab installation. If set before the call to
241    :command:`find_package`, the module will look for the components in that
242    path. If not set, then an automatic search of Matlab
243    will be performed. If set, it should point to a valid version of Matlab.
244
245 .. variable:: MATLAB_FIND_DEBUG
246
247    If set, the lookup of Matlab and the intermediate configuration steps are
248    outputted to the console.
249
250 .. variable:: MATLAB_ADDITIONAL_VERSIONS
251
252   If set, specifies additional versions of Matlab that may be looked for.
253   The variable should be a list of strings, organized by pairs of release
254   name and versions, such as follows::
255
256     set(MATLAB_ADDITIONAL_VERSIONS
257         "release_name1=corresponding_version1"
258         "release_name2=corresponding_version2"
259         ...
260         )
261
262   Example::
263
264     set(MATLAB_ADDITIONAL_VERSIONS
265         "R2013b=8.2"
266         "R2013a=8.1"
267         "R2012b=8.0")
268
269   The order of entries in this list matters when several versions of
270   Matlab are installed. The priority is set according to the ordering in
271   this list.
272 #]=======================================================================]
273
274 cmake_policy(PUSH)
275 cmake_policy(SET CMP0057 NEW) # if IN_LIST
276
277 set(_FindMatlab_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}")
278
279 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
280 include(CheckCXXCompilerFlag)
281 include(CheckCCompilerFlag)
282
283
284 # The currently supported versions. Other version can be added by the user by
285 # providing MATLAB_ADDITIONAL_VERSIONS
286 if(NOT MATLAB_ADDITIONAL_VERSIONS)
287   set(MATLAB_ADDITIONAL_VERSIONS)
288 endif()
289
290 set(MATLAB_VERSIONS_MAPPING
291   "R2022b=9.13"
292   "R2022a=9.12"
293   "R2021b=9.11"
294   "R2021a=9.10"
295   "R2020b=9.9"
296   "R2020a=9.8"
297   "R2019b=9.7"
298   "R2019a=9.6"
299   "R2018b=9.5"
300   "R2018a=9.4"
301   "R2017b=9.3"
302   "R2017a=9.2"
303   "R2016b=9.1"
304   "R2016a=9.0"
305   "R2015b=8.6"
306   "R2015a=8.5"
307   "R2014b=8.4"
308   "R2014a=8.3"
309   "R2013b=8.2"
310   "R2013a=8.1"
311   "R2012b=8.0"
312   "R2012a=7.14"
313   "R2011b=7.13"
314   "R2011a=7.12"
315   "R2010b=7.11"
316
317   ${MATLAB_ADDITIONAL_VERSIONS}
318   )
319
320
321 # temporary folder for all Matlab runs
322 set(_matlab_temporary_folder ${CMAKE_BINARY_DIR}/Matlab)
323
324 if(NOT EXISTS "${_matlab_temporary_folder}")
325   file(MAKE_DIRECTORY "${_matlab_temporary_folder}")
326 endif()
327
328 #[=======================================================================[.rst:
329 .. command:: matlab_get_version_from_release_name
330
331   Returns the version of Matlab (17.58) from a release name (R2017k)
332 #]=======================================================================]
333 macro(matlab_get_version_from_release_name release_name version_name)
334
335   string(REGEX MATCHALL "${release_name}=([0-9]+\\.?[0-9]*)" _matched ${MATLAB_VERSIONS_MAPPING})
336
337   set(${version_name} "")
338   if(NOT _matched STREQUAL "")
339     set(${version_name} ${CMAKE_MATCH_1})
340   else()
341     message(WARNING "[MATLAB] The release name ${release_name} is not registered")
342   endif()
343   unset(_matched)
344
345 endmacro()
346
347
348
349
350
351 #[=======================================================================[.rst:
352 .. command:: matlab_get_release_name_from_version
353
354   Returns the release name (R2017k) from the version of Matlab (17.58)
355 #]=======================================================================]
356 macro(matlab_get_release_name_from_version version release_name)
357
358   set(${release_name} "")
359   foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
360     string(REGEX MATCHALL "(.+)=${version}" _matched ${_var})
361     if(NOT _matched STREQUAL "")
362       set(${release_name} ${CMAKE_MATCH_1})
363       break()
364     endif()
365   endforeach(_var)
366
367   unset(_var)
368   unset(_matched)
369   if(${release_name} STREQUAL "")
370     message(WARNING "[MATLAB] The version ${version} is not registered")
371   endif()
372
373 endmacro()
374
375
376
377
378
379 # extracts all the supported release names (R2017k...) of Matlab
380 # internal use
381 macro(matlab_get_supported_releases list_releases)
382   set(${list_releases})
383   foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
384     string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var})
385     if(NOT _matched STREQUAL "")
386       list(APPEND ${list_releases} ${CMAKE_MATCH_1})
387     endif()
388     unset(_matched)
389     unset(CMAKE_MATCH_1)
390   endforeach(_var)
391   unset(_var)
392 endmacro()
393
394
395
396 # extracts all the supported versions of Matlab
397 # internal use
398 macro(matlab_get_supported_versions list_versions)
399   set(${list_versions})
400   foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
401     string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var})
402     if(NOT _matched STREQUAL "")
403       list(APPEND ${list_versions} ${CMAKE_MATCH_2})
404     endif()
405     unset(_matched)
406     unset(CMAKE_MATCH_1)
407   endforeach(_var)
408   unset(_var)
409 endmacro()
410
411
412 #[=======================================================================[.rst:
413 .. command:: matlab_extract_all_installed_versions_from_registry
414
415   This function parses the registry and founds the Matlab versions that are
416   installed. The found versions are returned in `matlab_versions`.
417   Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for
418   The returned list contains all versions under
419   ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` and
420   ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Runtime`` or an empty list in case an
421   error occurred (or nothing found).
422
423   .. note::
424
425     Only the versions are provided. No check is made over the existence of the
426     installation referenced in the registry,
427
428 #]=======================================================================]
429 function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions)
430
431   if(NOT CMAKE_HOST_WIN32)
432     message(FATAL_ERROR "[MATLAB] This macro can only be called by a windows host (call to reg.exe)")
433   endif()
434
435   if(${win64} AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "64")
436     set(APPEND_REG "/reg:64")
437   else()
438     set(APPEND_REG "/reg:32")
439   endif()
440
441   set(matlabs_from_registry)
442
443   foreach(_installation_type IN ITEMS "MATLAB" "MATLAB Runtime" "MATLAB Compiler Runtime")
444
445     # /reg:64 should be added on 64 bits capable OSs in order to enable the
446     # redirection of 64 bits applications
447     execute_process(
448       COMMAND reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\${_installation_type}" /f * /k ${APPEND_REG}
449       RESULT_VARIABLE resultMatlab
450       OUTPUT_VARIABLE varMatlab
451       ERROR_VARIABLE errMatlab
452       INPUT_FILE NUL
453       )
454
455
456     if(resultMatlab EQUAL 0)
457
458       string(
459         REGEX MATCHALL "${_installation_type}\\\\([0-9]+(\\.[0-9]+)?)"
460         matlab_versions_regex ${varMatlab})
461
462       foreach(match IN LISTS matlab_versions_regex)
463         string(
464           REGEX MATCH "${_installation_type}\\\\(([0-9]+)(\\.([0-9]+))?)"
465           current_match ${match})
466
467         set(_matlab_current_version ${CMAKE_MATCH_1})
468         set(current_matlab_version_major ${CMAKE_MATCH_2})
469         set(current_matlab_version_minor ${CMAKE_MATCH_4})
470         if(NOT current_matlab_version_minor)
471           set(current_matlab_version_minor "0")
472         endif()
473
474         list(APPEND matlabs_from_registry ${_matlab_current_version})
475         unset(_matlab_current_version)
476       endforeach()
477
478     endif()
479   endforeach()
480
481   if(matlabs_from_registry)
482     list(REMOVE_DUPLICATES matlabs_from_registry)
483     list(SORT matlabs_from_registry COMPARE NATURAL)
484     list(REVERSE matlabs_from_registry)
485   endif()
486
487   set(${matlab_versions} ${matlabs_from_registry} PARENT_SCOPE)
488
489 endfunction()
490
491
492
493 # (internal)
494 macro(extract_matlab_versions_from_registry_brute_force matlab_versions)
495   # get the supported versions
496   set(matlab_supported_versions)
497   matlab_get_supported_versions(matlab_supported_versions)
498
499
500   # this is a manual population of the versions we want to look for
501   # this can be done as is, but preferably with the call to
502   # matlab_get_supported_versions and variable
503
504   # populating the versions we want to look for
505   # set(matlab_supported_versions)
506
507   # # Matlab 7
508   # set(matlab_major 7)
509   # foreach(current_matlab_minor RANGE 4 20)
510     # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}")
511   # endforeach(current_matlab_minor)
512
513   # # Matlab 8
514   # set(matlab_major 8)
515   # foreach(current_matlab_minor RANGE 0 5)
516     # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}")
517   # endforeach(current_matlab_minor)
518
519   # # taking into account the possible additional versions provided by the user
520   # if(DEFINED MATLAB_ADDITIONAL_VERSIONS)
521     # list(APPEND matlab_supported_versions MATLAB_ADDITIONAL_VERSIONS)
522   # endif()
523
524   # we order from more recent to older
525   if(matlab_supported_versions)
526     list(REMOVE_DUPLICATES matlab_supported_versions)
527     list(SORT matlab_supported_versions COMPARE NATURAL)
528     list(REVERSE matlab_supported_versions)
529   endif()
530
531   set(${matlab_versions} ${matlab_supported_versions})
532 endmacro()
533
534
535
536
537 #[=======================================================================[.rst:
538 .. command:: matlab_get_all_valid_matlab_roots_from_registry
539
540   Populates the Matlab root with valid versions of Matlab or
541   Matlab Runtime (MCR).
542   The returned matlab_roots is organized in triplets
543   ``(type,version_number,matlab_root_path)``, where ``type``
544   indicates either ``MATLAB`` or ``MCR``.
545
546   ::
547
548     matlab_get_all_valid_matlab_roots_from_registry(
549         matlab_versions
550         matlab_roots)
551
552   ``matlab_versions``
553     the versions of each of the Matlab or MCR installations
554   ``matlab_roots``
555     the location of each of the Matlab or MCR installations
556 #]=======================================================================]
557 function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots)
558
559   # The matlab_versions comes either from
560   # extract_matlab_versions_from_registry_brute_force or
561   # matlab_extract_all_installed_versions_from_registry.
562
563   set(_matlab_roots_list )
564   # check for Matlab installations
565   foreach(_matlab_current_version ${matlab_versions})
566     get_filename_component(
567       current_MATLAB_ROOT
568       "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]"
569       ABSOLUTE)
570
571     if(EXISTS "${current_MATLAB_ROOT}")
572       list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT})
573     endif()
574
575   endforeach()
576
577   # Check for MCR installations
578   foreach(_matlab_current_version ${matlab_versions})
579     get_filename_component(
580       current_MATLAB_ROOT
581       "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Runtime\\${_matlab_current_version};MATLABROOT]"
582       ABSOLUTE)
583
584     # remove the dot
585     string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
586
587     if(EXISTS "${current_MATLAB_ROOT}")
588       list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
589     endif()
590
591   endforeach()
592
593   # Check for old MCR installations
594   foreach(_matlab_current_version ${matlab_versions})
595     get_filename_component(
596       current_MATLAB_ROOT
597       "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Compiler Runtime\\${_matlab_current_version};MATLABROOT]"
598       ABSOLUTE)
599
600     # remove the dot
601     string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
602
603     if(EXISTS "${current_MATLAB_ROOT}")
604       list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
605     endif()
606
607   endforeach()
608   set(${matlab_roots} ${_matlab_roots_list} PARENT_SCOPE)
609 endfunction()
610
611 #[=======================================================================[.rst:
612 .. command:: matlab_get_mex_suffix
613
614   Returns the extension of the mex files (the suffixes).
615   This function should not be called before the appropriate Matlab root has
616   been found.
617
618   ::
619
620     matlab_get_mex_suffix(
621         matlab_root
622         mex_suffix)
623
624   ``matlab_root``
625     the root of the Matlab/MCR installation
626   ``mex_suffix``
627     the variable name in which the suffix will be returned.
628 #]=======================================================================]
629 function(matlab_get_mex_suffix matlab_root mex_suffix)
630
631   # todo setup the extension properly. Currently I do not know if this is
632   # sufficient for all win32 distributions.
633   # there is also CMAKE_EXECUTABLE_SUFFIX that could be tweaked
634   set(mexext_suffix "")
635   if(WIN32)
636     list(APPEND mexext_suffix ".bat")
637   endif()
638
639   # we first try without suffix, since cmake does not understand a list with
640   # one empty string element
641   find_program(
642     Matlab_MEXEXTENSIONS_PROG
643     NAMES mexext
644     PATHS ${matlab_root}/bin
645     DOC "Matlab MEX extension provider"
646     NO_DEFAULT_PATH
647   )
648
649   foreach(current_mexext_suffix IN LISTS mexext_suffix)
650     if(NOT DEFINED Matlab_MEXEXTENSIONS_PROG OR NOT Matlab_MEXEXTENSIONS_PROG)
651       # this call should populate the cache automatically
652       find_program(
653         Matlab_MEXEXTENSIONS_PROG
654         "mexext${current_mexext_suffix}"
655         PATHS ${matlab_root}/bin
656         DOC "Matlab MEX extension provider"
657         NO_DEFAULT_PATH
658       )
659     endif()
660   endforeach(current_mexext_suffix)
661   if(MATLAB_FIND_DEBUG)
662     message(STATUS "[MATLAB] Determining mex files extensions from '${matlab_root}/bin' with program '${Matlab_MEXEXTENSIONS_PROG}'")
663   endif()
664
665   # the program has been found?
666   if((NOT Matlab_MEXEXTENSIONS_PROG) OR (NOT EXISTS ${Matlab_MEXEXTENSIONS_PROG}))
667     if(MATLAB_FIND_DEBUG)
668       message(WARNING "[MATLAB] Cannot found mexext program. Matlab root is ${matlab_root}")
669     endif()
670     unset(Matlab_MEXEXTENSIONS_PROG CACHE)
671     return()
672   endif()
673
674   set(_matlab_mex_extension)
675
676   set(devnull)
677   if(UNIX)
678     set(devnull INPUT_FILE /dev/null)
679   elseif(WIN32)
680     set(devnull INPUT_FILE NUL)
681   endif()
682
683   if(WIN32)
684     # this environment variable is used to determine the arch on Windows
685     if(CMAKE_SIZEOF_VOID_P EQUAL 8)
686       set(ENV{MATLAB_ARCH} "win64")
687     else()
688       set(ENV{MATLAB_ARCH} "win32")
689     endif()
690   endif()
691
692   # this is the preferred way. If this does not work properly (eg. MCR on Windows), then we use our own knowledge
693   execute_process(
694     COMMAND ${Matlab_MEXEXTENSIONS_PROG}
695     OUTPUT_VARIABLE _matlab_mex_extension
696     ERROR_VARIABLE _matlab_mex_extension_error
697     OUTPUT_STRIP_TRAILING_WHITESPACE
698     ${devnull})
699   unset(ENV{MATLAB_ARCH})
700
701   if(_matlab_mex_extension_error)
702     if(WIN32)
703       # this is only for intel architecture
704       if(CMAKE_SIZEOF_VOID_P EQUAL 8)
705         set(_matlab_mex_extension "mexw64")
706       else()
707         set(_matlab_mex_extension "mexw32")
708       endif()
709     endif()
710   endif()
711
712   string(STRIP "${_matlab_mex_extension}"  _matlab_mex_extension)
713   if(MATLAB_FIND_DEBUG)
714     message(STATUS "[MATLAB] '${Matlab_MEXEXTENSIONS_PROG}' : determined extension '${_matlab_mex_extension}' and error string is '${_matlab_mex_extension_error}'")
715   endif()
716
717   unset(Matlab_MEXEXTENSIONS_PROG CACHE)
718   set(${mex_suffix} ${_matlab_mex_extension} PARENT_SCOPE)
719 endfunction()
720
721
722
723
724 #[=======================================================================[.rst:
725 .. command:: matlab_get_version_from_matlab_run
726
727   This function runs Matlab program specified on arguments and extracts its
728   version. If the path provided for the Matlab installation points to an MCR
729   installation, the version is extracted from the installed files.
730
731   ::
732
733     matlab_get_version_from_matlab_run(
734         matlab_binary_path
735         matlab_list_versions)
736
737   ``matlab_binary_path``
738     the location of the `matlab` binary executable
739   ``matlab_list_versions``
740     the version extracted from Matlab
741 #]=======================================================================]
742 function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions)
743
744   set(${matlab_list_versions} "" PARENT_SCOPE)
745
746   if(MATLAB_FIND_DEBUG)
747     message(STATUS "[MATLAB] Determining the version of Matlab from ${matlab_binary_program}")
748   endif()
749
750   if(EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
751     if(MATLAB_FIND_DEBUG)
752       message(STATUS "[MATLAB] Removing previous ${_matlab_temporary_folder}/matlabVersionLog.cmaketmp file")
753     endif()
754     file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
755   endif()
756
757
758   # the log file is needed since on windows the command executes in a new
759   # window and it is not possible to get back the answer of Matlab
760   # the -wait command is needed on windows, otherwise the call returns
761   # immediately after the program launches itself.
762   if(WIN32)
763     set(_matlab_additional_commands "-wait")
764   endif()
765
766   set(devnull)
767   if(UNIX)
768     set(devnull INPUT_FILE /dev/null)
769   elseif(WIN32)
770     set(devnull INPUT_FILE NUL)
771   endif()
772
773   # we first try to run a simple program using the -r option, and then we use the
774   # -batch option that is supported and recommended since R2019a
775   set(_matlab_get_version_failed_with_r_option FALSE)
776
777   # timeout set to 120 seconds, in case it does not start
778   # note as said before OUTPUT_VARIABLE cannot be used in a platform
779   # independent manner however, not setting it would flush the output of Matlab
780   # in the current console (unix variant)
781   execute_process(
782     COMMAND "${matlab_binary_program}" -nosplash -nojvm ${_matlab_additional_commands} -logfile "matlabVersionLog.cmaketmp" -nodesktop -nodisplay -r "version, exit"
783     OUTPUT_VARIABLE _matlab_version_from_cmd_dummy
784     RESULT_VARIABLE _matlab_result_version_call
785     ERROR_VARIABLE _matlab_result_version_call_error
786     TIMEOUT 120
787     WORKING_DIRECTORY "${_matlab_temporary_folder}"
788     ${devnull}
789     )
790
791   if(_matlab_result_version_call MATCHES "timeout")
792     if(MATLAB_FIND_DEBUG)
793       message(WARNING "[MATLAB] Unable to determine the version of Matlab."
794         " Matlab call with -r option timed out after 120 seconds.")
795     endif()
796     set(_matlab_get_version_failed_with_r_option TRUE)
797   endif()
798
799   if(NOT ${_matlab_get_version_failed_with_r_option} AND ${_matlab_result_version_call})
800     if(MATLAB_FIND_DEBUG)
801       message(WARNING "[MATLAB] Unable to determine the version of Matlab. Matlab call with -r option returned with error ${_matlab_result_version_call}.")
802     endif()
803     set(_matlab_get_version_failed_with_r_option TRUE)
804   elseif(NOT ${_matlab_get_version_failed_with_r_option} AND NOT EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
805     if(MATLAB_FIND_DEBUG)
806       message(WARNING "[MATLAB] Unable to determine the version of Matlab. The log file does not exist.")
807     endif()
808     set(_matlab_get_version_failed_with_r_option TRUE)
809   endif()
810
811   if(_matlab_get_version_failed_with_r_option)
812     execute_process(
813       COMMAND "${matlab_binary_program}" -nosplash -nojvm ${_matlab_additional_commands} -logfile "matlabVersionLog.cmaketmp" -nodesktop -nodisplay -batch "version, exit"
814       OUTPUT_VARIABLE _matlab_version_from_cmd_dummy_batch
815       RESULT_VARIABLE _matlab_result_version_call_batch
816       ERROR_VARIABLE _matlab_result_version_call_error_batch
817       TIMEOUT 120
818       WORKING_DIRECTORY "${_matlab_temporary_folder}"
819       ${devnull}
820       )
821
822     if(_matlab_result_version_call_batch MATCHES "timeout")
823       if(MATLAB_FIND_DEBUG)
824         message(WARNING "[MATLAB] Unable to determine the version of Matlab."
825           " Matlab call with -batch option timed out after 120 seconds.")
826       endif()
827       return()
828     endif()
829
830     if(${_matlab_result_version_call_batch})
831       if(MATLAB_FIND_DEBUG)
832         message(WARNING "[MATLAB] Command executed \"${matlab_binary_program}\" -nosplash -nojvm ${_matlab_additional_commands} -logfile \"matlabVersionLog.cmaketmp\" -nodesktop -nodisplay -batch \"version, exit\"")
833         message(WARNING "_matlab_version_from_cmd_dummy_batch (OUTPUT_VARIABLE): ${_matlab_version_from_cmd_dummy_batch}")
834         message(WARNING "_matlab_result_version_call_batch (RESULT_VARIABLE): ${_matlab_result_version_call_batch}")
835         message(WARNING "_matlab_result_version_call_error_batch (ERROR_VARIABLE): ${_matlab_result_version_call_error_batch}")
836         message(WARNING "[MATLAB] Unable to determine the version of Matlab. Matlab call with -batch option returned with error ${_matlab_result_version_call_batch}.")
837       endif()
838       return()
839     elseif(NOT ${_matlab_get_version_failed_with_r_option} AND NOT EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
840       if(MATLAB_FIND_DEBUG)
841         message(WARNING "[MATLAB] Unable to determine the version of Matlab. The log file does not exist.")
842       endif()
843       return()
844     endif()
845   endif()
846
847   # if successful, read back the log
848   file(READ "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp" _matlab_version_from_cmd)
849   file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
850
851   set(index -1)
852   string(FIND "${_matlab_version_from_cmd}" "ans" index)
853   if(index EQUAL -1)
854
855     if(MATLAB_FIND_DEBUG)
856       message(WARNING "[MATLAB] Cannot find the version of Matlab returned by the run.")
857     endif()
858
859   else()
860     set(matlab_list_of_all_versions_tmp)
861
862     string(SUBSTRING "${_matlab_version_from_cmd}" ${index} -1 substring_ans)
863     string(
864       REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)?)"
865       matlab_versions_regex
866       ${substring_ans})
867     foreach(match IN LISTS matlab_versions_regex)
868       string(
869         REGEX MATCH "ans[\r\n\t ]*=[\r\n\t ]*'?(([0-9]+)(\\.([0-9]+))?)"
870         current_match ${match})
871
872       list(APPEND matlab_list_of_all_versions_tmp ${CMAKE_MATCH_1})
873     endforeach()
874     if(matlab_list_of_all_versions_tmp)
875       list(REMOVE_DUPLICATES matlab_list_of_all_versions_tmp)
876     endif()
877     set(${matlab_list_versions} ${matlab_list_of_all_versions_tmp} PARENT_SCOPE)
878
879   endif()
880
881 endfunction()
882
883 #[=======================================================================[.rst:
884 .. command:: matlab_add_unit_test
885
886   Adds a Matlab unit test to the test set of cmake/ctest.
887   This command requires the component ``MAIN_PROGRAM`` and hence is not
888   available for an MCR installation.
889
890   The unit test uses the Matlab unittest framework (default, available
891   starting Matlab 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK``
892   is given.
893
894   The function expects one Matlab test script file to be given.
895   In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file
896   should contain the script to be run, plus an exit command with the exit
897   value. This exit value will be passed to the ctest framework (0 success,
898   non 0 failure). Additional arguments accepted by :command:`add_test` can be
899   passed through ``TEST_ARGS`` (eg. ``CONFIGURATION <config> ...``).
900
901   ::
902
903     matlab_add_unit_test(
904         NAME <name>
905         UNITTEST_FILE matlab_file_containing_unittest.m
906         [CUSTOM_TEST_COMMAND matlab_command_to_run_as_test]
907         [UNITTEST_PRECOMMAND matlab_command_to_run]
908         [TIMEOUT timeout]
909         [ADDITIONAL_PATH path1 [path2 ...]]
910         [MATLAB_ADDITIONAL_STARTUP_OPTIONS option1 [option2 ...]]
911         [TEST_ARGS arg1 [arg2 ...]]
912         [NO_UNITTEST_FRAMEWORK]
913         )
914
915   The function arguments are:
916
917   ``NAME``
918     name of the unittest in ctest.
919   ``UNITTEST_FILE``
920     the matlab unittest file. Its path will be automatically
921     added to the Matlab path.
922   ``CUSTOM_TEST_COMMAND``
923     Matlab script command to run as the test.
924     If this is not set, then the following is run:
925     ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))``
926     where ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension.
927   ``UNITTEST_PRECOMMAND``
928     Matlab script command to be ran before the file
929     containing the test (eg. GPU device initialization based on CMake
930     variables).
931   ``TIMEOUT``
932     the test timeout in seconds. Defaults to 180 seconds as the
933     Matlab unit test may hang.
934   ``ADDITIONAL_PATH``
935     a list of paths to add to the Matlab path prior to
936     running the unit test.
937   ``MATLAB_ADDITIONAL_STARTUP_OPTIONS``
938     a list of additional option in order
939     to run Matlab from the command line.
940     ``-nosplash -nodesktop -nodisplay`` are always added.
941   ``TEST_ARGS``
942     Additional options provided to the add_test command. These
943     options are added to the default options (eg. "CONFIGURATIONS Release")
944   ``NO_UNITTEST_FRAMEWORK``
945     when set, indicates that the test should not
946     use the unittest framework of Matlab (available for versions >= R2013a).
947   ``WORKING_DIRECTORY``
948     This will be the working directory for the test. If specified it will
949     also be the output directory used for the log file of the test run.
950     If not specified the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` will
951     be used as the working directory and the log location.
952
953 #]=======================================================================]
954 function(matlab_add_unit_test)
955
956   if(NOT Matlab_MAIN_PROGRAM)
957     message(FATAL_ERROR "[MATLAB] This functionality needs the MAIN_PROGRAM component (not default)")
958   endif()
959
960   set(options NO_UNITTEST_FRAMEWORK)
961   set(oneValueArgs NAME UNITTEST_FILE TIMEOUT WORKING_DIRECTORY
962     UNITTEST_PRECOMMAND CUSTOM_TEST_COMMAND)
963   set(multiValueArgs ADDITIONAL_PATH MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS)
964
965   set(prefix _matlab_unittest_prefix)
966   cmake_parse_arguments(PARSE_ARGV 0 ${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" )
967
968   if(NOT ${prefix}_NAME)
969     message(FATAL_ERROR "[MATLAB] The Matlab test name cannot be empty")
970   endif()
971
972   # The option to run a batch program with MATLAB changes depending on the MATLAB version
973   # For MATLAB before R2019a (9.6), the only supported option is -r, afterwords the suggested option
974   # is -batch as -r is deprecated
975   set(maut_BATCH_OPTION "-r")
976   if(NOT (Matlab_VERSION_STRING STREQUAL ""))
977     if(Matlab_VERSION_STRING VERSION_GREATER_EQUAL "9.6")
978       set(maut_BATCH_OPTION "-batch")
979     endif()
980   endif()
981
982   add_test(NAME ${${prefix}_NAME}
983            COMMAND ${CMAKE_COMMAND}
984             "-Dtest_name=${${prefix}_NAME}"
985             "-Dadditional_paths=${${prefix}_ADDITIONAL_PATH}"
986             "-Dtest_timeout=${${prefix}_TIMEOUT}"
987             "-Doutput_directory=${_matlab_temporary_folder}"
988             "-Dworking_directory=${${prefix}_WORKING_DIRECTORY}"
989             "-DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM}"
990             "-Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK}"
991             "-DMatlab_ADDITIONAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS}"
992             "-Dunittest_file_to_run=${${prefix}_UNITTEST_FILE}"
993             "-Dcustom_Matlab_test_command=${${prefix}_CUSTOM_TEST_COMMAND}"
994             "-Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND}"
995             "-Dmaut_BATCH_OPTION=${maut_BATCH_OPTION}"
996             -P ${_FindMatlab_SELF_DIR}/MatlabTestsRedirect.cmake
997            ${${prefix}_TEST_ARGS}
998            ${${prefix}_UNPARSED_ARGUMENTS}
999            )
1000 endfunction()
1001
1002
1003 #[=======================================================================[.rst:
1004 .. command:: matlab_add_mex
1005
1006   Adds a Matlab MEX target.
1007   This commands compiles the given sources with the current tool-chain in
1008   order to produce a MEX file. The final name of the produced output may be
1009   specified, as well as additional link libraries, and a documentation entry
1010   for the MEX file. Remaining arguments of the call are passed to the
1011   :command:`add_library` or :command:`add_executable` command.
1012
1013   ::
1014
1015      matlab_add_mex(
1016          NAME <name>
1017          [EXECUTABLE | MODULE | SHARED]
1018          SRC src1 [src2 ...]
1019          [OUTPUT_NAME output_name]
1020          [DOCUMENTATION file.txt]
1021          [LINK_TO target1 target2 ...]
1022          [R2017b | R2018a]
1023          [EXCLUDE_FROM_ALL]
1024          [NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES]
1025          [...]
1026      )
1027
1028   ``NAME``
1029     name of the target.
1030   ``SRC``
1031     list of source files.
1032   ``LINK_TO``
1033     a list of additional link dependencies.  The target links to ``libmex``
1034     and ``libmx`` by default, unless the
1035     ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` option is passed.
1036   ``OUTPUT_NAME``
1037     if given, overrides the default name. The default name is
1038     the name of the target without any prefix and
1039     with ``Matlab_MEX_EXTENSION`` suffix.
1040   ``DOCUMENTATION``
1041     if given, the file ``file.txt`` will be considered as
1042     being the documentation file for the MEX file. This file is copied into
1043     the same folder without any processing, with the same name as the final
1044     mex file, and with extension `.m`. In that case, typing ``help <name>``
1045     in Matlab prints the documentation contained in this file.
1046   ``R2017b`` or ``R2018a``
1047     .. versionadded:: 3.14
1048
1049     May be given to specify the version of the C API
1050     to use: ``R2017b`` specifies the traditional (separate complex) C API,
1051     and corresponds to the ``-R2017b`` flag for the `mex` command. ``R2018a``
1052     specifies the new interleaved complex C API, and corresponds to the
1053     ``-R2018a`` flag for the `mex` command. Ignored if MATLAB version prior
1054     to R2018a. Defaults to ``R2017b``.
1055
1056   ``MODULE`` or ``SHARED``
1057     .. versionadded:: 3.7
1058
1059     May be given to specify the type of library to be
1060     created.
1061
1062   ``EXECUTABLE``
1063     .. versionadded:: 3.7
1064
1065     May be given to create an executable instead of
1066     a library. If no type is given explicitly, the type is ``SHARED``.
1067   ``EXCLUDE_FROM_ALL``
1068     This option has the same meaning as for :prop_tgt:`EXCLUDE_FROM_ALL` and
1069     is forwarded to :command:`add_library` or :command:`add_executable`
1070     commands.
1071   ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES``
1072     .. versionadded:: 3.24
1073
1074     This option permits to disable the automatic linking of MATLAB
1075     libraries, so that only the libraries that are actually required can be
1076     linked via the ``LINK_TO`` option.
1077
1078   The documentation file is not processed and should be in the following
1079   format:
1080
1081   ::
1082
1083     % This is the documentation
1084     function ret = mex_target_output_name(input1)
1085
1086 #]=======================================================================]
1087 function(matlab_add_mex)
1088
1089   if(NOT WIN32)
1090     # we do not need all this on Windows
1091     # pthread options
1092     if(CMAKE_CXX_COMPILER_LOADED)
1093       check_cxx_compiler_flag(-pthread HAS_MINUS_PTHREAD)
1094     elseif(CMAKE_C_COMPILER_LOADED)
1095       check_c_compiler_flag(-pthread HAS_MINUS_PTHREAD)
1096     endif()
1097     # we should use try_compile instead, the link flags are discarded from
1098     # this compiler_flag function.
1099     #check_cxx_compiler_flag(-Wl,--exclude-libs,ALL HAS_SYMBOL_HIDING_CAPABILITY)
1100
1101   endif()
1102
1103   set(options EXECUTABLE MODULE SHARED R2017b R2018a EXCLUDE_FROM_ALL NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES)
1104   set(oneValueArgs NAME DOCUMENTATION OUTPUT_NAME)
1105   set(multiValueArgs LINK_TO SRC)
1106
1107   set(prefix _matlab_addmex_prefix)
1108   cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
1109
1110   if(NOT ${prefix}_NAME)
1111     message(FATAL_ERROR "[MATLAB] The MEX target name cannot be empty")
1112   endif()
1113
1114   if(NOT ${prefix}_OUTPUT_NAME)
1115     set(${prefix}_OUTPUT_NAME ${${prefix}_NAME})
1116   endif()
1117
1118   if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, add version source file
1119     # Add the correct version file depending on which languages are enabled in the project
1120     if(CMAKE_C_COMPILER_LOADED)
1121       # If C is enabled, use the .c file as it will work fine also with C++
1122       set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/c_mexapi_version.c")
1123     elseif(CMAKE_CXX_COMPILER_LOADED)
1124       # If C is not enabled, check if CXX is enabled and use the .cpp file
1125       # to avoid that the .c file is silently ignored
1126       set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/cpp_mexapi_version.cpp")
1127     else()
1128       # If neither C or CXX is enabled, warn because we cannot add the source.
1129       # TODO: add support for fortran mex files
1130       message(WARNING "[MATLAB] matlab_add_mex requires that at least C or CXX are enabled languages")
1131     endif()
1132   endif()
1133
1134   # For 9.4 (R2018a) and newer, add API macro.
1135   # Add it for unknown versions too, just in case.
1136   if(NOT Matlab_VERSION_STRING VERSION_LESS "9.4"
1137       OR Matlab_VERSION_STRING STREQUAL "unknown")
1138     if(${${prefix}_R2018a})
1139       set(MEX_API_MACRO "MATLAB_DEFAULT_RELEASE=R2018a")
1140     else()
1141       set(MEX_API_MACRO "MATLAB_DEFAULT_RELEASE=R2017b")
1142     endif()
1143   endif()
1144
1145   set(_option_EXCLUDE_FROM_ALL)
1146   if(${prefix}_EXCLUDE_FROM_ALL)
1147     set(_option_EXCLUDE_FROM_ALL "EXCLUDE_FROM_ALL")
1148   endif()
1149
1150   if(${prefix}_EXECUTABLE)
1151     add_executable(${${prefix}_NAME}
1152       ${_option_EXCLUDE_FROM_ALL}
1153       ${${prefix}_SRC}
1154       ${MEX_VERSION_FILE}
1155       ${${prefix}_DOCUMENTATION}
1156       ${${prefix}_UNPARSED_ARGUMENTS})
1157   else()
1158     if(${prefix}_MODULE)
1159       set(type MODULE)
1160     else()
1161       set(type SHARED)
1162     endif()
1163
1164     add_library(${${prefix}_NAME}
1165       ${type}
1166       ${_option_EXCLUDE_FROM_ALL}
1167       ${${prefix}_SRC}
1168       ${MEX_VERSION_FILE}
1169       ${${prefix}_DOCUMENTATION}
1170       ${${prefix}_UNPARSED_ARGUMENTS})
1171   endif()
1172
1173   target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS})
1174
1175   if(NOT ${prefix}_NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES)
1176     if(Matlab_HAS_CPP_API)
1177       if(Matlab_ENGINE_LIBRARY)
1178         target_link_libraries(${${prefix}_NAME} ${Matlab_ENGINE_LIBRARY})
1179       endif()
1180       if(Matlab_DATAARRAY_LIBRARY)
1181         target_link_libraries(${${prefix}_NAME} ${Matlab_DATAARRAY_LIBRARY})
1182       endif()
1183     endif()
1184
1185     target_link_libraries(${${prefix}_NAME} ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY})
1186   endif()
1187   target_link_libraries(${${prefix}_NAME} ${${prefix}_LINK_TO})
1188   set_target_properties(${${prefix}_NAME}
1189       PROPERTIES
1190         PREFIX ""
1191         OUTPUT_NAME ${${prefix}_OUTPUT_NAME}
1192         SUFFIX ".${Matlab_MEX_EXTENSION}")
1193
1194   target_compile_definitions(${${prefix}_NAME} PRIVATE ${MEX_API_MACRO} MATLAB_MEX_FILE)
1195
1196   # documentation
1197   if(NOT ${${prefix}_DOCUMENTATION} STREQUAL "")
1198     get_target_property(output_name ${${prefix}_NAME} OUTPUT_NAME)
1199     add_custom_command(
1200       TARGET ${${prefix}_NAME}
1201       PRE_BUILD
1202       COMMAND ${CMAKE_COMMAND} -E copy_if_different ${${prefix}_DOCUMENTATION} $<TARGET_FILE_DIR:${${prefix}_NAME}>/${output_name}.m
1203       COMMENT "[MATLAB] Copy ${${prefix}_NAME} documentation file into the output folder"
1204     )
1205   endif() # documentation
1206
1207   # entry point in the mex file + taking care of visibility and symbol clashes.
1208   if(WIN32)
1209
1210     if (MSVC)
1211
1212       set(_link_flags "${_link_flags} /EXPORT:mexFunction")
1213       if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, export version
1214         set(_link_flags "${_link_flags} /EXPORT:mexfilerequiredapiversion")
1215       endif()
1216
1217       set_property(TARGET ${${prefix}_NAME} APPEND PROPERTY LINK_FLAGS ${_link_flags})
1218
1219     endif() # No other compiler currently supported on Windows.
1220
1221     set_target_properties(${${prefix}_NAME}
1222       PROPERTIES
1223         DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)")
1224
1225   else()
1226
1227     if(Matlab_VERSION_STRING VERSION_LESS "9.1") # For versions prior to 9.1 (R2016b)
1228       set(_ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/mexFunction.map)
1229     else()                                          # For 9.1 (R2016b) and newer
1230       set(_ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/c_exportsmexfileversion.map)
1231     endif()
1232
1233     if(NOT Matlab_VERSION_STRING VERSION_LESS "9.5") # For 9.5 (R2018b) (and newer?)
1234       target_compile_options(${${prefix}_NAME} PRIVATE "-fvisibility=default")
1235       # This one is weird, it might be a bug in <mex.h> for R2018b. When compiling with
1236       # -fvisibility=hidden, the symbol `mexFunction` cannot be exported. Reading the
1237       # source code for <mex.h>, it seems that the preprocessor macro `MW_NEEDS_VERSION_H`
1238       # needs to be defined for `__attribute__((visibility("default")))` to be added
1239       # in front of the declaration of `mexFunction`. In previous versions of MATLAB this
1240       # was not the case, there `DLL_EXPORT_SYM` needed to be defined.
1241       # Adding `-fvisibility=hidden` to the `mex` command causes the build to fail.
1242       # TODO: Check that this is still necessary in R2019a when it comes out.
1243     endif()
1244
1245     if(APPLE)
1246
1247       if(Matlab_HAS_CPP_API)
1248         list(APPEND _ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/cppMexFunction.map) # This one doesn't exist on Linux
1249         set(_link_flags "${_link_flags} -Wl,-U,_mexCreateMexFunction -Wl,-U,_mexDestroyMexFunction -Wl,-U,_mexFunctionAdapter")
1250         # On MacOS, the MEX command adds the above, without it the link breaks
1251         # because we indiscriminately use "cppMexFunction.map" even for C API MEX-files.
1252       endif()
1253
1254       set(_export_flag_name -exported_symbols_list)
1255
1256     else() # Linux
1257
1258       if(HAS_MINUS_PTHREAD)
1259         # Apparently, compiling with -pthread generated the proper link flags
1260         # and some defines at compilation
1261         target_compile_options(${${prefix}_NAME} PRIVATE "-pthread")
1262       endif()
1263
1264       set(_link_flags "${_link_flags} -Wl,--as-needed")
1265
1266       set(_export_flag_name --version-script)
1267
1268     endif()
1269
1270     foreach(_file ${_ver_map_files})
1271       set(_link_flags "${_link_flags} -Wl,${_export_flag_name},${_file}")
1272     endforeach()
1273
1274     # The `mex` command doesn't add this define. It is specified here in order
1275     # to export the symbol in case the client code decides to hide its symbols
1276     set_target_properties(${${prefix}_NAME}
1277       PROPERTIES
1278         DEFINE_SYMBOL "DLL_EXPORT_SYM=__attribute__((visibility(\"default\")))"
1279         LINK_FLAGS "${_link_flags}"
1280     )
1281
1282   endif()
1283
1284 endfunction()
1285
1286
1287 # (internal)
1288 # Used to get the version of matlab, using caching. This basically transforms the
1289 # output of the root list, with possible unknown version, to a version
1290 # This can possibly run Matlab for extracting the version.
1291 function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_version matlab_final_version)
1292
1293   # if the version is not trivial, we query matlab (if not MCR) for that
1294   # we keep track of the location of matlab that induced this version
1295   #if(NOT DEFINED Matlab_PROG_VERSION_STRING_AUTO_DETECT)
1296   #  set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version")
1297   #endif()
1298
1299   if(NOT matlab_known_version STREQUAL "NOTFOUND")
1300     # the version is known, we just return it
1301     set(${matlab_final_version} ${matlab_known_version} PARENT_SCOPE)
1302     set(Matlab_VERSION_STRING_INTERNAL ${matlab_known_version} CACHE INTERNAL "Matlab version (automatically determined)" FORCE)
1303     return()
1304   endif()
1305
1306   if(matlab_or_mcr STREQUAL "UNKNOWN")
1307     if(MATLAB_FIND_DEBUG)
1308       message(WARNING "[MATLAB] Determining Matlab or MCR")
1309     endif()
1310
1311     if(EXISTS "${matlab_root}/appdata/version.xml")
1312       # we inspect the application version.xml file that contains the product information
1313       file(STRINGS "${matlab_root}/appdata/version.xml" productinfo_string NEWLINE_CONSUME)
1314       string(REGEX MATCH "<installedProductData.*displayedString=\"([a-zA-Z ]+)\".*/>"
1315              product_reg_match
1316              ${productinfo_string}
1317             )
1318
1319       # default fallback to Matlab
1320       set(matlab_or_mcr "MATLAB")
1321       if(NOT CMAKE_MATCH_1 STREQUAL "")
1322         string(TOLOWER "${CMAKE_MATCH_1}" product_reg_match)
1323
1324         if(product_reg_match STREQUAL "matlab runtime")
1325           set(matlab_or_mcr "MCR")
1326         endif()
1327       endif()
1328     endif()
1329
1330     if(MATLAB_FIND_DEBUG)
1331       message(WARNING "[MATLAB] '${matlab_root}' contains the '${matlab_or_mcr}'")
1332     endif()
1333   endif()
1334
1335   # UNKNOWN is the default behavior in case we
1336   # - have an erroneous matlab_root
1337   # - have an initial 'UNKNOWN'
1338   if(matlab_or_mcr STREQUAL "MATLAB" OR matlab_or_mcr STREQUAL "UNKNOWN")
1339     # MATLAB versions
1340     set(_matlab_current_program ${Matlab_MAIN_PROGRAM})
1341
1342     # do we already have a matlab program?
1343     if(NOT _matlab_current_program)
1344
1345       set(_find_matlab_options)
1346       if(matlab_root AND EXISTS ${matlab_root})
1347         set(_find_matlab_options PATHS ${matlab_root} ${matlab_root}/bin NO_DEFAULT_PATH)
1348       endif()
1349
1350       find_program(
1351           _matlab_current_program
1352           matlab
1353           ${_find_matlab_options}
1354           DOC "Matlab main program"
1355         )
1356     endif()
1357
1358     if(NOT _matlab_current_program OR NOT EXISTS ${_matlab_current_program})
1359       # if not found, clear the dependent variables
1360       if(MATLAB_FIND_DEBUG)
1361         message(WARNING "[MATLAB] Cannot find the main matlab program under ${matlab_root}")
1362       endif()
1363       set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
1364       set(Matlab_VERSION_STRING_INTERNAL "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
1365       unset(_matlab_current_program)
1366       unset(_matlab_current_program CACHE)
1367       return()
1368     endif()
1369
1370     # full real path for path comparison
1371     get_filename_component(_matlab_main_real_path_tmp "${_matlab_current_program}" REALPATH)
1372     unset(_matlab_current_program)
1373     unset(_matlab_current_program CACHE)
1374
1375     # is it the same as the previous one?
1376     if(_matlab_main_real_path_tmp STREQUAL Matlab_PROG_VERSION_STRING_AUTO_DETECT)
1377       set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE)
1378       return()
1379     endif()
1380
1381     # update the location of the program
1382     set(Matlab_PROG_VERSION_STRING_AUTO_DETECT
1383         ${_matlab_main_real_path_tmp}
1384         CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
1385
1386     set(matlab_list_of_all_versions)
1387     matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions)
1388
1389     list(LENGTH matlab_list_of_all_versions list_of_all_versions_length)
1390     if(list_of_all_versions_length GREATER 0)
1391       list(GET matlab_list_of_all_versions 0 _matlab_version_tmp)
1392     else()
1393       set(_matlab_version_tmp "unknown")
1394     endif()
1395
1396     # set the version into the cache
1397     set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)" FORCE)
1398
1399     # warning, just in case several versions found (should not happen)
1400     if((list_of_all_versions_length GREATER 1) AND MATLAB_FIND_DEBUG)
1401       message(WARNING "[MATLAB] Found several versions, taking the first one (versions found ${matlab_list_of_all_versions})")
1402     endif()
1403
1404     # return the updated value
1405     set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE)
1406   elseif(EXISTS "${matlab_root}/VersionInfo.xml")
1407     # MCR
1408     # we cannot run anything in order to extract the version. We assume that the file
1409     # VersionInfo.xml exists under the MatlabRoot, we look for it and extract the version from there
1410     set(_matlab_version_tmp "unknown")
1411     file(STRINGS "${matlab_root}/VersionInfo.xml" versioninfo_string NEWLINE_CONSUME)
1412
1413     if(versioninfo_string)
1414       # parses "<version>9.2.0.538062</version>"
1415       string(REGEX MATCH "<version>(.*)</version>"
1416              version_reg_match
1417              ${versioninfo_string}
1418             )
1419
1420       if(CMAKE_MATCH_1 MATCHES "(([0-9]+)\\.([0-9]+))[\\.0-9]*")
1421         set(_matlab_version_tmp "${CMAKE_MATCH_1}")
1422       endif()
1423     endif()
1424     set(${matlab_final_version} "${_matlab_version_tmp}" PARENT_SCOPE)
1425     set(Matlab_VERSION_STRING_INTERNAL
1426         "${_matlab_version_tmp}"
1427         CACHE INTERNAL "Matlab (MCR) version (automatically determined)"
1428         FORCE)
1429   endif() # Matlab or MCR
1430
1431 endfunction()
1432
1433
1434 # Utility function for finding Matlab or MCR on Win32
1435 function(_Matlab_find_instances_win32 matlab_roots)
1436   # On WIN32, we look for Matlab installation in the registry
1437   # if unsuccessful, we look for all known revision and filter the existing
1438   # ones.
1439
1440   # testing if we are able to extract the needed information from the registry
1441   set(_matlab_versions_from_registry)
1442
1443   if(CMAKE_SIZEOF_VOID_P EQUAL 8)
1444     set(_matlab_win64 ON)
1445   else()
1446     set(_matlab_win64 OFF)
1447   endif()
1448
1449   matlab_extract_all_installed_versions_from_registry(_matlab_win64 _matlab_versions_from_registry)
1450
1451   # the returned list is empty, doing the search on all known versions
1452   if(NOT _matlab_versions_from_registry)
1453     if(MATLAB_FIND_DEBUG)
1454       message(STATUS "[MATLAB] Search for Matlab from the registry unsuccessful, testing all supported versions")
1455     endif()
1456     extract_matlab_versions_from_registry_brute_force(_matlab_versions_from_registry)
1457   endif()
1458
1459   # filtering the results with the registry keys
1460   matlab_get_all_valid_matlab_roots_from_registry("${_matlab_versions_from_registry}" _matlab_possible_roots)
1461   set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE)
1462
1463 endfunction()
1464
1465 # Utility function for finding Matlab or MCR on OSX
1466 function(_Matlab_find_instances_osx matlab_roots)
1467
1468   set(_matlab_possible_roots)
1469   # on mac, we look for the /Application paths
1470   # this corresponds to the behavior on Windows. On Linux, we do not have
1471   # any other guess.
1472   matlab_get_supported_releases(_matlab_releases)
1473   if(MATLAB_FIND_DEBUG)
1474     message(STATUS "[MATLAB] Matlab supported versions ${_matlab_releases}. If more version should be supported "
1475                  "the variable MATLAB_ADDITIONAL_VERSIONS can be set according to the documentation")
1476   endif()
1477
1478   foreach(_matlab_current_release IN LISTS _matlab_releases)
1479     matlab_get_version_from_release_name("${_matlab_current_release}" _matlab_current_version)
1480     string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
1481     set(_matlab_base_path "/Applications/MATLAB_${_matlab_current_release}.app")
1482
1483     # Check Matlab, has precedence over MCR
1484     if(EXISTS ${_matlab_base_path})
1485       if(MATLAB_FIND_DEBUG)
1486         message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_base_path}")
1487       endif()
1488       list(APPEND _matlab_possible_roots "MATLAB" ${_matlab_current_version} ${_matlab_base_path})
1489     endif()
1490
1491     # Checks MCR
1492     set(_mcr_path "/Applications/MATLAB/MATLAB_Runtime/v${_matlab_current_version_without_dot}")
1493     if(EXISTS "${_mcr_path}")
1494       if(MATLAB_FIND_DEBUG)
1495         message(STATUS "[MATLAB] Found MCR version ${_matlab_current_release} (${_matlab_current_version}) in ${_mcr_path}")
1496       endif()
1497       list(APPEND _matlab_possible_roots "MCR" ${_matlab_current_version} ${_mcr_path})
1498     endif()
1499
1500   endforeach()
1501   set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE)
1502
1503 endfunction()
1504
1505 # Utility function for finding Matlab or MCR from the PATH
1506 function(_Matlab_find_instances_from_path matlab_roots)
1507
1508   set(_matlab_possible_roots)
1509
1510   # At this point, we have no other choice than trying to find it from PATH.
1511   # If set by the user, this won't change.
1512   find_program(
1513     _matlab_main_tmp
1514     NAMES matlab)
1515
1516   if(_matlab_main_tmp)
1517     # we then populate the list of roots, with empty version
1518     if(MATLAB_FIND_DEBUG)
1519       message(STATUS "[MATLAB] matlab found from PATH: ${_matlab_main_tmp}")
1520     endif()
1521
1522     # resolve symlinks
1523     get_filename_component(_matlab_current_location "${_matlab_main_tmp}" REALPATH)
1524
1525     # get the directory (the command below has to be run twice)
1526     # this will be the matlab root
1527     get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY)
1528     get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY) # Matlab should be in bin
1529
1530     # We found the Matlab program
1531     list(APPEND _matlab_possible_roots "MATLAB" "NOTFOUND" ${_matlab_current_location})
1532
1533     # we remove this from the CACHE
1534     unset(_matlab_main_tmp CACHE)
1535   else()
1536     find_program(
1537       _matlab_mex_tmp
1538       NAMES mex)
1539     if(_matlab_mex_tmp)
1540       # we then populate the list of roots, with empty version
1541       if(MATLAB_FIND_DEBUG)
1542         message(STATUS "[MATLAB] mex compiler found from PATH: ${_matlab_mex_tmp}")
1543       endif()
1544
1545       # resolve symlinks
1546       get_filename_component(_mex_current_location "${_matlab_mex_tmp}" REALPATH)
1547
1548       # get the directory (the command below has to be run twice)
1549       # this will be the matlab root
1550       get_filename_component(_mex_current_location "${_mex_current_location}" DIRECTORY)
1551       get_filename_component(_mex_current_location "${_mex_current_location}" DIRECTORY) # Matlab Runtime mex compiler should be in bin
1552
1553       # We found the Matlab program
1554       list(APPEND _matlab_possible_roots "MCR" "NOTFOUND" ${_mex_current_location})
1555
1556       unset(_matlab_mex_tmp CACHE)
1557     else()
1558       if(MATLAB_FIND_DEBUG)
1559         message(STATUS "[MATLAB] mex compiler not found")
1560       endif()
1561     endif()
1562
1563
1564   endif()
1565
1566   set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE)
1567 endfunction()
1568
1569
1570 # ###################################
1571 # Exploring the possible Matlab_ROOTS
1572
1573 # this variable will get all Matlab installations found in the current system.
1574 set(_matlab_possible_roots)
1575
1576 if(Matlab_ROOT_DIR)
1577   # if the user specifies a possible root, we keep this one
1578
1579   if(NOT EXISTS "${Matlab_ROOT_DIR}")
1580     # if Matlab_ROOT_DIR specified but erroneous
1581     if(MATLAB_FIND_DEBUG)
1582       message(WARNING "[MATLAB] the specified path for Matlab_ROOT_DIR does not exist (${Matlab_ROOT_DIR})")
1583     endif()
1584   else()
1585     # NOTFOUND indicates the code below to search for the version automatically
1586     if("${Matlab_VERSION_STRING_INTERNAL}" STREQUAL "")
1587       list(APPEND _matlab_possible_roots "UNKNOWN" "NOTFOUND" ${Matlab_ROOT_DIR}) # empty version, empty MCR/Matlab indication
1588     else()
1589       list(APPEND _matlab_possible_roots "UNKNOWN" ${Matlab_VERSION_STRING_INTERNAL} ${Matlab_ROOT_DIR}) # cached version
1590     endif()
1591   endif()
1592 else()
1593
1594   # if the user does not specify the possible installation root, we look for
1595   # one installation using the appropriate heuristics.
1596   # There is apparently no standard way on Linux.
1597   if(CMAKE_HOST_WIN32)
1598     _Matlab_find_instances_win32(_matlab_possible_roots_win32)
1599     list(APPEND _matlab_possible_roots ${_matlab_possible_roots_win32})
1600   elseif(APPLE)
1601     _Matlab_find_instances_osx(_matlab_possible_roots_osx)
1602     list(APPEND _matlab_possible_roots ${_matlab_possible_roots_osx})
1603   endif()
1604 endif()
1605
1606
1607 list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots)
1608 if(_numbers_of_matlab_roots EQUAL 0)
1609   # if we have not found anything, we fall back on the PATH
1610   _Matlab_find_instances_from_path(_matlab_possible_roots)
1611 endif()
1612
1613
1614 if(MATLAB_FIND_DEBUG)
1615   message(STATUS "[MATLAB] Matlab root folders are ${_matlab_possible_roots}")
1616 endif()
1617
1618
1619
1620
1621
1622 # take the first possible Matlab root
1623 list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots)
1624 set(Matlab_VERSION_STRING "NOTFOUND")
1625 set(Matlab_Or_MCR "UNKNOWN")
1626 if(_numbers_of_matlab_roots GREATER 0)
1627   if(Matlab_FIND_VERSION_EXACT)
1628     list(FIND _matlab_possible_roots ${Matlab_FIND_VERSION} _list_index)
1629     if(_list_index LESS 0)
1630       set(_list_index 1)
1631     endif()
1632
1633     math(EXPR _matlab_or_mcr_index "${_list_index} - 1")
1634     math(EXPR _matlab_root_dir_index "${_list_index} + 1")
1635
1636     list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR)
1637     list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING)
1638     list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR)
1639   elseif(DEFINED Matlab_FIND_VERSION)
1640     set(_list_index -1)
1641     foreach(_matlab_root_index RANGE 1 ${_numbers_of_matlab_roots} 3)
1642       list(GET _matlab_possible_roots ${_matlab_root_index} _matlab_root_version)
1643       if(_matlab_root_version VERSION_GREATER_EQUAL Matlab_FIND_VERSION)
1644         set(_list_index ${_matlab_root_index})
1645         break()
1646       endif()
1647     endforeach()
1648
1649     if(_list_index LESS 0)
1650       set(_list_index 1)
1651     endif()
1652
1653     math(EXPR _matlab_or_mcr_index "${_list_index} - 1")
1654     math(EXPR _matlab_root_dir_index "${_list_index} + 1")
1655     list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR)
1656     list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING)
1657     list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR)
1658     # adding a warning in case of ambiguity
1659     if(_numbers_of_matlab_roots GREATER 3 AND MATLAB_FIND_DEBUG)
1660       message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})."
1661                       " If this is not the desired behavior, use the EXACT keyword or provide the -DMatlab_ROOT_DIR=... on the command line")
1662     endif()
1663   else()
1664     list(GET _matlab_possible_roots 0 Matlab_Or_MCR)
1665     list(GET _matlab_possible_roots 1 Matlab_VERSION_STRING)
1666     list(GET _matlab_possible_roots 2 Matlab_ROOT_DIR)
1667
1668     # adding a warning in case of ambiguity
1669     if(_numbers_of_matlab_roots GREATER 3 AND MATLAB_FIND_DEBUG)
1670       message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})."
1671                       " If this is not the desired behavior, use the EXACT keyword or provide the -DMatlab_ROOT_DIR=... on the command line")
1672     endif()
1673   endif()
1674 endif()
1675
1676
1677 # check if the root changed wrt. the previous defined one, if so
1678 # clear all the cached variables for being able to reconfigure properly
1679 if(DEFINED Matlab_ROOT_DIR_LAST_CACHED)
1680
1681   if(NOT Matlab_ROOT_DIR_LAST_CACHED STREQUAL Matlab_ROOT_DIR)
1682     set(_Matlab_cached_vars
1683         Matlab_VERSION_STRING
1684         Matlab_INCLUDE_DIRS
1685         Matlab_MEX_LIBRARY
1686         Matlab_MEX_COMPILER
1687         Matlab_MCC_COMPILER
1688         Matlab_MAIN_PROGRAM
1689         Matlab_MX_LIBRARY
1690         Matlab_ENG_LIBRARY
1691         Matlab_MAT_LIBRARY
1692         Matlab_ENGINE_LIBRARY
1693         Matlab_DATAARRAY_LIBRARY
1694         Matlab_MEX_EXTENSION
1695         Matlab_SIMULINK_INCLUDE_DIR
1696
1697         # internal
1698         Matlab_MEXEXTENSIONS_PROG
1699         Matlab_ROOT_DIR_LAST_CACHED
1700         #Matlab_PROG_VERSION_STRING_AUTO_DETECT
1701         #Matlab_VERSION_STRING_INTERNAL
1702         )
1703     foreach(_var IN LISTS _Matlab_cached_vars)
1704       if(DEFINED ${_var})
1705         unset(${_var} CACHE)
1706       endif()
1707     endforeach()
1708   endif()
1709 endif()
1710
1711 set(Matlab_ROOT_DIR_LAST_CACHED ${Matlab_ROOT_DIR} CACHE INTERNAL "last Matlab root dir location")
1712 set(Matlab_ROOT_DIR ${Matlab_ROOT_DIR} CACHE PATH "Matlab installation root path" FORCE)
1713
1714 # Fix the version, in case this one is NOTFOUND
1715 _Matlab_get_version_from_root(
1716   "${Matlab_ROOT_DIR}"
1717   "${Matlab_Or_MCR}"
1718   ${Matlab_VERSION_STRING}
1719   Matlab_VERSION_STRING
1720 )
1721
1722 if(MATLAB_FIND_DEBUG)
1723   message(STATUS "[MATLAB] Current version is ${Matlab_VERSION_STRING} located ${Matlab_ROOT_DIR}")
1724 endif()
1725
1726 # MATLAB 9.4 (R2018a) and newer have a new C++ API
1727 # This API pulls additional required libraries.
1728 if(NOT ${Matlab_VERSION_STRING} VERSION_LESS "9.4")
1729   set(Matlab_HAS_CPP_API 1)
1730 endif()
1731
1732 if(Matlab_ROOT_DIR)
1733   file(TO_CMAKE_PATH ${Matlab_ROOT_DIR} Matlab_ROOT_DIR)
1734 endif()
1735
1736 if(CMAKE_SIZEOF_VOID_P EQUAL 4)
1737   set(_matlab_64Build FALSE)
1738 else()
1739   set(_matlab_64Build TRUE)
1740 endif()
1741
1742 if(APPLE)
1743   set(_matlab_bin_prefix "mac") # i should be for intel
1744   set(_matlab_bin_suffix_32bits "i")
1745   if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
1746     set(_matlab_bin_suffix_64bits "a64")
1747   else()
1748     set(_matlab_bin_suffix_64bits "i64")
1749   endif()
1750 elseif(UNIX)
1751   set(_matlab_bin_prefix "gln")
1752   set(_matlab_bin_suffix_32bits "x86")
1753   set(_matlab_bin_suffix_64bits "xa64")
1754 else()
1755   set(_matlab_bin_prefix "win")
1756   set(_matlab_bin_suffix_32bits "32")
1757   set(_matlab_bin_suffix_64bits "64")
1758 endif()
1759
1760
1761
1762 set(MATLAB_INCLUDE_DIR_TO_LOOK ${Matlab_ROOT_DIR}/extern/include)
1763 if(_matlab_64Build)
1764   set(_matlab_current_suffix ${_matlab_bin_suffix_64bits})
1765 else()
1766   set(_matlab_current_suffix ${_matlab_bin_suffix_32bits})
1767 endif()
1768
1769 set(Matlab_BINARIES_DIR
1770     ${Matlab_ROOT_DIR}/bin/${_matlab_bin_prefix}${_matlab_current_suffix})
1771 set(Matlab_EXTERN_LIBRARY_DIR
1772     ${Matlab_ROOT_DIR}/extern/lib/${_matlab_bin_prefix}${_matlab_current_suffix})
1773 set(Matlab_EXTERN_BINARIES_DIR
1774     ${Matlab_ROOT_DIR}/extern/bin/${_matlab_bin_prefix}${_matlab_current_suffix})
1775
1776 if(WIN32)
1777   if(MINGW)
1778     set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/mingw64)
1779   else()
1780     set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/microsoft)
1781   endif()
1782   set(_matlab_lib_prefix_for_search "lib")
1783 else()
1784   set(_matlab_lib_dir_for_search ${Matlab_BINARIES_DIR} ${Matlab_EXTERN_BINARIES_DIR})
1785   set(_matlab_lib_prefix_for_search "lib")
1786 endif()
1787
1788 unset(_matlab_64Build)
1789
1790
1791 if(NOT DEFINED Matlab_MEX_EXTENSION)
1792   set(_matlab_mex_extension "")
1793   matlab_get_mex_suffix("${Matlab_ROOT_DIR}" _matlab_mex_extension)
1794
1795   # This variable goes to the cache.
1796   set(Matlab_MEX_EXTENSION ${_matlab_mex_extension} CACHE STRING "Extensions for the mex targets (automatically given by Matlab)")
1797   unset(_matlab_mex_extension)
1798 endif()
1799
1800
1801 if(MATLAB_FIND_DEBUG)
1802   message(STATUS "[MATLAB] [DEBUG]_matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}")
1803 endif()
1804
1805
1806
1807 # internal
1808 # This small stub around find_library is to prevent any pollution of CMAKE_FIND_LIBRARY_PREFIXES in the global scope.
1809 # This is the function to be used below instead of the find_library directives.
1810 function(_Matlab_find_library _matlab_library_prefix)
1811   set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} ${_matlab_library_prefix})
1812   find_library(${ARGN})
1813 endfunction()
1814
1815
1816 set(_matlab_required_variables)
1817
1818 # Order is as follow:
1819 # - unconditionally required libraries/headers first
1820 # - then library components
1821 # - then program components
1822
1823 # the MEX library/header are required
1824 find_path(
1825   Matlab_INCLUDE_DIRS
1826   mex.h
1827   PATHS ${MATLAB_INCLUDE_DIR_TO_LOOK}
1828   NO_DEFAULT_PATH
1829   )
1830 list(APPEND _matlab_required_variables Matlab_INCLUDE_DIRS)
1831
1832 if(Matlab_Or_MCR STREQUAL "MATLAB" OR Matlab_Or_MCR STREQUAL "UNKNOWN")
1833   _Matlab_find_library(
1834     ${_matlab_lib_prefix_for_search}
1835     Matlab_MEX_LIBRARY
1836     mex
1837     PATHS ${_matlab_lib_dir_for_search}
1838     NO_DEFAULT_PATH
1839   )
1840   list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY)
1841
1842   # the MEX extension is required
1843   list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION)
1844
1845   # the matlab root is required
1846   list(APPEND _matlab_required_variables Matlab_ROOT_DIR)
1847
1848   # The MX library is required
1849   _Matlab_find_library(
1850     ${_matlab_lib_prefix_for_search}
1851     Matlab_MX_LIBRARY
1852     mx
1853     PATHS ${_matlab_lib_dir_for_search}
1854     NO_DEFAULT_PATH
1855   )
1856   list(APPEND _matlab_required_variables Matlab_MX_LIBRARY)
1857   if(Matlab_MX_LIBRARY)
1858     set(Matlab_MX_LIBRARY_FOUND TRUE)
1859   endif()
1860 endif()
1861
1862 if(Matlab_HAS_CPP_API)
1863
1864   # The MatlabEngine library is required for R2018a+
1865   _Matlab_find_library(
1866     ${_matlab_lib_prefix_for_search}
1867     Matlab_ENGINE_LIBRARY
1868     MatlabEngine
1869     PATHS ${_matlab_lib_dir_for_search}
1870     DOC "MatlabEngine Library"
1871     NO_DEFAULT_PATH
1872   )
1873   if(Matlab_ENGINE_LIBRARY)
1874     set(Matlab_ENGINE_LIBRARY_FOUND TRUE)
1875   endif()
1876
1877   # The MatlabDataArray library is required for R2018a+
1878   _Matlab_find_library(
1879     ${_matlab_lib_prefix_for_search}
1880     Matlab_DATAARRAY_LIBRARY
1881     MatlabDataArray
1882     PATHS ${_matlab_lib_dir_for_search}
1883     DOC "MatlabDataArray Library"
1884     NO_DEFAULT_PATH
1885   )
1886   if(Matlab_DATAARRAY_LIBRARY)
1887     set(Matlab_DATAARRAY_LIBRARY_FOUND TRUE)
1888   endif()
1889
1890 endif()
1891
1892 # Component ENG library
1893 if("ENG_LIBRARY" IN_LIST Matlab_FIND_COMPONENTS)
1894   _Matlab_find_library(
1895     ${_matlab_lib_prefix_for_search}
1896     Matlab_ENG_LIBRARY
1897     eng
1898     PATHS ${_matlab_lib_dir_for_search}
1899     NO_DEFAULT_PATH
1900   )
1901   if(Matlab_ENG_LIBRARY)
1902     set(Matlab_ENG_LIBRARY_FOUND TRUE)
1903   endif()
1904 endif()
1905
1906 # Component MAT library
1907 if("MAT_LIBRARY" IN_LIST Matlab_FIND_COMPONENTS)
1908   _Matlab_find_library(
1909     ${_matlab_lib_prefix_for_search}
1910     Matlab_MAT_LIBRARY
1911     mat
1912     PATHS ${_matlab_lib_dir_for_search}
1913     NO_DEFAULT_PATH
1914   )
1915   if(Matlab_MAT_LIBRARY)
1916     set(Matlab_MAT_LIBRARY_FOUND TRUE)
1917   endif()
1918 endif()
1919
1920 # Component Simulink
1921 if("SIMULINK" IN_LIST Matlab_FIND_COMPONENTS)
1922   find_path(
1923     Matlab_SIMULINK_INCLUDE_DIR
1924     simstruc.h
1925     PATHS "${Matlab_ROOT_DIR}/simulink/include"
1926     NO_DEFAULT_PATH
1927     )
1928   if(Matlab_SIMULINK_INCLUDE_DIR)
1929     set(Matlab_SIMULINK_FOUND TRUE)
1930     list(APPEND Matlab_INCLUDE_DIRS "${Matlab_SIMULINK_INCLUDE_DIR}")
1931   endif()
1932 endif()
1933
1934 # component Matlab program
1935 if("MAIN_PROGRAM" IN_LIST Matlab_FIND_COMPONENTS)
1936   find_program(
1937     Matlab_MAIN_PROGRAM
1938     matlab
1939     PATHS ${Matlab_ROOT_DIR} ${Matlab_ROOT_DIR}/bin
1940     DOC "Matlab main program"
1941     NO_DEFAULT_PATH
1942   )
1943   if(Matlab_MAIN_PROGRAM)
1944     set(Matlab_MAIN_PROGRAM_FOUND TRUE)
1945   endif()
1946 endif()
1947
1948 # component Mex Compiler
1949 if("MEX_COMPILER" IN_LIST Matlab_FIND_COMPONENTS)
1950   find_program(
1951     Matlab_MEX_COMPILER
1952     "mex"
1953     PATHS ${Matlab_BINARIES_DIR}
1954     DOC "Matlab MEX compiler"
1955     NO_DEFAULT_PATH
1956   )
1957   if(Matlab_MEX_COMPILER)
1958     set(Matlab_MEX_COMPILER_FOUND TRUE)
1959   endif()
1960 endif()
1961
1962 # component MCC Compiler
1963 if("MCC_COMPILER" IN_LIST Matlab_FIND_COMPONENTS)
1964   find_program(
1965     Matlab_MCC_COMPILER
1966     "mcc"
1967     PATHS ${Matlab_BINARIES_DIR}
1968     DOC "Matlab MCC compiler"
1969     NO_DEFAULT_PATH
1970   )
1971   if(Matlab_MCC_COMPILER)
1972     set(Matlab_MCC_COMPILER_FOUND TRUE)
1973   endif()
1974 endif()
1975
1976 set(Matlab_LIBRARIES
1977   ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY}
1978   ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY})
1979
1980 if(Matlab_ENGINE_LIBRARY)
1981   list(APPEND Matlab_LIBRARIES ${Matlab_ENGINE_LIBRARY})
1982 endif()
1983
1984 if(Matlab_DATAARRAY_LIBRARY)
1985   list(APPEND Matlab_LIBRARIES ${Matlab_DATAARRAY_LIBRARY})
1986 endif()
1987
1988 # internal
1989 # This small stub permits to add imported targets for the found MATLAB libraries
1990 function(_Matlab_add_imported_target _matlab_library_variable_name _matlab_library_target_name)
1991   if(Matlab_${_matlab_library_variable_name}_LIBRARY)
1992     if(NOT TARGET Matlab::${_matlab_library_target_name})
1993       add_library(Matlab::${_matlab_library_target_name} UNKNOWN IMPORTED)
1994       set_target_properties(Matlab::${_matlab_library_target_name} PROPERTIES
1995         INTERFACE_INCLUDE_DIRECTORIES "${Matlab_INCLUDE_DIRS}"
1996         IMPORTED_LOCATION "${Matlab_${_matlab_library_variable_name}_LIBRARY}")
1997       if(_matlab_library_target_name STREQUAL "mex" OR
1998          _matlab_library_target_name STREQUAL "eng" OR
1999          _matlab_library_target_name STREQUAL "mat")
2000         set_target_properties(Matlab::${_matlab_library_target_name} PROPERTIES
2001           INTERFACE_LINK_LIBRARIES Matlab::mx)
2002       endif()
2003     endif()
2004   endif()
2005 endfunction()
2006
2007 _Matlab_add_imported_target(MX mx)
2008 _Matlab_add_imported_target(MEX mex)
2009 _Matlab_add_imported_target(ENG eng)
2010 _Matlab_add_imported_target(MAT mat)
2011 _Matlab_add_imported_target(ENGINE MatlabEngine)
2012 _Matlab_add_imported_target(DATAARRAY MatlabDataArray)
2013
2014 find_package_handle_standard_args(
2015   Matlab
2016   FOUND_VAR Matlab_FOUND
2017   REQUIRED_VARS ${_matlab_required_variables}
2018   VERSION_VAR Matlab_VERSION_STRING
2019   HANDLE_COMPONENTS)
2020
2021 unset(_matlab_required_variables)
2022 unset(_matlab_bin_prefix)
2023 unset(_matlab_bin_suffix_32bits)
2024 unset(_matlab_bin_suffix_64bits)
2025 unset(_matlab_current_suffix)
2026 unset(_matlab_lib_dir_for_search)
2027 unset(_matlab_lib_prefix_for_search)
2028
2029 if(Matlab_INCLUDE_DIRS AND Matlab_LIBRARIES)
2030   mark_as_advanced(
2031     Matlab_MEX_LIBRARY
2032     Matlab_MX_LIBRARY
2033     Matlab_ENG_LIBRARY
2034     Matlab_ENGINE_LIBRARY
2035     Matlab_DATAARRAY_LIBRARY
2036     Matlab_MAT_LIBRARY
2037     Matlab_INCLUDE_DIRS
2038     Matlab_FOUND
2039     Matlab_MAIN_PROGRAM
2040     Matlab_MEXEXTENSIONS_PROG
2041     Matlab_MEX_EXTENSION
2042   )
2043 endif()
2044
2045 cmake_policy(POP)