# C++: Building

The supplied project is built with CMake. A configured build directory ships
with the device, so in normal use you edit one file and run `make`.

## The standard workflow

1. Edit `~/Desktop/synergy_cpp/main.cpp`. This is the file the build compiles
   into the program.
2. Build from the build directory:

   ```bash
   cd ~/Desktop/synergy_cpp/build
   make
   ```

3. Run the result:

   ```bash
   sudo ./program
   ```

The executable is written to the same build directory. Rebuilds take a few
seconds because only the changed file is recompiled.

```{admonition} Why sudo
:class: note

The supplied `main.cpp` includes the RGB indicator library, which requires root
privileges. If your program does not drive the indicator, remove that include
and run the executable without `sudo`. Backplane access alone does not need
elevated privileges.
```

## Starting from an example

The examples under `~/Desktop/synergy_cpp/examples/` are complete programs.
To run one, copy its contents into `main.cpp` and rebuild:

```bash
cd ~/Desktop/synergy_cpp
cp examples/Basic/PrintModules/PrintModules.cpp main.cpp
cd build
make
sudo ./program
```

Keep a copy of your own `main.cpp` before overwriting it.

## Adding your own source files

For anything larger than a single file, add your sources to the executable in
`~/Desktop/synergy_cpp/CMakeLists.txt`:

```cmake
add_executable(program main.cpp src/control.cpp src/alarms.cpp)
```

Then reconfigure and build:

```bash
cd ~/Desktop/synergy_cpp/build
cmake ..
make
```

`cmake ..` is only needed after changing `CMakeLists.txt`. Ordinary edits to
existing source files need `make` alone.

## Building without CMake

The library is small enough to compile directly, which is useful if you keep
your program outside the supplied project:

```bash
LIB=~/Desktop/synergy_cpp/lib/synergy
g++ -std=c++17 -O2 -I $LIB $LIB/Synergy.cpp $LIB/RPi.cpp myprogram.cpp -o myprogram
```

Three translation units, one include path, and no linker flags. The library
uses only kernel headers and the standard library.

This form does not include the RGB indicator library. Add `lib/rpi_ws281x` to
the include path and link `libws2811.a` if you need it.

## Recommended compiler flags

| Flag | Purpose |
|---|---|
| `-std=c++17` | The library and examples assume a modern standard |
| `-O2` | Optimise, which is worthwhile in a control loop |
| `-Wall -Wextra` | Report the mistakes that otherwise become field faults |
| `-g` | Debug symbols, for use with `gdb` |

## Common build errors

`Synergy.h: No such file or directory`
: The include path does not point at the directory containing the headers.

`undefined reference to 'Synergy::init()'`
: You compiled against the header without compiling the implementation. Both
  `Synergy.cpp` and `RPi.cpp` must be in the source list.

`Permission denied` when running
: Not a build problem. See {doc}`setup`.

## Debugging

Build with debug symbols and no optimisation when stepping through code:

```bash
LIB=~/Desktop/synergy_cpp/lib/synergy
g++ -std=c++17 -g -O0 -I $LIB $LIB/Synergy.cpp $LIB/RPi.cpp myprogram.cpp -o myprogram
gdb ./myprogram
```

Stop the PLC before running under a debugger. Note that a breakpoint holds the
SPI bus mid-transaction for as long as execution is paused, which can trigger
the base controller's own timeouts.

## Next

{doc}`examples`, for complete programs.
