Software Delivery Foundations

A software project contains human-written source, configuration, dependencies, tests, and sometimes generated code.

What this module covers

Source files, headers, assets, tests, configuration, and generated files

The edit–build–test–package–release cycle Compilation, assembly, linking, loading, and execution Build artifacts versus source artifacts

Build tools versus version-control tools Local development, CI, staging, and production

Build failures versus test failures versus runtime failures A first manual build and why automation is needed

1.1 What happens between source code and a running program?

A software project contains human-written source, configuration, dependencies, tests, and sometimes generated code. A build pipeline transforms these inputs into artifacts that can be tested, distributed, or executed.

A web application may bundle JavaScript, CSS, and assets. A C application may produce object files and an executable. Embedded software may produce an ELF file, HEX file, BIN image, map file, and debug symbols.

Text equivalent: inputs are configured and resolved, compiled, linked into an artifact, then tested, scanned and packaged before becoming a versioned release. The build system owns the first four steps; version control records the inputs, and CI/CD drives the whole chain.

Source + Configuration + Dependencies
                  |
                  v
        Configure / Resolve
                  |
                  v
          Preprocess / Compile
                  |
                  v
            Assemble / Link
                  |
                  v
             Build Artifact
                  |
                  v
        Test / Scan / Package
                  |
                  v
          Versioned Release
flowchart TD
  S[Source, configuration, dependencies] --> C[Configure and resolve]
  C --> P[Preprocess and compile]
  P --> L[Assemble and link]
  L --> A[Build artifact]
  A --> T[Test, scan, package]
  T --> R[Versioned release]

1.2 Build versus version control

Build system: determines how inputs become outputs, in what order tasks run, and when work can be reused.

Version control system (VCS): records and coordinates changes to files and history.

They work together but solve different problems. Git can store a Makefile, but Git does not compile the program. Make can run git describe as part of a versioning recipe, but Make does not replace Git's history model.

1.3 A first manual C build

Compile and link with a compiler driver:

Terminal session (GCC 11.2, Ubuntu 22.04 on WSL2): Typical stages, when invoked separately:

Terminal session (GCC 11.2, Ubuntu 22.04 on WSL2), with file, wc and a final run added:

Exact compiler commands and file formats depend on the toolchain and operating system. The compiler driver commonly orchestrates several tools for you.

#include <stdio.h>

int main(void)
{
    puts("Hello, build systems!");
    return 0;
}
cc -Wall -Wextra -Wpedantic -g hello.c -o hello
./hello
$ cc -Wall -Wextra -Wpedantic -g hello.c -o hello
$ ./hello
Hello, build systems!
cc -E hello.c -o hello.i   # Preprocess
cc -S hello.i -o hello.s   # Compile to assembly
cc -c hello.s -o hello.o   # Assemble to object file
cc hello.o -o hello        # Link executable
$ cc -E hello.c -o hello.i   # Preprocess
$ cc -S hello.i -o hello.s   # Compile to assembly
$ cc -c hello.s -o hello.o   # Assemble to object file
$ cc hello.o -o hello        # Link executable
$ file hello.i hello.s hello.o hello | sed 's/, BuildID[^,]*//'
hello.i: C source, ASCII text
hello.s: assembler source, ASCII text
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
hello:   ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, not stripped
$ wc -l hello.c hello.i hello.s
    7 hello.c
  745 hello.i
   45 hello.s
  797 total
$ ./hello
Hello, build systems!

1.4 Why automate?

Manual builds become error-prone when projects have many files, generated assets, platform variants, third-party libraries, and tests. Automation provides a recorded procedure, dependency ordering, repeatability, and a way to avoid rebuilding unchanged components.

Knowledge check

Does Git compile source code? No. What is an artifact? A file or package produced or collected by a workflow, such as an executable, library, firmware image, or test report.

Why can an incremental build be faster than a clean build? It can reuse valid outputs whose inputs have not changed.

Quiz

? What does Git do with a Makefile in the repository?
- It compiles the project using the Makefile. :: Git does not build anything.
+ It stores and versions the file like any other content. :: Running the build is Make's job.
- It converts it to CMake. :: No such conversion exists.
- It ignores it automatically. :: Makefiles are ordinary tracked files.

? In the real run of `cc -E`, `cc -S`, `cc -c` and the final link, which file was the relocatable object?
- `hello.i` :: That is preprocessed C source.
- `hello.s` :: That is assembly text.
+ `hello.o` :: `file` reported it as an ELF relocatable object.
- `hello` :: That is the linked executable.

? Which are build artifacts? (select all that apply)
+ An executable :: Produced by the link step.
+ A test report :: Produced by a workflow and worth keeping.
+ A firmware HEX image :: Produced by conversion after linking.
- `main.c` :: Source code is an input, not an artifact.