Library / SDK
cc65/cc65 avatar
cc65/cc65

cc65: a C cross-compiler for 6502 machines

cc65 - a freeware C compiler for 6502 based systems

2,691 stars507 forksCZlib

At a glance

What is it?
cc65 is a cross-development package for 65(C)02 systems: a C compiler, macro assembler, linker, archiver, simulator and runtime libraries for machines from the Apple II to the Commander X16. It is aimed at retro developers who want to write in C rather than assembly, and it is still being pushed to as of 2026-09-20.
Who is it for?
Adopt cc65 if you are writing new software for a 6502 target and want C plus a runtime library instead of hand-written assembly; skip it if your target is not in the supported list and you are not prepared to write a custom config. Before committing, verify that the target you care about appears in the machine table, that the runtime library for it is maintained by someone active, and that the snapshot build you download matches the master branch you intend to track.
Can I use it commercially?
Yes. Zlib is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What cc65 solves, and who is actually compiling with it

Writing a game or utility for a Commodore 64, an Atari 8-bit or a NES in pure assembly is slow work: you manage zero page by hand, you write your own memory allocator, and every string routine is yours to debug. cc65 exists to remove that. It is described in its README as "a complete cross-development package for 65(C)02 systems", and the package is not just a compiler. It bundles a macro assembler, a C compiler, a linker, an archiver and a simulator, plus the runtime libraries that make C usable on a machine with a few tens of kilobytes of RAM.

The audience is narrow and specific. You are targeting a 6502-family CPU, you are developing on a modern host, and you want to write in C. The README lists support for Apple II and IIe, the Atari 400/800, 2600, 5200, 7800 and XL, Lynx, Oric Atmos and Telestrat, BBC series, C128, C16, C64, CBM 510/610, PET, Plus/4, VIC-20, CreatiVision, Commander X16, Gamate, GEOS, LUnix, NES, OSI C1P, KIM-1, PC Engine, RP6502, Supervision, SYM-1 and Agat-7/9. That breadth is unusual for a retro toolchain, and it is the main reason people pick cc65 over a target-specific assembler. A generic configuration also exists for adapting cc65 to new targets, which matters if your board is not on the list.

The toolchain pipeline: compiler, assembler, linker, library

cc65 is a chain rather than a single binary. The C compiler emits assembly for the 6502, the macro assembler turns that into object files, and the linker combines objects with a runtime library selected for your target. The cfg/ directory at the top level of the repository holds linker configurations, one per machine family, and asminc/ holds assembler include files. The include/ directory carries the C headers, and libsrc/ is the runtime library source. That layout tells you where to look when something goes wrong: a missing symbol usually means the wrong library or config, not a compiler bug.

The runtime library is the part that makes C practical here. It supplies the startup code, the C stack handling and the platform-specific routines, and the README credits maintainers per platform: the Atari, Atari5200 and CreatiVision library to Christian Groessler, the CBM library to groepaz, the Apple II library to Oliver Schmidt. That division is worth noting, because library coverage and freshness vary by target. A machine with an active maintainer gets fixes; one without may lag.

The project also ships targettest/ and test/ directories, which contain the test suites used to check targets and the compiler respectively. The root Makefile exposes a check target alongside all, install, zip, clean and checkstyle, so the repository is built and verified through the same make entry points a user runs.

Installing cc65 and compiling a first program

The README points to prebuilt downloads rather than giving a source build recipe: a Windows 64-bit snapshot, a Windows 32-bit snapshot, and Linux DEB and RPM packages. If you would rather build from source, the repository root has a Makefile, and the install target refuses to run without a destination. The Makefile shows the requirement directly: it errors with "PREFIX or DESTDIR must be set for install to work". So a source install looks like this, run from the repository root:

bash
make
make install PREFIX=/usr/local

The first command builds src, libsrc, doc, util and samples, then runs the checkprefix step. The second installs the compiler, libraries, documentation and utilities under the prefix you gave. If you only want the binaries in a staging directory, set DESTDIR instead.

The samples/ directory is where a first real program comes from. It contains hello.c along with Makefiles and per-machine subdirectories such as samples/cbm/, samples/apple2/, samples/atari2600/, samples/geos/, samples/lynx/, samples/kim1/ and samples/gamate/. After installing, the practical first step is to build a sample for your machine, for example by changing into samples/cbm and running make, which exercises the compiler, assembler, linker and target library end to end. If that produces a runnable binary, your setup is correct. If it fails at the link stage, the error will name a symbol from libsrc, and the fix is almost always the target configuration rather than the C source.

Targets that are supported on paper but thin in practice

