FindMatlab: Rewrite module and provide a usage API
Implement a brand new FindMatlab module: - Add support for versions and components. - Find Matlab and its version in a more precise and multiplatform way. - Add API to create a new mex extension with documentation. - Add API to add matlab unit tests (with or without the unit test framework). - Find as much as possible based on a single Matlab_ROOT_DIR cache entry and allow the user to change it to re-find everything.
This commit is contained in:
parent
6390d5f5cb
commit
49c8dcf7bb
|
@ -0,0 +1,7 @@
|
||||||
|
FindMatlab-rewrite
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The :module:`FindMatlab` module was completely rewritten. It learned
|
||||||
|
about versions and components and to find Matlab in a more precise and
|
||||||
|
multiplatform way. The module now offers APIs to create mex extensions,
|
||||||
|
documentation, and unit tests.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,92 @@
|
||||||
|
# This is an undocumented internal helper for the FindMatlab
|
||||||
|
# module ``matlab_add_unit_test`` command.
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# Copyright 2014-2015 Raffi Enficiaud, Max Planck Society
|
||||||
|
#
|
||||||
|
# Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
# see accompanying file Copyright.txt for details.
|
||||||
|
#
|
||||||
|
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the License for more information.
|
||||||
|
#=============================================================================
|
||||||
|
# (To distribute this file outside of CMake, substitute the full
|
||||||
|
# License text for the above reference.)
|
||||||
|
|
||||||
|
|
||||||
|
# Usage: cmake
|
||||||
|
# -Dtest_timeout=180
|
||||||
|
# -Dworking_directory="."
|
||||||
|
# -Doutput_directory=
|
||||||
|
# -Dadditional_paths=""
|
||||||
|
# -Dno_unittest_framework=""
|
||||||
|
# -DMatlab_PROGRAM=matlab_exe_location
|
||||||
|
# -DMatlab_ADDITIONNAL_STARTUP_OPTIONS=""
|
||||||
|
# -Dtest_name=name_of_the_test
|
||||||
|
# -Dcmd_to_run_before_test=""
|
||||||
|
# -Dunittest_file_to_run
|
||||||
|
# -P FindMatlab_TestsRedirect.cmake
|
||||||
|
|
||||||
|
set(Matlab_UNIT_TESTS_CMD -nosplash -nojvm -nodesktop -nodisplay ${Matlab_ADDITIONNAL_STARTUP_OPTIONS})
|
||||||
|
if(WIN32)
|
||||||
|
set(Matlab_UNIT_TESTS_CMD ${Matlab_UNIT_TESTS_CMD} -wait)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT test_timeout)
|
||||||
|
set(test_timeout 180)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT cmd_to_run_before_test)
|
||||||
|
set(cmd_to_run_before_test)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_filename_component(unittest_file_directory "${unittest_file_to_run}" DIRECTORY)
|
||||||
|
get_filename_component(unittest_file_to_run_name "${unittest_file_to_run}" NAME_WE)
|
||||||
|
|
||||||
|
set(concat_string '${unittest_file_directory}')
|
||||||
|
foreach(s IN LISTS additional_paths)
|
||||||
|
if(NOT "${s}" STREQUAL "")
|
||||||
|
set(concat_string "${concat_string}, '${s}'")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(unittest_to_run "runtests('${unittest_file_to_run_name}'), exit(max([ans(1,:).Failed]))")
|
||||||
|
if(no_unittest_framework)
|
||||||
|
set(unittest_to_run "try, ${unittest_file_to_run_name}, catch err, disp('An exception has been thrown during the execution'), disp(err), disp(err.stack), exit(1), end, exit(0)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(Matlab_SCRIPT_TO_RUN
|
||||||
|
"addpath(${concat_string}), path, ${cmd_to_run_before_test}, ${unittest_to_run}"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(Matlab_LOG_FILE "${output_directory}/${test_name}.log")
|
||||||
|
|
||||||
|
set(devnull)
|
||||||
|
if(UNIX)
|
||||||
|
set(devnull INPUT_FILE /dev/null)
|
||||||
|
elseif(WIN32)
|
||||||
|
set(devnull INPUT_FILE NUL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${Matlab_PROGRAM}" ${Matlab_UNIT_TESTS_CMD} -logfile "${test_name}.log" -r "${Matlab_SCRIPT_TO_RUN}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
TIMEOUT ${test_timeout}
|
||||||
|
OUTPUT_QUIET # we do not want the output twice
|
||||||
|
WORKING_DIRECTORY "${output_directory}"
|
||||||
|
${devnull}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT EXISTS ${Matlab_LOG_FILE})
|
||||||
|
message( FATAL_ERROR "[MATLAB] ERROR: cannot find the log file ${Matlab_LOG_FILE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# print the output in any case.
|
||||||
|
file(READ ${Matlab_LOG_FILE} matlab_log_content)
|
||||||
|
message("Matlab test ${name_of_the_test} output:\n${matlab_log_content}") # if we put FATAL_ERROR here, the file is indented.
|
||||||
|
|
||||||
|
|
||||||
|
if(NOT (res EQUAL 0))
|
||||||
|
message( FATAL_ERROR "[MATLAB] TEST FAILED" )
|
||||||
|
endif()
|
|
@ -1256,6 +1256,12 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
|
||||||
add_subdirectory(FindJsonCpp)
|
add_subdirectory(FindJsonCpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Matlab module
|
||||||
|
if(CMake_TEST_FindMatlab)
|
||||||
|
ADD_TEST_MACRO(FindMatlab.basic_checks ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>)
|
||||||
|
ADD_TEST_MACRO(FindMatlab.versions_checks ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(GTK2 QUIET)
|
find_package(GTK2 QUIET)
|
||||||
if(GTK2_FOUND)
|
if(GTK2_FOUND)
|
||||||
add_subdirectory(FindGTK2)
|
add_subdirectory(FindGTK2)
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
cmake_minimum_required (VERSION 2.8.12)
|
||||||
|
enable_testing()
|
||||||
|
project(basic_checks)
|
||||||
|
|
||||||
|
set(MATLAB_FIND_DEBUG TRUE)
|
||||||
|
|
||||||
|
# the success of the following command is dependent on the current configuration:
|
||||||
|
# - on 32bits builds (cmake is building with 32 bits), it looks for 32 bits Matlab
|
||||||
|
# - on 64bits builds (cmake is building with 64 bits), it looks for 64 bits Matlab
|
||||||
|
find_package(Matlab REQUIRED COMPONENTS MX_LIBRARY MAIN_PROGRAM)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
matlab_add_mex(
|
||||||
|
# target name
|
||||||
|
NAME cmake_matlab_test_wrapper1
|
||||||
|
# output name
|
||||||
|
OUTPUT_NAME cmake_matlab_mex1
|
||||||
|
SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper1.cpp
|
||||||
|
DOCUMENTATION ${CMAKE_CURRENT_SOURCE_DIR}/../help_text1.m.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
matlab_add_unit_test(
|
||||||
|
NAME ${PROJECT_NAME}_matlabtest-1
|
||||||
|
TIMEOUT 30
|
||||||
|
UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests1.m
|
||||||
|
ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
|
||||||
|
)
|
||||||
|
|
||||||
|
matlab_add_unit_test(
|
||||||
|
NAME ${PROJECT_NAME}_matlabtest-2
|
||||||
|
TIMEOUT 15
|
||||||
|
UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests_timeout.m
|
||||||
|
ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
|
||||||
|
)
|
||||||
|
set_tests_properties(${PROJECT_NAME}_matlabtest-2 PROPERTIES WILL_FAIL TRUE)
|
||||||
|
|
||||||
|
|
||||||
|
# testing the test without the unittest framework of Matlab
|
||||||
|
matlab_add_unit_test(
|
||||||
|
NAME ${PROJECT_NAME}_matlabtest-3
|
||||||
|
TIMEOUT 30
|
||||||
|
NO_UNITTEST_FRAMEWORK
|
||||||
|
UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests2.m
|
||||||
|
ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
|
||||||
|
)
|
||||||
|
|
||||||
|
matlab_add_unit_test(
|
||||||
|
NAME ${PROJECT_NAME}_matlabtest-4
|
||||||
|
TIMEOUT 30
|
||||||
|
NO_UNITTEST_FRAMEWORK
|
||||||
|
UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests3.m
|
||||||
|
ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
|
||||||
|
)
|
||||||
|
set_tests_properties(${PROJECT_NAME}_matlabtest-4 PROPERTIES WILL_FAIL TRUE)
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
classdef cmake_matlab_unit_tests1 < matlab.unittest.TestCase
|
||||||
|
% some simple unit test for CMake Matlab wrapper
|
||||||
|
properties
|
||||||
|
end
|
||||||
|
|
||||||
|
methods (Test)
|
||||||
|
function testDummyCall(testCase)
|
||||||
|
% very simple call test
|
||||||
|
cmake_matlab_mex1(rand(3,3));
|
||||||
|
end
|
||||||
|
|
||||||
|
function testDummyCall2(testCase)
|
||||||
|
% very simple call test 2
|
||||||
|
ret = cmake_matlab_mex1(rand(3,3));
|
||||||
|
testCase.verifyEqual(size(ret), size(rand(3,3)));
|
||||||
|
|
||||||
|
testCase.verifyEqual(size(cmake_matlab_mex1(rand(4,3))), [4,3] );
|
||||||
|
end
|
||||||
|
|
||||||
|
function testFailTest(testCase)
|
||||||
|
testCase.verifyError(@() cmake_matlab_mex1(10), 'cmake_matlab:configuration');
|
||||||
|
testCase.verifyError(@() cmake_matlab_mex1([10]), 'cmake_matlab:configuration');
|
||||||
|
end
|
||||||
|
|
||||||
|
function testHelpContent(testCase)
|
||||||
|
% testing the help feature
|
||||||
|
testCase.verifySubstring(evalc('help cmake_matlab_mex1'), 'Dummy matlab extension in cmake');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
ret = cmake_matlab_mex1(rand(3,3));
|
||||||
|
|
||||||
|
if(size(ret) ~= size(rand(3,3)))
|
||||||
|
error('Dimension mismatch!');
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
cmake_matlab_mex1(10);
|
||||||
|
|
||||||
|
% should not reach this point
|
||||||
|
exit(0);
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
classdef cmake_matlab_unit_tests_timeout < matlab.unittest.TestCase
|
||||||
|
% timeout tests
|
||||||
|
|
||||||
|
properties
|
||||||
|
end
|
||||||
|
|
||||||
|
methods (Test)
|
||||||
|
function testCallHangsShouldBeTimedOut(testCase)
|
||||||
|
cmake_matlab_mex1(rand(3,3));
|
||||||
|
disp('Will now wait.');
|
||||||
|
disp('Testing the cmake Matlab package timeout - do not kill');
|
||||||
|
pause(20); % supposed to be killed after 15s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,2 @@
|
||||||
|
% Dummy matlab extension in cmake
|
||||||
|
function ret = cmake_matlab_mex1(X)
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
// simple workaround to some compiler specific problems
|
||||||
|
// see http://stackoverflow.com/questions/22367516/mex-compile-error-unknown-type-name-char16-t/23281916#23281916
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "mex.h"
|
||||||
|
|
||||||
|
// this test should return a matrix of 10 x 10 and should check some of the arguments
|
||||||
|
|
||||||
|
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[])
|
||||||
|
{
|
||||||
|
if(nrhs != 1)
|
||||||
|
{
|
||||||
|
mexErrMsgTxt("Incorrect arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dim1 = mxGetM(prhs[0]);
|
||||||
|
size_t dim2 = mxGetN(prhs[0]);
|
||||||
|
|
||||||
|
if(dim1 == 1 || dim2 == 1)
|
||||||
|
{
|
||||||
|
mexErrMsgIdAndTxt("cmake_matlab:configuration", "Incorrect arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
plhs[0] = mxCreateNumericMatrix(dim1, dim2, mxGetClassID(prhs[0]), mxREAL);
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
cmake_minimum_required (VERSION 2.8.12)
|
||||||
|
enable_testing()
|
||||||
|
project(versions_checks)
|
||||||
|
|
||||||
|
set(MATLAB_FIND_DEBUG TRUE)
|
||||||
|
set(MATLAB_ADDITIONAL_VERSIONS
|
||||||
|
"dummy=14.9")
|
||||||
|
|
||||||
|
# the success of the following command is dependent on the current configuration
|
||||||
|
# in this case, we are only interested in the version macros
|
||||||
|
find_package(Matlab)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(NOT COMMAND matlab_get_version_from_release_name)
|
||||||
|
message(FATAL_ERROR "The macro matlab_get_version_from_release_name should be defined")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT COMMAND matlab_get_release_name_from_version)
|
||||||
|
message(FATAL_ERROR "The macro matlab_get_release_name_from_version should be defined")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# matlab_get_release_name_from_version
|
||||||
|
matlab_get_release_name_from_version("7.13" release_name)
|
||||||
|
if(NOT release_name STREQUAL "R2011b")
|
||||||
|
message(FATAL_ERROR "version 7.13 does not give release R2011b : '${release_name}' != R2011b")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
matlab_get_release_name_from_version("14.9" release_name)
|
||||||
|
if(NOT release_name STREQUAL "dummy")
|
||||||
|
message(FATAL_ERROR "version 14.9 does not give release dummy : '${release_name}' != dummy")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
matlab_get_release_name_from_version("14.10" release_name)
|
||||||
|
if(NOT release_name STREQUAL "")
|
||||||
|
message(FATAL_ERROR "version 14.10 does not give empty release: '${release_name}' != ''")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# matlab_get_version_from_release_name
|
||||||
|
matlab_get_version_from_release_name("R2011a" version)
|
||||||
|
if(NOT version STREQUAL "7.12")
|
||||||
|
message(FATAL_ERROR "Release R2011a does not give version 7.12 : '${version}' != 7.12")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
matlab_get_version_from_release_name("dummy" version)
|
||||||
|
#message(FATAL_ERROR "versionversion = ${version}")
|
||||||
|
if(NOT version STREQUAL "14.9")
|
||||||
|
message(FATAL_ERROR "Release dummy does not give version 14.9 : '${version}' != 14.9")
|
||||||
|
endif()
|
|
@ -211,3 +211,8 @@ if(RPMBUILD_EXECUTABLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_RunCMake_test(COMPILE_LANGUAGE-genex)
|
add_RunCMake_test(COMPILE_LANGUAGE-genex)
|
||||||
|
|
||||||
|
# Matlab module related tests
|
||||||
|
if(CMake_TEST_FindMatlab)
|
||||||
|
add_RunCMake_test(FindMatlab)
|
||||||
|
endif()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
include(${RunCMake_TEST}.cmake)
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,2 @@
|
||||||
|
CMake Error at .*FindMatlab.cmake:[0-9]+ \(message\):
|
||||||
|
\[MATLAB\] This functionality needs the MAIN_PROGRAM component \(not default\)
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
cmake_minimum_required (VERSION 2.8.12)
|
||||||
|
enable_testing()
|
||||||
|
project(test_should_fail)
|
||||||
|
|
||||||
|
find_package(Matlab REQUIRED COMPONENTS MX_LIBRARY)
|
||||||
|
|
||||||
|
matlab_add_mex(
|
||||||
|
# target name
|
||||||
|
NAME cmake_matlab_test_wrapper1
|
||||||
|
# output name
|
||||||
|
OUTPUT_NAME cmake_matlab_mex1
|
||||||
|
SRC ${CMAKE_CURRENT_SOURCE_DIR}/matlab_wrapper1.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# this command should raise a FATAL_ERROR, component MAIN_PROGRAM is missing
|
||||||
|
matlab_add_unit_test(
|
||||||
|
NAME ${PROJECT_NAME}_matlabtest-1
|
||||||
|
TIMEOUT 1
|
||||||
|
UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake_matlab_unit_tests2.m
|
||||||
|
ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
|
||||||
|
)
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
include(RunCMake)
|
||||||
|
run_cmake(MatlabTest1)
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
ret = cmake_matlab_mex1(rand(3,3));
|
||||||
|
|
||||||
|
if(size(ret) ~= size(rand(3,3)))
|
||||||
|
error('Dimension mismatch!');
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
// simple workaround to some compiler specific problems
|
||||||
|
// see http://stackoverflow.com/questions/22367516/mex-compile-error-unknown-type-name-char16-t/23281916#23281916
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "mex.h"
|
||||||
|
|
||||||
|
// this test should return a matrix of 10 x 10 and should check some of the arguments
|
||||||
|
|
||||||
|
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[])
|
||||||
|
{
|
||||||
|
if(nrhs != 1)
|
||||||
|
{
|
||||||
|
mexErrMsgTxt("Incorrect arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dim1 = mxGetM(prhs[0]);
|
||||||
|
size_t dim2 = mxGetN(prhs[0]);
|
||||||
|
|
||||||
|
if(dim1 == 1 || dim2 == 1)
|
||||||
|
{
|
||||||
|
mexErrMsgIdAndTxt("cmake_matlab:configuration", "Incorrect arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
plhs[0] = mxCreateNumericMatrix(dim1, dim2, mxGetClassID(prhs[0]), mxREAL);
|
||||||
|
}
|
Loading…
Reference in New Issue