How can I add all Boost libraries as include directories? - c++

I'm pulling in Boost using CPM to build another dependency of my project.
CPMAddPackage(
NAME Boost
VERSION 1.77.0
GITHUB_REPOSITORY "boostorg/boost"
GIT_TAG "boost-1.77.0"
)
The issue I'm having is exposing the header files to my dependency. I dumped all of the cmake variables, and there are many variables like boost_accumulators_SOURCE_DIR, boost_algorithm_SOURCE_DIR, boost_any_SOURCE_DIR, boost_asio_SOURCE_DIR, etc. My dependency depends on many of these libraries, and it's really tedious to list them all as include directories:
target_include_directories(
nghttp2_asio
PRIVATE "${boost_system_SOURCE_DIR}/include"
PRIVATE "${boost_config_SOURCE_DIR}/include"
PRIVATE "${boost_asio_SOURCE_DIR}/include"
PRIVATE "${boost_throw_exception_SOURCE_DIR}/include"
PRIVATE "${boost_assert_SOURCE_DIR}/include"
PRIVATE "${BoostAlign_SOURCE_DIR}/include"
PRIVATE "${boost_date_time_SOURCE_DIR}/include"
)
Is there a better way to do this?

CPM is just a thin layer around FetchContent, which in turn downloads your dependency into your build folder and then attempts to add_subdirectory it, adding it to your main build.
I think this is a bad idea for a lot of reasons...
Boost is one of the most commonly packaged C++ libraries, period. Integrating your project into an existing environment (like a Linux distro, or another package manager like Conan or Vcpkg) is going to be difficult if not impossible (without patching, I mean) since it will surely want your project to use the curated build of Boost.
Adding any third party CMake code to your own build is signing up for headaches... have you noticed how hard it is to write correct CMake code? What if Boost clobbers your cache variables or defines targets that conflict with yours?
CMake has built-in and standard support for locating many versions of Boost, including the newer versions that provide first-party CMake config modules.
Boost now provides first-party CMake config modules.
I don't think any build using Boost should be any more complex than this:
cmake_minimum_required(VERSION 3.22)
project(boost-usage-example)
find_package(Boost 1.77 REQUIRED system date_time)
add_executable(nghttp2_asio main.cpp ...)
target_link_libraries(
nghttp2_asio
PRIVATE
Boost::boost # all header-only libs: config asio throw_exception assert align
Boost::date_time
Boost::system
)
See the documentation here: https://cmake.org/cmake/help/latest/module/FindBoost.html
You only list as components (after REQUIRED) the non-header-only libraries. Those are also the ones that require special addition via target_link_libraries. Link to Boost::boost to get all the header-only modules.
This will work no matter what package manager you're using.
If you want to use vcpkg, create a file called vcpkg.json in your project root with the following contents:
{
"name": "boost-usage-example",
"version-string": "0.1.0-dev",
"dependencies": [
"boost-system",
"boost-config",
"boost-asio",
"boost-throw-exception",
"boost-assert",
"boost-align",
"boost-date-time"
]
}
You can also depend on just boost and it will acquire all boost modules, not just the ones you need. Then acquire vcpkg:
$ git clone https://github.com/microsoft/vcpkg.git
$ ./vcpkg/bootstrap-vcpkg.sh
Then build with:
$ cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build build
Done!
Suppose on the other hand that you wanted to use Conan. No big deal, just install Conan in a pip virtual environment:
$ python3 -m venv venv
$ . venv/bin/activate
$ python3 -m pip install -U pip setuptools wheel
$ python3 -m pip install conan
Then create a conanfile.txt with the following contents:
[requires]
boost/1.77.0
[generators]
cmake_paths
Install the dependencies:
$ mkdir build && pushd build && conan install .. && popd
And then build, using Conan's generated toolchain file:
$ cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$PWD/build/conan_paths.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build build
In fact, you can provide both a vcpkg.json and a conanfile.txt and your users will be free to use either one or neither and rely on their system package manager or a package manager you don't know about. In any case it will just work and you free yourself of a mountain of maintenance burdens.

Related

How to install a Library for C++ like Eigen and sharkML at vs code?

