17

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?

stevendesu
  • 15,753
  • 22
  • 105
  • 182
  • Try using the target based API. `target_link_libraries(you_exe PUBLIC boost::lambda)` This single command should add the include directory as well as linking libraries. – Guillaume Racicot Feb 07 '19 at 21:34
  • @GuillaumeRacicot https://imgur.com/ChwBo57 No luck – stevendesu Feb 07 '19 at 21:39
  • To work with target you must first find the boost package: `find_package(Boost COMPONENT lambda REQUIRED)` – Guillaume Racicot Feb 07 '19 at 21:42
  • So `find_package(Boot COMPONENTS lambda REQUIRED)` threw the error "Unable to find requested Boost libraries. Please set BOOST_ROOT to the root directory...". I then added `set(BOOST_ROOT "C:\\local\\boost_1_69_0")` and for the first time saw "Boost version: 1.69.0" (making progress!) followed shortly by "Could not find the following Boost libraries: lambda. No Boost libraries were found. You may need to set BOOST_LIBRARYDIR...". I tried `set(BOOST_LIBRARYDIR "${BOOST_ROOT}\\libs")` (among other things) but no luck yet – stevendesu Feb 07 '19 at 21:48
  • I had a similar error the first time trying with boost. I'm not with my main computer right now, I'll let you know when I have physical access to it. I know I managed to make it work. From what I remember, it was cmake not detecting the newer boost versions properly, but I cannot be 100% sure right now. – Guillaume Racicot Feb 07 '19 at 21:59
  • I'm fiddling around with my setup, I think I'll have an answer for you. It was indeed the version (for me) – Guillaume Racicot Feb 08 '19 at 01:45
  • CMake 3.8 is too old to work with Boost 1.67. See https://stackoverflow.com/a/42124857/2799037 – usr1234567 Mar 03 '21 at 18:57

4 Answers4

10

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.

vre
  • 6,041
  • 1
  • 25
  • 39
  • From what I can tell, the "Download Latest Version" link at the top just downloads an older version (1.66.0 versus 1.67.0) of what I already had -- a directory containing several Boost header files, docs, etc. Given you said to download the Boost "binary", I assume you meant one of the EXE files to be found inside the version folders. Clicking on "1.69.0" it revealed several EXEs -- how do I know which one to download? I'm not sure what my MSVC version is (or how to figure out): https://imgur.com/3TRTJgl – stevendesu Feb 07 '19 at 21:07
  • It is MSVC 14.1 for your compiler Visual Studio 15 2017. See here: https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/ – vre Feb 07 '19 at 21:09
  • Downloaded `boost_1_69_0-msvc-14.1-64`, double-clicked the executable, agreed to run an app from an unknown publisher, Windows "Antimalware Service Executable" began to lock up my entire system. If this continues for too much longer then I'll just disable antimalware / antivirus and try again. Right now `explorer.exe` is unresponsive – stevendesu Feb 07 '19 at 21:17
  • If you install Boost 64bit version you'll gonna need to adapt the generator too: it is `Visual Studio 15 2017 Win64` then. The size of the Boost install executable is 200+ MB and contains literally dozens of tiny, small and medium sized files. This maaay take some time. – vre Feb 07 '19 at 21:22
  • After my computer was unresponsive for a solid 20 minutes I killed the power, rebooted, and tried again (without disabling anti-virus first, to see if it was a fluke that it froze for so long). Explorer froze again. 10 minutes later I did another hard shutdown, reboot, disabled anti-virus, and ran it -- worked immediately. Then tried your CMakeLists.txt, still no good: https://imgur.com/sz8mbnu – stevendesu Feb 07 '19 at 21:44
  • I tend to forget adding the `PUBLIC`, `PRIVATE` or `INTERFACE` keyword after the target. So it should read `target_include_directories(CMakeProject2 PUBLIC ${Boost_INCLUDE_DIRS})` – vre Feb 07 '19 at 21:49
  • With the `target_include_directories` line updated, I'm now at the same point I was with @GuillaumeRacicot's answer: "No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT t othe location of Boost." – stevendesu Feb 07 '19 at 21:52
  • ***UPDATE:*** After re-reading your post (potentially with your new edits) I noticed the "If your libraries are header only you need to omit them from the `find_package(Boost ...)` call". I removed `lambda` from the call and it worked!... (double update: ***seems*** to have worked. No errors in the console now, but when I try to compile Visual Studio locks up) – stevendesu Feb 07 '19 at 21:54
  • Yeah that's the problem with Boost header only libraries. They **must** not be mentioned in the components call! I'll make that sentence more prominent in the answer. – vre Feb 07 '19 at 21:56
  • So after restarting Visual Studio I've got a new issue, not sure if it's related or not... There are no longer any errors in the error console, but I can't build the project at all! When I select "Current Document" (the default) it displays "Select Startup Item..." and attempting to build yields an error: https://imgur.com/r1MHXFw https://imgur.com/m7fy43o When I select "CMakeProject2.exe" I get the error "The startup project could not be launched." https://imgur.com/9IwIKG9 – stevendesu Feb 07 '19 at 22:00
  • Set in the solution explorer the project your yre trying to execute as startup project. By default CMake sets ALL_BUILD that is not connected to an executable or library. – vre Feb 07 '19 at 22:03
  • Not sure how to set the "startup project". I don't use Visual Studio much :( Clicking around a lot I was able to accidentally fix it, but I don't know why it fixed it. I clicked the drop-down beside the build target and selected "Manage Configurations" and created an x64-Release configuration. Doing so caused the x64-Debug configuration to disappear, and created a new `CMakeSettings.json` file. I deleted the `CMakeSettings.json` file, x64-Debug reappeared, and suddenly "Current Document" worked and I could build the project! – stevendesu Feb 07 '19 at 22:08
  • Just looked again at the images. Did you called CMake from the command line or did you opened the CMake file from the Visual Studio. That's a big difference. I noticed that inside ninja is called as build tool whereas it should be MSBuild. (at least in Visual Studio 2015 this is the case, don't know about 2017.) I always use the command line for CMake and later open the created solution. – vre Feb 07 '19 at 22:08
  • I've been editing the CMake files within Visual Studio, and every time I hit save it automatically re-parses the file updates Intellisense. Looking at the command line, I do see `-G "Ninja"`, whatever that means. Is that what was breaking my build? – stevendesu Feb 07 '19 at 22:10
  • Don't know, maybe. Visual Studio changed alot from version 2015 to 2017 so I'm only guessing. They truly integrated the CMake stuff, but there are some differences to the command line version IIRC. – vre Feb 07 '19 at 22:18
  • `To see which libraries are not header only see this post.` has a broken link. No idea where it used to point. Maybe https://stackoverflow.com/q/13604090/1938163 ? – Marco A. Mar 03 '21 at 16:25
  • @MarcoA. Thanks for notification. Fixed now. – vre Mar 03 '21 at 16:47
