10. Running the compiler

The compiler is run from the command line, or from an IDE that interfaces with the compiler using the command line.

10.1. Basic invocation

The compiler is invoked in the following way:

$ cc6502 [options] sourcefile [options]

As an example, to compile a source file with debugging information and a list file, you can use:

$ cc6502 --debug source.c -l

Command line options are optional arguments that tune the behavior of the compiler. They always start with a dash character. There are two variants, single letter options (-l to instruct the compiler to create a list file) starts with a single dash. The other variant is long descriptive options that starts with two dashes.

Some options require arguments. These follow the option, separated by a space or an equals sign (=). For single-argument options, the separator is optional:

$ cc6502 -Iinclude source.c -D VERBOSE=2 --list-file=tiny-source.lst

In this case the -I option adds include as a directory to scan for header files. The symbol VERBOSE is defined in the preprocessor with value 2. A list file with a specific name is also produced.

The order in which the options appear normally do matter, except for the -I option that adds directories to search for header files. Such directories are searched in the order in which they appear on the command line.

To display the version of the compiler, use --version:

$ cc6502 --version
Calypsi ISO C compiler for 6502 version 5.16

Command line options are described in Command line options.

10.2. Include search path

Header files are included by surrounding the filename with either double quotes or angled brackets:

#include "myheader.h"
#include <stdio.h>

Angled brackets are typically for system header files, while double quotes are for application-specific header files.

The search order for include files is as follows:

  1. Relative to compilation directory (double quote include only)

  2. In directories specified in the -I option in the order they appear on the command line

  3. The system directory, which is the installation directory

Header files specified in angle brackets are not searched relative to the compilation directory. Otherwise, they behave identically. The system header file directory is located within the installation directory.

Note

More precisely, the system header file directory is relative to the cc6502 executable. If an installation is moved, it will still find the correct system header file directory.

10.3. Compiler output

The compiler outputs one or two files, an object file that can be linked with other object files and libraries by ln6502 to produce an executable file, and optionally a list file.

Object file

The object file is in ELF format, optionally including DWARF debugging information if --debug (or -g) is specified.

It contains:

  • A symbol table

  • Relocatable sections for code and data

  • Relocations, allowing linker to modify address values after section placement

  • DWARF-formatted source-level debugging information (if --debug was specified)

  • Vendor-specific data, including runtime attributes and additional the Calypsi C compiler tool chain-specific information not covered by ELF/DWARF, used by the linker and debugger, with section types 0x8000000a and 0x8000000b.

Note

DWARF version 5 is used. The implementation covers the needs of the Calypsi C compiler tool chain and includes vendor extensions.

List file

The list file is a text file meant to be shown with a fixed width font. It contains a header that shows compiler, version, time when it was created and the command line used. The C source file follows intermixed with generated assembly code. Finally there is a summary of the code and data sizes.

The following simple summation function:

int sum(int a, int b, int c) {
  if (a < b) {
    return a + c;
  } else {
    return b + c;
  }
}

Compiling with the -l option produces a list file:

###############################################################################
#                                                                             #
# Calypsi ISO C compiler for 6502                                version 5.16 #
#                                                       14/Apr/2026  16:41:35 #
# Command line: sum.c -l                                                      #
#                                                                             #
###############################################################################

    \ 0000                      .rtmodel version,"1"
    \ 0000                      .rtmodel codeModel,"plain"
    \ 0000                      .rtmodel core,"6502"
    \ 0000                      .rtmodel target,"none-specified"
    \ 0000                      .extern _Vfp
    \ 0000                      .extern _Vsp
    \ 0000                      .extern _Zp
0001                int sum(int a, int b, int c) {
    \ 0000                      .section code,text
    \ 0000                      .public sum
    \ 0000          sum:
0002                  if (a < b) {
    \ 0000 a5..                 lda     zp:_Zp
    \ 0002 c5..                 cmp     zp:_Zp+2
    \ 0004 a5..                 lda     zp:_Zp+1
    \ 0006 e5..                 sbc     zp:_Zp+3
    \ 0008 5002                 bvc     `?L9`
    \ 000a 4980                 eor     #-128
    \ 000c 1010     `?L9`:      bpl     `?L4`
0003                    return a + c;
    \ 000e a5..                 lda     zp:_Zp+4
    \ 0010 18                   clc
    \ 0011 65..                 adc     zp:_Zp
    \ 0013 85..                 sta     zp:_Zp
    \ 0015 a5..                 lda     zp:_Zp+5
    \ 0017 65..                 adc     zp:_Zp+1
    \ 0019 85..                 sta     zp:_Zp+1
    \ 001b 4c....               jmp     `?L3`
    \ 001e          `?L4`:
0004                  } else {
0005                    return b + c;
    \ 001e a5..                 lda     zp:_Zp+4
    \ 0020 18                   clc
    \ 0021 65..                 adc     zp:_Zp+2
    \ 0023 85..                 sta     zp:_Zp
    \ 0025 a5..                 lda     zp:_Zp+5
    \ 0027 65..                 adc     zp:_Zp+3
    \ 0029 85..                 sta     zp:_Zp+1
    \ 002b          `?L3`:
0006                  }
0007                }
    \ 002b 60                   rts