I am trying to install libraries like eigen, sharkMl, xtensor, and others in VSCode for C++.
Please if anyone can help me to know the right way to do that.
All of these libraries use CMake for their build system so what I do is use CMake as my build system. My favorite way to do this is to use the libraries build systems to install them and then inlcude them with cmakes find_package function. This you can do by cloning the git repository for the library then build it and install it with cmake. On linux you do this by:
git clone https://gitlab.com/libeigen/eigen.git
cd eigen
mkdir build
cd build
cmake ..
sudo make install
VSCode has good integration for cmake so if you have the C/C++ Extension pack you will be able to build with cmake. In your project folder make a CMakeLists.txt file and add the packages you want:
add_executable(main main.cpp)
find_package(Eigen3 3.4 NO_MODULE)
target_link_libraries(main Eigen3::Eigen)
(This example assumes the main cpp file is main.cpp and creates an executable called main) Then when you press ctr+shift+p and perform CMake: Configure you can select your compiler and build the executable.

Cmake question: How do I use vcpkg to install dependencies automatically?

I'm working on c++ project on a linux machine and it uses several boost libraries. I've installed them on my system using vcpkg and build it using the toolchain provided by vcpkg. My question is:
How do I define the dependencies so that they automatically install on a different system, if they were to build it?
Conan has a way of doing it by defining the dependencies in conanfile.txt. How do I do the same with vcpkg?
Edit1: I've found autovcpkg which does the job I'm looking to do but can the same be done natively inside cmakelists.txt or by vcpkg itself?
If you have vcpkg as a submodule for your project, define a manifest for the libraries you want vcpkg to build, and are using the vcpkg CMake toolchain - then you will get everything you want.
Adding vcpkg as a submodule means that your users don't need to install it themselves, the CMake toolchain will install it on your behalf. It also means that you can fix the package versions
Using a manifest file is how you programmatically tell vcpkg which packages to get and build during a CMake configuration phase
Using a CMake toolchain file is the only way to tie this into your project's build system
$ git clone .../my_project
$ cd ./my_project
$ git submodule update --init
$ mkdir ../build
$ cd ../build
$ cmake ../my_project
-- Running vcpkg install
-- Running vcpkg install - done
...
I've found autovcpkg which does the job I'm looking to do but can the same be done natively inside cmakelists.txt or by vcpkg itself?
You can write a vcpkg port for your library or executable by providing a CONTROL and portfile.cmake file. In the CONTROL file you define all the dependencies and possible features while the portfile contains the build instruction. You can use vcpkg create <myport> <url> <filename> to create the CONTROL and portfile.cmake from a template which can be customized to your needs.
Together with a port-overlay this port can also be used by others without being merged into vcpkg/master

How to avoid users to manually install GDAL dependencies with CMake?

I know how to link GDAL with a C++ application using CMake. The procedure is summarized hereafter in two steps: (1) Installing the dependency on the system and (2) linking it to the C++ application (see here for more details).
Install GDAL (here on Ubuntu 18.04)
Add the PPA to the sources: sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
Update: sudo apt-get update
Install GDAL and its development files: sudo apt-get install gdal-bin libgdal-dev
Test the installation: gdalinfo --version
Link GDAL with the C++ application using CMake:
# find system installed GDAL package with predefined CMake variable for finding GDAL
find_package(GDAL REQUIRED)
...
# Specify location of GDAL header files
include_directories( include ${GDAL_INCLUDE_DIRS})
...
# Specify GDAL libraries to link your cpp executable target against
target_link_libraries( your_cpp_executable_target_name ${GDAL_LIBRARIES})
What is the most convenient way to avoid the user to perform the manual installation of the dependency? That is, how to ensure that the missing dependency will not stop the configuration, and download/build the dependency if not found on the system?
For managing the Boost dependency, I used the CMake ExternalProject feature with a Superbuild pattern, and I think a similar approach should be relevant for managing GDAL dependency. However, I am very new at modern CMake, and I struggle adapting this CMake project handling the Boost dependency to also manage a GDAL dependency.
Any general or step-by-step directions to help doing (or good reasons not to do so) would be helpful.

vcpkg: recalling the CMake instructions shown after installing a package?

