If you want to create a new conan build recipe for a package that already exists, use
Without tests:
conan new hello/0.1
With tests:
conan new hello/0.1 -t
More info: See packaging docs
If you want to create a new conan build recipe for a package that already exists, use
conan new hello/0.1
conan new hello/0.1 -t
More info: See packaging docs
When building a library using conan, this is the default conanfile.py
definition for building using CMake
cmake = CMake(self) cmake.configure(source_folder="hello") cmake.build()
You can easily add definitions like this:
cmake.definitions["MY_FLAG"] = "1"
This will generate -DMY_FLAG=1
when calling CMake
Full example:
cmake = CMake(self) cmake.definitions["USE_SYSTEM_CPR"] = "1 cmake.configure(source_folder="elasticlient")" cmake.build()
Note that you need to add all cmake.definitions
calls before calling cmake.configure()
When trying to configure your CMake project using
find_package(Protobuf REQUIRED)
you see an error message like
CMake Error at /usr/share/cmake-3.16/Modules/FindThreads.cmake:49 (message): FindThreads only works if either C or CXX language is enabled Call Stack (most recent call first): /usr/share/cmake-3.16/Modules/FindProtobuf.cmake:420 (find_package) CMakeLists.txt:7 (find_package) -- Configuring incomplete, errors occurred!
You need to put your
project(MyProject)
line before the
find_package(Protobuf REQUIRED)
line. If you don’t have a project()
line, create one.
Add this to your CMakeLists.txt
:
# # Compile test suite # find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED) add_executable(test_myprogram tests/MyTest.cpp ) target_include_directories(test_myprogram PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include") target_compile_features(test_myprogram PRIVATE cxx_std_17) target_link_libraries(test_myprogram ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ) add_test(test_myprogram test_myprogram) # make "make test" run the test program add_custom_target(test DEPENDS myprogram COMMAND ./test_myprogram )
In order to build the program and the test, run
make
In order to run the tests, use
make test
When compiling your CMake-based C++
CMake Error at /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:117 (find_package): Could not find a package configuration file provided by "boost_unit_test_framework" (requested version 1.71.0) with any of the following names: boost_unit_test_frameworkConfig.cmake boost_unit_test_framework-config.cmake Add the installation prefix of "boost_unit_test_framework" to CMAKE_PREFIX_PATH or set "boost_unit_test_framework_DIR" to a directory containing one of the above files. If "boost_unit_test_framework" provides a separate development package or SDK, be sure it has been installed. Call Stack (most recent call first): /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:182 (boost_find_component) /usr/share/cmake-3.16/Modules/FindBoost.cmake:443 (find_package) OCCUtils/CMakeLists.txt:58 (find_package) -- Configuring incomplete, errors occurred!
The error message is trying to tell you that you don’t have the boost unit test
library installed (or CMake can’t find it).
On Ubuntu, for example, install it using
sudo apt -y install libboost-test-dev
On Windows you can install it using the prebuilt boost binaries for Windows.
When compiling your CMake-based C++
CMake Error at /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:117 (find_package): Could not find a package configuration file provided by "boost_filesystem" (requested version 1.71.0) with any of the following names: boost_filesystemConfig.cmake boost_filesystem-config.cmake Add the installation prefix of "boost_filesystem" to CMAKE_PREFIX_PATH or set "boost_filesystem_DIR" to a directory containing one of the above files. If "boost_filesystem" provides a separate development package or SDK, be sure it has been installed. Call Stack (most recent call first): /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake:182 (boost_find_component) /usr/share/cmake-3.16/Modules/FindBoost.cmake:443 (find_package) CMakeLists.txt:58 (find_package)
The error message is trying to tell you that you don’t have the boost filesystem
library installed (or CMake can’t find it).
On Ubuntu, for example, install it using
sudo apt -y install libboost-filesystem-dev
On Windows you can install it using the prebuilt boost binaries for Windows.
I’m currently running 4 separate dockerized gitlab
instances on my server. These tend to consume quite a lot of memory even when not being used for some time.
The gitlab
default is to use 6
unicorn worker processes. By reducing the number of workers to 2
, my gitlab memory consumption decreased by approximately 60%
:
unicorn['worker_processes'] = 2
In my dockerized setup, I justed updated the GITLAB_OMNIBUS_CONFIG
in docker-compose.yml
and restarted the instance. If you didn’t install gitlab
using docker, you might need to sudo gitlab-ctl reconfigure
.
Note that you need at least 2
unicorn workers for gitlab
to work properly. See this issue for details.
Also note that reducing the number of workers to the minimum will likely impact your gitlab
performance in a negative way. Increase the number of workers if you notice a lack in performance.
Most small installation do not need Prometheus, the monitoring tool integrated into Gitlab:
prometheus_monitoring['enable'] = false
sidekiq
is the background job processor integrated into Gitlab. The default concurrency is 25
. I recommend reducing it.
sidekiq['concurrency'] = 2
This might cause background jobs to take longer since they have to wait in queue, but for small installations it does not matter in my experience.
This was recommended on StackOverflow.
postgresql['shared_buffers'] = "256MB"
Setting this too low might cause a heavier IO load and all operations (including website page loads) might be slower.
This is the configuration (combined from all strategies listed above) in order to get down the memory consumption:
# Unicorn config unicorn['worker_processes'] = 2 # PostgreSQL config postgresql['shared_buffers'] = "256MB" # Sidekiq config sidekiq['concurrency'] = 2 # Prometheus config prometheus_monitoring['enable'] = false
Since I had more than 100 repositories in my old gitolite instance and I wanted to migrate to Gitlab a more easy-to-use solution, I developed a
Warning: This is not a finished script but merely a guideline which you need to modify according to your specific needs. I don’t have private repositories in gitolite, so all of my repositories are explicitly listed in the config files. Use on your own responsibility and make a backup!
This does not change or delete any of your repositories in gitolite. Be sure to backup all your repositories in gitolite anyway, just in case!
# Configure git to not ask you for a password every time you are uploading. git config --global credential.helper store # Prepare list of repositories (check the text file and remove invalid names) cat ~/gitolite-admin/*.conf |grep repo | cut -d' ' -f2 > repos.txt # Clone all repos mkdir repos cd repos for i in $(cat ../repos.txt) ; do git clone [email protected]:${i} ; done # Push to Gitlab. This will automatically create a new project as your current user for i in * ; do cd $i && git remote rm origin && git remote add origin "https://gitlab.myserver.org/yourusername/${i}.git" && git push origin master && cd ..; done # Don't forget to make a backup of your gitolite repositories in case anything went wrong!
This script uses the fact that you can directly push to a new repository on Gitlab, creating the project in the process. You don’t need to manually create the project.
While running this script, my Gitlab instance crashed two times while a repository was in the last stage of the git push
process (this tended to happen for small kilobyte-sized repositories) due to heavy swapping induced by heavy memory usage. Restarting gitlab, and re-running the Push to gitlab part of the script fixed this issue.
Note that git config --global credential.helper store
will stay in effect, saving your git
passwords in clear-text. In case you want to restore the default behaviour of keeping them in the RAM for 15 minutes, use git config --global credential.helper cache
after running these commands.
This CMakeLists.txt
builds an executable called main
from main.cpp
:
add_executable(main main.cpp)
Note: Based on this post I have published buildock on GitHub.
Many C/C++ programmers and project managers know the pain of creating a reproducible build environment for all developers: Works for me is a common meme not without a reason.
My approach is to dockerize not neccessarily the application itself but the build system, encapsulating both the specific compiler version and the system around it plus all required system-level libraries in a Docker image.
Take the obligatory Hello World in C++:
// main.cpp #include <iostream> using namespace std; int main() { cout << "Hello, World!" << endl; return 0; }
and the corresponding Makefile
:
all: g++ -o helloworld main.cpp
How can we compile this simple project without installing a compiler and GNU make on the local computer (no cheating by using build servers allowed)?
Actually it’s rather simple:
docker run --user $(id -u):$(id -g) -v $PWD:/app -it ulikoehler/ubuntu-gcc-make make
Breaking it down:
docker run
: Create a new docker container and run a command in it--user $(id -u):$(id -g)
: This makes the docker container run with the current user’s ID and the current user’s group – both for preventing the compiler to create output files as root
and to safeguard against some IT security risks. Also see How to run docker container as current user & group-v $PWD:/app
: Mount the current directory ($PWD
) on /app
in the container. Since the Dockerfile used to build the container contains the WORKDIR /app
directive, whatever command we run in the container will by default be executed in the /app
directory – and therefore in the current local directory on the host.-it
runs the container in interactive mode, i.e. keypressed are passed down to the command you are running. Also, this means that our command will only finish when the container has finished executing.ulikoehler/ubuntu-gcc-make
: This is the image we’re using for that example. It’s nothing more than an ubuntu:18.04
base image with build-essentials
and make
installed and WORKDIR
set to /app
make
: This is the command we’ll run in the container. You can use any command here, even no command is possible (in which case the container’s default command will be used – in case of ulikoehler/ubuntu-gcc-make
that is CMD [ "/usr/bin/make" ]
)Here’s the complete Dockerfile
used to generate ulikoehler/ubuntu-gcc-make
:
FROM ubuntu:18.04 RUN apt update && apt -y install build-essential make && rm -rf /var/lib/apt/lists/* WORKDIR /app CMD [ "/usr/bin/make" ]
With automake/m4 in configure.ac
you use syntax like
AC_CHECK_FUNCS(atan2)
which defines HAVE_FDATASYNC
if the function is available.
In CMake, you can use check_symbol_exists()
for the same purpose like this:
cmake_minimum_required(VERSION 3.0) include(CheckSymbolExists) # Define executable add_executable(myexe main.c) # atan2 requires the math library to be linked list(APPEND CMAKE_REQUIRED_LIBRARIES m) check_symbol_exists(atan2 math.h HAVE_ATAN2) # Add compile definitions if we have the library if(HAVE_ATAN2) target_compile_definitions(myexe PRIVATE -DHAVE_ATAN2) endif()
Note that check_symbol_exists()
does not automatically add a preprocessor define but you have to do that manually (see the last block in the code shown above). While this might seem less comfortable at first, this approach provides you with much more flexibility on how to handle missing or available functions.
See the CMake check_symbol_exists()
documentation for more details.
cmake_minimum_required(VERSION 3.0) include(CheckSymbolExists) # Define executable add_executable(myexe main.c) # atan2 requires the math library to be linked list(APPEND CMAKE_REQUIRED_LIBRARIES m) check_symbol_exists(atan2 math.h HAVE_ATAN2) # Add compile definitions if we have the library if(HAVE_ATAN2) target_compile_definitions(myexe PRIVATE -DHAVE_ATAN2) endif()
If you have CMake code using check_symbol_exists(...)
like
list(APPEND CMAKE_REQUIRED_LIBRARIES m) check_symbol_exists(atan2 math.h HAVE_ATAN2)
but you get an error message like
CMake Error at CMakeLists.txt:8 (check_symbol_exists): Unknown CMake command "check_symbol_exists". -- Configuring incomplete, errors occurred!
you need to add
include(CheckSymbolExists)
near the top of your CMakeLists.txt
(before your first call to check_symbol_exists()
).
if
/else
/endif
looks like this in CMake:
if(myvar) message("if") else() message("else") endif()
Simply add these lines to the end of your CMakeLists.txt
and replace myTarget
by the name of your build target (usually the first argument to add_executable(...)
or add_library(...)
):
# Include boost find_package( Boost 1.30 COMPONENTS program_options REQUIRED ) target_include_directories( myTarget PRIVATE ${Boost_INCLUDE_DIR}) target_link_libraries( myTarget ${Boost_LIBRARIES} )
If you have multiple targets, copy & paste the last two lines for each target.
If you need a specific version of boost, replace 1.30
by the minimum version you need.
If you want to build an executable / library with debug symbols in CMake, run
cmake -DCMAKE_BUILD_TYPE=Debug . make
Conversely, if you want to build an executable / library in release mode, run
cmake -DCMAKE_BUILD_TYPE=Release . make
Let’s say you have a git submodule
in MySubmodule
directory. If you have made changes to the repository referred to by MySubmodule
, you might want to update your project to refer to the latest commit.
In order to do this, simply go to the MySubmodule
directory and run git pull
there. You can also git checkout
any other branch.
After that, you need to commit the changes (i.e. which commit git submodule
is referring to currently) in the outer repository.
git status
in the outer repository will show you the changes like this:
Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: MySubmodule (new commits)
Use git add MySubmodule
and git commit
normally, or use git commit -a
to commit all staged changes.
If you use SDCC to compile your C code for your microcontroller and you encounter an error message like this:
at 1: warning 119: don't know what to do with file 'main.o'. file extension unsupported
you have to configure your build system to use the .rel
suffix for object files instead of the standard .o
. SDCC expects built object files to have the .rel
extension! See How to change CMake object file suffix from default “.o” for details on how to do that in CMake.
You want to upload a package to a PPA using dput <filename>.changes
, but you see an error message like this:
Checking signature on .changes gpg: /home/uli/dev/deb-buildscripts/stm8flash_0.1-git261-deb1-1_amd64.changes: error 58: gpgme_op_verify gpgme_op_verify: GPGME: No data
You need to sign your .changes
file before uploading! Do this using
debsign -k 1BBC8BAA <filename>.changes
where 1BBC8BAA
is your GPG key ID which you intend to sign with.
In order to configure CMake to use an alternate object file suffix (default: .o
on Linux) use these lines in your CMakeLists.txt
:
set(CMAKE_C_OUTPUT_EXTENSION ".rel") set(CMAKE_CXX_OUTPUT_EXTENSION ".rel")
This example changes the output extension from .o
to .rel
(which is required for the SDCC compiler). Be sure to replace ".rel"
by your desired output suffix.
Note that in order for these to take effect, you might need to completely remove CMakeCache.txt
, CMakeFiles
& cmake_install.cmake
:
rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake