[CMake] find both shared and static versions?

Michael Hertling mhertling at online.de
Fri Feb 17 15:27:14 EST 2012


On 02/17/2012 01:36 AM, Dougal Sutherland wrote:
> I have an application where I want to link some targets against shared
> versions of Boost and some against static versions.
> 
> (I'd prefer shared in general, but I need to link against the static
> version of boost for my matlab mex interface, to avoid loading the
> different version of boost shipped by matlab on runtime. I'm using this
> approach<https://github.com/mariusmuja/flann/blob/master/src/matlab/CMakeLists.txt>of
> a custom target calling the mex command to compile the mex file.)
> 
> FindBoost.cmake honors the Boost_USE_STATIC_LIBS variable, but that doesn't
> quite solve it.
> 
> I've had the following ideas, none of which I'm happy with:
> 
>    1. Use -L${Boost_LIBRARY_DIRS} and then construct the name by doing a
>    string replacement from .so/.dylib to .a in ${Boost_THREAD_LIBRARY}.
>    Definitely won't work on Windows, might not work for some types of Boost
>    installations on Linux/Mac, and fails at link-time instead of
>    configure-time if the static version doesn't exist. Maybe there's an
>    equivalent transformation that'll probably work on Windows; I don't know,
>    I'm not a Windows user.
> 
>    2. Copy FindBoost.cmake to FindBoostS.cmake and replace all the
>    variables to use a BoostS prefix, as well as making the conditionals for
>    USE_STATIC_LIBS always be on; then I can run find_package(Boost) as well as
>    find_package(BoostS).
> 
>    3. There might be some trickery to approximate (2) without actually
>    modifying FindBoost, but I haven't figured it out.
> 
>    4. Modify FindBoost.cmake either to look for both dynamic and shared
>    libraries and set e.g. Boost_THREAD_LIBRARY_STATIC and
>    Boost_THREAD_LIBRARY_SHARED if found, or to add shared and static versions
>    for each component, as in
>    http://www.cmake.org/pipermail/cmake/2012-February/049142.html
> 
> (4) is obviously the "best" approach, but it's also probably much more work
> than I really want to do on this.
> 
> Any suggestions? Some other approach I haven't thought of, a way to do (3),
> a copy of (4) floating around somewhere?
> 
> Thanks,
> Dougal

You might use multiple invocations of FIND_PACKAGE(Boost ...):

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(P CXX)
SET(CMAKE_VERBOSE_MAKEFILE ON)
FILE(WRITE ${CMAKE_BINARY_DIR}/main.cxx "int main(void){return 0;}\n")
# main1:
FIND_PACKAGE(Boost COMPONENTS thread)
MESSAGE("Boost_LIBRARIES: ${Boost_LIBRARIES}")
ADD_EXECUTABLE(main1 main.cxx)
TARGET_LINK_LIBRARIES(main1 ${Boost_LIBRARIES})
# re-set up:
UNSET(Boost_LIBRARIES)
SET(Boost_USE_STATIC_LIBS ON)
#main2:
FIND_PACKAGE(Boost COMPONENTS regex)
MESSAGE("Boost_LIBRARIES: ${Boost_LIBRARIES}")
ADD_EXECUTABLE(main2 main.cxx)
TARGET_LINK_LIBRARIES(main2 ${Boost_LIBRARIES})

The main1 target is linked against the shared thread library whereas
main2 is linked against the static regex one. Note the switch in the
Boost_USE_STATIC_LIBS variable between the two FIND_PACKAGE() calls.

IMO, FindBoost.cmake behaves bad in one regard: It accumulates results
from different invocations within the same scope. For this reason, you
must intermediately unset the Boost_LIBRARIES variable - and probably
all further uncached result variables like Boost_INCLUDE_DIRS also.
Otherwise, main2 would be linked against the shared thread library,
too, although the latter has not been requested by the latest FIND_
PACKAGE() call. With Boost, AFAIK, it's sufficient to simply reset
the uncached result variables, but with {Find,Use}Qt4.cmake, e.g.,
and their QT_USE_QT* variables, it's a real annoyance to link two
targets against different sets of Qt modules within the same scope.

In summary, my vision of an improved FindBoost.cmake comprises:

- Explicitly shared and static components, e.g. "thread_shared" and
  "regex_static", so one can specifically select them even in mixed
  cases: FIND_PACKAGE(Boost COMPONENTS thread_shared regex_static)

- For convenience and backward compatibility, the usual components
  like "thread" and "regex" as always, with Boost_USE_STATIC_LIBS
  deciding whether component X is turned into X_shared or X_static.
  AFAICS, this can be accomplished as a kind of preprocessing the
  Boost_FIND_COMPONENTS variable quite early in FindBoost.cmake.

- No accumulation of uncached results across multiple invocations
  of FindBoost.cmake; in other words: The uncached results should
  depend only on the parameters of the FindBoost.cmake invocation,
  i.e. the components list, well-known variables as CMAKE_MODULE_
  PATH and well-documented ones as BOOST_ROOT - though the latter
  isn't mentioned in FindBoost.cmake's online documentation ATM.
  In contrast, results of previous FindBoost.cmake calls should
  not show up in the uncached result variables for exactly the
  reason mentioned above.

Feel free to file a feature request; maybe, PL can be persuaded. ;)

Regards,

Michael


More information about the CMake mailing list