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