Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C++: CMake not working with Homebrew Boost on OSX #217

Closed
araybold opened this issue Feb 18, 2019 · 7 comments
Closed

C++: CMake not working with Homebrew Boost on OSX #217

araybold opened this issue Feb 18, 2019 · 7 comments

Comments

@araybold
Copy link

araybold commented Feb 18, 2019

After installing Homebrew boost, running CMake with the generator 'Unix Makefiles' produces this error:

-- Boost version: 1.68.0
-- Found the following Boost libraries:
--   unit_test_framework
--   date_time
--   regex
-- Configuring done
CMake Error at CMakeLists.txt:27 (add_executable):
  Target "hello-world" links to target "Boost::unit_test_framework" but the
  target was not found.  Perhaps a find_package() call is missing for an
  IMPORTED target, or an ALIAS target is missing?

Similarly for date_time and regex.

There does not seem to be anything unusual about where the libraries are:

$ find /usr/local/lib -name '*[Bb]oost*' | grep unit_test_framework
/usr/local/lib/libboost_unit_test_framework-mt.a
/usr/local/lib/libboost_unit_test_framework-mt.dylib
/usr/local/lib/libboost_unit_test_framework.a
/usr/local/lib/libboost_unit_test_framework.dylib

I am able to compile and link a working program using boost from the command line, without any arguments to specify the location of headers or libraries:

$ cat boostCheck.cpp
#include <iostream>
#include <boost/version.hpp>

int main() {
  std::cout << BOOST_VERSION << '\n';
}

$ g++ boostCheck.cpp
$ a.out
106800
@KevinWMatthews
Copy link
Contributor

Hi @araybold ,

That's odd - CMake finds Boost and all three libraries but then fails to link them into the target. Typically find_package() is used to guarantee that target_link_libraries() succeeds....

I'm curious to see what happens if I rig up a Docker container with Boost 1.68.0 and your version of CMake. What version of CMake are you using?

@KevinWMatthews
Copy link
Contributor

Can you add some print statements to CMakeLists.txt? I'm curious to see the output of something like this:

