Merge pull request #26 from ttroy50/add-packaging-examples

Add packaging examples
This commit is contained in:
Thom Troy
2019-04-06 22:43:14 +01:00
committed by GitHub
15 changed files with 536 additions and 0 deletions

1
.gitignore vendored
View File

@@ -61,3 +61,4 @@ install_manifest.txt
/**/build.*
.tags
.vscode

View File

@@ -0,0 +1,13 @@
= Using System Provided Package Manager
:toc:
:toc-placement!:
toc::[]
# Introduction
Using your system provided packages is one of the oldest and most common form of package management solutions. For this, you use your systems package installer (e.g. apt, yum) to install libraries and headers into common locations. CMake can then use the `find_package()` function to search for these and make them available to your program.
# Examples
I have already shown how to do this in the link:https://github.com/ttroy50/cmake-examples/tree/master/01-basic/H-third-party-library[third party library] example from the basic section and the link:https://github.com/ttroy50/cmake-examples/tree/master/05-unit-testing/boost[boost unit test] example.

View File

@@ -0,0 +1,43 @@
= Vendoring Code
:toc:
:toc-placement!:
toc::[]
# Introduction
Vendoring code means to include the third party code inside your repository and build it as part of your project. It is a way to ensure that all files required to build your project are part of the development environment.
# Implementation
## Including 3rd Party Code
Typically, this might take the form or a `3rd_party` or `vendor` directory, in which you copy the source of the libraries you want to include. For example, you may do something like:
```
$ tree
.
├── 3rd_party
│   └── catch2
│   ├── catch2
│   │   └── catch.hpp
│   └── CMakeLists.txt
├── CMakeLists.txt
├── src
│   └── example.cpp
```
If these projects support CMake directly, it may be possible to do `add_subdirectory()` on the libraries folder and have that project build and be made available to your code.
If the third party code doesn't support CMake, you may need to create a "shim" layer on top of the project to allow it to be build and discovered from CMake.
## Using git to vendor code
A slightly different method to include the third party code can be to use your SCM software to manage the process for you.
In the case of git, you can use link:https://git-scm.com/book/en/v2/Git-Tools-Submodules[git sub-modules] or link:https://git-scm.com/book/en/v1/Git-Tools-Subtree-Merging[git subtree]. These can pull the correct version of the third party code into your repository on initialisation / update.
# Examples
A simple example of vendoring code can already be seen in the link:https://github.com/ttroy50/cmake-examples/tree/master/05-unit-testing/catch2-vendored[catch2] testing tutorial.

View File

@@ -0,0 +1,40 @@
= External Project
:toc:
:toc-placement!:
toc::[]
# Introduction
CMake supports downloading and building an external project using the link:https://cmake.org/cmake/help/latest/module/ExternalProject.html[External Project] commands. By adding +ExternalProject_Add+ to your code you can have CMake automatically download a source file from either HTTP or a source control system (e.g. git).
Once configured an external project will generate a custom target which can be used to control the download, update, build, test, and install phases of the external project.
# Implementation
## Standard
A simple example of an external project is as follows:
[source,cmake]
----
include(ExternalProject)
ExternalProject_Add(googletest
URL https://github.com/google/googletest/archive/bfc0ffc8a698072c794ae7299db9cb6866f4c0bc.tar.gz_
)
----
Once added you will have a target `googletest` which will attempt to download, build, and install google test when your build your project.
[NOTE]
====
This will attempt to install google test to your standard locations e.g. `/usr/` and may fail if you are not root. To skip the install step you can add a line `INSTALL_COMMAND ""`
====
By default the project is assumed to work via CMake and external project will know how to build using standard CMake commands. If the external project uses a different build system, you can set the various commands using +INSTALL_COMMAND+, +CONFIGURE_COMMAND+, +BUILD_COMMAND+, etc.
## Alternative
An alternative method to install packages is to have the ExternalProject command run at CMake configure time. This can cause the download to happen at the configure step and you may then use +add_subdirectory+ to add the project to your code (assuming it uses CMake). An example of this can be found in the link:https://github.com/ttroy50/cmake-examples/tree/master/05-unit-testing/google-test-download[google-test-download] tutorial.
A more generic version of the download code can be found link:https://github.com/Crascit/DownloadProject[here].