##########################
#                        #
# Memory sizes (decimal) #
#                        #
##########################

Executable  (Text): 44 bytes

Assembly source

The compiler can generate assembly source output, which is similar to a list file, except that this output file is actual source code that can be given to the assembler. This can be used to generate a starting point for an assembly source file. By providing suitable declarations and simplified C functions you can study what the compiler does and build upon it.

10.4. Diagnostics

Compiler diagnostic messages identify problems that either must or should be addressed.

Errors

An error identifies a problem in the code that prevents the compiler from producing a valid output file.

Warnings

A warning identifies a potential problem in the code that you probably want to take a look at and possibly rectify. The compiler is still able to produce a valid output file.

Internal errors

An internal error indicates an unexpected problem within the compiler product.

Controlling warnings

Diagnostic can be controlled using the -W option that takes a wide range of possible alternatives. It is beyond the scope of this guide to list them all. A complete reference can be found at https://clang.llvm.org/docs/DiagnosticsReference.html as the parser and diagnostics engine is the same as in the Clang project.

Consider the following code:

 int test(int x)
 {
   if (x = 6) {
     return 10;
   } else {
     return 0;
   }
}

In the code, an assignment is used in a comparison, a common C error. While legally testing a non-zero assignment expression, this often indicates an intended use of ==. The compiler cannot know your intent, but flags a potential problem. Compiling this code results in warnings:

