Joseph Gagnon
Joseph Gagnon

Reputation: 2115

CMake: Visual Studio build looks for wrong library

I have a project that uses CMake to perform the build on both Linux and Windows platforms. Some of the components of the project require some Boost libraries. Many of the components are built as shared libraries (.dll/.so). When I installed Boost, I opted to build the shared libraries.

Here is the problem:

After running CMake on Windows, openening the VS solution generated and running the build, the components that have the dependency on Boost fail with the error that a library cannot be found. For example:

LINK : fatal error LNK1104: cannot open file 'libboost_thread-vc100-mt-gd-1_58.lib'

Sure enough, there is no file by that name in the Boost lib directory. There are shared library files for that library: boost_thread-vc100-mt-gd-1_58.dll (and .lib).

I assume that the "lib..." variant represents a static library. Why is it looking for that when I specified to not use static libs from Boost? There appear to be no problems on the Linux side.

Here are some excerpts from my CMakeLists.txt files:

Project level:

...
# Set to use shared libraries from Boost.
set(Boost_USE_STATIC_LIBS OFF)
#set(Boost_USE_STATIC_RUNTIME OFF)   <- I also tried with this uncommented - no difference
#set(Boost_DEBUG ON)

if(WIN32)
  find_package(Boost 1.58 REQUIRED system thread date_time chrono)
elseif(UNIX)
  find_package(Boost 1.58 REQUIRED)
endif()

include_directories(${Boost_INCLUDE_DIRS})
...

Component that needs Boost:

set(source_files
  ...)

# Create library from source files.
add_library(lib_target SHARED ${source_files})

target_link_libraries(lib_target ${Boost_LIBRARIES})

It looks like someone else had the same (or similar) problem: cmake can't find boost libraries because it looks for the wrong file names. I built my Boost with link=shared.

Upvotes: 2

Views: 2673

Answers (1)

bames53
bames53

Reputation: 88155

The problem is Boost's use of the auto-linking feature of link.exe and the fact in order to choose between static and dynamic linking, you're expected to set some preprocessor definitions. That is, the headers will still try to pull in static libraries unless you either disable auto-linking, or define -DBOOST_ALL_DYN_LINK (or various -DBOOST_<WHATEVER>_DYN_LINK preprocessor definitions.)

To disable boost headers' auto-linking, set a preprocessor define -DBOOST_ALL_NO_LIB. Since CMake is already taking care of finding the libraries and setting flags, auto-linking really isn't very useful with CMake. However you don't have to disable it to get dynamic linking to work.

If you want to use dynamic linking, then set Boost_USE_STATIC_LIBS to OFF and add the preprocessor definition -DBOOST_ALL_DYN_LINK. -DBOOST_ALL_DYN_LINK will both enable __declspec(dllimport) on the declarations in boost headers, and make the auto-linking functionality (if enabled) depend on dlls instead of static libs.

Note that some boost libraries don't offer a choice between static and dynamic linking and won't be affected by -DBOOST_ALL_DYN_LINK. I haven't tried any so I don't know whether the CMake FindBoost module deals with this.

If you want to use static linking, set Boost_USE_STATIC_LIBS to ON. Boost headers use static linking by default so it doesn't matter whether you leave auto-linking enabled or not if you want static linking.

If you want to see what libraries Boost's auto-linking is demanding, set a preprocessor define -DBOOST_LIB_DIAGNOSTIC or use the FindBoost module's ${Boost_LIB_DIAGNOSTIC_DEFINITIONS}". This will cause the headers to output the names of the libraries they ask for as they are processed.


An example CMakeLists.txt fragment:

set(Boost_USE_STATIC_LIBS OFF)
find_package(Boost 1.58 REQUIRED system thread date_time chrono)

set(source_files ...)
add_library(lib_target SHARED ${source_files})

target_compile_definitions(lib_target PRIVATE -DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK)

target_include_directories(lib_target PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(lib_target PRIVATE ${Boost_LIBRARIES})

Here's an updated example that uses just targets instead of setting defines and include directories:

find_package(Boost 1.67 REQUIRED system thread date_time chrono)

set(source_files ...)
add_library(lib_target SHARED ${source_files})

target_link_libraries(lib_target PRIVATE
    Boost::disable_autolinking
    Boost::dynamic_linking
    Boost::boost Boost::system Boost::thread Boost::date_time Boost::chrono)

Upvotes: 5

Related Questions