[CMake] add_subdirectory and build directory
Michael Wild
themiwi at gmail.com
Fri Sep 11 10:28:14 EDT 2009
On 11. Sep, 2009, at 15:12, Pierre-Julien Villoud wrote:
> Hi everyone,
>
> After unsuccessfully looking for an answer on Google, I contact you.
> I have a question regarding the use of add_subdirectory. When a
> project A is depending on a project B, I add the following in A's
> CMakeLists.txt :
>
> Add_subdirectory(B Path/To/B/Build/Directory)
>
> It does build B before A. But when I build B in its build directory
> and I build A after, it builds B again whereas it should not since B
> is up to date.
>
> Anyone sees what's wrong ?
>
> Thanks in advance
>
> Pierre-Julien VILLOUD
>
That's NOT what add_subdirectory is made for. It is intended for
adding a sub-directory in the source tree. So, if your directory
structure looks like this (i.e. B is a sub-project of A)
A/CMakeLists.txt
A/B/CMakeLists.txt
things are simple:
A/CMakeLists.txt:
------>8------
# ....
add_subdirectory(B)
include_directories(B/include)
add_executable(a)
target_link_libraries(a b)
------<8------
However, if the two projects are unrelated (apart from A depending on
B), you should use the find_package mechanism which is much more
complex. I.e, in project B you create the files BConfig.cmake (or b-
config.cmake), BUse.cmake, BBuildSettings.cmake and
BLibraryDepends.cmake:
B/BConfig.cmake.in:
------->8------
# Tell the user project where to find our headers and libraries
set(B_INCLUDE_DIRS "@CONFIG_HEADER_PATH@")
set(B_LIBRARY_DIRS "@CONFIG_LIBRARY_PATH@")
# Our build settings and library dependencies
set(B_BUILD_SETTINGS_FILE
"@CONFIG_LIBRARY_PATH@/BBuildSettings.cmake"
)
include("@CONFIG_LIBRARY_PATH@/BLibraryDepends.cmake")
# Defines
set( B_DEFINITIONS "@CONFIG_DEFINITIONS@" )
# USE file
set(B_USE_FILE "@CONFIG_USE_FILE_PATH@/BUse.cmake")
------<8------
B/BUse.cmake:
------->8------
# import B build settings
include(CMakeImportBuildSettings)
cmake_import_build_settings(${B_BUILD_SETTINGS_FILE})
# set up header search path
include_directories(${B_INCLUDE_DIRS})
# set up library search path
link_directories(${BM_LIBRARY_DIRS})
# defines
add_definitions(${B_DEFINITIONS})
------<8------
In the B/CMakeLists.txt file you do the following (just a snippet,
showing the relevant stuff):
B/CMakeLists.txt:
------>8------
# ....
# say, you build two libraries, called b1 and b2
# with sources b1src1.c through b1src3.c and
# b2src1.c through b2src3.c, respectively.
add_library(b1 b1src1.c b1src2.c b1src3.c)
set_target_properties(b1 PROPERTIES
PUBLIC_HEADER "b1hdr1.h;b1hdr2.h;b1hdr3.h"
)
add_library(b2 b2src1.c b2src2.c b2src3.c)
set_target_properties(b2 PROPERTIES
PUBLIC_HEADER "b2hdr1.h;b2hdr2.h;b2hdr3.h"
)
# ....
# install the two libraries
install(TARGETS b1 b2
LIBRARY DESTINATION lib COMPONENT shlibs
RUNTIME DESTINATION bin COMPONENT shlibs
ARCHIVE DESTINATION lib COMPONENT dev
PUBLIC_HEADER DESTINATION include COMPONENT dev
)
# ....
# AT THE VERY END OF THE FILE...
# Export library dependencies
#############################
export( TARGETS b1 b2
NAMESPACE B_
FILE ${CMAKE_BINARY_DIR}/BLibraryDepends.cmake
)
# Export the build settings
###########################
include(CMakeExportBuildSettings)
cmake_export_build_settings(${CMAKE_BINARY_DIR}/BBuildSettings.cmake)
# create BConfig.cmake for the build tree
#########################################
# SET TO THE PREPROCESSOR FLAGS REQUIRED TO USE PROJECT B
set(CONFIG_DEFINITIONS)
# SET TO WHATEVER INCLUDE PATH IS REQUIRED TO USE B'S BINARY TREE
set(CONFIG_HEADER_PATH ${CMAKE_SOURCE_DIR}/include )
# SET TO WHATEVER LIBRARY PATH IS REQUIRED TO USE B'S BINARY TREE
# (ACTUALLY, DUE TO CMAKE-MAGIC THIS CAN BE EMPTY)
set(CONFIG_LIBRARY_PATH)
set(CONFIG_USE_FILE_PATH ${CMAKE_SOURCE_DIR})
configure_file(
${CMAKE_SOURCE_DIR}/BConfig.cmake.in
${CMAKE_BINARY_DIR}/BConfig.cmake
@ONLY
)
# create BConfig.cmake for the install tree
###########################################
set(CONFIG_HEADER_PATH "${CMAKE_INSTALL_PREFIX}/include")
set(CONFIG_LIBRARY_PATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CONFIG_USE_FILE_PATH "${CMAKE_INSTALL_PREFIX}/share/cmake/B" )
configure_file(
${CMAKE_SOURCE_DIR}/BConfig.cmake.in
${CMAKE_BINARY_DIR}/InstallFiles/BConfig.cmake
@ONLY
)
# install the CMake config files
################################
install( FILES
BUse.cmake
"${CMAKE_BINARY_DIR}/InstallFiles/BConfig.cmake"
"${CMAKE_BINARY_DIR}/BBuildSettings.cmake"
DESTINATION share/cmake/B
COMPONENT dev
)
# install the BLibraryDepends.cmake file
########################################
install( EXPORT BLibraryDepends
DESTINATION share/cmake/B
NAMESPACE B_
COMPONENT dev
)
------<8------
And then, in your A/CMakeLists.txt you do the following to use B:
A/CMakeLists.txt:
------>8------
find_package(B REQUIRED)
include(${B_USE_FILE})
add_executable(a asrc1.c asrc2.c asrc3.c)
target_link_libraries(a B_b1 B_b2)
------<8------
In order for CMake to find the BConfig.cmake, it searches some known
system directories (refer to the documentation of find_package). If
CMake can't find the file (which is very likely if you want to use B's
build tree), you have to set the cache variable B_DIR to the binary
directory of B.
I hope this explains how things work. If not, there's always the CMake
book...
Michael
More information about the CMake
mailing list