Project Layout
Overview
Once you have initialized your project from the MatlabProjectTemplate (“MPT”) template (using ./init_project_from_template
), you’ll have a directory structure that looks like this:
├── CHANGES.txt
├── LICENSE
├── Makefile
├── MatlabProjectTemplate/
├── Mcode/
│ └── +mycoolpackage/
│ ├── +examples/
│ ├── +internal/
│ ├── +logger/
│ ├── +test/
│ ├── Settings.m
│ └── globals.m
├── MyCoolProject.prj.in
├── README.md
├── VERSION
├── azure-pipelines.yml
├── .circleci/
├── .travis.yml
├── build/
├── dist/
├── dev-kit/
├── docs/
├── doc/
├── doc-project/
│ ├── Description for File Exchange.txt
│ ├── Developer Notes.md
│ ├── Release Checklist.md
│ └── TODO.md
├── examples/
├── info.xml
├── .matlab_version
├── .mlproject.json
├── lib/
│ ├── java/
│ └── matlab/
├── mycoolpackage_toolbox_info.m
├── project_settings.sh
└── src/
├── c/
└── java/
The main bits are:
Mcode/
– Your Matlab source code goes here!CHANGES.txt
– A changelog for your projectLICENSE
– Documents the licensing terms for your projectMakefile
– Defines how your project is builtMatlabProjectTemplate
– Doco about MatlabProjectTemplate (not your project)MyCoolProject.prj.in
,info.xml
,mycoolpackage_toolbox_info.m
– Config files for packaging your project as a Matlab ToolboxVERSION
– Central record of what version your project is onazure-pipelines.yml
,.circleci
,travis.yml
– Config files for Continuous Integration providersbuild/
– Where your intermediate build products godist/
– Where your final build products for distribution godev-kit/
– Developer tools for working on your project itselfdocs/
– The source for your project documentationdoc/
– Where your generated project documentation goesdoc-project/
– Documentation for internal use by your project’s developersexamples/
– Code examples to go with your project.matlab_version
– The version of Matlab your project is targeting.mlproject.json
– Configuration file that sets MPT-related options, such as how your project is builtlib/
– Third-party libraries you depend onproject_settings.sh
– Settings used to initialize your project from the templatesrc/
– Your non-Matlab custom source code
I’m really sorry for having both doc
and docs
; that’s confusing. I had to use the name docs
to be compatible with GitHub Pages. And doc
is the only thing that makes sense to me for the final built documentation that goes into the distribution.
Details
Mcode
This is the core of your project: where your Matlab source code goes! This is what will end up on the Matlab path for people using your project.
Mcode/+mycoolpackage
The top-level package for your project. All your code should go inside a package, to prevent name collisions with other people’s code. This makes it feasible to use multiple projects in a Matlab environment.
The code that users of your package will use – that is, the public API of your package – goes directly in here. If you have a really large package, you might want to break it out in to subpackages.
Mcode/+mycoolpackage/+examples
Example code that ships with your package. This is different from the top-level /examples/
in that code here is stuff you want to always be available at run time when someone has your package loaded in to Matlab. The /examples
stuff is more documentation-oriented, and the user has to pull that in separately.
Mcode/+mycoolpackage/+internal
Code for internal use by your package. This is a safe space to put stuff that is not part of your public API, and is undocumented and subject to change at any time, and you don’t want users calling directly.
Mcode/+mycoolpackage/+internal/+util
Little utility functions that wrap basic Matlab commands like system
and rmdir
with an exception-oriented interface, so you don’t have to write return-value-checking code each time you call them. This makes it a lot more concise to write scripts and functions that do a sequence of filesystem operations or system calls.
This stuff is written as a bunch of functions in a package (instead of static methods on a class) so you can do import mycoolpackage.internal.util.*
in your code and get all of them. None of the names here collide with Matlab standard library functions, so it’s safe to do so.
Normally I wouldn’t provide this much utility stuff in a simple project template, but I needed to supply them for dev-kit
’s implementation anyway, and all Matlab code actually should be using wrappers like this, so why not?
Mcode/+mycoolpackage/+logger
Support for SLF4M-compatible logging that’s built in to your package. We do it this way so you don’t have to take a dependency on SLF4M, because managing dependencies in Matlab is kind of a pain, and can lead to DLL Hell.
Mcode/+mycoolpackage/+test
Your unit tests go here. You’re going to write unit tests, right?
Author your unit tests using the Matlab Unit Test Framework.
Mcode/+mycoolpackage/globals.m
Global state, settings, and info about your package. This is a central class to store an run-time settings and global state your package may have. It also allows clients of the package to programmatically query its version and location at run time.
Mcode/+mycoolpackage/Settings.m
is a structure for your package’s settings that lives in a field on globals
. It has to be a separate class because Matlab doesn’t support mutable static class properties, only immutable Constant
ones. So we use the trick of defining a separate mutable handle
class for the settings structure, and sticking that in a Constant
field on globals
.
MyCoolProject.prj.in – Toolbox Packaging
The MyCoolProject.prj.in
, info.xml
, and mycoolpackage_toolbox_info.m
files are used for packaging your project as a Matlab Toolbox.
The project definition is supplied as a .prj.in
file instead of a .prj
file, because Matlab bakes absolute file paths into its .prj
files when you use the Toolbox packager. This is a flaw that makes .prj
projects unsuitable for sharing between multiple developers, or even for use in different repo locations or on different OSes by a single developer. So we define a .prj.in
file and then munge it into a .prj
file at each build time.
README.md
Summary info about your project. This is what any user will read first. It should have a summary of what your project does, how to install and use it, a quickstart guide and maybe some examples, and links to where to get more info and help.
dev-kit/
These are the development tools for working with and building your project itself. They are for the internal use of your project’s developers, and are not included in your package distribution.
Most of the stuff in here is used by calling make
instead of running the scripts directly.
What’s in dev-kit
:
package_mycoolpackage_toolbox
,batch_package_mycoolpackage_toolbox.m
– Code for packaging your project as a Matlab toolbox. Used by themake toolbox
target.build_mycoolpackage
– Does the build for distribution. Matlab isn’t a compiled language, so there’s no compile step required, but there is P-coding and maybe some other code munging stuff used to prepare M-code for distribution.buildallmexfiles_in_mycoolpackage.m
– Just what it sounds like. Searches yourMcode/
tree for MEX source files and compiles them all.load_mycoolpackage.m
– Loads the package. This is just used for bootstrapping the package for stuff likemake build
ormake test
runs.locate_matlab.sh
– Shell support for locating Matlab in environments where it’s not on the$PATH
by default. (That is, Macs.)make_release
– Does a release of your package! Takes care of updatingVERSION
, doing tests and builds, and tagging your release in Git.
Building the MEX files is done manually by the developer at code authoring time, not as part of the package build process. This is because, unlike binary artifacts in many programming languages, MEX files should actually be kept in the source tree and checked in to the Git repo, so that your program can be run directly from the repo without going through a build step. Many users, and even many developers, may not have an environment capable of easily building MEX files.
dist/
This is where the final packaged files (“release artifacts”) for distribution show up. Your project’s zip files and Matlab Toolbox .mltbx
files will show up here.
doc/
The built documentation for your project. This is what will be presented to your users, and is included in the distribution files.
You shouldn’t edit files in here directly. They are generated from the doc source files in docs/
by the make doc
target.
See Writing Documentation for more info.
I’m really sorry for having both doc
and docs
directories; that’s confusing. I had to use the name docs
to be compatible with GitHub Pages. And doc
is the only thing that makes sense to me for the final built documentation that goes into the distribution.
docs/
Source files for the project documentation. This is the stuff you should edit.
This contains Markdown, AsciiDoc, and other document formats used by Jekyll or mkdocs to build the stuff in doc.
See Writing Documentation for more info.
doc-project/
This is where you put internal developer-facing documentation for people working on your project itself. Things like code style guides, developer notes, a release checklist, and anything else documenting your development process go here.
examples/
Code examples for presentation to your users.
Because examples are useful for inclusion in your documentation, this folder is automatically copied into docs/
by the make doc-src
target.
.mlproject.json
Project settings that control stuff like how your project is built.
This is an MPT-defined file that I came up with, not a standard Matlab thing.
.matlab_version
The central place defining what version of Matlab your project is targeting. This is the “source of truth”; the other places in the project’s config files where the Matlab version appears are driven from this.
This is an MPT-defined file that I came up with, not a standard Matlab thing.
lib/
Third-party libraries that your package depends on.
If your project has custom Java code, its JAR files will also go here, just as if it were an external library. (Because really, it kind of is.)
lib/java
The lib/java/
subdirectory contains Java libraries. Each Java library should be in a lib/java/<libname>
subdirectory, with all its .jar
files immediately in that <libname>
subdirectory. If you’re using MatlabProjectTemplate’s automatic library initialization feature, all the jars in all the libs here will be automatically added to the Matlab javaclasspath
for you.
lib/matlab
External non-Toolbox Matlab libraries that you depend on and are redistributing with your package go here.
Each Matlab library should be in a lib/matlab/<libname>
subdirectory here.
There’s no standard layout or loading mechanism for non-Toolbox Matlab libraries (until now! 😉), so the package initialization code uses some heuristics to guess where the M-code in these libraries is located and get it on the Matlab path. Basically, if you take a submission from File Exchange, unzip it, and drop the resulting directory in here, it’ll probably work.
lib/c
C/C++ or other “native” libraries will go here.
I haven’t defined any further structure for this directory or how its contents will be loaded when your package is initialized. You’ll have to write custom library-loading code in your package initialization for now. Suggestions are welcome!
project_settings.sh
This is the configuration file you edit before running init_project_from_template
to define your basic project properties and metadata. It’s not used after that, so you can throw it away once your project is initialized, but I’d keep it around just in case, because I’m like that. Who knows, maybe you’ll need to re-run the project initialization if MatlabProjectTemplate is improved over time?
src/
This is all your project’s custom source code in languages besides Matlab.
src/java
Your project’s custom Java code.
Your Java code is contained in a MyCoolProject-java
directory here which contains a Maven project.
To build your Java code and install it in to your project’s lib/java
, run make java
in your repo root, or cd in to src/java/MyCoolProject-java
, run mvn package
, and copy the resulting .jar
file over manually.
Building your Java code should be done at code authoring time, not at project build time, because your M-code needs that JAR to run, and you should be able to run your code directly from the repo. For this same reason, the JAR for your custom Java code in lib/java/MyCoolProject-java
should be checked in to your Git repo.
src/c
Source code for your C/C++ and other “native” libraries or programs will go here.
I haven’t defined any further structure for this directory or how its contents will be built. You’ll have to come up with your own solution and build files for now. Suggestions are welcome!