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 installations and provides Matlab tools and libraries to cmake. 9# 10# This package first intention is to find the libraries associated with Matlab 11# in order to be able to build Matlab extensions (mex files). It can also be 12# used: 13# 14# * run specific commands in Matlab 15# * declare Matlab unit test 16# * retrieve various information from Matlab (mex extensions, versions and 17# release queries, ...) 18# 19# The module supports the following components: 20# 21# * ``MX_LIBRARY``, ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the MX, 22# ENG and MAT libraries of Matlab 23# * ``MAIN_PROGRAM`` the Matlab binary program. 24# * ``MEX_COMPILER`` the MEX compiler. 25# * ``SIMULINK`` the Simulink environment. 26# 27# .. note:: 28# 29# The version given to the :command:`find_package` directive is the Matlab 30# **version**, which should not be confused with the Matlab *release* name 31# (eg. `R2014`). 32# The :command:`matlab_get_version_from_release_name` and 33# :command:`matlab_get_release_name_from_version` allow a mapping 34# from the release name to the version. 35# 36# The variable :variable:`Matlab_ROOT_DIR` may be specified in order to give 37# the path of the desired Matlab version. Otherwise, the behaviour is platform 38# specific: 39# 40# * Windows: The installed versions of Matlab are retrieved from the 41# Windows registry 42# * OS X: The installed versions of Matlab are given by the MATLAB 43# paths in ``/Application``. If no such application is found, it falls back 44# to the one that might be accessible from the PATH. 45# * Unix: The desired Matlab should be accessible from the PATH. 46# 47# Additional information is provided when :variable:`MATLAB_FIND_DEBUG` is set. 48# When a Matlab binary is found automatically and the ``MATLAB_VERSION`` 49# is not given, the version is queried from Matlab directly. 50# On Windows, it can make a window running Matlab appear. 51# 52# The mapping of the release names and the version of Matlab is performed by 53# defining pairs (name, version). The variable 54# :variable:`MATLAB_ADDITIONAL_VERSIONS` may be provided before the call to 55# the :command:`find_package` in order to handle additional versions. 56# 57# A Matlab scripts can be added to the set of tests using the 58# :command:`matlab_add_unit_test`. By default, the Matlab unit test framework 59# will be used (>= 2013a) to run this script, but regular ``.m`` files 60# returning an exit code can be used as well (0 indicating a success). 61# 62# Module Input Variables 63# ^^^^^^^^^^^^^^^^^^^^^^ 64# 65# Users or projects may set the following variables to configure the module 66# behaviour: 67# 68# :variable:`Matlab_ROOT_DIR` 69# the root of the Matlab installation. 70# :variable:`MATLAB_FIND_DEBUG` 71# outputs debug information 72# :variable:`MATLAB_ADDITIONAL_VERSIONS` 73# additional versions of Matlab for the automatic retrieval of the installed 74# versions. 75# 76# Variables defined by the module 77# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 78# 79# Result variables 80# """""""""""""""" 81# 82# ``Matlab_FOUND`` 83# ``TRUE`` if the Matlab installation is found, ``FALSE`` 84# otherwise. All variable below are defined if Matlab is found. 85# ``Matlab_ROOT_DIR`` 86# the final root of the Matlab installation determined by the FindMatlab 87# module. 88# ``Matlab_MAIN_PROGRAM`` 89# the Matlab binary program. Available only if the component ``MAIN_PROGRAM`` 90# is given in the :command:`find_package` directive. 91# ``Matlab_INCLUDE_DIRS`` 92# the path of the Matlab libraries headers 93# ``Matlab_MEX_LIBRARY`` 94# library for mex, always available. 95# ``Matlab_MX_LIBRARY`` 96# mx library of Matlab (arrays). Available only if the component 97# ``MX_LIBRARY`` has been requested. 98# ``Matlab_ENG_LIBRARY`` 99# Matlab engine library. Available only if the component ``ENG_LIBRARY`` 100# is requested. 101# ``Matlab_MAT_LIBRARY`` 102# Matlab matrix library. Available only if the component ``MAT_LIBRARY`` 103# is requested. 104# ``Matlab_LIBRARIES`` 105# the whole set of libraries of Matlab 106# ``Matlab_MEX_COMPILER`` 107# the mex compiler of Matlab. Currently not used. 108# Available only if the component ``MEX_COMPILER`` is asked 109# 110# Cached variables 111# """""""""""""""" 112# 113# ``Matlab_MEX_EXTENSION`` 114# the extension of the mex files for the current platform (given by Matlab). 115# ``Matlab_ROOT_DIR`` 116# the location of the root of the Matlab installation found. If this value 117# is changed by the user, the result variables are recomputed. 118# 119# Provided macros 120# ^^^^^^^^^^^^^^^ 121# 122# :command:`matlab_get_version_from_release_name` 123# returns the version from the release name 124# :command:`matlab_get_release_name_from_version` 125# returns the release name from the Matlab version 126# 127# Provided functions 128# ^^^^^^^^^^^^^^^^^^ 129# 130# :command:`matlab_add_mex` 131# adds a target compiling a MEX file. 132# :command:`matlab_add_unit_test` 133# adds a Matlab unit test file as a test to the project. 134# :command:`matlab_extract_all_installed_versions_from_registry` 135# parses the registry for all Matlab versions. Available on Windows only. 136# The part of the registry parsed is dependent on the host processor 137# :command:`matlab_get_all_valid_matlab_roots_from_registry` 138# returns all the possible Matlab paths, according to a previously 139# given list. Only the existing/accessible paths are kept. This is mainly 140# useful for the searching all possible Matlab installation. 141# :command:`matlab_get_mex_suffix` 142# returns the suffix to be used for the mex files 143# (platform/architecture dependent) 144# :command:`matlab_get_version_from_matlab_run` 145# returns the version of Matlab, given the full directory of the Matlab 146# program. 147# 148# 149# Known issues 150# ^^^^^^^^^^^^ 151# 152# **Symbol clash in a MEX target** 153# By default, every symbols inside a MEX 154# file defined with the command :command:`matlab_add_mex` have hidden 155# visibility, except for the entry point. This is the default behaviour of 156# the MEX compiler, which lowers the risk of symbol collision between the 157# libraries shipped with Matlab, and the libraries to which the MEX file is 158# linking to. This is also the default on Windows platforms. 159# 160# However, this is not sufficient in certain case, where for instance your 161# MEX file is linking against libraries that are already loaded by Matlab, 162# even if those libraries have different SONAMES. 163# A possible solution is to hide the symbols of the libraries to which the 164# MEX target is linking to. This can be achieved in GNU GCC compilers with 165# the linker option ``-Wl,--exclude-libs,ALL``. 166# 167# **Tests using GPU resources** 168# in case your MEX file is using the GPU and 169# in order to be able to run unit tests on this MEX file, the GPU resources 170# should be properly released by Matlab. A possible solution is to make 171# Matlab aware of the use of the GPU resources in the session, which can be 172# performed by a command such as ``D = gpuDevice()`` at the beginning of 173# the test script (or via a fixture). 174# 175# 176# Reference 177# ^^^^^^^^^ 178# 179# .. variable:: Matlab_ROOT_DIR 180# 181# The root folder of the Matlab installation. If set before the call to 182# :command:`find_package`, the module will look for the components in that 183# path. If not set, then an automatic search of Matlab 184# will be performed. If set, it should point to a valid version of Matlab. 185# 186# .. variable:: MATLAB_FIND_DEBUG 187# 188# If set, the lookup of Matlab and the intermediate configuration steps are 189# outputted to the console. 190# 191# .. variable:: MATLAB_ADDITIONAL_VERSIONS 192# 193# If set, specifies additional versions of Matlab that may be looked for. 194# The variable should be a list of strings, organised by pairs of release 195# name and versions, such as follows:: 196# 197# set(MATLAB_ADDITIONAL_VERSIONS 198# "release_name1=corresponding_version1" 199# "release_name2=corresponding_version2" 200# ... 201# ) 202# 203# Example:: 204# 205# set(MATLAB_ADDITIONAL_VERSIONS 206# "R2013b=8.2" 207# "R2013a=8.1" 208# "R2012b=8.0") 209# 210# The order of entries in this list matters when several versions of 211# Matlab are installed. The priority is set according to the ordering in 212# this list. 213 214set(_FindMatlab_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}") 215 216include(FindPackageHandleStandardArgs) 217include(CheckCXXCompilerFlag) 218include(CheckCCompilerFlag) 219 220 221# The currently supported versions. Other version can be added by the user by 222# providing MATLAB_ADDITIONAL_VERSIONS 223if(NOT MATLAB_ADDITIONAL_VERSIONS) 224 set(MATLAB_ADDITIONAL_VERSIONS) 225endif() 226 227set(MATLAB_VERSIONS_MAPPING 228 "R2018a=9.4" 229 "R2017b=9.3" 230 "R2017a=9.2" 231 "R2016b=9.1" 232 "R2016a=9.0" 233 "R2015b=8.6" 234 "R2015a=8.5" 235 "R2014b=8.4" 236 "R2014a=8.3" 237 "R2013b=8.2" 238 "R2013a=8.1" 239 "R2012b=8.0" 240 "R2012a=7.14" 241 "R2011b=7.13" 242 "R2011a=7.12" 243 "R2010b=7.11" 244 245 ${MATLAB_ADDITIONAL_VERSIONS} 246 ) 247 248 249# temporary folder for all Matlab runs 250set(_matlab_temporary_folder ${CMAKE_BINARY_DIR}/Matlab) 251 252if(NOT EXISTS "${_matlab_temporary_folder}") 253 file(MAKE_DIRECTORY "${_matlab_temporary_folder}") 254endif() 255 256#.rst: 257# .. command:: matlab_get_version_from_release_name 258# 259# Returns the version of Matlab (17.58) from a release name (R2017k) 260macro (matlab_get_version_from_release_name release_name version_name) 261 262 string(REGEX MATCHALL "${release_name}=([0-9]+\\.?[0-9]*)" _matched ${MATLAB_VERSIONS_MAPPING}) 263 264 set(${version_name} "") 265 if(NOT _matched STREQUAL "") 266 set(${version_name} ${CMAKE_MATCH_1}) 267 else() 268 message(WARNING "The release name ${release_name} is not registered") 269 endif() 270 unset(_matched) 271 272endmacro() 273 274 275 276 277 278#.rst: 279# .. command:: matlab_get_release_name_from_version 280# 281# Returns the release name (R2017k) from the version of Matlab (17.58) 282macro (matlab_get_release_name_from_version version release_name) 283 284 set(${release_name} "") 285 foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) 286 string(REGEX MATCHALL "(.+)=${version}" _matched ${_var}) 287 if(NOT _matched STREQUAL "") 288 set(${release_name} ${CMAKE_MATCH_1}) 289 break() 290 endif() 291 endforeach(_var) 292 293 unset(_var) 294 unset(_matched) 295 if(${release_name} STREQUAL "") 296 message(WARNING "The version ${version} is not registered") 297 endif() 298 299endmacro() 300 301 302 303 304 305# extracts all the supported release names (R2017k...) of Matlab 306# internal use 307macro(matlab_get_supported_releases list_releases) 308 set(${list_releases}) 309 foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) 310 string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var}) 311 if(NOT _matched STREQUAL "") 312 list(APPEND ${list_releases} ${CMAKE_MATCH_1}) 313 endif() 314 unset(_matched) 315 unset(CMAKE_MATCH_1) 316 endforeach(_var) 317 unset(_var) 318endmacro() 319 320 321 322# extracts all the supported versions of Matlab 323# internal use 324macro(matlab_get_supported_versions list_versions) 325 set(${list_versions}) 326 foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) 327 string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var}) 328 if(NOT _matched STREQUAL "") 329 list(APPEND ${list_versions} ${CMAKE_MATCH_2}) 330 endif() 331 unset(_matched) 332 unset(CMAKE_MATCH_1) 333 endforeach(_var) 334 unset(_var) 335endmacro() 336 337 338#.rst: 339# .. command:: matlab_extract_all_installed_versions_from_registry 340# 341# This function parses the registry and founds the Matlab versions that are 342# installed. The found versions are returned in `matlab_versions`. 343# Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for 344# The returned list contains all versions under 345# ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` or an empty list in case an error 346# occurred (or nothing found). 347# 348# .. note:: 349# 350# Only the versions are provided. No check is made over the existence of the 351# installation referenced in the registry, 352# 353function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions) 354 355 if(NOT CMAKE_HOST_WIN32) 356 message(FATAL_ERROR "This macro can only be called by a windows host (call to reg.exe") 357 endif() 358 359 360 if(${win64} AND ${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "64") 361 set(APPEND_REG "/reg:64") 362 else() 363 set(APPEND_REG "/reg:32") 364 endif() 365 366 # /reg:64 should be added on 64 bits capable OSs in order to enable the 367 # redirection of 64 bits applications 368 execute_process( 369 COMMAND reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\MATLAB /f * /k ${APPEND_REG} 370 RESULT_VARIABLE resultMatlab 371 OUTPUT_VARIABLE varMatlab 372 ERROR_VARIABLE errMatlab 373 INPUT_FILE NUL 374 ) 375 376 377 set(matlabs_from_registry) 378 if(${resultMatlab} EQUAL 0) 379 380 string( 381 REGEX MATCHALL "MATLAB\\\\([0-9]+(\\.[0-9]+)?)" 382 matlab_versions_regex ${varMatlab}) 383 384 foreach(match IN LISTS matlab_versions_regex) 385 string( 386 REGEX MATCH "MATLAB\\\\(([0-9]+)(\\.([0-9]+))?)" 387 current_match ${match}) 388 389 set(_matlab_current_version ${CMAKE_MATCH_1}) 390 set(current_matlab_version_major ${CMAKE_MATCH_2}) 391 set(current_matlab_version_minor ${CMAKE_MATCH_4}) 392 if(NOT current_matlab_version_minor) 393 set(current_matlab_version_minor "0") 394 endif() 395 396 list(APPEND matlabs_from_registry ${_matlab_current_version}) 397 unset(_matlab_current_version) 398 endforeach(match) 399 400 endif() 401 402 if(matlabs_from_registry) 403 list(REMOVE_DUPLICATES matlabs_from_registry) 404 list(SORT matlabs_from_registry) 405 list(REVERSE matlabs_from_registry) 406 endif() 407 408 set(${matlab_versions} ${matlabs_from_registry} PARENT_SCOPE) 409 410endfunction() 411 412 413 414# (internal) 415macro(extract_matlab_versions_from_registry_brute_force matlab_versions) 416 # get the supported versions 417 set(matlab_supported_versions) 418 matlab_get_supported_versions(matlab_supported_versions) 419 420 421 # this is a manual population of the versions we want to look for 422 # this can be done as is, but preferably with the call to 423 # matlab_get_supported_versions and variable 424 425 # populating the versions we want to look for 426 # set(matlab_supported_versions) 427 428 # # Matlab 7 429 # set(matlab_major 7) 430 # foreach(current_matlab_minor RANGE 4 20) 431 # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") 432 # endforeach(current_matlab_minor) 433 434 # # Matlab 8 435 # set(matlab_major 8) 436 # foreach(current_matlab_minor RANGE 0 5) 437 # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") 438 # endforeach(current_matlab_minor) 439 440 # # taking into account the possible additional versions provided by the user 441 # if(DEFINED MATLAB_ADDITIONAL_VERSIONS) 442 # list(APPEND matlab_supported_versions MATLAB_ADDITIONAL_VERSIONS) 443 # endif() 444 445 446 # we order from more recent to older 447 if(matlab_supported_versions) 448 list(REMOVE_DUPLICATES matlab_supported_versions) 449 list(SORT matlab_supported_versions) 450 list(REVERSE matlab_supported_versions) 451 endif() 452 453 454 set(${matlab_versions} ${matlab_supported_versions}) 455 456 457endmacro() 458 459 460 461 462#.rst: 463# .. command:: matlab_get_all_valid_matlab_roots_from_registry 464# 465# Populates the Matlab root with valid versions of Matlab. 466# The returned matlab_roots is organized in pairs 467# ``(version_number,matlab_root_path)``. 468# 469# :: 470# 471# matlab_get_all_valid_matlab_roots_from_registry( 472# matlab_versions 473# matlab_roots) 474# 475# ``matlab_versions`` 476# the versions of each of the Matlab installations 477# ``matlab_roots`` 478# the location of each of the Matlab installations 479function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots) 480 481 # The matlab_versions comes either from 482 # extract_matlab_versions_from_registry_brute_force or 483 # matlab_extract_all_installed_versions_from_registry. 484 485 486 set(_matlab_roots_list ) 487 foreach(_matlab_current_version ${matlab_versions}) 488 get_filename_component( 489 current_MATLAB_ROOT 490 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]" 491 ABSOLUTE) 492 493 if(EXISTS ${current_MATLAB_ROOT}) 494 list(APPEND _matlab_roots_list ${_matlab_current_version} ${current_MATLAB_ROOT}) 495 endif() 496 497 endforeach(_matlab_current_version) 498 unset(_matlab_current_version) 499 set(${matlab_roots} ${_matlab_roots_list} PARENT_SCOPE) 500 unset(_matlab_roots_list) 501endfunction() 502 503#.rst: 504# .. command:: matlab_get_mex_suffix 505# 506# Returns the extension of the mex files (the suffixes). 507# This function should not be called before the appropriate Matlab root has 508# been found. 509# 510# :: 511# 512# matlab_get_mex_suffix( 513# matlab_root 514# mex_suffix) 515# 516# ``matlab_root`` 517# the root of the Matlab installation 518# ``mex_suffix`` 519# the variable name in which the suffix will be returned. 520function(matlab_get_mex_suffix matlab_root mex_suffix) 521 522 # todo setup the extension properly. Currently I do not know if this is 523 # sufficient for all win32 distributions. 524 # there is also CMAKE_EXECUTABLE_SUFFIX that could be tweaked 525 set(mexext_suffix "") 526 if(WIN32) 527 list(APPEND mexext_suffix ".bat") 528 endif() 529 530 # we first try without suffix, since cmake does not understand a list with 531 # one empty string element 532 find_program( 533 Matlab_MEXEXTENSIONS_PROG 534 NAMES mexext 535 PATHS ${matlab_root}/bin 536 DOC "Matlab MEX extension provider" 537 NO_DEFAULT_PATH 538 ) 539 540 foreach(current_mexext_suffix IN LISTS mexext_suffix) 541 if(NOT DEFINED Matlab_MEXEXTENSIONS_PROG OR NOT Matlab_MEXEXTENSIONS_PROG) 542 # this call should populate the cache automatically 543 find_program( 544 Matlab_MEXEXTENSIONS_PROG 545 "mexext${current_mexext_suffix}" 546 PATHS ${matlab_root}/bin 547 DOC "Matlab MEX extension provider" 548 NO_DEFAULT_PATH 549 ) 550 endif() 551 endforeach(current_mexext_suffix) 552 553 554 # the program has been found? 555 if((NOT Matlab_MEXEXTENSIONS_PROG) OR (NOT EXISTS ${Matlab_MEXEXTENSIONS_PROG})) 556 if(MATLAB_FIND_DEBUG) 557 message(WARNING "[MATLAB] Cannot found mexext program. Matlab root is ${matlab_root}") 558 endif() 559 unset(Matlab_MEXEXTENSIONS_PROG CACHE) 560 return() 561 endif() 562 563 set(_matlab_mex_extension) 564 565 set(devnull) 566 if(UNIX) 567 set(devnull INPUT_FILE /dev/null) 568 elseif(WIN32) 569 set(devnull INPUT_FILE NUL) 570 endif() 571 572 execute_process( 573 COMMAND ${Matlab_MEXEXTENSIONS_PROG} 574 OUTPUT_VARIABLE _matlab_mex_extension 575 ERROR_VARIABLE _matlab_mex_extension_error 576 ${devnull}) 577 string(STRIP ${_matlab_mex_extension} _matlab_mex_extension) 578 579 unset(Matlab_MEXEXTENSIONS_PROG CACHE) 580 set(${mex_suffix} ${_matlab_mex_extension} PARENT_SCOPE) 581endfunction() 582 583 584 585 586#.rst: 587# .. command:: matlab_get_version_from_matlab_run 588# 589# This function runs Matlab program specified on arguments and extracts its 590# version. 591# 592# :: 593# 594# matlab_get_version_from_matlab_run( 595# matlab_binary_path 596# matlab_list_versions) 597# 598# ``matlab_binary_path`` 599# the location of the `matlab` binary executable 600# ``matlab_list_versions`` 601# the version extracted from Matlab 602function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions) 603 604 set(${matlab_list_versions} "" PARENT_SCOPE) 605 606 607 if(MATLAB_FIND_DEBUG) 608 message(STATUS "[MATLAB] Determining the version of Matlab from ${matlab_binary_program}") 609 endif() 610 611 if(EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") 612 if(MATLAB_FIND_DEBUG) 613 message(STATUS "[MATLAB] Removing previous ${_matlab_temporary_folder}/matlabVersionLog.cmaketmp file") 614 endif() 615 file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") 616 endif() 617 618 619 # the log file is needed since on windows the command executes in a new 620 # window and it is not possible to get back the answer of Matlab 621 # the -wait command is needed on windows, otherwise the call returns 622 # immediately after the program launches itself. 623 if(WIN32) 624 set(_matlab_additional_commands "-wait") 625 endif() 626 627 set(devnull) 628 if(UNIX) 629 set(devnull INPUT_FILE /dev/null) 630 elseif(WIN32) 631 set(devnull INPUT_FILE NUL) 632 endif() 633 634 # timeout set to 120 seconds, in case it does not start 635 # note as said before OUTPUT_VARIABLE cannot be used in a platform 636 # independent manner however, not setting it would flush the output of Matlab 637 # in the current console (unix variant) 638 execute_process( 639 COMMAND "${matlab_binary_program}" -nosplash -nojvm ${_matlab_additional_commands} -logfile "matlabVersionLog.cmaketmp" -nodesktop -nodisplay -r "version, exit" 640 OUTPUT_VARIABLE _matlab_version_from_cmd_dummy 641 RESULT_VARIABLE _matlab_result_version_call 642 ERROR_VARIABLE _matlab_result_version_call_error 643 TIMEOUT 120 644 WORKING_DIRECTORY "${_matlab_temporary_folder}" 645 ${devnull} 646 ) 647 648 if("${_matlab_result_version_call}" MATCHES "timeout") 649 if(MATLAB_FIND_DEBUG) 650 message(WARNING "[MATLAB] Unable to determine the version of Matlab." 651 " Matlab call timed out after 120 seconds.") 652 endif() 653 return() 654 endif() 655 656 if(${_matlab_result_version_call}) 657 if(MATLAB_FIND_DEBUG) 658 message(WARNING "[MATLAB] Unable to determine the version of Matlab. Matlab call returned with error ${_matlab_result_version_call}.") 659 endif() 660 return() 661 elseif(NOT EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") 662 if(MATLAB_FIND_DEBUG) 663 message(WARNING "[MATLAB] Unable to determine the version of Matlab. The log file does not exist.") 664 endif() 665 return() 666 endif() 667 668 # if successful, read back the log 669 file(READ "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp" _matlab_version_from_cmd) 670 file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") 671 672 set(index -1) 673 string(FIND ${_matlab_version_from_cmd} "ans" index) 674 if(index EQUAL -1) 675 676 if(MATLAB_FIND_DEBUG) 677 message(WARNING "[MATLAB] Cannot find the version of Matlab returned by the run.") 678 endif() 679 680 else() 681 set(matlab_list_of_all_versions_tmp) 682 683 string(SUBSTRING ${_matlab_version_from_cmd} ${index} -1 substring_ans) 684 string( 685 REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)?)" 686 matlab_versions_regex 687 ${substring_ans}) 688 foreach(match IN LISTS matlab_versions_regex) 689 string( 690 REGEX MATCH "ans[\r\n\t ]*=[\r\n\t ]*'?(([0-9]+)(\\.([0-9]+))?)" 691 current_match ${match}) 692 693 list(APPEND matlab_list_of_all_versions_tmp ${CMAKE_MATCH_1}) 694 endforeach() 695 if(matlab_list_of_all_versions_tmp) 696 list(REMOVE_DUPLICATES matlab_list_of_all_versions_tmp) 697 endif() 698 set(${matlab_list_versions} ${matlab_list_of_all_versions_tmp} PARENT_SCOPE) 699 700 endif() 701 702endfunction() 703 704#.rst: 705# .. command:: matlab_add_unit_test 706# 707# Adds a Matlab unit test to the test set of cmake/ctest. 708# This command requires the component ``MAIN_PROGRAM``. 709# The unit test uses the Matlab unittest framework (default, available 710# starting Matlab 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK`` 711# is given. 712# 713# The function expects one Matlab test script file to be given. 714# In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file 715# should contain the script to be run, plus an exit command with the exit 716# value. This exit value will be passed to the ctest framework (0 success, 717# non 0 failure). Additional arguments accepted by :command:`add_test` can be 718# passed through ``TEST_ARGS`` (eg. ``CONFIGURATION <config> ...``). 719# 720# :: 721# 722# matlab_add_unit_test( 723# NAME <name> 724# UNITTEST_FILE matlab_file_containing_unittest.m 725# [CUSTOM_TEST_COMMAND matlab_command_to_run_as_test] 726# [UNITTEST_PRECOMMAND matlab_command_to_run] 727# [TIMEOUT timeout] 728# [ADDITIONAL_PATH path1 [path2 ...]] 729# [MATLAB_ADDITIONAL_STARTUP_OPTIONS option1 [option2 ...]] 730# [TEST_ARGS arg1 [arg2 ...]] 731# [NO_UNITTEST_FRAMEWORK] 732# ) 733# 734# The function arguments are: 735# 736# ``NAME`` 737# name of the unittest in ctest. 738# ``UNITTEST_FILE`` 739# the matlab unittest file. Its path will be automatically 740# added to the Matlab path. 741# ``CUSTOM_TEST_COMMAND`` 742# Matlab script command to run as the test. 743# If this is not set, then the following is run: 744# ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))`` 745# where ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension. 746# ``UNITTEST_PRECOMMAND`` 747# Matlab script command to be ran before the file 748# containing the test (eg. GPU device initialisation based on CMake 749# variables). 750# ``TIMEOUT`` 751# the test timeout in seconds. Defaults to 180 seconds as the 752# Matlab unit test may hang. 753# ``ADDITIONAL_PATH`` 754# a list of paths to add to the Matlab path prior to 755# running the unit test. 756# ``MATLAB_ADDITIONAL_STARTUP_OPTIONS`` 757# a list of additional option in order 758# to run Matlab from the command line. 759# ``-nosplash -nodesktop -nodisplay`` are always added. 760# ``TEST_ARGS`` 761# Additional options provided to the add_test command. These 762# options are added to the default options (eg. "CONFIGURATIONS Release") 763# ``NO_UNITTEST_FRAMEWORK`` 764# when set, indicates that the test should not 765# use the unittest framework of Matlab (available for versions >= R2013a). 766# ``WORKING_DIRECTORY`` 767# This will be the working directory for the test. If specified it will 768# also be the output directory used for the log file of the test run. 769# If not specifed the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` will 770# be used as the working directory and the log location. 771# 772function(matlab_add_unit_test) 773 774 if(NOT Matlab_MAIN_PROGRAM) 775 message(FATAL_ERROR "[MATLAB] This functionality needs the MAIN_PROGRAM component (not default)") 776 endif() 777 778 set(options NO_UNITTEST_FRAMEWORK) 779 set(oneValueArgs NAME UNITTEST_FILE TIMEOUT WORKING_DIRECTORY 780 UNITTEST_PRECOMMAND CUSTOM_TEST_COMMAND) 781 set(multiValueArgs ADDITIONAL_PATH MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS) 782 783 set(prefix _matlab_unittest_prefix) 784 cmake_parse_arguments(PARSE_ARGV 0 ${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ) 785 786 if(NOT ${prefix}_NAME) 787 message(FATAL_ERROR "[MATLAB] The Matlab test name cannot be empty") 788 endif() 789 790 add_test(NAME ${${prefix}_NAME} 791 COMMAND ${CMAKE_COMMAND} 792 "-Dtest_name=${${prefix}_NAME}" 793 "-Dadditional_paths=${${prefix}_ADDITIONAL_PATH}" 794 "-Dtest_timeout=${${prefix}_TIMEOUT}" 795 "-Doutput_directory=${_matlab_temporary_folder}" 796 "-Dworking_directory=${${prefix}_WORKING_DIRECTORY}" 797 "-DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM}" 798 "-Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK}" 799 "-DMatlab_ADDITIONAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS}" 800 "-Dunittest_file_to_run=${${prefix}_UNITTEST_FILE}" 801 "-Dcustom_Matlab_test_command=${${prefix}_CUSTOM_TEST_COMMAND}" 802 "-Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND}" 803 -P ${_FindMatlab_SELF_DIR}/MatlabTestsRedirect.cmake 804 ${${prefix}_TEST_ARGS} 805 ${${prefix}_UNPARSED_ARGUMENTS} 806 ) 807endfunction() 808 809 810#.rst: 811# .. command:: matlab_add_mex 812# 813# Adds a Matlab MEX target. 814# This commands compiles the given sources with the current tool-chain in 815# order to produce a MEX file. The final name of the produced output may be 816# specified, as well as additional link libraries, and a documentation entry 817# for the MEX file. Remaining arguments of the call are passed to the 818# :command:`add_library` or :command:`add_executable` command. 819# 820# :: 821# 822# matlab_add_mex( 823# NAME <name> 824# [EXECUTABLE | MODULE | SHARED] 825# SRC src1 [src2 ...] 826# [OUTPUT_NAME output_name] 827# [DOCUMENTATION file.txt] 828# [LINK_TO target1 target2 ...] 829# [...] 830# ) 831# 832# ``NAME`` 833# name of the target. 834# ``SRC`` 835# list of source files. 836# ``LINK_TO`` 837# a list of additional link dependencies. The target links to ``libmex`` 838# by default. If ``Matlab_MX_LIBRARY`` is defined, it also 839# links to ``libmx``. 840# ``OUTPUT_NAME`` 841# if given, overrides the default name. The default name is 842# the name of the target without any prefix and 843# with ``Matlab_MEX_EXTENSION`` suffix. 844# ``DOCUMENTATION`` 845# if given, the file ``file.txt`` will be considered as 846# being the documentation file for the MEX file. This file is copied into 847# the same folder without any processing, with the same name as the final 848# mex file, and with extension `.m`. In that case, typing ``help <name>`` 849# in Matlab prints the documentation contained in this file. 850# ``MODULE`` or ``SHARED`` may be given to specify the type of library to be 851# created. ``EXECUTABLE`` may be given to create an executable instead of 852# a library. If no type is given explicitly, the type is ``SHARED``. 853# 854# The documentation file is not processed and should be in the following 855# format: 856# 857# :: 858# 859# % This is the documentation 860# function ret = mex_target_output_name(input1) 861# 862function(matlab_add_mex) 863 864 if(NOT WIN32) 865 # we do not need all this on Windows 866 # pthread options 867 if(CMAKE_CXX_COMPILER_LOADED) 868 check_cxx_compiler_flag(-pthread HAS_MINUS_PTHREAD) 869 elseif(CMAKE_C_COMPILER_LOADED) 870 check_c_compiler_flag(-pthread HAS_MINUS_PTHREAD) 871 endif() 872 # we should use try_compile instead, the link flags are discarded from 873 # this compiler_flag function. 874 #check_cxx_compiler_flag(-Wl,--exclude-libs,ALL HAS_SYMBOL_HIDING_CAPABILITY) 875 876 endif() 877 878 set(options EXECUTABLE MODULE SHARED) 879 set(oneValueArgs NAME DOCUMENTATION OUTPUT_NAME) 880 set(multiValueArgs LINK_TO SRC) 881 882 set(prefix _matlab_addmex_prefix) 883 cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) 884 885 if(NOT ${prefix}_NAME) 886 message(FATAL_ERROR "[MATLAB] The MEX target name cannot be empty") 887 endif() 888 889 if(NOT ${prefix}_OUTPUT_NAME) 890 set(${prefix}_OUTPUT_NAME ${${prefix}_NAME}) 891 endif() 892 893 if(${prefix}_EXECUTABLE) 894 add_executable(${${prefix}_NAME} 895 ${${prefix}_SRC} 896 ${${prefix}_DOCUMENTATION} 897 ${${prefix}_UNPARSED_ARGUMENTS}) 898 else() 899 if(${prefix}_MODULE) 900 set(type MODULE) 901 else() 902 set(type SHARED) 903 endif() 904 905 add_library(${${prefix}_NAME} 906 ${type} 907 ${${prefix}_SRC} 908 ${${prefix}_DOCUMENTATION} 909 ${${prefix}_UNPARSED_ARGUMENTS}) 910 endif() 911 912 target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS}) 913 914 if(DEFINED Matlab_MX_LIBRARY) 915 target_link_libraries(${${prefix}_NAME} ${Matlab_MX_LIBRARY}) 916 endif() 917 918 target_link_libraries(${${prefix}_NAME} ${Matlab_MEX_LIBRARY} ${${prefix}_LINK_TO}) 919 set_target_properties(${${prefix}_NAME} 920 PROPERTIES 921 PREFIX "" 922 OUTPUT_NAME ${${prefix}_OUTPUT_NAME} 923 SUFFIX ".${Matlab_MEX_EXTENSION}") 924 925 926 # documentation 927 if(NOT ${${prefix}_DOCUMENTATION} STREQUAL "") 928 get_target_property(output_name ${${prefix}_NAME} OUTPUT_NAME) 929 add_custom_command( 930 TARGET ${${prefix}_NAME} 931 PRE_BUILD 932 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${${prefix}_DOCUMENTATION} $<TARGET_FILE_DIR:${${prefix}_NAME}>/${output_name}.m 933 COMMENT "Copy ${${prefix}_NAME} documentation file into the output folder" 934 ) 935 endif() # documentation 936 937 # entry point in the mex file + taking care of visibility and symbol clashes. 938 if(WIN32) 939 set_target_properties(${${prefix}_NAME} 940 PROPERTIES 941 DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)") 942 else() 943 944 if(HAS_MINUS_PTHREAD AND NOT APPLE) 945 # Apparently, compiling with -pthread generated the proper link flags 946 # and some defines at compilation 947 target_compile_options(${${prefix}_NAME} PRIVATE "-pthread") 948 endif() 949 950 951 # if we do not do that, the symbols linked from eg. boost remain weak and 952 # then clash with the ones defined in the matlab process. So by default 953 # the symbols are hidden. 954 # This also means that for shared libraries (like MEX), the entry point 955 # should be explicitly declared with default visibility, otherwise Matlab 956 # cannot find the entry point. 957 # Note that this is particularly meaningful if the MEX wrapper itself 958 # contains symbols that are clashing with Matlab (that are compiled in the 959 # MEX file). In order to propagate the visibility options to the libraries 960 # to which the MEX file is linked against, the -Wl,--exclude-libs,ALL 961 # option should also be specified. 962 963 set_target_properties(${${prefix}_NAME} 964 PROPERTIES 965 CXX_VISIBILITY_PRESET "hidden" 966 C_VISIBILITY_PRESET "hidden" 967 VISIBILITY_INLINES_HIDDEN ON 968 ) 969 970 # get_target_property( 971 # _previous_link_flags 972 # ${${prefix}_NAME} 973 # LINK_FLAGS) 974 # if(NOT _previous_link_flags) 975 # set(_previous_link_flags) 976 # endif() 977 978 # if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 979 # set_target_properties(${${prefix}_NAME} 980 # PROPERTIES 981 # LINK_FLAGS "${_previous_link_flags} -Wl,--exclude-libs,ALL" 982 # # -Wl,--version-script=${_FindMatlab_SELF_DIR}/MatlabLinuxVisibility.map" 983 # ) 984 # elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 985 # # in this case, all other symbols become hidden. 986 # set_target_properties(${${prefix}_NAME} 987 # PROPERTIES 988 # LINK_FLAGS "${_previous_link_flags} -Wl,-exported_symbol,_mexFunction" 989 # #-Wl,-exported_symbols_list,${_FindMatlab_SELF_DIR}/MatlabOSXVisilibity.map" 990 # ) 991 # endif() 992 993 994 995 set_target_properties(${${prefix}_NAME} 996 PROPERTIES 997 DEFINE_SYMBOL "DLL_EXPORT_SYM=__attribute__ ((visibility (\"default\")))" 998 ) 999 1000 1001 endif() 1002 1003endfunction() 1004 1005 1006# (internal) 1007# Used to get the version of matlab, using caching. This basically transforms the 1008# output of the root list, with possible unknown version, to a version 1009# 1010function(_Matlab_get_version_from_root matlab_root matlab_known_version matlab_final_version) 1011 1012 # if the version is not trivial, we query matlab for that 1013 # we keep track of the location of matlab that induced this version 1014 #if(NOT DEFINED Matlab_PROG_VERSION_STRING_AUTO_DETECT) 1015 # set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version") 1016 #endif() 1017 1018 if(NOT ${matlab_known_version} STREQUAL "NOTFOUND") 1019 # the version is known, we just return it 1020 set(${matlab_final_version} ${matlab_known_version} PARENT_SCOPE) 1021 set(Matlab_VERSION_STRING_INTERNAL ${matlab_known_version} CACHE INTERNAL "Matlab version (automatically determined)" FORCE) 1022 return() 1023 endif() 1024 1025 # 1026 set(_matlab_current_program ${Matlab_MAIN_PROGRAM}) 1027 1028 # do we already have a matlab program? 1029 if(NOT _matlab_current_program) 1030 1031 set(_find_matlab_options) 1032 if(matlab_root AND EXISTS ${matlab_root}) 1033 set(_find_matlab_options PATHS ${matlab_root} ${matlab_root}/bin NO_DEFAULT_PATH) 1034 endif() 1035 1036 find_program( 1037 _matlab_current_program 1038 matlab 1039 ${_find_matlab_options} 1040 DOC "Matlab main program" 1041 ) 1042 endif() 1043 1044 if(NOT _matlab_current_program OR NOT EXISTS ${_matlab_current_program}) 1045 # if not found, clear the dependent variables 1046 if(MATLAB_FIND_DEBUG) 1047 message(WARNING "[MATLAB] Cannot find the main matlab program under ${matlab_root}") 1048 endif() 1049 set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE) 1050 set(Matlab_VERSION_STRING_INTERNAL "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE) 1051 unset(_matlab_current_program) 1052 unset(_matlab_current_program CACHE) 1053 return() 1054 endif() 1055 1056 # full real path for path comparison 1057 get_filename_component(_matlab_main_real_path_tmp "${_matlab_current_program}" REALPATH) 1058 unset(_matlab_current_program) 1059 unset(_matlab_current_program CACHE) 1060 1061 # is it the same as the previous one? 1062 if(_matlab_main_real_path_tmp STREQUAL Matlab_PROG_VERSION_STRING_AUTO_DETECT) 1063 set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE) 1064 return() 1065 endif() 1066 1067 # update the location of the program 1068 set(Matlab_PROG_VERSION_STRING_AUTO_DETECT ${_matlab_main_real_path_tmp} CACHE INTERNAL "internal matlab location for the discovered version" FORCE) 1069 1070 set(matlab_list_of_all_versions) 1071 matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions) 1072 1073 list(LENGTH matlab_list_of_all_versions list_of_all_versions_length) 1074 if(${list_of_all_versions_length} GREATER 0) 1075 list(GET matlab_list_of_all_versions 0 _matlab_version_tmp) 1076 else() 1077 set(_matlab_version_tmp "unknown") 1078 endif() 1079 1080 # set the version into the cache 1081 set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)" FORCE) 1082 1083 # warning, just in case several versions found (should not happen) 1084 if((${list_of_all_versions_length} GREATER 1) AND MATLAB_FIND_DEBUG) 1085 message(WARNING "[MATLAB] Found several versions, taking the first one (versions found ${matlab_list_of_all_versions})") 1086 endif() 1087 1088 # return the updated value 1089 set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE) 1090 1091endfunction() 1092 1093 1094 1095 1096 1097 1098 1099# ################################### 1100# Exploring the possible Matlab_ROOTS 1101 1102# this variable will get all Matlab installations found in the current system. 1103set(_matlab_possible_roots) 1104 1105 1106 1107if(Matlab_ROOT_DIR) 1108 # if the user specifies a possible root, we keep this one 1109 1110 if(NOT EXISTS ${Matlab_ROOT_DIR}) 1111 # if Matlab_ROOT_DIR specified but erroneous 1112 if(MATLAB_FIND_DEBUG) 1113 message(WARNING "[MATLAB] the specified path for Matlab_ROOT_DIR does not exist (${Matlab_ROOT_DIR})") 1114 endif() 1115 else() 1116 # NOTFOUND indicates the code below to search for the version automatically 1117 if("${Matlab_VERSION_STRING_INTERNAL}" STREQUAL "") 1118 list(APPEND _matlab_possible_roots "NOTFOUND" ${Matlab_ROOT_DIR}) # empty version 1119 else() 1120 list(APPEND _matlab_possible_roots ${Matlab_VERSION_STRING_INTERNAL} ${Matlab_ROOT_DIR}) # cached version 1121 endif() 1122 endif() 1123 1124 1125else() 1126 1127 # if the user does not specify the possible installation root, we look for 1128 # one installation using the appropriate heuristics 1129 1130 if(WIN32) 1131 1132 # On WIN32, we look for Matlab installation in the registry 1133 # if unsuccessful, we look for all known revision and filter the existing 1134 # ones. 1135 1136 # testing if we are able to extract the needed information from the registry 1137 set(_matlab_versions_from_registry) 1138 1139 if(CMAKE_SIZEOF_VOID_P EQUAL 8) 1140 set(_matlab_win64 ON) 1141 else() 1142 set(_matlab_win64 OFF) 1143 endif() 1144 1145 matlab_extract_all_installed_versions_from_registry(_matlab_win64 _matlab_versions_from_registry) 1146 1147 # the returned list is empty, doing the search on all known versions 1148 if(NOT _matlab_versions_from_registry) 1149 1150 if(MATLAB_FIND_DEBUG) 1151 message(STATUS "[MATLAB] Search for Matlab from the registry unsuccessful, testing all supported versions") 1152 endif() 1153 1154 extract_matlab_versions_from_registry_brute_force(_matlab_versions_from_registry) 1155 endif() 1156 1157 # filtering the results with the registry keys 1158 matlab_get_all_valid_matlab_roots_from_registry("${_matlab_versions_from_registry}" _matlab_possible_roots) 1159 unset(_matlab_versions_from_registry) 1160 1161 elseif(APPLE) 1162 1163 # on mac, we look for the /Application paths 1164 # this corresponds to the behaviour on Windows. On Linux, we do not have 1165 # any other guess. 1166 matlab_get_supported_releases(_matlab_releases) 1167 if(MATLAB_FIND_DEBUG) 1168 message(STATUS "[MATLAB] Matlab supported versions ${_matlab_releases}. If more version should be supported " 1169 "the variable MATLAB_ADDITIONAL_VERSIONS can be set according to the documentation") 1170 endif() 1171 1172 foreach(_matlab_current_release IN LISTS _matlab_releases) 1173 set(_matlab_full_string "/Applications/MATLAB_${_matlab_current_release}.app") 1174 if(EXISTS ${_matlab_full_string}) 1175 set(_matlab_current_version) 1176 matlab_get_version_from_release_name("${_matlab_current_release}" _matlab_current_version) 1177 if(MATLAB_FIND_DEBUG) 1178 message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_full_string}") 1179 endif() 1180 list(APPEND _matlab_possible_roots ${_matlab_current_version} ${_matlab_full_string}) 1181 unset(_matlab_current_version) 1182 endif() 1183 1184 unset(_matlab_full_string) 1185 endforeach(_matlab_current_release) 1186 1187 unset(_matlab_current_release) 1188 unset(_matlab_releases) 1189 1190 endif() 1191 1192endif() 1193 1194 1195 1196list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots) 1197if(_numbers_of_matlab_roots EQUAL 0) 1198 # if we have not found anything, we fall back on the PATH 1199 1200 1201 # At this point, we have no other choice than trying to find it from PATH. 1202 # If set by the user, this wont change 1203 find_program( 1204 _matlab_main_tmp 1205 NAMES matlab) 1206 1207 1208 if(_matlab_main_tmp) 1209 # we then populate the list of roots, with empty version 1210 if(MATLAB_FIND_DEBUG) 1211 message(STATUS "[MATLAB] matlab found from PATH: ${_matlab_main_tmp}") 1212 endif() 1213 1214 # resolve symlinks 1215 get_filename_component(_matlab_current_location "${_matlab_main_tmp}" REALPATH) 1216 1217 # get the directory (the command below has to be run twice) 1218 # this will be the matlab root 1219 get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY) 1220 get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY) # Matlab should be in bin 1221 1222 list(APPEND _matlab_possible_roots "NOTFOUND" ${_matlab_current_location}) 1223 1224 unset(_matlab_current_location) 1225 1226 endif() 1227 unset(_matlab_main_tmp CACHE) 1228 1229endif() 1230 1231 1232 1233 1234 1235if(MATLAB_FIND_DEBUG) 1236 message(STATUS "[MATLAB] Matlab root folders are ${_matlab_possible_roots}") 1237endif() 1238 1239 1240 1241 1242 1243# take the first possible Matlab root 1244list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots) 1245set(Matlab_VERSION_STRING "NOTFOUND") 1246if(_numbers_of_matlab_roots GREATER 0) 1247 list(GET _matlab_possible_roots 0 Matlab_VERSION_STRING) 1248 list(GET _matlab_possible_roots 1 Matlab_ROOT_DIR) 1249 1250 # adding a warning in case of ambiguity 1251 if(_numbers_of_matlab_roots GREATER 2 AND MATLAB_FIND_DEBUG) 1252 message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})." 1253 " If this is not the desired behaviour, provide the -DMatlab_ROOT_DIR=... on the command line") 1254 endif() 1255endif() 1256 1257 1258# check if the root changed wrt. the previous defined one, if so 1259# clear all the cached variables for being able to reconfigure properly 1260if(DEFINED Matlab_ROOT_DIR_LAST_CACHED) 1261 1262 if(NOT Matlab_ROOT_DIR_LAST_CACHED STREQUAL Matlab_ROOT_DIR) 1263 set(_Matlab_cached_vars 1264 Matlab_INCLUDE_DIRS 1265 Matlab_MEX_LIBRARY 1266 Matlab_MEX_COMPILER 1267 Matlab_MAIN_PROGRAM 1268 Matlab_MX_LIBRARY 1269 Matlab_ENG_LIBRARY 1270 Matlab_MAT_LIBRARY 1271 Matlab_MEX_EXTENSION 1272 Matlab_SIMULINK_INCLUDE_DIR 1273 1274 # internal 1275 Matlab_MEXEXTENSIONS_PROG 1276 Matlab_ROOT_DIR_LAST_CACHED 1277 #Matlab_PROG_VERSION_STRING_AUTO_DETECT 1278 Matlab_VERSION_STRING_INTERNAL 1279 ) 1280 foreach(_var IN LISTS _Matlab_cached_vars) 1281 if(DEFINED ${_var}) 1282 unset(${_var} CACHE) 1283 endif() 1284 endforeach() 1285 endif() 1286endif() 1287 1288set(Matlab_ROOT_DIR_LAST_CACHED ${Matlab_ROOT_DIR} CACHE INTERNAL "last Matlab root dir location") 1289set(Matlab_ROOT_DIR ${Matlab_ROOT_DIR} CACHE PATH "Matlab installation root path" FORCE) 1290 1291# Fix the version, in case this one is NOTFOUND 1292_Matlab_get_version_from_root( 1293 "${Matlab_ROOT_DIR}" 1294 ${Matlab_VERSION_STRING} 1295 Matlab_VERSION_STRING 1296) 1297 1298 1299 1300 1301if(MATLAB_FIND_DEBUG) 1302 message(STATUS "[MATLAB] Current version is ${Matlab_VERSION_STRING} located ${Matlab_ROOT_DIR}") 1303endif() 1304 1305 1306 1307if(Matlab_ROOT_DIR) 1308 file(TO_CMAKE_PATH ${Matlab_ROOT_DIR} Matlab_ROOT_DIR) 1309endif() 1310 1311if(CMAKE_SIZEOF_VOID_P EQUAL 4) 1312 set(_matlab_64Build FALSE) 1313else() 1314 set(_matlab_64Build TRUE) 1315endif() 1316 1317if(APPLE) 1318 set(_matlab_bin_prefix "mac") # i should be for intel 1319 set(_matlab_bin_suffix_32bits "i") 1320 set(_matlab_bin_suffix_64bits "i64") 1321elseif(UNIX) 1322 set(_matlab_bin_prefix "gln") 1323 set(_matlab_bin_suffix_32bits "x86") 1324 set(_matlab_bin_suffix_64bits "xa64") 1325else() 1326 set(_matlab_bin_prefix "win") 1327 set(_matlab_bin_suffix_32bits "32") 1328 set(_matlab_bin_suffix_64bits "64") 1329endif() 1330 1331 1332 1333set(MATLAB_INCLUDE_DIR_TO_LOOK ${Matlab_ROOT_DIR}/extern/include) 1334if(_matlab_64Build) 1335 set(_matlab_current_suffix ${_matlab_bin_suffix_64bits}) 1336else() 1337 set(_matlab_current_suffix ${_matlab_bin_suffix_32bits}) 1338endif() 1339 1340set(Matlab_BINARIES_DIR 1341 ${Matlab_ROOT_DIR}/bin/${_matlab_bin_prefix}${_matlab_current_suffix}) 1342set(Matlab_EXTERN_LIBRARY_DIR 1343 ${Matlab_ROOT_DIR}/extern/lib/${_matlab_bin_prefix}${_matlab_current_suffix}) 1344 1345if(WIN32) 1346 if(MINGW) 1347 set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/mingw64) 1348 else() 1349 set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/microsoft) 1350 endif() 1351 set(_matlab_lib_prefix_for_search "lib") 1352else() 1353 set(_matlab_lib_dir_for_search ${Matlab_BINARIES_DIR}) 1354 set(_matlab_lib_prefix_for_search "lib") 1355endif() 1356 1357unset(_matlab_64Build) 1358 1359 1360if(NOT DEFINED Matlab_MEX_EXTENSION) 1361 set(_matlab_mex_extension "") 1362 matlab_get_mex_suffix("${Matlab_ROOT_DIR}" _matlab_mex_extension) 1363 1364 # This variable goes to the cache. 1365 set(Matlab_MEX_EXTENSION ${_matlab_mex_extension} CACHE STRING "Extensions for the mex targets (automatically given by Matlab)") 1366 unset(_matlab_mex_extension) 1367endif() 1368 1369 1370if(MATLAB_FIND_DEBUG) 1371 message(STATUS "[MATLAB] [DEBUG]_matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}") 1372endif() 1373 1374 1375 1376# internal 1377# This small stub around find_library is to prevent any pollution of CMAKE_FIND_LIBRARY_PREFIXES in the global scope. 1378# This is the function to be used below instead of the find_library directives. 1379function(_Matlab_find_library _matlab_library_prefix) 1380 set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} ${_matlab_library_prefix}) 1381 find_library(${ARGN}) 1382endfunction() 1383 1384 1385set(_matlab_required_variables) 1386 1387 1388# the MEX library/header are required 1389find_path( 1390 Matlab_INCLUDE_DIRS 1391 mex.h 1392 PATHS ${MATLAB_INCLUDE_DIR_TO_LOOK} 1393 NO_DEFAULT_PATH 1394 ) 1395list(APPEND _matlab_required_variables Matlab_INCLUDE_DIRS) 1396 1397_Matlab_find_library( 1398 ${_matlab_lib_prefix_for_search} 1399 Matlab_MEX_LIBRARY 1400 mex 1401 PATHS ${_matlab_lib_dir_for_search} 1402 NO_DEFAULT_PATH 1403) 1404 1405list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY) 1406 1407# the MEX extension is required 1408list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION) 1409 1410# the matlab root is required 1411list(APPEND _matlab_required_variables Matlab_ROOT_DIR) 1412 1413# component Mex Compiler 1414list(FIND Matlab_FIND_COMPONENTS MEX_COMPILER _matlab_find_mex_compiler) 1415if(_matlab_find_mex_compiler GREATER -1) 1416 find_program( 1417 Matlab_MEX_COMPILER 1418 "mex" 1419 PATHS ${Matlab_BINARIES_DIR} 1420 DOC "Matlab MEX compiler" 1421 NO_DEFAULT_PATH 1422 ) 1423 if(Matlab_MEX_COMPILER) 1424 set(Matlab_MEX_COMPILER_FOUND TRUE) 1425 endif() 1426endif() 1427unset(_matlab_find_mex_compiler) 1428 1429# component Matlab program 1430list(FIND Matlab_FIND_COMPONENTS MAIN_PROGRAM _matlab_find_matlab_program) 1431if(_matlab_find_matlab_program GREATER -1) 1432 find_program( 1433 Matlab_MAIN_PROGRAM 1434 matlab 1435 PATHS ${Matlab_ROOT_DIR} ${Matlab_ROOT_DIR}/bin 1436 DOC "Matlab main program" 1437 NO_DEFAULT_PATH 1438 ) 1439 if(Matlab_MAIN_PROGRAM) 1440 set(Matlab_MAIN_PROGRAM_FOUND TRUE) 1441 endif() 1442endif() 1443unset(_matlab_find_matlab_program) 1444 1445# Component MX library 1446list(FIND Matlab_FIND_COMPONENTS MX_LIBRARY _matlab_find_mx) 1447if(_matlab_find_mx GREATER -1) 1448 _Matlab_find_library( 1449 ${_matlab_lib_prefix_for_search} 1450 Matlab_MX_LIBRARY 1451 mx 1452 PATHS ${_matlab_lib_dir_for_search} 1453 NO_DEFAULT_PATH 1454 ) 1455 if(Matlab_MX_LIBRARY) 1456 set(Matlab_MX_LIBRARY_FOUND TRUE) 1457 endif() 1458endif() 1459unset(_matlab_find_mx) 1460 1461# Component ENG library 1462list(FIND Matlab_FIND_COMPONENTS ENG_LIBRARY _matlab_find_eng) 1463if(_matlab_find_eng GREATER -1) 1464 _Matlab_find_library( 1465 ${_matlab_lib_prefix_for_search} 1466 Matlab_ENG_LIBRARY 1467 eng 1468 PATHS ${_matlab_lib_dir_for_search} 1469 NO_DEFAULT_PATH 1470 ) 1471 if(Matlab_ENG_LIBRARY) 1472 set(Matlab_ENG_LIBRARY_FOUND TRUE) 1473 endif() 1474endif() 1475unset(_matlab_find_eng) 1476 1477# Component MAT library 1478list(FIND Matlab_FIND_COMPONENTS MAT_LIBRARY _matlab_find_mat) 1479if(_matlab_find_mat GREATER -1) 1480 _Matlab_find_library( 1481 ${_matlab_lib_prefix_for_search} 1482 Matlab_MAT_LIBRARY 1483 mat 1484 PATHS ${_matlab_lib_dir_for_search} 1485 NO_DEFAULT_PATH 1486 ) 1487 if(Matlab_MAT_LIBRARY) 1488 set(Matlab_MAT_LIBRARY_FOUND TRUE) 1489 endif() 1490endif() 1491unset(_matlab_find_mat) 1492 1493# Component Simulink 1494list(FIND Matlab_FIND_COMPONENTS SIMULINK _matlab_find_simulink) 1495if(_matlab_find_simulink GREATER -1) 1496 find_path( 1497 Matlab_SIMULINK_INCLUDE_DIR 1498 simstruc.h 1499 PATHS "${Matlab_ROOT_DIR}/simulink/include" 1500 NO_DEFAULT_PATH 1501 ) 1502 if(Matlab_SIMULINK_INCLUDE_DIR) 1503 set(Matlab_SIMULINK_FOUND TRUE) 1504 list(APPEND Matlab_INCLUDE_DIRS "${Matlab_SIMULINK_INCLUDE_DIR}") 1505 endif() 1506endif() 1507unset(_matlab_find_simulink) 1508 1509unset(_matlab_lib_dir_for_search) 1510 1511set(Matlab_LIBRARIES ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY}) 1512 1513find_package_handle_standard_args( 1514 Matlab 1515 FOUND_VAR Matlab_FOUND 1516 REQUIRED_VARS ${_matlab_required_variables} 1517 VERSION_VAR Matlab_VERSION_STRING 1518 HANDLE_COMPONENTS) 1519 1520unset(_matlab_required_variables) 1521unset(_matlab_bin_prefix) 1522unset(_matlab_bin_suffix_32bits) 1523unset(_matlab_bin_suffix_64bits) 1524unset(_matlab_current_suffix) 1525unset(_matlab_lib_dir_for_search) 1526unset(_matlab_lib_prefix_for_search) 1527 1528if(Matlab_INCLUDE_DIRS AND Matlab_LIBRARIES) 1529 mark_as_advanced( 1530 Matlab_MEX_LIBRARY 1531 Matlab_MX_LIBRARY 1532 Matlab_ENG_LIBRARY 1533 Matlab_MAT_LIBRARY 1534 Matlab_INCLUDE_DIRS 1535 Matlab_FOUND 1536 Matlab_MAIN_PROGRAM 1537 Matlab_MEXEXTENSIONS_PROG 1538 Matlab_MEX_EXTENSION 1539 ) 1540endif() 1541