name: MATLAB Bindings
on:
push:
branches:
- "**"
tags:
- "v*"
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: matlab-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
COPP_MATLAB_RELEASE: R2024b
RUSTFLAGS: "-C target-cpu=generic"
jobs:
package:
name: ${{ matrix.platform }} package
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
platform: linux-x86_64
supported_win64: false
supported_mac: false
supported_glnxa64: true
- os: windows-2022
platform: windows-x86_64
supported_win64: true
supported_mac: false
supported_glnxa64: false
- os: macos-15
platform: macos-aarch64
supported_win64: false
supported_mac: true
supported_glnxa64: false
- os: macos-15-intel
platform: macos-x86_64
supported_win64: false
supported_mac: true
supported_glnxa64: false
env:
COPP_MATLAB_PLATFORM: ${{ matrix.platform }}
COPP_MATLAB_SUPPORT_WIN64: ${{ matrix.supported_win64 }}
COPP_MATLAB_SUPPORT_MAC: ${{ matrix.supported_mac }}
COPP_MATLAB_SUPPORT_GLNXA64: ${{ matrix.supported_glnxa64 }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Prepare package metadata
shell: pwsh
run: |
$refName = $env:GITHUB_REF_NAME
if ($env:GITHUB_EVENT_NAME -eq "pull_request") {
$refName = "pr-${{ github.event.pull_request.number }}"
}
$safeRefName = $refName -replace '[^A-Za-z0-9._-]', '-'
$toolboxVersion = "0.0.1"
if ($env:GITHUB_REF_TYPE -eq "tag") {
$tagVersion = $env:GITHUB_REF_NAME -replace '^v', ''
if ($tagVersion -match '^[0-9]+(\.[0-9]+){1,3}([+-].*)?$') {
$toolboxVersion = ($tagVersion -split '[+-]')[0]
}
}
"COPP_MATLAB_PACKAGE_NAME=copp-matlab-$safeRefName-${{ matrix.platform }}" >> $env:GITHUB_ENV
"COPP_MATLAB_TOOLBOX_VERSION=$toolboxVersion" >> $env:GITHUB_ENV
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: matlab-${{ matrix.platform }}
- name: Install Linux system dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libfontconfig1-dev
- name: Build Rust MATLAB native library
run: cargo build --release --lib --features matlab
- name: Set up MATLAB
uses: matlab-actions/setup-matlab@v3
with:
release: ${{ env.COPP_MATLAB_RELEASE }}
- name: Build, package, and smoke test MATLAB toolbox
uses: matlab-actions/run-command@v3
env:
LD_PRELOAD: /usr/lib/x86_64-linux-gnu/libstdc++.so.6
LD_LIBRARY_PATH: /usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}
with:
command: |
repo = string(pwd);
matlabRoot = fullfile(repo, "bindings", "matlab");
cd(matlabRoot);
build(Linkage="static", Configuration="release");
packageDir = "";
for candidate = ["+copp", "+copp"]
if isfolder(fullfile(matlabRoot, candidate))
packageDir = candidate;
break
end
end
assert(strlength(packageDir) > 0, "COPP MATLAB package folder was not found.");
addpath(matlabRoot);
if packageDir == "+copp"
versionText = copp.version();
toolboxName = "COPP for MATLAB";
else
versionText = copp.version();
toolboxName = "COPP for MATLAB";
end
disp("Built COPP MATLAB package version: " + string(versionText));
artifactRoot = fullfile(repo, "release-artifacts");
stageRoot = fullfile(repo, "dist", getenv("COPP_MATLAB_PACKAGE_NAME"));
if isfolder(artifactRoot)
rmdir(artifactRoot, "s");
end
if isfolder(stageRoot)
rmdir(stageRoot, "s");
end
mkdir(artifactRoot);
mkdir(stageRoot);
copyfile(fullfile(matlabRoot, packageDir), fullfile(stageRoot, packageDir));
copyfile(fullfile(matlabRoot, "examples"), fullfile(stageRoot, "examples"));
copyfile(fullfile(matlabRoot, "README.md"), fullfile(stageRoot, "MATLAB-README.md"));
for fileName = ["README.md", "CHANGELOG.md", "LICENSE"]
sourceFile = fullfile(repo, fileName);
if isfile(sourceFile)
copyfile(sourceFile, fullfile(stageRoot, fileName));
end
end
toolboxId = "0d55637d-8f40-49b9-9d1a-7cad2cf11bd1";
toolboxVersion = string(getenv("COPP_MATLAB_TOOLBOX_VERSION"));
outputFile = fullfile(artifactRoot, string(getenv("COPP_MATLAB_PACKAGE_NAME")) + ".mltbx");
previousDir = pwd;
cd(stageRoot);
opts = matlab.addons.toolbox.ToolboxOptions(stageRoot, toolboxId);
opts.ToolboxName = toolboxName;
opts.ToolboxVersion = toolboxVersion;
opts.Summary = "MATLAB bindings for COPP.";
opts.Description = "MATLAB package wrapping the COPP native solver core through a MEX gateway.";
opts.AuthorName = "TOPP-THU";
opts.AuthorEmail = "hello@copp.pro";
opts.ToolboxMatlabPath = {"."};
opts.OutputFile = outputFile;
opts.MinimumMatlabRelease = string(getenv("COPP_MATLAB_RELEASE"));
opts.MaximumMatlabRelease = "";
opts.SupportedPlatforms.Win64 = strcmpi(getenv("COPP_MATLAB_SUPPORT_WIN64"), "true");
opts.SupportedPlatforms.Mac = strcmpi(getenv("COPP_MATLAB_SUPPORT_MAC"), "true");
opts.SupportedPlatforms.Glnxa64 = strcmpi(getenv("COPP_MATLAB_SUPPORT_GLNXA64"), "true");
opts.SupportedPlatforms.MatlabOnline = false;
matlab.addons.toolbox.packageToolbox(opts);
cd(previousDir);
installerRoot = string(tempname);
mkdir(installerRoot);
copyfile(fullfile(matlabRoot, "install_copp.m"), installerRoot);
rmpath(matlabRoot);
rehash toolboxcache;
addpath(installerRoot);
packageName = extractAfter(packageDir, "+");
installed = install_copp( ...
AssetRoot=artifactRoot, ...
Version="latest", ...
Package=packageName, ...
AgreeToLicense=true);
disp(installed);
- name: Generate SHA256
shell: pwsh
run: |
$toolbox = Get-ChildItem -Path release-artifacts -Filter "*.mltbx" | Select-Object -First 1
if (-not $toolbox) {
throw "No MATLAB toolbox was generated."
}
$hash = Get-FileHash $toolbox.FullName -Algorithm SHA256
"$($hash.Hash.ToLower()) $($toolbox.Name)" |
Set-Content -Path "$($toolbox.FullName).sha256" -NoNewline
- name: Upload MATLAB toolbox artifact
uses: actions/upload-artifact@v4
with:
name: copp-matlab-${{ matrix.platform }}
path: |
release-artifacts/*.mltbx
release-artifacts/*.mltbx.sha256
if-no-files-found: error
publish-draft:
name: Create Draft GitHub Release
needs: package
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download MATLAB package artifacts
uses: actions/download-artifact@v4
with:
path: release-assets
- name: Create or update draft GitHub Release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_TAG: ${{ github.ref_name }}
run: |
$assetPaths = @(
Get-ChildItem release-assets -Recurse -File |
Where-Object { $_.Name -like "*.mltbx" -or $_.Name -like "*.mltbx.sha256" } |
Sort-Object Name |
ForEach-Object { $_.FullName }
)
if ($assetPaths.Count -eq 0) {
throw "No release assets were downloaded."
}
$notesFile = "release-notes.md"
@'
Prebuilt MATLAB toolbox packages are attached below.
See CHANGELOG.md in this tag for API changes and breaking changes.
'@ | Set-Content -Path $notesFile -NoNewline
gh release view $env:RELEASE_TAG *> $null
if ($LASTEXITCODE -eq 0) {
& gh release upload $env:RELEASE_TAG $assetPaths --clobber
& gh release edit $env:RELEASE_TAG `
--draft `
--title $env:RELEASE_TAG `
--notes-file $notesFile
} else {
& gh release create $env:RELEASE_TAG $assetPaths `
--draft `
--verify-tag `
--title $env:RELEASE_TAG `
--notes-file $notesFile
}