4

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

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • If your CMake version 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. – vre Feb 08 '19 at 08:08
  • @vre thank you for this info, I'll try it on my project. – Guillaume Racicot Feb 08 '19 at 14:03
1

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.

BugHunterUK
  • 8,346
  • 16
  • 65
  • 121
-3

Add a target_include_directories(CMakeProject2 PRIVATE .) into your CMakeList.txt.

The . is the relative path of boost/lambda/lambda.hpp from CMakeLists.txt

And you should not add any .hpp file to the source list.

rene-d
  • 343
  • 1
  • 6
  • Well, I look at your screenshot... first the target_include_directories() command is to add an include dir to a cmake target (i.e. the executable CMakeProject2). and has to be put *after* add_executable(). Also it's better to put explicit filenames in add_executable(), not a glob. In your case: add_executable(CMakeProject2 CMakeProject2.cpp) . – rene-d Feb 07 '19 at 21:02
  • But it doesn't really explain why boost/lambda/lambda.hpp can't be found. – rene-d Feb 07 '19 at 21:06
  • https://imgur.com/l7ywL6e - Still throwing an error after moving `target_include_directories` and replacing the `glob` with explicit filenames – stevendesu Feb 07 '19 at 21:13
  • The problem intrigues me... So I have just set up a project like yours... tested with cmake 3.6 (Linux) and 3.13 (macOS) - ok it's not vs2017 and windows. And it works, as you can guess. https://github.com/rene-d/test-CMakeProject2. – rene-d Feb 07 '19 at 21:47
  • Sounds like the issues I had with Clang++ (see: https://stackoverflow.com/questions/54521402/locating-iostream-in-clang) I ended up joining the Clang IRC and debugging for ***several hours*** and no one could figure it out. Sometimes I feel like this is my life: https://xkcd.com/2083/ – stevendesu Feb 07 '19 at 21:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188079/discussion-between-rene-d-and-stevendesu). – rene-d Feb 07 '19 at 21:57