RISC OS Makefile System
Overview
RISC OS components are built with AMU (Acorn Make Utility) using the command riscos-amu.
Component makefiles are named Makefile,fe1 (the ,fe1 suffix is the RISC OS AMU filetype).
Each component makefile sets a small number of variables describing the component, then includes a shared makefile that provides all the build rules:
COMPONENT = MyTool
OBJS = o.main
LIBS = ${CLIB}
include LibraryCommand
Shared makefiles are located via the AMUFILES environment variable (on Linux/Mac) or
the Makefiles$Path system variable (on RISC OS). Include them by name only — no path.
Variables set before the include configure the build.
Rules and extra targets placed after the include extend or override the build.
For detailed AMU makefile-language behaviour, read
references/makefile-language.md from this skill. Keep that reference aligned
with the riscos-help makefiles topic when behaviour or conventions change.
AMU Makefile Language
AMU makefiles are plain ASCII text, usually stored as Makefile,fe1. A
makefile is read as logical lines; a trailing \ continues a logical line onto
the next physical line.
Comments begin with #. The special comment:
# Dynamic dependencies:
marks the section that AMU and related tools may update automatically. Leave it in place even when it is empty.
The main line types are:
- dependency lines,
target : prerequisites - command lines, which must begin with white space
- macro definition lines such as
NAME = value - special-rule lines such as
.PHONY: test
For compatibility, prefer a tab at the start of command lines. A single-command
rule may also be written as target:; command.
AMU Macros and Directives
Macros are referenced as ${NAME} or $(NAME). Macro names are
case-insensitive, unlike GNU make.
Assignment forms supported by AMU:
=lazy expansion:=immediate expansion?=assign only if unset+=append
Macros may also be pre-defined on the command line, for example
riscos-amu BUILD64=1 or riscos-amu COMPONENT=MyTool.
Useful built-in and automatic macros include:
$@current target$*matched stem in inference rules$<inferred source dependency$?prerequisites newer than the targetMAKE,MFLAGS,MAKEFLAGS,MAKECMDGOALS__riscos,__crosscompile, and the older host-side name__linux
Directives and parsing features commonly seen in project makefiles:
includeand.include; prefix with-to ignore missing filesifeq,ifneq,ifdef,ifndef,else,endifVPATHfor prerequisite search paths::to keep repeated rules for the same target distinct
Special Targets and Functions
Special targets with practical impact:
.PHONYmarks synthetic targets that should always run.SILENTsuppresses command echoing globally.IGNOREignores command failures globally.INITruns before requested targets.DONEruns after a successful build.FAILEDruns after a failed build.DEFAULTprovides a fallback rule.SUFFIXEScontrols suffix inference rules.UNIXNAMESfavours Unix-style filename handling
Command prefixes:
@suppresses echoing for one command-ignores failure for one command
AMU supports a useful subset of GNU-make-style functions. The ones agents are most likely to encounter in real project makefiles are:
- text/list helpers:
subst,patsubst,strip,sort,findstring,filter,filter-out,word,wordlist,words,firstword,lastword,join,addprefix,addsuffix - filename helpers:
dir,notdir - control helpers:
if,foreach,call,warning,error,origin wildcardfor simple existence checkslcas a non-standard lower-case helper
Do not assume full GNU make compatibility. In particular, wildcard is not a
full shell-style expander, and suffix, basename, and shell should not be
relied upon as dependable features.
Building
riscos-amu # 32-bit build (default)
riscos-amu BUILD26=1 # 26-bit build (legacy)
riscos-amu BUILD64=1 # 64-bit build
Makefile targets are passed as arguments:
riscos-amu clean
riscos-amu export
riscos-amu ram
riscos-amu test
If a component has no shared testing convention, add a small project-local test target after the shared makefile include. For a C module smoke test, make it depend on ram and run the module with a BASIC test driver:
.PHONY: test
test: ram
riscos-build-run rm32/Module,ffa tests/test-module,fd1 --command "RMLoad Module" --command "Run test-module"
Use distinct RISC OS leaf names for the module and the test driver. riscos-build-run copies inputs into the guest by leaf name, so tests/module,fd1 can collide with rm32/Module,ffa.
Creating a New Project
Use riscos-project to generate a skeleton with the correct file layout:
riscos-project create --type command --name PROJECTNAME --skeleton
riscos-project create --type cmodule --name PROJECTNAME --skeleton
For desktop applications, choose a conventional RISC OS application name for
COMPONENT: capitalised, and usually without hyphens. For example, prefer
WimpClicks over wimp-clicks.
Always build the skeleton before editing to confirm the toolchain is working.
Shared makefile quick picks
Use these shared makefiles by default:
LibraryCommandfor command-line tools and standalone executables.CModulefor C modules using CMHG.AsmModulefor assembly modules.LibExportfor libraries intended to be exported.CAppandBasicAppfor desktop applications.Documentationfor PRM-in-XML-only components.Resourcefor resource-only components.
Read references/shared-makefile-types.md when you need the detailed variable
tables, export behaviour, or per-makefile caveats.
Common targets and architecture
The targets agents most often need are all, ram, rom, install,
export, resources, and clean. Architecture is controlled with at most one
of BUILD26=1, BUILD32=1, or BUILD64=1.
Read references/shared-makefile-types.md for:
- target-by-target behaviour;
- output directory names such as
o32,oz32,aif32, andrm32; - global build variables, optional feature variables, and pre-defined library variables;
LibraryCommand,CModule,AsmModule,LibExport,CApp,BasicApp,Documentation, andResourcevariable reference tables;- export-path variables and common
INITTARGET/CLEANTARGETpatterns.
Running built outputs
- 32-bit absolute:
riscos-build-run aif32 --command 'aif32.Program'
- 64-bit absolute:
riscos-build-run --64 aif64 --command 'aif64.Program'
If --64 is omitted for a 64-bit absolute, the runner may report that 64-bit absolute files are not executable on this system even though the binary itself built correctly.
For CApp and other install-oriented components, verify packaging with an
explicit install directory rather than a bare riscos-amu install. Use a
command such as:
riscos-amu install INSTDIR=install
This exercises the install rules and produces an application directory under
install/ without relying on an implicit destination.
See references/shared-makefile-types.md for the detailed variable tables and
patterns that used to live inline here.
Object File Dependency Patterns
To express that a compiled object depends on a generated header (e.g. the CMHG-generated
h.modhead):
$(OZDIR).module: h.modhead
Note: use $(OZDIR) not $(ODIR) for module objects, as modules use module
compilation.
Practical validation pattern
For command projects:
- Build 32-bit with
riscos-amu. - Run 32-bit smoke or self-tests with
riscos-build-run aif32 .... - Build 64-bit with
riscos-amu BUILD64=1. - Run 64-bit smoke or self-tests with
riscos-build-run --64 aif64 ....
Keep the 64-bit status distinct:
buildsmeansriscos-amu BUILD64=1succeeds.runtime-validatedmeans the--64runner path also succeeds.
64-bit cautions
- The 64-bit build environment is useful as a separate portability check, even before runtime validation.
- Some library or kernel helper entry points available in 32-bit builds may need guarding or replacement for
__riscos64. - Avoid assuming that success in the 32-bit Norcroft build implies success in the 64-bit build.
Agent Guidance
- Always add
OBJSentries aso.name— the build system substitutes the correct directory prefix (o,o32,oz32, etc.) automatically based on architecture and build type. Never writeo32.nameinOBJS. - Multi-line
OBJSandLIBS— use backslash continuation and consistent indentation:OBJS = o.main \ o.utils \ o.output INCLUDESis comma-separated, not space-separated. It is added afterC:automatically. Example:INCLUDES = C:MyLib.CDEFINESis space-separated, e.g.CDEFINES = -DDEBUG -DVERSION=2.- Do not include
${CLIB_ZM}in moduleLIBS— module makefiles add the module C library automatically. Adding it explicitly will cause duplicate symbol errors. - After adding new source files, run
riscos-amuto confirm the build succeeds before making further changes. DOCSRCfilenames use RISC OS dot-separated paths, e.g.docs.MyAPIrefers to the filedocs/MyAPI,xmlon Linux.cleandoes not remove exports — to force a clean export, delete the export directory or runexport_clean_dirmanually if supported.- The
Dynamic dependencies:comment at the end of a makefile is maintained by AMU and should be left in place even when empty.