Skip to content

Repository files navigation

CMake C++ Project Template

This template is designed for organizing cross-platform C++ projects, aimed at solving the main issues of maintaining a clean project structure and convenient work using VSCode and MS VisualStudio.

Benefits and features

  • Based on CMakePresets.json.
  • The default release build now includes minimal debug info, that is useful for backtracing.
    • RelWithDebInfo renamed to Release and cofigured, Release renamed to RelNoDebInfo.
  • Target binaries are placed separately from all other build artifacts.
    • build/arch_type_platform/
  • CMake cache and other build artifacts are placed into separate directories to minimize rebuilding when the build type changes.
    • build/.cmake/arch_type_platform/
  • A single shared working directory to minimize duplication of runtime resources.
    • workdir/
  • add_metainfo that allows adding icon, version, and other information to binary files in different ways at the same time:
    • Universal: generated source code {application}.metainfo.h & c:

      Example
      add_metainfo(${PROJECT_NAME}VERSION1.2.3.4-alpha5DESCRIPTION"Application Template"PRODUCT"CMake C++ Template"COMPANY"HOME Co."COPYRIGHT"© 2007-2024 HOME Co. All rights reserved."ICON"icon"
      )
      constchar*application_Architecture(); // "x64"constchar*application_CxxStandard(); // "C++20"constchar*application_CompilerName(); // "GCC"constchar*application_CompilerVersion(); // "12.3.0"constchar*application_Description(); // "Application Template"constchar*application_Product(); // "CMake C++ Template"constchar*application_Company(); // "HOME Co."constchar*application_Copyright(); // "© 2007-2026 HOME Co. All rights reserved."constchar*application_Version(); // "1.2.3.4-alpha5"uint16_tapplication_VersionMajor(); // 1uint16_tapplication_VersionMinor(); // 2uint16_tapplication_VersionPatch(); // 3uint16_tapplication_VersionBuild(); // 4constchar*application_VersionQualifier(); // "alpha5"uint32_tapplication_VersionU32(); // if it fits into 4 bytesuint64_tapplication_VersionU64(); // if it fits into 8 bytes
      add_metainfo(${PROJECT_NAME}VERSION3333-pre-release
      )
      constchar*application_Architecture(); // "x64"constchar*application_CxxStandard(); // "C++20"constchar*application_CompilerName(); // "GCC"constchar*application_CompilerVersion(); // "12.3.0"constchar*application_Description(); // ""constchar*application_Product(); // ""constchar*application_Company(); // ""constchar*application_Copyright(); // ""constchar*application_Version(); // "3333-pre-release"uint16_tapplication_VersionMajor(); // 3333uint16_tapplication_VersionMinor(); // 0uint16_tapplication_VersionPatch(); // 0uint16_tapplication_VersionBuild(); // 0constchar*application_VersionQualifier(); // "pre-release"uint64_tapplication_VersionU64(); // 0x0D05'0000'0000'0000
    • Universal: embedded strings in non-strict according to SCCS.

    • Platform-specific: Windows-resource .rc, ELF-sections, MacOS-resource TODO:Info.plist.

      Examples of working with SCCS and ELF-sections
      $ grep --binary-files=text "@(#)" application
      @(#) Version: v1.2.3.4-alpha5 x64 C++20 GCC.12.3.0@(#) Description: Application Template@(#) Product Name: CMake C++ Template@(#) Company Name: HOME Co.@(#) Copyright: © 2007-2024 HOME Co. All rights reserved.
      $ grep --binary-files=text "\$Id:" application
      $Id: v1.2.3.4-alpha5 x64 C++20 GCC.12.3.0; Application Template; CMake C++ Template; HOME Co.; © 2007-2024 HOME Co. All rights reserved. $
      $ readelf -p .note.version -p .note.description -p .note.product -p .note.company -p .note.copyright application
      String dump of section '.note.version':
      [ c] 1.2.3.4-alpha5
      [ 1b] 1.2.3.4-alpha5 x64 C++20 GCC.12.3.0
      String dump of section '.note.description':
      [ c] description
      [ 18] Application Template
      String dump of section '.note.product':
      [ c] product
      [ 14] CMake C++ Template
      String dump of section '.note.company':
      [ c] company
      [ 14] HOME Co.
      String dump of section '.note.copyright':
      [ 4] +
      [ c] copyright
      [ 18] 2007-2024 HOME Co. All rights reserved.
      $ readelf -n application
      Displaying notes found in: .note.version
      Owner Data size Description
      1.2.3.4-alpha5 0x00000013 NT_VERSION (version)
      description data: 2e 32 2e 33 2e 34 2d 61 6c 70 68 61 35 20 78 36 34 00 00
      Displaying notes found in: .note.description
      Owner Data size Description
      description 0x00000015 NT_VERSION (version)
      description data: 41 70 70 6c 69 63 61 74 69 6f 6e 20 54 65 6d 70 6c 61 74 65 00
      Displaying notes found in: .note.product
      Owner Data size Description
      product 0x00000013 NT_VERSION (version)
      description data: 43 4d 61 6b 65 20 43 2b 2b 20 54 65 6d 70 6c 61 74 65 00
      Displaying notes found in: .note.company
      Owner Data size Description
      company 0x00000009 NT_VERSION (version)
      description data: 48 4f 4d 45 20 43 6f 2e 00
      Displaying notes found in: .note.copyright
      Owner Data size Description
      copyright 0x0000002b NT_VERSION (version)
      description data: 20 32 30 30 37 2d 32 30 32 36 20 48 4f 4d 45 20 43 6f 2e 20 41 6c 6c 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 64 2e 00 00 00
      $ readelf -p .sccsid application
      String dump of section '.sccsid':
      [ 2] @(#) Version: v1.2.3.4-alpha5 x64 C++20 GCC.12.3.0\n@(#) Description: Application Template\n@(#) Product Name: CMake C++ Template\n@(#) Company Name: HOME Co.\n@(#) Copyright: � 2007-2024 HOME Co. All rights reserved.\n$Id: v1.2.3.4-alpha5 x64 C++20 GCC.12.3.0; Application Template; CMake C++ Template; HOME Co.; � 2007-2024 HOME Co. All rights reserved. $\n
  • add_option as a better variant of set(...CACHE...) that has the next features:
    • More simple and intuitive interface.
    • 5 data types with some strict rules.
    • All the options have OPTION_ prefix that simplifies working with CMakeCache when you have only a text editor.
    • All the options are automatically defined as macros for desired targets.
  • Git utilities.
    • fetch_git as a better variant of FetchContent_... that is useful for additional projects such as examples or tests (for main projects use classic git submodules or package managers) and has the next features:
      • More simple and intuitive interface.
      • Better work speed.
      • Aimed to work as classic git submodules.
    • git_commits_count_by_regex & git_commits_count_by_tag.
  • Qt5 support.
    • Autosearch (simple) for Qt5 libraries if Qt5_DIR is not specified.
    • Custom qt5_create_ts_and_qm(...) that minimizes calls of lrelease if lupdate returns zero changes.
  • MS Visual Studio support.
  • VSCode support.
    • Lots of tweaks in .vscode/settings.json.

Steps terminology

StepParticipants
1preparegit, etc
2configurecmake, git
3compilecompilers, cmake
4runapplications

TODO

Clang, TODO

Multiprocessor compilation

ToolCompilerPlatformParameter
VSCodeGCCLinux.vscode/settings.json: "cmake.parallelJobs": N
VSCodeClangLinuxTODO
VSCodeMSVCWindowsTODO
VSCodeClangWindowsTODO
MSVSMSVCWindowsCMakeUtils.cmake: target_compile_options /MP
MSVSClangWindowsTODO
cmakeGCCLinuxmake -jN, ninja -jN
cmakeClangLinuxmake -jN, ninja -jN

Program's arguments

ToolPlatformParameter
VSCodeLinux.vscode/settings.json: "args": []
MSVSWindowsinit_project("client --ip=localhost" "server")
VSCodeWindowsTODO

NOTE: VSCode: workdir can't be configured when running target without debugging

Cross-compilation with Docker

  1. Prepare a copy of target sysroot. For example:
rsync -az --progress login@ip:/etc sysroot
rsync -az --progress login@ip:/lib sysroot
rsync -az --progress login@ip:/usr/include sysroot/usr
rsync -az --progress login@ip:/usr/lib/aarch64-linux-gnu sysroot/usr/lib
rsync -az --progress login@ip:/usr/lib/qt5 sysroot/usr/lib
rm -rf sysroot/usr/lib/aarch64-linux-gnu/dri
https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py sysroot
tar cf - sysroot -P | gzip > sysroot.tar.gz
  1. Example of a Dockerfile:
# GCC 10.5, GCC 12.3, CMake 3.22FROM ubuntu:22.04
# GCC 10.5, GCC 13, CMake 3.25#FROM ubuntu:23.04RUN mkdir /sysroot
ADD sysroot.tar.gz /
# Optional, for dumping debug symbolsADD --chmod=755 breakpad_dump_syms /usr/local/bin/
RUN apt update \
&& apt -y install --no-install-recommends \
cmake \
xz-utils \
wget \
ninja-build \
git \
ssh \
sshpass \
pkg-config \
libudev-dev \
build-essential \
binutils-aarch64-linux-gnu \
gcc-12-aarch64-linux-gnu \
g++-12-aarch64-linux-gnu \
g++-12 \
qtbase5-dev \
&& apt clean \
&& rm -rf /var/lib/apt/lists/* \
&& mv /sysroot/usr/lib/aarch64-linux-gnu/qt5/bin/ \
/sysroot/usr/lib/aarch64-linux-gnu/qt5/bin.arm/ \
&& cp -RL /usr/lib/x86_64-linux-gnu/qt5/bin/ \
/sysroot/usr/lib/aarch64-linux-gnu/qt5/ \
&& mv /sysroot/usr/lib/qt5/bin/ \
/sysroot/usr/lib/qt5/bin.arm/ \
&& cp -RL /usr/lib/x86_64-linux-gnu/qt5/bin/ \
/sysroot/usr/lib/qt5/bin/ \
\
&& git config --global http.sslverify false \
&& git config --global --add safe.directory "*" \
\
# https://github.com/rui314/mold/blob/main/dist.sh
&& git clone --branch v2.4.0 --filter=tree:0 --recurse-submodules https://github.com/rui314/mold.git /mold \
&& cd /mold \
&& cmake -DCMAKE_BUILD_TYPE=Release -DMOLD_MOSTLY_STATIC=On . \
&& cmake --build . -j$(nproc) \
&& cmake --install . --strip \
&& rm -rf /mold \
&& ln -s /usr/local/bin/mold /usr/bin/aarch64-linux-gnu-ld.mold \
\
&& apt -y purge g++-12
RUN echo "#!/usr/bin/bash\n\cmake \$@ \-DCMAKE_CXX_COMPILER_ARCHITECTURE_ID=aarch64 \-DCMAKE_CXX_COMPILER=/bin/aarch64-linux-gnu-g++-12 \-DCMAKE_C_COMPILER=/bin/aarch64-linux-gnu-gcc-12 \-DCMAKE_STRIP=/bin/aarch64-linux-gnu-strip \-DCMAKE_SYSROOT=/sysroot \-DQt5_DIR=/sysroot/usr/lib/aarch64-linux-gnu/cmake/Qt5 \-DBREAKPAD_DUMP_SYMS=/usr/local/bin/breakpad_dump_syms \-DCMAKE_BUILD_RPATH=\"\/sysroot/usr/lib;\/sysroot/lib/aarch64-linux-gnu;\/sysroot/usr/lib/aarch64-linux-gnu\\"" \
> /usr/bin/crosscmake.sh \
&& chmod +x /usr/bin/crosscmake.sh
  1. Run crosscmake.sh in build/.cmake/{configuration} on the root of your project:
fromntpathimportjoinimportos, sysargs="../../.. "iflen(sys.argv) >1:
args+=" ".join(sys.argv[1:])
os.system("docker run"" --rm"" -v "+os.getcwd() +":/project"" -w /project/build/.cmake/arm64-Release-Linux"" my_docker_image_crosscompiler:latest"" /usr/bin/crosscmake.sh -G Ninja -DBUILD_ARCH=arm64 "+args)
  1. Build:
importosos.system("docker run"" --rm"" -t"" -v "+os.getcwd() +":/project"" -w /project/build/.cmake/arm64-Release-Linux"" my_docker_image_crosscompiler:latest"" ninja")

About

Linux: VSCode; Windows: MSVS, VSCode(TODO)

Topics

Resources

Stars

7 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages