Hello friends, I hope you are doing well. Today we will convert a MATLAB M-file into a P-file so another MATLAB user can run our function without receiving its readable implementation. We will start with one small calculation, create its P-code version, and then organize a distribution folder that includes everything needed to use it.

The basic command is short, but a reliable delivery requires a few additional decisions. Where will MATLAB write the output? Which copy of the function will run? Does the recipient have a compatible MATLAB release and the required toolboxes? We will answer these questions as we work through the example.

Figure: An example of readable M-file source; use the tutorial's pcode commands for conversion.

What Are M-Files and P-Files?

An M-file is a readable MATLAB program saved with the .m extension. It can contain a script, a function or a class definition. A P-file is a content-obscured executable representation of MATLAB source, saved with the .p extension. MATLAB executes it, but the MATLAB Editor does not expose its original source text.

According to the MathWorks pcode reference, the command accepts individual M-files or folders. Ordinary output goes to the current folder; use '-inplace' when you specifically want output alongside the input files. The source files remain available for future development.

PropertyM-fileP-file
PurposeDevelop and maintain MATLAB codeDistribute executable functionality with obscured implementation
Read or edit implementationYes, in a text editorNot through the MATLAB Editor
Normal function callUse the function name and argumentsUse the same public function name and arguments
Independent desktop applicationNoNo
Maintenance copyKeep this as the authoritative sourceRegenerate it when the source changes

What P-Code Protects

P-code helps when you want to share an algorithm's behavior while withholding the editable implementation. For example, you might supply a calculation routine to a project team with a documented interface while keeping its internal design in your development repository.

Describe this as obfuscation, not as an absolute guarantee against reverse engineering. It also does not prevent an authorized recipient from calling the function with different inputs and observing the results. Credentials, private keys and other secrets should not be placed in a distributed algorithm on the assumption that P-code makes them inaccessible.

MathWorks discusses several approaches in its source-code protection guidance, including P-code, compiled applications and controlled server execution. The appropriate choice depends on whether users need MATLAB integration, a standalone program or access to a remotely hosted calculation.

Step 1: Write a Small Function

Let us create a function that calculates the steady-state power dissipated by an ideal resistor. This is a useful example because we can calculate the expected answer independently:

P = V² / R

Here voltage is in volts, resistance is in ohms and power is in watts. Save the following code in a file named resistorPower.m. The function name and filename should agree.

function powerW = resistorPower(voltageV, resistanceOhm)
% RESISTORPOWER Calculate resistor power from voltage and resistance.
% voltageV can be a scalar or a real numeric array.
% resistanceOhm must be one positive, finite scalar.

validateattributes(voltageV, {'numeric'}, ...
    {'real', 'finite'}, mfilename, 'voltageV');
validateattributes(resistanceOhm, {'numeric'}, ...
    {'real', 'finite', 'scalar', 'positive'}, ...
    mfilename, 'resistanceOhm');

powerW = double(voltageV).^2 ./ double(resistanceOhm);
end

The dot before the exponent operator means that MATLAB squares each voltage value independently. The resistance is restricted to one positive scalar because zero resistance would make this expression undefined and negative resistance is outside this simple component model. Converting accepted numeric inputs to double avoids performing the arithmetic in an integer storage type.

The function describes an ideal resistance at a specified voltage. It does not account for temperature-dependent resistance or certify a physical resistor's power rating. Those remain separate component-selection questions.

Step 2: Establish Expected Results

Before converting anything, run the source function with a few easy cases:

voltageV = [0 5 10];
powerW = resistorPower(voltageV, 1000)

% Expected values in watts:
%     0    0.0250    0.1000

At 5 V across 1000 ohms, the calculation is 25/1000 = 0.025 W. At 10 V, it is 100/1000 = 0.1 W. Doubling voltage produces four times the power when resistance stays fixed. The zero-voltage case should return zero.

Also try resistorPower(5, 0). This should produce an input-validation error instead of an infinite result. Both correct answers and correct rejection of invalid inputs are part of the public behavior you want to preserve.