w.c:3:10: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
   if (x = 6) {
       ~~^~~
w.c:3:10: note: place parentheses around the assignment to silence this warning
   if (x = 6) {
         ^
       (    )
w.c:3:10: note: use '==' to turn this assignment into an equality comparison
   if (x = 6) {
         ^
         ==

The warnings point out that there may be a problem in the code. The name of the warning that triggered is also given (-Wparentheses). Finally, it makes suggestions on how you can change the code.

If you think the warning is of no use to you and you do not want to see this particular warning again, you can add the option -Wno-parentheses to the command line to silence it.

Adding an extra pair of parentheses around the assignment is a common way to indicate an intentional assignment within a test expression:

 int test(int x)
 {
   if ((x = 6)) {
     return 10;
   } else {
     return 0;
   }
}

Finally, if the intention with the code was to use the equality operator, you should change it to use the correct operator:

 int test(int x)
 {
   if (x == 6) {
     return 10;
   } else {
     return 0;
   }
}

10.5. Command line options

This section covers the cc6502 command-line options in detail.

Options overview

If you run the compiler from the command line without any arguments it will complain that the input source file is missing and then shows a short form help:

$ cc6502
Missing: FILE

Usage: cc6502 [--version] [-o|--output-file OUTPUT-FILE] [-l]
              [--list-file LIST-FILE] [-I DIRECTORY] [-D IDENTIFIER]
              [-U IDENTIFIER] [-g|--debug] ([--32bit-doubles] |
              [--64bit-doubles]) ([--char-is-signed] | [--char-is-unsigned])
              [-E] [--print-macro-definitions] [--align-functions ALIGNMENT]
              [-O LEVEL] ([--space] | [--speed]) [--no-cross-call]
              [--no-interprocedural-cross-jump] ([--no-inline] |
              [--always-inline]) [--only-marked-as-inline] [--strong-inline]
              [--inline-on-matching-custom-text-section] [--rtattr NAME=VALUE]
              [--weak-symbols] [--no-vector-sections] [-c]
              [--assembly-source ASSEMBLY-FILE] [-S] [--force-switch STRATEGY]
              [-W ARG] [--dependencies] [-M ARG] [--pedantic-errors]
              [--include-system DIRECTORY] [--include-system-after DIRECTORY]
              [--core CORE] [--target TARGET] FILE
  use 'cc6502 --help' for detailed help

For more detailed help, use the --help option:

$ cc6502 --help
Calypsi ISO C compiler for 6502 version 5.16

Usage: cc6502 [--version] [-o|--output-file OUTPUT-FILE] [-l]
              [--list-file LIST-FILE] [-I DIRECTORY] [-D IDENTIFIER]
              [-U IDENTIFIER] [-g|--debug] ([--32bit-doubles] |
              [--64bit-doubles]) ([--char-is-signed] | [--char-is-unsigned])
              [-E] [--print-macro-definitions] [--align-functions ALIGNMENT]
              [-O LEVEL] ([--space] | [--speed]) [--no-cross-call]
              [--no-interprocedural-cross-jump] ([--no-inline] |
              [--always-inline]) [--only-marked-as-inline] [--strong-inline]
              [--inline-on-matching-custom-text-section] [--rtattr NAME=VALUE]
              [--weak-symbols] [--no-vector-sections] [-c]
              [--assembly-source ASSEMBLY-FILE] [-S] [--force-switch STRATEGY]
              [-W ARG] [--dependencies] [-M ARG] [--pedantic-errors]
              [--include-system DIRECTORY] [--include-system-after DIRECTORY]
              [--core CORE] [--target TARGET] FILE
  use 'cc6502 --help' for detailed help

Available options:
  --version                Display version number
  -o,--output-file OUTPUT-FILE
                           Name of output file
  -l                       Generate a list file, named by appending '.lst' to
                           input file
  --list-file LIST-FILE    Generate list file, using given name
  -I DIRECTORY             Include directory
  -D IDENTIFIER            Predefine a macro
  -U IDENTIFIER            #undef a predefined macro
  -g,--debug               Produce debugging information
  --32bit-doubles          Make the 'double' data type 32-bits (this is the
                           default)
  --64bit-doubles          Make the 'double' data type 64-bits
  --char-is-signed         Treat 'char' as a signed type
  --char-is-unsigned       Treat 'char' as an unsigned type (this is the
                           default)
  -E                       Stop after preprocessing
  --print-macro-definitions
                           Print macro definitions in -E mode in addition to
                           normal output
  --align-functions ALIGNMENT
                           Align the start of functions to given alignment
  -O LEVEL                 Enable optimizer, -O0, -O1 or -O2
  --space                  Optimize for space (this is the default, use together
                           with -O)
  --speed                  Optimize for speed (use together with -O)
  --no-cross-call          Disable cross call optimization
  --no-interprocedural-cross-jump
                           Disable interprocedural cross jump optimization
  --no-inline              Disable all function inlining
  --always-inline          Always inline functions
  --only-marked-as-inline  Only consider inlining functions marked as 'inline'
  --strong-inline          Always (try to) inline functions marked as 'inline'
  --inline-on-matching-custom-text-section
                           Only inline custom text section functions when the
                           section names match
  --rtattr NAME=VALUE      Define a runtime attribute (identifier or quoted
                           string value accepted)
  --weak-symbols           Make all public symbols entries weak
  --no-vector-sections     Discard auto generated interrupt vector sections
  -c                       Generate object file and do not try to link
  --assembly-source ASSEMBLY-FILE
                           Generate an assembly source file, using given name
  -S                       Generate an assembly source file, named by appending
                           '.s' to input file
  --force-switch STRATEGY  Switch strategy, one of 'if-else', 'jump-table' or
                           'value-table'
  -W ARG                   Warning control
  --dependencies           Generate dependencies to stdout
  -M ARG                   Dependency file control
  --pedantic-errors        Error on language extensions
  --include-system DIRECTORY
                           Add system include directory
  --include-system-after DIRECTORY
                           Add system include directory after
  --core CORE              Core, one of '6502', '65b02', '65c02', '65cnr02' or
                           '45gs02' (defaults to '6502')
  --target TARGET          Target system, one of 'C64' or 'MEGA65' (defaults to
                           embedded/ROM use, if omitted)
  -h,--help                Show this help text

Options in detail

--version

Displays the name and version of the compiler.

--output-file, -o

Specify the output object file name. If omitted, the output file is derived from the input file name (excluding path) with a .o extension, written to the current directory by default.

This option can also alter the output file name and provide a directory path. The specified directory must already exist.

-l

Generate a list file. The name used is the name of the input file (ignoring any directory path) with a .lst file extension. See also --list-file.

--list-file

Generate a list file. The name of the list file is given as argument to this option. See also -l to generate a list file based on the source filename.

-I

Add a directory to the current include search path. This option can be used multiple times on a command line. The order in which they appear specifies the search order between the directories.

The system include directory is always added last to the search order list.

--include-system

Add a directory to the current system include search path before the provided system include directories. This option can be used multiple times on a command line. The order in which they appear specifies the search order between the directories.

--include-system-after

Add a directory to the current system include search path after the provided system include directories. This option can be used multiple times on a command line. The order in which they appear specifies the search order between the directories.

-D

Define a macro. This takes an argument with the symbol name and optionally an assignment value -Dsymbol[=value]. If no value is given, the macro is given the value 1.

-U

Undefine a macro. This takes an argument with the symbol name to be undefined.

--debug

Generate DWARF symbolic debugging information. In order to get debugging information all the way to the debugger, the linker must also be given this option.

When debugging information is enabled the __CALYPSI_DEBUG__ macro is also defined and set to 1.

-g

Synonym for --debug.

-S

Generate an assembly source file as output. The name used is the name of the input file (ignoring any directory path) with a .s file extension. No object file is generated. See also --assembly-source.

--assembly-source

Generate an assembly source file as output. The name of the output file is given as an argument to this option. See also -S to generate an assembly source file based on the C source filename. No object file is generated.

--32bit-doubles

The double floating point data type has 32 bits precision.

--64bit-doubles

The double floating point data type has 64 bits precision.

--char-is-signed

Makes the char data type signed. The default is unsigned.

--char-is-unsigned

Makes the char data type unsigned. This is also the default.

-E

Stop after running the preprocessor. The output from the preprocessor is written to standard output (stdout).

-O

Runs the optimizer, expecting an argument of 0, 1, or 2. -O0 (the default) performs no additional optimization passes but still produces good code. -O1 enables additional passes to further improve code, and -O2 enables all optimizer passes.

--space

Optimize for space, this is the default. Use -O to enable optimizations.

--speed

Optimize for speed. Use -O to enable optimizations. This option controls decisions about tradeoffs and will balance towards making the code run faster at the expense of additional code space. See also --no-cross-call below.

--no-cross-call

Disables the cross-call optimizer, normally enabled at -O2. The cross-call optimizer extracts common code sequences into small subroutines, which can significantly reduce code space, so it is also enabled by default with --speed.

--no-inline

Disable all function inlining which is normally enabled at -O1.

--always-inline

Enable function inlining regardless of optimization level setting.

--only-marked-as-inline

Only considers functions marked with the inline keyword for inlining. This disregards small functions and single-use static functions for inlining.

--strong-inline

Regard functions marked with the inline keyword as a strong hint that they should be inlined. The compiler may still decide not to do it.

--rtattr NAME=VALUE

This defines a runtime attribute which is written to the object file. This is used to specify runtime attribute value that can be used in the linker for checking object file consistency.

--weak-symbols

Makes all public symbols in the object file weak. This is normally not needed, but can provide a default library function implementation that is used if no replacement is provided.

--no-vector-sections

Do not generate vector table entries for interrupt functions. This is useful when writing interrupt functions that are going to be installed using some other mechanism.

-c

Generate an object file without linking. This is a no-operation, as the compiler always generates an object file. This option is provided due to its common use with many compilers.

--force-switch

Forces the compiler to use a specific strategy for generating switch tables. The compiler normally uses heuristics, but this option overrides them to force a particular variant.

Available variants are: series of “if-else” tests, a jump table, or a table with value and label pairs. “If-else” is often best for very small switches. A jump table is typically fastest for a decent number of close entries. Value and label pairs work well for larger tables with spread-out values, using a binary search lookup that scales fairly well.

In big O notation: “if-else” is O(n), a jump table is O(1), and value and label pairs are O(log(n)).

-MD

Write a dependency file that contains user and system headers.

--dependencies

Like -MD, but also implies -E and writes to stdout by default.

-MF<file>

Write dependency file output from -MMD, -MD, -MM, or -M to <file>.

-MG

Add missing headers to the dependency file.

-MJ<arg>

Write a compilation database entry for each input.

-MM

Like -MMD, but also implies -E and writes to stdout by default.

-MMD

Write a dependency file containing user headers.

-MP

Create phony target for each dependency (other than main file).

-MQ<arg>

Specify name of main file output to quote in dependency file.

-MT<arg>

Specify name of main file output in dependency file.

-MV

Use NMake/Jom format for the dependency file.

-W

Control warnings, see Controlling warnings.

--pedantic-errors

Generates errors when language extensions are used. The supported language includes relaxations to the strict C standard for increased flexibility; use this option to disable such extensions.

--align-functions

Aligns the start of all functions to the provided alignment.

--core

Selects the 6502 core (e.g., 6502, 65B02, 65C02, 65CNR02, or 45GS02). This affects available instructions and defaults to 6502 if not specified.

--target

Specifies the target platform for the code. Supported platforms include MEGA65 and C64 (Commodore 64).

The --target=mega65 option implies --core=45gs02, enabling instructions to access data in the full 32-bit address space, and defines the __CALYPSI_TARGET_SYSTEM_MEGA65__ macro.

The --target=c64 option solely defines the __CALYPSI_TARGET_SYSTEM_C64__ macro.