Bndbuild Examples
This page documents working examples from the cpclib-bndbuild/tests directory. Each example demonstrates different features and use cases of bndbuild.
Note: Build files use a mix of Jinja templating and YAML syntax.
Table of Contents
- Basic Examples
- dummy - Basic Snapshot Build
- hello_world - DSK Creation
- Templating Examples
- jinja - Variable Substitution
- expansion - Advanced Target Expansion
- Assembler Integration
- orgams - Monogams/Orgams Workflow
- C Language Support
- hello_c - C Compilation
- Music and Audio
- ay_players - AY Music Players
- at3 - Arkos Tracker 3
- chipnsfx - ChipNSFX Music
- Data Compression
- crunch - Multiple Crunchers
- Complex Projects
- ucpm - Multi-Format Project
- delegated - Delegated Build Rules
- Emulator Integration
- emu - Emulator Launching
- watch - Watch Mode
- Help System
- help - Rule Help
Basic Examples
dummy - Basic Snapshot Build
Location: cpclib-bndbuild/tests/dummy
A simple project demonstrating snapshot generation with basm, image conversion with img2cpc, and emulator integration.
Build file: bndbuild.yml
- tgt: build
dep: dummy.sna
help: Ask to build the snapshot file without explicitly giving its name
- tgt: dummy.sna dummy.lst dummy.sym
dep: dummy_code.asm dummy_logo.o dummy_logo_palette.bin
cmd: basm dummy_code.asm --snapshot -o dummy.sna --lst dummy.lst --sym dummy.sym --sym_kind winape
help: Generate the snapshot file using basm
- tgt: dummy_logo.o dummy_logo_palette.bin
dep: dummy_logo_exin.bmp
cmd: >
img2cpc dummy_logo_exin.bmp
--mode 1 sprite
-c dummy_logo_conf.asm
--palette dummy_logo_palette.bin
-o dummy_logo.o
help: Convert the BMP file and generate the necessary data to build it
- tgt: clean
phony: true
cmd:
- -rm *.o *.bin *.lst
- -rm dummy_logo_conf.asm
help: Remove all needed generated files
- tgt: distclean
phony: true
dep: clean
cmd: -rm dummy.sna
help: Remove the snapshot
- tgt: m4
dep: build
cmd: xfer 192.168.1.26 -y dummy.sna
help: Send the generated snapshot to the M4 card corresponding to the given IP address
- tgt: cpcec
dep: build
cmd: emu --emulator cpcec --snapshot dummy.sna run
- tgt: winape
dep: build
phony: true
cmd: emu --emulator winape --snapshot dummy.sna run
- tgt: ace
dep: build
phony: true
cmd: emu --emulator ace --snapshot dummy.sna run
Key Features: - Snapshot generation with basm - Image conversion with img2cpc - Multiple emulator targets - M4 transfer support - Clean and distclean rules
hello_world - DSK Creation
Location: cpclib-bndbuild/tests/hello_world
Demonstrates two approaches to creating DSK files: directly from basm and as post-processing.
Build file: bndbuild.yml
#!/usr/bin/env -S bndbuild -f
- tgt: dsk
dep: hello1.dsk hello2.dsk
help: In this example, we add files to a dsk directly from basm (hello1.dsk) or as a postprocessing (hello2.dsk)
- tgt: HELLO2.BIN hello1.dsk
dep: hello.asm
cmd: basm hello.asm --header -o HELLO2.BIN
- tgt: hello2.dsk
dep: HELLO2.BIN
cmd:
- dsk hello2.dsk format --format data
- dsk hello2.dsk add HELLO2.BIN
- tgt: clean
cmd: -rm HELLO2.BIN
- tgt: distclean
dep: clean
cmd: -rm hello1.dsk hello2.dsk
Key Features: - DSK formatting and file addition - AMSDOS header generation - Multiple command execution
Templating Examples
jinja - Variable Substitution
Location: cpclib-bndbuild/tests/jinja
Shows how to use Jinja templating for variable substitution and conditional logic.
Build file: bndbuild.yml
#!/usr/bin/env -S bndbuild -f
# bndbuild -DCPCADDR=<myip> m4 if you want a specific address for the M4
# bndbuild -DASSEMBLER=rasm m4 if you want to assemble with rasm (needs to be on the PATH) instead of basm
# bndbuild -DASSEMBLER=rasm --dot | dot -Tpng | display if you want to see the dependency tree for rasm-based construction
{%- if not CPCADDR -%}
{%- set CPCADDR = "192.168.1.26" -%}
{%- endif -%}
{{ASSEMBLER}}
{%- if not ASSEMBLER -%}
{%- set ASSEMBLER = "basm" -%}
{%- endif -%}
{{ASSEMBLER}}
{%- macro assemble(base) -%}
{%- if ASSEMBLER == "rasm" -%}
rasm {{base}}
{%- elif ASSEMBLER == "basm" -%}
basm {{base}}
{%- else -%}
{{- fail("wrong ASSEMBER value: " + ASSEMBLER) }}
{%- endif -%}
{%- endmacro -%}
{%- set source = "test.asm" -%}
{%- set prog = "TEST" %}
- dep: {{source}}
tgt: {{prog}}
cmd: {{assemble(source)}}
- tgt: distclean
phony: true
cmd: -rm {{prog}}
- dep: {{prog}}
tgt: m4
cmd: xfer {{CPCADDR}} -y {{prog}}
Key Features:
- Variable definition and defaults
- Conditional logic
- Jinja macros
- Command-line variable override (-D flag)
- Error handling with fail()
expansion - Advanced Target Expansion
Location: cpclib-bndbuild/tests/expansion
Demonstrates target expansion and automatic variable substitution.
Build file: bndbuild.yml
- dep: A B C
tgt: E10 E20 E30
cmd: extern touch $@ E20 E30
- dep: E10 E20 E30
tgt: E40 E35 E33
cmd: extern touch $@ E35 E33
Key Features:
- Multiple targets from single rule
- Automatic variable $@ for first target
- Target expansion logic
Assembler Integration
orgams - Monogams/Orgams Workflow
Location: cpclib-bndbuild/tests/orgams
Integration with Orgams assembler running on Albireo emulation.
Build file: build.bnd
#!/usr/bin/env -S bndbuild -f
{% set FROM="cpcfolder" %}
{% set SRC="BORDER.O" %}
{% set DST="BORDER" %}
# Note :
# 0 is written in #BOOT.CFG of the albireo folder. It means unidos does not try to access the other drives (and we do not lost time with a wrong drive configuration)
# of course, an emulator is used to assemble the file
# `bndbuild edit` to open monogams on the source
# `bndbuild exec` to assemble and launch the executable
# `bndbuild cpc` to launch an my CPC
- tgt: exec
dep: {{FROM}}/{{DST}}
cmd: emu --albireo {{FROM}} -k run --text "run\"BORDER\n"
- tgt: cpc
dep: {{FROM}}/{{DST}}
cmd: xfer 192.168.1.26 -y {{FROM}}/{{DST}}
- tgt: {{FROM}}/{{DST}}
dep: {{FROM}}/{{SRC}}
cmd: orgams --from {{FROM}} --src {{SRC}} --dst {{DST}}
# open monogams to edit the file
- tgt: edit
phony: true
cmd: emu --albireo {{FROM}} -k run --text "ùo,\"{{SRC}}\n"
- tgt: distclean
phony: true
cmd: -rm {{FROM}}/{{DST}}
Key Features: - Orgams assembler integration - Albireo folder simulation - Editor integration - Keyboard automation
C Language Support
hello_c - C Compilation
Location: cpclib-bndbuild/tests/hello_c
Demonstrates using bndbuild as a Make-like system for C projects.
Build file: bnd.build
- tgt: run
dep: hello
cmd:
- extern pwd
- extern ls -l
- extern ./hello world
- tgt: clean
cmd: -rm *.o
- tgt: distclean
dep: clean
cmd: -rm hello
- tgt: hello
dep: hello.o main.o
cmd: extern gcc hello.o main.o -o hello
- tgt: hello.o
dep: hello.c hello.h
cmd: extern gcc -c hello.c
- tgt: main.o
dep: main.c hello.h
cmd: extern gcc -c main.c
Key Features: - External command execution - Standard C compilation workflow - Object file dependency management
Music and Audio
ay_players - AY Music Players
Location: cpclib-bndbuild/tests/ay_players
Converts YM music files to different player formats (FAP, Miny, AYT).
Build file: bnd.build
#!/usr/bin/env -S bndbuild -f
# `bndbuild ace` plays the first music
# `bndbuild ace -DMUSIC_IDX=n` plays the nth music (starts with 0)
# This build file conver the musics in farious formats
# The list of musics and their buffer size
# TODO find a way to automatically get the buffer size
{%-
set MUSICS = [
("FenyxKell - Bobline", "&b42"),
("Targhan - A Harmless Grenade", "&b42"),
("Targhan - Hocus Pocus", "&c48"),
("Tom&Jerry - Boules Et Bits (Extended)", "&c48"),
("Tom&Jerry - From Scratch - Part 1", "&a64"),
("UltraSyd - Fractal", "0xb42")
]
-%}
# handle the music selection
{% if MUSIC_IDX %}
{% set PARAMS=MUSIC_IDX|int%}
{% else %}
{% set PARAMS=3%}
{% endif %}
{% if not PLAYER_FORMAT%}
{% set PLAYER_FORMAT="fap" %}
{% endif %}
{% if PLAYER_FORMAT == "fap" %}
{% set SNA="fap.sna" %}
{% elif PLAYER_FORMAT == "miny" %}
{% set SNA="miny.sna" %}
{% elif PLAYER_FORMAT == "ayt" %}
{% set SNA="ayt.sna" %}
{% endif %}
# get the appropriate value of the selected music
{%- set selected_music = MUSICS[PARAMS][0] -%}
{%- set fap_selected_music = MUSICS[PARAMS][0] + ".fap" -%}
{%- set miny_selected_music = MUSICS[PARAMS][0] + ".miny" -%}
{%- set ayt_selected_music = MUSICS[PARAMS][0] + ".ayt" -%}
{%- set fap_buff_size = MUSICS[PARAMS][1]-%}
{%- macro fap_rule(file, opt=None) %}
{% set ym_file = "ym/" + file + ".ym" %}
{% set fap_file = file + ".fap" %}
- dep: "\"{{ym_file}}\""
tgt: "\"{{fap_file}}\""
cmd: fap "ym/{{ym_file}}" "{{fap_file}}" {%if opt %}{{opt}}{% endif %}
{% endmacro -%}
{%- macro miny_rule(file) %}
{% set ym_file = "ym/" + file + ".ym" %}
{% set miny_file = file + ".miny" %}
- dep: "\"{{ym_file}}\""
tgt: "\"{{miny_file}}\""
cmd: miny pack "{{ym_file}}" "{{miny_file}}"
{% endmacro -%}
{%- macro ayt_rule(file) %}
{% set ym_file = "ym/" + file + ".ym" %}
{% set ayt_file = file + ".ayt" %}
- dep: "\"{{ym_file}}\""
tgt: "\"{{ayt_file}}\""
cmd: ayt --verbose --target CPC "{{ym_file}}" # -o and --output are not recognized despite the documentation ...
{% endmacro -%}
{% for (music, size) in MUSICS %}
{{fap_rule(music)}}
{{miny_rule(music)}}
{{ayt_rule(music)}}
{% endfor %}
# build the sna test music
# it uses
# - the converted fap file
# - the init and play binary code provided by FAP automatically downloaded by bndbuild
# - the sour of the test program
- tgt: fap.sna
dep: "\"{{fap_selected_music}}\" players/fap.asm"
phony: true
cmd: |
basm players/fap.asm --snapshot -o fap.sna
-DFAP_INIT_PATH="\"{{FAP_INIT_PATH|basm_escape_path}}\""
-DFAP_PLAY_PATH="\"{{FAP_PLAY_PATH|basm_escape_path}}\""
-DMUSIC="\"{{fap_selected_music}}\""
-DBuffSize="{{fap_buff_size}}"
- tgt: miny.sna
dep: "\"{{miny_selected_music}}\" players/{ymp.z80,miny.asm}"
phony: true
cmd: |
basm players/miny.asm --snapshot -o miny.sna
-DMUSIC="\"{{miny_selected_music|basm_escape_path}}\""
Key Features:
- Multiple music player formats
- Music selection via command-line variables
- Complex Jinja templating with lists and loops
- Preset variable usage (FAP_INIT_PATH, FAP_PLAY_PATH)
at3 - Arkos Tracker 3
Location: cpclib-bndbuild/tests/at3
Converts Arkos Tracker 3 songs to multiple formats and generates WAV files.
Build file: build.bnd
# `bndbuild generate_all` convert the music in the 4 expected formats
# `bndbuild play` uses vlc to play the wav version of the music
# `bndbuild at3` opens AT3. Sadly AT3 does not take input arguments, so it cannot automatically open a given file
- tgt: generate_all
phony: true
dep:
- "'Targhan - Crtc - End part.akm'"
- "'Targhan - Crtc - End part.aky'"
- "'Targhan - Crtc - End part.akg'"
- "'Targhan - Crtc - End part.wav'"
- tgt: play
phony: true
dep: "'Targhan - Crtc - End part.wav'"
cmd: extern vlc "$<"
- tgt: at3
phony: true
cmd: at3
{% macro convert_music(converter, from, to) -%}
- tgt: "{{to}}"
dep: "{{from}}"
cmd: {{converter}} {{from}} {{to}}
{%- endmacro %}
{% macro compile_akm(from, to) -%}
{{convert_music("SongToAkm", from, to)}}
{%- endmacro %}
{% macro compile_aky(from, to) -%}
{{convert_music("SongToAky", from, to)}}
{%- endmacro %}
{% macro compile_akg(from, to) -%}
{{convert_music("SongToAkg", from, to)}}
{%- endmacro %}
{% macro to_wav(from, to) -%}
{{convert_music("SongToWav", from, to)}}
{%- endmacro %}
{{ compile_akm("'Targhan - Crtc - End part.aks'", "'Targhan - Crtc - End part.akm'") }}
{{ compile_akg("'Targhan - Crtc - End part.aks'", "'Targhan - Crtc - End part.akg'") }}
{{ compile_aky("'Targhan - Crtc - End part.aks'", "'Targhan - Crtc - End part.aky'") }}
{{ to_wav("'Targhan - Crtc - End part.aks'", "'Targhan - Crtc - End part.wav'") }}
- tgt: distclean
phony: true
cmd: -rm *.akm *.akg *.wav *.aky
Key Features: - Arkos Tracker format conversions - WAV generation and playback - Filename with spaces handling - Reusable conversion macros
chipnsfx - ChipNSFX Music
Location: cpclib-bndbuild/tests/chipnsfx
Demonstrates ChipNSFX music compilation and integration with BASIC.
Build file: build.bnd
{# use -DSELECTED_MUSIC="other.chp" to select another music #}
{%- if not SELECTED_MUSIC -%}
{%- set SELECTED_MUSIC = "WINGSOD5.CHP" -%}
{%- endif -%}
{# use -DEMULATOR="ace" to open with ace #}
{%- if not EMULATOR -%}
{%- set EMULATOR = "cpcec" -%}
{%- endif -%}
{# Generic macro that could used anywhere. takes a .CHP and build a .asm #}
{% macro compile_chipnsfx(from, to="chipnsfz.mus", opt="-t") -%}
- tgt: {{to}}
from: {{from}}
cmd: chipnsfx {{from}} {{to}} {{opt}}
{%- endmacro %}
{# Generate the rule that compile a musix #}
{{ compile_chipnsfx(SELECTED_MUSIC, opt="-lchip_song_ -t") }}
{# Build the basic file that contains player and mlusic #}
- tgt: CHIPNSFZ.BAS
dep: CHIPNSFZ.S80 CHIPNSFX.I80 chipnsfz.mus
cmd: uz80 -q CHIPNSFZ.S80 -o$@
{# Create a dsk to transfert #}
- tgt: CHIPNSFZ.DSK
dep: CHIPNSFZ.BAS
cmd:
- dsk $@ format
- dsk $@ add $<
{# launch on an emulator #}
- dep: CHIPNSFZ.DSK
tgt: emu
phony: true
cmd: emu --emulator={{EMULATOR}} --drivea=CHIPNSFZ.DSK --auto-run-file CHIPNSFZ.BAS run
- tgt: distclean
phony: true
cmd: -rm *.BAS *dsk chipnsfz.mus
Key Features: - ChipNSFX music compilation - BASIC file generation with uz80 - Emulator selection variable - DSK creation and auto-run
Data Compression
crunch - Multiple Crunchers
Location: cpclib-bndbuild/tests/crunch
Tests various compression formats supported by bndbuild.
Build file: bnd.build
- tgt: all
dep: crunch.exo crunch.lz48 crunch.apultra crunch.lz4 crunch.lz49 crunch.lzsa1 crunch.lzsa2 crunch.shrinkler crunch.zx0
- tgt: distclean
phony: true
cmd: -rm crunch.exo crunch.lz48 crunch.apultra crunch.lz4 crunch.lz49 crunch.lzsa1 crunch.lzsa2 crunch.shrinkler crunch.zx0
- tgt: crunch.exo
dep: bnd.build
cmd: crunch -c exomizer -i $< -o $@
- tgt: crunch.lz48
dep: bnd.build
cmd: crunch -c lz48 -i $< -o $@
- tgt: crunch.lz49
dep: bnd.build
cmd: crunch -c lz48 -i $< -o $@
- tgt: crunch.apultra
dep: bnd.build
cmd: crunch -c apultra -i $< -o $@
- tgt: crunch.lz4
dep: bnd.build
cmd: crunch -c lz4 -i $< -o $@
- tgt: crunch.lzsa1
dep: bnd.build
cmd: crunch -c lzsa1 -i $< -o $@
- tgt: crunch.lzsa2
dep: bnd.build
cmd: crunch -c lzsa2 -i $< -o $@
- tgt: crunch.shrinkler
dep: bnd.build
cmd: crunch -c shrinkler -i $< -o $@
- tgt: crunch.zx0
dep: bnd.build
cmd: crunch -c zx0 -i $< -o $@
Key Features: - Multiple compression formats - Exomizer, LZ48, LZ49, ApUltra, LZ4, LZSA1, LZSA2, Shrinkler, ZX0 - Automated $< and $@ variable usage
Complex Projects
ucpm - Multi-Format Project
Location: cpclib-bndbuild/tests/ucpm
A complex project using multiple assemblers, Orgams integration, and various output formats.
Build file: build.bnd
#!/usr/bin/env -S bndbuild -f
{% set DSK="u c p m.dsk" %} # Spaces for the fun
{% set SNA="ucpm.sna" %}
{%- if not CPCADDR -%} {# Modify hard coded address #}
{%- set CPCADDR = "192.168.1.24" -%}
{%- endif -%}
{%- macro ace(dsk, exec=None, debug=None) -%}
cpc --emu ace --drivea "{{dsk}}" --disable-rom orgams --disable-rom unidos
{%- if debug %} --debug {{debug}} {%endif -%}
{%- if exec %} --autoRunFile {{exec}} {%endif -%}
run
{%- endmacro -%}
{%- macro build_data(data) -%}
- tgt: {{data}}.o
dep: {{data}}.asm
cmd: rasm {{data}}.asm -ob {{data}}.o
{%- endmacro -%}
- tgt: sna
dep: {{SNA}}
- tgt: dsk
dep: "\"{{DSK}}\"" # These ugly quotes are mandatory because
# of spaces in filename and yaml string encoding
# best is to avoid spaces
- tgt: "\"{{DSK}}\" {{SNA}} ucpm.rasm ucpm.lst"
dep: ucpm.asm data1.o data2.o orgams/DATA3.BIN
cmd: >
basm ucpm.asm
--snapshot -o {{SNA}}
--ace ucpm.rasm
--lst ucpm.lst
--override
-DUCPM_EXEC=\"UCPM\" # this is a string
-DUCPM_DSK="\"{{DSK}}\"" # this is a string with spaces
{{build_data("data1")}}
{{build_data("data2")}}
- tgt: orgams/DATA3.BIN
dep: orgams/DATA3.O
cmd: orgams --from orgams --src DATA3.O --dst DATA3.BIN
- tgt: monogams
phony: true
cmd: orgams --from orgams --src DATA3.O --edit
- tgt: emu
dep: "\"{{DSK}}\" ucpm.rasm"
cmd: -{{ace(DSK, "UCPM", debug="ucpm.rasm")}}
- tgt: m4
dep: {{SNA}}
cmd: xfer {{CPCADDR}} -y {{SNA}}
- tgt: clean
phony: true
cmd: -rm data?.o ucpm.rasm ucpm.lst orgams/DATA3.BIN
- tgt: distclean
dep: clean
phony: true
cmd: -rm "{{DSK}}" {{SNA}}
Key Features: - Multiple assemblers (basm, rasm, orgams) - Filenames with spaces - ACE debug file generation - Orgams folder-based workflow - Complex macro usage
delegated - Delegated Build Rules
Location: cpclib-bndbuild/tests/delegated
Demonstrates delegating build tasks to external build files.
Build file: build.bnd
# This example demonstrates delegated builds where one build file references another
# See the source code for implementation details
Key Features: - Delegated build rules - External build file references
Emulator Integration
emu - Emulator Launching
Location: cpclib-bndbuild/tests/emu
Tests emulator launching on different platforms.
Build file: bndbuild.yml
#!/usr/bin/env -S bndbuild -f
# execute properly both on linux and windows
- tgt: ace
cmd: ace ../../../cpclib/tests/dsk/harley.dsk -autoRunFile '-CED-.exe'
# execute properly both on linux and windows
- tgt: cpcec
cmd: cpcec ../../../cpclib/tests/dsk/harley.dsk
# Fail to properly provide the file both on linux and windows
- tgt: winape
cmd: winape ../../../cpclib/tests/dsk/harley.dsk /A:-CED-.exe
Key Features: - Cross-platform emulator launching - ACE, CPCEC, WinAPE support - Auto-run file specification
watch - Watch Mode
Location: cpclib-bndbuild/tests/watch
Example for testing watch mode functionality.
Build file: bnd.build
# Watch mode example - monitors file changes and automatically rebuilds
# Use: bndbuild --watch <target>
Key Features: - File watch mode - Automatic rebuild on changes
Help System
help - Rule Help
Location: cpclib-bndbuild/tests/help
Demonstrates the help system for documenting build rules.
Build file: bnd.build
Key Features: - Rule documentation - Help text display
Summary
These examples cover: - Basic builds: Snapshot generation, DSK creation - Templating: Variables, conditionals, loops, macros - Assemblers: basm, rasm, orgams integration - Languages: Assembly, C, BASIC - Audio: YM, Arkos Tracker, ChipNSFX - Compression: Multiple cruncher formats - Emulators: ACE, CPCEC, WinAPE - Hardware: M4 transfer, Albireo
All examples are maintained as working tests in the repository and serve as both documentation and regression tests.