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