message(STATUS "---------------------")
message(STATUS "Boost_FOUND: ${Boost_FOUND}")
message(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
message(STATUS "Boost_LIBRARY_DIRS: ${Boost_LIBRARY_DIRS}")
message(STATUS "Boost_LIBRARIES: ${Boost_LIBRARIES}")
message(STATUS "---------------------")

This needs to be placed after the call to find_package() but before the call to target_link_libraries().

@araybold
Copy link
Author

Hi @KevinWMatthews

My CMake version is 3.7.2.

This is the full output from running CMake with the CMakeLists.txt modified as you asked:

$ cmake -G 'Unix Makefiles' ..
CMake Warning at /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:761 (message):
  Imported targets not available for Boost version 106800
Call Stack (most recent call first):
  /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:865 (_Boost_COMPONENT_DEPENDENCIES)
  /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:1454 (_Boost_MISSING_DEPENDENCIES)
  CMakeLists.txt:14 (find_package)


CMake Warning at /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:761 (message):
  Imported targets not available for Boost version 106800
Call Stack (most recent call first):
  /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:865 (_Boost_COMPONENT_DEPENDENCIES)
  /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:1454 (_Boost_MISSING_DEPENDENCIES)
  CMakeLists.txt:14 (find_package)


CMake Warning at /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:761 (message):
  Imported targets not available for Boost version 106800
Call Stack (most recent call first):
  /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:865 (_Boost_COMPONENT_DEPENDENCIES)
  /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:1454 (_Boost_MISSING_DEPENDENCIES)
  CMakeLists.txt:14 (find_package)


-- Boost version: 1.68.0
-- Found the following Boost libraries:
--   unit_test_framework
--   date_time
--   regex
-- ---------------------
-- Boost_FOUND: 1
-- Boost_INCLUDE_DIRS: /usr/local/include
-- Boost_LIBRARY_DIRS: /usr/local/lib
-- Boost_LIBRARIES: /usr/local/lib/libboost_unit_test_framework-mt.a;/usr/local/lib/libboost_date_time-mt.a;/usr/local/lib/libboost_regex-mt.a
-- ---------------------
-- Configuring done
CMake Error at CMakeLists.txt:35 (add_executable):
  Target "hello-world" links to target "Boost::unit_test_framework" but the
  target was not found.  Perhaps a find_package() call is missing for an
  IMPORTED target, or an ALIAS target is missing?


CMake Error at CMakeLists.txt:35 (add_executable):
  Target "hello-world" links to target "Boost::date_time" but the target was
  not found.  Perhaps a find_package() call is missing for an IMPORTED
  target, or an ALIAS target is missing?


CMake Error at CMakeLists.txt:35 (add_executable):
  Target "hello-world" links to target "Boost::regex" but the target was not
  found.  Perhaps a find_package() call is missing for an IMPORTED target, or
  an ALIAS target is missing?


-- Generating done
-- Build files have been written to: /Users/me/Dev/Exercism/cpp/hello-world/build

These are the Boost unit test framework libraries available in /usr/local/lib:

$ ls -1 /usr/local/lib/libboost_unit_test_framework*
/usr/local/lib/libboost_unit_test_framework-mt.a
/usr/local/lib/libboost_unit_test_framework-mt.dylib
/usr/local/lib/libboost_unit_test_framework.a
/usr/local/lib/libboost_unit_test_framework.dylib

I see that the messages I added only show the *-mt.a form of the library. If I am following correctly, the exercise will need the dynamic library for at least unit_test_framework, though this may be moot until CMake can agree with itself about whether it has found some version of the required Boost libraries.

At the command line, without using CMake, I have successfully built and run a test program that uses dynamically-linking versions of these Homebrew-installed Boost libraries, though I have not yet tried building a unit test framework program.

@KevinWMatthews
Copy link
Contributor

KevinWMatthews commented Feb 22, 2019

You're right, your example doesn't actually link against Boost's unit test library.

If you compile this:

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(test_hello)
{
    BOOST_REQUIRE_EQUAL("Hello, World!", "should fail");
}

without any flags

$ g++ <filename>

I'm guessing it will throw a healthy set of linker errors. My Linux box needs:

$ g++ <filename> -lboost_unit_test_framework

I have boost installed to system so I don't need to add -I and -L flags. I think your system will be the same.

That should link, but likely fails to compile:

`undefined reference to 'main'`

It seems that #define BOOST_TEST_MAIN requires using static libraries. It should compile if you add --static:

$ g++ <filename> -lboost_unit_test_framework --static

The program should run but the test will fail:

$ ./a.out
Running 1 test case...
boost_check_unit_test.cpp(6): fatal error: in "test_hello": critical check "Hello, World!" == "should fail" has failed [Hello, World! != should fail]

*** 1 failure is detected in the test module "Master Test Suite"

@KevinWMatthews
Copy link
Contributor

Interesting, I think this is the root of the problem:

CMake Warning at /opt/local/share/cmake-3.7/Modules/FindBoost.cmake:761 (message):
  Imported targets not available for Boost version 106800

It looks like CMake 3.7.2 doesn't support Boost 1.68.0.

I've heard of some history here [it might even be accurate ;)]. In an ideal world, Boost would provide explicit CMake support; it's their package so they know best what is required to link against each version. Apparently they don't, so CMake itself steps up and builds in a module, FindBoost.cmake, to help find Boost libraries. This goes out of date each time Boost releases a new version, so we can get in a situation like yours: CMake is too old to properly find Boost.

The most straightforward solution is to upgrade CMake. Is that feasible for your system?

I think it's possible to install a second version of CMake on a system without ill effects (I did it in a container), but then you need to remember to use the correct executable.

If so, think version 3.12 should work. There is a reference to this issue on Stack Overflow. This states that 3.13 is required, but FindBoost.cmake from version 3.12 looks like it will to work.

@araybold
Copy link
Author

araybold commented Feb 25, 2019

Thanks - upgrading CMake (to the current Homebrew version, 3.13.4) solved this problem.

Perhaps the instructions could be modified to prominently note the cross-dependency between Boost and CMake, as, in my case, each was more recent than its individual oldest viable version.

While this is somewhat off-topic, I have found that one can link statically by explicitly specifying the full paths of the Boost libraries you want to link from (this is how CMake does it.) If you try using -L and -l, the dynamic libraries will be used instead, as they are in the same directory, and dynamic linking is the default. If you try to change this with -static, it is missing at least crt0.o (the C(++) runtime?), which is not available in static form. One can use -L and -l (without -static) by creating a separate directory containing only the static Boost libraries (or links to them, which will be advantageous when one upgrades Boost).

$ g++ -Wall -Werror -std=c++11 -o hello-world \
      hello_world_test.cpp hello_world.cpp \
      /usr/local/lib/libboost_unit_test_framework-mt.a /usr/local/lib/libboost_date_time-mt.a /usr/local/lib/libboost_regex-mt.a

$./hello-world 
Running 1 test case...

*** No errors detected

$ g++ -Wall -Werror -std=c++11 -o hello-world \
      -L ./staticlib \
      -l boost_unit_test_framework-mt -l boost_date_time-mt -l boost_regex-mt \
      hello_world_test.cpp hello_world.cpp

$./hello-world 
Running 1 test case...

*** No errors detected

@KevinWMatthews
Copy link
Contributor

@araybold Glad that fixed the issue.

Documenting the Boost/CMake interplay is a good idea. Long term we're considering moving away from Boost because it tends to be difficult to configure.

Interesting - using --static worked fine in my container, but it's a Linux system. I think this highlights why we use build systems - CMake can figure out the implementation-specific details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants