Search code examples
c++cmakeinclude-path

CMakeLists configuration to link two C++ projects


I have the following situation: a Project A depends on a Project B, but both are built at the same time. Project A has to include the includes of project B and it needs also to link its libraries. Up to now I've tried this way:

 ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/other_project other_project)

and then:

INCLUDE_DIRECTORIES(includ ${CMAKE_SOURCE_DIR}/other_project/include})
LIST(APPEND LINK_LIBS other_project)

in the CMakeLists.txt of Project A but it doesn't seem to work, the compiler also gives me error when including the headers of Project B saying that they do not exist.

What is the right way to add dependencies in A? How should the CMakeLists.txt look like?

EDIT:

as suggested in the comments, this question was addressed in this, however I'd like to see an example of how to use it in a CMakeList.txt file.


Solution

  • The following is a simple example which builds zlib and then builds libxml2 which depends on the zlib we build. One thing to note, I quickly pulled this example from stuff I've done before. The libxml2 example uses make, thus will only actually build on a system which has it, e.g. Linux, Mac ...

    Here is the proposed directory structure for this example ...

    • src/
      -- CMakeLists.txt
      • CMake/
        ---- External_ZLib.cmake
        ---- External_libxml2.cmake
      • Dowloads/ ( no need to create this directory, CMake will do it for you )
    • build/ ( Out of source build to prevent littering source tree )

    Files:
    CMakeLists.txt

    # Any version that supports ExternalProject should do
    cmake_minimum_required( VERSION 3.1)
    
    project(test_ext_proj)
    
    set(test_ext_proj_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
    set(CMAKE_MODULE_PATH ${test_ext_proj_CMAKE_DIR} ${CMAKE_MODULE_PATH})
    
    set(test_ext_proj_BUILD_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install)
    
    set(test_ext_proj_DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Downloads CACHE PATH "Directory to store downloaded tarballs.")
    
    include(ExternalProject)
    include(External_ZLib)
    include(External_libxml2)
    

    External_ZLib.cmake:

    set(ZLib_version 1.2.8)
    set(ZLib_url "http://zlib.net/zlib-${ZLib_version}.tar.gz")
    set(ZLib_md5 "44d667c142d7cda120332623eab69f40")
    
    ExternalProject_Add(ZLib
      URL ${ZLib_url}
      URL_MD5 ${ZLib_md5}
      PREFIX ${vision-tpl_BUILD_PREFIX}
      DOWNLOAD_DIR ${test_ext_proj_DOWNLOAD_DIR}
      INSTALL_DIR ${test_ext_proj_BUILD_INSTALL_PREFIX}
      CMAKE_GENERATOR ${gen}
      CMAKE_ARGS
        -DCMAKE_INSTALL_PREFIX:PATH=${test_ext_proj_BUILD_INSTALL_PREFIX}
        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
        -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
    )
    
    #This variable is required so other packages can find it.
    set(ZLIB_ROOT ${test_ext_proj_BUILD_INSTALL_PREFIX} CACHE PATH "" FORCE)
    

    External_libxml2.cmake:

    set(libxml2_release "2.9")
    set(libxml2_patch_version 0)
    set(libxml2_url "ftp://xmlsoft.org/libxml2/libxml2-sources-${libxml2_release}.${libxml2_patch_version}.tar.gz")
    set(libxml2_md5 "7da7af8f62e111497d5a2b61d01bd811")
    
    #We need to state that we're dependent on ZLib so build order is correct
    set(_XML2_DEPENDS ZLib)
    
    #This build requires make, ensure we have it, or error out.
    if(CMAKE_GENERATOR MATCHES ".*Makefiles")
      set(MAKE_EXECUTABLE "$(MAKE)")
    else()
      find_program(MAKE_EXECUTABLE make)
      if(NOT MAKE_EXECUTABLE)
        message(FATAL_ERROR "Could not find 'make', required to build libxml2.")
      endif()
    endif()
    
    ExternalProject_Add(libxml2
      DEPENDS ${_XML2_DEPENDS}
      URL ${libxml2_url}
      URL_MD5 ${libxml2_md5}
      PREFIX  ${test_ext_proj_BUILD_PREFIX}
      DOWNLOAD_DIR ${test_ext_proj_DOWNLOAD_DIR}
      INSTALL_DIR  ${test_ext_proj_BUILD_INSTALL_PREFIX}
      BUILD_IN_SOURCE 1
      CONFIGURE_COMMAND ./configure
        --prefix=${test_ext_proj_BUILD_INSTALL_PREFIX}
        --with-zlib=${ZLIB_ROOT}
      BUILD_COMMAND ${MAKE_EXECUTABLE}
      INSTALL_COMMAND ${MAKE_EXECUTABLE} install
    )