Hello, I’m experimenting with Zig in microcontroller projects.
In my current experiment, I build a simple program for a Nucleo-64 (STM32L476) :
Initialized by the STM32CubeMX software.
“build.zig” created to compile the sources (Zig / C / ASM)
Zig code (function “main_zig”) called from a C source file (main.c).
I managed to compile and run this code with version 0.11.0 of Zig. (even with an unknown linker error from lld)
When I have upgraded to 0.12.0, the compilation produces a binary that is too large.
I have no clue yet as to why this change occurred.
I’m on my phone so I haven’t seen the file sizes, but if the size difference is stark, you should submit an issue and someone will investigate this. @kubkon might be willing to help.
I need to look more into the MicroZig build system, however, from what I’ve gathered, MicroZig appears to implement all the software layers using the Zig programming language. In my experiment, I explore an approach that involves retaining the official drivers, such as HAL and LL drivers, in C, along with the code generated by the ST software and other components like FreeRTOS, also in C.
-lnosys doesn’t belong here! That’s a linker argument to include the library named “nosys”, or more specifically the “.a” file libnosys.a (more on that later), so you can remove that from this line
--specs=nano.specs also a linker argument, and unfortunately isn’t doing what you expect, this is actually specific to the arm-none-eabi-gcc compiler, and the TLDR is that uses the “nano” variant of newlib as the “standard c library” for the project. However, zig cc compiler doesn’t know about that spec sheet, so go ahead and remove that from this line, we’ll have to manually link those libraries in later
Wl,--gc-sections also a linker argument, see below how to do this without manually specifying the flag
Alright, so essentially arm-none-eabi-gcc comes with a bunch of pre-compiled libraries + objects. Annoyingly, a lot of these are snuck in without explicitly linking to them by default. So to replicate this behavior but using the zig compiler and linker, we have to manually reference these. I see you were already on the right track here, but I can give you some copy/paste that will do what you intend:
elf.entry = .{ .symbol_name = "Reset_Handler" }; I don’t think this is necessary but also am not sure if it hurts anything or not… TBD on this while I investigate more on my own
The following will accomplish what you wanted with Wl,--gc-sections : elf.link_gc_sections = true;
As a bonus you can remove the manual specification of -ffunction-sections -fdata-sections flags and replace with:
Lastly, the giant .bin file is almost certainly because of differences in how zig (LLVM’s) linker interprets .ld files vs gcc. Look for areas to potentially add (NOLOAD) as I have a feeling it’s trying to “fill” the memory range between your flash and ram (despite there logically not being anything there in the chip)
How can I enable float parsing with the libc ( -u _printf_float linker option) ?
The symbol ‘_printf_float’ is present in the final binary, I suppose I don’t need to use this option. Float formatting still don’t work (tested with snprintf), I will investigate.
Is it possible to generate a .map file using lld ?
Ahh yep, that’s actually because you’re using the “nano” variant of newlib, where float printf formatting isn’t included. One of the things that got axed to make the library tiny. You could link in the non “nano” version but that probably will bloat your size more than you want!