Search code examples
cmakeexternal-project

CMake - linking to library downloaded from ExternalProject_add()


I am trying to use ExternalProject_add() to download/install dependencies. It installs fine, but I can't figure out how to actually link the libraries after they are downloaded.

I want to call target_link_libraries() on the library that was just downloaded, but the path to the library will vary by system.

If this were a system dependency, I could just call find_package() - but the packages weren't installed on the default search path. I don't think you can specify a search path for find_package in module mode.

Here's a snippet of my CMakeLists.txt that doesn't work:

ExternalProject_Add(
protobuf
URL http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.gz
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR>
PREFIX ${MYPROJ_SOURCE_DIR}/dependencies
)
find_package(protobuf REQUIRED)
set(LIBS ${LIBS} ${PROTOBUF_LIBRARIES})
target_link_libraries (mybinary ${LIBS})

Solution

  • When you're using ExternalProject_Add, you can't use find_package, since there's nothing to find when CMake runs to configure the outer project.

    So, if library locations vary by platform you will need conditional logic based on your platform. (I don't know protobuf's libraries or structure here, so this is just an example, but it should get you headed in the right direction...) Something like this:

    if(WIN32)
      set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/win"
      set(prefix "")
      set(suffix ".lib")
    elseif(APPLE)
      set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/mac"
      set(prefix "lib")
      set(suffix ".a")
    else()
      set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/linux"
      set(prefix "lib")
      set(suffix ".a")
    endif()
    
    set(PROTOBUF_LIBRARIES
      "${PROTOBUF_LIB_DIR}/${prefix}protobufLib1${suffix}"
      "${PROTOBUF_LIB_DIR}/${prefix}protobufLib2${suffix}")
    

    Granted, this is less convenient than using find_package. If you can use a pre-built/pre-installed package, you should, so that you can use find_package. If you must build the other package from source code as part of your project, though, ExternalProject_Add is useful, even though it is unable to abstract away all the details for you.