简体   繁体   中英

cmake: how to reference and build separate cmake project dependency?

I have a cross-compiler cmake project that depends on libraries from a separate project that happens to also use cmake:

/myProject/CMakeLists.txt (uses cross-compiler)
/anotherProject/CMakeLists.txt (platform-agnostic)

anotherProject can be built completely separately on its own. It has no knowledge of myProject at all.

Now, anotherProject has numerous modules that I need, like:

anotherProject/A/CMakeLists.txt (produces static lib A.a)
anotherProject/B/CMakeLists.txt (produces static lib B.a)
etc

When I build myProject, I want to build and link against anotherProject/A and anotherProject/B, to produce shared lib myproject.so. I'd like to leverage the existing cmake-ness of anotherProject if possible, as opposed to manually globbing its various source sets from myProject.

What's the correct way to achieve this with cmake? I feel like I'm missing something obvious.

It would be straightforward if, say, myProject were just a subdirectory under anotherProject, or if there were a top-level CMakeLists.txt that could reference both myProject and anotherProject; but neither is what I'm after. I know I could build anotherProject and export its libraries to a well-known location, and then reference the export directory from myProject - but I would like to avoid that setup as well.

A solution is to use CMake packages .

Basically, in anotherProject, you craft a CMake configuration file where you set variables to be used by myProject (eg. include directory, list of libraries, compilation flags...), or even targets.

Then, in myProject, you use the find_package() mechanism so that CMake finds this configuration file and imports the variables/targets in your current project.

There is a tutorial on the CMake wiki.

The only alternative setup that I can think of based on your requirements is to allow your main (dependent) project to discover the other (dependee) project using find_package .

In your main project CMakeLists.txt you should add something like this:

find_package(anotherProject CONFIG)

if(anotherProject_FOUND)
  message(STATUS "Found project dependency: anotherProject")
else
  # change WARNING to FATAL_ERROR if the dependency is NOT optional
  message(WARNING "package anotherProject was not found")
endif()

On the differences between CONFIG and MODULE modes, check the documentation and this link .

Then assuming that your main project creates an executable, you could hook up the discovered dependency like this:

add_executable(myProject ${SOURCES})
[...]

if(anotherProject_FOUND)
   target_link_libraries(myProject PUBLIC anotherProject)
endif()

This should take care of the required include files and definitions as well.


Now in the dependee project CMakeLists.txt you should do something like this:

set(PRJ_NAME "anotherProject")
string(TOLOWER ${PRJ_NAME} PRJ_NAME_LOWER)
set(ANOTHERPROJECT_EXPORT_NAME "${PRJ_NAME}")

install(TARGETS ${PRJ_NAME} EXPORT ${ANOTHERPROJECT_EXPORT_NAME}
  RUNTIME DESTINATION .)
install(EXPORT ${ANOTHERPROJECT_EXPORT_NAME} DESTINATION "share/cmake")

This associates an export with a target and then installs the export.

Now, if you check that export file, it expects certain things to be found and include d, that could be specific for your project. To make this as supple as possible, you can use the configure feature to generate them from a template and then install from the build directory.
So, in the project under a subdir named share/cmake you could have a file named config.cmake.in with contents:

include(${CMAKE_CURRENT_LIST_DIR}/@PRJ_NAME@.cmake)

In the main project's CMakeLists.txt you need to add the following for generating the file from that template:

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/share/cmake/config.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/share/cmake/${PRJ_NAME_LOWER}-config.cmake)

install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/share/
  DESTINATION share)

Notice that I used PRJ_NAME , because you could potentially reuse that to name the actual executable at the add_executable command. It mentally helps if the exported target has the same name with produced one.

This is a more versatile version to accommodate multiple subprojects of this tutorial.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM