EmbCCdocs Repository

EmbCC's own conventions, GCC's as a layer#

Decided 2026-10-14. EmbCC had been drifting into GCC's way of doing things: it read GCC's spellings, its manual was laid out like GCC's (Overall options, C and C++ language options, ...) and keyed by GCC's flags, and its help text said it used "the spellings GCC and Clang use". On that date the driver tested about 230 option spellings, 114 of them -f and 134 -m flags taken from GCC, against 44 of EmbCC's own; the user manual named GCC 293 times.

We read GCC to understand a problem, and then make EmbCC's own answer. We do not copy its names, its structure or its wording.

Three kinds of convention#

Kind What Rule
Contracts ABIs and calling conventions; object, archive and debug formats; the runtime helpers' symbol names (__mulsi3, __aeabi_*); __attribute__ and asm syntax in C source; linker-script syntax Match exactly. Breaking one means existing objects and sources stop working with EmbCC.
Ours EmbCC's command line, diagnostics, documentation, tool names and output formats; the POSIX c99 utility's letters (-c -o -E -I -D -U -L -l -g -O) Designed for EmbCC, in its own words.
The compatibility layer GCC's spellings of options (-fshort-enums, -mcpu=, -Wl,), the arm-none-eabi-gcc-style program names, the binutils names (embcc-ar, embcc-objcopy) Accepted, so a build written for GCC keeps working. Kept in one place, and documented on one page (Migrating from GCC), never as how EmbCC names something.

The redesign's rule still holds: nothing that works today breaks. GCC's spellings stay accepted indefinitely.

The command line#

Every option is a row in src/driver/options.def: EmbCC's spelling, its value's name, the other spelling it stands for (GCC's, or EmbCC's own older GCC-style one), a group, and a line of help. embcc --help prints EmbCC's spellings, embcc --help=gcc the other ones, and embcc --reference=options the option reference that the manual includes.

The rules for EmbCC's spellings:

  • POSIX's letters, then words. The c99 utility's options keep their letters. Everything else is a long option made of words, not abbreviations: --freestanding, --stack-usage, --no-common.
  • A noun and a value, rather than a family of flags. --opt=size (not -Os), --enums=short, --char=unsigned, --sections=functions,data, --endian=big, --isa=thumb. A value may follow as the next argument (--cpu cortex-m4).
  • --no- turns a thing off: --no-warn=NAME, --no-unwind-tables.
  • The goal, not the mechanism. --opt=speed and --opt=size say what is wanted; the levels (-O2, -Os) stay as POSIX's -O letter.

Native spellings are rewritten into the ones the driver's argument loop reads before it runs (opts_normalize in src/driver/options.c), so a build gets byte-identical output whichever spelling it uses. tests/golden/options-table.sh holds the driver to the table:

  • every spelling the loop tests is a row in it;
  • every native spelling is accepted;
  • EmbCC's and GCC's spellings build identical objects, dependency files and diagnostics.

Still to do#

  1. Move GCC's spellings into one module. Today the argument loop in main.c reads GCC's spellings, and native ones are translated to them. The loop should read EmbCC's options by id, and src/driver/compat_gcc.c should translate GCC's spellings in. That includes each target's -m lists (src/arch/*/options.c).

Done since:

  • A warning ends with the EmbCC option that controls it, [--warn=conversion] (it was GCC's [-Wconversion]). JSON output keeps GCC's "option": "-Wconversion", because tools read that format. --help-warnings lists --warn=NAME.
  • Every message about an option quotes it as the user typed it (opt_typed and opt_said in src/driver/util.c), in the driver and in each target's option file, and suggests EmbCC's spelling. An EmbCC option a target has no use for says so instead of "unknown argument".
  • -O1 is --opt=basic, -mtune= is --tune=.
  • A warning named on its own wins over --warn=all and --warn=extra in either order, as in GCC.
  • embcc --reference=man prints embcc(1) from the table, and make install installs it.
  • The manual uses EmbCC's spellings throughout; GCC's appear under each heading, on the Migrating from GCC page, and in what other programs read (embld's own options, the host compiler's flags).

The documentation#

The documentation is generated by EmbCC's own tool, embdoc (C99, no dependencies). Its sources:

  • the handbook in docs/, written by hand;
  • the pages generated from the tables in the source, so they cannot drift from the compiler:
    • the option reference (embcc --reference=options);
    • the warnings (embcc --reference=warnings);
    • the targets (embcc --reference=targets, from src/targets/*.def);
    • and, next, the attributes and builtins.

embdoc renders all of it into a static website and checks every link and anchor across it; the same tables give --help and the man page (embcc --reference=man).

The manual's structure is EmbCC's: what a firmware engineer does (starting, building for a part, fitting in flash, debugging, simulating), then the references. The GCC comparisons move to Migrating from GCC. That page is the one place that says "GCC's -fshort-enums is EmbCC's --enums=short".

The website#

GitHub Pages for this repository (emblinkos.github.io/EmbCC). A GitHub Actions workflow builds embdoc, checks the links, renders the site and deploys it on every push to main. The site is never committed. The generated reference pages are: make reference writes them, and tests/golden/reference-pages.sh fails when one is stale.