Keep these small checks with the source project. They let you distinguish an algorithm change from a packaging problem when a future release behaves differently.

Step 3: Create the P-File

Set MATLAB's current folder to the folder containing your function and run:

pcode('resistorPower.m')

You should now have a file named resistorPower.p. Continue calling the function by its original name:

powerW = resistorPower(5, 1000);

Do not add .p to that call. The public interface remains the function name, its two inputs and its returned result. There is no new installer and no separate operating-system command to learn.

The conversion command does not require you to delete your M-file. Preserve that source in a private development location, together with its documentation and tests. A generated delivery file is not a replacement for an editable development history.

Step 4: Confirm Which Function MATLAB Uses

Use MATLAB's function lookup command:

which resistorPower
which resistorPower -all

The first command identifies the resolved implementation. The second helps reveal duplicates on the search path. When matching M- and P-files are in the same folder, MATLAB gives the P-file precedence. This rule is documented in Function Precedence Order.

This is a common source of confusing results during development. You edit resistorPower.m, run the function again and see the old behavior because MATLAB still selects resistorPower.p. Keep generated files in a separate release directory or regenerate them whenever their source changes.

Also avoid assigning a workspace variable named resistorPower. That name then describes a variable, which can change how MATLAB interprets your expression. Distinct names for data and functions make an example much easier to troubleshoot.

Step 5: Build in a Separate Delivery Folder

For a real project, I prefer to keep development and delivery folders separate. The development folder contains source, tests and internal notes. The delivery folder contains only the approved executable files, public instructions and required supporting data.

The following example creates a new temporary delivery folder and restores the original working directory if conversion fails:

sourceFile = fullfile(pwd, 'resistorPower.m');
deliveryFolder = tempname;
mkdir(deliveryFolder);

originalFolder = pwd;
restoreFolder = onCleanup(@() cd(originalFolder));
cd(deliveryFolder);

pcode(sourceFile);
dir('*.p')

clear restoreFolder

Here we pass an absolute source path while working in the new delivery directory. That makes the destination unambiguous. The cleanup object restores the previous folder when it is cleared or leaves scope.

For repeatable releases, replace the temporary folder with a deliberately chosen versioned folder that does not already contain an older package. Check the archive contents before sharing it; source-control metadata, backup files and editor autosaves should not enter the delivery simply because they sit beside the source.

Converting Several Files

You can name several source files in one command or supply a folder. The following forms illustrate the syntax; substitute files that actually exist in your project:

pcode('calculateLoad.m', 'checkInputs.m');
pcode('sourceFunctions');
pcode('sourceFunctions', '-inplace');

A folder argument applies to its contained M-files. Do not assume one call automatically packages a complete application, recursively discovers every dependency or copies calibration data. For projects containing packages, private functions or class folders, retain the required directory organization and verify resolution from the final delivery layout.

For example, flattening a private folder into the top-level directory can change which callers can see a helper. Moving a package function out of its +packageName directory changes its qualified name. A distribution should preserve these relationships instead of collecting every P-file into one undifferentiated folder.

Release Compatibility

Modern MATLAB provides an enhanced P-code format selected with '-R2022a'; its files require R2022a or later. The legacy format can be requested with '-R2007b'. These options describe the P-code representation, not a converter that rewrites newer MATLAB functions for older releases.

% Run these only in a release supporting these options.
pcode('resistorPower.m', '-R2022a');

% Alternative when the legacy format is required:
% pcode('resistorPower.m', '-R2007b');

Suppose your algorithm calls a toolbox function introduced after the recipient's release. Selecting an older P-code format will not supply that missing function. Document and check three separate requirements: the P-code format, the language and function features used by the source, and the required products.

The original version of this tutorial predates the enhanced format. For an old installation, open doc pcode within that installation rather than copying options from newer documentation without checking availability.

Include Dependencies and Public Instructions

A P-file does not absorb all the functions or data it uses. If calculateLoad calls your helper checkInputs, both must remain available. A model that loads a MAT-file still needs that MAT-file at the expected location.

