RISC OS Build EnvironmentROBE

Workflow guides10Building, Linking, and Outputs

Introduction and Overview

Most projects in the build environment are built with riscos-amu and a shared Makefile,fe1. It is still useful to understand the lower level compiler, assembler, and linker tools because they explain the output directories, the naming conventions, and the occasions when a direct tool invocation is simpler than a full makefile build.

This chapter covers the everyday path from source to a built binary. Generated build assets such as module headers and ALF libraries are covered in Generated build assets; packaging built output and checking source quality are covered in Packaging and source maintenance.

Shared build system

Normal AMU workflow

For standard projects, riscos-amu is the normal build entry point. If no target is supplied, it builds the first target in the makefile. Build architecture is usually selected with a macro such as BUILD32=1 or BUILD64=1.

The standard project build path is simply:

riscos-amu BUILD32=1

Using the shared makefile system

Most projects in this environment do not carry a large hand-written build script. Instead, their Makefile,fe1 sets a small number of variables describing the component and then includes one of the shared makefiles supplied by the RISC OS Makefile System. The included makefile provides the actual rules for compilation, linking, exporting, installing, ROM integration, and cleaning.

A typical component makefile looks like this:

COMPONENT = MyTool
OBJS = o.main
LIBS = ${CLIB}

include LibraryCommand

The shared makefiles are found via Makefiles$Path on RISC OS or AMUFILES in the host environment. They are included by name only. The main types you will encounter are:

  • LibraryCommand for command-line tools and standalone executables;
  • CModule for C modules using CMHG or CMunge-generated headers (see Generated build assets for the CMunge workflow);
  • AsmModule for assembly modules;
  • LibExport for exportable libraries;
  • CApp and BasicApp for desktop applications;
  • Documentation and Resource for documentation-only and resource-only components.

The normal authoring pattern is:

  1. generate or update the makefile with riscos-project;
  2. set variables such as COMPONENT, OBJS, LIBS, and optional export or install variables before the include line;
  3. put any project-specific extra rules after the include line;
  4. build with riscos-amu, optionally selecting an architecture such as BUILD26=1, BUILD32=1, or BUILD64=1.

When new source files are added, riscos-project update can refresh the object list and related dependencies. The fuller makefile system reference is in Tool Reference: Build Orchestration and Makefiles.

Common outputs

The shared makefiles typically place outputs in directories such as:

  • aif32/ for 32-bit absolute binaries;
  • rm32/ for 32-bit modules;
  • o/ or similar directories for object files.

The exact names depend on the project type and selected build macros, but the host file suffixes still record the intended RISC OS filetype. The naming rules are summarised in Appendix A: Naming conventions and project files.

The build architecture selected for the shared makefile system determines the main directory families:

  • 26-bit: o/, oz/, aif/, rm/, aof/;
  • 32-bit: o32/, oz32/, aif32/, rm32/, aof32/;
  • 64-bit: o64/, oz64/, aif64/, rm64/, elf64/.

The oz-prefixed directories hold the same objects compiled in module-safe form (position-independent, ROM-safe code, selected automatically by module-type makefiles) rather than the ordinary form used for applications; see Glossary.

Direct language toolchains

Direct compiler and linker use

A direct compiler or linker invocation is reasonable when experimenting with a small single-file program, investigating a toolchain issue, or explaining how a generated makefile works. The wrappers accept either host-style or RISC OS-style filenames for many arguments.

For a one-file utility, the compile and link steps may also be combined by passing the link library on the compiler command line.

One direct 32-bit compile-and-link sequence is:

riscos-cc -apcs 3/32 c/main -c
riscos-link o/main C:o.stubsG -o main

-apcs selects the APCS (ARM Procedure Call Standard) variant and qualifiers the compiler should target; 3/32 is the common 32-bit RISC OS form. See Glossary for APCS itself, and Compilers, linkers, and 64-bit binary tools for the full set of accepted qualifiers.

Pascal translation and compilation

Pascal sources use a slightly different path from C and assembler. The base translator is riscos-p2c, which converts Pascal source into C and, for units or modules, may also generate a matching header file. Most of the time, however, you will use riscos-p2cc instead. That wrapper runs P2C, invokes the C compiler on the generated source, adds the P2C runtime library automatically when linking, and hides the temporary translated C file from the normal build artefacts.

Use riscos-p2c directly when you want to inspect the C output, generate or check headers, inspect the resolved system configuration with -i, or experiment with a local p2crc override file. Use riscos-p2cc for routine builds, because it behaves more like a compiler front-end and keeps the Pascal source as the real input to the build.

Typical workflows are:

riscos-p2cc -32 source.p -o output,ff8
riscos-p2cc -F source.p -o c/source
riscos-p2c -i
riscos-p2c -c project.p2crc source.p -o c/source

The P2C configuration language is controlled through the system stage, an optional current-directory override, and any explicit -c file. The structure of that configuration file is summarised in Appendix H: p2crc file format.

Simple assembler workflow

Assembler sources are normally built with riscos-objasm and then linked with riscos-link. Labels must start in column 1, and most non-trivial assembly uses the standard header includes that define SWI names and CPU options.

ObjAsm source is line-oriented. A typical line is a label, followed by an instruction or directive, followed by an optional semicolon comment. If no label is present, the line must begin with whitespace. Instruction mnemonics and register names may be written in upper or lower case, but directives are written in upper case. Long lines may be continued with a trailing backslash.

Most real sources begin with one or more AREA directives, use GET or INCLUDE to pull in shared headers, define constants with GBL/LCL and SETA/SETL/SETS, and use [, |, and ] for conditional assembly. Macros are introduced with MACRO and ended with MEND.

Headers pulled in with GET hdr.swis-style names are resolved against the search path, and the standard exported headers are not on that path by default for a bare direct invocation; the makefile-driven build adds them through the project's INCLUDES variable. When invoking riscos-objasm directly outside a makefile, add the export header directories explicitly with -I if your source GETs shared headers.

A simple assembler build looks like this. riscos-objasm is silent on success, and riscos-link appends the filetype suffix to the output name itself, so -o util actually produces util,ffc:

riscos-objasm -apcs 3/32 -predefine 'No32bitCode SETL {FALSE}' -predefine 'No26bitCode SETL {FALSE}' s/util
riscos-link -bin o.util -o util
riscos-settype util,ffc utility

,ffc is already the host-side suffix for the Utility filetype, so -bin linking typically produces the right type directly; the explicit riscos-settype step is there for the cases where the linker's default does not already match the filetype you want.

The assembler language itself is summarised in Appendix C: ObjAsm assembler format.

When not to bypass AMU

Direct tool use is educational and sometimes convenient, but full project builds should usually stay with AMU so that object dependencies, export paths, resources, and architecture selection remain consistent with the project makefile.