Mastering Embedded Build Systems: Exploring the 5 Essential Configurations

If you’ve ever developed embedded software, you know typical embedded build systems have just two build configurations: debug and release. In fact, you’ve probably spent most of your time only using the debug build. The Rust build system has gone a little further in that test has been added. However, did you know there are five essential build configurations you should use? Let’s explore the different embedded build system configurations you and your team can use to ensure you develop software faster. We’ll start with the least common and work towards the most common.

Build System Configuration #1 – Analyze

The first embedded build system configuration for us to discuss is an analysis build. Developing quality embedded software requires you to be reviewing and analyze your software. You should be asking questions such as:

  • What’s the cyclomatic complexity of my functions?
  • What’s the coupling of my code?
  • Are my tasks executing at the correct rate?
  • What’s my worst-case CPU load?
  • Am I passing my static code analysis tests for correctness and coding standards?

Many build time checks can be performed on code, often delegated to manual reviews or pushed to CI/CD. Typically, before I commit my code, I run my analyze build. The build will run all my static, dynamic, and metrics checks to ensure that my code is in the right shape to commit to the DevOps system.

Action Item: What analysis checks should you be performing on your code? How can you automate this as part of your analysis build?

Build System Configuration #2 – Simulate

Simulating the application code is the most underutilized technique for developing embedded software. Your build system should have a configuration that allows you to build your software for simulation on your host environment. You don’t necessarily need a target emulator; you can verify your application code by running it on the host. There are a lot of advantages to simulation, such as:

  • Improved time efficiency – You don’t have to wait for hardware to arrive, no franken-boards, and removing the bug-flash-debug cycle.
  • Flexibility and scalability – You must use hardware abstraction layers (HALs) that decouple code and improve reusability.
  • Reduced development costs – You can debug and solve problems faster within a host environment than on an embedded target.

Embedded developers often believe they can’t simulate their software because it touches the hardware. However, carefully crafting the software architecture can enable simulation and on-target execution. In addition, modern techniques like DevOps’ CI/CD techniques are forcing many teams to rethink how they architect their software to manage their hardware dependencies better. So if you are pursuing DevOps, adding a simulation build is a natural extension.

Action Items: What is your biggest hurdle in using simulation with your embedded software? Can you identify a single application module to use as a test case for creating a simulation build over the next month?

Build System Configuration #3 – Test

If you’ve been working on modernizing your embedded software processes, then you’ve probably encountered or created your test build configuration. A test configuration is about running unit tests, integration tests, and maybe even system-level tests (although I usually push that to the CI/CD process). My typical workflow is to use the test build configuration while creating modules using test-driven development (TDD). I write a test, make it fail, write some code, and make the test pass. Part of the configuration will also run my regression tests and report my code coverage.

When you create a test build configuration, you’ll integrate a test harness that runs the build. The test harness usually compiles for your host machine, not your target, but it depends on your needs. Like with simulation, you’ll want a good HAL and decoupling to test your application code on the host. Be warned, though; unit testing is not a simulation. Simulation is about running the code on the host like you would on your target. Unit testing is about running individual controlled tests to ensure individual modules work as expected.

Action Items: If you don’t have a test build that uses a test harness, investigate a free test harness like cpputest or ctest.

Build System Configuration #4 – Release

You’ve probably encountered the release build occasionally in your career. For example, when ready to deploy our firmware to a shippable product, we use a release build. The release build applies all the production optimizations and removes debug information. Now, there is certainly something to be said about shipping what you test, so make sure that your quality assurance testing is done using your release builds.

One issue often encountered with release builds is developers leaving symbols and other confidential information accessible within their build. While this might be useful for in-field debugging, it can also be a security liability. Make sure that you take the time to check what is included in your release build carefully! If I can pull your firmware and you have your symbol tables easily accessible, converting your application back into readable code takes a few dozen seconds.

Action Items: Carefully review and analyze what your release build settings are. Ask yourself why you are using the settings that you are.

Build System Configuration #5 – Debug

The debug configuration is your tried-and-true embedded build system configuration. If you walk around the floor of an engineering department, you can often find embedded developers happily single stepping away in their software to debug code. Unfortunately, this is probably the worst thing an embedded developer can do most of the time (sometimes, this debugging time is necessary).

Debug builds often include far more information in the image so developers can poke around and debug. The problem is that most application code can be debugged far better on a host. Debug building often slows down developers and encourages poor debugging practices. They are a necessary evil for driver development, but most teams I see today are using their silicon vendors’ driver code, so using a good HAL and you can simulate or test your bugs.

Action Items: Encourage yourself and your team to use the debug build configuration less. Use your test harness and simulation builds to identify and resolve issues quickly. You’ll find it’s faster and more efficient.

Embedded Build System Conclusions

The debug build configuration isn’t the only configuration available to embedded software teams. In fact, I hope that you’ve realized that the use of analyze, test, and simulate build configurations can be more valuable and efficient. The trick is thinking about embedded software and firmware as just software. Properly layered, decoupled, and abstracted application code can be tested on MacOS, Linux, or Windows easier than on an embedded target. I hope you’ll carefully think through these build configurations and develop a plan of action to start integrating them into your build processes.

Share >

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.