View File

@@ -0,0 +1,152 @@
= Conan
:toc:
:toc-placement!:
toc::[]
# Introduction
link:https://conan.io[Conan] is an open source, decentralized, and multi-platform package manager that can be used to create and share native libraries and binaries. It supports multiple build systems (CMake, Visual Studio, Makefiles) and OSes (Linux, Windows, and Mac).
Conan servers can be installed privately or you can use public servers and packages made available by link:https://bintray.com/conan/conan-center[Jfrog bintray].
Full documentation for conan can be found from link:https://docs.conan.io/en/latest/[here]
# Installing Conan
Conan is a python application and can be installed using pip.
[source,bash]
----
$ sudo apt-get install python3 python3-pip
$ pip3 install conan
$ conan help
Consumer commands
install Installs the requirements specified in a recipe (conanfile.py or conanfile.txt).
...
----
Alternatively, native packages are available for most operating systems. Full details are available link:https://docs.conan.io/en/latest/installation.html[here].
# Conan Profile
In conan link:https://docs.conan.io/en/latest/reference/profiles.html#profiles[profiles] control information such as the compiler and environments that are available on your system.
To create a new default profile run
[source,bash]
----
$ conan profile new default --detect
Found gcc 5.4
gcc>=5, using the major as version
Profile created with detected settings: /home/devuser/.conan/profiles/default
----
The generated profile will look something like:
[source,bash]
----
[settings]
os=Linux
os_build=Linux
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=5
compiler.libcxx=libstdc++
build_type=Release
[options]
[build_requires]
[env]
----
[NOTE]
====
If you are using GCC compiler >= 5.1, Conan will set the compiler.libcxx to the old ABI for backwards compatibility. You can change this with the following commands:
[source,bash]
----
$ conan profile update settings.compiler.libcxx=libstdc++11 default
----
[source,bash]
----
[settings]
os=Linux
os_build=Linux
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=5
compiler.libcxx=libstdc++11
build_type=Release
[options]
[build_requires]
[env]
----
You can find more information about this link:https://docs.conan.io/en/latest/howtos/manage_gcc_abi.html#manage-gcc-abi[here].
====
All examples provided will assume that the ABI being used for libstdc++ is the Cpp11 ABI.
# Finding Packages
Remote repositories can be searched for conan packages. By default the `conan-center` remote is configured. This is located in link:https://bintray.com/conan/conan-center[bintray].
## Searching for Packages
You can search for packages using the `conan search` command. For example, to search for a package such as link:https://github.com/fmtlib/fmt[fmtlib] you can run:
[source,bash]
----
$ conan search fmt* --remote=conan-center
Existing package recipes:
fmt/4.0.0@bincrafters/stable
fmt/4.1.0@bincrafters/stable
fmt/5.0.0@bincrafters/stable
fmt/5.1.0@bincrafters/stable
fmt/5.2.0@bincrafters/stable
fmt/5.2.1@bincrafters/stable
fmt/5.3.0@bincrafters/stable
----
## Inspecting Packages
You can then inspect a package using the `conan inspect` command. To inspect one one of the fmt packages from the search command above you can run:
[source,bash]
----
$ conan inspect fmt/5.3.0@bincrafters/stable --remote=conan-center
name: fmt
version: 5.3.0
url: https://github.com/bincrafters/conan-fmt
homepage: https://github.com/fmtlib/fmt
license: MIT
author: Bincrafters <bincrafters@gmail.com>
description: A safe and fast alternative to printf and IOStreams.
topics: None
generators: cmake
exports: ['LICENSE.md']
exports_sources: ['CMakeLists.txt']
short_paths: False
apply_env: True
build_policy: None
revision_mode: hash
settings: ('os', 'compiler', 'build_type', 'arch')
options:
fPIC: [True, False]
header_only: [True, False]
shared: [True, False]
with_fmt_alias: [True, False]
default_options:
fPIC: True
header_only: False
shared: False
with_fmt_alias: False
----
This shows details about the package including what link:https://docs.conan.io/en/latest/using_packages/conanfile_txt.html#options[options] can be set when including the package. In the case of fmtlib there are 4 options which allow you to specify the type of installion you want.

