# CPP project setup
## static analyer
我看到一個 cppcon,我和它只差在 clang-tidy,其他 sanitizer, clang-format... 都是有的。
[Can C++ be 10x Simpler & Safer? - Herb Sutter - CppCon 2022 ](https://www.youtube.com/watch?v=ELeZAKCN4tY)
重點不是用 cppfront,而是講者發現 cpp 有什麼 1.不必要 2.error prone 的東西,透過語法直接**禁止**去使用。我們可以把這些東西加入static analyer 達到一樣的效果。
有兩種大方向的用法 1. integrate with cmake, CI/CD, forbid compile warning code 2. 和 IDE 整合,improve coder develop experience。
~~我認為先導入 option2 會有幫助一點。一來不會影響 compile time,二來比較像鼓勵,試試水溫。目前 vscode 下,可靠的方法基本只有 clangd。~~
先用 clang-tidy CI 比較好一點,vscode已經現有 C++ intellisense。clang-tidy CLI 更像是optional,而非強制。
[開發Ray的VSCode Clangd 設置 - You-Cheng Lin](https://owen-lin.medium.com/%E7%B5%A6%E9%96%8B%E7%99%BCray%E7%9A%84-vscode-clangd-%E8%A8%AD%E7%BD%AE-cda47a15a3e5)
## static polymorphism
[ Cost of C++ Abstractions in C++ Embedded Systems - Marcell Juhasz - CppCon 2024 ](https://www.youtube.com/watch?v=7gz98K_hCEM)
static polymorphism 對 MCU 和 一些 compile time checking 應該有巨大的作用。但是大量使用應該要等 modules 導入。
## cpp modules enable
with conan
[A short tour of C++ modules](https://www.kgmw.ch/posts/cpp-modules-intro/#history) contain require tool version
[C++ Modules: The Packaging Story](https://blog.conan.io/2023/10/17/modules-the-packaging-story.html)
```bash
conan install . --build=missing --profile:host=clang_debug --profile:build=clang_debug
source build/Debug/generators/conanbuild.sh
cmake -B build/Debug/ -S . -DCMAKE_TOOLCHAIN_FILE=build/Debug/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -G Ninja
cmake --build build/Debug/
```
conan 目前的 recipe 都是沒開 module 的,所以
[C++ Modules: The Packaging Story](https://blog.conan.io/2023/10/17/modules-the-packaging-story.html) 才需要自己寫recipe `tc.cache_variables["FMT_MODULE"] = "ON"`
這表示 modules 可能只能自己用,這樣很難判斷 modules 到底有多少效益,因為 these lib 的 code base 大很多。
[ {fmt} 11.0 released with improved build speed, C++20 module support, faster print and more ](https://www.reddit.com/r/cpp/comments/1dssm2s/fmt_110_released_with_improved_build_speed_c20/), compile time get 4x boost, really huge.
#### migrate
> gcc 要等到 gcc15 才有完整的 support
module 要 改檔名,hpp --> cppm。是 large migration
cpp23 才有 stl module。migrate 會順利一點。
## todo
1. 先用 c++20 without moudle
2. 導入 clang-tidy ~~with clangd~~ CI
3. implement under module
## conan
### profiles
#### clang(under linux)
```bash
# may need different libstdc++-{}-dev version
sudo apt-get install libstdc++-dev
# install clang, following is v19
wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- 19
# install clang-tools for e.g. clang-scan-deps
sudo apt install clang-tools-19
```
`clang-scan-deps` is necessary for c++20 moudle.
```ini
[settings]
arch=x86_64
build_type=Debug
compiler=clang
compiler.cppstd=20
compiler.libcxx=libstdc++11
compiler.version=19
os=Linux
#[options]
#*:shared=True
[buildenv]
CC=/usr/lib/llvm-19/bin/clang
CXX=/usr/lib/llvm-19/bin/clang++
# for sys installed lib
LIBRARY_PATH=/home/morgana/tx7_out/igh_5.10.21-rt34_build/lib
[conf]
tools.system.package_manager:sudo=True
tools.system.package_manager:mode=install
tools.build:cflags+=['-Wall','-fcolor-diagnostics']
tools.build:cxxflags+=['-Wall','-fcolor-diagnostics']
#tools.build:exelinkflags+=['-fuse-ld=mold']
#tools.build:sharedlinkflags+=['-fuse-ld=mold']
# for sys installed lib
tools.build:exelinkflags+=["-L/usr/local/lib"]
tools.build:compiler_executables={"cpp": "clang++-19", "c": "clang-19", "rc": "clang-19"}
*:tools.cmake.cmaketoolchain:generator=Ninja
```
> LIBRARY_PATH=/usr/lib/llvm-19/lib
#/usr/local/lib
##### ~~with libc++~~
clang defautl 是配 libc++, gcc 配 libstdc++11。上面配libstdc++11 是因為 default linux 是沒有 libc++ 的。
其實在 linux 下不建議用,很容易找不到 .so, header...。
> **以下尚未成功,勿使用。**
```bash
sudo apt install libc++-dev libc++abi-dev
```
```ini
[settings]
arch=x86_64
build_type=Debug
compiler=clang
compiler.cppstd=20
compiler.libcxx=libc++
compiler.version=19
os=Linux
#[options]
#*:shared=True
[buildenv]
CC=/usr/lib/llvm-19/bin/clang
CXX=/usr/lib/llvm-19/bin/clang++
# CMAKE_PREFIX_PATH=/usr/lib/llvm-19
[conf]
tools.system.package_manager:sudo=True
tools.system.package_manager:mode=install
tools.build:cflags+=['-Wall','-fcolor-diagnostics']
tools.build:cxxflags+=['-Wall','-fcolor-diagnostics']
# '-stdlib=libc++'
#tools.build:exelinkflags+=['-fuse-ld=mold']
#tools.build:sharedlinkflags+=['-fuse-ld=mold']
# for sys installed lib
tools.build:exelinkflags+=["-L/usr/local/lib"]
# "-lc++abi"
tools.build:compiler_executables={"cpp": "clang++-19", "c": "clang-19", "rc": "clang-19"}
*:tools.cmake.cmaketoolchain:generator=Ninja
```
#### cross compile
take arm32 for example, with separate builded lib
```ini
[settings]
os=Linux
arch=armv7hf
compiler=gcc
compiler.cppstd=20
compiler.libcxx=libstdc++11
compiler.version=12.3
build_type=Release
[buildenv]
CC=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-gcc
CXX=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-g++
LD=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-ld
AR=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-ar
AS=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-as
NM=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-nm
GDB=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-gdb
STRIP=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-strip
RANLIB=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-ranlib
OBJCOPY=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-objcopy
OBJDUMP=/home/morgana/arm-tx7-linux-gnueabihf/bin/arm-tx7-linux-gnueabihf-objdump
LIBTOOL=/home/morgana/arm-tx7-linux-gnueabihf/bin/libtool
#CMAKE_PREFIX_PATH=/home/morgana/tx7_out/igh_5.10.21-rt34_build #this only set env variable rather than config cmake variable
[conf]
tools.build:sysroot=/home/morgana/arm-tx7-linux-gnueabihf/arm-tx7-linux-gnueabihf/sysroot
#tools.build:exelinkflags=['-fuse-ld=gold']
#tools.build:sharedlinkflags=['-fuse-ld=gold']
tools.build:exelinkflags+=["-L/home/morgana/tx7_out/igh_5.10.21-rt34_build/lib"]
tools.cmake.cmaketoolchain:user_toolchain=["/home/morgana/.conan2/profiles/tx7_external_paths.cmake"]
#[replace_requires]
#[platform_requires]
#[platform_tool_requires]
#cmake/3.24.2
*:tools.cmake.cmaketoolchain:generator=Ninja
*:tools.build:verbosity=verbose
*:tools.compilation:verbosity=verbose
[options]
#capehand/*:with_igh=True
#resymot/*:with_igh=True
```
```cmake
#tx7_external_paths.cmake
list(APPEND CMAKE_PREFIX_PATH "/home/morgana/tx7_out/igh_5.10.21-rt34_build")
message(STATUS "Conan User Toolchain: Appended /home/morgana/tx7_out/igh_5.10.21-rt34_build to CMAKE_PREFIX_PATH.")
```
## unittest
run for foreign architecture is the most difficult part
### docker as runner
newest ubuntu will give you new glibc version
```bash
docker run --rm --platform linux/arm/v7 -v $(pwd):/$(pwd) -t ubuntu:24.04 bash -c "cd $(pwd) && apt update && apt install cmake -y && ctest"
```
build your own runner image
```dockerfile
# Dockerfile
# syntax=docker/dockerfile:1.4
# This line is important for BuildKit features like --platform in FROM
# Use a build argument for the target platform.
# BUILDPLATFORM is a special BuildKit variable that resolves to the platform
# of the builder itself (e.g., linux/amd64 if you're building on an AMD64 machine).
# We use it here to ensure the base image is pulled for the correct architecture
# that the build process is running on, even if the final target is different.
FROM --platform=$BUILDPLATFORM ubuntu:24.04
# Set environment variables for non-interactive apt installations
ENV DEBIAN_FRONTEND=noninteractive
# Update package lists and install CMake
# This also cleans up apt lists to keep the image size down
# The 'cmake' package will be installed for the architecture of the base image.
RUN apt update && \
apt install -y cmake && \
rm -rf /var/lib/apt/lists/*
# Set a default working directory. Your host path will be mounted into this.
WORKDIR /usr/src/app
# No CMD or ENTRYPOINT specified, making it a general-purpose image.
# You will specify the command when you run the container.
```
```bash
docker build --platform linux/arm/v7 -t my-arm32-dev-image:latest .
docker run --rm --platform linux/arm/v7 -v $(pwd):$(pwd) -t my-arm32-dev-image:latest bash -c "cd $(pwd) && ctest"
```
encourage compile whole program in static build, or you may have to mount, find and link your shared libs in container
```bash
clear && conan build . */*:shared=False -pr armv7x_debug --build=missing
```
other arch
```bash
docker buildx build --platform linux/arm64 -t my-dev-image:arm64v8 --load .
```