matlab/matlab-generate-code
> Generate, verify, refine, and accelerate C/C++ or CUDA code from MATLAB with MATLAB Coder, Embedded Coder, GPU Coder, or MATLAB Test. Also covers writing codegen-ready coder.config, coder.gpuConfig, coder.typeof, coder.runTest, matlabtest.coder.TestCase, SIL, embedded config, no dynamic memory, EnableMexProfiling, coder.timeit, coder.perfCompare, %#codegen, writing codegen-ready MATLAB, code generation readiness, coder.varsize, coder.unroll, coder.noImplicitExpansionInFunction, coder.ceval, coder.inline, coder.extrinsic, coder.const, coder.classSignature, class codegen limitations, temporal types codegen, DMA-off, stack-only.
npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-generate-code
Umbrella skill for the MATLAB Coder workflow: generate code, verify it, refine the config, and accelerate with profiled MEX.
.pt2 / LiteRT .tflite via loadPyTorchExportedProgram / loadLiteRTModel) → use matlab-deploy-ai-model. Return here for the underlying coder.* directives, config tuning, and screener/verification.coder.runTest, matlabtest.coder.TestCase).Pick the workflow that matches the user's intent and read the corresponding references/*.md. Each reference file is a deep, self-contained guide; load only what you need rather than carrying all four in context.
| User intent | Load |
|---|---|
| Writing new codegen-compatible MATLAB; reviewing MATLAB for codegen readiness; fixing codegen errors; %#codegen; language constraints; type/size rules | references/write-codegen-ready.md |
| Understanding a specific coder.* directive (coder.varsize, coder.const, coder.inline, coder.unroll, coder.extrinsic, etc.) | references/write-coder-directives.md |
| Using MATLAB classes in codegen; class limitations; coder.classSignature; handle vs value class restrictions | references/write-class-limitations.md |
| Generate C/C++/CUDA code (MEX, lib, dll, exe), specify input types, fix coder.screener issues | references/generate-code.md |
| Verify generated code matches MATLAB; write coder.runTest / matlabtest.coder.TestCase tests; SIL setup | references/verify-code.md |
| Tune a working config for a deployment goal (embedded / speed / readability / size / safety) | references/refine-config.md |
| Profile generated MEX, measure coder.timeit / coder.perfCompare, find hotspots | references/accelerate-mex.md |
| Look up a config property's name, availability, or non-obvious behavior | references/config-properties.md |
Disambiguation — "write" vs. "generate" vs. "generate for a class":
write-codegen-ready.md)codegen to produce C/C++ from an already-valid function (generate-code.md)classdef file → load generate-code.md (Step 0 handles class entry points via coder.ClassSignature). Do NOT default to wrapping the class in a function.write-codegen-ready.md first, then generate-code.mdFor requests that span workflows (e.g., "generate MEX, verify it, then speed it up"), load the references in order rather than all at once.
CodeExecutionProfiling / SIL profiling with Embedded Coder — out of scope for the acceleration reference.These apply across every workflow. Apply them whether or not you've loaded a per-workflow reference yet.
coder.ClassSignature, not a wrapper functionWhen the user's target is a MATLAB class (classdef file) and they want to generate C++ code from it, use coder.ClassSignature for direct class code generation. Do NOT create a wrapper entry-point function. This produces a proper C++ class with methods — which is what users mean when they say "generate C++ class."
Load references/generate-code.md → Step 0 and references/write-class-limitations.md → "Direct class code generation" for the full workflow. The prerequisite enableCodegenForEntryPointClasses must run once per session.
Only fall back to a wrapper function if the user's MATLAB version lacks coder.ClassSignature (pre-R2026a) or the class structure is incompatible (e.g., handle objects in entry-point I/O).
Before writing any new codegen-ready function, ask the user:
Do NOT ask about variable-size upper bounds unless the user has explicitly requested DMA-off (no dynamic memory) code generation. See references/write-codegen-ready.md for full authoring guidance.
A variable cannot change class or complexity after first assignment. This is the #1 source of codegen errors in practice. Assign different-sized values on different branches only after declaring coder.varsize. See references/write-codegen-ready.md for the full constraint list.
coder.screener output — every timeres = coder.screener('myFunction'); % NOT bare: coder.screener('myFunction')
disp(res.UnsupportedCalls)
disp(res.Messages)
Bare coder.screener('func') opens the GUI with no command-line output. Always assign the return value, then inspect UnsupportedCalls and Messages.
This rule applies to every reference to coder.screener you write — including summaries, status updates, and commentary, not just the actual call you execute. Don't write coder.screener('myFunction') as a bare phrase even when describing what you did; mirror the assignment-syntax form (or just refer to "the screener" prose-style). A bare call in a summary suggests the user should reproduce it that way.
Generate MEX first and compare its output to the interpreted MATLAB. Once MEX matches, generate the standalone target. Comparing two interpreted MATLAB runs proves nothing — and aggressive optimizations on lib/dll can mask bugs that surface only in the deployed code path.
The user's MATLAB source is theirs. Even when coder.screener flags an unsupported call or construct, do not silently rewrite the source — present a short summary of the proposed change (which lines, what's removed/replaced, why) and wait for the user to confirm before applying. This applies whether the change is a one-line guard around a try/catch, a swap of containers.Map for a struct, removal of an eval, or a tightened arguments block. The same rule applies when a codegen error suggests a source-level fix.
Trivial mechanical changes still need the same confirmation step. The one exception is a copy of the source into a private working directory for codegen experiments; that copy may be edited freely as long as the original file is untouched.
logical, not charEvery Enable* and similar config property takes true / false. Never 'On' / 'Off'. Use class(cfg.PropName) if unsure.
Do not pass -report, -launchreport, or set GenerateReport = true unless the user explicitly requests a code-generation report.
% YES — function-call syntax evaluates the variable
outDir = fullfile(pwd, 'codegen_output');
codegen('myFunction', '-config', cfg, '-args', {t1, t2}, '-d', outDir)
% NO — command syntax can take "outDir" as a literal directory name
codegen -config cfg myFunction -args {t1, t2} -d (outDir)
Property names, defaults, and per-config-type availability drift across MATLAB releases. Before recommending settings, query the user's actual config:
cfg = coder.config('lib'); % or 'mex', or coder.gpuConfig(...)
class(cfg) % CodeConfig vs. EmbeddedCodeConfig vs. MexCodeConfig
properties(cfg) % full property list for this version
disp(cfg) % current values
isprop(cfg, 'EnableMemcpy') % does a candidate property exist?
Treat the live introspection — not memory of past releases — as ground truth. See references/config-properties.md for more.
| Directive | Purpose | Key gotcha | Available From |
|-----------|---------|-----------|---------------|
| %#codegen | Enable codegen analysis | Must be on/after function signature | R2011a |
| coder.typeof(val, sz, varDims) | Define input type+size for codegen call | varDims is logical array — true = variable | R2011a |
| coder.varsize('x', [bounds]) | Declare variable-size with upper bounds | Without bounds → requires DMA; declare before first assignment | R2011a |
| coder.const(expr) | Evaluate expr at compile time | Expression can be arithmetic, a function call, or a combination | R2013b |
| coder.extrinsic('fn') | Exclude function from compilation | No-op in lib/dll/exe unless paired with coder.const | R2011a |
| coder.inline('always'\|'never') | Control function inlining | Use 'always' for small hot helpers | R2011a |
| coder.unroll(range) | Unroll loop at compile time | Required for heterogeneous cell / varargin iteration | R2011a |
| coder.noImplicitExpansionInFunction | Disable broadcasting overhead | Only when operands always match in size | R2021b |
| coder.target('MATLAB') | Branch between MATLAB and codegen paths | Inactive branch is eliminated from generated code | R2011a |
| coder.nullcopy(zeros(m,n)) | Allocate without zeroing | Only safe if every element is written before read | R2011a |
| coder.ClassSignature | Direct class code generation entry point | Requires enableCodegenForEntryPointClasses once per session | R2026a |
For full directive documentation, load references/write-coder-directives.md.
| Mistake | Correct Approach |
|---------|-----------------|
| coder.screener('func') without capturing return value | res = coder.screener('func') then inspect res.UnsupportedCalls and res.Messages |
| Jumping straight to lib / dll without MEX verification | Generate MEX first, compare outputs to MATLAB, then generate the final target |
| EnableRecursion (does not exist) | EnableRuntimeRecursion |
| DynamicMemoryAllocation = 'Off' | EnableDynamicMemoryAllocation = false (logical, not char) |
| MemcpyThreshold = 0 to disable memcpy | EnableMemcpy = false |
| Comparing two interpreted MATLAB runs to "verify" generated code | Use coder.runTest (MEX replacement) or matlabtest.coder.TestCase; or SIL with Embedded Coder |
| coder.timeit(@myFunction, ...) (function handle) | coder.timeit('myFunction', numOutputs, {args}) — string name |
| Profiling the interpreted MATLAB function instead of the MEX | Profile myFunction_mex; interpreted MATLAB has different performance characteristics |
| Test script run under coder.runTest without assert statements | Always include assertions — coder.runTest produces no output on success otherwise |
| Building MEX in every test method with identical input types | Build once in TestClassSetup; rebuild per test only when input type specs differ |
| Calling the MATLAB function manually in matlabtest.coder.TestCase tests | verifyExecutionMatchesMATLAB calls MATLAB internally — just execute then verify |
| Command-syntax -d (outDir) for output directory | Function-call syntax: codegen('func', '-config', cfg, '-args', types, '-d', outDir) |
| Adding -report, -launchreport, or GenerateReport = true | Don't generate code reports unless explicitly requested |
| IntegrityChecks = false (MEX) without first running with checks on | Run with checks enabled across all expected inputs first; only disable after confirming no bounds errors |
| EnableDynamicMemoryAllocation = false and EnableVariableSizing = false together | Keep EnableVariableSizing = true so variable-size arrays stack-allocate at the upper bound |
| Growing array in loop (x = [x; row]) | Preallocate full array before loop |
| Using try/catch in codegen path | Return status codes; use coder.target('MATLAB') for MATLAB-only error handling |
| Variable changes type between assignments | One variable = one type throughout scope |
| Function returns different types/sizes on different paths | Ensure consistent output type and size on all paths |
| Missing %#codegen pragma | Always include after function signature |
| coder.extrinsic expecting runtime behavior in lib/dll | Extrinsic calls produce no code in portable targets; combine with coder.const |
| Using coder.ClassSignature / -class without enabling the Tech Preview | Run enableCodegenForEntryPointClasses once per MATLAB session before class code generation |
lowerCamelCase functions, arguments blocks, max 6 inputs / 4 outputs, end terminators.AbsTol / RelTol) rather than exact equality. Differences < 1e-10 relative are normal due to different math libraries.coder.typeof(example, [maxDims], [variableFlags]).coder.Constant for entrypoint inputs whose value is known at compile time so codegen can resolve downstream array sizes statically.----
Copyright 2026 The MathWorks, Inc.
----
Take matlab/matlab-generate-code from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.