manatttta
manatttta

Reputation: 3124

Various libs in subfolders, how do I export them to the parent?

I have a code folder structure like this:

project/
  CMakeLists.txt
  src/
    project.cpp
  lib/
    libA/
      CMakeLists.txt
      src/
        libA.cpp
      include/
        libA.h
    libB/
      CMakeLists.txt
      src/
        libB.cpp
      include/
        libB.h

Now, libA is totally standalone, so I have a CMakeLists.txt similar to this:

cmake_minimum_required(VERSION 2.8)
project ( libA )
set ( LIBA_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE )
include_directories ( include/ )

file (GLOB LIBA_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}
  src/libA.cpp
  )
add_library         ( libA STATIC ${LIBA_SOURCES} )

However, libB depends on libA. How can I export the libA.a output path to be used for linking to libB, and the corresponding include path?

And furthermore, how do I pass that data to the parent CMakeLists.txt for the main project?

Upvotes: 3

Views: 1497

Answers (3)

Florian
Florian

Reputation: 42852

Taking @epicbrew and @NicolasHolthaus answers/comments I just wanted to show how the complete example would look in a newer version of CMake and discuss some of the implications:

project/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project( project )

add_subdirectory( lib/libB )
add_subdirectory( lib/libA )

add_executable( project src/project.cpp )
target_link_libraries( project libB )

project/lib/libA/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project( libA )

add_library( libA STATIC src/libA.cpp include/libA.h )
target_include_directories( libA PUBLIC include )

project/lib/libB/CMakeLists.txt

add_library( libB STATIC src/libB.cpp  include/libB.h )
target_include_directories( libB PUBLIC include )
target_link_libraries( libB libA )

As you can see

  1. You need to know in the main CMakeLists.txt file that you also need libA. I was deliberately reversing the add_subdirectory() calls to show that the order doesn't matter when using target_link_libraries() (sort of allows target forward declarations).
  2. You don't need the local include_directories() call anymore it's an implicit part of the target_include_directories().
  3. With target_include_directories(... PUBLIC ...) those include paths are self-propagating.
  4. You don't need to add the ${CMAKE_CURRENT_SOURCE_DIR} prefixes, those are the defaults.
  5. I just added the source/header files directly to the add_executable()/add_library() calls for compactness of this example code. Normally I also would place those in local variables.
  6. libB is not standalone, but you could change that e.g. by adding add_subdirectory( ../libA libA ) to its CMakeLists.txt file. Obviously you then have to remove add_subdirectory( lib/libA ) from the main CMakeLists.txt.
  7. If you want to optimize the CMake processing a little you should not repeat the project() commands. If you still want libA to be self-sufficient you could add if ( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )/endif() around the cmake_minimum_required(VERSION 3.0)/project( libA ) calls.

Upvotes: 2

Nicolas Holthaus
Nicolas Holthaus

Reputation: 8273

I haven't done this personally, so this answer may only be a starting point, but Qt uses cmake and is able to tie all the include directories and library dependencies into each 'module' (library). If you accomplish that, then you can simply do

add_executable(myExe ...)
target_link_libraries(myExe libB)

to the executable in your main cmake project.

Looking through the Qt scripts, it appears what you need to set (for each library) is:

add_library(libA ...)
set_target_properties(libA PROPERTIES
    "INTERFACE_LINK_LIBRARIES" "${LIBRARIES_LIBA_DEPENDS_ON}"
    "INTERFACE_INCLUDE_DIRECTORIES" "${LIBA_INCLUDE_DIRECTORIES}"
)

then for libB

add_library(libB ...)
set_target_properties(libB PROPERTIES
    "INTERFACE_LINK_LIBRARIES" "libA"
    "INTERFACE_INCLUDE_DIRECTORIES" "${LIBB_INCLUDE_DIRECTORIES}"
)

The cool thing about this method is that when done properly, you can chain together as many libraries as you like without having to worry about the combinatorial explosion of dependencies and include dirs.

Upvotes: 2

mshildt
mshildt

Reputation: 9352

CMake knows about all of the targets that you've built, so there's no need to export information up to the parent. You simply tell CMake that libB links against libA and CMake takes care of putting the correct path on the linker command line. So just specify libA as a link dependency of libB in your libB/CMakeLists.txt:

target_link_libraries(libB libA)

For the include path you either need to set variables in the parent along the lines of the following in the top level project/CMakeLists.txt:

set(LIBA_INCLUDES libA/include)
set(LIBB_INCLUDES libB/include)

Then reference these in the subprojects CMakeList.txt files.

Or, you could use a relative path in your libB/CMakeLists.txt file:

include_directories(../libA/include)

Upvotes: 1

Related Questions