Software Engineering Blog

Tipps und Tricks aus dem Leben eines Systemadministrators.

How to include external libraries

von

Include Google Benchmark / Test in C++ Project

Both Google Test and Google Benchmark are common libraries used in C++ projects for testing and benchmarking. When starting a new project, adding a testsuite should be one of the first actions. But doing that correctly is often a tedious and error-prone task.

In this blog post I will show a common and a better and more recent approach. As you are probably using CMake anyway, it should be no limitation that I only cover this build system. While I show the necessary steps using the mentioned libraries, it should work with most other libraries as well.

Anti-Pattern: External Project

What I have seen multipe times - even as a recommendation - is to use the cmake script ExternalProject. While the integration is done relatively easily there are some major drawbacks:

  • Internet access required in build step
  • Massively slows down build process (for small changes)
  • No packaging possible

Especially in HPC environments often direct internet access is not possible. Hence, the build hangs when the external target is build. There is no easy workaround for that problem, even support for local library versions has to be implemented in the cmake scripts.

Site note: That is why we dropped this approach in DASH.

Solution: Git Submodule

Instead of trying to solve both packaging and building in one step, we seperate this as follows:

  • Use Git submodules for external sources
  • Build each submodule and link everything together

Git Part

A good starting point for the directory structure could be the following:

Project
> vendor          // external sources
>> google         // place submodules in this dir
> src             // project sources
> CMakeLists.txt  // main cmake skript

Now add the submodules:

git submodule add https://github.com/google/googletest.git vendor/google/googletest
git submodule add https://github.com/google/benchmark.git vendor/google/benchmark

Now verify the changes using git status. The output should be similar to the following:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   .gitmodules
    new file:   vendor/google/benchmark
    new file:   vendor/google/googletest

When adding the git submodules it is important to also commit the .gitmodules, as otherwise they are not referenced in other clones. The changes are already staged, so just run git commit -m '...' to commit them.

CMake Part

To solve the issues described above, just clone using git clone --recursive. Now you have a self-contained directory with all sources.

The following code shows the top-level CMakeLists.txt where both submodules are build. Here, the precondition is that both modules can be build using cmake.

# build google benchmark (target: benchmark)
# do not build tests of benchmarking lib
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Suppressing benchmark's tests" FORCE)
add_subdirectory(vendor/google/benchmark)

# build tests (targets: gtest_main, gtest)
add_subdirectory(vendor/google/googletest/googletest)

Now we can link against the previously generated targets. As the headers are already bundled with the target, we just have to "link" it.

# google benchmark
target_link_libraries("${PROJECT_NAME}-bench" benchmark)

# googletest
target_link_libraries("${PROJECT_NAME}-test" gtest)

A full working example of this approach can be found in my minimum vertex cover solver library LibMVC.

Conclusion

In my opinion the second approach using submodules is much easier to maintain and offers many advantages. However it requires the users to deal with git submodules which can be tricky sometimes. Another problem arises when the submodules are added later on (after the first clone), as this requires some additional steps to get everything working.

References

Zurück

Kommentare

Einen Kommentar schreiben

Bitte addieren Sie 2 und 5.

Ähnliche Beiträge

von

Including external libraries in CMake projects is often a tedious and error-prone task. In this blog post I will show a common and a better and more recent approach.

von

Running software (single instance) in a multi-node cluster might reduce downtimes due to planned maintenance, as the VM can be live-migrated to another node prior to that. This in fact increases the availability of the instance. However this only holds for planned events.