View File

@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.5)
project (conan_third_party_include)
set(CMAKE_CXX_STANDARD 11)
# Included the conan build information
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
# Add an executable
add_executable(third_party_include main.cpp)
# link against the fmt target supplied by conan
target_link_libraries(third_party_include
PRIVATE
${CONAN_LIBS}
)

View File

@@ -0,0 +1,213 @@
= Conan Basic Example
:toc:
:toc-placement!:
toc::[]
# Introduction
link:http://conan.io[Conan] supports downloading libraries and making them available to an application developers. Packages are defined in the link:https://docs.conan.io/en/latest/using_packages/conanfile_txt.html[+conanfile.txt+] file, which defines packages, options, and the link:https://docs.conan.io/en/latest/reference/generators.html#generators-reference[generators] for your project.
The files in this tutorial are below:
```
.
├── CMakeLists.txt
├── conanfile.txt
├── main.cpp
└── README.adoc
```
* link:CMakeLists.txt[] - Contains the CMake commands to run
* link:conanfile.txt[] - Contains the conan dependencies and options
* link:main.cpp[] - Source file of the application.
# Concepts
## conanfile.txt
### requires
The conanfile.txt defines the required packages you wish to install
[source,ini]
----
[requires]
fmt/5.3.0@bincrafters/stable
----
Where:
* `fmt` is the name of the package / library.
* `5.3.0` is the version of the package.
* `bincrafters` is the owner / builder of the package.
* `stable` is channel of the package. Channels provide a to have different variants of packages.
### generators
Generators define the build systems that you are using and allows Conan to create files with all the information needed to find your libraries and link your program.
[source,ini]
----
[generators]
cmake
----
The CMake generator will create the file `conanbuildinfo.cmake` which should be included in your +CMakeLists.txt+ file. This will be a per-user file and should not be committed to your source control system.
## Installing Packages
To install packages you should run the following:
[source,bash]
----
$ mkdir build
$ cd build
$ conan install ..
----
This will tell conan to read the +conanfile.txt+ from your root folder and install any required package configurations. If the package is not availabe in your package cache it will be downloaded.
As per our requires section, `conan install` will download a static library version of fmtlib along with all required headers. On my system with default configuration, this cached library is as follows:
[source,bash]
----
$ ls ~/.conan/data/fmt/5.3.0/bincrafters/stable/package/4d887c1c2779c63d2cdd81580698d2e22cb35b29/
conaninfo.txt conanmanifest.txt include lib licenses share
$ ls ~/.conan/data/fmt/5.3.0/bincrafters/stable/package/4d887c1c2779c63d2cdd81580698d2e22cb35b29/lib
cmake libfmt.a
----
The install command will also create any temporary files such as the +conanbuildinfo.cmake+ file.
## conanbuildinfo.cmake
As mentioned the +conanbuildinfo.cmake+ file contains any CMake commands that are required to link against your installed libraries. You must include this file in your CMakeLists.txt as follows
[source,cmake]
----
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
----
The +CMAKE_BINARY_DIR+ here is the same build directory that your ran `conan install` in and will eventually run your `cmake` command in.
Once included the variable +CONAN_LIBS+ is made available which contains the information you need to link against the libraries.
[source,cmake]
----
# link against the fmt target supplied by conan
target_link_libraries(third_party_include
PRIVATE
${CONAN_LIBS}
)
----
# Building the Example
[source,bash]
----
$ mkdir build
$ cd build/
$ conan install ..
Configuration:
[settings]
arch=x86_64
arch_build=x86_64
build_type=Release
compiler=gcc
compiler.libcxx=libstdc++11
compiler.version=5
os=Linux
os_build=Linux
[options]
[build_requires]
[env]
fmt/5.3.0@bincrafters/stable: Not found in local cache, looking in remotes...
fmt/5.3.0@bincrafters/stable: Trying with 'conan-center'...
Downloading conanmanifest.txt
[==================================================] 166B/166B
Downloading conanfile.py
[==================================================] 2.9KB/2.9KB
Downloading conan_export.tgz
[==================================================] 758B/758B
Decompressing conan_export.tgz: 1.98kB [00:00, 504kB/s]
fmt/5.3.0@bincrafters/stable: Downloaded recipe revision 0
conanfile.txt: Installing package
Requirements
fmt/5.3.0@bincrafters/stable from 'conan-center' - Downloaded
Packages
fmt/5.3.0@bincrafters/stable:4d887c1c2779c63d2cdd81580698d2e22cb35b29 - Download
fmt/5.3.0@bincrafters/stable: Retrieving package 4d887c1c2779c63d2cdd81580698d2e22cb35b29 from remote 'conan-center'
Downloading conanmanifest.txt
[==================================================] 1.1KB/1.1KB
Downloading conaninfo.txt
[==================================================] 550B/550B
Downloading conan_package.tgz
[==================================================] 156.2KB/156.2KB
Decompressing conan_package.tgz: 161kB [00:00, 13.8MB/s]
fmt/5.3.0@bincrafters/stable: Package installed 4d887c1c2779c63d2cdd81580698d2e22cb35b29
fmt/5.3.0@bincrafters/stable: Downloaded package revision 0
conanfile.txt: Generator cmake created conanbuildinfo.cmake
conanfile.txt: Generator txt created conanbuildinfo.txt
conanfile.txt: Generated conaninfo.txt
conanfile.txt: Generated graphinfo
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: Adjusting output directories
-- Conan: Using cmake global configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Current conanbuildinfo.cmake directory: /home/devuser/ws/build
-- Conan: Compiler GCC>=5, checking major version 5
-- Conan: Checking correct version: 5
-- Configuring done
-- Generating done
-- Build files have been written to: /home/devuser/ws/build
$ make VERBOSE=1
/usr/bin/cmake -H/home/devuser/ws -B/home/devuser/ws/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/devuser/ws/build/CMakeFiles /home/devuser/ws/build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/devuser/ws/build'
make -f CMakeFiles/third_party_include.dir/build.make CMakeFiles/third_party_include.dir/depend
make[2]: Entering directory '/home/devuser/ws/build'
cd /home/devuser/ws/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/devuser/ws /home/devuser/ws /home/devuser/ws/build /home/devuser/ws/build /home/devuser/ws/build/CMakeFiles/third_party_include.dir/DependInfo.cmake --color=
Dependee "/home/devuser/ws/build/CMakeFiles/third_party_include.dir/DependInfo.cmake" is newer than depender "/home/devuser/ws/build/CMakeFiles/third_party_include.dir/depend.internal".
Dependee "/home/devuser/ws/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/devuser/ws/build/CMakeFiles/third_party_include.dir/depend.internal".
Scanning dependencies of target third_party_include
make[2]: Leaving directory '/home/devuser/ws/build'
make -f CMakeFiles/third_party_include.dir/build.make CMakeFiles/third_party_include.dir/build
make[2]: Entering directory '/home/devuser/ws/build'
[ 50%] Building CXX object CMakeFiles/third_party_include.dir/main.cpp.o
/usr/bin/c++ -I/home/devuser/.conan/data/fmt/5.3.0/bincrafters/stable/package/4d887c1c2779c63d2cdd81580698d2e22cb35b29/include -std=gnu++11 -o CMakeFiles/third_party_include.dir/main.cpp.o -c /home/devuser/ws/main.cpp
[100%] Linking CXX executable bin/third_party_include
/usr/bin/cmake -E cmake_link_script CMakeFiles/third_party_include.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/third_party_include.dir/main.cpp.o -o bin/third_party_include -L/home/devuser/.conan/data/fmt/5.3.0/bincrafters/stable/package/4d887c1c2779c63d2cdd81580698d2e22cb35b29/lib -lfmt -Wl,-rpath,/home/devuser/.conan/data/fmt/5.3.0/bincrafters/stable/package/4d887c1c2779c63d2cdd81580698d2e22cb35b29/lib
make[2]: Leaving directory '/home/devuser/ws/build'
[100%] Built target third_party_include
make[1]: Leaving directory '/home/devuser/ws/build'
/usr/bin/cmake -E cmake_progress_start /home/devuser/ws/build/CMakeFiles 0
$ ./bin/third_party_include
Hello, conan. This is fmtlib!
----

