Skip to content

Instantly share code, notes, and snippets.

@scivision
Last active January 27, 2025 14:35
Show Gist options
  • Save scivision/8ca7bf851d742db5b9148959c28f4f6e to your computer and use it in GitHub Desktop.
Save scivision/8ca7bf851d742db5b9148959c28f4f6e to your computer and use it in GitHub Desktop.
Matlab buildtool MEX standalone example

Matlab buildtool buildfile.m examples

This is a minimal standalone example of using Matlab's build system buildtool as configured by buildfile.m to build MEX targets and run tests. buildtool can be used instead of CMake or custom scripts to check code, build binaries and run tests, among other tasks including coverage tests and publishing documentation.

buildtool check

checks the syntax of Matlab script using CodeIssuesTask.

buildtool mex

builds MEX targets using MexTask.

buildtool test

runs tests using TestTask.

More advanced real usage

See several additional examples of more advanced Mex and Matlab Engine tasks. Matlab-stdlib is another substantial example of buildfile.m usage.

function plan = buildfile
import matlab.buildtool.tasks.MexTask
import matlab.buildtool.tasks.CodeIssuesTask
import matlab.buildtool.tasks.TestTask
plan = buildplan();
plan.DefaultTasks = "test";
% store the binary outputs out-of-tree
bindir = fullfile(tempdir, "build-mex-engine-" + matlabRelease().Release);
if ~isfolder(bindir), mkdir(bindir); end
addpath(bindir)
plan("check") = CodeIssuesTask(".", IncludeSubfolders=true, ...
WarningThreshold=0, Results="code-issues.sarif");
complex_api = "-R2018a";
% required "newer" interleaved interface, until it becomes default
example_dir = fullfile(matlabroot, "extern/examples");
compiler_opts = get_compiler_options();
plan("mex:cpp_array") = MexTask(fullfile(example_dir, "cpp_mex/arrayProduct.cpp"), bindir, ...
Options=[complex_api, compiler_opts]);
% pass multiple Options by using a string array
plan("mex:disk_available") = MexTask("disk_available.cpp", bindir, Options=compiler_opts);
%% TestTask
plan("test:mex:cpp_array") = TestTask("TestMex/test_cpp_array");
plan("test:mex:disk_available") = TestTask("TestMex/test_disk_available");
end
function compiler_opt = get_compiler_options()
%% helper function to get compiler options
% this example shows setting the C++ compiler standard to C++17
cxx = mex.getCompilerConfigurations('c++');
flags = cxx.Details.CompilerFlags;
msvc = startsWith(cxx.ShortName, "MSVCPP");
std = "-std=c++17";
% mex() can't handle string.empty
compiler_id = "";
if msvc
std = "/std:c++17";
end
opt = flags + " " + std;
if msvc
compiler_opt = "COMPFLAGS=" + opt;
else
% Windows oneAPI also uses this
compiler_opt = "CXXFLAGS=" + opt;
end
if strlength(compiler_id)
compiler_opt = [compiler_id, compiler_opt];
end
end
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <string>
#include <string_view>
#include <vector>
#include <memory>
#include <cstdint>
#include <filesystem>
#include <system_error>
class MexFunction : public matlab::mex::Function {
private:
#include "mex1string.inl"
public:
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
matlab::data::ArrayFactory factory;
std::error_code ec;
std::uintmax_t s = std::filesystem::space(matlab_1string_input(inputs), ec).available;
if (ec)
s = 0;
outputs[0] = factory.createScalar(s);
}
};
std::string matlab_1string_input(matlab::mex::ArgumentList inputs)
{
std::shared_ptr<matlab::engine::MATLABEngine> matlabEng = getEngine();
matlab::data::ArrayFactory factory;
std::string in;
if (inputs.size() != 1) {
matlabEng->feval(u"error", 0,
std::vector<matlab::data::Array>({ factory.createScalar("MexFunction requires exactly one scalar input argument") }));
}
if ((inputs[0].getType() == matlab::data::ArrayType::MATLAB_STRING && inputs[0].getNumberOfElements() == 1)){
matlab::data::TypedArray<matlab::data::MATLABString> stringArr = inputs[0];
in = stringArr[0];
} else if (inputs[0].getType() == matlab::data::ArrayType::CHAR){
matlab::data::CharArray charArr = inputs[0];
in.assign(charArr.begin(), charArr.end());
} else {
matlabEng->feval(u"error", 0,
std::vector<matlab::data::Array>({ factory.createScalar("MexFunction: First input must be a scalar string or char vector") }));
}
return in;
}
classdef TestMex < matlab.unittest.TestCase
methods(Test)
function test_cpp_array(tc)
a = eye(3);
x = arrayProduct(2, a);
tc.verifyEqual(x, 2*a)
end
function test_disk_available(tc)
a = disk_available(".");
tc.verifyGreaterThan(a, 0)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment