diff --git a/.github/workflows/mexbuild.yml b/.github/workflows/mexbuild.yml new file mode 100644 index 0000000..4fd0948 --- /dev/null +++ b/.github/workflows/mexbuild.yml @@ -0,0 +1,58 @@ +name: releaseWorkflow + +on: + push: + tags: + - '*' +jobs: + mexBuild: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + + steps: + - name: Check out repository + uses: actions/checkout@v4 + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v2 + - name: Run build task + uses: matlab-actions/run-build@v2 + with: + tasks: mex test + - name: Upload MEX functions + uses: actions/upload-artifact@v4 + with: + name: MEX_${{ matrix.os }} + path: toolbox/private + + packageAndRelease: + needs: mexBuild + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: MEX_ubuntu-latest + path: toolbox/private + - uses: actions/download-artifact@v4 + with: + name: MEX_windows-latest + path: toolbox/private + - uses: actions/download-artifact@v4 + with: + name: MEX_macos-latest + path: toolbox/private + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v2 + - name: Run build task + uses: matlab-actions/run-build@v2 + with: + tasks: release + - name: Create GitHub Release + uses: ncipollo/release-action@v1 + with: + draft: true + artifacts: "release/Arithmetic_Toolbox.mltbx" + \ No newline at end of file diff --git a/README.md b/README.md index fa76f1d..9b0ee61 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![](https://img.shields.io/github/v/release/mathworks/arithmetic?label=version) ![](https://img.shields.io/github/license/mathworks/arithmetic) -This is an example MATLAB® toolbox created to showcase how toolboxes are constructed and laid out, as described in the [MATLAB Toolbox Best Practices](https://github.com/mathworks/toolboxdesign). This toolbox is not functional, but rather serves as an example of how to create your own toolbox. +This is an example MATLAB® toolbox created to showcase how toolboxes are constructed and laid out, as described in the [MATLAB Toolbox Best Practices](https://github.com/mathworks/toolboxdesign). This toolbox is not functional, but rather serves as an example of how to create your own toolbox. It uses works well in MATLAB R2024b and later. ![Toolbox Logo](images/readmeImage.jpg) diff --git a/buildfile.m b/buildfile.m index 65a6013..3d15753 100644 --- a/buildfile.m +++ b/buildfile.m @@ -1,43 +1,63 @@ function plan = buildfile - % Create a plan from the task functions - plan = buildplan(localfunctions); - - % Make the "test" task the default task in the plan - plan.DefaultTasks = "test"; - - % Make the "release" task dependent on the "check" and "test" tasks - plan("release").Dependencies = ["check" "test"]; +% Create a plan from the task functions +plan = buildplan(localfunctions); + +% Define the "clean" Task +plan("clean") = matlab.buildtool.tasks.CleanTask; + +% Output folder for MEX functions +mexOutputFolder = fullfile("toolbox","derived"); + +% Compile Cpp source code within cpp/*Mex into MEX functions +foldersToMex = plan.files(fullfile("cpp", "*Mex")).select(@isfolder); +for folder = foldersToMex.paths + [~, folderName] = fileparts(folder); + plan("mex:"+folderName) = matlab.buildtool.tasks.MexTask(fullfile(folder, "**/*.cpp"), ... + mexOutputFolder, ... + Filename=folderName); +end +plan("mex").Description = "Build MEX functions"; + +% Define the "check" task +sourceFolder = files(plan, "toolbox"); +plan("check") = matlab.buildtool.tasks.CodeIssuesTask(sourceFolder,... + IncludeSubfolders = true); + +% Define the "test" task +testsFolder = files(plan, "tests"); +plan("test") = matlab.buildtool.tasks.TestTask(testsFolder,... + IncludeSubfolders = true, OutputDetail = "terse"); + +% Make the "test" task the default task in the plan +plan.DefaultTasks = ["mex" "test"]; + +% Make the "release" task dependent on the "check" and "test" tasks +plan("release").Dependencies = ["mex" "check" "test"]; +plan("release").Outputs = "release\Arithmetic_Toolbox.mltbx"; +end + +function releaseTask(~) +% Create an MLTBX package +releaseFolderName = "release"; +if isMATLABReleaseOlderThan("R2025a") + % Toolbox packaging metadata migrated from packaging prj to project prj + % in 25a. + opts = matlab.addons.toolbox.ToolboxOptions("toolboxPackaging.prj"); +else + % Create a release and put it in the release directory + opts = matlab.addons.toolbox.ToolboxOptions("arithmetic.prj"); +end + +% By default, the packaging GUI restricts the name of the getting started guide, so we fix that here. +opts.ToolboxGettingStartedGuide = fullfile("toolbox", "gettingStarted.mlx"); + +% GitHub releases don't allow spaces, so replace spaces with underscores +mltbxFileName = strrep(opts.ToolboxName," ","_") + ".mltbx"; +opts.OutputFile = fullfile(releaseFolderName,mltbxFileName); + +% Create the release directory, if needed +if ~exist(releaseFolderName,"dir") + mkdir(releaseFolderName) +end +matlab.addons.toolbox.packageToolbox(opts); end - - function checkTask(~) - % Identify code issues - issues = codeIssues; - assert(isempty(issues.Issues),formattedDisplayText( ... - issues.Issues(:,["Location" "Severity" "Description"]))) - end - - function testTask(~) - % Run unit tests - results = runtests(IncludeSubfolders=true,OutputDetail="terse"); - assertSuccess(results); - end - - function releaseTask(~) - releaseFolderName = "release"; - % Create a release and put it in the release directory - opts = matlab.addons.toolbox.ToolboxOptions("toolboxPackaging.prj"); - - % By default, the packaging GUI restricts the name of the getting started guide, so we fix that here. - opts.ToolboxGettingStartedGuide = fullfile("toolbox", "gettingStarted.mlx"); - - % GitHub releases don't allow spaces, so replace spaces with underscores - mltbxFileName = strrep(opts.ToolboxName," ","_") + ".mltbx"; - opts.OutputFile = fullfile(releaseFolderName,mltbxFileName); - - % Create the release directory, if needed - if ~exist(releaseFolderName,"dir") - mkdir(releaseFolderName) - end - matlab.addons.toolbox.packageToolbox(opts); - end - \ No newline at end of file diff --git a/cpp/invertMex/invertMex.cpp b/cpp/invertMex/invertMex.cpp new file mode 100644 index 0000000..594628d --- /dev/null +++ b/cpp/invertMex/invertMex.cpp @@ -0,0 +1,16 @@ +#include "mex.hpp" +#include "mexAdapter.hpp" + +using namespace matlab::data; +using matlab::mex::ArgumentList; + +class MexFunction : public matlab::mex::Function { +public: + void operator()(ArgumentList outputs, ArgumentList inputs) { + TypedArray doubleArray = std::move(inputs[0]); + for (auto& elem : doubleArray) { + elem = 1/elem; + } + outputs[0] = doubleArray; + } +}; diff --git a/resources/project/Project.xml b/resources/project/Project.xml index 4c29d34..125f29a 100644 --- a/resources/project/Project.xml +++ b/resources/project/Project.xml @@ -1,184 +1,228 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - + + - - - - - + + + + + + + + + + + + + + + + + - - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + diff --git a/tests/testInvertNumber.m b/tests/testInvertNumber.m new file mode 100644 index 0000000..14bf565 --- /dev/null +++ b/tests/testInvertNumber.m @@ -0,0 +1,49 @@ +% FUNCTIONAL TEST: invertNumber +% +% This functional test ensures that the invertNumber function is working properly. +% The invertNumber function takes a scalar/ vercor of numbers as input and returns their inverse. +% +% This test ensures that the function returns the correct results for a +% variety of inputs. + +% Please remember that this is an example MATLAB toolbox created to showcase how toolboxes are constructed and laid out, as described in the MATLAB +% Toolbox Best Practices. This toolbox is not functional, but rather serves as an example of how to create your own toolbox. + + +function tests = testInvertNumber + tests = functiontests(localfunctions); +end + +function testInverse(testCase) + % Ensure that the function returns the correct inverse for positive numbers + actual = invertNumber(5); + expected = 0.2; + verifyEqual(testCase, actual, expected); + + % Ensure that the function returns the correct inverse for negative numbers + actual = invertNumber(-5); + expected = -0.2; + verifyEqual(testCase, actual, expected); + + % Ensure that the function returns the correct inverse for zero input + actual = invertNumber(0); + expected = Inf; + verifyEqual(testCase, actual, expected); + + % Ensure that the function returns the correct inverse for NaN + actual = invertNumber(NaN); + expected = NaN; + verifyEqual(testCase, actual, expected); +end + +function testInputValidation(testCase) + % % Ensure that the function raises an error when given non-scalar inputs + % verifyError(testCase, @()add([1,2],3), "MATLAB:validation:IncompatibleSize"); + + % Ensure that the function raises an error when given non-numeric inputs + verifyError(testCase, @()invertNumber("2"), "MATLAB:validators:mustBeNumeric"); + + % Ensure that the function raises an error when not given enough input + % arguments + verifyError(testCase, @()invertNumber(), "MATLAB:minrhs"); +end \ No newline at end of file diff --git a/toolbox/derived/.gitignore b/toolbox/derived/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/toolbox/derived/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/toolbox/invertNumber.m b/toolbox/invertNumber.m new file mode 100644 index 0000000..f9431be --- /dev/null +++ b/toolbox/invertNumber.m @@ -0,0 +1,7 @@ +function invertedNumber = invertNumber(numberToInvert) +arguments + numberToInvert(1,:) {mustBeNumeric}; +end +mh = mexhost(); +invertedNumber = mh.feval("invertMex", numberToInvert); +end \ No newline at end of file