Compare commits
5 Commits
f843ea2c13
...
427f11bbdf
| Author | SHA1 | Date |
|---|---|---|
|
|
427f11bbdf | |
|
|
a745b47cf1 | |
|
|
ea55d3e6fd | |
|
|
8e657df097 | |
|
|
0e95d60bcd |
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AllowAllArgumentsOnNextLine: 'false'
|
||||||
|
AllowAllConstructorInitializersOnNextLine: 'false'
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||||
|
AllowShortBlocksOnASingleLine: 'false'
|
||||||
|
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||||
|
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: None
|
||||||
|
AllowShortLoopsOnASingleLine: 'false'
|
||||||
|
AlwaysBreakTemplateDeclarations: 'Yes'
|
||||||
|
BinPackArguments: 'false'
|
||||||
|
BinPackParameters: 'false'
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
ColumnLimit: '120'
|
||||||
|
Cpp11BracedListStyle: 'true'
|
||||||
|
FixNamespaceComments: 'true'
|
||||||
|
IncludeBlocks: Merge
|
||||||
|
IndentCaseLabels: 'true'
|
||||||
|
IndentWidth: '4'
|
||||||
|
Language: Cpp
|
||||||
|
MaxEmptyLinesToKeep: '2'
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
PointerAlignment: Left
|
||||||
|
SortUsingDeclarations: 'true'
|
||||||
|
SpaceAfterTemplateKeyword: 'false'
|
||||||
|
SpacesInAngles: 'false'
|
||||||
|
SpacesInCStyleCastParentheses: 'false'
|
||||||
|
SpacesInContainerLiterals: 'false'
|
||||||
|
SpacesInSquareBrackets: 'false'
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: '4'
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
...
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
[requires]
|
||||||
|
boost/1.84.0
|
||||||
|
gtest/1.14.0
|
||||||
|
|
||||||
|
[generators]
|
||||||
|
CMakeDeps
|
||||||
|
CMakeToolchain
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import os
|
||||||
|
from conan import ConanFile
|
||||||
|
from conan.tools.files import copy
|
||||||
|
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps
|
||||||
|
|
||||||
|
class HelloConan(ConanFile):
|
||||||
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
|
requires = "boost/1.84.0", "gtest/1.14.0", "libmagic/5.45"
|
||||||
|
generators = "CMakeDeps"
|
||||||
|
build_policy = "*"
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
# We need to find the folder of libmagic and supply it to cmake so that
|
||||||
|
# we can deploy the magic file.
|
||||||
|
libmagic = self.dependencies["libmagic"]
|
||||||
|
|
||||||
|
tc = CMakeToolchain(self)
|
||||||
|
tc.variables["CONAN_LIBMAGIC_PACKAGE_FOLDER"] = libmagic.package_folder
|
||||||
|
tc.generate()
|
||||||
|
|
@ -0,0 +1,462 @@
|
||||||
|
\documentclass[aspectratio=169]{beamer}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage{graphics}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{verbatim}
|
||||||
|
\usepackage{plantuml}
|
||||||
|
\usepackage{listings}
|
||||||
|
\usepackage{csquotes}
|
||||||
|
\usepackage{multicol}
|
||||||
|
\usepackage{menukeys}
|
||||||
|
|
||||||
|
|
||||||
|
% Style related code
|
||||||
|
%
|
||||||
|
\setbeamerfont{footnote}{size=\tiny}
|
||||||
|
|
||||||
|
% Code block style
|
||||||
|
%
|
||||||
|
\lstset{
|
||||||
|
basicstyle=\footnotesize\ttfamily,
|
||||||
|
columns=fullflexible,
|
||||||
|
frame=single,
|
||||||
|
numbers=left
|
||||||
|
}
|
||||||
|
|
||||||
|
\title{Workshop Modern C++ build environment}
|
||||||
|
\author{Bart Beumer (bart.beumer@alten.nl)}
|
||||||
|
\institute{Alten}
|
||||||
|
\date{2025-07-29}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\titlepage
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Rationale}
|
||||||
|
Using modern tools in combination with C \& C++ we can describe the build environment, 3rd party libraries and executables to build.
|
||||||
|
|
||||||
|
We will be able to create a highly reproducable build environment regardless of the OS running on the developer PC (as long as it can run docker).
|
||||||
|
|
||||||
|
\vspace{5mm}
|
||||||
|
|
||||||
|
This workshop aims to demonstrate how to create this build environment, how to use the tools, introduce ourselves to this way of working using included demonstration projects.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Tools}
|
||||||
|
We will be using a combination of tools, each having their own purpose.
|
||||||
|
\begin{itemize}
|
||||||
|
\item Dev containers \footnote{\url{https://containers.dev/}}
|
||||||
|
|
||||||
|
\begin{quote}
|
||||||
|
A development container (or dev container for short) allows you to use a container as a full-featured development environment.
|
||||||
|
\end{quote}
|
||||||
|
|
||||||
|
\item Conan \footnote{\url{https://conan.io/faq}}
|
||||||
|
|
||||||
|
Open source, decentralized and multi-platform package manager.
|
||||||
|
|
||||||
|
\item CMake \footnote{\url{https://cmake.org/about/}}
|
||||||
|
|
||||||
|
\begin{quote}
|
||||||
|
... an open source, cross-platform family of tools designed to build, test, and package software.
|
||||||
|
\end{quote}
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Dev containers}
|
||||||
|
Solves the problem of having an encapsulated environment containing all tools, files, configuration that makes up the development environment.
|
||||||
|
|
||||||
|
\vspace{5mm}
|
||||||
|
|
||||||
|
Supported by multiple tools like:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Visual Studio Code \footnote{\url{https://containers.dev/supporting}}
|
||||||
|
\item IntelliJ IDEA \footnote{\url{https://blog.jetbrains.com/idea/2024/07/using-dev-containers-in-jetbrains-ides-part-1/}}
|
||||||
|
\item GitHub codespaces \footnote{\url{https://docs.github.com/en/codespaces/about-codespaces/what-are-codespaces}}
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Dev containers}
|
||||||
|
We need the following files:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Dockerfile
|
||||||
|
\item devcontainer.json
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Dev containers}
|
||||||
|
Using docker compose we create the entire container.
|
||||||
|
\lstinputlisting[keepspaces,firstline=1, firstnumber=1]{../.devcontainer/Dockerfile}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Dev containers}
|
||||||
|
A devcontainer.json contains metadata used by tools.
|
||||||
|
\lstinputlisting[firstline=1, firstnumber=1]{../.devcontainer/devcontainer.json}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Dev containers}
|
||||||
|
We will experiment with these files during the workshop.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Conan}
|
||||||
|
\begin{quotation}
|
||||||
|
Conan is a package manager for C and C++ which aims to solve some very common and difficult challenges.\footnote{\url{https::/conan.io/faq}}
|
||||||
|
\end{quotation}
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Conveniently depend on 3rd party packages and use them.
|
||||||
|
\item Automates the process of downloading, building \& deploy for further use.
|
||||||
|
\item Provide a mechanism to use libraries.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Conan}
|
||||||
|
A simple text file can be used to configure dependencies on packages.
|
||||||
|
\lstinputlisting[language=make]{example_conan.txt}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Conan}
|
||||||
|
We will experiment with these files during the workshop.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake}
|
||||||
|
\begin{quote}
|
||||||
|
CMake is an open source, cross-platform family of tools designed to build, test, and package software. CMake gives you control of the software compilation process using simple independent configuration files. Unlike many cross-platform systems, CMake is designed to be used in conjunction with the native build environment.
|
||||||
|
\footnote{\url{https://cmake.org/about/}}
|
||||||
|
\end{quote}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Good documentation and tutorials provided.\footnote{\url{https://cmake.org/cmake/help/latest/guide/tutorial/index.html}}
|
||||||
|
\item Tools run locally on a system.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake}
|
||||||
|
Using files we can describe libraries, executables, the (external) dependencies they have.
|
||||||
|
\lstinputlisting[language=make]{../src/hello_world/CMakeLists.txt}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake}
|
||||||
|
We will experiment with these files during the workshop.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Workshop}
|
||||||
|
\begin{multicols}{2}
|
||||||
|
Lets start with opening our IDE and our project folder.
|
||||||
|
|
||||||
|
\includegraphics[width=0.45\textwidth]{vscode_empty}
|
||||||
|
|
||||||
|
Quickly after opening the folder we get the following question:
|
||||||
|
|
||||||
|
\includegraphics[width=0.45\textwidth]{vscode_folder_contains_devcontainer}
|
||||||
|
|
||||||
|
VS Code will build the container if needed and start using it.
|
||||||
|
\end{multicols}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Workshop}
|
||||||
|
The dev container has been built, now we need to let conan work and fetch and build dependencies.
|
||||||
|
|
||||||
|
\vspace{5mm}
|
||||||
|
|
||||||
|
\keys{CTRL + SHIFT + P} ``conan install''
|
||||||
|
|
||||||
|
\vspace{5mm}
|
||||||
|
|
||||||
|
\includegraphics[width=0.75\textwidth]{vscode_conan_install}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Workshop}
|
||||||
|
\begin{multicols}{2}
|
||||||
|
We can now use CMake to build our software.
|
||||||
|
\includegraphics[height=0.65\textheight]{vscode_conan_done_cmake}
|
||||||
|
\begin{itemize}
|
||||||
|
\item configure
|
||||||
|
\item build
|
||||||
|
\item debug/launch
|
||||||
|
\end{itemize}
|
||||||
|
\end{multicols}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Workshop}
|
||||||
|
Continuing with theory
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}[fragile]{Conan: important commands}
|
||||||
|
\begin{verbatim}
|
||||||
|
pip install conan
|
||||||
|
\end{verbatim}
|
||||||
|
We use the python package manager to install conan. (part of Dockerfile)
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
conan profile detect
|
||||||
|
\end{verbatim}
|
||||||
|
We let conan detect compilers and tools for which it can use. (part of Dockerfile)
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
conan install
|
||||||
|
\end{verbatim}
|
||||||
|
While in the project working directory, download packages, compile them, generate CMake environment. (was run using vs code)
|
||||||
|
|
||||||
|
After that we can use CMake as we would normally.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake: The basics}
|
||||||
|
\lstinputlisting[language=make]{../src/hello_world/CMakeLists.txt}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake: The basics}
|
||||||
|
\lstinputlisting[language=make,firstline=1,lastline=2]{../src/hello_world/CMakeLists.txt}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Sets the minimum required version of cmake for a project.
|
||||||
|
\item Sets behavior of CMake as it was at a certain version (set policies)\footnote{\url{https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html}}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\vspace{5mm}
|
||||||
|
|
||||||
|
A mechanism to provide backwards compatibility while allowing future versions to change behavior of commands.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}[fragile]{CMake: The basics}
|
||||||
|
\lstinputlisting[language=make,firstline=2, firstnumber=2, lastline=9]{../src/hello_world/CMakeLists.txt}
|
||||||
|
\begin{itemize}
|
||||||
|
\item ``project''
|
||||||
|
|
||||||
|
Used to set the PROJECT\_NAME variable.
|
||||||
|
|
||||||
|
\item ``add\_executable''
|
||||||
|
|
||||||
|
Adding executable by specifying the executable name and the source files.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}[fragile]{CMake: The basics}
|
||||||
|
\lstinputlisting[language=make,firstline=9, firstnumber=9, lastline=18]{../src/hello_world/CMakeLists.txt}
|
||||||
|
\begin{itemize}
|
||||||
|
\item ``set\_property''
|
||||||
|
|
||||||
|
Enables us to set properties like language standard to use (C++, CUDA, ...)
|
||||||
|
|
||||||
|
\item ``target\_link\_libraries''
|
||||||
|
|
||||||
|
Specify library dependencies.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake: The basics, library}
|
||||||
|
\lstinputlisting[language=make]{../src/log/CMakeLists.txt}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake: The basics, library}
|
||||||
|
\lstinputlisting[language=make,firstline=4,firstnumber=4,lastline=9]{../src/log/CMakeLists.txt}
|
||||||
|
|
||||||
|
Similar to ``add\_executable'' we can create a library, specifying the name of the library and the sources that form it.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{CMake: The basics, library}
|
||||||
|
\lstinputlisting[language=make,firstline=15,firstnumber=15,lastline=18]{../src/log/CMakeLists.txt}
|
||||||
|
|
||||||
|
Add include directories, look for header files.
|
||||||
|
|
||||||
|
Applicable for building the given target
|
||||||
|
|
||||||
|
Applicable for building targets depending on this target
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Using 3rd-party packages}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Conan: 3rd-party packages}
|
||||||
|
\lstinputlisting[language=make]{example_conan.txt}
|
||||||
|
\begin{itemize}
|
||||||
|
\item ``[requires]''
|
||||||
|
|
||||||
|
Declare the libraries that we want to use in our project.
|
||||||
|
|
||||||
|
\item ``[generators]''
|
||||||
|
|
||||||
|
Tell Conan to generate files for given build system
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Conan: 3rd-party packages the python way}
|
||||||
|
\lstinputlisting[language=make]{example_conan_py.txt}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake: Using 3rd-party packages}
|
||||||
|
\lstinputlisting[language=make]{../src/hello_world_boost/CMakeLists.txt}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake, 3rd-party packages}
|
||||||
|
\lstinputlisting[language=make, firstline=2,firstnumber=2,lastline=4]{../src/hello_world_boost/CMakeLists.txt}
|
||||||
|
Find a package (usually provided by something external to the project), and load its package-specific details.\footnote{\url{https://cmake.org/cmake/help/latest/command/find_package.html}}
|
||||||
|
|
||||||
|
\lstinputlisting[language=make, firstline=17,firstnumber=17,lastline=20]{../src/hello_world_boost/CMakeLists.txt}
|
||||||
|
Using exposed target names we can use those packages.
|
||||||
|
\begin{itemize}
|
||||||
|
\item Affects libraries linked to target.
|
||||||
|
\item Affects include paths to look for headers.
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{VERIFIED UNTIL HERE}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CWorkshop time!}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Open VS Code, build example applications
|
||||||
|
\item Create your own application, using 3rd-party library of your choice (fmt,gtest)
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}[fragile]{CMake: Integrate testing}
|
||||||
|
\begin{verbatim}
|
||||||
|
enable_testing()
|
||||||
|
\end{verbatim}
|
||||||
|
Use enable\_testing() at the top level CMakeLists.txt to enable cmake to generate things needed to support testing\footnote{\url{https://cmake.org/cmake/help/latest/command/enable_testing.html}}.
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
add_test()
|
||||||
|
\end{verbatim}
|
||||||
|
Use add\_test() inside your CMakeLists.txt to register the test\footnote{\url{https://cmake.org/cmake/help/latest/command/add_test.html}}.
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
ctest
|
||||||
|
\end{verbatim}
|
||||||
|
Commandline application to run all registered tests\footnote{\url{https://cmake.org/cmake/help/latest/manual/ctest.1.html}}.
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CWorkshop time!}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Open VS Code, build example applications
|
||||||
|
\item Create your own unittest, add testing in CMake
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{C++23 Modules is supported!}
|
||||||
|
For C++23 we have a feature called ``modules''. This feature requires support not only by compilers, but also by build tools. The latest version of CMake in combination with Ninja does this.
|
||||||
|
|
||||||
|
Included in provided material is an example
|
||||||
|
|
||||||
|
FURTHER DEV NEEDED
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{END OF THE PRESENTATION}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{CMake, where to find more info}
|
||||||
|
\begin{itemize}
|
||||||
|
\item https://cmake.org/
|
||||||
|
\item https://cmake.org/cmake/help/latest/
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Conan, in the background}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{Workshop}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{Uniform reproducable environment}
|
||||||
|
There are a lot of factors that influence your C++ development environment
|
||||||
|
\begin{itemize}
|
||||||
|
\item The OS being used.
|
||||||
|
\item Environment variables.
|
||||||
|
\item Installed compilers.
|
||||||
|
\item Libraries and tools.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Setting up a developer environment (1st day at new assignment) can involve a lot of steps!
|
||||||
|
|
||||||
|
Dev containes is a small facility built on top of docker that allows all of the above factors to be contained and easilly created
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}{CMake, common variables}
|
||||||
|
\begin{tabular}{| c | c |}
|
||||||
|
\hline
|
||||||
|
PROJECT\_NAME & Name of the project given to the project command. \\
|
||||||
|
\hline
|
||||||
|
CMAKE\_CURRENT\_SOURCE\_DIR & Path to source directory currently being processed. \\
|
||||||
|
\hline
|
||||||
|
CMAKE\_CURRENT\_BINARY\_DIR & Path to binary directory currently being processed. \\
|
||||||
|
\hline
|
||||||
|
CMAKE\_COMMAND & Path to the cmake executable. \\
|
||||||
|
\hline
|
||||||
|
\end{tabular}
|
||||||
|
|
||||||
|
Variables can be used in CMake to navigate directories
|
||||||
|
\footnote{\url{https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html}}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{frame}{CMake, creating modules}
|
||||||
|
\begin{columns}
|
||||||
|
\begin{column}{0.45\textwidth}
|
||||||
|
\lstinputlisting[language=make]{../src/math/CMakeLists.txt}
|
||||||
|
\end{column}
|
||||||
|
\begin{column}{0.45\textwidth}
|
||||||
|
Requires recent CMake and Ninja packages.
|
||||||
|
\end{column}
|
||||||
|
\end{columns}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
||||||
|
\end{document}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 217 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -1,3 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
add_subdirectory(example_boost)
|
add_subdirectory(example_boost)
|
||||||
|
add_subdirectory(hello_world)
|
||||||
|
add_subdirectory(hello_world_awesome)
|
||||||
|
add_subdirectory(awesome_log)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
project(awesome_log)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
./src/console_writer.cpp
|
||||||
|
./src/log.cpp
|
||||||
|
./src/null_writer.cpp
|
||||||
|
./src/scoped_log.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
TARGET ${PROJECT_NAME}
|
||||||
|
PROPERTY CXX_STANDARD 20
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(GTest REQUIRED)
|
||||||
|
|
||||||
|
project(awesome_log_test)
|
||||||
|
add_executable(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
./test/test_scoped_log.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
TARGET ${PROJECT_NAME}
|
||||||
|
PROPERTY CXX_STANDARD 20
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PUBLIC
|
||||||
|
awesome_log
|
||||||
|
GTest::gtest_main
|
||||||
|
GTest::gmock
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME ${PROJECT_NAME}
|
||||||
|
COMMAND ${PROJECT_NAME}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "writer_interface.hpp"
|
||||||
|
|
||||||
|
namespace awesome_log
|
||||||
|
{
|
||||||
|
class console_writer : public writer_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~console_writer() override;
|
||||||
|
void log(std::string_view msg) override;
|
||||||
|
};
|
||||||
|
} // namespace awesome_log
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace awesome_log
|
||||||
|
{
|
||||||
|
class writer_interface;
|
||||||
|
|
||||||
|
writer_interface& get_writer();
|
||||||
|
void set_writer(const std::shared_ptr<writer_interface>& writer);
|
||||||
|
} // namespace awesome_log
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "writer_interface.hpp"
|
||||||
|
|
||||||
|
namespace awesome_log
|
||||||
|
{
|
||||||
|
class null_writer : public writer_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~null_writer() override;
|
||||||
|
void log(std::string_view msg) override;
|
||||||
|
};
|
||||||
|
} // namespace awesome_log
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace awesome_log
|
||||||
|
{
|
||||||
|
class scoped_log
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
scoped_log(std::string_view msg);
|
||||||
|
~scoped_log();
|
||||||
|
|
||||||
|
scoped_log() = delete;
|
||||||
|
|
||||||
|
// No copying or moving allowed.
|
||||||
|
scoped_log(const scoped_log&) = delete;
|
||||||
|
scoped_log(scoped_log&&) = delete;
|
||||||
|
scoped_log& operator=(const scoped_log&) = delete;
|
||||||
|
scoped_log& operator=(scoped_log&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_msg;
|
||||||
|
int m_uncaught_exceptions;
|
||||||
|
};
|
||||||
|
} // namespace awesome_log
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace awesome_log
|
||||||
|
{
|
||||||
|
class writer_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~writer_interface() = default;
|
||||||
|
|
||||||
|
virtual void log(std::string_view msg) = 0;
|
||||||
|
};
|
||||||
|
} // namespace awesome_log
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#include <awesome_log/console_writer.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace awesome_log;
|
||||||
|
|
||||||
|
console_writer::~console_writer() = default;
|
||||||
|
|
||||||
|
void console_writer::log(std::string_view msg)
|
||||||
|
{
|
||||||
|
std::cout << msg << std::endl;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <awesome_log/log.hpp>
|
||||||
|
#include <awesome_log/null_writer.hpp>
|
||||||
|
|
||||||
|
using awesome_log::writer_interface;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::shared_ptr<writer_interface> g_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer_interface& awesome_log::get_writer()
|
||||||
|
{
|
||||||
|
if (!g_instance)
|
||||||
|
{
|
||||||
|
g_instance = std::make_shared<null_writer>();
|
||||||
|
}
|
||||||
|
return *g_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void awesome_log::set_writer(const std::shared_ptr<writer_interface>& writer)
|
||||||
|
{
|
||||||
|
g_instance = writer;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
#include <awesome_log/null_writer.hpp>
|
||||||
|
|
||||||
|
using namespace awesome_log;
|
||||||
|
|
||||||
|
null_writer::~null_writer() = default;
|
||||||
|
|
||||||
|
void null_writer::log(std::string_view)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include <awesome_log/log.hpp>
|
||||||
|
#include <awesome_log/scoped_log.hpp>
|
||||||
|
#include <awesome_log/writer_interface.hpp>
|
||||||
|
#include <exception>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace awesome_log;
|
||||||
|
|
||||||
|
scoped_log::scoped_log(std::string_view msg)
|
||||||
|
: m_msg(msg)
|
||||||
|
, m_uncaught_exceptions(std::uncaught_exceptions())
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "> " << m_msg;
|
||||||
|
|
||||||
|
get_writer().log(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_log::~scoped_log()
|
||||||
|
{
|
||||||
|
bool is_stack_unwinding = (m_uncaught_exceptions != std::uncaught_exceptions());
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "< " << m_msg;
|
||||||
|
|
||||||
|
if (is_stack_unwinding)
|
||||||
|
{
|
||||||
|
ss << " (stack unwinding)";
|
||||||
|
}
|
||||||
|
|
||||||
|
get_writer().log(ss.str());
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <awesome_log/writer_interface.hpp>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
class mock_writer : public awesome_log::writer_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~mock_writer() override = default;
|
||||||
|
|
||||||
|
MOCK_METHOD(void, log, (std::string_view), (override));
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "mock_writer.hpp"
|
||||||
|
#include <awesome_log/log.hpp>
|
||||||
|
#include <awesome_log/scoped_log.hpp>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class test_scoped_log : public ::testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
m_writer = std::make_shared<mock_writer>();
|
||||||
|
awesome_log::set_writer(m_writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override { awesome_log::set_writer(std::shared_ptr<awesome_log::writer_interface>()); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<mock_writer> m_writer;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(test_scoped_log, log_normal_flow)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*m_writer, log("> log"));
|
||||||
|
EXPECT_CALL(*m_writer, log("< log"));
|
||||||
|
|
||||||
|
{
|
||||||
|
awesome_log::scoped_log a("log");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_scoped_log, log_stack_unwind)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*m_writer, log("> log"));
|
||||||
|
EXPECT_CALL(*m_writer, log("< log (stack unwinding)"));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
awesome_log::scoped_log a("log");
|
||||||
|
throw std::runtime_error("");
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
// Not doing anything
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
find_package(Boost 1.88.0 REQUIRED COMPONENTS serialization)
|
find_package(Boost 1.88.0 REQUIRED COMPONENTS serialization)
|
||||||
|
|
||||||
project(hello_world_boost)
|
project(example_boost)
|
||||||
|
|
||||||
add_executable(
|
add_executable(
|
||||||
${PROJECT_NAME}
|
${PROJECT_NAME}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <boost/archive/text_oarchive.hpp>
|
|
||||||
#include <boost/archive/text_iarchive.hpp>
|
#include <boost/archive/text_iarchive.hpp>
|
||||||
|
#include <boost/archive/text_oarchive.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
struct position
|
struct position
|
||||||
{
|
{
|
||||||
double x;
|
int x;
|
||||||
double y;
|
int y;
|
||||||
|
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int /*version*/)
|
void serialize(Archive& ar, const unsigned int /*version*/)
|
||||||
|
|
@ -15,17 +15,13 @@ struct position
|
||||||
ar & y;
|
ar & y;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const position& rhs) const
|
bool operator==(const position& rhs) const { return x == rhs.x && y == rhs.y; }
|
||||||
{
|
|
||||||
return x == rhs.x
|
|
||||||
&& y == rhs.y;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
position myposition{.x=123.0, .y=456.0};
|
position myposition{.x = 123, .y = 456};
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
{
|
{
|
||||||
|
|
@ -44,5 +40,4 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
std::cout << "positions are the same" << std::endl;
|
std::cout << "positions are the same" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
project(hello_world)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
src/main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
TARGET ${PROJECT_NAME}
|
||||||
|
PROPERTY CXX_STANDARD 20
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
std::cout << "Hello world" << std::endl;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
project(hello_world_awesome)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
src/main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
awesome_log
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
TARGET ${PROJECT_NAME}
|
||||||
|
PROPERTY CXX_STANDARD 20
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <awesome_log/console_writer.hpp>
|
||||||
|
#include <awesome_log/log.hpp>
|
||||||
|
#include <awesome_log/scoped_log.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using awesome_log::scoped_log;
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
awesome_log::set_writer(std::make_shared<awesome_log::console_writer>());
|
||||||
|
|
||||||
|
{
|
||||||
|
scoped_log scoped("main.cpp, printing text");
|
||||||
|
std::cout << "Hello world" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
scoped_log scoped("main.cpp, playing with exceptions");
|
||||||
|
throw std::runtime_error("Let's play!");
|
||||||
|
// ... unreachable code goes here.
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << "Caught an exception, as expected in this example" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue