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)
|
||||
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)
|
||||
if(GTK2_FOUND)
|
||||
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()
|
||||
|
||||
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