View File

@@ -0,0 +1,5 @@
[requires]
fmt/5.3.0@bincrafters/stable
[generators]
cmake

View File

@@ -0,0 +1,8 @@
#include <iostream>
#include <fmt/format.h>
int main(int argc, char *argv[])
{
fmt::print("Hello, {}. This is {}!\n", "conan", "fmtlib");
return 0;
}

View File

@@ -0,0 +1,19 @@
#!/bin/bash
conan_bin=`which conan`
if [ -z $conan_bin ]; then
exit 0
fi
conan profile show default || {
conan profile new default --detect
}
conan profile update settings.compiler.libcxx=libstdc++11 default
echo "correct version of cmake"
mkdir -p build && cd build && conan install .. && cmake .. && make
if [ $? -ne 0 ]; then
echo "Error running example"
exit 1
fi

View File

@@ -0,0 +1,12 @@
= Package Management
:toc:
:toc-placement!:
toc::[]
[[intro]]
Introduction
------------
For C++ and CMake there is currently no universally accepted way of managing and packaging dependencies. However, in recent years there have been some new and interesting package management systems made available. While these are seperate systems to CMake, most of them have are designed to integrate directly into a CMake based build system.

View File

@@ -66,6 +66,11 @@ Some specific examples may require other tools including:
$ sudo apt-get install ninja-build
* link:https://conan.io[conan]
$ sudo apt-get install python3 python3-pip
$ sudo pip3 install conan
## Docker
Docker containers with all requirements and various versions of CMake are generated to help make testing the examples easier. These are available from the docker hub repository link:https://hub.docker.com/r/matrim/cmake-examples/[matrim/cmake-examples].
@@ -100,3 +105,4 @@ to some of these which I have found helpful in my CMake journey.
* https://www.openfoundry.org/svn/cms/trunk/cmake/CppcheckTargets.cmake[CppCheck Targets]
* https://samthursfield.wordpress.com/2015/10/20/some-cmake-tips/[CMake Tips]
* https://www.johnlamp.net/cmake-tutorial.html[John Lamp - CMake Tutorial]
* link:https://docs.conan.io[Conan Documentation]

View File

@@ -13,6 +13,9 @@ RUN apt-get update && apt-get install -y build-essential \
ninja-build \
wget \
git \
python3 \
python3-pip \
&& pip3 install conan \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

View File

@@ -13,6 +13,9 @@ RUN apt-get update && apt-get install -y build-essential \
ninja-build \
wget \
git \
python3 \
python3-pip \
&& pip3 install conan \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

View File

@@ -36,6 +36,7 @@ dirs=(./01-basic/A-hello-cmake \
./05-unit-testing/google-test-download \
./05-unit-testing/catch2-vendored \
./06-installer/deb \
./07-package-management/D-conan/basic \
)
ROOT_DIR=`pwd`