Awesome
Docker Libdragon
This is a wrapper for a docker container to make managing the libdragon toolchain easier. It has the additional advantage that libdragon toolchain and library can be installed on a per-project basis instead of managing system-wide installations.
Prerequisites
You should have docker (>= 27.2.0
) and git installed on your system.
Installation
This is primarily a node.js script which is also packaged as an executable. You have a few options:
installer
Download the windows installer and run it. This option is currently only available on Windows.
<details> <summary>Detailed instructions</summary>- Download the Windows installer and run it
- It can show a "Windows protected your PC" warning. Click "More info" and "Run anyway".
- You should now be able to use the
libdragon
on a command line or PowerShell. - To update it with a new version, download a newer installer and repeat the steps above.
pre-built executable
Download the pre-built executable for your system and put it somewhere on your PATH. It is discouraged to put it in your project folder.
<details> <summary>Windows instructions</summary>- Download the Windows executable and copy it to
C:\bin
- Press
Windows + R
key combination and then enterrundll32 sysdm.cpl,EditEnvironmentVariables
- In the
Environment Variables
window find thePath
variable underUser variables for <your user name>
- Double click it and add a new entry as
C:\bin
- Restart your computer.
- You should now be able to use the
libdragon
on a command line or PowerShell. - To update it with a new version, just replace the file in
C:\bin
- Download the MacOS executable and copy it to
/usr/local/bin
- Right click it and choose
Open
. - It will show a warning, approve it by clicking
Open
again. You can close the newly opened terminal window. - You should now be able to use the
libdragon
command. - To update it with a new version, replace the file in
/usr/local/bin
and repeat the other steps.
- You should already know this :)
via NPM
Install node.js (>= 22
) and install libdragon
as a global NPM package;
npm install -g libdragon
To update the tool to the latest, do npm i -g libdragon@latest
.
Quick Guide
Navigate to the folder you want to initialize your project and invoke libdragon;
libdragon init
On first init
an example project will be created, the container will be downloaded, started and latest libdragon will get installed on it with all the example ROMs built. You can find all the example ROMs in the libdragon/examples
folder.
The container's make
can be invoked on your current working directory via;
libdragon make
Any additonal parameters are passed down to the actual make command. You can work on the files simultaneously with the docker container and any built artifacts will be available in project directory as it is mounted on the container.
To update the library and rebuild/install all the artifacts;
libdragon update
In general, you can invoke libdragon as follows;
libdragon [flags] <action>
Run libdragon help [action]
for more details on individual actions.
Recipes
Using a different libdragon branch
Use the --branch
flag to set up a custom libdragon branch when initializing your project:
libdragon init --branch unstable
This will use the unstable
toolchain and code.
Switching to a different branch of libdragon
On an already initialized project, switch the submodule to the desired branch:
git -C ./libdragon checkout opengl
libdragon install
If your changes are on a different remote, then you will need to manage your git remotes as usual. If you also want to update the remote tracking branch for the submodule, run:
git submodule set-branch -b opengl libdragon
This will update the branch on .gitmodules
and if you commit that change, subsequent initializations will use the opengl
branch by default.
Testing changes on libdragon
As libdragon is an actively developed library, you may find yourself at a position where you want to change a few things on it and see how it works. In general, if you modify the files in libdragon
folder of your project, you can install that version to the docker container by simply running:
libdragon install
This will update all the artifacts in your container and your new code will start linking against the new version when you re-build it via libdragon make
. The build system should pick up the change in the library and re-compile the dependent files.
Instead of depending on the above command, you can automatically re-build the library by making it a make dependency in your project:
libdragon-install:
$(MAKE) -C ./libdragon install
If your build now depends on libdragon-install
, it will force an install (which should be pretty quick if you don't have changes) and force the build system to rebuild your project when necessary.
If you clone this repository, this setup is pretty much ready for you. Make sure you have a working libdragon setup and you get the submodules (e.g git submodule update --init
). Then you can run libdragon make bench
to execute the code in ./src
with your library changes. Also see test bench.
When managing your changes to the library, you have a few options:
Using submodule
vendor strategy.
To be able to share your project with the library change, you would need to push it somewhere public and make sure it is cloned properly by your contributors. This is not recommended for keeping track of your changes but is very useful if you plan to contribute it back to upstream. In the latter case, you can push your submodule branch to your fork and easily open a PR.
Using subtree
vendor strategy.
To be able to share your project with the library change, you just commit your changes. This is very useful for keeping track of your changes specific to your project. On the other hand this is not recommended if you plan to contribute it back to upstream because you will need to make sure your libdragon commits are isolated and do the juggling when pushing it somewhere via git subtree push
.
Working on this repository
After cloning this repository on a system with node.js (>= 18
) & docker (>= 27.2.0
), in this repository's root do;
npm install
This will install all necessary NPM dependencies. Now it is time to get the original libdragon repository. (you can also clone this repository with --recurse-submodules
)
git submodule update --init
Then run;
npm run libdragon -- init
to download the pre-built toolchain image, start and initialize it. This will also install test bench dependencies into the container if any.
Now you will be able to work on the files simultaneously with the docker container and any built binaries will be available in your workspace as it is mounted on the container.
There is a root Makefile
making deeper makefiles easier with these recipes;
bench: build the test bench (see below)
examples: build libdragon examples
tests: build the test ROM
libdragon-install: build and install libdragon
clean-bench: clean the test bench (see below)
clean: clean everything and start from scratch
For example, to re-build the original libdragon examples do;
npm run libdragon -- make examples
Similarly to run the clean
recipe, run;
npm run libdragon -- make clean
[!IMPORTANT] Keep in mind that
--
is necessary for actual arguments when using npm scripts.
To update the submodule and re-build everything;
npm run libdragon -- update
Local test bench
The root bench
recipe is for building the code in root src
folder. This is a quick way of testing your libdragon changes or a sample code built around libdragon, and is called the test bench. This recipe together with examples
and tests
recipes will build and install libdragon automatically as necessary. Thus, they will always produce a rom image using the libdragon code in the repository via their make dependencies, which is ideal for experimenting with libdragon itself.
There are also vscode launch configurations to quickly build and run the examples, tests and the bench. If you have ares on your PATH
, the launch configurations ending in (emu)
will start it automatically. For the examples configuration, you can navigate to the relevant .c
file and Run selected example
will start it most of the time. In some cases, the output ROM name may not match the .c
file and in those cases, you can select the ROM file instead and it should work.
[!NOTE] This repository also uses UNFLoader, so you can use the launch configurations without
(emu)
to run the code if you have a supported flashcart plugged in and haveUNFLoader
executable on yourPATH
.The special
Debug Test Bench (emu)
configuration will start ares with remote debugging for the test bench if you havegdb-multiarch
executable on yourPATH
. It should automatically break in yourmain
function.
You can clean everything with the clean
recipe/task (open the command palette and choose Run Task -> clean
).
Developing the tool itself
For a quick development loop it really helps linking the code in this repository as the global libdragon installation. To do this run;
npm link
in the root of the repository. Once you do this, running libdragon
will use the code here rather than the actual npm installation. Then you can test your changes in the libdragon project here or elsewhere on your computer. This setup is automatically done if you use the devcontainer.
When you are happy with your changes, you can verify you conform to the coding standards via:
npm run format-check
npm run lint-check
You can auto-fix applicable errors by running format
and lint
scripts instead. Additionally, typescript is used as the type system. To be able to get away with transpiling the code during development, jsDoc flavor of types are used instead of inline ones. To check your types, run:
npm run tsc
To run the test suite:
npm run test
This repository uses semantic-release
and manages releases from specially formatted commit messages. To simplify creating them you can use:
npx cz
It will create a semantic-release
compatible commit from your current staged changes.
Experimental devcontainer support
The repository provides a configuration (in .devcontainer
) so that IDEs that support it can create and run the Docker container for you. Then, you can start working on it as if you are working on a machine with libdragon installed.
With the provided setup, you can continue using the cli in the container and it will work for non-container specific actions like install
, disasm
etc. You don't have to use the cli in the container, but you can. In general it will be easier and faster to just run make
in the container but this setup is included to ease developing the cli as well.
To create your own dev container backed project, you can use the contents of the .devcontainer
folder as reference. You don't need to include nodejs or the cli and you can just run build.sh
as postCreateCommand
. See the devcontainer.json
for more details. As long as your container have the DOCKER_CONTAINER
environment variable, the tool can work inside a container.
Caveats
- In the devcontainer, uploading via USB will not work.
- Error matching is not yet tested.
- Ideally the necessary extensions should be automatically installed. This is not configured yet.
- Make sure you have the Dev container extension installed and you fulfill its requirements.
- Clone this repository with
--recurse-submodules
or rungit submodule update --init
. - Open command palette and run
Dev Containers: Reopen in container
. - It will prepare the container and open it in the editor.
As an NPM dependency
You can install libdragon as an NPM dependency by npm install libdragon --save
in order to use docker in your N64 projects. A libdragon
command similar to global installation is provided that can be used in your NPM scripts as follows;
"scripts": {
"prepare": "libdragon init"
"build": "libdragon make",
"clean": "libdragon make clean"
}
Funding
If this tool helped you, consider supporting its development by sponsoring it!