Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding Boost to CMake project?

Background

I'm a complete newb with C++ and I've been running into one headache after another, so forgive me if this is incredibly simple and I'm just that dumb...

I have a project that should ultimately compile and run in Linux. Unfortunately after lots of issues with my C++ development environemnt (still unresolved), I gave up on trying to develop in Linux and moved to Windows Visual Studio 2017. My hope was to get my code working in Windows and then, since C++ is supposedly a portable language, it should just work in Linux with minimal changes.

For a day or so Visual Studio seemed to be working. I could write code, hit "compile", and like magic it would run. I threw together a few classes to construct a directed acyclic graph, used the standard library for a hash table, and then I tried to create a socket...

Windows and Linux use different libraries for sockets (<sys/socket.h> vs <winsock.h>) so I needed some way to abstract the differences, and I preferred a well-established standard. Googling around I found the Boost library that seemed to fit my needs... That's when everything went to hell.

My project setup

Because this project will be developed across a variety of platforms and IDEs (some people use Windows + Visual Studio, some people use Mac + Eclipse, and others use Linux + VIM) I opted to make it a CMake project. After several hours of reading and learning and research it seems like CMake should give me what I want (convenient and reproducible cross-platform builds with little or no dependency issues)

Creating a new project, pt 1 Creating a new project, pt 2

My source code (directly from the Boost Getting Started on Windows guide) is as follows:

CMakeProject2.cpp

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    using namespace boost::lambda;
    typedef std::istream_iterator<int> in;

    std::for_each(
        in(std::cin), in(), std::cout << (_1 * 3) << " ");
}

Per the Boost Getting Started on Windows guide, I downloaded Boost from here:

https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.zip

(interestingly, the Getting Started guide is titled "Boost Getting Started on Windows - 1.69.0", yet it linked to Boost versions 1.67.0)

After downloading and extracting the ZIP file, I had a whole mess of files - but no idea where to put them:

Boost download directory

Attempts to Get It Working So Far

I tried to add the Boost library to my project, but none of the expected menu options were available:

Right-clicking on project in Solution Explorer

Although I couldn't find a single page that warns you of this gotcha, apparently CMake projects don't have the elusive "Properties" window - and instead third party libraries must somehow be included via the CMakeLists.txt file

For starters, I copied the entire 540 MB contents of the Boost ZIP file to within my project under the folder name "Boost":

Boost in project

I then tried a series of different CMakeList.txt commands:

Per How do you add Boost libraries in CMakeLists.txt?:

set(Boost_USE_STATIC_LIBS OFF) 
set(Boost_USE_MULTITHREADED ON)  
set(Boost_USE_STATIC_RUNTIME OFF) 
find_package(Boost REQUIRED COMPONENTS lambda) 

if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS}) 
    add_executable(CMakeProject2 "CMakeProject2.cpp" "CMakeProject2.h") 
    target_link_libraries(CMakeProject2 ${Boost_LIBRARIES})
endif()

Per https://www.selectiveintellect.net/blog/2016/7/29/using-cmake-to-add-third-party-libraries-to-your-project-1:

include("Boost")
add_subdirectory("Boost")
add_subdirectory("boost")
add_subdirectory("Boost/boost")
add_subdirectory("Boost/boost/lambda")

target_link_libraries(boost)
target_link_libraries(Boost)

Per https://cmake.org/pipermail/cmake/2009-November/033249.html:

SET (Boost_FIND_REQUIRED TRUE)
SET (Boost_FIND_QUIETLY TRUE)
SET (Boost_DEBUG FALSE)
set (Boost_USE_MULTITHREADED TRUE)
set (Boost_USE_STATIC_LIBS TRUE)
SET (Boost_ADDITIONAL_VERSIONS "1.67" "1.67.0")

FIND_PACKAGE(Boost COMPONENTS  lambda)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})

I tried several other incantations (not being familiar with C++ or CMake as a tool) and either received errors from CMakeLists.txt, or from CMakeProject2.cpp about cannot open source file "boost/lambda/lambda.hpp". In fact, with regards to those "CMakeLists.txt" errors, after adding enough lines to my file I started to crash Visual Studio regularly. Note that I have an 8th generation i7, 32 gigabytes of RAM, and an M.2 NVMe hard drive -- so I was rather impressed that a few lines in a text file pissed off Microsoft enough to lock up my computer for 10 minutes at a time.

Failing all of that, I tried copying the files I needed directly into my project:

New project setup

Now, again, I'm new to C/C++ development and everything that can go wrong has gone wrong. So far I've spent almost two weeks and barely managed to compile a single "Hello, World" app across two computers, three IDEs, and four compilers. I've yet to have any success including a third party library, from anywhere, of any popularity level or simplicity level, and actually compile a functioning program that references the library. So believe me when I say: I don't know the difference between a "header-only library" and... whatever the alternative is. I just know that, according to the Boost Getting Started on Windows guide, most of Boost is "headers only" and therefore I shouldn't have any build step -- it should be simple to use it. Furthermore, this example (using boost::lambda) is - per their instructions - a header-only library, and should therefore be extremely easy to use.

I now updated the source code slightly to look in the current directory, instead of looking in the system include directory (which, as far as I'm aware at this point, doesn't exist in Windows):

#include "boost/lambda/lambda.hpp"
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    using namespace boost::lambda;
    typedef std::istream_iterator<int> in;

    std::for_each(
        in(std::cin), in(), std::cout << (_1 * 3) << " ");
}

Now I can manually verify that this file exists (the file CMakeProject2\CMakeProject2\boost\lambda\lambda.hpp can be found in File Explorer) - yet I'm still getting errors:

cannot open source file "boost/lambda/lambda.hpp"

Some further Googling led me to update my CMakeLists.txt file once more, putting it in its current form:

