diff --git a/CMakeLists.txt b/CMakeLists.txt index 60ee6785b8..fed2bf9df3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.29) set(Horace_ROOT ${CMAKE_CURRENT_LIST_DIR}) file(READ "${Horace_ROOT}/VERSION" _version) @@ -66,7 +66,7 @@ include(PACE_FindMatlab) # message(" MATLAB CURRENT VERSION: ${MATLAB_CURRENT_VERSION}") set(BUILD_HDF_MEX_PLUGIN TRUE) -if ((${MATLAB_CURRENT_VERSION} VERSION_LESS "7.11") OR (${MATLAB_CURRENT_VERSION} VERSION_GREATER "9.4")) +if ((${MATLAB_CURRENT_VERSION} VERSION_LESS_EQUAL "7.11") OR (${MATLAB_CURRENT_VERSION} VERSION_GREATER "9.4")) set(BUILD_HDF_MEX_PLUGIN FALSE) endif() @@ -75,7 +75,7 @@ include(PACE_AddMex) include(PACE_CodeAnalysis) include(PACE_Docs) if (${BUILD_HDF_MEX_PLUGIN}) - include(horace_FindHDF5) + include(horace_FindHDF5) endif() include(herbert_FindMPI) diff --git a/_LowLevelCode/cpp/bin_pixels_c/BinningArg.cpp b/_LowLevelCode/cpp/bin_pixels_c/BinningArg.cpp index c1cd17c95f..16491b71fc 100644 --- a/_LowLevelCode/cpp/bin_pixels_c/BinningArg.cpp +++ b/_LowLevelCode/cpp/bin_pixels_c/BinningArg.cpp @@ -264,7 +264,9 @@ void BinningArg::set_all_pix(mxArray const* const pField) auto data_type = mxGetClassID(a_cell_ptr); if (data_type != mxDOUBLE_CLASS) { std::stringstream buf; - buf << "Binning the data-type N " << data_type << " have not been implemented yet"; + buf << " Setting input pixel data to bin\n"; + buf << " Binning for input datatype N: " << data_type << " have not been implemented yet\n"; + buf << " You can bin datatype N " << mxDOUBLE_CLASS << " only"; mexErrMsgIdAndTxt("HORACE:bin_pixels_c:not_implemented", buf.str().c_str()); } @@ -417,6 +419,20 @@ void BinningArg::return_pix_img_idx(mxArray* pFieldName, mxArray* pFieldValue, i mxSetCell(pFieldValue, fld_idx, pix_img_idx); this->pix_img_idx_ptr = nullptr; }; +// return array of pixels indices, which specify position of pixels within image cell +void BinningArg::return_is_pix_selected(mxArray* pFieldName, mxArray* pFieldValue, int fld_idx, const std::string& field_name) +{ + mxSetCell(pFieldName, fld_idx, mxCreateString(field_name.c_str())); + mxArray* is_pix_selected(nullptr); + if (this->is_pix_selected_ptr) { + is_pix_selected = this->is_pix_selected_ptr; + } else { + is_pix_selected = mxCreateLogicalMatrix(0, 0); + } + mxSetCell(pFieldValue, fld_idx, is_pix_selected); + this->is_pix_selected_ptr = nullptr; +}; + //=================================================================================== // calculate steps used in binning over non-unit directions and numbers of these dimensions @@ -477,12 +493,21 @@ void BinningArg::register_output_methods() this->Mode6ParList = this->Mode5ParList; this->Mode6ParList["pix_img_idx"] = [this](mxArray* p1, mxArray* p2, int idx, const std::string& name) { this->return_pix_img_idx(p1, p2, idx, name); }; + this->Mode7ParList = this->Mode6ParList; + this->Mode7ParList["is_pix_selected"] = [this](mxArray* p1, mxArray* p2, int idx, const std::string& name) { this->return_is_pix_selected(p1, p2, idx, name); }; + + this->Mode8ParList = this->Mode0ParList; + this->Mode8ParList["is_pix_selected"] = [this](mxArray* p1, mxArray* p2, int idx, const std::string& name) { this->return_is_pix_selected(p1, p2, idx, name); }; + + this->out_handlers[opModes::npix_only] = &Mode0ParList; this->out_handlers[opModes::sig_err] = &Mode0ParList; this->out_handlers[opModes::sigerr_cell] = &Mode0ParList; this->out_handlers[opModes::sort_pix] = &Mode4ParList; this->out_handlers[opModes::sort_and_uid] = &Mode5ParList; this->out_handlers[opModes::nosort] = &Mode6ParList; + this->out_handlers[opModes::nosort_sel] = &Mode7ParList; + this->out_handlers[opModes::siger_selected] = &Mode8ParList; }; /** Parse input binning arguments and set new BinningArg from MATLAB input arguments * structure. @@ -715,6 +740,7 @@ void BinningArg::return_test_inputs(mxArray* plhs[], int nlhs) this->OutParList["pix_ok_data"] = [this](mxArray* p1, mxArray* p2, int idx, const std::string& name) { this->return_pix_ok_data(p1, p2, idx, name); }; this->OutParList["unique_runid"] = [this](mxArray* p1, mxArray* p2, int idx, const std::string& name) { this->return_unique_runid(p1, p2, idx, name); }; this->OutParList["pix_img_idx"] = [this](mxArray* p1, mxArray* p2, int idx, const std::string& name) { this->return_pix_img_idx(p1, p2, idx, name); }; + this->OutParList["is_pix_selected"] = [this](mxArray* p1, mxArray* p2, int idx, const std::string& name) { this->return_is_pix_selected(p1, p2, idx, name); }; /* ******************************************************************************** * retrieve binning parameters form BinningArg class and copy them into output array @@ -835,7 +861,7 @@ void BinningArg::check_and_init_accumulators(mxArray* plhs[], mxArray const* prh plhs[out_arg::Error] = this->error_ptr; } // pixels modes - if (this->binMode >= opModes::sort_pix) { + if (this->binMode >= opModes::sort_pix && this->binModen_data_points > this->pix_ok_bin_idx.size()) { this->pix_ok_bin_idx.resize(this->n_data_points); } @@ -928,6 +954,7 @@ BinningArg::BinningArg() , pix_data_range_ptr(nullptr) , pix_ok_ptr(nullptr) , pix_img_idx_ptr(nullptr) + , is_pix_selected_ptr(nullptr) { /* initialize input Matlab parameters map with methods which associate * Matlab field names with the methods, which set appropriate property value */ diff --git a/_LowLevelCode/cpp/bin_pixels_c/BinningArg.h b/_LowLevelCode/cpp/bin_pixels_c/BinningArg.h index 0dda904419..b03c3e1220 100644 --- a/_LowLevelCode/cpp/bin_pixels_c/BinningArg.h +++ b/_LowLevelCode/cpp/bin_pixels_c/BinningArg.h @@ -112,6 +112,8 @@ class BinningArg { mxArray* pix_ok_ptr; // pointer to array of all pixels retained after binning std::unordered_set unique_runID; // set containing unique run_id-s of the mxArray* pix_img_idx_ptr; // pointer to array of pixel indices within the image cell + mxArray* is_pix_selected_ptr; // pointer to logical array containing true where pixel + // was selected for binning and false otherwise // processed pixels //******************************************************************************** // helper values @@ -120,7 +122,7 @@ class BinningArg { std::vector stride; // vector, which describes binning steps reflecting multidimensional array strides std::vector bin_cell_idx_range; // vector containing allowed maximal indices of the binning (with nbins_all_dims>1) cells in binning directions // auxiliary array containing pixel indices over bins - std::vector pix_ok_bin_idx; + std::vector pix_ok_bin_idx; // auxiliary array defining ranges of the bins to sort pixels over std::vector npix_bin_start; std::vector npix1; // pixel distribution over bins calculated in single call to bin_pixels routine; @@ -155,7 +157,7 @@ class BinningArg { void set_alignment_matrix(mxArray const* const pField); // matrix which have to be applied to raw pixels to bring them into Crystal Cartesian coordinate system void set_check_pix_selection(mxArray const* const pField); // if true, check if detector_id are negative which may suggest that pixels have been alreary used in previous binning operation - // register with parameters map all methods which + // register with parameters map all methods which return variable results to MATLAB void register_output_methods(); // setters for binning results returned to MATLAB in output structure void return_npix_retained(mxArray* p1, mxArray* p2, int idx, const std::string& name); @@ -167,7 +169,9 @@ class BinningArg { void return_unique_runid(mxArray* p1, mxArray* p2, int idx, const std::string& name); // setter to return pixels indices within the image cell void return_pix_img_idx(mxArray* p1, mxArray* p2, int fld_idx, const std::string& name); - + // setter to return array containing true for selected pixels and false if they have not been selected + void return_is_pix_selected(mxArray* p1, mxArray* p2, int fld_idx, const std::string& name); + // public: BinningArg(); // construction // process binning arguments input values for new binning arguments cycle @@ -201,6 +205,8 @@ class BinningArg { OutHandlerMap Mode4ParList; OutHandlerMap Mode5ParList; OutHandlerMap Mode6ParList; + OutHandlerMap Mode7ParList; + OutHandlerMap Mode8ParList; std::unordered_map out_handlers; }; diff --git a/_LowLevelCode/cpp/bin_pixels_c/bin_pixels.h b/_LowLevelCode/cpp/bin_pixels_c/bin_pixels.h index 1742f68a86..e9a953766c 100644 --- a/_LowLevelCode/cpp/bin_pixels_c/bin_pixels.h +++ b/_LowLevelCode/cpp/bin_pixels_c/bin_pixels.h @@ -2,21 +2,20 @@ #include "BinningArg.h" #include -// use C-mutexes while binning the data -// #define C_MUTEXES - -/** return true if input coordinates lie outside of the ranges specified as input +/** Return true if input coordinates lie outside of the ranges specified as input. * -* Template can be instantiated for any input numerical types convertible to double +* Template can be instantiated for any input numerical types convertible to double. +* * Inputs: -* coord_ptr -- pointer to 2-Dimensional array of pixel coordinates allocated -* as 1-Dimensional FORTRAN array of COORD_STRIDE*Num_pixels size. -* where pixels coordinates are changed along first direction. +* coord_ptr -- pointer to the beginning of the area containing 2-Dimensional array +* of pixel coordinates allocated as 2-Dimensional MATLAB array of +* (COORD_STRIDE,Num_pixels) size with total size: COORD_STRIDE*Num_pixels. +* Pixels coordinates are changed along first direction. * i -- second index of the pixel array, indicating number of pixel to pick up * from pixels array * COORD_STRIDE -- size of the first dimension of the pixels array * cut_range -- 2*COORD_STRIDE array of pixel ranges to check. The ranges are -* arranged in 2-Dimensional array with FORTRAN allocation in the form: +* arranged in 2-Dimensional array with MATLAB allocation in the form: * [q1_min,q1_max,q2_min,q2_max,... q_COORD_STRIDE_min,q_COORD_STRIDE_max] * qi -- Output vector of input q-coordinates converted in double if all input coordinates are in range. Undefined if they are not @@ -27,8 +26,8 @@ * at least by 10% or even more. Difficult to judge properly, as code in this form would not compile * without inline. */ -template -bool inline out_of_ranges(TRG const* const coord_ptr, long i, size_t COORD_STRIDE, const std::vector& cut_range, std::vector& qi) +template +bool inline out_of_ranges(SRC const* const coord_ptr, long i, size_t COORD_STRIDE, const std::vector& cut_range, std::vector& qi) { size_t ic0 = i * COORD_STRIDE; for (size_t upix = 0; upix < COORD_STRIDE; upix++) { @@ -39,7 +38,7 @@ bool inline out_of_ranges(TRG const* const coord_ptr, long i, size_t COORD_STRID } return false; }; -/** identifies the image cell where the particular pixel belongs to +/** identifies 1D index of the image cell where the particular pixel belongs to * Inputs: * qi -- 1-dimensional vector of pixel coordinates to process * pax -- 1-to-4 elements vector of pixel indices accounted in binning. Indicates @@ -73,6 +72,80 @@ size_t inline pix_position(const std::vector& qi, const std::vector +size_t inline add_pix_to_accumulators(const SRC* pix_coord_ptr, size_t pix_in_pix_pos, + const std::vector& qi, const std::vector& pax, + const std::vector& cut_range, const std::vector& bin_step, + const std::vector& bin_cell_idx_range, const std::vector& stride, + std::span& npix, std::span& s, std::span& e) +{ + // calculate location of pixel within the image grid + auto il = pix_position(qi, pax, cut_range, bin_step, bin_cell_idx_range, stride); + // calculate npix accumulators + npix[il]++; + // calculate signal and error accumulators + s[il] += (double)pix_coord_ptr[pix_in_pix_pos + pix_flds::iSign]; + e[il] += (double)pix_coord_ptr[pix_in_pix_pos + pix_flds::iErr]; + + return il; +}; +// copy selected pixels from original array to the target array, containing only selected pixels +// pixels are not sorted and array of indices which correspond to pixels positions according +// to image is returned instead +template +void inline copy_resiults_to_final_arrays(BinningArg* const bin_par_ptr, const SRC* const pix_coord_ptr, + size_t data_size, size_t nPixel_retained, std::vector& pix_ok_bin_idx) +{ + // allocate memory for pixels to retain. + TRG* selected_pix_ptr(nullptr); // pointer to the actual data position. + bin_par_ptr->pix_ok_ptr = allocate_pix_memory(pix_flds::PIX_WIDTH, nPixel_retained, selected_pix_ptr); + // allocated memory for pixel indices + mxInt64* pix_img_idx_ptr(nullptr); + bin_par_ptr->pix_img_idx_ptr = allocate_pix_memory(nPixel_retained, 1, pix_img_idx_ptr); + std::span pix_img_idx(pix_img_idx_ptr, nPixel_retained); + + bool align_result = bin_par_ptr->alignment_matrix.size() == 9; + + // actually move pixels and copy indices the target array + size_t targ_pix_pos(0); + size_t targ_pix_array_pos(0); + for (size_t i = 0; i < data_size; i++) { + if (pix_ok_bin_idx[i] < 0) // drop pixels with have not been included above + continue; + + size_t il = (size_t)pix_ok_bin_idx[i]; // number of image cell pixel should go to + pix_img_idx[targ_pix_pos] = il + 1; // MATLB indices start from 1 and these -- from 0 + + if (align_result) { + // align q-coordinates and copy all other pixel data into the location requested + targ_pix_array_pos = align_and_copy_pixels(bin_par_ptr->alignment_matrix, pix_coord_ptr, i, selected_pix_ptr, targ_pix_pos); + } else { + // copy all pixel data into the location requested + targ_pix_array_pos = copy_pixels(pix_coord_ptr, i, selected_pix_ptr, targ_pix_pos); + } + // search for unique run_id; + bin_par_ptr->unique_runID.insert(uint32_t(selected_pix_ptr[targ_pix_array_pos + pix_flds::irun])); + + targ_pix_pos++; // move to the next pixel position within the target array + } +}; /** Procedure calculates positions of the input pixels coordinates within specified * image box and various other values related to distributions of pixels over the image @@ -117,8 +190,8 @@ size_t bin_pixels(std::span& npix, std::span& s, std::span pix_ranges; auto pix_range_ids = (bin_par_ptr->pix_data_range_ptr == nullptr) ? 0 : 2 * pix_flds::PIX_WIDTH; - if (bin_par_ptr->binMode > opModes::sigerr_cell && pix_range_ids > 0) { // higher modes process pixel ranges - pix_ranges = std::span(mxGetPr(bin_par_ptr->pix_data_range_ptr), pix_range_ids); + if (bin_par_ptr->binMode > opModes::sigerr_cell && pix_range_ids > 0 && bin_par_ptr->binMode < opModes::siger_selected) { // higher modes process pixel ranges except + pix_ranges = std::span(mxGetPr(bin_par_ptr->pix_data_range_ptr), pix_range_ids); init_min_max_range_calc(pix_ranges, pix_flds::PIX_WIDTH); } bool check_pix_selection = bin_par_ptr->check_pix_selection && (pix_coord_ptr != nullptr); @@ -150,13 +223,9 @@ size_t bin_pixels(std::span& npix, std::span& s, std::span(pix_coord_ptr, ip0, qi, pax, cut_range, bin_step, bin_cell_idx_range, stride, + npix, s, e); } break; } @@ -200,9 +269,8 @@ size_t bin_pixels(std::span& npix, std::span& s, std::span pix_ok_bin_idx; + case (opModes::sort_and_uid): { + std::vector pix_ok_bin_idx; pix_ok_bin_idx.swap(bin_par_ptr->pix_ok_bin_idx); std::vector npix1; npix1.swap(bin_par_ptr->npix1); @@ -216,13 +284,17 @@ size_t bin_pixels(std::span& npix, std::span& s, std::span(pix_ranges, pix_coord_ptr, PIX_STRIDE, i); @@ -253,7 +325,7 @@ size_t bin_pixels(std::span& npix, std::span& s, std::span(bin_par_ptr->alignment_matrix, pix_coord_ptr, i, sorted_pix_ptr, cell_pix_ind); + targ_pix_pos = align_and_copy_pixels(bin_par_ptr->alignment_matrix, pix_coord_ptr, i, sorted_pix_ptr, cell_pix_ind); } else { targ_pix_pos = copy_pixels(pix_coord_ptr, i, sorted_pix_ptr, cell_pix_ind); // copy all pixel data into the location requested } @@ -268,26 +340,25 @@ size_t bin_pixels(std::span& npix, std::span& s, std::span pix_ok_bin_idx; + std::vector pix_ok_bin_idx; pix_ok_bin_idx.swap(bin_par_ptr->pix_ok_bin_idx); for (long i = 0; i < data_size; i++) { // drop out coordinates outside of the binning range if (out_of_ranges(coord_ptr, i, COORD_STRIDE, cut_range, qi)) continue; + // drop out already selected pixels, if requested size_t ip0 = i * PIX_STRIDE; if (check_pix_selection && pix_coord_ptr[ip0 + pix_flds::idet] < 0) continue; nPixel_retained++; - // calculate location of pixel within the image grid - size_t il = pix_position(qi, pax, cut_range, bin_step, bin_cell_idx_range, stride); - // calculate npix accumulators for whole image which include multiple pixels pages - npix[il]++; - // calculate signal and error accumulators - s[il] += (double)pix_coord_ptr[ip0 + pix_flds::iSign]; - e[il] += (double)pix_coord_ptr[ip0 + pix_flds::iErr]; + // calculate location of pixel within the image grid and add values of this pixels to the accumulators + auto il = add_pix_to_accumulators(pix_coord_ptr, ip0, qi, pax, cut_range, bin_step, bin_cell_idx_range, stride, + npix, s, e); + + // store indices of contributing pixels pix_ok_bin_idx[i] = il; // calculate pix ranges calc_pix_ranges(pix_ranges, pix_coord_ptr, PIX_STRIDE, i); @@ -299,31 +370,58 @@ size_t bin_pixels(std::span& npix, std::span& s, std::spanpix_img_idx_ptr = allocate_pix_memory(nPixel_retained, 1, pix_img_idx_ptr); std::span pix_img_idx(pix_img_idx_ptr, nPixel_retained); + copy_resiults_to_final_arrays(bin_par_ptr, pix_coord_ptr, + data_size, nPixel_retained, pix_ok_bin_idx); + // swap memory of working arrays back to binning_arguments to retain it for the next call + bin_par_ptr->pix_ok_bin_idx.swap(pix_ok_bin_idx); + break; + } + case (opModes::nosort_sel): + case (opModes::siger_selected): { + auto return_selected_only = bin_par_ptr->binMode == opModes::siger_selected; + std::vector pix_ok_bin_idx; + if (!return_selected_only) { + pix_ok_bin_idx.swap(bin_par_ptr->pix_ok_bin_idx); + } - bool align_result = bin_par_ptr->alignment_matrix.size() == 9; + // Allocate memory for logical array of selected pixels + mxLogical* is_pix_selected_ptr(nullptr); + std::span is_pix_selected; + bin_par_ptr->is_pix_selected_ptr = allocate_pix_memory(1, data_size, is_pix_selected_ptr); + is_pix_selected = std::span(is_pix_selected_ptr, data_size); - // actually move pixels and copy indices the target array - size_t targ_pix_pos(0); - size_t targ_pix_array_pos(0); - for (size_t i = 0; i < data_size; i++) { - if (pix_ok_bin_idx[i] < 0) // drop pixels with have not been included above + for (long i = 0; i < data_size; i++) { + // drop out coordinates outside of the binning range + if (out_of_ranges(coord_ptr, i, COORD_STRIDE, cut_range, qi)) { + is_pix_selected[i] = false; continue; - - size_t il = (size_t)pix_ok_bin_idx[i]; // number of image cell pixel should go to - pix_img_idx[targ_pix_pos] = mxInt64(il + 1); // MATLB indices start from 1 and these -- from 0 - - if (align_result) { - // align q-coordinates and copy all other pixel data into the location requested - targ_pix_array_pos = align_and_copy_pixels(bin_par_ptr->alignment_matrix, pix_coord_ptr, i, selected_pix_ptr, targ_pix_pos); } else { - // copy all pixel data into the location requested - targ_pix_array_pos = copy_pixels(pix_coord_ptr, i, selected_pix_ptr, targ_pix_pos); + is_pix_selected[i] = true; + } + + // drop out already selected pixels, if requested + size_t ip0 = i * PIX_STRIDE; + if (check_pix_selection && pix_coord_ptr[ip0 + pix_flds::idet] < 0) { + is_pix_selected[i] = false; + continue; } - // search for unique run_id; - bin_par_ptr->unique_runID.insert(uint32_t(selected_pix_ptr[targ_pix_array_pos + pix_flds::irun])); - targ_pix_pos++; // move to the next pixel position within the target array + nPixel_retained++; + + // calculate location of pixel within the image grid and add values of this pixels to the accumulators + auto il = add_pix_to_accumulators(pix_coord_ptr, ip0, qi, pax, cut_range, bin_step, bin_cell_idx_range, stride, + npix, s, e); + if (!return_selected_only) { + pix_ok_bin_idx[i] = il; + // calculate pix ranges + calc_pix_ranges(pix_ranges, pix_coord_ptr, PIX_STRIDE, i); + } + } + if (return_selected_only) { + break; } + copy_resiults_to_final_arrays(bin_par_ptr, pix_coord_ptr, + data_size, nPixel_retained, pix_ok_bin_idx); // swap memory of working arrays back to binning_arguments to retain it for the next call bin_par_ptr->pix_ok_bin_idx.swap(pix_ok_bin_idx); break; diff --git a/_LowLevelCode/cpp/bin_pixels_c/bin_pixels_c.cpp b/_LowLevelCode/cpp/bin_pixels_c/bin_pixels_c.cpp index cb853fc5cb..e389146675 100644 --- a/_LowLevelCode/cpp/bin_pixels_c/bin_pixels_c.cpp +++ b/_LowLevelCode/cpp/bin_pixels_c/bin_pixels_c.cpp @@ -166,7 +166,6 @@ void parse_inputs(mxArray* plhs[], mxArray const* prhs[], std::unique_ptrparse_bin_inputs(prhs[in_arg::param_struct]); - bin_arg_ptr->check_and_init_accumulators(plhs, prhs,force_update); return; }; diff --git a/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.cpp b/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.cpp index 202b3a6993..ac56220296 100644 --- a/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.cpp +++ b/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.cpp @@ -1,6 +1,6 @@ #include "cpp_communicator.h" #include "../utility/version.h" -#include + /* The mex file provides media for MPI communications between various Horace workers. diff --git a/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.h b/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.h index 0911952372..63c35c1241 100644 --- a/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.h +++ b/_LowLevelCode/cpp/cpp_communicator/cpp_communicator.h @@ -1,6 +1,8 @@ #pragma once // #include +#include + #include "MPI_wrapper.h" #include "input_parser.h" diff --git a/_LowLevelCode/cpp/cpp_communicator/input_parser.cpp b/_LowLevelCode/cpp/cpp_communicator/input_parser.cpp index f8488fbd7b..f80e2bad4a 100644 --- a/_LowLevelCode/cpp/cpp_communicator/input_parser.cpp +++ b/_LowLevelCode/cpp/cpp_communicator/input_parser.cpp @@ -20,9 +20,9 @@ T retrieve_value(const char* err_id, const mxArray* prhs) return static_cast(pVector[0]); } +// Return size in bytes of different MATLAB mx types. size_t get_byte_length(const char* err_id, const mxArray* prhs) { - mxClassID category = mxGetClassID(prhs); switch (category) { case mxINT8_CLASS: @@ -111,7 +111,7 @@ void retrieve_string(const mxArray* param, std::string& result, const char* Erro Inputs: ModeName -- pointer to string, indicating mode name if error occurs is_test_mode -- boolean string, indicating that the init is done in test mode -prhs -- array of input array of pointers to the right hand parameters, recevied from Matlab +prhs -- array of input array of pointers to the right hand parameters, received from Matlab nrgs -- size of input array of pointers Outputs: AddPar -- the reference to structure, containing additional information about inputs @@ -129,7 +129,6 @@ void process_init_mode(const char* ModeName, bool is_test_mode, const mxArray* p } if (mpi_holder_ptr == nullptr) { mpi_holder_ptr = new class_handle(CLASS_HANDLE_SIGNATURE); - } else { } init_par.is_tested = is_test_mode; @@ -164,8 +163,8 @@ prhs -- array of pointers to right hand side parameters work_mode -- retrieved IO operations mode. data_address -- address of the node to communicate with data_tag -- MPI messages tag -is_synchronous -- for send/receive operations, if the communication mode is synchroneous -data_buffer -- refernece to pointert to the buffer with data. Defined for send and undef for labReceive/labProbe +is_synchronous -- for send/receive operations, if the communication mode is synchronous +data_buffer -- reference to pointer to the buffer with data. Defined for send and undef for labReceive/labProbe nbytes_to_transfer-- number of bytes to transfer over mpi. AddParr -- The structure, containing additional parameters, different operation calls may need to process and @@ -200,7 +199,7 @@ input_types parse_inputs(int nlhs, int nrhs, const mxArray* prhs[], data_addresses[0] = (int32_t)retrieve_value("labReceive: source address", prhs[(int)ReceiveInputs::source_id]) - 1; // the source data tag data_tag[0] = (int32_t)retrieve_value("labReceive: source tag", prhs[(int)ReceiveInputs::tag]); - // if the transfer is synchroneous or not + // if the transfer is synchronous or not is_synchronous = (bool)retrieve_value("labReceive: is synchronous", prhs[(int)ReceiveInputs::is_synchronous]); work_mode = input_types::labReceive; @@ -217,7 +216,7 @@ input_types parse_inputs(int nlhs, int nrhs, const mxArray* prhs[], data_addresses[0] = (int32_t)retrieve_value("labSend: destination address", prhs[(int)SendInputs::dest_id]) - 1; // the sending data tag data_tag[0] = (int32_t)retrieve_value("labSend: destination tag", prhs[(int)SendInputs::tag]); - // if the transfer is synchroneous or not + // if the transfer is synchronous or not is_synchronous = (bool)retrieve_value("labSend: is synchronous", prhs[(int)SendInputs::is_synchronous]); // retrieve pointer to serialized data to transfer size_t vector_size, bytesize; @@ -259,12 +258,12 @@ input_types parse_inputs(int nlhs, int nrhs, const mxArray* prhs[], work_mode = input_types::clearAll; } else { std::stringstream err; - err << " Unknow operation mode: " << mex_mode; + err << " Unknown operation mode: " << mex_mode; throw_error("MPI_MEX_COMMUNICATOR:invalid_argument", err.str().c_str()); } if (work_mode != input_types::close_mpi && nrhs < 1) { throw_error("MPI_MEX_COMMUNICATOR:invalid_argument", - "MPI communicator needs at least one argument to return the instance of the communicatir"); + "MPI communicator needs at least one argument to return the instance of the communicator"); } // finally retrieve communicator pointer from MATLAB. If it was just initialized by init routine have already returned // and here we come with modes, when object is retrieved from MATLAB diff --git a/_LowLevelCode/cpp/include/CommonCode.h b/_LowLevelCode/cpp/include/CommonCode.h index 6490a40b53..a95fdc8d68 100644 --- a/_LowLevelCode/cpp/include/CommonCode.h +++ b/_LowLevelCode/cpp/include/CommonCode.h @@ -203,6 +203,7 @@ T getMatlabScalar(const mxArray* pPar, const char* const fieldName) { }; + class omp_storage /** Class to manage dynamical storage used in OMP loops with various sources depending on the size of the storage and diff --git a/_LowLevelCode/cpp/mtimesx_horace/MatMultiply.h b/_LowLevelCode/cpp/mtimesx_horace/MatMultiply.h index 28140cdde2..8794b71891 100644 --- a/_LowLevelCode/cpp/mtimesx_horace/MatMultiply.h +++ b/_LowLevelCode/cpp/mtimesx_horace/MatMultiply.h @@ -27,9 +27,9 @@ void calc_output_size(mwSize const *const dimsA, size_t ndimsA, mwSize const *co * ---------- * res -- pointer to the contents of allocated MATLAB matrix which contains result * a -- pointer to the contents of the first MATLAB matrix participating in multiplication operation -* b -- pointer to the contents of the seconr MATLAB matrix participating in multiplication operation +* b -- pointer to the contents of the second MATLAB matrix participating in multiplication operation * Mi -- number of elements in the first dimension of matrices to multiply (columns for a and rows for b matrices) -* Mj -- number of elements in the second dimension of matrices to multiply (rosw for a and columns for b marices) +* Mj -- number of elements in the second dimension of matrices to multiply (rows for a and columns for b matrices) * Mk0 -- product of all remaining (except first and second) dimensions of matrix a to multiply * Mk -- product of all remaining (except first and second) dimensions of matrix b to multiply * expandA -- boolean containing true if Mk0 0; end %================================================================== - function performance_mex_nomex_mode6_sort_and_uid(obj) + function test_bin_pixels_mode8_sigerr_and_selected(obj) + if obj.no_mex + skipTest('Can not test mex code to bin pixels in mode 8'); + end + AB = AxesBlockBase_tester('nbins_all_dims',[10,1,30,1], ... + 'img_range',[0,0,0,0;1,0.8,1,0.8]); + pix_coord = rand(9,20); + pix_id = [10,10,11,11,7, 5,5,5,10,10]; + pix_coord(PixelDataBase.field_index('run_idx'),:) = [pix_id,pix_id]; + + + pix = PixelDataMemory(pix_coord); + + clObHor = set_temporary_config_options(hor_config, 'use_mex', false); + in_coord = pix.coordinates; + [npix_nom,s_nom,e_nom,selected_nom] = AB.bin_pixels(in_coord,[],[],[],pix,'-return_selected'); + assertEqual(size(npix_nom),[10,30]); + + clear clObHor + clObHor = set_temporary_config_options(hor_config, 'use_mex', true); + [npix_mex,s_mex,e_mex,selected_mex] = AB.bin_pixels(in_coord,[],[],[],pix,'-return_selected'); + assertEqual(size(npix_mex),[10,30]); + + assertEqual(selected_nom,selected_mex) + assertEqual(npix_mex,npix_nom); + assertEqual(s_mex,s_nom); + assertEqual(e_mex,e_nom); + end + + function test_return_inputs_mex_mode8_sigerr_and_selected(obj) + % bin pixels and sort pixels, input/output parameters + if obj.no_mex + skipTest('Can not test mex code to check binning against mex'); + end + clObHor = set_temporary_config_options(hor_config, 'use_mex', true); + + AB = AxesBlockBase_tester('nbins_all_dims',[10,1,1,40], ... + 'img_range',[-1,-2,-3,-10;1,2,3,40]); + pix_id = [10,10,11,11,7, 5,5,5,10,10]; + pix_coord = rand(9,10); + pix_coord(PixelDataBase.field_index('run_idx'),:) = pix_id; + pix = PixelDataMemory(pix_coord); + + in_coord = pix.coordinates; + [npix,s,e,is_selected,out_data] = AB.bin_pixels(in_coord,[],[],[],pix,'-return_selected','-test_mex_inputs'); + + assertEqual(size(npix),[10,40]); + assertEqual(npix,zeros(10,40)); + assertEqual(s,npix); + assertEqual(e,npix); + assertTrue(isempty(is_selected)); + assertTrue(isa(is_selected,'logical')); + + assertTrue(isempty(out_data.pix_ok_data_range)); + + assertEqual(out_data.coord_in,in_coord); + assertEqual(out_data.binning_mode,bin_mode.sigerr_sel); + assertEqual(out_data.num_threads, ... + config_store.instance().get_value('parallel_config','threads')); + assertEqual(out_data.data_range,AB.img_range) + assertEqual(out_data.bins_all_dims,uint32(AB.nbins_all_dims)); + assertTrue(isempty(out_data.unique_runid)); + assertFalse(out_data.force_double); + assertTrue(out_data.test_input_parsing); + assertTrue(isempty(out_data.alignment_matr)); + assertEqual(out_data.pix_candidates,pix.data); + assertTrue(out_data.check_pix_selection); + assertTrue(isempty(out_data.pix_img_idx)); + assertEqual(out_data.is_pix_selected,is_selected); + end + + %================================================================== + function performance_mex_nomex_mode7_nosort_idx_sel(obj) + if obj.no_mex + skipTest('Can not test mex code to check binning against mex'); + end + % this will recover existing configuration after test have been + % finished and temporary mex/nomex values will be set within + % the loop. + clObHor = set_temporary_config_options(hor_config, 'use_mex', false,'log_level',-1); + % + AB = AxesBlockBase_tester('nbins_all_dims',[50,20,50,20], ... + 'img_range',[0,0,0,0;1,0.8,1,0.8]); + + n_points = 20000000; + n_repeats = 5; + npix_nomex = []; s_nomex = [];e_nomex=[];uniqId_nom = []; + npix_mex = []; s_mex = []; e_mex=[];uniqId_mex = []; + + t_nomex = zeros(1,n_repeats); + t_mex = zeros(1,n_repeats); + disp("*** Mex/nomex performance mode7 (bin pixels + unique runid + return idx + selected):") + for i= 1:n_repeats + fprintf('.') + pix_data = rand(9,n_points); + ids = 500+floor(100*rand(1,n_points)); + pix_data(PixelDataBase.field_index('run_idx'),:) = ids; + + pix = PixelDataMemory(pix_data); + coord = pix.coordinates; + config_store.instance.set_value('hor_config','use_mex',false); + t1 = tic(); + [npix_nomex,s_nomex,e_nomex,pix_ok_nom,uniqId_nom,pix_idx_nom,is_sel_nom] = AB.bin_pixels(coord,npix_nomex,s_nomex,e_nomex,pix,uniqId_nom); + t_nomex(i) = toc(t1); + fprintf('.') + + config_store.instance.set_value('hor_config','use_mex',true); + + t1 = tic(); + [npix_mex,s_mex,e_mex,pix_ok_mex,uniqId_mex,pix_idx_mex,is_sel_mex] = AB.bin_pixels(coord,npix_mex,s_mex,e_mex,pix,uniqId_mex); + t_mex(i) = toc(t1); + + assertEqual(uint32(uniqId_nom),uniqId_mex); + assertEqual(uint64(pix_idx_nom),pix_idx_mex); + assertEqual(is_sel_nom,is_sel_mex); + + assertEqual(npix_nomex,npix_mex) + assertEqualToTol(s_nomex,s_mex,'tol',[1.e-12,1.e-12]) + assertEqualToTol(e_nomex,e_mex,'tol',[1.e-12,1.e-12]) + assertEqualToTol(pix_ok_nom,pix_ok_mex,'tol',[1.e-12,1.e-12]) + end + tav_mex = sum(t_mex)/n_repeats; + tav_nom = sum(t_nomex)/n_repeats; + fprintf( ... + '\n*** time of first step, nomex: %4.2g(sec) mex: %4.2g(sec); Acceleration : %4.2g\n', ... + t_nomex(1),t_mex(1),t_nomex(1)/t_mex(1)); + fprintf( ... + '*** Average time per step, nomex: %4.2g(sec) mex: %4.2g(sec); Acceleration : %4.2g\n', ... + tav_nom,tav_mex,tav_nom/tav_mex); + % REFERENCE DATA: ndw2671 + %*** Mex/nomex performance mode7 (bin pixels + unique runid + return idx + selected): + %*** time of first step, nomex: 3.1(sec) mex: 1.2(sec); Acceleration : 2.5 + %*** Average time per step, nomex: 3.1(sec) mex: 1.3(sec); Acceleration : 2.3 + end + + function test_bin_pixels_mex_nomex_mode7_nosort_and_sel_multipage(obj) + if obj.no_mex + skipTest('Can not test mex code to check binning against mex'); + end + AB = AxesBlockBase_tester('nbins_all_dims',[10,1,20,1], ... + 'img_range',[0,0,0,0;0.8,0.8,1,0.8]); + pix_coord1 = rand(9,20); + pix_id = [10,10,11,11,7, 5,5,5,10,10]; + pix_coord1(PixelDataBase.field_index('run_idx'),:) = [pix_id,pix_id]; + + pix_coord2 = rand(9,10); + pix_id = [10,11,7,11,7, 8,5,5,10,10]; + pix_coord2(PixelDataBase.field_index('run_idx'),:) = pix_id; + pix1 = PixelDataMemory(pix_coord1); + pix2 = PixelDataMemory(pix_coord2); + + clObHor = set_temporary_config_options(hor_config, 'use_mex', false); + + npix_nom = []; s_nom = []; e_nom = []; + in_coord = pix1.coordinates; + [npix_nom,s_nom,e_nom,pix_ok_nom1,uniq_id1_nom,pix_idx_nom1,sel_nom1] = AB.bin_pixels(in_coord,npix_nom,s_nom,e_nom,pix1); + in_coord = pix2.coordinates; + [npix_nom,s_nom,e_nom,pix_ok_nom2,uniq_id2_nom,pix_idx_nom2,sel_nom2] = AB.bin_pixels(in_coord,npix_nom,s_nom,e_nom,pix2,uniq_id1_nom); + assertEqual(size(npix_nom),[10,20]); + + clear clObHor + clObHor = set_temporary_config_options(hor_config, 'use_mex', true); + + npix_mex = []; s_mex = []; e_mex = []; + + in_coord = pix1.coordinates; + [npix_mex,s_mex,e_mex,pix_ok_mex1,uniq_id1_mex,pix_idx_mex1,sel_mex1] = AB.bin_pixels(in_coord,npix_mex,s_mex,e_mex,pix1); + assertEqual(pix_ok_nom1,pix_ok_mex1); + assertEqual(int64(pix_idx_nom1),pix_idx_mex1); + assertEqual(uint32(uniq_id1_nom),uniq_id1_mex) + assertEqual(sel_nom1,sel_mex1) + in_coord = pix2.coordinates; + [npix_mex,s_mex,e_mex,pix_ok_mex2,uniq_id2_mex,pix_idx_mex2,sel_mex2] = AB.bin_pixels(in_coord,npix_mex,s_mex,e_mex,pix2,uniq_id1_mex); + assertEqual(sel_nom2,sel_mex2) + assertEqual(size(npix_nom),[10,20]); + + assertEqual(npix_mex,npix_nom); + assertEqualToTol(s_mex,s_nom); + assertEqualToTol(e_mex,e_nom); + assertEqual(int64(pix_idx_nom2),pix_idx_mex2); + assertEqual(uint32(uniq_id2_nom),uniq_id2_mex) + + assertEqual(pix_ok_nom2,pix_ok_mex2); + end + + function test_bin_pixels_mode7_nosort_and_sel(obj) + if obj.no_mex + skipTest('Can not test mex code to bin pixels in mode 5'); + end + AB = AxesBlockBase_tester('nbins_all_dims',[10,1,30,1], ... + 'img_range',[0,0,0,0;1,0.8,1,0.8]); + pix_coord = rand(9,20); + pix_id = [10,10,11,11,7, 5,5,5,10,10]; + pix_coord(PixelDataBase.field_index('run_idx'),:) = [pix_id,pix_id]; + + + pix = PixelDataMemory(pix_coord); + + clObHor = set_temporary_config_options(hor_config, 'use_mex', false); + in_coord = pix.coordinates; + [npix_nom,s_nom,e_nom,pix_ok_nom,unique_runid_nom,pix_id_nom,is_select_nom] = AB.bin_pixels(in_coord,[],[],[],pix); + assertEqual(size(npix_nom),[10,30]); + + clear clObHor + clObHor = set_temporary_config_options(hor_config, 'use_mex', true); + [npix_mex,s_mex,e_mex,pix_ok_mex,unique_runid_mex,pix_id_mex,is_select_mex] = AB.bin_pixels(in_coord,[],[],[],pix); + assertEqual(size(npix_mex),[10,30]); + + assertEqual(uint32(unique_runid_nom),unique_runid_mex) + assertEqual(int64(pix_id_nom),pix_id_mex) + assertEqual(is_select_nom,is_select_mex); + assertEqual(npix_mex,npix_nom); + assertEqual(s_mex,s_nom); + assertEqual(e_mex,e_nom); + assertEqualToTol(pix_ok_nom,pix_ok_mex); + + pix_sel = pix.get_pixels(is_select_mex); + assertEqualToTol(pix_sel,pix_ok_mex); + + end + + function test_return_inputs_mex_mode7_nosort_and_selected(obj) + % bin pixels and sort pixels, input/output parameters + if obj.no_mex + skipTest('Can not test mex code to check binning against mex'); + end + clObHor = set_temporary_config_options(hor_config, 'use_mex', true); + + AB = AxesBlockBase_tester('nbins_all_dims',[10,1,1,40], ... + 'img_range',[-1,-2,-3,-10;1,2,3,40]); + pix_id = [10,10,11,11,7, 5,5,5,10,10]; + pix_coord = rand(9,10); + pix_coord(PixelDataBase.field_index('run_idx'),:) = pix_id; + pix = PixelDataMemory(pix_coord); + + in_coord = pix.coordinates; + [npix,s,e,pix_ok,unique_id,pix_idx,is_selected,out_data] = AB.bin_pixels(in_coord,[],[],[],pix,'-test_mex_inputs'); + + assertEqual(size(npix),[10,40]); + assertEqual(npix,zeros(10,40)); + assertEqual(s,npix); + assertEqual(e,npix); + assertTrue(isempty(unique_id)); + assertTrue(isa(unique_id,'uint32')); + assertTrue(isempty(pix_idx)); + assertTrue(isa(pix_idx,'int64')); + assertTrue(isempty(is_selected)); + assertTrue(isa(is_selected,'logical')); + + assertEqual(pix_ok.data,out_data.pix_ok_data); + assertEqual(pix_ok.data,pix_coord); + assertEqual(pix_ok.data_range,out_data.pix_ok_data_range); + % range matrix have been allocated and probably contains zeros + % but this is not guaranteed. + assertEqual(size(out_data.pix_ok_data_range),[2,9]); + + assertEqual(out_data.coord_in,in_coord); + assertEqual(out_data.binning_mode,bin_mode.nosort_sel); + assertEqual(out_data.num_threads, ... + config_store.instance().get_value('parallel_config','threads')); + assertEqual(out_data.data_range,AB.img_range) + assertEqual(out_data.bins_all_dims,uint32(AB.nbins_all_dims)); + assertTrue(isempty(out_data.unique_runid)); + assertFalse(out_data.force_double); + assertTrue(out_data.test_input_parsing); + assertTrue(isempty(out_data.alignment_matr)); + assertEqual(out_data.pix_candidates,pix.data); + assertTrue(out_data.check_pix_selection); + assertEqual(out_data.pix_img_idx,pix_idx); + assertEqual(out_data.is_pix_selected,is_selected); + end + + %================================================================== + function performance_mex_nomex_mode6_nosort_idx(obj) if obj.no_mex skipTest('Can not test mex code to check binning against mex'); end diff --git a/_test/test_transformation/test_axes_block_integration.m b/_test/test_transformation/test_axes_block_integration.m index b11d5e90e5..d4ab7efe1f 100644 --- a/_test/test_transformation/test_axes_block_integration.m +++ b/_test/test_transformation/test_axes_block_integration.m @@ -86,6 +86,7 @@ function test_ab_indexes_1D_same_bin_partial_region(~) assertEqual(reb_data,2*ones(ab_r.dims_as_ssize)) end + function test_ab_alignment_iax_aligned(~) clOb = set_temporary_warning('off','HORACE:realign_bin_edges:invalid_argument'); diff --git a/admin/CMakeLists.txt b/admin/CMakeLists.txt index 8004343859..d2cce22881 100644 --- a/admin/CMakeLists.txt +++ b/admin/CMakeLists.txt @@ -28,12 +28,12 @@ configure_file("version.h.template" "${Horace_ROOT}/_LowLevelCode/cpp/utility/version.h") # Runs docify -configure_file("run_docify.m" "${CMAKE_CURRENT_BINARY_DIR}/run_docify.m") -add_custom_target(run_docify) -add_custom_command( - TARGET run_docify - COMMAND ${Matlab_MAIN_PROGRAM} -batch "run_docify" -) +#configure_file("run_docify.m" "${CMAKE_CURRENT_BINARY_DIR}/run_docify.m") +#add_custom_target(run_docify) +#add_custom_command( +# TARGET run_docify +# COMMAND ${Matlab_MAIN_PROGRAM} -batch "run_docify" +#) # ============================================================================= # Install commands diff --git a/admin/horace_mex.m b/admin/horace_mex.m index 0eac055016..27076302c5 100644 --- a/admin/horace_mex.m +++ b/admin/horace_mex.m @@ -69,13 +69,12 @@ function horace_mex() end % simple OMP routines % build C++ files - % mex_single(fullfile(cpp_in_rel_dir,'serialiser'), out_rel_dir,... - % 'c_serialize.cpp') - % mex_single(fullfile(cpp_in_rel_dir,'serialiser'), out_rel_dir,... - % 'c_deserialize.cpp') - % mex_single(fullfile(cpp_in_rel_dir,'serialiser'), out_rel_dir,... - % 'c_serial_size.cpp') - + mex_single(fullfile(cpp_in_rel_dir,'serialiser'), out_rel_dir,... + 'c_serialize.cpp') + mex_single(fullfile(cpp_in_rel_dir,'serialiser'), out_rel_dir,... + 'c_deserialize.cpp') + mex_single(fullfile(cpp_in_rel_dir,'serialiser'), out_rel_dir,... + 'c_serial_size.cpp') mex_single([cpp_in_rel_dir 'accumulate_cut_c'], out_rel_dir, ... 'accumulate_cut_c.cpp'); @@ -95,7 +94,6 @@ function horace_mex() mex_single([cpp_in_rel_dir 'mex_bin_plugin'], out_rel_dir, ... 'mex_bin_plugin.cpp'); - % create the procedure to access hdf files if build_hdf_reader cof = {'hdf_mex_reader.cpp','hdf_pix_accessor.cpp','input_parser.cpp',... diff --git a/admin/horace_mex_mpi.m b/admin/horace_mex_mpi.m index a3258d746c..07bbcf6a66 100644 --- a/admin/horace_mex_mpi.m +++ b/admin/horace_mex_mpi.m @@ -9,7 +9,7 @@ % we supply MPI libraries together with Herbert. They may not work with any % Matlab version and with any OS so may be cases when it is preferable to % use system libraries but: -use_her_mpich = false; % if true, use MPI libraries, provided with Herbert. +use_her_mpich = true; % if true, use MPI libraries, provided with Herbert. % if false, modify script below providing the location of the MPI libraries % present on the system. @@ -24,7 +24,7 @@ if ispc() if use_her_mpich mpi_folder = fullfile(pths.low_level,'external','win64','MSMPI-8.0.12'); - mpi_hdrs_folder = fullfile(mpi_folder,'include'); + mpi_hdrs_folder = fullfile(mpi_folder,'Include'); mpi_lib_folder = fullfile(mpi_folder,'lib'); else @@ -64,14 +64,14 @@ % code folder: code_folder = fullfile(pths.low_level,'cpp','cpp_communicator'); +common_include_folder = fullfile(pths.low_level,'cpp'); input_files = fullfile(code_folder,input_files); -% additional include folder, containing mpich -add_include = ['-I',mpi_hdrs_folder]; +% common include folder with common code and additional include folder, containing mpich +add_include ={['-I',common_include_folder],['-I',mpi_hdrs_folder]}; + if verbose - add_include = {'-v',add_include}; -else - add_include = {add_include}; + add_include = {'-v',add_include{:}}; end outdir = fullfile(pths.horace,'DLL',['_',computer],'_R2015a'); @@ -79,7 +79,7 @@ try opt = sprintf('CXXFLAGS=$CFLAGS -fopenmp -std=c++17 -Wl,-rpath=%s,--enable-new-dtags,--no-undefined,-fopenmp',mpi_lib_folder); if isempty(opt_file) - mex('-v',add_include{:},opt,input_files{:},... + mex(add_include{:},opt,input_files{:},...add_include = {'-v',add_include{:}} mpi_lib{:},'-outdir',outdir); else mex(add_include{:},opt,input_files{:},... diff --git a/cmake/PACE_Docs.cmake b/cmake/PACE_Docs.cmake index e301ba7eaf..bd1e2805d9 100644 --- a/cmake/PACE_Docs.cmake +++ b/cmake/PACE_Docs.cmake @@ -49,12 +49,12 @@ else() set(Horace_DOCS_PACK_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/docs.tar.gz" CACHE FILEPATH "File to store packed HTML documentation") endif() -find_package(PythonInterp) +find_package(Python3 REQUIRED COMPONENTS Interpreter) find_program(sphinx-build NAMES sphinx-build HINTS ${Horace_DOCS_ROOT_DIR}) find_program(pdflatex NAMES pdflatex) find_program(latexmk NAMES latexmk) -execute_process(COMMAND ${PYTHON_EXECUTABLE} ${sphinx-build} ERROR_VARIABLE test) +execute_process(COMMAND ${Python3_EXECUTABLE} ${sphinx-build} ERROR_VARIABLE test) string(REGEX MATCH "ModuleNotFoundError" sphinx-build-failed ${test}) if (NOT sphinx-build-failed) @@ -63,16 +63,16 @@ if (NOT sphinx-build-failed) add_custom_target(docs COMMENT "Building HTML user documentation" BYPRODUCTS "${Horace_DOCS_OUTPUT_DIR}/*" - COMMAND ${PYTHON_EXECUTABLE} ${sphinx-build} -b html "${Horace_DOCS_SOURCE_DIR}" "${Horace_DOCS_OUTPUT_DIR}" ${SPHINX_OPTS} - -D "release=${${PROJECT_NAME}_SHORT_VERSION}" - -D "version=${${PROJECT_NAME}_SHORT_VERSION}" + COMMAND ${Python3_EXECUTABLE} ${sphinx-build} -b html "${Horace_DOCS_SOURCE_DIR}" "${Horace_DOCS_OUTPUT_DIR}" ${SPHINX_OPTS} + -D "release=${${PROJECT_NAME}_SHORT_VERSION}" + -D "version=${${PROJECT_NAME}_SHORT_VERSION}" ) if (WIN32) add_custom_target(docs-pack COMMENT "Zipping HTML documentation to ${Horace_DOCS_PACK_OUTPUT}" COMMAND powershell -ExecutionPolicy Bypass -command - "Compress-Archive -Path \"${Horace_DOCS_OUTPUT_DIR}/*\" -DestinationPath \"${Horace_DOCS_PACK_OUTPUT}\"" + "Compress-Archive -Path \"${Horace_DOCS_OUTPUT_DIR}/*\" -DestinationPath \"${Horace_DOCS_PACK_OUTPUT}\"" DEPENDS docs ) @@ -89,8 +89,8 @@ if (NOT sphinx-build-failed) if (pdflatex AND latexmk) add_custom_command(OUTPUT horace.tex COMMAND ${PYTHON_EXECUTABLE} ${sphinx-build} -b latex "${Horace_DOCS_SOURCE_DIR}" "${Horace_MANUAL_WORK_DIR}" ${SPHINX_OPTS} - -D "release=${${PROJECT_NAME}_SHORT_VERSION}" - -D "version=${${PROJECT_NAME}_SHORT_VERSION}" + -D "release=${${PROJECT_NAME}_SHORT_VERSION}" + -D "version=${${PROJECT_NAME}_SHORT_VERSION}" WORKING_DIRECTORY "${Horace_DOCS_ROOT_DIR}" ) diff --git a/cmake/external/FindMatlab.cmake b/cmake/external/FindMatlab.cmake index f366becbce..231700a7e0 100644 --- a/cmake/external/FindMatlab.cmake +++ b/cmake/external/FindMatlab.cmake @@ -1,285 +1,786 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. +# file LICENSE.rst or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindMatlab ---------- -# This script is taken from CMake git repository Cmake version 3.24.0.rc1 -Finds Matlab or Matlab Compiler Runtime (MCR) and provides Matlab tools, -libraries and compilers to CMake. -This package primary purpose is to find the libraries associated with Matlab -or the MCR in order to be able to build Matlab extensions (mex files). It -can also be used: +Finds MATLAB or MATLAB Compiler Runtime (MCR) and provides its tools, +libraries and compilers to CMake: -* to run specific commands in Matlab in case Matlab is available -* for declaring Matlab unit test -* to retrieve various information from Matlab (mex extensions, versions and +.. code-block:: cmake + + find_package(Matlab [] [COMPONENTS ...] [REGISTRY_VIEW ] [...]) + +The primary purpose of this module is to find the libraries associated with +MATLAB or the MCR in order to be able to build MATLAB extensions (MEX files). +It can also be used: + +* to run specific commands in MATLAB in case MATLAB is available +* for declaring MATLAB unit tests +* to retrieve various information from MATLAB (MEX extensions, versions and release queries, ...) .. versionadded:: 3.12 - Added Matlab Compiler Runtime (MCR) support. + MATLAB Compiler Runtime (MCR) support. + +.. versionadded:: 3.30 + Support for specifying a version range to :command:`find_package`, + support for specifying ``REGISTRY_VIEW`` argument to + :command:`find_package`, + :command:`matlab_extract_all_installed_versions_from_registry` and + :command:`matlab_get_all_valid_matlab_roots_from_registry` commands. + The default behavior remained unchanged, by using the registry view + ``TARGET``. + +.. note:: + + The version given to the :command:`find_package` argument is the MATLAB + *version*, which should not be confused with the MATLAB *release name* + (e.g. ``R2023b``). The :command:`matlab_get_version_from_release_name` + and :command:`matlab_get_release_name_from_version` commands provide a + mapping between the release name and the version. + +Components +^^^^^^^^^^ + +This module supports optional components which can be specified using the +:command:`find_package` command: + +.. code-block:: cmake + + find_package(Matlab [COMPONENTS ...]) -The module supports the following components: +Supported components include: -* ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the ``ENG`` and ``MAT`` - libraries of Matlab -* ``MAIN_PROGRAM`` the Matlab binary program. Note that this component is not +``ENG_LIBRARY`` + .. versionadded:: 3.3 + + Finds the ``ENG`` library of MATLAB. + +``MAT_LIBRARY`` + .. versionadded:: 3.7 + + Finds the ``MAT`` library of MATLAB. + +``MAIN_PROGRAM`` + .. versionadded:: 3.3 + + Finds the MATLAB binary program. Note that this component is not available on the MCR version, and will yield an error if the MCR is found - instead of the regular Matlab installation. -* ``MEX_COMPILER`` the MEX compiler. -* ``MCC_COMPILER`` the MCC compiler, included with the Matlab Compiler add-on. -* ``SIMULINK`` the Simulink environment. + instead of the regular MATLAB installation. -.. versionadded:: 3.7 - Added the ``MAT_LIBRARY`` component. +``MEX_COMPILER`` + .. versionadded:: 3.3 -.. versionadded:: 3.13 - Added the ``ENGINE_LIBRARY``, ``DATAARRAY_LIBRARY`` and ``MCC_COMPILER`` - components. + Finds the MEX compiler. -.. versionchanged:: 3.14 - Removed the ``MX_LIBRARY``, ``ENGINE_LIBRARY`` and ``DATAARRAY_LIBRARY`` - components. These libraries are found unconditionally. +``MCC_COMPILER`` + .. versionadded:: 3.13 -.. note:: + Finds the MCC compiler, included with the MATLAB Compiler add-on. - The version given to the :command:`find_package` directive is the Matlab - **version**, which should not be confused with the Matlab *release* name - (eg. `R2014`). - The :command:`matlab_get_version_from_release_name` and - :command:`matlab_get_release_name_from_version` provide a mapping - between the release name and the version. - -The variable :variable:`Matlab_ROOT_DIR` may be specified in order to give -the path of the desired Matlab version. Otherwise, the behavior is platform -specific: - -* Windows: The installed versions of Matlab/MCR are retrieved from the - Windows registry -* OS X: The installed versions of Matlab/MCR are given by the MATLAB - default installation paths in ``/Application``. If no such application is - found, it falls back to the one that might be accessible from the ``PATH``. -* Unix: The desired Matlab should be accessible from the ``PATH``. This does - not work for MCR installation and :variable:`Matlab_ROOT_DIR` should be - specified on this platform. - -Additional information is provided when :variable:`MATLAB_FIND_DEBUG` is set. -When a Matlab/MCR installation is found automatically and the ``MATLAB_VERSION`` -is not given, the version is queried from Matlab directly (on Windows this -may pop up a Matlab window) or from the MCR installation. - -The mapping of the release names and the version of Matlab is performed by -defining pairs (name, version). The variable -:variable:`MATLAB_ADDITIONAL_VERSIONS` may be provided before the call to -the :command:`find_package` in order to handle additional versions. - -A Matlab scripts can be added to the set of tests using the -:command:`matlab_add_unit_test`. By default, the Matlab unit test framework -will be used (>= 2013a) to run this script, but regular ``.m`` files -returning an exit code can be used as well (0 indicating a success). - -Module Input Variables -^^^^^^^^^^^^^^^^^^^^^^ +``SIMULINK`` + .. versionadded:: 3.3 -Users or projects may set the following variables to configure the module -behavior: + Finds the Simulink environment. -:variable:`Matlab_ROOT_DIR` - the root of the Matlab installation. -:variable:`MATLAB_FIND_DEBUG` - outputs debug information -:variable:`MATLAB_ADDITIONAL_VERSIONS` - additional versions of Matlab for the automatic retrieval of the installed - versions. +Implicitly Found Components +""""""""""""""""""""""""""" -Imported targets -^^^^^^^^^^^^^^^^ +The following components are always found unconditionally, without needing +to be specified explicitly: + +``MX_LIBRARY`` + .. versionchanged:: 3.14 + This component has been removed and is now always found unconditionally. -.. versionadded:: 3.22 + .. versionadded:: 3.3 -This module defines the following :prop_tgt:`IMPORTED` targets: + Finds the MATLAB mx library. + +``ENGINE_LIBRARY`` + .. versionchanged:: 3.14 + This component has been removed and is now always found unconditionally. + + .. versionadded:: 3.13 + + Finds the MATLAB engine library. + +``DATAARRAY_LIBRARY`` + .. versionchanged:: 3.14 + This component has been removed and is now always found unconditionally. + + .. versionadded:: 3.13 + + Finds the C++ MATLAB data array library. + +If no components are specified, the module looks for the ``MX_LIBRARY``, +``ENGINE_LIBRARY``, and ``DATAARRAY_LIBRARY`` by default. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following :ref:`Imported Targets`: ``Matlab::mex`` - The ``mex`` library, always available. + .. versionadded:: 3.22 + + Target encapsulating the ``mex`` library usage requirements, always + available for MATLAB installations. Available for MCR installations if + provided by MCR. ``Matlab::mx`` - The mx library of Matlab (arrays), always available. + .. versionadded:: 3.22 + + Target encapsulating the usage requirements of the mx library of MATLAB + (arrays), always available for MATLAB installations. Available for MCR + installations if provided by MCR. ``Matlab::eng`` - Matlab engine library. Available only if the ``ENG_LIBRARY`` component - is requested. + .. versionadded:: 3.22 + + Target encapsulating the MATLAB engine library usage requirements. + Available only if the ``ENG_LIBRARY`` component is requested. ``Matlab::mat`` - Matlab matrix library. Available only if the ``MAT_LIBRARY`` component - is requested. + .. versionadded:: 3.22 + + Target encapsulating the MATLAB matrix library usage requirements. + Available only if the ``MAT_LIBRARY`` component is requested. ``Matlab::MatlabEngine`` - Matlab C++ engine library, always available for R2018a and newer. + .. versionadded:: 3.22 + + Target encapsulating the MATLAB C++ engine library usage requirements, + always available for MATLAB R2018a and newer. Available for MCR + installations if provided by MCR. ``Matlab::MatlabDataArray`` - Matlab C++ data array library, always available for R2018a and newer. + .. versionadded:: 3.22 + + Target encapsulating the MATLAB C++ data array library usage requirements, + always available for MATLAB R2018a and newer. Available for MCR + installations if provided by MCR. -Variables defined by the module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Result Variables +^^^^^^^^^^^^^^^^ -Result variables -"""""""""""""""" +This module defines the following variables: ``Matlab_FOUND`` - ``TRUE`` if the Matlab installation is found, ``FALSE`` - otherwise. All variable below are defined if Matlab is found. + .. versionadded:: 3.3 + + Boolean indicating whether the (requested version of) MATLAB installation + was found. All variables below are defined if MATLAB is found. + +``Matlab_VERSION`` + .. versionadded:: 3.27 + + The numerical version (e.g. ``23.2.0``) of MATLAB found. Not to be + confused with MATLAB release name (e.g. ``R2023b``) that can be obtained + with :command:`matlab_get_release_name_from_version`. + + When a MATLAB/MCR installation is found automatically and the + ``Matlab_VERSION`` is not given, the version is queried from MATLAB + directly (on Windows this may pop up a MATLAB window) or from the MCR + installation. + ``Matlab_ROOT_DIR`` - the final root of the Matlab installation determined by the FindMatlab - module. + .. versionadded:: 3.3 + + The final root of the MATLAB installation determined by this module. + ``Matlab_MAIN_PROGRAM`` - the Matlab binary program. Available only if the component ``MAIN_PROGRAM`` - is given in the :command:`find_package` directive. + .. versionadded:: 3.3 + + The MATLAB binary program. Available only if the component ``MAIN_PROGRAM`` + is given in the :command:`find_package` argument. + ``Matlab_INCLUDE_DIRS`` - the path of the Matlab libraries headers + .. versionadded:: 3.3 + + The path of the MATLAB libraries headers. + ``Matlab_MEX_LIBRARY`` - library for mex, always available. + Library for MEX, always available for MATLAB installations. Available + for MCR installations if provided by MCR. + ``Matlab_MX_LIBRARY`` - mx library of Matlab (arrays), always available. + The mx library of MATLAB (arrays), always available for MATLAB + installations. Available for MCR installations if provided by MCR. + ``Matlab_ENG_LIBRARY`` - Matlab engine library. Available only if the component ``ENG_LIBRARY`` + MATLAB engine library. Available only if the component ``ENG_LIBRARY`` is requested. + ``Matlab_MAT_LIBRARY`` - Matlab matrix library. Available only if the component ``MAT_LIBRARY`` + .. versionadded:: 3.7 + + Matlab matrix library. Available only if the component ``MAT_LIBRARY`` is requested. + ``Matlab_ENGINE_LIBRARY`` .. versionadded:: 3.13 - Matlab C++ engine library, always available for R2018a and newer. + Matlab C++ engine library, always available for MATLAB R2018a and newer. + Available for MCR installations if provided by MCR. + ``Matlab_DATAARRAY_LIBRARY`` .. versionadded:: 3.13 - Matlab C++ data array library, always available for R2018a and newer. + Matlab C++ data array library, always available for MATLAB R2018a and + newer. Available for MCR installations if provided by MCR. + ``Matlab_LIBRARIES`` - the whole set of libraries of Matlab + The whole set of libraries of MATLAB. + ``Matlab_MEX_COMPILER`` - the mex compiler of Matlab. Currently not used. - Available only if the component ``MEX_COMPILER`` is requested. + .. versionadded:: 3.3 + + The MEX compiler of MATLAB. Currently not used. Available only if the + component ``MEX_COMPILER`` is requested. + ``Matlab_MCC_COMPILER`` .. versionadded:: 3.13 - the mcc compiler of Matlab. Included with the Matlab Compiler add-on. + The mcc compiler of MATLAB. Included with the MATLAB Compiler add-on. Available only if the component ``MCC_COMPILER`` is requested. -Cached variables -"""""""""""""""" +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: ``Matlab_MEX_EXTENSION`` - the extension of the mex files for the current platform (given by Matlab). + .. versionadded:: 3.3 + + The extension of the MEX files for the current platform (given by MATLAB). + ``Matlab_ROOT_DIR`` - the location of the root of the Matlab installation found. If this value + .. versionadded:: 3.3 + + The location of the root of the MATLAB installation found. If this value is changed by the user, the result variables are recomputed. -Provided macros +Input Variables ^^^^^^^^^^^^^^^ -:command:`matlab_get_version_from_release_name` - returns the version from the release name -:command:`matlab_get_release_name_from_version` - returns the release name from the Matlab version - -Provided functions -^^^^^^^^^^^^^^^^^^ - -:command:`matlab_add_mex` - adds a target compiling a MEX file. -:command:`matlab_add_unit_test` - adds a Matlab unit test file as a test to the project. -:command:`matlab_extract_all_installed_versions_from_registry` - parses the registry for all Matlab versions. Available on Windows only. - The part of the registry parsed is dependent on the host processor -:command:`matlab_get_all_valid_matlab_roots_from_registry` - returns all the possible Matlab or MCR paths, according to a previously - given list. Only the existing/accessible paths are kept. This is mainly - useful for the searching all possible Matlab installation. -:command:`matlab_get_mex_suffix` - returns the suffix to be used for the mex files - (platform/architecture dependent) -:command:`matlab_get_version_from_matlab_run` - returns the version of Matlab/MCR, given the full directory of the Matlab/MCR - installation path. - - -Known issues -^^^^^^^^^^^^ +Users or projects may set the following variables to configure the module +behavior before calling ``find_package(Matlab)``: -**Symbol clash in a MEX target** - By default, every symbols inside a MEX - file defined with the command :command:`matlab_add_mex` have hidden - visibility, except for the entry point. This is the default behavior of - the MEX compiler, which lowers the risk of symbol collision between the - libraries shipped with Matlab, and the libraries to which the MEX file is - linking to. This is also the default on Windows platforms. +:variable:`Matlab_ROOT <_ROOT>` + .. versionadded:: 3.25 - However, this is not sufficient in certain case, where for instance your - MEX file is linking against libraries that are already loaded by Matlab, - even if those libraries have different SONAMES. - A possible solution is to hide the symbols of the libraries to which the - MEX target is linking to. This can be achieved in GNU GCC compilers with - the linker option ``-Wl,--exclude-libs,ALL``. + Default value for the ``Matlab_ROOT_DIR`` variable, the root of the + MATLAB installation. -**Tests using GPU resources** - in case your MEX file is using the GPU and - in order to be able to run unit tests on this MEX file, the GPU resources - should be properly released by Matlab. A possible solution is to make - Matlab aware of the use of the GPU resources in the session, which can be - performed by a command such as ``D = gpuDevice()`` at the beginning of - the test script (or via a fixture). +``Matlab_ROOT_DIR`` + .. versionadded:: 3.3 + + The root folder of the MATLAB installation. If set before the call to + :command:`find_package`, the module will look for the components in that + path. If not set, then an automatic search of MATLAB will be performed. + If set, it should point to a valid version of MATLAB. + + This variable may be specified in order to give the path of the desired + MATLAB version. Otherwise, the behavior is platform specific: + + * Windows: The installed versions of MATLAB/MCR are retrieved from the + Windows registry. The ``REGISTRY_VIEW`` argument may optionally be + specified to manually control whether 32bit or 64bit versions shall be + searched for. + * macOS: The installed versions of MATLAB/MCR are given by the MATLAB + default installation paths under ``$HOME/Applications`` and + ``/Applications``. If no such application is found, it falls back to + the one that might be accessible from the ``PATH``. + * Unix: The desired MATLAB should be accessible from the ``PATH``. This + does not work for MCR installation and ``Matlab_ROOT_DIR`` should be + specified on this platform. + +``MATLAB_FIND_DEBUG`` + .. versionadded:: 3.3 + + If set to a boolean true, additional debug information is outputted to + the console, such as the lookup of MATLAB and the intermediate + configuration steps. + +``MATLAB_ADDITIONAL_VERSIONS`` + .. versionadded:: 3.3 + + If set, it specifies additional versions of MATLAB for the automatic + retrieval of the installed versions that may be handled and looked for. + + The mapping of the release names and the version of MATLAB is performed + by defining pairs (name, version). The variable should be a list of + strings, organized by pairs of release name and versions, such as + follows: + + .. code-block:: cmake + + set( + MATLAB_ADDITIONAL_VERSIONS + "release_name1=corresponding_version1" + "release_name2=corresponding_version2" + # ... + ) + find_package(Matlab) -Reference -^^^^^^^^^ + Example: -.. variable:: Matlab_ROOT_DIR + .. code-block:: cmake - The root folder of the Matlab installation. If set before the call to - :command:`find_package`, the module will look for the components in that - path. If not set, then an automatic search of Matlab - will be performed. If set, it should point to a valid version of Matlab. + set( + MATLAB_ADDITIONAL_VERSIONS + "R2013b=8.2" + "R2013a=8.1" + "R2012b=8.0" + # ... + ) -.. variable:: MATLAB_FIND_DEBUG + find_package(Matlab) - If set, the lookup of Matlab and the intermediate configuration steps are - outputted to the console. + The order of entries in this list matters when several versions of MATLAB + are installed. The priority is set according to the ordering in this + list. -.. variable:: MATLAB_ADDITIONAL_VERSIONS +Commands +^^^^^^^^ - If set, specifies additional versions of Matlab that may be looked for. - The variable should be a list of strings, organized by pairs of release - name and versions, such as follows:: +This module provides the following commands: - set(MATLAB_ADDITIONAL_VERSIONS - "release_name1=corresponding_version1" - "release_name2=corresponding_version2" - ... - ) +* :command:`matlab_get_version_from_release_name` +* :command:`matlab_get_release_name_from_version` +* :command:`matlab_get_version_from_matlab_run` +* :command:`matlab_extract_all_installed_versions_from_registry` +* :command:`matlab_get_all_valid_matlab_roots_from_registry` +* :command:`matlab_add_mex` +* :command:`matlab_get_mex_suffix` +* :command:`matlab_add_unit_test` - Example:: +.. command:: matlab_get_version_from_release_name - set(MATLAB_ADDITIONAL_VERSIONS - "R2013b=8.2" - "R2013a=8.1" - "R2012b=8.0") + .. versionadded:: 3.3 + + Returns the version of MATLAB from a release name: + + .. code-block:: cmake + + matlab_get_version_from_release_name( ) + + The arguments are: + + ```` + Input release name string (e.g. ``R2023b``). + + ```` + The name of the variable in which to store the version of MATLAB. The + output result is e.g. ``23.2.0``. + + .. note:: + + This command provides correct versions mappings for MATLAB but not MCR. + +.. command:: matlab_get_release_name_from_version + + .. versionadded:: 3.3 + + Returns the release name from the version of MATLAB: - The order of entries in this list matters when several versions of - Matlab are installed. The priority is set according to the ordering in - this list. + .. code-block:: cmake + + matlab_get_release_name_from_version( ) + + The arguments are: + + ```` + Input MATLAB version string (e.g. ``23.2.0``). + + ```` + The name of the variable in which to store the MATLAB release name. The + output result is e.g. ``R2023b``. + + .. note:: + + This command provides correct version mappings for MATLAB but not MCR. + +.. command:: matlab_get_version_from_matlab_run + + .. versionadded:: 3.3 + + Runs the specified MATLAB program and extracts the version of MATLAB/MCR, + given the full directory of the MATLAB/MCR installation path: + + .. code-block:: cmake + + matlab_get_version_from_matlab_run( ) + + The arguments are: + + ```` + The path to the ``matlab`` binary executable. + + ```` + The name of the variable in which a list of extracted MATLAB versions + are stored. + + If the path provided for the MATLAB installation points to an MCR + installation, the version is extracted from the installed files. + +.. command:: matlab_extract_all_installed_versions_from_registry + + .. versionadded:: 3.3 + + Parses the Windows registry and finds all installed MATLAB versions: + + .. signature:: + matlab_extract_all_installed_versions_from_registry( + [REGISTRY_VIEW ]) + :target: matlab_extract_all_installed_versions_from_registry-keyword + + The arguments are: + + ```` + The name of the variable in which to store the list of all MATLAB + versions found. + + ``REGISTRY_VIEW `` + .. versionadded:: 3.30 + + Optional registry view argument that provides a more precise interface + on how to interact with the Windows Registry. The argument is passed + (or omitted) to :command:`cmake_host_system_information` without + further checks or modification. For example, ```` value can be + one of ``64``, ``32``, ``64_32``, ``32_64``, ``HOST``, ``TARGET``, + ``BOTH``. + + The old signature is: + + .. signature:: + matlab_extract_all_installed_versions_from_registry( ) + :target: matlab_extract_all_installed_versions_from_registry-positional + + The arguments are: + + ```` + Boolean whether to search for the 64-bit version of MATLAB. If set + to boolean true, 64-bit registry view will be searched. If set to + boolean false, 32-bit registry view will be searched. For finer + control, use the above signature. + + ```` + The name of the variable in which to store the list of all MATLAB + versions found. + + This command is available on Windows only. The part of the registry + parsed is dependent on the host processor. + + The returned list contains all versions under + ``HKLM\SOFTWARE\Mathworks\MATLAB``, + ``HKLM\SOFTWARE\Mathworks\MATLAB Runtime`` and + ``HKLM\SOFTWARE\Mathworks\MATLAB Compiler Runtime`` or an empty list in + case an error occurred (or nothing found). + + .. note:: + + Only the versions are provided. No check is made over the existence of + the installation referenced in the registry. + +.. command:: matlab_get_all_valid_matlab_roots_from_registry + + .. versionadded:: 3.3 + + Returns all the possible MATLAB or MCR paths, according to a previously + given list: + + .. code-block:: cmake + + matlab_get_all_valid_matlab_roots_from_registry( + + + [REGISTRY_VIEW ] + ) + + This command populates the MATLAB root with valid versions of MATLAB or + MATLAB Runtime (MCR) and is mainly useful for the searching of all + possible MATLAB installations. Only the existing/accessible paths are + kept. + + The arguments are: + + ```` + A :ref:`semicolon-separated list ` of each of the + MATLAB or MCR installations. Specify it as a single string value. + + ```` + The name of the variable in which to store a list of locations of each + of the MATLAB or MCR installations. + + The value of this variable is organized in triplets + ``(type,version_number,matlab_root_path)``, where ``type`` indicates + either ``MATLAB`` or ``MCR``. + + ``REGISTRY_VIEW `` + .. versionadded:: 3.30 + + Optional registry view argument that provides a more precise interface + on how to interact with the Windows Registry. The argument is passed + (or omitted) to :command:`cmake_host_system_information` without + further checks or modification. For example, ```` value can be + one of ``64``, ``32``, ``64_32``, ``32_64``, ``HOST``, ``TARGET``, + ``BOTH``. + +.. command:: matlab_add_mex + + .. versionadded:: 3.3 + + Adds a target that compiles MATLAB MEX target file: + + .. code-block:: cmake + + matlab_add_mex( + NAME + [EXECUTABLE | MODULE | SHARED] + SRC ... + [OUTPUT_NAME ] + [DOCUMENTATION ] + [LINK_TO ...] + [R2017b | R2018a] + [EXCLUDE_FROM_ALL] + [NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES] + [...] + ) + + This commands compiles the given sources with the current tool-chain in + order to produce a MEX file. The final name of the produced output may + be specified, as well as additional link libraries, and a documentation + entry for the MEX file. Remaining arguments of the call are passed to + the :command:`add_library` or :command:`add_executable` command. + + The arguments are: + + ``NAME `` + The name of the target. + + ``SRC ...`` + One or more source files to be compiled. + + ``LINK_TO ...`` + A list of additional link dependencies. The target links to ``libmex`` + and ``libmx`` by default, unless the + ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` option is passed. + + ``OUTPUT_NAME `` + If given, overrides the default name. The default name is the name of + the target without any prefix and with ``Matlab_MEX_EXTENSION`` suffix. + + ``DOCUMENTATION `` + If given, the ```` will be considered as being the documentation + file for the MEX file. This file is copied into the same folder without + any processing, with the same name as the final MEX file, and with + extension ``.m``. In that case, typing ``help `` in MATLAB + prints the documentation contained in this file. + + The documentation file is not processed and should be in the following + format: + + .. code-block:: matlab + + % This is the documentation + function ret = mex_target_output_name(input1) + + ``R2017b`` or ``R2018a`` + .. versionadded:: 3.14 + + May be given to specify the version of the C API + to use: ``R2017b`` specifies the traditional (separate complex) C API, + and corresponds to the ``-R2017b`` flag for the ``mex`` command. + ``R2018a`` specifies the new interleaved complex C API, and corresponds + to the ``-R2018a`` flag for the ``mex`` command. Ignored for MATLAB + versions prior to R2018a. Defaults to ``R2017b``. + + ``MODULE`` or ``SHARED`` + .. versionadded:: 3.7 + + May be given to specify the type of library to be created. + + ``EXECUTABLE`` + .. versionadded:: 3.7 + + May be given to create an executable instead of a library. If no type + is given explicitly, the default type is ``SHARED``. + + ``EXCLUDE_FROM_ALL`` + This option has the same meaning as the :prop_tgt:`EXCLUDE_FROM_ALL` + target property and is forwarded to the :command:`add_library`, or + :command:`add_executable` command. + + ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` + .. versionadded:: 3.24 + + This option permits to disable the automatic linking of MATLAB + libraries, so that only the libraries that are actually required can be + linked via the ``LINK_TO`` option. + +.. command:: matlab_get_mex_suffix + + .. versionadded:: 3.3 + + Returns the extension to be used for the MEX files (the suffix): + + .. code-block:: cmake + + matlab_get_mex_suffix( ) + + The arguments are: + + ```` + The root of MATLAB/MCR installation. For example, the value of the + ``Matlab_ROOT_DIR`` variable. + + ```` + The name of the variable in which the suffix will be returned. + + This command is platform and architecture dependent. It should not be + called before the appropriate MATLAB root has been found. + +.. command:: matlab_add_unit_test + + .. versionadded:: 3.3 + + Adds a MATLAB unit test file to the project's test set of CMake/CTest: + + .. code-block:: cmake + + matlab_add_unit_test( + NAME + UNITTEST_FILE + [CUSTOM_TEST_COMMAND ] + [UNITTEST_PRECOMMAND ] + [TIMEOUT ] + [ADDITIONAL_PATH ...] + [MATLAB_ADDITIONAL_STARTUP_OPTIONS ...] + [TEST_ARGS ...] + [NO_UNITTEST_FRAMEWORK] + [WORKING_DIRECTORY ] + ) + + By default, the MATLAB unit test framework will be used (>= 2013a) to run + the added MATLAB script, but regular ``.m`` files returning an exit code + can be used as well (0 indicating a success). + + This command requires the component ``MAIN_PROGRAM`` and hence is not + available for an MCR installation. + + The unit test uses the MATLAB unittest framework (default, available + starting MATLAB 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK`` + is given. + + The command expects one MATLAB test script file to be given. + In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file + should contain the script to be run, plus an exit command with the exit + value. This exit value will be passed to the ctest framework (0 success, + non 0 failure). Additional arguments accepted by :command:`add_test` can + be passed through ``TEST_ARGS`` (e.g. ``CONFIGURATIONS ...``). + + The arguments are: + + ``NAME `` + The name of the unittest in ctest. + + ``UNITTEST_FILE `` + The MATLAB unittest file. Its path will be automatically added to the + MATLAB path. + + ``CUSTOM_TEST_COMMAND `` + MATLAB script command to run as the test. + If this is not set, then the following is run: + ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))`` where + ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension. + + ``UNITTEST_PRECOMMAND `` + MATLAB script command to be ran before the file + containing the test (e.g. GPU device initialization based on CMake + variables). + + ``TIMEOUT `` + The test timeout in seconds. Defaults to 180 seconds as the + MATLAB unit test may hang. + + ``ADDITIONAL_PATH ...`` + A list of paths to add to the MATLAB path prior to running the unit + test. + + ``MATLAB_ADDITIONAL_STARTUP_OPTIONS `` + A list of additional option in order to run MATLAB from the command + line. The ``-nosplash``, ``-nodesktop``, and ``-nodisplay`` options + are always added automatically. + + ``TEST_ARGS ...`` + Additional options provided to the add_test command. These + options are added to the default options (e.g. ``CONFIGURATIONS Release``). + + ``NO_UNITTEST_FRAMEWORK`` + When set, indicates that the test should not + use the unittest framework of MATLAB (available for versions >= R2013a). + + ``WORKING_DIRECTORY `` + This will be the working directory for the test. If specified it will + also be the output directory used for the log file of the test run. + If not specified the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` + will be used as the working directory and the log location. + +Known Issues +^^^^^^^^^^^^ + +**Symbol clash in a MEX target** + By default, every symbol inside a MEX + file defined with the command :command:`matlab_add_mex` have hidden + visibility, except for the entry point. This is the default behavior of + the MEX compiler, which lowers the risk of symbol collision between the + libraries shipped with MATLAB, and the libraries to which the MEX file is + linking to. This is also the default on Windows platforms. + + However, this is not sufficient in certain case, where for instance the + MEX file is linking against libraries that are already loaded by MATLAB, + even if those libraries have different SONAMES. + A possible solution is to hide the symbols of the libraries to which the + MEX target is linking to. This can be achieved in GNU GCC compilers with + the linker option ``-Wl,--exclude-libs,ALL``. + +**Tests using GPU resources** + In case the MEX file is using the GPU and in order to be able to run unit + tests on this MEX file, the GPU resources should be properly released by + MATLAB. A possible solution is to make MATLAB aware of the use of the + GPU resources in the session, which can be performed by a command, such + as ``D = gpuDevice()``, at the beginning of the test script (or via a + fixture). + +Examples +^^^^^^^^ + +Finding MATLAB and linking imported target to a project target: + +.. code-block:: cmake + + find_package(Matlab) + target_link_libraries(example PRIVATE Matlab::mx) #]=======================================================================] cmake_policy(PUSH) -cmake_policy(SET CMP0057 NEW) # if IN_LIST +cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_ set(_FindMatlab_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}") -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) -include(CheckCXXCompilerFlag) -include(CheckCCompilerFlag) +include(FindPackageHandleStandardArgs) +if(NOT WIN32 AND NOT APPLE AND NOT Threads_FOUND + AND (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)) + # MEX files use pthread if available + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads) +endif() # The currently supported versions. Other version can be added by the user by # providing MATLAB_ADDITIONAL_VERSIONS @@ -288,6 +789,12 @@ if(NOT MATLAB_ADDITIONAL_VERSIONS) endif() set(MATLAB_VERSIONS_MAPPING + "R2025a=25.1" + "R2024b=24.2" + "R2024a=24.1" + "R2023b=23.2" + "R2023a=9.14" + "R2022b=9.13" "R2022a=9.12" "R2021b=9.11" "R2021a=9.10" @@ -320,18 +827,12 @@ set(MATLAB_VERSIONS_MAPPING # temporary folder for all Matlab runs set(_matlab_temporary_folder ${CMAKE_BINARY_DIR}/Matlab) -if(NOT EXISTS "${_matlab_temporary_folder}") - file(MAKE_DIRECTORY "${_matlab_temporary_folder}") -endif() - -#[=======================================================================[.rst: -.. command:: matlab_get_version_from_release_name +file(MAKE_DIRECTORY "${_matlab_temporary_folder}") - Returns the version of Matlab (17.58) from a release name (R2017k) -#]=======================================================================] +# Public. macro(matlab_get_version_from_release_name release_name version_name) - string(REGEX MATCHALL "${release_name}=([0-9]+\\.?[0-9]*)" _matched ${MATLAB_VERSIONS_MAPPING}) + string(REGEX MATCHALL "${release_name}=([0-9]+\\.[0-9]+)" _matched ${MATLAB_VERSIONS_MAPPING}) set(${version_name} "") if(NOT _matched STREQUAL "") @@ -343,331 +844,213 @@ macro(matlab_get_version_from_release_name release_name version_name) endmacro() +# Public. +function(matlab_get_release_name_from_version version release_name) + # only the major.minor version is used + string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*" "\\1" version "${version}") - - -#[=======================================================================[.rst: -.. command:: matlab_get_release_name_from_version - - Returns the release name (R2017k) from the version of Matlab (17.58) -#]=======================================================================] -macro(matlab_get_release_name_from_version version release_name) - - set(${release_name} "") foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) - string(REGEX MATCHALL "(.+)=${version}" _matched ${_var}) - if(NOT _matched STREQUAL "") - set(${release_name} ${CMAKE_MATCH_1}) - break() + if(_var MATCHES "(.+)=${version}") + set(${release_name} ${CMAKE_MATCH_1} PARENT_SCOPE) + return() endif() - endforeach(_var) - - unset(_var) - unset(_matched) - if(${release_name} STREQUAL "") - message(WARNING "[MATLAB] The version ${version} is not registered") - endif() - -endmacro() - - + endforeach() + message(WARNING "[MATLAB] The version ${version} is not registered") +endfunction() -# extracts all the supported release names (R2017k...) of Matlab +# extracts all the supported release names (R2022b...) of Matlab # internal use macro(matlab_get_supported_releases list_releases) set(${list_releases}) foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) - string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var}) + string(REGEX MATCHALL "(.+)=([0-9]+\\.[0-9]+)" _matched ${_var}) if(NOT _matched STREQUAL "") list(APPEND ${list_releases} ${CMAKE_MATCH_1}) endif() unset(_matched) unset(CMAKE_MATCH_1) - endforeach(_var) + endforeach() unset(_var) endmacro() - - # extracts all the supported versions of Matlab # internal use macro(matlab_get_supported_versions list_versions) set(${list_versions}) foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING) - string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var}) + string(REGEX MATCHALL "(.+)=([0-9]+\\.[0-9]+)" _matched ${_var}) if(NOT _matched STREQUAL "") list(APPEND ${list_versions} ${CMAKE_MATCH_2}) endif() unset(_matched) unset(CMAKE_MATCH_1) - endforeach(_var) + endforeach() unset(_var) endmacro() - -#[=======================================================================[.rst: -.. command:: matlab_extract_all_installed_versions_from_registry - - This function parses the registry and founds the Matlab versions that are - installed. The found versions are returned in `matlab_versions`. - Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for - The returned list contains all versions under - ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` and - ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Runtime`` or an empty list in case an - error occurred (or nothing found). - - .. note:: - - Only the versions are provided. No check is made over the existence of the - installation referenced in the registry, - -#]=======================================================================] -function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions) +# Public. +function(matlab_extract_all_installed_versions_from_registry win64_or_matlab_versions) if(NOT CMAKE_HOST_WIN32) - message(FATAL_ERROR "[MATLAB] This macro can only be called by a windows host (call to reg.exe)") + message(FATAL_ERROR "[MATLAB] This function can only be called by a Windows host") endif() - if(${win64} AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "64") - set(APPEND_REG "/reg:64") + set(_registry_view_args) + if("${ARGC}" EQUAL "2") + # Old API: + if(${win64_or_matlab_versions}) + set(_registry_view_args VIEW 64) + else() + set(_registry_view_args VIEW 32) + endif() + set(matlab_versions ${ARGV1}) else() - set(APPEND_REG "/reg:32") + # New API: [REGISTRY_VIEW ] + set(matlab_versions ${win64_or_matlab_versions}) + cmake_parse_arguments(_Matlab "" "REGISTRY_VIEW" "" ${ARGN}) + if(_Matlab_REGISTRY_VIEW) + set(_registry_view_args VIEW "${_Matlab_REGISTRY_VIEW}") + endif() + endif() + + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Extracting MATLAB versions with registry view args '${_registry_view_args}'") endif() set(matlabs_from_registry) foreach(_installation_type IN ITEMS "MATLAB" "MATLAB Runtime" "MATLAB Compiler Runtime") - # /reg:64 should be added on 64 bits capable OSs in order to enable the - # redirection of 64 bits applications - execute_process( - COMMAND reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\${_installation_type}" /f * /k ${APPEND_REG} - RESULT_VARIABLE resultMatlab - OUTPUT_VARIABLE varMatlab - ERROR_VARIABLE errMatlab - INPUT_FILE NUL - ) - - - if(resultMatlab EQUAL 0) + cmake_host_system_information(RESULT _reg + QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/${_installation_type}" + SUBKEYS + ${_registry_view_args} + ) - string( - REGEX MATCHALL "${_installation_type}\\\\([0-9]+(\\.[0-9]+)?)" - matlab_versions_regex ${varMatlab}) - - foreach(match IN LISTS matlab_versions_regex) - string( - REGEX MATCH "${_installation_type}\\\\(([0-9]+)(\\.([0-9]+))?)" - current_match ${match}) - - set(_matlab_current_version ${CMAKE_MATCH_1}) - set(current_matlab_version_major ${CMAKE_MATCH_2}) - set(current_matlab_version_minor ${CMAKE_MATCH_4}) - if(NOT current_matlab_version_minor) - set(current_matlab_version_minor "0") - endif() + string(REGEX MATCHALL "([0-9]+(\\.[0-9]+)+)" _versions_regex "${_reg}") - list(APPEND matlabs_from_registry ${_matlab_current_version}) - unset(_matlab_current_version) - endforeach() + list(APPEND matlabs_from_registry ${_versions_regex}) - endif() endforeach() if(matlabs_from_registry) list(REMOVE_DUPLICATES matlabs_from_registry) - if(${CMAKE_VERSION} VERSION_LESS "3.18.0") - message("Please consider to switch to CMake 3.18.0 as this sorting may select wrong Matlab version: ${matlabs_from_registry}") - list(SORT matlabs_from_registry) - else() - list(SORT matlabs_from_registry COMPARE NATURAL) - endif() - list(REVERSE matlabs_from_registry) + list(SORT matlabs_from_registry COMPARE NATURAL ORDER DESCENDING) endif() set(${matlab_versions} ${matlabs_from_registry} PARENT_SCOPE) endfunction() - - # (internal) -macro(extract_matlab_versions_from_registry_brute_force matlab_versions) - # get the supported versions - set(matlab_supported_versions) - matlab_get_supported_versions(matlab_supported_versions) - - - # this is a manual population of the versions we want to look for - # this can be done as is, but preferably with the call to - # matlab_get_supported_versions and variable - - # populating the versions we want to look for - # set(matlab_supported_versions) - - # # Matlab 7 - # set(matlab_major 7) - # foreach(current_matlab_minor RANGE 4 20) - # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") - # endforeach(current_matlab_minor) - - # # Matlab 8 - # set(matlab_major 8) - # foreach(current_matlab_minor RANGE 0 5) - # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") - # endforeach(current_matlab_minor) - - # # taking into account the possible additional versions provided by the user - # if(DEFINED MATLAB_ADDITIONAL_VERSIONS) - # list(APPEND matlab_supported_versions MATLAB_ADDITIONAL_VERSIONS) - # endif() +macro(extract_matlab_versions_from_registry_brute_force matlab_versions) + # get the supported versions + set(matlab_supported_versions) + matlab_get_supported_versions(matlab_supported_versions) # we order from more recent to older if(matlab_supported_versions) list(REMOVE_DUPLICATES matlab_supported_versions) - list(SORT matlab_supported_versions COMPARE NATURAL) - list(REVERSE matlab_supported_versions) + list(SORT matlab_supported_versions COMPARE NATURAL ORDER DESCENDING) endif() set(${matlab_versions} ${matlab_supported_versions}) endmacro() - - - -#[=======================================================================[.rst: -.. command:: matlab_get_all_valid_matlab_roots_from_registry - - Populates the Matlab root with valid versions of Matlab or - Matlab Runtime (MCR). - The returned matlab_roots is organized in triplets - ``(type,version_number,matlab_root_path)``, where ``type`` - indicates either ``MATLAB`` or ``MCR``. - - :: - - matlab_get_all_valid_matlab_roots_from_registry( - matlab_versions - matlab_roots) - - ``matlab_versions`` - the versions of each of the Matlab or MCR installations - ``matlab_roots`` - the location of each of the Matlab or MCR installations -#]=======================================================================] +# Public. function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots) # The matlab_versions comes either from # extract_matlab_versions_from_registry_brute_force or # matlab_extract_all_installed_versions_from_registry. - set(_matlab_roots_list ) - # check for Matlab installations - foreach(_matlab_current_version ${matlab_versions}) - get_filename_component( - current_MATLAB_ROOT - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]" - ABSOLUTE) - - if(EXISTS "${current_MATLAB_ROOT}") - list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT}) - endif() - - endforeach() + cmake_parse_arguments(_Matlab "" "REGISTRY_VIEW" "" ${ARGN}) + set(_registry_view_args) + if(_Matlab_REGISTRY_VIEW) + set(_registry_view_args VIEW "${_Matlab_REGISTRY_VIEW}") + endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Getting MATLAB roots with registry view args '${_registry_view_args}'") + endif() - # Check for MCR installations - foreach(_matlab_current_version ${matlab_versions}) - get_filename_component( - current_MATLAB_ROOT - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Runtime\\${_matlab_current_version};MATLABROOT]" - ABSOLUTE) + # Mostly the major.minor version is used in Mathworks Windows Registry keys. + # If the patch is not zero, major.minor.patch is used. + list(TRANSFORM matlab_versions REPLACE "^([0-9]+\\.[0-9]+(\\.[1-9][0-9]*)?).*" "\\1") - # remove the dot - string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}") + set(_matlab_roots_list ) + # check for Matlab installations + foreach(_matlab_current_version IN LISTS matlab_versions) + cmake_host_system_information(RESULT current_MATLAB_ROOT + QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/MATLAB/${_matlab_current_version}" + VALUE "MATLABROOT" + ${_registry_view_args} + ) + cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT) - if(EXISTS "${current_MATLAB_ROOT}") - list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}") + if(IS_DIRECTORY "${current_MATLAB_ROOT}") + _Matlab_VersionInfoXML("${current_MATLAB_ROOT}" _matlab_version_tmp) + if("${_matlab_version_tmp}" STREQUAL "unknown") + set(_matlab_version_tmp ${_matlab_current_version}) + endif() + list(APPEND _matlab_roots_list "MATLAB" ${_matlab_version_tmp} ${current_MATLAB_ROOT}) endif() endforeach() - # Check for old MCR installations - foreach(_matlab_current_version ${matlab_versions}) - get_filename_component( - current_MATLAB_ROOT - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Compiler Runtime\\${_matlab_current_version};MATLABROOT]" - ABSOLUTE) - - # remove the dot - string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}") + # Check for MCR installations + foreach(_installation_type IN ITEMS "MATLAB Runtime" "MATLAB Compiler Runtime") + foreach(_matlab_current_version IN LISTS matlab_versions) + cmake_host_system_information(RESULT current_MATLAB_ROOT + QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/${_installation_type}/${_matlab_current_version}" + VALUE "MATLABROOT" + ${_registry_view_args} + ) + cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT) - if(EXISTS "${current_MATLAB_ROOT}") - list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}") - endif() + # remove the dot + string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}") + if(IS_DIRECTORY "${current_MATLAB_ROOT}") + if(IS_DIRECTORY "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}") + cmake_path(APPEND current_MATLAB_ROOT "v${_matlab_current_version_without_dot}") + endif() + _Matlab_VersionInfoXML("${current_MATLAB_ROOT}" _matlab_version_tmp) + if("${_matlab_version_tmp}" STREQUAL "unknown") + set(_matlab_version_tmp ${_matlab_current_version}) + endif() + list(APPEND _matlab_roots_list "MCR" ${_matlab_version_tmp} "${current_MATLAB_ROOT}") + endif() + endforeach() endforeach() set(${matlab_roots} ${_matlab_roots_list} PARENT_SCOPE) endfunction() -#[=======================================================================[.rst: -.. command:: matlab_get_mex_suffix - - Returns the extension of the mex files (the suffixes). - This function should not be called before the appropriate Matlab root has - been found. - - :: - - matlab_get_mex_suffix( - matlab_root - mex_suffix) - - ``matlab_root`` - the root of the Matlab/MCR installation - ``mex_suffix`` - the variable name in which the suffix will be returned. -#]=======================================================================] +# Public. function(matlab_get_mex_suffix matlab_root mex_suffix) - # todo setup the extension properly. Currently I do not know if this is - # sufficient for all win32 distributions. - # there is also CMAKE_EXECUTABLE_SUFFIX that could be tweaked + # find_program does not consider script suffix .bat for Matlab mexext.bat on Windows set(mexext_suffix "") if(WIN32) - list(APPEND mexext_suffix ".bat") + set(mexext_suffix ".bat") endif() - # we first try without suffix, since cmake does not understand a list with - # one empty string element find_program( Matlab_MEXEXTENSIONS_PROG - NAMES mexext + NAMES mexext mexext${mexext_suffix} PATHS ${matlab_root}/bin DOC "Matlab MEX extension provider" NO_DEFAULT_PATH ) - foreach(current_mexext_suffix IN LISTS mexext_suffix) - if(NOT DEFINED Matlab_MEXEXTENSIONS_PROG OR NOT Matlab_MEXEXTENSIONS_PROG) - # this call should populate the cache automatically - find_program( - Matlab_MEXEXTENSIONS_PROG - "mexext${current_mexext_suffix}" - PATHS ${matlab_root}/bin - DOC "Matlab MEX extension provider" - NO_DEFAULT_PATH - ) - endif() - endforeach(current_mexext_suffix) if(MATLAB_FIND_DEBUG) message(STATUS "[MATLAB] Determining mex files extensions from '${matlab_root}/bin' with program '${Matlab_MEXEXTENSIONS_PROG}'") endif() # the program has been found? - if((NOT Matlab_MEXEXTENSIONS_PROG) OR (NOT EXISTS ${Matlab_MEXEXTENSIONS_PROG})) + if(NOT Matlab_MEXEXTENSIONS_PROG) if(MATLAB_FIND_DEBUG) message(WARNING "[MATLAB] Cannot found mexext program. Matlab root is ${matlab_root}") endif() @@ -684,23 +1067,23 @@ function(matlab_get_mex_suffix matlab_root mex_suffix) set(devnull INPUT_FILE NUL) endif() + set(_arch) if(WIN32) # this environment variable is used to determine the arch on Windows if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(ENV{MATLAB_ARCH} "win64") + set(_arch "MATLAB_ARCH=win64") else() - set(ENV{MATLAB_ARCH} "win32") + set(_arch "MATLAB_ARCH=win32") endif() endif() # this is the preferred way. If this does not work properly (eg. MCR on Windows), then we use our own knowledge execute_process( - COMMAND ${Matlab_MEXEXTENSIONS_PROG} + COMMAND ${CMAKE_COMMAND} -E env ${_arch} ${Matlab_MEXEXTENSIONS_PROG} OUTPUT_VARIABLE _matlab_mex_extension ERROR_VARIABLE _matlab_mex_extension_error OUTPUT_STRIP_TRAILING_WHITESPACE ${devnull}) - unset(ENV{MATLAB_ARCH}) if(_matlab_mex_extension_error) if(WIN32) @@ -718,31 +1101,10 @@ function(matlab_get_mex_suffix matlab_root mex_suffix) message(STATUS "[MATLAB] '${Matlab_MEXEXTENSIONS_PROG}' : determined extension '${_matlab_mex_extension}' and error string is '${_matlab_mex_extension_error}'") endif() - unset(Matlab_MEXEXTENSIONS_PROG CACHE) set(${mex_suffix} ${_matlab_mex_extension} PARENT_SCOPE) endfunction() - - - -#[=======================================================================[.rst: -.. command:: matlab_get_version_from_matlab_run - - This function runs Matlab program specified on arguments and extracts its - version. If the path provided for the Matlab installation points to an MCR - installation, the version is extracted from the installed files. - - :: - - matlab_get_version_from_matlab_run( - matlab_binary_path - matlab_list_versions) - - ``matlab_binary_path`` - the location of the `matlab` binary executable - ``matlab_list_versions`` - the version extracted from Matlab -#]=======================================================================] +# Public. function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions) set(${matlab_list_versions} "" PARENT_SCOPE) @@ -848,6 +1210,15 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve endif() endif() + if(NOT EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") + # last resort check as some HPC with "module load matlab" not enacted fail to catch in earlier checks + # and error CMake configure even if find_package(Matlab) is not REQUIRED + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Unable to determine the version of Matlab. The version log file does not exist.") + endif() + return() + endif() + # if successful, read back the log file(READ "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp" _matlab_version_from_cmd) file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp") @@ -865,7 +1236,7 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve string(SUBSTRING "${_matlab_version_from_cmd}" ${index} -1 substring_ans) string( - REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)?)" + REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)+)" matlab_versions_regex ${substring_ans}) foreach(match IN LISTS matlab_versions_regex) @@ -884,77 +1255,7 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve endfunction() -#[=======================================================================[.rst: -.. command:: matlab_add_unit_test - - Adds a Matlab unit test to the test set of cmake/ctest. - This command requires the component ``MAIN_PROGRAM`` and hence is not - available for an MCR installation. - - The unit test uses the Matlab unittest framework (default, available - starting Matlab 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK`` - is given. - - The function expects one Matlab test script file to be given. - In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file - should contain the script to be run, plus an exit command with the exit - value. This exit value will be passed to the ctest framework (0 success, - non 0 failure). Additional arguments accepted by :command:`add_test` can be - passed through ``TEST_ARGS`` (eg. ``CONFIGURATION ...``). - - :: - - matlab_add_unit_test( - NAME - UNITTEST_FILE matlab_file_containing_unittest.m - [CUSTOM_TEST_COMMAND matlab_command_to_run_as_test] - [UNITTEST_PRECOMMAND matlab_command_to_run] - [TIMEOUT timeout] - [ADDITIONAL_PATH path1 [path2 ...]] - [MATLAB_ADDITIONAL_STARTUP_OPTIONS option1 [option2 ...]] - [TEST_ARGS arg1 [arg2 ...]] - [NO_UNITTEST_FRAMEWORK] - ) - - The function arguments are: - - ``NAME`` - name of the unittest in ctest. - ``UNITTEST_FILE`` - the matlab unittest file. Its path will be automatically - added to the Matlab path. - ``CUSTOM_TEST_COMMAND`` - Matlab script command to run as the test. - If this is not set, then the following is run: - ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))`` - where ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension. - ``UNITTEST_PRECOMMAND`` - Matlab script command to be ran before the file - containing the test (eg. GPU device initialization based on CMake - variables). - ``TIMEOUT`` - the test timeout in seconds. Defaults to 180 seconds as the - Matlab unit test may hang. - ``ADDITIONAL_PATH`` - a list of paths to add to the Matlab path prior to - running the unit test. - ``MATLAB_ADDITIONAL_STARTUP_OPTIONS`` - a list of additional option in order - to run Matlab from the command line. - ``-nosplash -nodesktop -nodisplay`` are always added. - ``TEST_ARGS`` - Additional options provided to the add_test command. These - options are added to the default options (eg. "CONFIGURATIONS Release") - ``NO_UNITTEST_FRAMEWORK`` - when set, indicates that the test should not - use the unittest framework of Matlab (available for versions >= R2013a). - ``WORKING_DIRECTORY`` - This will be the working directory for the test. If specified it will - also be the output directory used for the log file of the test run. - If not specified the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` will - be used as the working directory and the log location. - -#]=======================================================================] +# Public. function(matlab_add_unit_test) if(NOT Matlab_MAIN_PROGRAM) @@ -974,7 +1275,7 @@ function(matlab_add_unit_test) endif() # The option to run a batch program with MATLAB changes depending on the MATLAB version - # For MATLAB before R2019a (9.6), the only supported option is -r, afterwords the suggested option + # For MATLAB before R2019a (9.6), the only supported option is -r, afterwards the suggested option # is -batch as -r is deprecated set(maut_BATCH_OPTION "-r") if(NOT (Matlab_VERSION_STRING STREQUAL "")) @@ -983,6 +1284,10 @@ function(matlab_add_unit_test) endif() endif() + # The ${${prefix}_TEST_ARGS} and ${${prefix}_UNPARSED_ARGUMENTS} used below + # should have semicolons escaped, so empty arguments should be preserved. + # There's also no target used for the command, so we don't need to do + # anything here for CMP0178. add_test(NAME ${${prefix}_NAME} COMMAND ${CMAKE_COMMAND} "-Dtest_name=${${prefix}_NAME}" @@ -1003,107 +1308,9 @@ function(matlab_add_unit_test) ) endfunction() - -#[=======================================================================[.rst: -.. command:: matlab_add_mex - - Adds a Matlab MEX target. - This commands compiles the given sources with the current tool-chain in - order to produce a MEX file. The final name of the produced output may be - specified, as well as additional link libraries, and a documentation entry - for the MEX file. Remaining arguments of the call are passed to the - :command:`add_library` or :command:`add_executable` command. - - :: - - matlab_add_mex( - NAME - [EXECUTABLE | MODULE | SHARED] - SRC src1 [src2 ...] - [OUTPUT_NAME output_name] - [DOCUMENTATION file.txt] - [LINK_TO target1 target2 ...] - [R2017b | R2018a] - [EXCLUDE_FROM_ALL] - [NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES] - [...] - ) - - ``NAME`` - name of the target. - ``SRC`` - list of source files. - ``LINK_TO`` - a list of additional link dependencies. The target links to ``libmex`` - and ``libmx`` by default, unless the - ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` option is passed. - ``OUTPUT_NAME`` - if given, overrides the default name. The default name is - the name of the target without any prefix and - with ``Matlab_MEX_EXTENSION`` suffix. - ``DOCUMENTATION`` - if given, the file ``file.txt`` will be considered as - being the documentation file for the MEX file. This file is copied into - the same folder without any processing, with the same name as the final - mex file, and with extension `.m`. In that case, typing ``help `` - in Matlab prints the documentation contained in this file. - ``R2017b`` or ``R2018a`` - .. versionadded:: 3.14 - - May be given to specify the version of the C API - to use: ``R2017b`` specifies the traditional (separate complex) C API, - and corresponds to the ``-R2017b`` flag for the `mex` command. ``R2018a`` - specifies the new interleaved complex C API, and corresponds to the - ``-R2018a`` flag for the `mex` command. Ignored if MATLAB version prior - to R2018a. Defaults to ``R2017b``. - - ``MODULE`` or ``SHARED`` - .. versionadded:: 3.7 - - May be given to specify the type of library to be - created. - - ``EXECUTABLE`` - .. versionadded:: 3.7 - - May be given to create an executable instead of - a library. If no type is given explicitly, the type is ``SHARED``. - ``EXCLUDE_FROM_ALL`` - This option has the same meaning as for :prop_tgt:`EXCLUDE_FROM_ALL` and - is forwarded to :command:`add_library` or :command:`add_executable` - commands. - ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` - .. versionadded:: 3.24 - - This option permits to disable the automatic linking of MATLAB - libraries, so that only the libraries that are actually required can be - linked via the ``LINK_TO`` option. - - The documentation file is not processed and should be in the following - format: - - :: - - % This is the documentation - function ret = mex_target_output_name(input1) - -#]=======================================================================] +# Public. function(matlab_add_mex) - if(NOT WIN32) - # we do not need all this on Windows - # pthread options - if(CMAKE_CXX_COMPILER_LOADED) - check_cxx_compiler_flag(-pthread HAS_MINUS_PTHREAD) - elseif(CMAKE_C_COMPILER_LOADED) - check_c_compiler_flag(-pthread HAS_MINUS_PTHREAD) - endif() - # we should use try_compile instead, the link flags are discarded from - # this compiler_flag function. - #check_cxx_compiler_flag(-Wl,--exclude-libs,ALL HAS_SYMBOL_HIDING_CAPABILITY) - - endif() - set(options EXECUTABLE MODULE SHARED R2017b R2018a EXCLUDE_FROM_ALL NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES) set(oneValueArgs NAME DOCUMENTATION OUTPUT_NAME) set(multiValueArgs LINK_TO SRC) @@ -1120,14 +1327,27 @@ function(matlab_add_mex) endif() if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, add version source file + # Compilers officially supported by Matlab 9.1 (R2016b): + # MinGW 4.9, MSVC 2012, Intel C++ 2013, Xcode 6, GCC 4.9 + # These compilers definitely support the -w flag to suppress warnings. + # Other compilers (Clang) may support the -w flag and can be added here. + set(_Matlab_silenceable_compilers AppleClang Clang GNU Intel IntelLLVM MSVC) + # Add the correct version file depending on which languages are enabled in the project if(CMAKE_C_COMPILER_LOADED) # If C is enabled, use the .c file as it will work fine also with C++ set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/c_mexapi_version.c") + # Silence warnings for version source file + if("${CMAKE_C_COMPILER_ID}" IN_LIST _Matlab_silenceable_compilers) + set_source_files_properties("${MEX_VERSION_FILE}" PROPERTIES COMPILE_OPTIONS -w) + endif() elseif(CMAKE_CXX_COMPILER_LOADED) # If C is not enabled, check if CXX is enabled and use the .cpp file # to avoid that the .c file is silently ignored set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/cpp_mexapi_version.cpp") + if("${CMAKE_CXX_COMPILER_ID}" IN_LIST _Matlab_silenceable_compilers) + set_source_files_properties("${MEX_VERSION_FILE}" PROPERTIES COMPILE_OPTIONS -w) + endif() else() # If neither C or CXX is enabled, warn because we cannot add the source. # TODO: add support for fortran mex files @@ -1174,7 +1394,7 @@ function(matlab_add_mex) ${${prefix}_UNPARSED_ARGUMENTS}) endif() - target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS}) + target_include_directories(${${prefix}_NAME} SYSTEM PRIVATE ${Matlab_INCLUDE_DIRS}) if(NOT ${prefix}_NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES) if(Matlab_HAS_CPP_API) @@ -1213,18 +1433,17 @@ function(matlab_add_mex) if (MSVC) - set(_link_flags "${_link_flags} /EXPORT:mexFunction") + string(APPEND _link_flags " /EXPORT:mexFunction") if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, export version - set(_link_flags "${_link_flags} /EXPORT:mexfilerequiredapiversion") + string(APPEND _link_flags " /EXPORT:mexfilerequiredapiversion") endif() set_property(TARGET ${${prefix}_NAME} APPEND PROPERTY LINK_FLAGS ${_link_flags}) endif() # No other compiler currently supported on Windows. - set_target_properties(${${prefix}_NAME} - PROPERTIES - DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)") + set_property(TARGET ${${prefix}_NAME} PROPERTY + DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)") else() @@ -1250,7 +1469,7 @@ function(matlab_add_mex) if(Matlab_HAS_CPP_API) list(APPEND _ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/cppMexFunction.map) # This one doesn't exist on Linux - set(_link_flags "${_link_flags} -Wl,-U,_mexCreateMexFunction -Wl,-U,_mexDestroyMexFunction -Wl,-U,_mexFunctionAdapter") + string(APPEND _link_flags " -Wl,-U,_mexCreateMexFunction -Wl,-U,_mexDestroyMexFunction -Wl,-U,_mexFunctionAdapter") # On MacOS, the MEX command adds the above, without it the link breaks # because we indiscriminately use "cppMexFunction.map" even for C API MEX-files. endif() @@ -1259,20 +1478,18 @@ function(matlab_add_mex) else() # Linux - if(HAS_MINUS_PTHREAD) - # Apparently, compiling with -pthread generated the proper link flags - # and some defines at compilation - target_compile_options(${${prefix}_NAME} PRIVATE "-pthread") + if(Threads_FOUND) + target_link_libraries(${${prefix}_NAME} Threads::Threads) endif() - set(_link_flags "${_link_flags} -Wl,--as-needed") + string(APPEND _link_flags " -Wl,--as-needed") set(_export_flag_name --version-script) endif() - foreach(_file ${_ver_map_files}) - set(_link_flags "${_link_flags} -Wl,${_export_flag_name},${_file}") + foreach(_file IN LISTS _ver_map_files) + string(APPEND _link_flags " -Wl,${_export_flag_name},${_file}") endforeach() # The `mex` command doesn't add this define. It is specified here in order @@ -1287,7 +1504,6 @@ function(matlab_add_mex) endfunction() - # (internal) # Used to get the version of matlab, using caching. This basically transforms the # output of the root list, with possible unknown version, to a version @@ -1300,10 +1516,14 @@ function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_ve # set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version") #endif() + if(NOT matlab_or_mcr STREQUAL "UNKNOWN") + set(Matlab_OR_MCR_INTERNAL ${matlab_or_mcr} CACHE INTERNAL "Whether Matlab root contains MATLAB or MCR") + endif() + if(NOT matlab_known_version STREQUAL "NOTFOUND") # the version is known, we just return it set(${matlab_final_version} ${matlab_known_version} PARENT_SCOPE) - set(Matlab_VERSION_STRING_INTERNAL ${matlab_known_version} CACHE INTERNAL "Matlab version (automatically determined)" FORCE) + set(Matlab_VERSION_STRING_INTERNAL ${matlab_known_version} CACHE INTERNAL "Matlab version (automatically determined)") return() endif() @@ -1314,7 +1534,7 @@ function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_ve if(EXISTS "${matlab_root}/appdata/version.xml") # we inspect the application version.xml file that contains the product information - file(STRINGS "${matlab_root}/appdata/version.xml" productinfo_string NEWLINE_CONSUME) + file(READ "${matlab_root}/appdata/version.xml" productinfo_string) string(REGEX MATCH "" product_reg_match ${productinfo_string} @@ -1347,25 +1567,26 @@ function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_ve if(NOT _matlab_current_program) set(_find_matlab_options) - if(matlab_root AND EXISTS ${matlab_root}) + if(IS_DIRECTORY "${matlab_root}") set(_find_matlab_options PATHS ${matlab_root} ${matlab_root}/bin NO_DEFAULT_PATH) endif() find_program( _matlab_current_program - matlab + NAMES matlab ${_find_matlab_options} DOC "Matlab main program" ) endif() - if(NOT _matlab_current_program OR NOT EXISTS ${_matlab_current_program}) + if(NOT _matlab_current_program) # if not found, clear the dependent variables if(MATLAB_FIND_DEBUG) message(WARNING "[MATLAB] Cannot find the main matlab program under ${matlab_root}") endif() - set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE) - set(Matlab_VERSION_STRING_INTERNAL "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE) + set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version") + set(Matlab_VERSION_STRING_INTERNAL "" CACHE INTERNAL "internal matlab location for the discovered version") + set(Matlab_OR_MCR_INTERNAL ${matlab_or_mcr} CACHE INTERNAL "Whether Matlab root contains MATLAB or MCR") unset(_matlab_current_program) unset(_matlab_current_program CACHE) return() @@ -1385,10 +1606,16 @@ function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_ve # update the location of the program set(Matlab_PROG_VERSION_STRING_AUTO_DETECT ${_matlab_main_real_path_tmp} - CACHE INTERNAL "internal matlab location for the discovered version" FORCE) + CACHE INTERNAL "internal matlab location for the discovered version") - set(matlab_list_of_all_versions) - matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions) + _Matlab_VersionInfoXML("${matlab_root}" _matlab_version_tmp) + if(NOT "${_matlab_version_tmp}" STREQUAL "unknown") + # at least back to R2016 VersionInfo.xml exists + set(matlab_list_of_all_versions ${_matlab_version_tmp}) + else() + # time consuming, less stable way to find Matlab version by running Matlab + matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions) + endif() list(LENGTH matlab_list_of_all_versions list_of_all_versions_length) if(list_of_all_versions_length GREATER 0) @@ -1398,42 +1625,47 @@ function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_ve endif() # set the version into the cache - set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)" FORCE) + set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)") + set(Matlab_OR_MCR_INTERNAL ${matlab_or_mcr} CACHE INTERNAL "Whether Matlab root contains MATLAB or MCR") # warning, just in case several versions found (should not happen) if((list_of_all_versions_length GREATER 1) AND MATLAB_FIND_DEBUG) message(WARNING "[MATLAB] Found several versions, taking the first one (versions found ${matlab_list_of_all_versions})") endif() - # return the updated value - set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE) - elseif(EXISTS "${matlab_root}/VersionInfo.xml") + else() # MCR # we cannot run anything in order to extract the version. We assume that the file # VersionInfo.xml exists under the MatlabRoot, we look for it and extract the version from there - set(_matlab_version_tmp "unknown") - file(STRINGS "${matlab_root}/VersionInfo.xml" versioninfo_string NEWLINE_CONSUME) - - if(versioninfo_string) - # parses "9.2.0.538062" - string(REGEX MATCH "(.*)" - version_reg_match - ${versioninfo_string} - ) - - if(CMAKE_MATCH_1 MATCHES "(([0-9]+)\\.([0-9]+))[\\.0-9]*") - set(_matlab_version_tmp "${CMAKE_MATCH_1}") - endif() + _Matlab_VersionInfoXML("${matlab_root}" _matlab_version_tmp) + if(NOT "${_matlab_version_tmp}" STREQUAL "unknown") + set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)") + set(Matlab_OR_MCR_INTERNAL ${matlab_or_mcr} CACHE INTERNAL "Whether Matlab root contains MATLAB or MCR") endif() - set(${matlab_final_version} "${_matlab_version_tmp}" PARENT_SCOPE) - set(Matlab_VERSION_STRING_INTERNAL - "${_matlab_version_tmp}" - CACHE INTERNAL "Matlab (MCR) version (automatically determined)" - FORCE) endif() # Matlab or MCR + # return the updated value + set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE) + endfunction() +function(_Matlab_VersionInfoXML matlab_root _version) + + set(_ver "unknown") + + set(_XMLfile ${matlab_root}/VersionInfo.xml) + if(EXISTS ${_XMLfile}) + file(READ ${_XMLfile} versioninfo_string) + + # parses "23.2.0.2365128" + if(versioninfo_string MATCHES "([0-9]+(\\.[0-9]+)+)") + set(_ver "${CMAKE_MATCH_1}") + endif() + endif() + + set(${_version} ${_ver} PARENT_SCOPE) + +endfunction() # Utility function for finding Matlab or MCR on Win32 function(_Matlab_find_instances_win32 matlab_roots) @@ -1444,13 +1676,7 @@ function(_Matlab_find_instances_win32 matlab_roots) # testing if we are able to extract the needed information from the registry set(_matlab_versions_from_registry) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_matlab_win64 ON) - else() - set(_matlab_win64 OFF) - endif() - - matlab_extract_all_installed_versions_from_registry(_matlab_win64 _matlab_versions_from_registry) + matlab_extract_all_installed_versions_from_registry(_matlab_versions_from_registry ${ARGN}) # the returned list is empty, doing the search on all known versions if(NOT _matlab_versions_from_registry) @@ -1461,16 +1687,16 @@ function(_Matlab_find_instances_win32 matlab_roots) endif() # filtering the results with the registry keys - matlab_get_all_valid_matlab_roots_from_registry("${_matlab_versions_from_registry}" _matlab_possible_roots) + matlab_get_all_valid_matlab_roots_from_registry("${_matlab_versions_from_registry}" _matlab_possible_roots ${ARGN}) set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE) endfunction() -# Utility function for finding Matlab or MCR on OSX -function(_Matlab_find_instances_osx matlab_roots) +# Utility function for finding Matlab or MCR on macOS +function(_Matlab_find_instances_macos matlab_roots) set(_matlab_possible_roots) - # on mac, we look for the /Application paths + # on macOS, we look for the standard /Applications paths # this corresponds to the behavior on Windows. On Linux, we do not have # any other guess. matlab_get_supported_releases(_matlab_releases) @@ -1480,27 +1706,33 @@ function(_Matlab_find_instances_osx matlab_roots) endif() foreach(_matlab_current_release IN LISTS _matlab_releases) - matlab_get_version_from_release_name("${_matlab_current_release}" _matlab_current_version) - string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}") - set(_matlab_base_path "/Applications/MATLAB_${_matlab_current_release}.app") - - # Check Matlab, has precedence over MCR - if(EXISTS ${_matlab_base_path}) - if(MATLAB_FIND_DEBUG) - message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_base_path}") + foreach(_macos_app_base IN ITEMS "$ENV{HOME}/Applications" "/Applications") + matlab_get_version_from_release_name("${_matlab_current_release}" _matlab_current_version) + string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}") + set(_matlab_base_path "${_macos_app_base}/MATLAB_${_matlab_current_release}.app") + + _Matlab_VersionInfoXML("${_matlab_base_path}" _matlab_version_tmp) + if(NOT "${_matlab_version_tmp}" STREQUAL "unknown") + set(_matlab_current_version ${_matlab_version_tmp}) endif() - list(APPEND _matlab_possible_roots "MATLAB" ${_matlab_current_version} ${_matlab_base_path}) - endif() - # Checks MCR - set(_mcr_path "/Applications/MATLAB/MATLAB_Runtime/v${_matlab_current_version_without_dot}") - if(EXISTS "${_mcr_path}") - if(MATLAB_FIND_DEBUG) - message(STATUS "[MATLAB] Found MCR version ${_matlab_current_release} (${_matlab_current_version}) in ${_mcr_path}") + # Check Matlab, has precedence over MCR + if(IS_DIRECTORY "${_matlab_base_path}") + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_base_path}") + endif() + list(APPEND _matlab_possible_roots "MATLAB" ${_matlab_current_version} ${_matlab_base_path}) endif() - list(APPEND _matlab_possible_roots "MCR" ${_matlab_current_version} ${_mcr_path}) - endif() + # Checks MCR + set(_mcr_path "${_macos_app_base}/MATLAB/MATLAB_Runtime/v${_matlab_current_version_without_dot}") + if(IS_DIRECTORY "${_mcr_path}") + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Found MCR version ${_matlab_current_release} (${_matlab_current_version}) in ${_mcr_path}") + endif() + list(APPEND _matlab_possible_roots "MCR" ${_matlab_current_version} ${_mcr_path}) + endif() + endforeach() endforeach() set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE) @@ -1577,21 +1809,34 @@ endfunction() # this variable will get all Matlab installations found in the current system. set(_matlab_possible_roots) +if(NOT DEFINED Matlab_ROOT AND DEFINED ENV{Matlab_ROOT}) + set(Matlab_ROOT $ENV{Matlab_ROOT}) +endif() +if(DEFINED Matlab_ROOT) + set(Matlab_ROOT_DIR ${Matlab_ROOT}) +endif() + if(Matlab_ROOT_DIR) # if the user specifies a possible root, we keep this one - if(NOT EXISTS "${Matlab_ROOT_DIR}") + if(NOT IS_DIRECTORY "${Matlab_ROOT_DIR}") # if Matlab_ROOT_DIR specified but erroneous if(MATLAB_FIND_DEBUG) message(WARNING "[MATLAB] the specified path for Matlab_ROOT_DIR does not exist (${Matlab_ROOT_DIR})") endif() else() + if("${Matlab_OR_MCR_INTERNAL}" STREQUAL "") + set(_matlab_cached_matlab_or_mcr "UNKNOWN") + else() + set(_matlab_cached_matlab_or_mcr "${Matlab_OR_MCR_INTERNAL}") + endif() # NOTFOUND indicates the code below to search for the version automatically if("${Matlab_VERSION_STRING_INTERNAL}" STREQUAL "") - list(APPEND _matlab_possible_roots "UNKNOWN" "NOTFOUND" ${Matlab_ROOT_DIR}) # empty version, empty MCR/Matlab indication + set(_matlab_cached_version "NOTFOUND") # empty version, empty MCR/Matlab indication else() - list(APPEND _matlab_possible_roots "UNKNOWN" ${Matlab_VERSION_STRING_INTERNAL} ${Matlab_ROOT_DIR}) # cached version + set(_matlab_cached_version "${Matlab_VERSION_STRING_INTERNAL}") # cached version endif() + list(APPEND _matlab_possible_roots "${_matlab_cached_matlab_or_mcr}" "${_matlab_cached_version}" "${Matlab_ROOT_DIR}") endif() else() @@ -1599,11 +1844,14 @@ else() # one installation using the appropriate heuristics. # There is apparently no standard way on Linux. if(CMAKE_HOST_WIN32) - _Matlab_find_instances_win32(_matlab_possible_roots_win32) + if(NOT DEFINED Matlab_FIND_REGISTRY_VIEW) + set(Matlab_FIND_REGISTRY_VIEW TARGET) + endif() + _Matlab_find_instances_win32(_matlab_possible_roots_win32 REGISTRY_VIEW ${Matlab_FIND_REGISTRY_VIEW}) list(APPEND _matlab_possible_roots ${_matlab_possible_roots_win32}) elseif(APPLE) - _Matlab_find_instances_osx(_matlab_possible_roots_osx) - list(APPEND _matlab_possible_roots ${_matlab_possible_roots_osx}) + _Matlab_find_instances_macos(_matlab_possible_roots_macos) + list(APPEND _matlab_possible_roots ${_matlab_possible_roots_macos}) endif() endif() @@ -1619,61 +1867,34 @@ if(MATLAB_FIND_DEBUG) message(STATUS "[MATLAB] Matlab root folders are ${_matlab_possible_roots}") endif() - - - - # take the first possible Matlab root list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots) set(Matlab_VERSION_STRING "NOTFOUND") set(Matlab_Or_MCR "UNKNOWN") if(_numbers_of_matlab_roots GREATER 0) - if(Matlab_FIND_VERSION_EXACT) - list(FIND _matlab_possible_roots ${Matlab_FIND_VERSION} _list_index) - if(_list_index LESS 0) - set(_list_index 1) + set(_list_index -1) + foreach(_matlab_root_index RANGE 1 ${_numbers_of_matlab_roots} 3) + list(GET _matlab_possible_roots ${_matlab_root_index} _matlab_root_version) + find_package_check_version(${_matlab_root_version} _matlab_version_ok HANDLE_VERSION_RANGE) + if(_matlab_version_ok) + set(_list_index ${_matlab_root_index}) + break() endif() + endforeach() - math(EXPR _matlab_or_mcr_index "${_list_index} - 1") - math(EXPR _matlab_root_dir_index "${_list_index} + 1") - - list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR) - list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING) - list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR) - elseif(DEFINED Matlab_FIND_VERSION) - set(_list_index -1) - foreach(_matlab_root_index RANGE 1 ${_numbers_of_matlab_roots} 3) - list(GET _matlab_possible_roots ${_matlab_root_index} _matlab_root_version) - if(_matlab_root_version VERSION_GREATER_EQUAL Matlab_FIND_VERSION) - set(_list_index ${_matlab_root_index}) - break() - endif() - endforeach() - - if(_list_index LESS 0) - set(_list_index 1) - endif() + if(_list_index LESS 0) + set(_list_index 1) + endif() - math(EXPR _matlab_or_mcr_index "${_list_index} - 1") - math(EXPR _matlab_root_dir_index "${_list_index} + 1") - list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR) - list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING) - list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR) - # adding a warning in case of ambiguity - if(_numbers_of_matlab_roots GREATER 3 AND MATLAB_FIND_DEBUG) - message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})." - " If this is not the desired behavior, use the EXACT keyword or provide the -DMatlab_ROOT_DIR=... on the command line") - endif() - else() - list(GET _matlab_possible_roots 0 Matlab_Or_MCR) - list(GET _matlab_possible_roots 1 Matlab_VERSION_STRING) - list(GET _matlab_possible_roots 2 Matlab_ROOT_DIR) - - # adding a warning in case of ambiguity - if(_numbers_of_matlab_roots GREATER 3 AND MATLAB_FIND_DEBUG) - message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})." - " If this is not the desired behavior, use the EXACT keyword or provide the -DMatlab_ROOT_DIR=... on the command line") - endif() + math(EXPR _matlab_or_mcr_index "${_list_index} - 1") + math(EXPR _matlab_root_dir_index "${_list_index} + 1") + list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR) + list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING) + list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR) + # adding a warning in case of ambiguity + if(_numbers_of_matlab_roots GREATER 3 AND NOT Matlab_FIND_VERSION_EXACT AND MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})." + " If this is not the desired behavior, use the EXACT keyword or provide the -DMatlab_ROOT_DIR=... on the command line") endif() endif() @@ -1737,16 +1958,26 @@ if(Matlab_ROOT_DIR) file(TO_CMAKE_PATH ${Matlab_ROOT_DIR} Matlab_ROOT_DIR) endif() -if(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(_matlab_64Build FALSE) -else() - set(_matlab_64Build TRUE) + +if(NOT DEFINED Matlab_MEX_EXTENSION) + set(_matlab_mex_extension "") + matlab_get_mex_suffix("${Matlab_ROOT_DIR}" _matlab_mex_extension) + + # This variable goes to the cache. + set(Matlab_MEX_EXTENSION ${_matlab_mex_extension} CACHE STRING "Extensions for the mex targets (automatically given by Matlab)") + unset(_matlab_mex_extension) endif() if(APPLE) set(_matlab_bin_prefix "mac") # i should be for intel set(_matlab_bin_suffix_32bits "i") - set(_matlab_bin_suffix_64bits "i64") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND Matlab_MEX_EXTENSION MATCHES "a64$") + # native Apple Silicon Matlab + set(_matlab_bin_suffix_64bits "a64") + else() + # Intel Mac OR Apple Silicon using Rosetta for Matlab + set(_matlab_bin_suffix_64bits "i64") + endif() elseif(UNIX) set(_matlab_bin_prefix "gln") set(_matlab_bin_suffix_32bits "x86") @@ -1758,12 +1989,11 @@ else() endif() - set(MATLAB_INCLUDE_DIR_TO_LOOK ${Matlab_ROOT_DIR}/extern/include) -if(_matlab_64Build) - set(_matlab_current_suffix ${_matlab_bin_suffix_64bits}) -else() +if(CMAKE_SIZEOF_VOID_P EQUAL 4) set(_matlab_current_suffix ${_matlab_bin_suffix_32bits}) +else() + set(_matlab_current_suffix ${_matlab_bin_suffix_64bits}) endif() set(Matlab_BINARIES_DIR @@ -1785,35 +2015,23 @@ else() set(_matlab_lib_prefix_for_search "lib") endif() -unset(_matlab_64Build) - - -if(NOT DEFINED Matlab_MEX_EXTENSION) - set(_matlab_mex_extension "") - matlab_get_mex_suffix("${Matlab_ROOT_DIR}" _matlab_mex_extension) - - # This variable goes to the cache. - set(Matlab_MEX_EXTENSION ${_matlab_mex_extension} CACHE STRING "Extensions for the mex targets (automatically given by Matlab)") - unset(_matlab_mex_extension) -endif() - if(MATLAB_FIND_DEBUG) - message(STATUS "[MATLAB] [DEBUG]_matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}") + message(STATUS "[MATLAB] _matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}") endif() - - # internal # This small stub around find_library is to prevent any pollution of CMAKE_FIND_LIBRARY_PREFIXES in the global scope. # This is the function to be used below instead of the find_library directives. function(_Matlab_find_library _matlab_library_prefix) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} ${_matlab_library_prefix}) + list(APPEND CMAKE_FIND_LIBRARY_PREFIXES ${_matlab_library_prefix}) find_library(${ARGN}) endfunction() -set(_matlab_required_variables) +# the matlab root is required +set(_matlab_required_variables Matlab_ROOT_DIR) +set(Matlab_LIBRARIES) # Order is as follow: # - unconditionally required libraries/headers first @@ -1823,40 +2041,50 @@ set(_matlab_required_variables) # the MEX library/header are required find_path( Matlab_INCLUDE_DIRS - mex.h + NAMES mex.h matrix.h PATHS ${MATLAB_INCLUDE_DIR_TO_LOOK} NO_DEFAULT_PATH ) list(APPEND _matlab_required_variables Matlab_INCLUDE_DIRS) +_Matlab_find_library( + ${_matlab_lib_prefix_for_search} + Matlab_MEX_LIBRARY + NAMES mex + PATHS ${_matlab_lib_dir_for_search} + NO_DEFAULT_PATH +) +if(Matlab_MEX_LIBRARY) + set(Matlab_MEX_LIBRARY_FOUND TRUE) + list(APPEND Matlab_LIBRARIES ${Matlab_MEX_LIBRARY}) +endif() +if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] mex C library: ${Matlab_MEX_LIBRARY}") +endif() + +# The MX library is required +_Matlab_find_library( + ${_matlab_lib_prefix_for_search} + Matlab_MX_LIBRARY + NAMES mx + PATHS ${_matlab_lib_dir_for_search} + NO_DEFAULT_PATH +) +if(Matlab_MX_LIBRARY) + set(Matlab_MX_LIBRARY_FOUND TRUE) + list(APPEND Matlab_LIBRARIES ${Matlab_MX_LIBRARY}) +endif() +if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] mx C library: ${Matlab_MX_LIBRARY}") +endif() + if(Matlab_Or_MCR STREQUAL "MATLAB" OR Matlab_Or_MCR STREQUAL "UNKNOWN") - _Matlab_find_library( - ${_matlab_lib_prefix_for_search} - Matlab_MEX_LIBRARY - mex - PATHS ${_matlab_lib_dir_for_search} - NO_DEFAULT_PATH - ) list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY) # the MEX extension is required list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION) - # the matlab root is required - list(APPEND _matlab_required_variables Matlab_ROOT_DIR) - - # The MX library is required - _Matlab_find_library( - ${_matlab_lib_prefix_for_search} - Matlab_MX_LIBRARY - mx - PATHS ${_matlab_lib_dir_for_search} - NO_DEFAULT_PATH - ) list(APPEND _matlab_required_variables Matlab_MX_LIBRARY) - if(Matlab_MX_LIBRARY) - set(Matlab_MX_LIBRARY_FOUND TRUE) - endif() endif() if(Matlab_HAS_CPP_API) @@ -1865,26 +2093,34 @@ if(Matlab_HAS_CPP_API) _Matlab_find_library( ${_matlab_lib_prefix_for_search} Matlab_ENGINE_LIBRARY - MatlabEngine + NAMES MatlabEngine PATHS ${_matlab_lib_dir_for_search} DOC "MatlabEngine Library" NO_DEFAULT_PATH ) if(Matlab_ENGINE_LIBRARY) set(Matlab_ENGINE_LIBRARY_FOUND TRUE) + list(APPEND Matlab_LIBRARIES ${Matlab_ENGINE_LIBRARY}) + endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Engine C++ library: ${Matlab_ENGINE_LIBRARY}") endif() # The MatlabDataArray library is required for R2018a+ _Matlab_find_library( ${_matlab_lib_prefix_for_search} Matlab_DATAARRAY_LIBRARY - MatlabDataArray + NAMES MatlabDataArray PATHS ${_matlab_lib_dir_for_search} DOC "MatlabDataArray Library" NO_DEFAULT_PATH ) if(Matlab_DATAARRAY_LIBRARY) set(Matlab_DATAARRAY_LIBRARY_FOUND TRUE) + list(APPEND Matlab_LIBRARIES ${Matlab_DATAARRAY_LIBRARY}) + endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Data array C++ library: ${Matlab_DATAARRAY_LIBRARY}") endif() endif() @@ -1894,12 +2130,16 @@ if("ENG_LIBRARY" IN_LIST Matlab_FIND_COMPONENTS) _Matlab_find_library( ${_matlab_lib_prefix_for_search} Matlab_ENG_LIBRARY - eng + NAMES eng PATHS ${_matlab_lib_dir_for_search} NO_DEFAULT_PATH ) if(Matlab_ENG_LIBRARY) set(Matlab_ENG_LIBRARY_FOUND TRUE) + list(APPEND Matlab_LIBRARIES ${Matlab_ENG_LIBRARY}) + endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] eng C library: ${Matlab_ENG_LIBRARY}") endif() endif() @@ -1908,12 +2148,16 @@ if("MAT_LIBRARY" IN_LIST Matlab_FIND_COMPONENTS) _Matlab_find_library( ${_matlab_lib_prefix_for_search} Matlab_MAT_LIBRARY - mat + NAMES mat PATHS ${_matlab_lib_dir_for_search} NO_DEFAULT_PATH ) if(Matlab_MAT_LIBRARY) set(Matlab_MAT_LIBRARY_FOUND TRUE) + list(APPEND Matlab_LIBRARIES ${Matlab_MAT_LIBRARY}) + endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] mat C library: ${Matlab_MAT_LIBRARY}") endif() endif() @@ -1921,7 +2165,7 @@ endif() if("SIMULINK" IN_LIST Matlab_FIND_COMPONENTS) find_path( Matlab_SIMULINK_INCLUDE_DIR - simstruc.h + NAMES simstruc.h PATHS "${Matlab_ROOT_DIR}/simulink/include" NO_DEFAULT_PATH ) @@ -1929,13 +2173,16 @@ if("SIMULINK" IN_LIST Matlab_FIND_COMPONENTS) set(Matlab_SIMULINK_FOUND TRUE) list(APPEND Matlab_INCLUDE_DIRS "${Matlab_SIMULINK_INCLUDE_DIR}") endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Simulink include dir: ${Matlab_SIMULINK_INCLUDE_DIR}") + endif() endif() # component Matlab program if("MAIN_PROGRAM" IN_LIST Matlab_FIND_COMPONENTS) find_program( Matlab_MAIN_PROGRAM - matlab + NAMES matlab PATHS ${Matlab_ROOT_DIR} ${Matlab_ROOT_DIR}/bin DOC "Matlab main program" NO_DEFAULT_PATH @@ -1943,13 +2190,16 @@ if("MAIN_PROGRAM" IN_LIST Matlab_FIND_COMPONENTS) if(Matlab_MAIN_PROGRAM) set(Matlab_MAIN_PROGRAM_FOUND TRUE) endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] Main program: ${Matlab_MAIN_PROGRAM}") + endif() endif() # component Mex Compiler if("MEX_COMPILER" IN_LIST Matlab_FIND_COMPONENTS) find_program( Matlab_MEX_COMPILER - "mex" + NAMES "mex" PATHS ${Matlab_BINARIES_DIR} DOC "Matlab MEX compiler" NO_DEFAULT_PATH @@ -1957,13 +2207,16 @@ if("MEX_COMPILER" IN_LIST Matlab_FIND_COMPONENTS) if(Matlab_MEX_COMPILER) set(Matlab_MEX_COMPILER_FOUND TRUE) endif() + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] MEX compiler: ${Matlab_MEX_COMPILER}") + endif() endif() # component MCC Compiler if("MCC_COMPILER" IN_LIST Matlab_FIND_COMPONENTS) find_program( Matlab_MCC_COMPILER - "mcc" + NAMES "mcc" PATHS ${Matlab_BINARIES_DIR} DOC "Matlab MCC compiler" NO_DEFAULT_PATH @@ -1971,18 +2224,9 @@ if("MCC_COMPILER" IN_LIST Matlab_FIND_COMPONENTS) if(Matlab_MCC_COMPILER) set(Matlab_MCC_COMPILER_FOUND TRUE) endif() -endif() - -set(Matlab_LIBRARIES - ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} - ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY}) - -if(Matlab_ENGINE_LIBRARY) - list(APPEND Matlab_LIBRARIES ${Matlab_ENGINE_LIBRARY}) -endif() - -if(Matlab_DATAARRAY_LIBRARY) - list(APPEND Matlab_LIBRARIES ${Matlab_DATAARRAY_LIBRARY}) + if(MATLAB_FIND_DEBUG) + message(STATUS "[MATLAB] MCC compiler: ${Matlab_MCC_COMPILER}") + endif() endif() # internal @@ -2011,11 +2255,13 @@ _Matlab_add_imported_target(MAT mat) _Matlab_add_imported_target(ENGINE MatlabEngine) _Matlab_add_imported_target(DATAARRAY MatlabDataArray) +set(Matlab_VERSION ${Matlab_VERSION_STRING}) + find_package_handle_standard_args( Matlab - FOUND_VAR Matlab_FOUND REQUIRED_VARS ${_matlab_required_variables} - VERSION_VAR Matlab_VERSION_STRING + VERSION_VAR Matlab_VERSION + HANDLE_VERSION_RANGE HANDLE_COMPONENTS) unset(_matlab_required_variables) diff --git a/cmake/external/FindPackageHandleStandardArgs.cmake b/cmake/external/FindPackageHandleStandardArgs.cmake index 83be0ed639..70c634b05d 100644 --- a/cmake/external/FindPackageHandleStandardArgs.cmake +++ b/cmake/external/FindPackageHandleStandardArgs.cmake @@ -1,33 +1,46 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. -# This script is taken from CMake git repository Cmake version 3.24.0.rc1 +# file LICENSE.rst or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindPackageHandleStandardArgs ----------------------------- -This module provides functions intended to be used in :ref:`Find Modules` +This module provides commands intended for use in :ref:`Find Modules` implementing :command:`find_package()` calls. +Load this module in a CMake find module with: + +.. code-block:: cmake + :caption: ``FindFoo.cmake`` + + include(FindPackageHandleStandardArgs) + +Commands +^^^^^^^^ + +This module provides the following commands: + +* :command:`find_package_handle_standard_args` +* :command:`find_package_check_version` + .. command:: find_package_handle_standard_args - This command handles the ``REQUIRED``, ``QUIET`` and version-related - arguments of :command:`find_package`. It also sets the - ``_FOUND`` variable. The package is considered found if all - variables listed contain valid results, e.g. valid filepaths. + Handles the ``REQUIRED``, ``QUIET`` and version-related arguments of + :command:`find_package`. There are two signatures: .. code-block:: cmake - find_package_handle_standard_args( + find_package_handle_standard_args( + (DEFAULT_MSG|) - ... - ) + ... + ) - find_package_handle_standard_args( - [FOUND_VAR ] - [REQUIRED_VARS ...] + find_package_handle_standard_args( + + [REQUIRED_VARS ...] [VERSION_VAR ] [HANDLE_VERSION_RANGE] [HANDLE_COMPONENTS] @@ -35,36 +48,33 @@ implementing :command:`find_package()` calls. [NAME_MISMATCHED] [REASON_FAILURE_MESSAGE ] [FAIL_MESSAGE ] - ) + [FOUND_VAR ] # Deprecated + ) + + This command sets the ``_FOUND`` variable to ``TRUE`` if all + the variables listed in ``...`` contain valid results + (e.g., valid filepaths) and any optional constraints are satisfied, and + ``FALSE`` otherwise. A success or failure message may be displayed based + on the results and on whether the ``REQUIRED`` and/or ``QUIET`` option + was given to the :command:`find_package` call. - The ``_FOUND`` variable will be set to ``TRUE`` if all - the variables ``...`` are valid and any optional - constraints are satisfied, and ``FALSE`` otherwise. A success or - failure message may be displayed based on the results and on - whether the ``REQUIRED`` and/or ``QUIET`` option was given to - the :command:`find_package` call. + The arguments are: - The options are: + ```` + The name of the package. For example, as written in the + ``Find.cmake`` find module filename. ``(DEFAULT_MSG|)`` In the simple signature this specifies the failure message. Use ``DEFAULT_MSG`` to ask for a default message to be computed (recommended). Not valid in the full signature. - ``FOUND_VAR `` - .. deprecated:: 3.3 - - Specifies either ``_FOUND`` or - ``_FOUND`` as the result variable. This exists only - for compatibility with older versions of CMake and is now ignored. - Result variables of both names are always set for compatibility. - - ``REQUIRED_VARS ...`` + ``REQUIRED_VARS ...`` Specify the variables which are required for this package. These may be named in the generated failure message asking the user to set the missing variable values. Therefore these should - typically be cache entries such as ``FOO_LIBRARY`` and not output - variables like ``FOO_LIBRARIES``. + typically be cache entries such as ``Foo_LIBRARY`` and not output + variables like ``Foo_LIBRARIES``. .. versionchanged:: 3.18 If ``HANDLE_COMPONENTS`` is specified, this option can be omitted. @@ -100,6 +110,14 @@ implementing :command:`find_package()` calls. will automatically check whether the package configuration file was found. + ``NAME_MISMATCHED`` + .. versionadded:: 3.17 + + Indicate that the ```` does not match the value of + :variable:`CMAKE_FIND_PACKAGE_NAME` variable. This is usually a mistake + and raises a warning, but it may be intentional for usage of the + command for components of a larger package. + ``REASON_FAILURE_MESSAGE `` .. versionadded:: 3.16 @@ -110,48 +128,76 @@ implementing :command:`find_package()` calls. Specify a custom failure message instead of using the default generated message. Not recommended. - ``NAME_MISMATCHED`` - .. versionadded:: 3.17 + ``FOUND_VAR `` + .. deprecated:: 3.3 + This option should no longer be used. - Indicate that the ```` does not match - ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a - warning, but it may be intentional for usage of the command for components - of a larger package. + Specifies either ``_FOUND`` or ``_FOUND`` as the + result variable. This exists only for backward compatibility with older + versions of CMake and is now ignored. Result variables of both names are + now always set for compatibility also with or without this option. -Example for the simple signature: + .. note:: -.. code-block:: cmake + If ```` does not match :variable:`CMAKE_FIND_PACKAGE_NAME` + for the calling module, a warning that there is a mismatch is given. The + ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using + the old signature and the ``NAME_MISMATCHED`` argument using the new + signature. To avoid forcing the caller to require newer versions of CMake + for usage, the variable's value will be used if defined when the + ``NAME_MISMATCHED`` argument is not passed for the new signature (but using + both is an error). + +.. command:: find_package_check_version + + .. versionadded:: 3.19 + + Checks if a given version is valid against the version-related arguments + of :command:`find_package`: + + .. code-block:: cmake + + find_package_check_version( + + + [HANDLE_VERSION_RANGE] + [RESULT_MESSAGE_VARIABLE ] + ) + + The arguments are: + + ```` + The version string to check. - find_package_handle_standard_args(LibXml2 DEFAULT_MSG - LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) + ```` + Name of the result variable that will hold a boolean value giving the + result of the check. -The ``LibXml2`` package is considered to be found if both -``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid. -Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found -and ``REQUIRED`` was used, it fails with a -:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was -used or not. If it is found, success will be reported, including -the content of the first ````. On repeated CMake runs, -the same message will not be printed again. + ``HANDLE_VERSION_RANGE`` + Enable handling of a version range, if one is specified. Without this + option, a developer warning will be displayed if a version range is + specified. + + ``RESULT_MESSAGE_VARIABLE `` + Specify a variable to get back a message describing the result of the check. -.. note:: +Examples +^^^^^^^^ - If ```` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the - calling module, a warning that there is a mismatch is given. The - ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using - the old signature and the ``NAME_MISMATCHED`` argument using the new - signature. To avoid forcing the caller to require newer versions of CMake for - usage, the variable's value will be used if defined when the - ``NAME_MISMATCHED`` argument is not passed for the new signature (but using - both is an error).. +Examples: Full Signature +"""""""""""""""""""""""" -Example for the full signature: +Example for using a full signature of ``find_package_handle_standard_args()``: .. code-block:: cmake + :caption: ``FindLibArchive.cmake`` - find_package_handle_standard_args(LibArchive + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args( + LibArchive REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR - VERSION_VAR LibArchive_VERSION) + VERSION_VAR LibArchive_VERSION + ) In this case, the ``LibArchive`` package is considered to be found if both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid. @@ -159,81 +205,94 @@ Also the version of ``LibArchive`` will be checked by using the version contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given, the default messages will be printed. -Another example for the full signature: +Another example for the full signature of +``find_package_handle_standard_args()``: .. code-block:: cmake + :caption: ``FindAutomoc4.cmake`` find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) - find_package_handle_standard_args(Automoc4 CONFIG_MODE) -In this case, a ``FindAutmoc4.cmake`` module wraps a call to + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Automoc4 CONFIG_MODE) + +In this case, a ``FindAutomoc4.cmake`` module wraps a call to ``find_package(Automoc4 NO_MODULE)`` and adds an additional search directory for ``automoc4``. Then the call to -``find_package_handle_standard_args`` produces a proper success/failure +``find_package_handle_standard_args()`` produces a proper success/failure message. -.. command:: find_package_check_version - - .. versionadded:: 3.19 - - Helper function which can be used to check if a ```` is valid - against version-related arguments of :command:`find_package`. +Example: Simple Signature +""""""""""""""""""""""""" - .. code-block:: cmake +Example for using a simple signature of ``find_package_handle_standard_args()``: - find_package_check_version( - [HANDLE_VERSION_RANGE] - [RESULT_MESSAGE_VARIABLE ] - ) +.. code-block:: cmake + :caption: ``FindLibXml2.cmake`` - The ```` will hold a boolean value giving the result of the check. + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args( + LibXml2 + DEFAULT_MSG + LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR + ) - The options are: +In this example, the ``LibXml2`` package is considered to be found if both +``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` variables are valid. Then +also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found and +``REQUIRED`` was used, it fails with a :command:`message(FATAL_ERROR)`, +independent whether ``QUIET`` was used or not. If it is found, success will +be reported, including the content of the first required variable specified +in ``...``. On repeated CMake runs, the same message will +not be printed again. - ``HANDLE_VERSION_RANGE`` - Enable handling of a version range, if one is specified. Without this - option, a developer warning will be displayed if a version range is - specified. - - ``RESULT_MESSAGE_VARIABLE `` - Specify a variable to get back a message describing the result of the check. +Example: Checking Version +""""""""""""""""""""""""" -Example for the usage: +Example for the ``find_package_check_version()`` usage: .. code-block:: cmake - - find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE - RESULT_MESSAGE_VARIABLE reason) - if (result) - message (STATUS "${reason}") + :caption: ``FindFoo.cmake`` + + include(FindPackageHandleStandardArgs) + find_package_check_version( + 1.2.3 + result + HANDLE_VERSION_RANGE + RESULT_MESSAGE_VARIABLE reason + ) + if(result) + message(STATUS "${reason}") else() - message (FATAL_ERROR "${reason}") + # Logic when version check is not successful. + message(WARNING "${reason}") endif() -#]=======================================================================] -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) +See Also +^^^^^^^^ +* :ref:`Find Modules` for details how to write a find module. +#]=======================================================================] -cmake_policy(PUSH) -# numbers and boolean constants -cmake_policy (SET CMP0012 NEW) -# IN_LIST operator -cmake_policy (SET CMP0057 NEW) +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) # internal helper macro macro(_FPHSA_FAILURE_MESSAGE _msg) - set (__msg "${_msg}") - if (FPHSA_REASON_FAILURE_MESSAGE) + set(__msg "${_msg}") + if(FPHSA_REASON_FAILURE_MESSAGE) string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n") + elseif(NOT DEFINED PROJECT_NAME AND NOT CMAKE_SCRIPT_MODE_FILE) + string(APPEND __msg "\n" + "Hint: The project() command has not yet been called. It sets up system-specific search paths.") endif() - if (${_NAME}_FIND_REQUIRED) + if(${_NAME}_FIND_REQUIRED) message(FATAL_ERROR "${__msg}") - else () - if (NOT ${_NAME}_FIND_QUIETLY) + else() + if(NOT ${_NAME}_FIND_QUIETLY) message(STATUS "${__msg}") - endif () - endif () + endif() + endif() endmacro() @@ -247,15 +306,11 @@ macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) # List them all in the error message: if(${_NAME}_CONSIDERED_CONFIGS) set(configsText "") - list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) - math(EXPR configsCount "${configsCount} - 1") - foreach(currentConfigIndex RANGE ${configsCount}) - list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) - list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + foreach(filename version IN ZIP_LISTS ${_NAME}_CONSIDERED_CONFIGS ${_NAME}_CONSIDERED_VERSIONS) string(APPEND configsText "\n ${filename} (version ${version})") endforeach() - if (${_NAME}_NOT_FOUND_MESSAGE) - if (FPHSA_REASON_FAILURE_MESSAGE) + if(${_NAME}_NOT_FOUND_MESSAGE) + if(FPHSA_REASON_FAILURE_MESSAGE) string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ") else() set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}") @@ -274,101 +329,100 @@ endmacro() function(FIND_PACKAGE_CHECK_VERSION version result) - cmake_parse_arguments (PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "") + cmake_parse_arguments(PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "") - if (FPCV_UNPARSED_ARGUMENTS) - message (FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments") + if(FPCV_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments") endif() - if ("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES) - message (FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument") + if("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES) + message(FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument") endif() - set (${result} FALSE PARENT_SCOPE) - if (FPCV_RESULT_MESSAGE_VARIABLE) + set(${result} FALSE PARENT_SCOPE) + if(FPCV_RESULT_MESSAGE_VARIABLE) unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE) endif() - if (_CMAKE_FPHSA_PACKAGE_NAME) - set (package "${_CMAKE_FPHSA_PACKAGE_NAME}") - elseif (CMAKE_FIND_PACKAGE_NAME) - set (package "${CMAKE_FIND_PACKAGE_NAME}") + if(_CMAKE_FPHSA_PACKAGE_NAME) + set(package "${_CMAKE_FPHSA_PACKAGE_NAME}") + elseif(CMAKE_FIND_PACKAGE_NAME) + set(package "${CMAKE_FIND_PACKAGE_NAME}") else() - message (FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'") + message(FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'") endif() - if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE + if(NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE) message(AUTHOR_WARNING - "`find_package()` specify a version range but the option " - "HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. " + "find_package() specify a version range but the option " + "HANDLE_VERSION_RANGE` is not passed to find_package_check_version(). " "Only the lower endpoint of the range will be used.") endif() - - set (version_ok FALSE) + set(version_ok FALSE) unset (version_msg) - if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE) - if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" + if(FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE) + if((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN) AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX) OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND version VERSION_LESS ${package}_FIND_VERSION_MAX))) - set (version_ok TRUE) + set(version_ok TRUE) set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")") else() set(version_msg "Found unsuitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\"") endif() - elseif (DEFINED ${package}_FIND_VERSION) + elseif(DEFINED ${package}_FIND_VERSION) if(${package}_FIND_VERSION_EXACT) # exact version required # count the dots in the version string string(REGEX REPLACE "[^.]" "" version_dots "${version}") # add one dot because there is one dot more than there are components string(LENGTH "${version_dots}." version_dots) - if (version_dots GREATER ${package}_FIND_VERSION_COUNT) + if(version_dots GREATER ${package}_FIND_VERSION_COUNT) # Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT # is at most 4 here. Therefore a simple lookup table is used. - if (${package}_FIND_VERSION_COUNT EQUAL 1) + if(${package}_FIND_VERSION_COUNT EQUAL 1) set(version_regex "[^.]*") - elseif (${package}_FIND_VERSION_COUNT EQUAL 2) + elseif(${package}_FIND_VERSION_COUNT EQUAL 2) set(version_regex "[^.]*\\.[^.]*") - elseif (${package}_FIND_VERSION_COUNT EQUAL 3) + elseif(${package}_FIND_VERSION_COUNT EQUAL 3) set(version_regex "[^.]*\\.[^.]*\\.[^.]*") else() set(version_regex "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") endif() string(REGEX REPLACE "^(${version_regex})\\..*" "\\1" version_head "${version}") - if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head) + if(NOT ${package}_FIND_VERSION VERSION_EQUAL version_head) set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"") - else () + else() set(version_ok TRUE) - set(version_msg "(found suitable exact version \"${_FOUND_VERSION}\")") - endif () - else () - if (NOT ${package}_FIND_VERSION VERSION_EQUAL version) + set(version_msg "(found suitable exact version \"${version}\")") + endif() + else() + if(NOT ${package}_FIND_VERSION VERSION_EQUAL version) set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"") - else () + else() set(version_ok TRUE) set(version_msg "(found suitable exact version \"${version}\")") - endif () - endif () + endif() + endif() else() # minimum version - if (${package}_FIND_VERSION VERSION_GREATER version) + if(${package}_FIND_VERSION VERSION_GREATER version) set(version_msg "Found unsuitable version \"${version}\", but required is at least \"${${package}_FIND_VERSION}\"") else() set(version_ok TRUE) set(version_msg "(found suitable version \"${version}\", minimum required is \"${${package}_FIND_VERSION}\")") endif() endif() - else () + else() set(version_ok TRUE) set(version_msg "(found version \"${version}\")") endif() - set (${result} ${version_ok} PARENT_SCOPE) - if (FPCV_RESULT_MESSAGE_VARIABLE) - set (${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE) + set(${result} ${version_ok} PARENT_SCOPE) + if(FPCV_RESULT_MESSAGE_VARIABLE) + set(${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE) endif() endfunction() @@ -385,21 +439,21 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) unset(FPHSA_NAME_MISMATCHED_override) - if (DEFINED FPHSA_NAME_MISMATCHED) + if(DEFINED FPHSA_NAME_MISMATCHED) # If the variable NAME_MISMATCHED variable is set, error if it is passed as # an argument. The former is for old signatures, the latter is for new # signatures. list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx) - if (NOT name_mismatched_idx EQUAL "-1") + if(NOT name_mismatched_idx EQUAL "-1") message(FATAL_ERROR - "The `NAME_MISMATCHED` argument may only be specified by the argument or " + "The NAME_MISMATCHED argument may only be specified by the argument or " "the variable, not both.") - endif () + endif() # But use the variable if it is not an argument to avoid forcing minimum # CMake version bumps for calling modules. set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}") - endif () + endif() if(${INDEX} EQUAL -1) set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) @@ -409,7 +463,7 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) if(FPHSA_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + message(FATAL_ERROR "Unknown keywords given to find_package_handle_standard_args(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") endif() if(NOT FPHSA_FAIL_MESSAGE) @@ -425,28 +479,28 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) endif() if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS) - message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + message(FATAL_ERROR "No REQUIRED_VARS specified for find_package_handle_standard_args()") endif() endif() - if (DEFINED FPHSA_NAME_MISMATCHED_override) + if(DEFINED FPHSA_NAME_MISMATCHED_override) set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}") - endif () + endif() - if (DEFINED CMAKE_FIND_PACKAGE_NAME + if(DEFINED CMAKE_FIND_PACKAGE_NAME AND NOT FPHSA_NAME_MISMATCHED AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME) message(AUTHOR_WARNING - "The package name passed to `find_package_handle_standard_args` " + "The package name passed to find_package_handle_standard_args() " "(${_NAME}) does not match the name of the calling package " "(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling " - "code that expects `find_package` result variables (e.g., `_FOUND`) " + "code that expects find_package() result variables (e.g., `_FOUND`) " "to follow a certain pattern.") - endif () + endif() - if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE) + if(${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE) message(AUTHOR_WARNING - "`find_package()` specify a version range but the module ${_NAME} does " + "find_package() specify a version range but the module ${_NAME} does " "not support this capability. Only the lower endpoint of the range " "will be used.") endif() @@ -460,7 +514,7 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") endif() - if (FPHSA_REQUIRED_VARS) + if(FPHSA_REQUIRED_VARS) list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) endif() @@ -470,13 +524,12 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) if(FPHSA_FOUND_VAR) set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND) set(_FOUND_VAR_MIXED ${_NAME}_FOUND) - if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER) - set(_FOUND_VAR ${FPHSA_FOUND_VAR}) - else() + if( + NOT FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED + AND NOT FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER + ) message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.") endif() - else() - set(_FOUND_VAR ${_NAME_UPPER}_FOUND) endif() # collect all variables which were not found, so they can be printed, so the @@ -529,40 +582,46 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) endif() endforeach() set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") - string(APPEND DETAILS "[c${COMPONENT_MSG}]") + string(APPEND DETAILS "[${COMPONENT_MSG}]") endif() # version handling: set(VERSION_MSG "") set(VERSION_OK TRUE) - # check with DEFINED here as the requested or found version may be "0" - if (DEFINED ${_NAME}_FIND_VERSION) + # check that the version variable is not empty to avoid emitting a misleading + # message(i.e. `Found unsuitable version ""`) + if(DEFINED ${_NAME}_FIND_VERSION) if(DEFINED ${FPHSA_VERSION_VAR}) - set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}}) - if (FPHSA_HANDLE_VERSION_RANGE) - set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE) + if(NOT "${${FPHSA_VERSION_VAR}}" STREQUAL "") + set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}}) + if(FPHSA_HANDLE_VERSION_RANGE) + set(FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE) + else() + set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE) + endif() + find_package_check_version("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG + ${FPCV_HANDLE_VERSION_RANGE}) else() - set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE) + set(VERSION_OK FALSE) endif() - find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG - ${FPCV_HANDLE_VERSION_RANGE}) - else() + endif() + if("${${FPHSA_VERSION_VAR}}" STREQUAL "") # if the package was not found, but a version was given, add that to the output: if(${_NAME}_FIND_VERSION_EXACT) set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") - elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE) + elseif(FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE) set(VERSION_MSG "(Required is version range \"${${_NAME}_FIND_VERSION_RANGE}\")") else() set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") endif() endif() - else () + else() # Check with DEFINED as the found version may be 0. if(DEFINED ${FPHSA_VERSION_VAR}) set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")") endif() - endif () + endif() if(VERSION_OK) string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]") @@ -572,23 +631,23 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) # print the result: - if (${_NAME}_FOUND) - FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") - else () + if(${_NAME}_FOUND) + find_package_message(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else() if(FPHSA_CONFIG_MODE) _FPHSA_HANDLE_FAILURE_CONFIG_MODE() else() if(NOT VERSION_OK) set(RESULT_MSG) - if (_FIRST_REQUIRED_VAR) - string (APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}") + if(_FIRST_REQUIRED_VAR) + string(APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}") endif() - if (COMPONENT_MSG) - if (RESULT_MSG) - string (APPEND RESULT_MSG ", ") + if(COMPONENT_MSG) + if(RESULT_MSG) + string(APPEND RESULT_MSG ", ") endif() - string (APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}") + string(APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}") endif() _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})") else() @@ -596,11 +655,8 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) endif() endif() - endif () + endif() set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) endfunction() - - -cmake_policy(POP) diff --git a/cmake/external/FindPackageMessage.cmake b/cmake/external/FindPackageMessage.cmake index 53187388dd..859b0b612d 100644 --- a/cmake/external/FindPackageMessage.cmake +++ b/cmake/external/FindPackageMessage.cmake @@ -1,33 +1,90 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. -# This script is taken from CMake git repository Cmake version 3.24.0.rc1 +# file LICENSE.rst or https://cmake.org/licensing for details. + #[=======================================================================[.rst: FindPackageMessage ------------------ +This module provides a command for printing find result messages and is +intended for use in :ref:`Find Modules` implementing +:command:`find_package()` calls. + +Load this module in a CMake find module with: + .. code-block:: cmake + :caption: ``FindFoo.cmake`` + + include(FindPackageMessage) + +Commands +^^^^^^^^ + +This module provides the following command: + +.. command:: find_package_message + + Prints a message once for each unique find result to inform the user which + package was found and where: + + .. code-block:: cmake + + find_package_message(
) + + ```` + The name of the package (for example, as used in the + ``Find.cmake`` module filename). - find_package_message( "message for user" "find result details") + ```` + The message string to display. -This function is intended to be used in FindXXX.cmake modules files. -It will print a message once for each unique find result. This is -useful for telling the user where a package was found. The first -argument specifies the name (XXX) of the package. The second argument -specifies the message to display. The third argument lists details -about the find result so that if they change the message will be -displayed again. The macro also obeys the QUIET argument to the -find_package command. + ``
`` + A unique identifier for tracking message display. The ```` is + printed only once per distinct ``
`` value. If ``
`` string + changes in a subsequent configuration phase, the message will be displayed + again. -Example: + If :command:`find_package` was called with the ``QUIET`` option, the + ```` is not printed. + +Examples +^^^^^^^^ + +Printing a result message in a custom find module: .. code-block:: cmake + :caption: ``FindFoo.cmake`` + + find_library(Foo_LIBRARY foo) + find_path(Foo_INCLUDE_DIR foo.h) - if(X11_FOUND) - find_package_message(X11 "Found X11: ${X11_X11_LIB}" - "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") + include(FindPackageMessage) + + if(Foo_LIBRARY AND Foo_INCLUDE_DIR) + find_package_message( + Foo + "Found Foo: ${Foo_LIBRARY}" + "[${Foo_LIBRARY}][${Foo_INCLUDE_DIR}]" + ) else() - ... + message(STATUS "Could NOT find Foo") endif() + +When writing standard find modules, use the +:module:`FindPackageHandleStandardArgs` module and its +:command:`find_package_handle_standard_args` command which automatically +prints the find result message based on whether the package was found: + +.. code-block:: cmake + :caption: ``FindFoo.cmake`` + + # ... + + include(FindPackageHandleStandardArgs) + + find_package_handle_standard_args( + Foo + REQUIRED_VARS Foo_LIBRARY Foo_INCLUDE_DIR + ) #]=======================================================================] function(find_package_message pkg msg details) @@ -37,6 +94,7 @@ function(find_package_message pkg msg details) set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") # The message has not yet been printed. + string(STRIP "${msg}" msg) message(STATUS "${msg}") # Save the find details in the cache to avoid printing the same diff --git a/cmake/external/MatlabTestsRedirect.cmake b/cmake/external/MatlabTestsRedirect.cmake index 3eb96e50a8..a52ff02a71 100644 --- a/cmake/external/MatlabTestsRedirect.cmake +++ b/cmake/external/MatlabTestsRedirect.cmake @@ -1,6 +1,6 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. -# This script is taken from CMake git repository Cmake version 3.24.0.rc1 +# file LICENSE.rst or https://cmake.org/licensing for details. + # This is an undocumented internal helper for the FindMatlab # module ``matlab_add_unit_test`` command. @@ -19,8 +19,8 @@ # -P FindMatlab_TestsRedirect.cmake set(Matlab_UNIT_TESTS_CMD -nosplash -nodesktop -nodisplay ${Matlab_ADDITIONAL_STARTUP_OPTIONS}) -if(WIN32) - set(Matlab_UNIT_TESTS_CMD ${Matlab_UNIT_TESTS_CMD} -wait) +if(WIN32 AND maut_BATCH_OPTION STREQUAL "-r") + list(APPEND Matlab_UNIT_TESTS_CMD -wait) endif() if(NOT test_timeout) diff --git a/cmake/shared/PACE_FindMatlab.cmake b/cmake/shared/PACE_FindMatlab.cmake index 61e93fd1b4..368983695e 100644 --- a/cmake/shared/PACE_FindMatlab.cmake +++ b/cmake/shared/PACE_FindMatlab.cmake @@ -46,11 +46,11 @@ module. You'll find the FindMatlab.cmake script bundled with this repo. #]=======================================================================] include(PACE_MatlabHelpers) -set(MATLAB_ADDITIONAL_VERSIONS - "R2023b=23.2" - "R2023a=23.1" - "R2022b=9.13" - ) +#set(MATLAB_ADDITIONAL_VERSIONS +# "R2023b=23.2" +# "R2023a=23.1" +# "R2022b=9.13" +# ) # Call `find_package(Matlab)` using passed in arguments `Matlab_ROOT_DIR` and/or # `Matlab_RELEASE` to find the desired version. diff --git a/documentation/release_notes/v4.1.1.md b/documentation/release_notes/v4.1.1.md index 0bc586a5b6..879bf5bf76 100644 --- a/documentation/release_notes/v4.1.1.md +++ b/documentation/release_notes/v4.1.1.md @@ -1,6 +1,13 @@ ## Release Notes v4.1.1 # Highlights + - #896 a-c Updated mex code is enabled for binning pixels. Horace-3 was using mex code for + binning pixels in some algorithms. Horace-4 has substantially refactored these algorithms + and disabled mex code. As a result, the algorithms (e.g. cut) which were completely IO bound + in Horace-3,have taken 60% of its time in MATLAB calculations in Horace-4. This ticket partially + solves this issue, updates and modifies `bin_pixels` code to run in all cases where MATLAB code + is used if mex code is enabled and makes majority of Horace algorithms which use `bin_pixels` + algorithm IO-speed constrained again. ## Bugs fixed and code improvements: diff --git a/horace_core/DLL/_PCWIN64/GetMD5.mexw64 b/horace_core/DLL/_PCWIN64/GetMD5.mexw64 index 17efa945b5..5d17f9372f 100644 Binary files a/horace_core/DLL/_PCWIN64/GetMD5.mexw64 and b/horace_core/DLL/_PCWIN64/GetMD5.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/accumulate_cut_c.mexw64 b/horace_core/DLL/_PCWIN64/accumulate_cut_c.mexw64 index f3d03a4e74..18797f9dae 100644 Binary files a/horace_core/DLL/_PCWIN64/accumulate_cut_c.mexw64 and b/horace_core/DLL/_PCWIN64/accumulate_cut_c.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/bin_pixels_c.mexw64 b/horace_core/DLL/_PCWIN64/bin_pixels_c.mexw64 index e12ed44670..e6dba3ee39 100644 Binary files a/horace_core/DLL/_PCWIN64/bin_pixels_c.mexw64 and b/horace_core/DLL/_PCWIN64/bin_pixels_c.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/c_deserialize.mexw64 b/horace_core/DLL/_PCWIN64/c_deserialize.mexw64 index 758f5b919b..5b6f58a2d2 100644 Binary files a/horace_core/DLL/_PCWIN64/c_deserialize.mexw64 and b/horace_core/DLL/_PCWIN64/c_deserialize.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/c_serial_size.mexw64 b/horace_core/DLL/_PCWIN64/c_serial_size.mexw64 index 3b76e135e8..940186d001 100644 Binary files a/horace_core/DLL/_PCWIN64/c_serial_size.mexw64 and b/horace_core/DLL/_PCWIN64/c_serial_size.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/c_serialize.mexw64 b/horace_core/DLL/_PCWIN64/c_serialize.mexw64 index 790fa8c432..728ae7083d 100644 Binary files a/horace_core/DLL/_PCWIN64/c_serialize.mexw64 and b/horace_core/DLL/_PCWIN64/c_serialize.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/calc_projections_c.mexw64 b/horace_core/DLL/_PCWIN64/calc_projections_c.mexw64 index 7938390dc7..f4f53f845c 100644 Binary files a/horace_core/DLL/_PCWIN64/calc_projections_c.mexw64 and b/horace_core/DLL/_PCWIN64/calc_projections_c.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/combine_sqw.mexw64 b/horace_core/DLL/_PCWIN64/combine_sqw.mexw64 index 3969dd45ba..3e79b8fa2c 100644 Binary files a/horace_core/DLL/_PCWIN64/combine_sqw.mexw64 and b/horace_core/DLL/_PCWIN64/combine_sqw.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/compute_pix_sums_c.mexw64 b/horace_core/DLL/_PCWIN64/compute_pix_sums_c.mexw64 index 6b79d8a398..d52115736a 100644 Binary files a/horace_core/DLL/_PCWIN64/compute_pix_sums_c.mexw64 and b/horace_core/DLL/_PCWIN64/compute_pix_sums_c.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/mtimesx_mex.mexw64 b/horace_core/DLL/_PCWIN64/mtimesx_mex.mexw64 index 505841c44c..7d4556f561 100644 Binary files a/horace_core/DLL/_PCWIN64/mtimesx_mex.mexw64 and b/horace_core/DLL/_PCWIN64/mtimesx_mex.mexw64 differ diff --git a/horace_core/DLL/_PCWIN64/sort_pixels_by_bins.mexw64 b/horace_core/DLL/_PCWIN64/sort_pixels_by_bins.mexw64 index db60161fbf..bcb27816e5 100644 Binary files a/horace_core/DLL/_PCWIN64/sort_pixels_by_bins.mexw64 and b/horace_core/DLL/_PCWIN64/sort_pixels_by_bins.mexw64 differ diff --git a/horace_core/sqw/@sqw/sqw_op_bin_pixels.m b/horace_core/sqw/@sqw/sqw_op_bin_pixels.m index 6b1f7d61a1..3bfc805e1f 100644 --- a/horace_core/sqw/@sqw/sqw_op_bin_pixels.m +++ b/horace_core/sqw/@sqw/sqw_op_bin_pixels.m @@ -47,20 +47,8 @@ % and step size % For example, [106, 4, 116] will define a plot % axis with bin edges 104-108, 108-112, 112-116. -% if step is 0, -% - [plo, rdiff, phi, rwidth] -% Integration axis: minimum range centre, -% distance between range centres, maximum range -% centre, range size for each cut. -% When using this syntax, an array of cuts is -% outputted. The number of cuts produced will -% be the number of rdiff sized steps between plo -% and phi; phi will be automatically increased -% such that rdiff divides phi - plo. -% For example, [106, 4, 113, 2] defines the -% integration range for three cuts, the first -% cut integrates the axis over 105-107, the -% second over 109-111 and the third 113-115. +% If step is 0, uses actual step, present in +% source object. % % p4_bin Binning along the energy axis: % - [] or '' Plot axis: use bin boundaries of input data @@ -97,7 +85,8 @@ % Default is false so resulting object intended to be put in % memory but if the resulting object is too big to % be stored in memory, result will be filebacked. -% combine with true/false value folloving key or option '-combine' +% combine with true/false value folloving key +% or '-combine' option. % if true or option '-combine' present, input sqw objects are % treated as parts of a single sqw object and the result is % build from the image of the first object, pixels of all diff --git a/horace_core/sqw/axes_blocks/@AxesBlockBase/AxesBlockBase.m b/horace_core/sqw/axes_blocks/@AxesBlockBase/AxesBlockBase.m index 9ccb2df321..f1eb28ce52 100644 --- a/horace_core/sqw/axes_blocks/@AxesBlockBase/AxesBlockBase.m +++ b/horace_core/sqw/axes_blocks/@AxesBlockBase/AxesBlockBase.m @@ -756,13 +756,6 @@ % convert different input forms into fully expanded common form [npix,s,e,pix_cand,unique_runid,use_mex]=... obj.normalize_bin_input(coord_transf,mode,argi{:}); - if mode>bin_mode.nosort - % temporary, until ticket #896 is completed - clOb = set_temporary_config_options('hor_config','use_mex',false); - [npix,s,e,pix_cand,unique_runid,use_mex]=... - obj.normalize_bin_input(coord_transf,mode,argi{:}); - clear clOb; - end % bin pixels varargout = cell(1,nargout); diff --git a/horace_core/sqw/axes_blocks/@AxesBlockBase/private/bin_pixels_with_mex_code_.m b/horace_core/sqw/axes_blocks/@AxesBlockBase/private/bin_pixels_with_mex_code_.m index c8eef5f6c4..1a362caf27 100644 --- a/horace_core/sqw/axes_blocks/@AxesBlockBase/private/bin_pixels_with_mex_code_.m +++ b/horace_core/sqw/axes_blocks/@AxesBlockBase/private/bin_pixels_with_mex_code_.m @@ -12,7 +12,7 @@ % coord -- the 3D or 4D array of pixels coordinates transformed into % AxesBlockBase coordinate system % mode_to_bin -% -- the mode used to bin pixels. Depending on this number, +% -- the mode used to bin pixels. Depending on this number, % additional parts of the algorithm are deployed % and additional output parameters are returned. % The modes are defined and described in bin_mode enum. @@ -58,25 +58,25 @@ % the pixels, contributing into the grid. num_outputs >=3 requests % pix_cand parameter to be present and not empty. % pix_ok -% -- if mode_to_bin >=4, returns input pix_cand contributed to +% -- if mode_to_bin >=sort_pix(4), returns input pix_cand contributed to % the the cut and sorted by grid cell or left unsorted, % depending on requested pix_indx output. % IF return_selected is true, contains indices of kept pixels % unique_runid -% -- if mode_to_bin >=5, array, containing the unique runids from the -% pixels, contributed to the cut. If input unique_runid was not -% empty, output unique_runid is combined with the input unique_runid -% and contains no duplicates. +% -- if mode_to_bin >=sort_and_uid(5), array, containing the unique +% runids from the pixels, contributed to the cut. If input +% unique_runid was not empty, output unique_runid is combined +% with the input unique_runid and contains no duplicates. % pix_indx -% -- in mode_to_bin ==6, contains indices of the grid cells, +% -- in mode_to_bin ==nosort(6), contains indices of the grid cells, % containing the pixels from input pix_cand. If this parameter is % requested, the order of output pix corresponds to the order of -% pixels in PixelData. if mode_to_bin < 6, output pix are sorted by -% npix bins. +% pixels in PixelData. if mode_to_bin < nosort(6), output pix +% are sorted by npix bins. % % selected -% -- in mode_to_bin == 7, contains logical array with true where -% pixels were kept and false, where they are dropped +% -- in mode_to_bin == nosort_sel(7), contains logical array with true +% where pixels were kept and false, where they are dropped persistent mex_code_holder; % the variable contains pointer, which ensure % constitency of subsequent calls to mex code. @@ -130,6 +130,15 @@ other_mex_input.alignment_matr = []; end else + if iscell(pix_cand) + % this may be improved/simplified in a future by enabling mex code + % to process any type of data + for i=1:numel(pix_cand) + if ~isa(pix_cand{i},'double') + pix_cand{i} = double(pix_cand{i}); + end + end + end other_mex_input.alignment_matr = []; other_mex_input.pix_candidates = pix_cand; other_mex_input.check_pix_selection = false; % use all pixels, do not analyze selection @@ -190,12 +199,11 @@ if mode_to_bin< bin_mode.sort_pix && ~test_mex_inputs return; end - - if mode_to_bin == bin_mode.sigerr_sel + if mode_to_bin == bin_mode.sigerr_sel % this mode does not return pixels and is similar to sigerr but in % addition returns logical array with true for pixels selected in % binning (used by symmetrisation routines) - varargout{bin_out.sigerr_sel} = out_struc.selected; + varargout{bin_out.sigerr_sel} = out_struc.is_pix_selected; return; end @@ -211,7 +219,7 @@ if mode_to_bin< bin_mode.sort_pix return; end - pix_ok = PixelDataMemory(); + pix_ok = PixelDataMemory(); if isempty(pix_ok_data) varargout{bin_out.pix_ok} = pix_ok; else @@ -231,8 +239,7 @@ varargout{bin_out.pix_idx} = out_struc.pix_img_idx; if mode_to_bin < bin_mode.nosort_sel return; - end - varargout{bin_out.selected} = out_struc.selected; + end + varargout{bin_out.selected} = out_struc.is_pix_selected; end - end diff --git a/horace_core/utilities/@MagneticIons/MagneticIons.m b/horace_core/utilities/@MagneticIons/MagneticIons.m index 7eb4f176e1..dd0935a9bb 100644 --- a/horace_core/utilities/@MagneticIons/MagneticIons.m +++ b/horace_core/utilities/@MagneticIons/MagneticIons.m @@ -42,6 +42,8 @@ properties(Dependent) % the ion to fix or calculate magnetic form factor for. currentIon + % Current Ion fitting Parameters, used in interpolation formula + fitting_param % Cellarray of all ion names, with known magnetic form factor % interpolation functions. IonNames @@ -72,6 +74,9 @@ mi.currentIon = 'Fe0'; end end + function par = get.fitting_param(obj) + par = obj.IonParMap_(obj.currentIon_); + end %------------------------------------------------------------------ % Interfaces: % @@ -131,33 +136,33 @@ IonParams_={... - %double j_Sc0[4][8] = { - [0.2512, 90.03, 0.329, 39.402, 0.4235, 14.322, -0.0043, 0.2029;... // + %double j_Sc0[4][8] = { + [0.2512, 90.03, 0.329, 39.402, 0.4235, 14.322, -0.0043, 0.2029;... // 10.8172, 54.327, 4.7353, 14.847, 0.6071, 4.218, 0.0011, 0.1212;...// 1.342, 10.2, 0.3837, 3.079, 0.0468, 0.118, -0.0328, 0.1343;... // 0, 0, 0, 0, 0, 0, 0, 0] ... // %double j_Sc1[4][8] = { - [0.4889, 51.16, 0.5203, 14.076, -0.0286, 0.179, 0.0185, 0.1217; ... // + [0.4889, 51.16, 0.5203, 14.076, -0.0286, 0.179, 0.0185, 0.1217; ... // 2 8.5021, 34.285, 3.2116, 10.994, 0.4244, 3.605, 0.0009, 0.1037; ... // 7.1167, 15.487, -6.6671, 18.269, 0.49, 2.992, 0.0047, 0.1624; ... // 0, 0, 0, 0, 0, 0, 0, 0]... // %double j_Sc2[4][8] = - [0.5048, 31.403, 0.5186, 10.99, -0.0241, 1.183, 0, 0.0578; ... // + [0.5048, 31.403, 0.5186, 10.99, -0.0241, 1.183, 0, 0.0578; ... // 3 4.3683, 28.654, 3.7231, 10.823, 0.6074, 3.668, 0.0014, 0.0681; ... // -1.6684, 15.648, 1.7742, 9.062, 0.4075, 2.412, 0.0042, 0.1105; ... // 0, 0, 0, 0, 0, 0, 0, 0]... // %double j_Ti0[4][8] = - [0.4657, 33.59, 0.549, 9.879, -0.0291, 0.323, 0.0123, 0.1088; ... // + [0.4657, 33.59, 0.549, 9.879, -0.0291, 0.323, 0.0123, 0.1088; ... // 4 4.3583, 36.056, 3.823, 11.133, 0.6855, 3.469, 0.002, 0.0967; ... // -2.1515, 11.271, 2.5149, 8.859, 0.3555, 2.149, 0.0045, 0.1244; ... // 0, 0, 0, 0, 0, 0, 0, 0]... // %double j_Ti1[4][8] = - [0.5093, 36.703, 0.5032, 10.371, -0.0263, 0.311, 0.0116, 0.1125; ... // + [0.5093, 36.703, 0.5032, 10.371, -0.0263, 0.311, 0.0116, 0.1125; ... // 5 6.1567, 27.275, 2.6833, 8.983, 0.407, 3.052, 0.0011, 0.0902; ... // -1.0383, 16.19, 1.4699, 8.924, 0.3631, 2.283, 0.0044, 0.127; ... // 0, 0, 0, 0, 0, 0, 0, 0]... // %double j_Ti2[4][8] = - [0.5091, 24.976, 0.5162, 8.757, -0.0281, 0.916, 0.0015, 0.0589; ... // + [0.5091, 24.976, 0.5162, 8.757, -0.0281, 0.916, 0.0015, 0.0589; ... // 6 4.3107, 18.348, 2.096, 6.797, 0.2984, 2.548, 0.0007, 0.064; ... // -1.3242, 15.31, 1.2042, 7.899, 0.3976, 2.156, 0.0051, 0.082; ... // 0, 0, 0, 0, 0, 0, 0, 0]... // diff --git a/horace_core/utilities/bin_mode.m b/horace_core/utilities/bin_mode.m index c3092f0732..918bfecf87 100644 --- a/horace_core/utilities/bin_mode.m +++ b/horace_core/utilities/bin_mode.m @@ -33,7 +33,8 @@ num_arguments = num_arguments+1; end error('HORACE:bin_mode:invalid_argument',... - 'mode requesting to return "selectied" arguments needs 4 output arguments. Provided %d arguments', ... + ['mode requesting to return "selectied" arguments needs 4 output arguments or 5 arguments in test mode.' ... + ' Provided %d arguments'], ... num_arguments+1); end end diff --git a/tools/build_config/Jenkinsfile b/tools/build_config/Jenkinsfile index f410babbba..1441f2976f 100644 --- a/tools/build_config/Jenkinsfile +++ b/tools/build_config/Jenkinsfile @@ -31,7 +31,7 @@ properties([ trim: true ), string( - defaultValue: '', + defaultValue: 'latest', description: 'The version of CMake to run the build with. Affects Linux builds only.', name: 'CMAKE_VERSION', trim: true @@ -61,7 +61,7 @@ properties([ trim: true ), booleanParam( - defaultValue: true, + defaultValue: false, description: 'If this pipeline is to build docs.', name: 'BUILD_DOCS' ), @@ -94,7 +94,7 @@ pipeline { // removing the R here from the pipeline library standard version so as not to break other library dependent pipelines MATLAB_VERSION = utilities.get_param('MATLAB_VERSION', pli.matlab_release) MATLAB_MODULE = utilities.get_param('MATLAB_VERSION', pli.matlab_release.minus('R')) - CMAKE_VERSION = utilities.get_param('CMAKE_VERSION', '3.26') + CMAKE_VERSION = utilities.get_param('CMAKE_VERSION', 'latest') GCC_VERSION = utilities.get_param('GCC_VERSION', '13') PYTHON_VERSION = utilities.get_param('PYTHON_VERSION', '3.8') VS_VERSION = utilities.get_param('VS_VERSION', '2019')