Hi I’m trying to build a C project with build.zig
The project is for an embedded platform on ARMv7-M (thumb) specifically for an STM32 CPU. The vendor provides hardware abstraction layer (HAL c-sources ) libraries, startup-code (assembly) and main file.
I successfully included paths to header and sources (c+asm) for the HAL and linker script.
The constraint is that I have to link against newlib as the libc standard library. I added the references to the newlib library object files for my target (ARM embedded cpus have multiple pre-build binaries compiled by the arm-none-eabi-gcc project like crt0.o crtbegin.o, newlibc.o etc…) but I’m unable to compile with zig build
because it fails with no significant messages on the linking step. I suspect that it has something to do with how I link to newlib.
I read the startup assembly script for my CPU, and it is the first code that runs after a cpu reset. It does most of the initialization that a normal crt0.s code does a part from calling _start
. In fact later on it calls __libc_init_array
that calls __init
an probably later __start
but the call to main
is done in the startup assembly (startup_stm32f446xx.s).
I don’t know how to debug my linking error and how to generate a build.
build.zig
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
//b.verbose_cc = true;
b.verbose_link = true;
//b.verbose_air = true;
//b.verbose = true;
const prj_name = "test";
const target = .{
.cpu_arch = .thumb, // ARMv7
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 }, // STM32F446RE
.os_tag = .freestanding, // running in bare metal
.abi = .eabihf, // no libc (noneabi) with hardware floating point (hf)
};
const asm_sources = [_][]const u8{"startup_stm32f446xx.s"};
//const asm_flags = [_][]const u8{
// "-fdata-sections",
// "-ffunction-sections",
// "-Wall",
// "-Wextra",
// "-Werror",
// "-pedantic",
// "-fstack-usage"
//};
const c_includes = [_][]const u8{
"./Core/Inc",
"./Drivers/STM32F4xx_HAL_Driver/Inc",
"./Drivers/STM32F4xx_HAL_Driver/Inc/Legacy",
"./Drivers/CMSIS/Device/ST/STM32F4xx/Include",
"./Drivers/CMSIS/Include",
};
const c_sources_drivers = [_][]const u8{
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c",
"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c",
};
// "-Wno-unused-parameter",
const c_sources_drivers_compile_flags = [_][]const u8{
"-std=gnu11",
"-DUSE_HAL_DRIVER",
"-DSTM32F446xx",
"-ffunction-sections",
"-fdata-sections",
"-nostdlib",
"-nostdinc",
"-Wall",
//"-Werror",
"-Wextra",
"-pedantic",
"-fstack-usage",
"-mthumb",
};
const c_sources_core = [_][]const u8{
"./Core/Src/system_stm32f4xx.c",
"./Core/Src/stm32f4xx_it.c",
"./Core/Src/stm32f4xx_hal_msp.c",
};
const c_sources_app = [_][]const u8{
"./Core/Src/main.c",
"./Core/Src/MedianFilter.c",
};
//const c_compile_flags = [_][]const u8{ "-DUSE_HAL_DRIVER", "-DSTM32F446xx", "-std=gnu11", "-Wall", "-Werror", "-Wextra", "-pedantic", "-fstack-usage", "-fdata-sections", "-ffunction-sections" };
const c_compile_flags = [_][]const u8{ "-DUSE_HAL_DRIVER", "-DSTM32F446xx", "-std=gnu11", "-Wall", "-Wextra", "-pedantic", "-fstack-usage", "-fdata-sections", "-ffunction-sections" };
//const c_compile_flags = [_][]const u8{ "-DUSE_HAL_DRIVER", "-DSTM32F446xx", "-fstack-usage", "-fdata-sections", "-ffunction-sections" };
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const elf = b.addExecutable(.{
.name = prj_name ++ ".elf",
.target = target,
.optimize = optimize, // use optimization given by user
//.strip = false, // do not strip debug symbols
.linkage = .static, // static linking
.link_libc = false, // will link against newlib_nano
.single_threaded = true, // single core cpu
});
// Add necessary libraries and link to them
elf.addIncludePath(.{ .path = "/usr/arm-none-eabi/include" });
elf.addIncludePath(.{ .path = "/usr/arm-none-eabi/include/newlib-nano" });
elf.addObjectFile(.{ .path = "/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libnosys.a" });
elf.addObjectFile(.{ .path = "/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc_nano.a" });
elf.addObjectFile(.{ .path = "/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libm.a" });
//elf.addObjectFile(.{ .path = "/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libgcc.a" });
//elf.addObjectFile(.{ .path = "/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/crti.o" });
//elf.addObjectFile(.{ .path = "/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/crtbegin.o" });
// C runtime 0 contains _start function, initializes stack and libc
// runtime, then calls _main
// Cruntime 0: This object is expected to contain the _start symbol which
// takes care of bootstrapping the initial execution of the program.
// this object initializes very early ABI requirements
// (like the stack or frame pointer), setting up the argc/argv/env values, and
// then passing pointers to the init/fini/main funcs to the internal libc main
// which in turn does more general bootstrapping before finally calling the real
// main function.
elf.addObjectFile(.{ .path = "/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/crt0.o" });
// crti (cruntime init) Defines the function prologs for the .init and
// .fini sections (with the _init and _fini symbols respectively). This
// way they can be called directly. They contain constructors and destructors
// for global structs
elf.addObjectFile(.{ .path = "/usr/lib/gcc/arm-none-eabi/13.2.0/thumb/v7e-m+fp/hard/crti.o" });
// Defines the function epilogs for the .init/.fini sections
//elf.addObjectFile(.{ .path = "/usr/lib/gcc/arm-none-eabi/13.2.0/thumb/v7e-m+fp/hard/crtn.o" });
// GCC uses this to find the start of the constructors
elf.addObjectFile(.{ .path = "/usr/lib/gcc/arm-none-eabi/13.2.0/thumb/v7e-m+fp/hard/crtbegin.o" });
// GCC uses this to find the start of the destructors.
//elf.addObjectFile(.{ .path = "/usr/lib/gcc/arm-none-eabi/13.2.0/thumb/v7e-m+fp/hard/crtend.o" });
// Add C source files
elf.addCSourceFiles(&c_sources_drivers, &c_sources_drivers_compile_flags);
elf.addCSourceFiles(&c_sources_core, &c_compile_flags);
elf.addCSourceFiles(&c_sources_app, &c_compile_flags);
// Add Assembly sources
for (asm_sources) |path| {
elf.addAssemblyFile(.{ .path = path });
}
// Add C headers include dirs
for (c_includes) |path| {
elf.addIncludePath(.{ .path = path });
}
// Set Entry Point of the firmware
elf.entry_symbol_name = "Reset_Handler";
// Set linker script file
elf.setLinkerScriptPath(.{ .path = "./STM32F446RETx_FLASH.ld" });
elf.setVerboseLink(true);
b.default_step.dependOn(&elf.step);
b.installArtifact(elf);
}
Here my linking error result after zig build
:
zig build-exe test.elf Debug thumb-freestanding-eabihf: error: ld.lld --error-limit=0 -O0 --entry Reset_Handler -z stack-size=16777216 -T /home/simone/Documents/test/stm32f446re/STM32F446RETx_FLASH.ld --gc-sections -znow -m armelf_linux_eabi -Bstatic -o /home/simone/Documents/test/stm32f446re/zig-cache/o/2926eb9bebe0b6086adb9408f974c605/test.elf /usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libnosys.a /usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc_nano.a /usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libm.a /usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/crt0.o /usr/lib/gcc/arm-none-eabi/13.2.0/thumb/v7e-m+fp/hard/crti.o /usr/lib/gcc/arm-none-eabi/13.2.0/thumb/v7e-m+fp/hard/crtbegin.o /home/simone/Documents/test/stm32f446re/zig-cache/o/99288ce3e59a0a256c3a994803be2af0/stm32f4xx_hal_tim.o /home/simone/Documents/test/stm32f446re/zig-cache/o/3392d5d156564ae16d92e6e1e61287dd/stm32f4xx_hal_tim_ex.o /home/simone/Documents/test/stm32f446re/zig-cache/o/f45f1e22a18dfeb915af7d502fe65480/stm32f4xx_hal_uart.o /home/simone/Documents/test/stm32f446re/zig-cache/o/dfc9ef3cafd45a08e1748e5daf7d89c1/stm32f4xx_hal_rcc.o /home/simone/Documents/test/stm32f446re/zig-cache/o/dd46e027c458622b9f55f8559f13606c/stm32f4xx_hal_rcc_ex.o /home/simone/Documents/test/stm32f446re/zig-cache/o/7ec7a26337c091e4b5b68b21fca20066/stm32f4xx_hal_flash.o /home/simone/Documents/test/stm32f446re/zig-cache/o/efd3655fa5f8371e61870ae4070e0039/stm32f4xx_hal_flash_ex.o /home/simone/Documents/test/stm32f446re/zig-cache/o/e575702641443b72ac5f71bcd076bb7e/stm32f4xx_hal_flash_ramfunc.o /home/simone/Documents/test/stm32f446re/zig-cache/o/8bd73bf66e49c02b4de785fa40745d3d/stm32f4xx_hal_gpio.o /home/simone/Documents/test/stm32f446re/zig-cache/o/320697216849f57288f06ee30b883927/stm32f4xx_hal_dma_ex.o /home/simone/Documents/test/stm32f446re/zig-cache/o/d8005e7182f54a18ef4f67f4611b352e/stm32f4xx_hal_dma.o /home/simone/Documents/test/stm32f446re/zig-cache/o/b47ab7db75a3fa4f15862b8bf641f383/stm32f4xx_hal_pwr.o /home/simone/Documents/test/stm32f446re/zig-cache/o/01e7e5906a3cfce5eb6706ad53b571b8/stm32f4xx_hal_pwr_ex.o /home/simone/Documents/test/stm32f446re/zig-cache/o/e5b65b2fa6b1256cab359bf320787ca0/stm32f4xx_hal_cortex.o /home/simone/Documents/test/stm32f446re/zig-cache/o/1696de14f92d2c979677719783df1848/stm32f4xx_hal.o /home/simone/Documents/test/stm32f446re/zig-cache/o/47c1c46543fadda6325e01461f19c71c/stm32f4xx_hal_exti.o /home/simone/Documents/test/stm32f446re/zig-cache/o/458200b72dc662e8df51c6bf2e572a28/system_stm32f4xx.o /home/simone/Documents/test/stm32f446re/zig-cache/o/8556142a4e8cb3a64acad0a21c600e20/stm32f4xx_it.o /home/simone/Documents/test/stm32f446re/zig-cache/o/88e82eefb964b9cc17f8339c485391dd/stm32f4xx_hal_msp.o /home/simone/Documents/test/stm32f446re/zig-cache/o/9e04bf4154200a9ad229a98adf1ef133/main.o /home/simone/Documents/test/stm32f446re/zig-cache/o/608588b52ad424e39fbe7b754bc2d13b/MedianFilter.o /home/simone/Documents/test/stm32f446re/zig-cache/o/34deb1aa406cbf5da07069ba8d251c04/startup_stm32f446xx.o /home/simone/.cache/zig/o/c0e0857fbf17c71bbc9eeea5e5debd97/libc.a --as-needed /home/simone/.cache/zig/o/5201866f2b3579a8a2d793a3128633bc/libcompiler_rt.a --allow-shlib-undefined
You can find the repo and other files here GitHub - simoneruffini/test
The linking of newlib is hardcoded because provided by the arm-none-eabi-newlib
package in archlinux, but other linux distributions have the same package.
The project works with the provided makefile that I used as the base to create the build.zig. You can see the verbose output of the compilation with makefile in this file for understanding how and which libraries are linked: test/make_v.log at master · simoneruffini/test · GitHub
Thank you, I don’t know how to proceed more then this.