The machine table is long, and that is the selling point, but it is not a uniform list. The README names library maintainers for only a few platforms, and the contributor list shows recent target work concentrated on specific machines: the Telestrat target, the Atari 7800 target, the osic1p target, the Sym-1 target, the KIM-1 target and the RP6502 target each come from an individual contributor. A target added by one person is a target that can stall when that person moves on.

The second limitation is the language itself. This is C for a 6502, not a modern C implementation with generous memory. The samples reflect that: mandelbrot.c, gunzip65.c and overlaydemo.c are the kind of programs the toolchain is built to handle, and overlaydemo.c exists because code size is a real constraint on these machines. If your design assumes dynamic allocation or large arrays, the runtime library and the hardware will both push back, and the documentation, not the README, is where the actual limits are spelled out.

The third case where cc65 is the wrong tool is when you are not writing C at all. If your project is a few hundred bytes of hand-tuned assembly, or you are working on a target with a mature native assembler and no C runtime, adding cc65 buys you a compiler you will not use and a linker configuration you will have to maintain.

How cc65 differs from a single-target assembler toolchain

The obvious alternative is a machine-specific assembler, such as the ones distributed with emulator projects for the C64 or NES. The difference in approach is structural. A single-target assembler assumes one memory map and one output format, and it gives you no C runtime, no linker script language and no portable library layer. cc65 makes the opposite bet: one toolchain, many targets, with the target differences pushed into cfg/ files and libsrc/ platform directories.

That bet has costs. You inherit a linker configuration and a runtime library for your machine, and if either is wrong for your use case you are editing files that other targets also depend on. A single-target assembler has no such layer to fight. But you also get the ability to move code between a C64 and an Apple II with a config change rather than a rewrite, and you get a C compiler that the project has been developing for decades, originally based on Ron Cain's Small C compiler and later rewritten by Ullrich von Bassewitz. For a project that spans several 6502 machines, that trade is usually worth taking. For a one-machine demo, it usually is not.

Maintenance, releases and the licence

The repository is not archived, and the last push was on 2026-09-20, which is recent. That matters because the release cadence is slow: V2.19 dates from 2020-11-20, V2.18 from 2019-05-29 and V2.17 from 2018-03-07. If you install a tagged release, you are installing code that is several years old. The project's answer is snapshot builds: the README links Windows 64-bit and Windows 32-bit snapshots and Linux DEB and RPM packages, and the badge in the README points at a snapshot workflow that runs on pushes to master. In practice that means the master branch is the thing being maintained, and the releases are milestones rather than the current state.

The licence is Zlib, a permissive licence. That is relevant if you are shipping a commercial retro release: permissive terms generally allow linking the runtime library into your binary without a copyleft obligation, but the exact wording is in the LICENSE file and this is not legal advice. Read it before you ship.

Upgrade cost is low in one direction and high in another. Upgrading the toolchain itself is a download or a git pull plus a rebuild. Upgrading a project that depends on a particular runtime library behaviour is not, because the libraries are maintained per platform and a change in one target's library may not reach another.

Editorial conclusion

Adopt cc65 if you are writing new software for a 6502 target and want C plus a runtime library instead of hand-written assembly; skip it if your target is not in the supported list and you are not prepared to write a custom config. Before committing, verify that the target you care about appears in the machine table, that the runtime library for it is maintained by someone active, and that the snapshot build you download matches the master branch you intend to track. The project's own documentation, at cc65.github.io/doc, is the place to confirm the linker config and library calls for your machine.

Frequently asked questions

What is cc65 used for?

It is a cross-development package for 65(C)02 systems, containing a C compiler, macro assembler, linker, archiver, simulator and runtime libraries. People use it to write software in C for machines such as the C64, NES, Apple II and Atari 8-bit instead of writing pure assembly.

How do I install cc65?

The README links prebuilt Windows 64-bit and 32-bit snapshots and Linux DEB and RPM packages. To build from source, run make and then make install PREFIX=/usr/local from the repository root; the install target errors out unless PREFIX or DESTDIR is set.

Which machines does cc65 support?

The README lists Apple II and IIe, Atari 400/800, 2600, 5200, 7800 and XL, Lynx, Oric Atmos and Telestrat, BBC series, C128, C16, C64, CBM 510/610, PET, Plus/4, VIC-20, CreatiVision, Commander X16, Gamate, GEOS, LUnix, NES, OSI C1P, KIM-1, PC Engine, RP6502, Supervision, SYM-1 and Agat-7/9. A generic configuration exists for adapting cc65 to new targets.

Official sources

  1. cc65/cc65 on GitHub
  2. License: Zlib
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cc65-cc65.svg)](https://hysenlabs.com/projects/cc65-cc65)