Proven C Book한국어 GitHub

97 The embedded toolbox — compilers and the tools beside them

What to know first

chapter 18, The compiler landscape · the terrain of compilers
chapter 83, A program’s memory layout · memory in embedded systems

Looking back

Chapter 18 said that numerically the largest branch of the world’s C compilers is embedded. Why is that — cannot gcc alone target them all?

A. Three reasons. First, there are chips gcc does not know — when a company invents its own instruction set, the compiler that knows that chip is made by that company. Second, certification. The safety standards of automotive, aerospace and medical devices demand evidence that “this compiler has been qualified against the standard”, and selling that qualification together with the responsibility is the business of specialist firms. Third, code size. On a chip with tens of KiB of memory, a few per cent of size decides whether a product exists.

The need for this chapter, and its context

Setting embedded aside for the end is not because it is an appendix-like topic — it is, if anything, where C is least replaceable. But that world’s tools only make sense with both chapter 18′s compiler landscape and chapter 83′s memory layout in hand, so having passed both, now is at once the latest and the earliest possible slot.

By the end of this chapter

What people who write C that runs on chips carry with them. The compilers that differ by vendor (IAR, Arm, TI, Microchip, Renesas, SDCC and others), and the tools that sit beside make and git — build tools, debug probes and on-chip debugging, how to see a log on a machine with no screen, simulators, static analysis and unit testing, and the tools that measure size. There is no need to install any of it now. The point is to know the names and what they are for.

The questions this chapter answers

  1. Must all of this be learned before starting embedded work?

97.1 The embedded compilers

Only those currently in service. Since the point is recognising names, a table will do.

compilerchips targetedcharacter
IAR Embedded WorkbenchArm, RISC-V, 8051, MSP430, AVR, RX, RL78, RH850 and many morecommercial. known for certification (automotive, medical) and code size
Arm Compiler for Embedded (armclang)the Arm Cortex familycommercial (included in Keil MDK). Clang-based
TI Arm Clang (tiarmclang)TI’s Arm coresfree. Clang-based, with TI extensions
MPLAB XC8 / XC-DSC / XC32Microchip PIC, AVR, SAMusable free of charge. XC32 covers Arm and MIPS
Renesas CC-RX / CC-RLRenesas RX, RL78commercial. Renesas chips only
Green Hills Optimising CompilersArm, PowerPC, RISC-V and otherscommercial. a long-standing power in the safety market
Wind River DiabArm, PowerPC and otherscommercial. aerospace and automotive certification
SDCC8051, STM8, Z80, 6502, PDK and other 8-bitfree software. the standard for small chips
arm-none-eabi-gcc and other GCC portsArm, RISC-V, AVR, MSP430 …free software. the default inside vendor SDKs
Clang/LLVM embedded buildsArm, RISC-Vthe common base of the vendor compilers

Table 98.1

Two currents show. One is the same as in chapter 18 — nearly every new compiler is LLVM-based (Arm’s armclang, TI’s tiarmclang, Microchip’s new XC32). The other is becoming free. Compilers that required a paid key to enable optimisation used to be common; Microchip removed that restriction in recent editions.

Platform note. Look at the chip vendor’s SDK first

In practice the starting point is often not choosing a compiler but getting the development bundle the chip company provides (its SDK) — ST’s STM32Cube, NXP’s MCUXpresso, Espressif’s ESP-IDF, Nordic’s nRF Connect SDK and the like. Inside them a compiler (usually GCC or Clang), a linker script, startup code, peripheral libraries and debugging configuration already come paired. Choosing tools one by one from scratch is something you do after learning why that bundle looks the way it does.

97.2 The tools beside make and git

Now for the tools. On an embedded developer’s desk there are several beyond make and git. Grouped by what they do:

① Assembling the build. make is still the base, but today’s practice puts a generator on top. CMake is the de facto standard (it produces build files and is commonly paired with Ninja, a fast executor, behind it), and Meson is used too. Higher-level tools that manage libraries, boards and toolchains wholesale include PlatformIO (many boards with one command), the Zephyr project’s west, and Espressif’s idf.py. Projects with many configuration options, like a kernel, switch features on and off with Kconfig and describe the hardware layout in a device tree.

② Burning it onto the chip and stopping it. To flash a program onto a chip and halt it mid-execution to look inside, you need a small piece of hardware called a debug probe. SEGGER’s J-Link, ST’s ST-Link and the standard CMSIS-DAP family are common. The software joining probe to computer is OpenOCD, pyOCD or the vendor’s own server, and on top of that chapter 17′s gdb works just as before — except that this is remote debugging, with the program running on another machine. Chip and probe are connected by a few wires called JTAG or SWD.

