aarch64-linux-gnu-gcc-13 builds a C program for 64-bit ARM Linux on an ordinary x86-64 workstation, no target hardware required. You'll compile a small program, link it, inspect the target architecture, and generate Make-compatible header dependencies. The installed command is from Ubuntu package version 13.3.0-6ubuntu2~24.04.1.
Allow about 15 minutes if the cross-toolchain is already installed. None of the commands need sudo; save elevated privileges for installing or repairing packages through your normal process.
Check the exact binary before trusting its output. The unversioned aarch64-linux-gnu-gcc name is an alias here; the versioned command pins the compiler explicitly:
$ command -v aarch64-linux-gnu-gcc-13
/usr/bin/aarch64-linux-gnu-gcc-13
$ aarch64-linux-gnu-gcc-13 --version
aarch64-linux-gnu-gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
$ aarch64-linux-gnu-gcc-13 -dumpmachine
aarch64-linux-gnu
Checkpoint: the last line must say AArch64 GNU/Linux. If the command is missing, install the distribution's cross-compiler package. Never swap in your native gcc instead, it builds code for the machine it runs on, not the one you're targeting.
Make a working directory and a source file. This one prints a message and the size of a pointer, ordinary C where only the compiler command picks the target:
$ mkdir -p /tmp/aarch64-gcc-demo/build
$ cd /tmp/aarch64-gcc-demo
$ cat > hello.c <<'EOF'
#include <stdio.h>
int main(void)
{
puts("hello from an AArch64 build");
printf("pointer bytes: %zu\n", sizeof(void *));
return 0;
}
EOF
That here-document only writes under /tmp; swap in a project directory for real work. Keep the terminating EOF at the very start of its line, or the shell keeps waiting for more input.
Use -c for one object file and no executable yet. -Wall -Wextra turns on useful diagnostics, -O2 asks for release-style optimisation, and a named output stops a later command grabbing the wrong file by accident:
$ aarch64-linux-gnu-gcc-13 -Wall -Wextra -O2 -c hello.c -o build/hello.o
$ file build/hello.o
build/hello.o: ELF 64-bit LSB relocatable, ARM aarch64, ...
The rest of that file line varies by host. Look for ELF 64-bit, ARM aarch64, and relocatable. A zero exit status means it compiled; warnings still deserve a read before you call the build clean.
Run the driver again without -c. GCC calls the target assembler and linker and pulls in the startup and C library files the toolchain supplies:
$ aarch64-linux-gnu-gcc-13 -Wall -Wextra -O2 hello.c -o build/hello
$ file build/hello
build/hello: ELF 64-bit LSB pie executable, ARM aarch64, ...
Tip: don't run ./build/hello on an ordinary x86-64 workstation and read "Exec format error" as a compile failure. This binary is for an AArch64 Linux system, emulator or remote target; a native file check is the honest verification you get on the build host.
To see the driver's commands without running them, use -###:
$ aarch64-linux-gnu-gcc-13 -### hello.c -o build/hello 2>&1
Using built-in specs.
COLLECT_GCC=.../aarch64-linux-gnu-gcc-13
... target assembler and linker commands ...
Paths and internal details are installation-specific. The useful checkpoint is that the trace names the AArch64 driver and shows target tools, not a native linker quietly substituted in.
The normal run does preprocessing, compilation, assembly and linking in one pass. Add -E to stop after preprocessing and send the result somewhere you can search it:
$ aarch64-linux-gnu-gcc-13 -E hello.c -o build/hello.i
$ test -s build/hello.i && head -n 5 build/hello.i
# 0 "hello.c"
# 0 <built-in>
...
Line directives and included declarations depend on the installed headers. Skip -o with -E and the preprocessed source floods standard output instead, which is rarely what you want interactively. Use -S when you want AArch64 assembler source without assembling it.
For a Make-based build, -MMD records user header dependencies while compiling, -MP adds harmless phony targets for headers that later disappear, and -MF names the dependency file, kept separate from the object output:
$ aarch64-linux-gnu-gcc-13 -Wall -Wextra -O2 -MMD -MP -MF build/hello.d -c hello.c -o build/hello.o
$ sed -n '1,8p' build/hello.d
build/hello.o: hello.c
hello.c, since -MMD omits system headers by design.-MD instead.-M and -MM request dependency output in place of a normal compile; -MD and -MMD generate it as a side effect of one.GCC's defaults are handy for a quick experiment and a liability in a build script: skip -o and a linked program lands in a.out, an object usually follows the source's basename, and preprocessed output goes to standard output. Always give the primary output an explicit path in scripts.
Everything above lives under /tmp/aarch64-gcc-demo. To clear this disposable demo once you're done checking it:
$ rm -rf -- /tmp/aarch64-gcc-demo
Warning: that deletion is irreversible. Never copy it into a project script or run it with a variable, a home directory, or a repository path standing in for the literal path. If a build fails for real, leave the source and diagnostics in place, fix the reported issue, and rerun the exact failed command rather than starting over. Nothing in this workflow touches a service or installs anything system-wide.
-dumpmachine says aarch64-linux-gnu.-E and at assembly with -S..d file sits beside the object, built with -MMD and -MP on purpose.