|  | --- | 
|  | title: Build Software | 
|  | --- | 
|  |  | 
|  | ## Prerequisites | 
|  |  | 
|  | _Make sure you followed the install instructions to [prepare the system]({{< relref "install_instructions#system-preparation" >}}) and install the [compiler toolchain]({{< relref "install_instructions#compiler-toolchain" >}})._ | 
|  |  | 
|  | ## Building software | 
|  |  | 
|  | OpenTitan software is built using [Meson](https://mesonbuild.com). | 
|  | However, Meson is not an exact fit for a lot of things OpenTitan does (such as distinguishing between FPGA, ASIC, and simulations), so the setup is a little bit different. | 
|  |  | 
|  | For example, the following commands build the `boot_rom` and `hello_world` binaries for FPGA: | 
|  |  | 
|  | ```console | 
|  | # Configure the Meson environment. | 
|  | $ cd $REPO_TOP | 
|  | $ ./meson_init.sh | 
|  |  | 
|  | # Build the two targets we care about, specifically. | 
|  | $ ninja -C build-out sw/device/boot_rom/boot_rom_export_fpga_nexysvideo | 
|  | $ ninja -C build-out sw/device/examples/hello_world/hello_world_export_fpga_nexysvideo | 
|  |  | 
|  | # Build *everything*, including targets for other devices. | 
|  | $ ninja -C build-out all | 
|  | ``` | 
|  |  | 
|  | Note that specific targets are followed by the device they are built for. | 
|  | OpenTitan needs to link the same device executable for multiple devices, so each executable target is duplicated one for each device we support. | 
|  |  | 
|  | In general, `clean` rules are unnecessary, and Meson will set up `ninja` such that it reruns `meson.build` files which have changed. | 
|  |  | 
|  | Build intermediates will show up in `$REPO_TOP/build-out`, including unlinked object files and libraries, while completed executables are exported to `$REPO_TOP/build-bin`. | 
|  | As a rule, you should only ever need to refer to artifacts inside of `build-bin`; the exact structure of `build-out` is subject to change. | 
|  | Complete details of these semantics are documented in `util/build_consts.sh`. | 
|  |  | 
|  | The locations of `build-{out,bin}` can be controled by setting the `$BUILD_ROOT` enviromnent variable, which defaults to `$REPO_TOP`. | 
|  |  | 
|  | `./meson_init.sh` itself is idempotent, but this behavior can be changed with additional flags; see `./meson_init.sh` for more information. | 
|  | For this reason, most examples involving Meson will include a call to `./meson_init.sh`, but you will rarely need to run it more than once per checkout. | 
|  |  | 
|  | Building an executable `foo` destined to run on the OpenTitan device `$DEVICE` will output the following files under `build-bin/sw/device`: | 
|  | * `foo_$DEVICE.elf`: the linked program, in ELF format. | 
|  | * `foo_$DEVICE.bin`: the linked program, as a plain binary with ELF debug information removed. | 
|  | * `foo_$DEVICE.dis`: the disassembled program with inline source code. | 
|  | * `foo_$DEVICE.vmem`: a Verilog memory file which can be read by `$readmemh()` in Verilog code. | 
|  |  | 
|  | In general, this executable is built by building the `foo_export_$DEVICE` target. | 
|  |  | 
|  | Building an executable destined to run on a host machine (i.e., under `sw/host`) will output a host excecutable under `build-bin/sw/host`, which can be run directly. | 
|  |  | 
|  | ## Troubleshooting the build system | 
|  |  | 
|  | If you encounter an error running `./meson_init.sh` you could re-run using the `-f` flag which will erase any existing building directories to yield a clean build. | 
|  | This sledgehammer is only intended to be used as a last resort when the existing configuration is seriously broken. | 
|  |  | 
|  | ```console | 
|  | $ ./meson_init.sh -f | 
|  | ``` | 
|  |  | 
|  | If any `meson.build` files are changed the configuration can be regenerated by passing the `-r` flag to `./meson_init.sh` | 
|  |  | 
|  | ```console | 
|  | $ ./meson_init.sh -r | 
|  | ``` | 
|  |  | 
|  | ## Bringing your own toolchain | 
|  |  | 
|  | `./meson_init.sh` needs to know where the toolchain you are using is, and which tools from it should be used. | 
|  |  | 
|  | If you are using the lowrisc-provided toolchain (obtained with `get-toolchain.py`), and it is installed in the default location (`/tools/riscv`), then `./meson_init.sh` does not need additional configuration. | 
|  |  | 
|  | If you are using the lowrisc-provided toolchain, but have located it in a non-default location (using `get-toolchain.py -t /path/to/lowrisc/toolchain`), you can use the environment variable `TOOLCHAIN_PATH` to point to your toolchain location, like so: | 
|  | ```console | 
|  | $ export TOOLCHAIN_PATH=/path/to/lowrisc/toolchain | 
|  | $ ./meson_init.sh | 
|  | ``` | 
|  |  | 
|  | If you have moved a lowrisc-provided toolchain (obtained with `get-toolchain.py`), you will need to update paths within the meson toolchain configuration files within the toolchain installation. | 
|  | These are called `meson-<triple>-<compiler>.txt`, and are present in toolchains since version 20200602-1. | 
|  | You can still use `TOOLCHAIN_PATH` to point to the toolchain location if you have updated the paths within these files. | 
|  |  | 
|  | If you have built your own toolchain by following option 2 under [Installing Software Build Requirements]({{< relref "doc/ug/install_instructions/index#device-compiler-toolchain-rv32imc" >}}), then you need to point `./meson_init.sh` to your custom toolchain file using `-t FILE`: | 
|  |  | 
|  | ```console | 
|  | $ ./meson_init -t /path/to/toolchain/file | 
|  | ``` | 
|  |  | 
|  | If you do not specify your own toolchain configuration file (using `./meson_init.sh -t`), and `meson_init.sh` cannot find the default configuration in your toolchain, the legacy `toolchain.txt` from the main OpenTitan repository will be used. | 
|  | If `TOOLCHAIN_PATH` is set, this will be used to update any paths within the legacy configuration. | 
|  |  | 
|  | ## Debugging device software | 
|  |  | 
|  | ### Attaching a debugger | 
|  |  | 
|  | GDB can be used to debug device software running on an FPGA or in a Verilator simulation. | 
|  | Refer to the [Getting started on FPGAs]({{<relref getting_started_fpga >}}) and [Verilator]({{<relref getting_started_verilator >}}) guides for more details. | 
|  |  | 
|  | ### Disassembling device code | 
|  |  | 
|  | A disassembly of all executable sections is produced by the build system by default. | 
|  | It can be found by looking for files with the `.dis` extension next to the corresponding ELF file. | 
|  |  | 
|  | To get a different type of disassembly, e.g. one which includes data sections in addition to executable sections, objdump can be called manually. | 
|  | For example the following command shows how to disassemble all sections of the UART DIF smoke test interleaved with the actual source code. | 
|  |  | 
|  | ```console | 
|  | $ riscv32-unknown-elf-objdump --disassemble-all --headers --line-numbers --source build-bin/sw/device/tests/dif_uart_smoketest_sim_verilator.elf | 
|  | ``` | 
|  |  | 
|  | Refer to the output of `riscv32-unknown-elf-objdump --help` for a full list of options. |