Skip to content

Build System Architecture

The EmbSec Kit uses a sophisticated CMake-based build system designed to handle cross-compilation for ARM targets, support multiple platforms, and provide a flexible development environment.

Overview

The build system architecture supports:

  • Cross-compilation for ARM Cortex-M3 targets
  • Multiple target platforms (hardware and emulation)
  • Modular lab compilation
  • Automated testing and packaging
  • Docker-based build environments

CMake Structure

Root CMakeLists.txt

The root CMakeLists.txt establishes the project structure:

cmake_minimum_required(VERSION 3.20)
project(embsec-kit VERSION ${VERSION_CONTENTS} LANGUAGES C ASM)

# Options
option(EMBSEC_BUILD_LABS "Build lab exercises" ON)
option(EMBSEC_BUILD_TESTS "Build tests" OFF)
option(EMBSEC_BUILD_DOCS "Build documentation" OFF)

Key features:

  • Version management from VERSION file
  • Enforced out-of-source builds
  • Configurable build options
  • C99 standard enforcement

Module System

The build system uses custom CMake modules in sdk/cmake/:

EmbSecConfig.cmake

  • Sets up compiler flags and toolchain configuration
  • Defines common build settings
  • Manages platform-specific configurations

EmbSecLab.cmake

The heart of the lab build system, providing the embsec_add_lab() function:

function(embsec_add_lab)
    set(options "")
    set(oneValueArgs NAME SALT)
    set(multiValueArgs SOURCES DEFINITIONS)
    cmake_parse_arguments(LAB "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

This function:

  • Creates lab executables with standard configuration
  • Generates binary formats (.bin, .hex)
  • Creates flash targets for hardware deployment
  • Sets up QEMU targets for emulation
  • Configures test targets

LM3S6965Toolchain.cmake

Cross-compilation toolchain file for ARM targets:

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

# Compiler flags for LM3S6965 (Cortex-M3)
set(CPU_FLAGS "-mcpu=cortex-m3 -mthumb")

# Target definitions for QEMU
add_compile_definitions(
    PART_LM3S6965
    TARGET_IS_DUSTDEVIL_RA0
    QEMU_BUILD
)

Build Presets

The CMakePresets.json file defines standard build configurations:

Development Preset

{
    "name": "dev",
    "generator": "Ninja",
    "binaryDir": "${sourceDir}/build-dev",
    "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "EMBSEC_BUILD_TESTS": "ON"
    }
}

Embedded Preset

{
    "name": "embedded",
    "generator": "Ninja",
    "binaryDir": "${sourceDir}/build",
    "toolchainFile": "${sourceDir}/sdk/cmake/LM3S6965Toolchain.cmake",
    "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
    }
}

QEMU Preset

{
    "name": "qemu",
    "inherits": "embedded",
    "binaryDir": "${sourceDir}/build-qemu",
    "cacheVariables": {
        "EMBSEC_TARGET_QEMU": "ON"
    }
}

Build Targets

Global Targets

  • labs: Builds all lab exercises
  • package-labs: Creates zip archives of lab binaries
  • test-labs: Runs all lab tests in QEMU
  • embsec-sdk: Builds the core SDK library

Per-Lab Targets

For each lab (e.g., buffer-overflow):

  • buffer-overflow: Build the lab executable
  • flash-buffer-overflow: Flash to hardware
  • qemu-buffer-overflow: Run in QEMU
  • debug-buffer-overflow: Debug with GDB
  • exploit-buffer-overflow: Debug with exploit helpers
  • package-buffer-overflow: Create distribution package

Dependency Management

TivaWare Integration

set(TIVAWARE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/vendor/tivaware)
if(EXISTS ${TIVAWARE_ROOT})
    set(TIVAWARE_FOUND TRUE)
    set(TIVAWARE_LIBS ${TIVAWARE_ROOT}/driverlib/gcc/libdriver.a)
endif()

Common Dependencies

  • Startup code: labs/common/startup_gcc.c
  • Linker script: labs/common/tm4c123gh6pm.ld
  • SDK headers: sdk/include/

Build Process Flow

  1. Configuration Phase
  2. CMake reads project files
  3. Detects toolchain and dependencies
  4. Generates build files

  5. Compilation Phase

  6. Compiles SDK library
  7. Builds individual labs
  8. Links with TivaWare and SDK

  9. Post-Build Phase

  10. Generates binary formats (.bin, .hex)
  11. Creates memory maps
  12. Displays size information

  13. Packaging Phase

  14. Bundles lab binaries with documentation
  15. Creates distribution archives

CI/CD Integration

The build system integrates with GitLab CI/CD through .gitlab-ci.yml:

build:labs:
  stage: build
  script:
    - cmake --preset embedded
    - cmake --build ${BUILD_DIR} --target labs
    - cmake --build ${BUILD_DIR} --target package-labs

Docker Support

Build environments are containerized:

  • Dockerfile: Development environment
  • Dockerfile.arm: ARM toolchain environment
  • Dockerfile.ci: CI/CD environment

Best Practices

  1. Always use presets for consistent builds
  2. Out-of-source builds are enforced
  3. Use embsec_add_lab() for new labs
  4. Test in QEMU before hardware deployment
  5. Package labs for distribution

Troubleshooting

Common issues and solutions:

Missing Toolchain

Error: arm-none-eabi-gcc not found!
Solution: Install ARM toolchain or use Docker environment

TivaWare Not Found

Warning: TivaWare not found at vendor/tivaware
Solution: Run setup script or manually install TivaWare

Build Failures

Check: CMakeFiles/CMakeError.log
Verify: Toolchain file is specified
Ensure: Dependencies are installed