7

Been looking around all day for a solution but no joy.

I have a CMake solution with 2 projects. The one is a static library which links to boost, and the other is an executable which links to boost and my own static library. Problem is: In Linux it compiles fine with gcc. But in VS2008 I get the following type of linker errors for program_options only.

libboost_program_options-vc90-mt-gd-1_46_1.lib(options_description.obj) : error LNK2005: "public: class boost::program_options::options_description_easy_init & __thiscall boost::program_options::options_description_easy_init::operator()(char const *,char const *)" (??Roptions_description_easy_init@program_options@boost@@QAEAAV012@PBD0@Z) already defined in boost_program_options-vc90-mt-gd-1_46_1.lib(boost_program_options-vc90-mt-gd-1_46_1.dll)

Looks like it's linking to both the static lib and the dll lib...but why?

So I have a solution directory with a CMakeFile like this:

    CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
    PROJECT( BBlockTools )

    SET( TopDir ${CMAKE_CURRENT_SOURCE_DIR} )
    ADD_SUBDIRECTORY( Utilities )
    ADD_SUBDIRECTORY( BBlockFixer )

And then the two project directories. Utilities is a static library and is created by following CMakeFile:

PROJECT( Utilities )

SET(Boost_USE_STATIC_LIBS ON)
FIND_PACKAGE(Boost COMPONENTS system program_options REQUIRED)
LINK_DIRECTORIES ( ${Boost_LIBRARY_DIRS} )
INCLUDE_DIRECTORIES ( ${Boost_INCLUDE_DIRS} )

SET( src_h Utilities.h )
SET( src_cpp Utilities.cpp )

ADD_LIBRARY( Utilities STATIC ${src_h} ${src_cpp} )

TARGET_LINK_LIBRARIES( Utilities 
  ${Boost_SYSTEM_LIBRARY}
  ${Boost_PROGRAM_OPTIONS_LIBRARY}
  ${Boost_LIBRARIES}
)

And the second project created by this CMakeFile:

PROJECT( BBlockFixer )

SET(Boost_USE_STATIC_LIBS ON)
FIND_PACKAGE(Boost COMPONENTS system filesystem program_options REQUIRED)
LINK_DIRECTORIES ( ${BBlockTools_BINARY_DIR}/Utilities/Debug ${Boost_LIBRARY_DIRS} )
INCLUDE_DIRECTORIES ( ${TopDir} ${Boost_INCLUDE_DIRS} )

SET( src_cpp fixerMain.cpp )

ADD_EXECUTABLE( BBlockFixer ${src_cpp} )

TARGET_LINK_LIBRARIES( BBlockFixer 
  Utilities
  ${Boost_FILESYSTEM_LIBRARY}
  ${Boost_PROGRAM_OPTIONS_LIBRARY}
  ${Boost_SYSTEM_LIBRARY}
  ${Boost_LIBRARIES}
)

I'm new to CMake so I might be doing something very bad but I really can't find out what's going on. I started playing around with the VS Project(Fixer) like removing the link input to program_options which fixes the problem(until I run cmake again). But I think that isn't the solution since from how it looks it's linking both to the dll lib and to the static lib for some reason... I tried removing ${Boost_PROGRAM_OPTIONS_LIBRARY} from BBlockFixer from TARGET_LINK_LIBRARIES and program_options from FIND_PACKAGE but doesnt help.

From what I understand in CMake my BBlockFixer inherits the links to program_options from my static lib which should be all fine. But where did this boost_program_options-vc90-mt-gd-1_46_1.lib(boost_program_options-vc90-mt-gd-1_46_1.dll) get linked into my project?

Any help would be appreciated because I'm becoming desperate. It can't really be that hard...

PS. this TopDir I set is so that I can include the .h file from the Utilities. But I'm sure there must be a cleaner way to do it or?

Stefan
  • 71
  • 1
  • 2

1 Answers1

7

My guess is that you are still auto-linking: On MSVC, boost uses some pragma's to automically instruct the compiler to link to the necessary libraries and there is then no need to specify all the link-targets manually to the linker. Of course, this bites with the dependency-resolution of CMake and you specifying target_link_libraries manually.

Take a look at my answer to a similar question where I suggested the following extra definition to disable auto-linking:

add_definition( -DBOOST_ALL_NO_LIB )

You may need to add the following when linking dynamically and depending on the Boost version and the components:

add_definitions( -DBOOST_ALL_DYN_LINK )

Note also that you specify the Boost components you want in the find_package() call and then specify them again manually in your target_link_libraries() call. Depending a bit on your need, you could also replace this with

target_link_libraries( ${Boost_LIBRARIES} )
Community
  • 1
  • 1
André
  • 18,348
  • 6
  • 60
  • 74
  • Thanks for your answer! One second ago I solved the problem by moving the dynamic libraries out of the boost libs folder. What I realized is that cmake(FindBoost.cmake?) only found the dynamic libraries in that folder even though I told it to link to the static libs. Seems like it has a priority to select the dynamic ones if it finds them first. In linux apparently I only had the static libraries of boost and that's why no clashes occured. Am I right that this is the effect of what you just told me about auto-linking? I will try disabling autolinking now :) thanks, Stefan – Stefan Jul 08 '11 at 13:00
  • Hm I tried putting add_definitions( -DBOOST_ALL_NO_LIB ) in all 3 of my CMakeList files but didn't change the fact that CMake prefers the dynamic libraries. I guess I'll stick to my moving the dynamic libs out of the boost lib folder – Stefan Jul 08 '11 at 13:05
  • Oho!!! I actually hid the fact from you that I had other projects too in my solution. In some of them I had forgoten to put SET(Boost_USE_STATIC_LIBS ON). For some reason that convinced cmake to select the dynamic libraries instead of the static at config step for all my projects. Great. Now that I put it everywhere it's fine. – Stefan Jul 08 '11 at 13:14
  • You know, you can put if ( NOT Boost_FOUND ) tests around your Boost-sections. This would prevent that problem, at the cost of needing to find all boost-components in one go. – André Jul 08 '11 at 14:37
  • My impression was that boost was found but the wrong version of it(dynamic instead of static). So I guess it wouldn't help to put this if or? – Stefan Jul 12 '11 at 07:22
  • Yes, you are right and I agree it would not help with distinguishing static from dynamic. I intended it more as a debugging help, because FindBoost will be called only once. – André Jul 12 '11 at 07:27