Based on @Hikke's excellent answer, I wrote two macros to make it easier to use external projects.
the code
include(ExternalProject) # # Add external project. # # \param name Name of external project # \param path Path to source directory # \param external Name of the external target # macro(add_external_project name path) # Create external project set(${name}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${path}) set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${path}) ExternalProject_Add(${name} SOURCE_DIR "${${name}_SOURCE_DIR}" BINARY_DIR "${${name}_BINARY_DIR}" CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}" "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" # These are only useful if you're cross-compiling. # They, however, will not hurt regardless. "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}" "-DCMAKE_AR=${CMAKE_AR}" "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}" "-DCMAKE_COMPILER_PREFIX=${CMAKE_COMPILER_PREFIX}" "-DCMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}" INSTALL_COMMAND "" ) endmacro(add_external_project) # # Add external target to external project. # # \param name Name of external project # \param includedir Path to include directory # \param libdir Path to library directory # \param build_type Build type {STATIC, SHARED} # \param external Name of the external target # macro(add_external_target name includedir libdir build_type external) # Configurations set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${libdir}) # Create external library add_library(${name} ${build_type} IMPORTED) set(${name}_LIBRARY "${${name}_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${CMAKE_${build_type}_LIBRARY_PREFIX}${name}${CMAKE_${build_type}_LIBRARY_SUFFIX}") # Find paths and set dependencies add_dependencies(${name} ${external}) set(${name}_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${includedir}") # Set interface properties set_target_properties(${name} PROPERTIES IMPORTED_LOCATION ${${name}_LIBRARY}) set_target_properties(${name} PROPERTIES INCLUDE_DIRECTORIES ${${name}_INCLUDE_DIR}) endmacro(add_external_target)
Explanation
The first macro creates an external project that runs the entire external build step, and the second step sets up the necessary dependencies and defines the interface. Separation of the two is important because most projects have more than one interface / library.
Example
Let's say that I am GoogleTest as a submodule in my project, located in a subfolder of googletest . I can use the following interface to define the gtest and gtest_main , very similar to how Googletest does it.
add_external_project(googletest_external googletest) add_external_target(gtest googletest/googletest/include googletest/googlemock/gtest STATIC googletest_external) add_external_target(gtest_main googletest/googletest/include googletest/googlemock/gtest STATIC googletest_external)
Then I can associate my goal with googletest in the same way as before:
target_link_libraries(target_tests gtest gtest_main
This should provide enough template to simplify the actual external build process, even with projects with CMake support.
source share