③ Seeing a log on a machine with no screen. Embedded boards usually have no screen, so where printf output goes becomes a question. The traditional answer is to send it out of a serial port (UART) and receive it on a computer with a terminal program (picocom, minicom, screen, PuTTY). The Arm family has two faster routes — ITM/SWO, which floats characters out over the debug line, and SEGGER’s RTT, in which the probe peeks at a memory buffer. There is also semihosting, where the debugger performs host I/O on the target’s behalf, but it is slow and used only for testing.

Counter-example. Using printf anywhere in embedded code

The printf debugging habit formed on a host (chapter 17) brings three problems in embedded work. Size — the whole format interpreter is linked in and eats tens of KiB. Speed — pushing one character at a time over a UART costs milliseconds. Timing — that delay changes the real-time behaviour, so the bug disappears the moment you print: the classic situation.

So practice uses lighter alternatives: a reduced printf handling integers only, a scheme that sends only a number instead of putting the format string on the chip, or a nearly free channel such as the RTT above. It is also why chapter 17′s “learn the debugger” is especially valuable in embedded work.

④ Running it without the machine. When the hardware does not exist yet, or many boards must be tested automatically, you use a simulator. QEMU imitates various boards, and Renode can imitate several devices and even a network together, which makes it common in test automation (CI). Vendor IDEs often ship an instruction-level simulator too.

⑤ Having the code read for you. Embedded software is hard to fix once shipped (the product leaves your hands), so static analysis has great value. Free tools include cppcheck and clang-tidy (and the compiler’s own -Wall -Wextra); commercial ones commonly used are PC-lint Plus, PVS-Studio, Polyspace and Coverity. In the automotive industry the ability to check conformance to a set of coding rules called MISRA C is especially important — an approach of “using only the subset of C that has been decided as allowed.”

⑥ Testing. Code that runs on a chip is unit-tested too. For C, Unity (with its build tool Ceedling) and CppUTest are widely used, and it is the practice to compile logic that does not touch hardware on the host and test it there — where you can turn on checkers like -fsanitize=address,undefined (chapter 17), receiving in place of the chip the checks it cannot give you.

⑦ Measuring size and layout. Memory is small, so “how much went in” is measured constantly. Binary tools such as size, nm, objdump and readelf are the basics, and you read the map file the linker leaves to see what occupies the space. Tools such as bloaty and puncover present that analysis nicely. To convert into a format for the chip you use objcopy (ELF → bin/hex) or srec_cat.

⑧ Seeing the signals with your eyes. A moment comes when software tools alone will not do. When you must see what signal is leaving a pin, out come the logic analyser (the free software sigrok/PulseView supports inexpensive hardware) and the oscilloscope. That half of the “the code is right but it does not work” problems are wiring and power is an old proverb of this world.

In practice. Compiler Explorer — a museum of compilers opened in a browser

One tool that needs no installation. The website godbolt.org (Compiler Explorer) lets you write C on the left and shows, immediately on the right, what machine code that code becomes. You can compare across compilers and versions (from gcc 4 to the newest, clang, MSVC, embedded arm targets — hundreds of them) and optimisation options.

It is the easiest way to see with your own eyes what chapter 13 (compiler optimisation) called “the editor rewriting the code” — x * 2 becoming a shift, the outputs of -O0 and -O2 being utterly different, a loop disappearing entirely, all visible in seconds. In embedded work it is also used to check “how many bytes of instruction does this code become.”

Q. Must all of this be learned before starting embedded work?

A. No. The minimum bundle to start is four things — the chip company’s SDK, a compiler (usually inside the SDK), one debug probe, and a serial terminal. The rest grows one at a time as the need arises. The purpose of this chapter is not to make you memorise a list but to let you recognise, when you later meet those names, which slot the tool sits in.

Recap

what it doestools
assembling the buildCMake, Ninja, Meson; PlatformIO, west, idf.py; Kconfig
burning and haltingJ-Link, ST-Link, CMSIS-DAP + OpenOCD, pyOCD + gdb
seeing logsUART + terminal, ITM/SWO, RTT, (slow) semihosting
running without hardwareQEMU, Renode, vendor simulators
having code readcppcheck, clang-tidy; PC-lint Plus, PVS-Studio; MISRA
testingUnity, Ceedling, CppUTest; sanitizers on the host
measuring sizesize, nm, objdump, readelf; map files; bloaty, puncover
seeing signalslogic analyser (sigrok), oscilloscope
inspecting machine codeCompiler Explorer (godbolt.org)

Table 98.2

We have looked round the embedded desk. After chapter 18′s landscape of compilers and chapter 96′s toolbox, the tools of the place where C is rooted most deeply have their names too.

Now the last chapter. It retraces the road this book has travelled, gathers the practices of modern C into a single page of guidance, and closes.