title: Building and Packaging Modern C++ class: wrapper layout: true --- class: wrapper, center, middle # {{title}} --- class: wrapper, center, middle # Piotr Gaczkowski ![DoomHammer](img/doomhammer.jpg)
|
[@doomhammerng](https://twitter.com/doomhammerng)
--- class: wrapper, center, middle # Adrian Ostrowski
|
[@adr_ostrowski](https://twitter.com/adr_ostrowski)
--- background-image: url(img/samuel-regan-asante-g9A2llpDObU-unsplash.jpg) --- class: wrapper, center, middle # Speeding up Builds --- class: wrapper, center, middle # CCache https://ccache.dev/ ??? In essence: compiler cache --- # CCache - features - much faster recompilation ??? - supports C, C++, Objective-C, Objective-C++, CUDA & assembly -- - compression -- - statistics ??? - low overhead - checksums for correctness since 4.0 -- - silent fallback in unsupported cases -- - easy integration -- - support for C++20's modules ??? - modules - doc mentions Clang only; require settings a few options --- # CCache - supported environment - works on Linux and macOS, other Unixes, and Windows - supports GCC, Clang and NVCC - MSVC support underway (PR [#506](https://github.com/ccache/ccache/pull/506)) --- exclude: true # CCache - usage ``` ccache [flag] ccache [[compiler] [flags ...]] compiler [flags ...] ``` ??? First: for managing ccache itself, e.g. stats 2 & 3: for compiling -- exclude: true or via build systems --- # CCache - installation - Windows: - just use binaries from GitHub - Others: - system package manager - usually not the latest version - `brew install ccache` - build from sources (CMake) --- class: wrapper, center, middle # Intermission: Brew ![Homebrew](img/homebrew-256x256.png) https://brew.sh/ ??? Package manager for macOS and Linux Why use it? - all files installed in one subtree - clean removal if needed - plethora of packages in recent versions - Snap has old and unofficial CCache (3.7 vs brew's 4.2) Scoop for Windows Python has C++ software too, e. g. CMake (`pip install cmake`) --- # CCache - usage - invoke manually ``` ccache
``` -- - invoke via symbolic links masquerading the compilers ??? masqerading: we'll show that in a sec -- - integrate with build systems --- # CCache - masquerading compilers To ensure CCache is used by default: -- 1. Run: ``` cp ccache /usr/local/bin/ ln -s ccache /usr/local/bin/gcc ln -s ccache /usr/local/bin/g++ ln -s ccache /usr/local/bin/cc ln -s ccache /usr/local/bin/c++ ``` ??? When invoked, ccache deduces orig. compiler from $0 -- 2. Put `/usr/local/bin` early in `PATH` --- # CCache - configuration - many environment variables - corresponding settings in `ccache.conf` ??? In most cases defaults work well. --- # CCache - configuration, cont'd - cache size and location - behavior: `sloppiness`, preprocessing, etc. - compiler specific, e. g. `prefix_command` - read only mode - debugging and logging ??? Cache size - one thing worth increasing. Sloppiness: - pretty strict by default -> less false hits - allows to use ctimes/mtimes instead of file contents - needed for modules and precompiled headers --- # CCache - integrating with CMake Available since CMake 3.4 -- ``` -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ``` -- ``` find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") endif() ``` ??? RULE_LAUNCH_LINK - no use, CCache doesn't support linking --- # CCache - sharing cache - possible on same machine and using a network storage -- - for locations afar, consider providing their own caches -- - users need to be in same group -- - in config, provide: ``` cache_size = 100G base_dir = /home/current/user/ cache_dir = /network/storage/path hash_dir = false temporary_dir = /some/local/dir/like/tmp umask = 002 ``` ??? - `base_dir` - allows different users to share cache - `hash_dir` - paths in debug symbols - `temporary_dir` - faster + helps avoid some bugs - To share between OS-es: set `sloppiness` to `system_headers` --- # How much does it help? A lot! Personal experience: builds shorter by up to 95% --- # How much does it help - cont'd ![Benchmark](img/ccache.png) ??? - Preprocessor - first run preprocessor, then hash results - Direct - hash source file and include files directly. If miss, goto preprocessor. - Depend - like direct, but doesn't goto preproc. on miss. - depends on compiler's `-MD` or `-MMD` - Great for dist. builds (reduce local overhead) --- class: wrapper, center, middle # What else a developer needs? --- background-image: url(img/lama-roscu-Wpg3Qm0zaGk-unsplash.jpg) --- class: wrapper, center, middle # Icecream https://github.com/icecc/icecream ??? fork of distcc - with a central server that chooses fastest free server --- # Icecream - features - scheduler -- - only uses free resources on machines -- - allows good perf on heterogeneous environments -- - allows some machines to be off during compilation -- - remote cross compiling ??? Automatically sends toolchain to remote -- - monitoring --- exclude: true # Monitoring - Icemon https://github.com/icecc/icemon --- # Monitoring - Sundae https://github.com/JPEWdev/icecream-sundae
--- # Monitoring - Sundae - cont'd ![Sundae](img/icecream_sundae_demo.png) ??? % - local job = - remote job --- # Icecream - supported environments - Linux - macOS - FreeBSD - Cygwin No native Windows :( --- background-image: url(img/icecream.jpg) --- # Icecream - installation - developers recommend using distro's package - `sudo apt install icecc` - `sudo apt install icecc-scheduler` - `sudo apt install icecream-sundae` ??? - `icecc` has client and daemon (both required for remote builds) - scheduler - on one host only (two possible, automatic fallback) - sundae - optional --- # Icecream - configuration - firewall - TCP: 10245, 8765, 8766 - UDP: 8765 - other defaults should work fine - persistent connections: - `--scheduler-host` for daemon - `--persistent-client-connection` for scheduler ??? icecc must be in your path - that's all. Network should be fast. Avoid far away nodes. Scheduler should have dedicated resources - sensitive to latency. --- # Icecream - configuration, cont'd To ensure Icecream is always used by default, put ``` /usr/lib/icecc/bin ``` early in your `PATH`. --- # Icecream - integrating with CMake ``` find_program(ICECC_PROGRAM icecc) if(ICECC_PROGRAM) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${ICECC_PROGRAM}") endif() ``` --- # Combining CCache and Icecream - Your `ccache.conf` file must contain: ``` prefix_command=icecc ``` -- - CCache should come before IceCC in `PATH` --- # How much does it help? ![Firefox with IceCC](img/icecc_firefox.png) ??? - Many cases show at least 20% faster builds - More responsive local machine https://bugzilla.mozilla.org/show_bug.cgi?id=927952 --- class: wrapper, center, middle # Noteworthy alternatives --- # IncrediBuild - distributed building for Windows and Linux - commercial https://www.incredibuild.com/ --- # `sccache` - Mozilla's `ccache`-like compiler cache - built-in `icecream`-style distributed compilation - supports C, C++, Rust, and NVCC - on Windows, Linux and macOS Not production ready yet (current version: 0.2.15) https://github.com/mozilla/sccache --- exclude: true # Bazel https://bazel.build/ --- exclude: true # C++20's Modules TODO --- background-image: url(img/switch.jpg) --- class: twitter # Portable build environments -- How to make sure everyone's playing the same toys? --- class: twitter # VMs -- - All the software preinstalled -- - Easy distribution -- - May be less than pleasant to use --- class: twitter # Containers? -- - Oooh, shiny! -- - Slicker than VMs! -- - Application containers and toolchains don't match --- class: twitter # What else? --- class: twitter # Nix features - Operates in userland - Deterministic packages and environments - Atomic upgrades - Rollbacks - Build environment management - Multiple versions of packages side-by-side on a single system - Runs on Linux and macOS --- class: twitter # Functional approach - Installing or upgrading package won't break other packages - Every package is installed in a separate directory - It allows easy rollback - Prevents inconsistent state --- class: twitter # Good for multi-user environments - Several users can install packages without superuser privileges - Different users can have different package versions --- class: twitter # Projects with direnv Uses `nix-shell`. Automatically sets up development environment whenever you enter a directory. You can pin the packages version. --- .envrc ```bash use_nix . env/bin/activate ``` default.nix ```nix { pkgs ? import
{} }: with pkgs; let gcc = gcc10; in mkShell { buildInputs = [ cmake ccache gcc git gnumake icecream ]; } ``` --- class: twitter # How Does it Compare to The Rest? - Still not as easy as Homebrew - GNU Guix using GNU Scheme (LISP) - ... if you love parentheses, you'll love GUIX! - ... also works with direnv! --- class: twitter # Managing Git hooks -- - There's an app for that! -- - pre-commit --- class: twitter # pre-commit ``` repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.5.0 hooks: - id: check-added-large-files - id: check-byte-order-marker - id: check-case-conflict - id: check-merge-conflict - id: mixed-line-ending - id: no-commit-to-branch args: [--branch, master] - id: trailing-whitespace ``` --- class: twitter # pre-commit ``` #[...] - repo: https://github.com/pocc/pre-commit-hooks rev: v1.1.0 hooks: - id: clang-format args: [--style=Google, -i] exclude: 3rd-parties/ - repo: https://github.com/iconmaster5326/cmake-format-pre-commit-hook rev: v0.6.9 hooks: - id: cmake-format exclude: 3rd-parties/ ``` --- class: twitter # Packaging --- class: twitter # Conan -- - Package manager for C++ -- - Written in Python -- - like pip/npm/gem but with full toolchain support -- - uses binaries when possible --- class: twitter # Conan profile ``` [settings] os=Linux os_build=Linux arch=x86_64 arch_build=x86_64 compiler=gcc compiler.version=9 compiler.libcxx=libstdc++11 build_type=Release [options] [build_requires] [env] ``` --- class: twitter # Conanfile ``` [requires] flac/1.3.3 spdlog/[>=1.4.1] [generators] cmake [imports] bin, *.dll -> ./bin lib, *.dylib* -> ./bin ``` --- class: twitter # CMakeLists.txt ``` #[...] conan_basic_setup(TARGETS) #[...] target_link_libraries( songcorder #[...] ${CONAN_LIBS} #[...] ) ``` --- class: twitter # CPack -- - Generates sources and binary packages -- - Could spit out NSIS installers and macOS dmg archives -- - Produces Deb and RPM on supported platforms --- class: twitter # AppImage / Flatpack - The new way to package portable Linux apps ---
--- class: center, middle, split50 # Hungry for more? .left-pane[
] .right-pane[ .left[ Our brand new book is coming out! Featuring: - More on building and packaging - Designing quality software - Leveraging C++20 features - Microservices and cloud-native C++ Available from March 12th on [Packt](https://www.packtpub.com/product/software-architecture-with-c/9781838554590) And from April 9th on Amazon ] ] --- # Questions? --- class: center, middle, split50 # Thank you! .left-pane[ ![DoomHammer](img/doomhammer.jpg)
] .right-pane[
] ###
--- # Attributions - _Building Site_ photo by
Samuel Regan-Asante
on
Unsplash
- _Icecream rainbow_ photo by
Lama Roscu
on
Unsplash
- Sundae image by
Gerhard G.
from
Pixabay
- Switch photo by
Isabella and Louisa Fischer
on
Unsplash