If you have ever done software development that involves Apple products, FreeBSD, WebAssembly, or Rust, you have used the wildly popular compiler toolchain known as LLVM. However, LLVM and the open source C-language compiler built on top of it (Clang) do not get a lot of attention in the embedded world.
Thatâs a great post! I have also tried to experiment with Clang few months ago to solve the problem related to iostream C++ STL header.
The problem is that if one would like to include iostream or sstream to implement e.g. nice streaming to a logger, or to some other peripheral, using operator<< for example, then the binary size increases so much, that it will not fit into Flash memory.
This is really annoying, because I canât simply use std::ostringstream, to reuse easy string conversion, and I need to add quite a lot of boilerplate to be able to convert various types to string, using e.g. std::to_string.
As I researched, I have found out that it is caused by the standard library bundled with GCC. After iostream is included some static objects are instantiated, even though they are not used at all.
In this post it is explained that the STL from ARM Toolchain is used. Do you know whether the use of the lld or the -Oz flag resolves the problem related to too big size of the binary?
When I try even a simple program, which had main() and used std::ostringstream to stringify some numbers, and was compiled for a ARM Cortex M CPU (with e.g. 256 kB of Flash), the Flash area was overflown.
Thanks for the post, really interesting. I gave this a try (had to make some tweaks to my CMake builds first) but canât seem to get it to work properly.
I get a bunch of errors similar to this:
In file included from /Users/kamil/xxxxx/../Drivers/CMSIS/CMSIS/Include/cmsis_compiler.h:48:
/Users/kamil/xxx/../Drivers/CMSIS/CMSIS/Include/cmsis_gcc.h:868:19: error: invalid instruction mnemonic 'isb'
__ASM volatile ("isb 0xF":::"memory");
^
<inline asm>:1:2: note: instantiated into assembly here
isb 0xF
^~~
In any parts of the code that are trying to compile the hardware drivers (from ST in this case)
Glad to hear you enjoyed the article! The error you hit above suggests you may not be targeting the right architecture. What CFLAGs are you using? (For example, if you are compiling for a cortex M4, you want to make sure you have something like -mthumb-mcpu=cortex-m4).
Ah, looks like you are missing --target=arm-none-eabi to tell clang to cross-compile which will result in those warnings and the assembly one you are seeing.
Hey @KKoovalsky, youâre right that using the STL on embedded in general is tricky. I donât use C++ much myself, but Phillip at Embedded Artistry does and writes about it. Check out his article about the Embedded Templates Library: https://embeddedartistry.com/blog/2018/12/13/embedded-template-library/. It might be what youâre looking for!
Another great post at Interrupt, thank you @chrisc! This is the first time I am reading about ownership_returns and ownership_takes and it looks like some powerful tool beyond malloc-like functions (especially in combination with ownership_holds).
I failed to find real-world examples on Github. Are you aware of any non-trivial examples I could learn from?
Unfortunately I have not found any examples either. I think today itâs really only used within the llvm-project for the unix MallocChecker but agree there seems like a lot of potential for other types of passes with the annotation in general!
Something Iâd like to try is implementing a custom plugin that uses the ownership_ type attribute.
Great article! The majority of my companyâs firmware (with the exception of PIC-based systems) is developed & shipped with clang; when we switched 5-6 years ago the primary motivation was the superior quality of its diagnostic messages compared to GCC. I understand GCCâs output has improved drastically since then, but we havenât had any practical reasons to reconsider that decision. Weâre currently building with c++17 and Iâm hoping to get clang 10 up and running soon so we can take advantage of some c++20 features.
I think clang-tidy also belongs in this conversation: it includes the static analyzer checks performed by scan-build, and additionally can perform a whole raft of checks against various coding & style guidelines including the C++ core guidelines. Running it is a little bit more involved than scan-build as it works best with a compile_commands database and introducing it to an existing codebase can be a big task, but itâs got some great checks: https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/list.html
Welcome to Interrupt @gdharris! Exciting to hear from more folks using clang on embedded. We had evaluated clang 5-6 years ago, but we found that it wasnât quite as good at optimizing for code size then. Was that a concern for your use case?
Thank you for bringing up clang-tidy. I have not had the change to try it, but I will. If youâre ever inspired to write a short post about it, weâd love to publish it :-).
Hi I follow your posts regularly. I am interested in converting some of my gcc projects to clang. This article is a great starting point. However, I am stuck early on in the scan-build step. I am getting the following errors: ~/.../example/freertos-example-llvm >>> scan-build make scan-build: Using '/usr/bin/clang-10' for static analysis /usr/bin/../lib/clang/ccc-analyzer ===GCC Compiler Detected=== Compiling src/builtin_scanbuild_examples.c gcc: warning: â-mcpu=â is deprecated; use â-mtune=â or â-march=â instead gcc: error: unrecognized command line option â-mthumbâ gcc: error: unrecognized command line option â-mfloat-abi=hardâ gcc: error: unrecognized command line option â-mfpu=fpv4-sp-d16â make: *** [Makefile:167: /home/rajah/workspace/interrupt/example/freertos-example- llvm/build/src/builtin_scanbuild_examples.o] Error 1 scan-build: Removing directory '/tmp/scan-build-2020-05-28-170744-12711-1' because it contains no reports. scan-build: No bugs found. ~/.../example/freertos-example-llvm >>>
I have installed clang 10 on arch and I also have arm-none-eabi-gcc installed. What am I missing? Thanks in advance for any pointers.
Under the hood scan-build works by searching for a compiler to use, overriding CC in the makefile, and then running a static analysis pass with Clang. In your case it looks like it found the wrong compiler (âgccâ instead of âarm-none-eabi-gccâ or âclangâ) which is why you are seeing the error.
Can you try using the --use-cc argument with scan-build to tell it the compiler to exact compiler to use instead: i.e scan-build --use-cc=<path_to_clang>/clang make?
Thanks for the question, Iâll add a note to the article about it!
Hi Chris,
Thank you very much for the prompt response!!
I was able to get it working (mostly) with the -use-cc switch. After compile, I got a linker error.
Compiling freertos_kernel/portable/GCC/ARM_CM4F/port.c Compiling freertos_kernel/portable/MemMang/heap_1.c Linking library clang-10: error: unable to execute command: Executable "ld.lld" doesn't exist! clang-10: error: ld.lld command failed with exit code 1 (use -v to see invocation)
I got around this error by installing the the linker package (lld on arch). Once I installed this, I got a library related error:
Compiling freertos_kernel/portable/MemMang/heap_1.c Linking library ld.lld: error: unable to find library -lgcc clang-10: error: ld.lld command failed with exit code 1 (use -v to see invocation) make: *** [Makefile:148: /home/rajah/workspace/interrupt/example/freertos-example-``llvm/build/nrf52.elf] Error 1
When I just run make instead of scan-build make, an elf output is generated. However, even with this error, I can still run scan-view as all the errors have been captured as part of the compile process. I am very impressed with how the errors are presented. I will continue with rest of the blog post as scan-build is working now. Any idea why scan-build its not able to find the gcc library?
This is a very interesting post. I have tried to get scan-build to run in the past without success⌠Thatâs still the case, but I think I got a lot closer today.
Have you had any success running this on Windows? I can get LLVM installed no problem and scan-build runs, but fails at various points. The closest I got was specifying the analyzer, target, and compiler, but it still failed due to what appears to be a space in the path of ccc-analyzer⌠Anyway, has anyone run this on Windows with success? My makefile runs no problem.