# CMakeList.txt : CMake project for CMakeProject2, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)

# Add source to this project's executable.
file(GLOB CMakeProject2_SRC
    "*.h"
    "*.cpp"
    "**/*.h"
    "**/*.cpp"
    "**/*.hpp"
    "boost/lambda/lambda.hpp"
)
add_executable (CMakeProject2 ${CMakeProject2_SRC})
#add_executable (CMakeProject2 "CMakeProject2.cpp" "CMakeProject2.h")

# TODO: Add tests and install targets if needed.

Despite this I'm still getting the error:

cannot open source file "boost/lambda/lambda.hpp"

At this point I'm ripping my hair out. What am I doing wrong? What do I not know? How is something as simple as the Boost-equivalent of "Hello, World" not working for me?

like image 453
stevendesu Avatar asked Feb 07 '19 20:02

stevendesu


People also ask

Can I build Boost with CMake?

One of my current projects relies on Boost. Python, which requires a more recent version of Boost (1.64) than the one (1.54) provided by my Linux distribution (Ubuntu 14.04).

How do you add a Boost to Cmakelist?

For CMake, you need to add boost_program_options to the list of libraries, and IIRC this is done via SET(liblist boost_program_options) in your CMakeLists. txt .

Where do I put Boost?

Install Boost (Windows) Download the source code from http://www.boost.org/users/download/. Extract in a Boost folder located at C:\ or C:\Program files so that CMake find-modules can detect it. Invoke the command line and navigate to the extracted folder (e.g. cd C:\Boost\boost_1_63_0 ).


3 Answers

I'm using CMake 3.22 with Boost version 1.78.

The simplest solution is to set the Boost_INCLUDE_DIR when calling Cmake:

cmake -DBoost_INCLUDE_DIR=boost

Pass the directory to where the Boost libraries are. If you're using Visual Studio you can also set this in your CMake Settings:

enter image description here

Or, in the CMakeSettings.json file:

"cmakeCommandArgs": "-DBoost_INCLUDE_DIR=boost",

In my opinion, this is better than using the set function because you're not hard coding the path.

like image 94
BugHunterUK Avatar answered Oct 19 '22 18:10

BugHunterUK


Following recipe should work

Download Boost binaries from official boost binaries location and install to say C:\Boost

Most times you do not need to build Boost on your own.

Your CMakeLists.txt should look like follows

cmake_minimum_required (VERSION 3.8)

project(boostAndCMake)

set(BOOST_ROOT "C:\Boost") # either set it here or from the command line  
set(Boost_USE_STATIC_LIBS OFF) 
set(Boost_USE_MULTITHREADED ON)  
set(Boost_USE_STATIC_RUNTIME OFF) 
find_package(Boost REQUIRED COMPONENTS system) # header only libraries must not be added here

add_executable(CMakeProject2 CMakeProject2.cpp CMakeProject2.h) 
target_include_directories(CMakeProject2 PUBLIC ${Boost_INCLUDE_DIRS}) 
target_link_libraries(CMakeProject2 ${Boost_LIBRARIES})

Because we used REQUIRED on the find_package call, CMake will fail execution and skip the rest of the script if it cannot be found. So no need to check Boost_FOUND. You need to check it, when you omit REQUIRED.

Now from the command line call from the directory where your script resides:

cmake -H. -Bbuildit -G "Visual Studio 15 2017" -DBOOST_ROOT=C:\Boost 

This creates a build directory named buildit in the current directory, further creates a solution for Visual Studio 2017 inside the build directory and provides the setting for the variable BOOST_ROOT that is used in the find_package call to identify the Boost directory on your computer. To see what options are available on the find_package(Boost ...) call see FindBoost documentation in CMake.

Header Only Libraries

If your libraries are header only you need to omit them from the find_package(Boost ...) call. To see which libraries are not header only see this post.

Using newer Boost versions

If your CMake installation cannot find the requested version, e.g. 1.69.0, but supports the naming scheme of the more recent Boost version you can use it with set(Boost_ADDITIONAL_VERSIONS "1.69.0" "1.69"). Last change of the Boost naming scheme was from 1.65.1 to 1.66.

like image 9
vre Avatar answered Oct 19 '22 20:10

vre


Here's a working setup for Boost 1.68 with CMake 3.12. Boost 1.69 is apparently "too new" for cmake to detect it properly. Since boost is not buildable by cmake, cmake itself must provide a FindBoost.cmake module that must keep up with boost changes.

So anyway, the CMakeLists.txt is as small as this:

cmake_minimum_required(VERSION 3.11)

project(foobar)

find_package(Boost 1.68 REQUIRED)
add_executable(foo foo.cpp)
target_link_libraries(foo PUBLIC Boost::boost)

Of course, you can split it in many subdirectories.

Invoking CMake in the command line should look like this:

cmake -DCMAKE_PREFIX_PATH=path_to_local_directory ..

Where path_to_local_directory is the installation path of all library you want to depend on. It will work for Boost, nlohmann_json, glfw3, Qt, you name it *(1). For my case, it was C:/local/ and another case was ../external/ (yes, it can be a directory local to the project!)

Let's take a peek at my own C:/local/:

ls -l /c/local/
total 12
drwxr-xr-x 1 myself 197609 0 May 26  2018 boost_1_67_0/
drwxr-xr-x 1 myself 197609 0 Sep  5 02:02 boost_1_68_0/

WARNING: Ensure your compiler architecture is the same as the installed boost version. Or else cmake will simply not find it.

I think that about it. The next CMake version (3.14) should work with the latest boost.


*(1) The said library will either need to export it's CMake target or you must provide a FindXXX.cmake

like image 4
Guillaume Racicot Avatar answered Oct 19 '22 19:10

Guillaume Racicot