After installing packages with vcpkg, help text is shown, eg...
The package fmt:x64-windows provides CMake targets:
find_package(fmt CONFIG REQUIRED)
target_link_libraries(main PRIVATE fmt::fmt fmt::fmt-header-only)
... for the varying instructions needed for using them with CMake. Where do you get this information from if you want to recall it in the future and didn't write it down? Some libraries have more involved instructions than the above.
You can find the help text in files called 'usage'.
You can locate them in either in ports directory or if you are interested only for your packages, then they are in installed. You can search for them with the following command:
# VCPKG_ROOT denotes where is vcpkg installed
$ find $VCPKG_ROOT . -name usage
installed/x64-linux/share/openssl/usage
installed/x64-linux/share/gtest/usage
However some packages, including fmt, are not providing this information in a specific file, they are providing only targets. They are stored in $VCPKG_ROOT/installed/<YOUR_ARCHITECTURE>/share/fmt/fmt-targets.cmake.
vcpkg is then printing a list of targets after the installation. I don't know if there exists a better solution then finding the <package>-targets.cmake files and checks the content.
$ find $VCPKG_ROOT/installed -name *-targets.cmake
installed/x64-linux/share/cxxopts/cxxopts-targets.cmake
installed/x64-linux/share/fmt/fmt-targets.cmake
So if you combine these two techniques, you should be able to find all the information that vcpkg is printing after installation.
Just run the command vcpkg install again.
.\vcpkg.exe install fmt
Computing installation plan...
The following packages are already installed:
fmt[core]:x64-windows -> 8.0.1
Package fmt:x64-windows is already installed
Restored 0 packages from **\AppData\Local\vcpkg\archives in 155.9 us. Use --debug to see more details.
Total elapsed time: 58.04 ms
The package fmt provides CMake targets:
find_package(fmt CONFIG REQUIRED)
target_link_libraries(main PRIVATE fmt::fmt)
# Or use the header-only version
find_package(fmt CONFIG REQUIRED)
target_link_libraries(main PRIVATE fmt::fmt-header-only)

How to properly setup googleTest on OS X aside from XCode

How do I setup gTest, so that I can link aganist the library? I will code in vim, so I just want to install the libraries, unlike the XCode setup. Goal is to be able to link a project against the library by setting -lgtest as linker flag and optionally, if I did not write my own test mainroutine, the explicit -lgtest_main flag.
Before you start make sure your have read and understood
this note from Google! This tutorial makes using gtest easy, but may introduce nasty bugs.
1. Get the googletest framework
$ wget https://github.com/google/googletest/archive/release-1.8.0.zip
Or get it by hand. I guess I won't manitain this little How-to, so if you stumbled upon it and the links are outdated, feel free to edit it.
2. Unzip and build google test
$ unzip gtest-1.8.0.zip
$ cd gtest-1.8.0
$ ./configure
$ make
3. "Install" the headers and libs on your system.
$ sudo cp -a include/gtest /usr/include
$ sudo cp -a lib/.libs/* /usr/lib/
gTestframework is now ready to use. Just don't forget to link your project against the library by setting -lgtest as linker flag and optionally, if you did not write your own test mainroutine, the explicit -lgtest_main flag.
From here on you might want to go to Googles documentation about the framework to learn how it works. Happy coding!
It's adviced that you link statically. There's no secret. Being a bit offtopic, I use CMake in my projects, which I recommend, and here (https://github.com/oblitum/operations) I have setup a very basic skeleton project that links to gmock and gtest (it's also adviced by google that you use the same gtest from gmock, when you use gmock). In the external folder reside the external CMake files that actually import gtest and gmock through ExternalProject_Add. In the sample, I'm setting the URL as a file path in my system where gmock and gtest are downloaded, but, if you check CMake ExternalProject_Add docs you can see that download urls, online repository urls are also available, which can allow your build to download gtest and gmock, and cache it, automatically.
I think cmake is an easy way to setup and use gtest on OSX. It works without manually copying files. Unzip gooletest-release-1.8.0, then
cd googletest-release-1.8.0
# create a build directory
mkdir build
cd build
# build configuration
cmake .. -DBUILD_GTEST=ON -DBUILD_SHARED_LIBS=ON
# build it
make
# installation
sudo make install
Afterwards, you can easily incorporate gtest in your project with the cmake commands
# sets GTEST_INCLUDE_DIRS and GTEST_LIBRARIES
find_package( GTest REQUIRED )
# adds the gtest include directory
include_directories( ${GTEST_INCLUDE_DIRS} )
# links gtest
target_link_libraries( yourTestApp ${GTEST_LIBRARIES} )