Project management

How to generate new Conan recipe for pre-existing package

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

Posted by Uli Köhler in C/C++, Conan

How to add conan CMake build definition

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()

Posted by Uli Köhler in C/C++, Conan

How to fix CMake Protobuf “FindThreads only works if either C or CXX language is enabled”

Problem:

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!

Solution:

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.

Posted by Uli Köhler in C/C++, CMake

How to compile boost unit test program using CMake

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
Posted by Uli Köhler in Boost, C/C++, CMake

How to fix CMake error Could not find a package configuration file provided by “boost_unit_test_framework”

Problem:

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!

Solution:

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.

Posted by Uli Köhler in C/C++, CMake

How to fix CMake error Could not find a package configuration file provided by “boost_filesystem”

Problem:

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)

Solution:

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.

Posted by Uli Köhler in C/C++, CMake

How I reduced gitlab memory consumption in my docker-based setup

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.

Reduce the number of unicorn worker processes

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.

Disable Prometheus monitoring

Most small installation do not need Prometheus, the monitoring tool integrated into Gitlab:

prometheus_monitoring['enable'] = false

Reduce sidekiq concurrency

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.

Reduce the PostgreSQL shared memory

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.

The complete config

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

 

Posted by Uli Köhler in Docker, git

How I migrated my gitolite to Gitlab

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.

Posted by Uli Köhler in git

CMake executable minimal example

This CMakeLists.txt builds an executable called main from main.cpp:

add_executable(main main.cpp)

 

Posted by Uli Köhler in CMake

Towards a docker-based build of C/C++ applications

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" ]
Posted by Uli Köhler in Build systems, C/C++, Container, Docker

What is the CMake equivalent to AC_CHECK_FUNCS()?

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.

Posted by Uli Köhler in CMake

CMake check_symbol_exists() minimal example

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()
Posted by Uli Köhler in CMake

How to fix ‘Unknown CMake command “check_symbol_exists”‘

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()).

Posted by Uli Köhler in CMake

Minimal CMake if/else/endif example

if/else/endif looks like this in CMake:

if(myvar)
  message("if")
else()
  message("else")
endif()

 

Posted by Uli Köhler in CMake

How to add boost::program_options to your CMake build

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.

Posted by Uli Köhler in Boost, C/C++, CMake

How to build debug in CMake

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

 

Posted by Uli Köhler in C/C++, CMake

How to update git submodule to current master or other branch?

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.

Posted by Uli Köhler in git, Version management

How to fix SDCC ‘at 1: warning 119: don’t know what to do with file ‘main.o’. file extension unsupported’

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.

Posted by Uli Köhler in Build systems, Embedded

How to fix dput ‘error 58: gpgme_op_verify’

Problem:

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

Solution:

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.

Posted by Uli Köhler in Build systems

How to change CMake object file suffix from default ‘.o’

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

 

Posted by Uli Köhler in C/C++, CMake