bundle-gen
is a tool for making bundles for the Atari VCS. A bundle
is a software package that the console user can choose to install, as
opposed to software that makes up the core platform, which is managed
externally. This tool takes a specification file and produces an
installable bundle for the VCS.
You will need Docker installed on your machine, and to have the
necessary permissions to use it. It's most convenient to use the
make-bundle.sh
bash script to launch the tool - how to run this
depends on your system. On a modern Linux distribution, it is as
simple as adding it to your PATH
.
In this section we'll build the example bundles, and see how to use
bundle-gen
in two standard scenarios.
We'll start with an example of using bundle-gen
to create a real
Homebrew bundle.
We'll be building game contained in the Atari HTML Pong Example repository, which can be found at
https://github.com/atari-vcs/html-example-bundle
The HTML Pong example has a specification file,
html-pong-example.yaml
, in the root of the repository. This is the
input for the bundle-gen
tool. The contents of that file are:
Name: "Html Pong Example"
HomebrewID: "HTMLPongExample"
Type: Game
Exec: res/index.html
Launcher: chrome
Build:
VersionFile: version.txt
Resources:
- index.html
- bounce.wav
- explosion.wav
- atari-controller.js
- style.css
- script.js
In general, you will want to put your specification file at the top level of your project - this will be explained later.
There are two parts to this file. The first part, lines 1-5, describes
the game to the VCS - the necessary metadata - so that it can be
displayed in the right places to users, and so that the VCS knows how
to start it. The second part, the Build
section, describes the files
that make up the bundle, and how to generate them (if necessary).
This is a very simple bundle. The first 5 lines say:
- List this bundle to users as "Html Pong Example" (its
Name
). - This is a Homebrew bundle (it doesn't come from the store, users
install it themselves via Homebrew), and its unique identifier
(
HomebrewID
) isHTMLPongExample
. This identifier is mostly there so that you don't end up with lots of copies of it, if you reinstall it. There's no issuer for these ideas, it's up to you to make it not clash with any other Homebrew bundles. - It should be listed under games not under applications (
Type
isGame
notApplication
). - The VCS can launch it by passing the file in
res/index.html
inside the bundle tochrome
. So this is a bundle containing a web page that is displayed by Google Chrome.
The Build
section says:
- Take the version of the bundle from the file
version.txt
in the same directory as this YAML file (VersionFile
). - Include the following static list of files (
Resources
) from the current directory into the bundle, underres/
.
To make a bundle from this repository, we'll want to have the bundle-gen
scripts available. These scripts are written for bash
, so you should
be able to run them in any suitable environment, although we test
exclusively on modern Linux machines.
If you have the bundle-gen scripts in your path, then in the top level of the HTML Pong Example repository, you can simply run
make-bundle.sh html-pong-example.yaml
Otherwise you'll need to give the full path to make-bundle.sh
. If
your system doesn't support shebangs (#!
to select a script
interpreter, e.g. Windows), you may need to run it as:
bash /path/to/make-bundle.sh html-pong-example.yaml
The script is very simple, so if you're familiar with your environment, you may find it easier to replace it with one of your own (e.g. a Windows batch file).
The result of running this command will be a file
html-pong-example_0.1.0.bundle
or similar (the version might change,
depending upon when you are reading this guide, 0.1.0
is current
at the time of writing).
You can now use Atari Homebrew to upload this bundle directly to your VCS and play it.
Now that you have a grasp of the basics, it's time to look at a more
complicated example. bundle-gen
primarily exists to make it easier
and less error-prone to create bundles containing native code.
We'll cover the Native Indy800 Example here, which can be downloaded from GitHub
https://github.com/atari-vcs/native-example-bundle
In the root of the native example bundle's repository there is a YAML
file, which can be used by bundle-gen
to build this bundle. It has
the following contents:
Name: "Native Indy 800 Example"
HomebrewID: "NativeIndy800Example"
Type: Game
Exec: bin/native
Build:
VersionFile: version.txt
RequiredPackages:
- cmake
- g++
RequiredModules:
- mod/sdl2-mixer.mod
BuildCommand: build_script.sh
Executables:
- native
Resources:
- res/
The first section of this bundle is very similar to the previous
example. It's a Homebrew bundle, containing a Game
. Notice that
there is no longer a Launcher
: we are going to build a program that
is directly executable on the VCS. Also notice that the Exec
part
says that the file to run will be under bin/
(where conventionally
executable files are placed) rather than res/
(where data is usually
placed).
The Build
section contains most of the changes. This repository is
built with cmake
, and the code is written in C++, so we install the
(Atari-provided) system packages for cmake
and g++
(the GNU C++
compiler) into our build environment using RequiredPackages
. This
will not affect the host machine: the build runs in a Docker image.
Not every dependency you might have can be installed from the VCS
package repositories. For things you can't find there, you can use
modules. For example SDL2 mixer is not current provided in binary
form for the Atari VCS, and the native example depends on it. The
RequiredModules
key gives an ordered list of scripts to run to set
up the build environment for your own build. It's structured this way
so that you can share and re-use modules for common libraries.
Remember to be careful to respect the licensing terms of libraries
that you link against.
The contents of sdl2-mixer.mod
are:
#!/bin/bash
export DEBIAN_FRONTEND=noninteractive
apt-get install -y --no-install-recommends git
mkdir -p /usr/src
cd /usr/src
git clone -b release-2.0.4 https://github.com/libsdl-org/SDL_mixer.git
cd /usr/src/SDL_mixer
./configure --prefix=/usr
make -j$(nproc)
make install
This will clone the official SDL2 mixer repository at the 2.0.4 release tag (the latest at the time of writing) then build and install it. Going through the script in sections:
- The first line is a shebang (
#!
) to tell a Linux system how to run this script. The build environment is always the Atari VCS Linux variant, regardless of what your host environment is, so you can rely on shebangs working. - The next section installs
git
into the build environment, so that we can clone the repository. The extra options and variables around it are just to stopapt-get
from ever prompting for user confirmation. - The next section clones the source for SDL2 mixer into
/usr/src/SDL_mixer
. - The last section configures SDL2 mixer to install into
/usr
(i.e. a system-wide install - this is safe because it only affects the temporary build environment), and to use as many cores as possible to do the build.
You can in principle build any dependencies you might have using
modules. You should prefer packages when they are available, because
they install much more quickly - the module has to run a build every
single time you rebuild the bundle, although you can mitigate some of
this for bigger libraries, by using a build directory under /build
that will persist between rebuilds - and because customisations for
the VCS may have been applied to Atari supplied packages.
Unlike our earlier, simpler example, there is now a build stage to
making our bundle. We need to do the build within the bundle-gen
build environment so that we get the right binary format and shared
library dependencies for the VCS. In this example, the build script is
just called build_script.sh
. It has the following contents:
#!/bin/bash
cmake /source
make -j$(nproc)
As mentioned before, when we're building our bundle, we're running in
an Atari VCS environment in a Docker image. The provided script,
make-bundle.sh
maps two host directories into that Docker image:
/source
is mapped to the directory containing the specification (YAML) file./build
is mapped to the current directory at the time you ran the script. If you runmake-bundle.sh
from the same directory as your YAML file, then both/build
and/source
are mapped to the same directory.
Your initial working directory in the build environment will be
/build
, so the build script given here can be used to perform an out
of tree cmake
build, just by making an empty directory and running
make-bundle.sh
from there.
Once the build script has completed, the final two sections of the specification file will be used:
Executables
gives a list of native (ELF-format) programs to copy into thebin/
directory of your bundle.Resources
as before gives a list of files or directories to copy over into theres/
directory of your bundle.
There are a couple of things to note here. All shared libraries that
your executables depend on from your build container, that are not
part of the standard VCS base system, will be added to your bundle in
lib/
automatically. In the vast majority of cases, you can just
ignore this issue from a technical standpoint, although you must of
course always bear in mind the licensing terms of any third party
software you choose to distribute in your own bundles.
Directories in the list of resources are treated differently,
depending upon whether they have a trailing slash. A trailing slash
(as the example has) means to copy the contents of the directory into
res/
; no trailing slash means to copy the directory itself. If we
removed the trailing slash in the example, our resulting bundle would
have a directory res/res/
.
As before we'll need to have the bundle-gen scripts available. The
native example is tested with an out of tree build. So after cloning
it, create a directory build
in the top level
of the native example bundle repository, change into that directory,
and run
make-bundle.sh ../native-indy800-example.yaml
The result of running this command will be a file
native-indy-800-example_0.1.0.bundle
or similar (the version might change,
depending upon when you are reading this guide, 0.1.0
is current
at the time of writing).
You can now use Atari Homebrew to upload this bundle directly to your VCS and play it.
This section provides a short-form overview of all the functionality
provided by bundle-gen
.
bundle-gen
is built into a Docker image suitable for creating binaries
for the Atari VCS: the Docker image has an entrypoint set to the
bundle-gen
tool from this repository.
The included script make-bundle.sh
will mount into the Docker image:
- Your current directory as
/build
. - The directory containing the specification file as
/source
.
The only argument to either the Docker image or make-bundle.sh
is a
specification file; this argument is mandatory.
Your /source
directory will be mounted read-only, and your /build
directory will be mounted writable. For the common case of your
game or application's build system using an out of tree build, you
should invoke the make-bundle.sh
from your build directory. For an
in-tree build, invoke it in the same location as the specification
file.
When run through the standard script, the bundle-gen
tool will not
have access to directories above your specification file, so you
should usually place the bundle specification file in the top level of
your project. You can however modify the script, if needed.
All the packages initially installed on the Docker image, and any
packages additional packages you request, are drawn from the Atari VCS
OS apt
repositories. They are mostly a subset of the packages
available in Debian, so you can use Debian package searches online to
identify the names of the packages you will need. Packages listed
under RequiredPackages
are installed before your modules (if any)
run, and before your build script. You should make sure that you are
aware of, and obey, the licensing terms of any packages you use. The
use of packages is optional.
Modules provide an easy way to make use of software that isn't included
in the official Atari VCS OS repositories. Each module is just an
executable program. They are conventionally written for bash
, but
they could be written in any language that you have installed into the
build image, and could even be executable programs if you know they
are binary compatible with the VCS environment (for example,
self-extracting launchers).
Note that modules are run on each and every build, and naive modules
can lead to long build times. If you want to speed things up, you need
to do any required caching of build products within the module
itself. You may also find it helpful to use a directory under /build
to store your sources and generated object files, to avoid repeating
compilation. Modules are intended to be self-contained, so that you
can re-use them between projects, and perhaps share them with other
developers. Note that you are responsible for honoring the license
terms of any software you install using modules.
To improve re-usability, it is wise to install any packages your module requires within the module itself. This will make it easier to transfer modules directly between projects, without needing to find out each module's required environment: a module should establish its own required environment.
The use of modules is optional.
A build script is not required. If present it will be run after the
the required packages and modules have been installed. It must be
executable. Its initial working directory will be /build
, which is
writable, and (if using the standard script, make-bundle.sh
) is the
directory from which the tool was launched.
You may find it helpful within your build script to generate a version file, for example from your git repository tags, or otherwise. This is supported: a version will not be assigned to your bundle until the build script has run, and there is a field in the specification for the file to read the version from.
Each bundle you want to generate has its own specification file, in
YAML format, which can be passed to bundle-gen
. The contents of this
file are described in this section.
The first part of the YAML specification file is very similar to the
bundle.ini
file that each bundle contains. It contains:
Name
: The human readable name of your program, which will be shown to users.Type
: The kind of bundle you are making:Game
,Application
orLauncherOnly
. Note that both games and applications can be launchers as well, butLauncherOnly
titles will not be shown in the user's list of installed games on the dashboard (Homebrew bundles cannot be launchers, they can only use them).StoreID
: For store bundles, the unique identifier obtained from Atari for your product. This is guaranteed unique.HomebrewID
: For Homebrew bundles, an identifier you chose for your game or application; you're responsible for its uniqueness.Exec
: Either the command to run, if you don't specify a launcher, or the arguments to provide to your chosen launcher.Background
: For store bundles only, specify that this bundle runs in the background. Optional, defaults to false.PreferXBoxMode
: Request that the VCS controllers be set to emulate XBox360 controllers before your program starts. You lose out on unique Atari functionality, but you might find it easier to get compatible behaviour with other platforms. Optional, defaults to false.Launcher
: Request that another program be used to run your program, for example an emulator, or web browser. This is a tag name, and the VCS will match it to a launcher providing that tag amongst its list ofLauncherTags
. Optional.LauncherTags
: For store bundles only, instruct the VCS to use your bundle to launch games specifying any of the given list of launcher tags.LauncherExec
: For store bundles only, the command to run when functioning as a launcher. The environment variableBUNDLE_PATH
will point to the install location of the bundle you have been asked to run. The active home directory will be that bundle's home directory.
The Build section contains the instructions for generating files and including them in your bundle. It has the following keys, which are effectively worked through in order:
-
First, the
RequiredPackages
key is read, and any listed packages are installed into the Docker image. -
Then the
RequiredModules
key is read, and all listed modules are run directly. -
Next, the
BuildCommand
key is read, and the script given there is found and executed. -
Now the
VersionFile
is read, and the version of the bundle identified. This is just plain text, and its contents will be trimmed at the ends for whitespace before becoming the version string -
A bundle archive is created with the same name stem as the YAML file, but with a version appended as found in the previous step.
-
All the files listed under
Executables
are found and put intobin/
in the bundle. -
All the libraries listed under
Libraries
are found and put intolib/
in the bundle. You do not need to list system libraries, they will be discovered automatically. -
You can, if necessary, specify additional files whose dependencies you want to include from the build image using
ExtraElfFiles
. These files are not automatically copied into the archive, only their dependencies. This is only needed in rare circumstances, for things like dynamically loaded plugins that can't be identified automatically upfront, and can't be placed underlib/
for some reason. -
All the shared system libraries on the Docker image that your bundle depends upon, which aren't available by default on the VCS, are found and put into
lib/
in the bundle. -
All the files listed under
Resources
are found and put intores/
in the bundle. The lookup is the same as forExecutables
,Libraries
andBuildCommand
. A trailing slash on a directory means to copy only the contents, discarding the directory. Without a trailing slash, the directory itself will appear underres/
.