Where supported, begin dependency analysis on the readable entry point:

[requiredFiles, requiredProducts] = ...
    matlab.codetools.requiredFilesAndProducts('resistorPower.m');

disp(requiredFiles)
disp({requiredProducts.Name})

The MathWorks dependency-analysis reference describes the tool and its limitations. Treat its output as a starting inventory. File names constructed at run time, optional plugins and data selected interactively deserve separate review and recipient-side testing.

Include a short public usage document containing the function signature, supported input types, dimensions, units, output meaning, expected errors, MATLAB release and product requirements. An implementation that cannot be inspected needs especially clear interface documentation.

For our example, the public contract is simple: accept a finite real voltage array and a positive finite resistance scalar, then return a double array of power values with the same shape as the voltage input. The user does not need the source to understand that contract.

Test the Package as a Recipient

Testing from the development folder can hide missing dependencies because your source and private helper paths are still present. Open a clean MATLAB session, switch to the delivery folder and add only the documented supporting paths.

which resistorPower -all

actual = resistorPower([0 5 10], 1000);
expected = [0 0.025 0.1];
assert(max(abs(actual - expected)) < 1e-12);

disp('Example calculation matches the expected values.')

This is a suggested check for you to run in MATLAB, not a claim that the article's example has been executed on your installation. Repeat it on the oldest release and each operating environment you promise to support.

If external MEX binaries are part of the application, their platform and compiler dependencies need separate attention. A MATLAB-only P-file does not remove those requirements.

Choosing a Distribution Method

Recipient needsSuitable directionQuestion to resolve
Call a function from MATLABP-code with documented dependenciesWhich MATLAB releases and products are required?
Run an application without MATLAB installedMATLAB Compiler deploymentWhich runtime and deployment requirements apply?
Use an algorithm in native softwareSupported code generation and binary integrationIs the algorithm supported by the selected generator?
Use a calculation without receiving its implementationControlled server executionHow are authentication, availability and data handled?
Simulate a protected block modelSimulink model protectionWhat simulation or code-generation capabilities are needed?

Common Problems

SymptomLikely explanationNext step
My source edit has no effectAn older P-file is selectedCheck which and rebuild the delivery
The P-file is missing beside the sourceOutput was written to the working directoryInspect pwd and the selected destination
Recipient sees an undefined functionA dependency or path is missingTest the complete package in a clean session
Conversion rejects a live scriptpcode takes M-files, not MLX filesMove the computational interface into an M-file function
An older MATLAB cannot run the deliveryFormat or function compatibility mismatchBuild and test for the agreed release

Practical Review

We created a source function, established simple expected results, generated a P-file and examined the path and packaging issues that determine what the recipient actually runs. The most useful habits are keeping editable source privately, generating a fresh delivery directory and testing with only the delivered files available.

P-code is convenient for sharing a MATLAB interface without its readable implementation. It does not replace dependency management, version compatibility or a sensible approach to confidential data. When you change the source, regenerate and identify the matching delivery so users can report exactly which version they used.

Frequently Asked Questions

Should I delete the original M-file?

No. Keep it privately for maintenance and future releases. Omit it from the recipient package if you intend to distribute only the obscured implementation.

Do I call the P-file differently?

No. Call the same public function name with the same arguments. Use which when you need to check the selected implementation.

Does a P-file run without MATLAB?

A P-file by itself is not a standalone executable. Choose a deployment workflow designed for users without MATLAB when that is the requirement.

Will conversion make the algorithm faster?

Do not treat source protection as a performance optimization. Measure the actual workload and improve its computation, data movement or numerical method when speed is the goal.

Can I protect a Simulink model with pcode?

P-code applies to MATLAB program files. A Simulink block diagram needs a model-oriented delivery workflow, which we discuss in the next tutorial.

How should I update a delivered function?

Modify the source, repeat its behavioral checks, create a fresh P-code package and publish a clear version description. Keep the matching source revision so a reported problem can be reproduced.