---
# System prepended metadata

title: CPP project setup
tags: [c++, compile]

---

# 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 .
```
