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