This tutorial introduces a way to set up projects that use Cakelisp. This isn't the only way, so you shouldn't feel you have to follow this format.
An example repository (which also uses GameLib) is available here.
Prerequisites
The following operating systems are supported by Cakelisp:
- GNU/Linux
- macOS
- Windows
Anything POSIX/Unix-y will likely work because Cakelisp uses the C++ standard library and the platform's C/C++ compiler only.
You need a C++ compiler installed or available to build Cakelisp itself.
Cakelisp will use this compiler while cakelisp
is running to build
compile-time code. You also need your target's C/C++ compiler so
Cakelisp can build the code it generates.
You should install git for the best experience. You can download the code manually, but that will make getting updates harder.
Project setup
The assumption GameLib makes is
that your project's root directory has a Dependencies
directory with
cakelisp
inside it. This is only expected by GameLib, but enables a
whole bunch of convenience.
For this tutorial, we will set up a new directory tree like so:
my-project/
src/
Dependencies/
Build.sh
(orBuild.bat
on Windows)
I also recommend you include a COPYING
for copyright and LICENSE
for
license if you plan to ever upload or distribute your code.
Getting Cakelisp
Let's get cakelisp with git
. In my-project/
:
git clone https://macoy.me/code/macoy/cakelisp.git Dependencies/cakelisp
Submodules
If you are using Git on your project, I recommend you use submodules to track Cakelisp's version. To do so, instead of the above command, run this:
git submodule add https://macoy.me/code/macoy/cakelisp.git Dependencies/cakelisp
That way, I can freely update Cakelisp and your project won't break, because your project tracks a specific version of Cakelisp.
Building the project
Now that we have Cakelisp's source code downloaded, we need to set up a script to build both Cakelisp and our project.
First, let's create an empty .cake
file where we will put a "Hello
World". I typically name this the same as the project, or Main.cake
.
We'll call it MyProject.cake
and put it in src/
:
(c-import "<stdio.h>") (defun main (&return int) (fprintf stderr "Hello, world! From Cakelisp!\n") (return 0))
Now, to build the project, we need to do slightly different things on Windows vs. on GNU/Linux or macOS. Skip the section for platforms you aren't worrying about for now.
The line with src/MyProject.cake
determines which file your project
should start the build with. You can add files as necessary, or use
(import)
within any of the files included on that line.
On GNU/Linux and macOS
#!/bin/sh CAKELISP_DIR=Dependencies/cakelisp # Build Cakelisp itself echo "\n\nCakelisp\n\n" cd $CAKELISP_DIR ./Build.sh || exit $? cd ../.. echo "\n\nMy Project\n\n" CAKELISP=./Dependencies/cakelisp/bin/cakelisp $CAKELISP --execute src/MyProject.cake || exit $?
On Windows
cd Dependencies\cakelisp call Build.bat @if %ERRORLEVEL% == 0 ( echo Successfully built Cakelisp goto user ) else ( echo Error while building cakelisp goto fail ) :user cd ../../ "Dependencies\cakelisp\bin\cakelisp.exe" --execute src/MyProject.cake @if %ERRORLEVEL% == 0 ( echo Success! goto success ) else ( echo Error while building user program goto fail ) :fail goto end :success goto end :end echo Done
Building
Now, open a terminal or command prompt and navigate to the project's
root directory. Type ./Build.sh
or Build.bat
and hit enter.
You should see output saying that Cakelisp is being built. Once that succeeds, Cakelisp will build itself again, but this time using Cakelisp's build system rather than the Build scripts. This is a good way to test that things in Cakelisp are hooked up to the compiler properly.
The build script we wrote also builds and runs our project. It runs it
because of --execute
. You can remove that if desired.
You should see the following output, if all things go well:
Cakelisp bin/cakelisp_bootstrap does not exist. Building bootstrap executable manually Built bin/cakelisp_bootstrap successfully. Now building with Cakelisp Successfully built and linked bin/cakelisp Cakelisp successfully bootstrapped. Use ./bin/cakelisp to build your files My Project Successfully built and linked a.out Hello, world! From Cakelisp!
Troubleshooting
Permission denied
Run chmod +x Build.sh
to give the build script executable permissions,
then run ./Build.sh
again.
No such directory "Dependencies/cakelisp"
Check you are in project's root directory when running build script.
Download cakelisp to Dependencies/cakelisp
.
Build fails after "Building bootstrap executable manually", and "Built bin/cakelisp~bootstrap~ successfully." was not output
Check Dependencies/cakelisp/Build.sh
. Does it reference your system's
compiler toolchain correctly? Edit it if not.
Build fails after "Built bin/cakelisp~bootstrap~ successfully.", and "Successfully built and linked bin/cakelisp" was not output
Cakelisp itself must not refer to your system's compiler toolchain
correctly. Open ModuleManager.cpp
and find your platform in
moduleManagerInitialize()
. You may need to edit these defaults.
Another option is to look at
Dependencies/cakelisp/runtime/Config_Mingw.cake
and add similar code
to the Dependencies/cakelisp/Bootstrap*.cake
script for your platform.
This allows you to override Cakelisp's default compiler toolchain
variables.
Build fails after "Cakelisp successfully bootstrapped."
At this point, Cakelisp is building successfully, but your project is failing to build. There are many ways this can happen:
Incorrect process commands
Edit your build script to include --verbose-processes
on the same line
with src/MyProject.cake
(there should be a space on both sides of
--verbose-processes
):
$CAKELISP --execute --verbose-processes src/MyProject.cake
That will cause output for all the subprocesses Cakelisp launches. By
running these commands, you can more quickly diagnose compiler issues.
See cakelisp/runtime/Config_*.cake
files for references on how to
override cakelisp's default compiler/linker.
Invalid Cakelisp code
Cakelisp should print an error saying where it encountered a problem.
Please email [email protected]
if you encounter errors you don't know
how to proceed to fix. By telling me about your error experience, I can
write better errors that help save everyone frustration!
Invalid generated code
If you have errors output by your C/C++ compiler or linker, Cakelisp is successfully generating code, but the generated code is invalid. This is where knowing C/C++ is important. Cakelisp assumes a relatively strong grasp of C, so read up on C if you are trying to find problems at this stage.
If the generated C is syntactically invalid (e.g., missing a semicolon),
please email [email protected]
, because it may be an issue with Cakelisp.
Using GameLib
GameLib is a collection of generally useful modules for applications and game development.
GameLib uses Cakelisp's compile-time code execution features to
automatically download dependencies as you (import)
them. It is the
closest thing to a package manager Cakelisp has, and could be compared
to Go's remote packages (and
I believe Rust has similar functionality).
To add Gamelib, we clone it using git:
git clone https://macoy.me/code/macoy/gamelib.git Dependencies/gamelib
# Or, if using git for your project
git submodule add https://macoy.me/code/macoy/gamelib.git Dependencies/gamelib
Read Dependencies/gamelib/ReadMe.org
for an overview of how GameLib
works and what modules it offers.
Example: Using raylib
Let's use raylib. GameLib has a
Raylib.cake
module that will automatically download, build, and
statically link Raylib to your project.
Modify src/MyProject.cake
to include the following:
;; Tell Cakelisp what our directory structure is (set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src") (set-cakelisp-option cakelisp-lib-dir "Dependencies/cakelisp/bin") (add-cakelisp-search-directory "Dependencies/gamelib/src") (add-cakelisp-search-directory "Dependencies/cakelisp/runtime") (add-cakelisp-search-directory "src") ;; Edit this with your platform. 'Windows or 'Unix (comptime-define-symbol 'Unix) (import "Raylib.cake") (defun main (&return int) (InitWindow 800 450 "raylib [core] example - basic window") (while (not (WindowShouldClose)) (BeginDrawing) (ClearBackground RAYWHITE) (DrawText "Congrats! You created your first window!" 190 200 20 LIGHTGRAY) (EndDrawing)) (CloseWindow) (return 0))
Now, when you run ./Build.sh
(or Build.bat
), you should see the
following:
My Project
Dependencies/raylib: Automatically adding as submodule from https://github.com/raysan5/raylib.git
Cloning into '/home/macoy/Repositories/cakelisp-tutorial-project/Dependencies/raylib'...
Raylib: Building via Configure and Make
...
It will output the building of Raylib as well as building your project. Note that it only downloads and builds Raylib if you don't already have it downloaded and built. You should only have to wait for this once for your project.
Adding your own 3rd party dependencies
Look at gamelib/src/
and see how the various dependencies are
implemented. SDL.cake
is a good example of a module which also
includes helper functions added for Cakelisp. You should see how
add-dependency-git-submodule
makes it much more convenient to obtain
dependencies. Unlike Rust or Go, this feature is completely optional.