简体   繁体   中英

Tradeof between CMAKE_BINARY_DIR and PROJECT_BINARY_DIR when setting submodule targets' output directories

I'm working on a library which will be used by another project. The main project uses a couple of libraries linked as git submodules . Inside the library project used as a submodule, I can set the LIBRARY_OUTPUT_DIRECTORY and the ARCHIVE_OUTPUT_DIRECTORY in two different ways.

In option A the targets are built and saved to their own subdirectories using the ${PROJECT_BINARY_DIR}/lib , but in option B all targets are built and saved to the ${CMAKE_BINARY_DIR}/lib directory.

This could also be extended to binaries built by the submodules. Thus, which of the two options will scale better / is normally used as best-practice?

OPTION A

CMakeLists.txt

# Set target properties
    set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
            LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
    set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
            ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib/static)

Folder Structure

.
+-- build
|   +-- bin
|       +-- MainProject
|       +-- test
|   +-- lib
|       +-- SubModuleA
|           +-- SubModuleA_lib_shared.a
|           +-- static
|               +-- SubModuleA_lib_static.so
|       +-- SubModuleB
|           +-- SubModuleB_lib_shared.a
|           +-- static
|               +-- SubModuleB_lib_static.so
+-- lib
|   +-- SubModuleA
|   |   +-- CMakeLists.txt
|   +--- SubModuleB
|   |   +-- CMakeLists.txt
+-- inc
|   +-- foo.h
+-- src 
|   +-- foo.cpp
|   +-- main.cpp
|   +-- CMakeLists.txt
+-- test
|   +-- test.cpp
|   +-- CMakeLists.txt
+-- CMakeLists.txt

OPTION B

CMakeLists.txt

# Set target properties
    set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
            LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
    set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
            ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/static)

Folder Structure

.
+-- build
|   +-- bin
|       +-- MainProject
|       +-- test
|   +-- lib
|       +-- SubModuleA_lib_shared.a
|       +-- SubModuleB_lib_shared.a
|       +-- static
|           +-- SubModuleA_lib_static.so
            +-- SubModuleB_lib_static.so
+-- lib
|   +-- SubModuleA
|   |   +-- CMakeLists.txt
|   +--- SubModuleB
|   |   +-- CMakeLists.txt
+-- inc
|   +-- foo.h
+-- src 
|   +-- foo.cpp
|   +-- main.cpp
|   +-- CMakeLists.txt
+-- test
|   +-- test.cpp
|   +-- CMakeLists.txt
+-- CMakeLists.txt

Unless there is a good reason you shouldn't set the output directory for your targets in the library project at all. If consumers link to the CMake targets provided by the library project then they usually don't even need to know where exactly these libraries will be located, and even if they do they have access to the location through target-dependent generator-expressions .

Moreover, even if you do have a good reason (eg because you'd like to archive the build-artifacts in a CI build and don't use CPack to generate proper packages yet), you still shouldn't force your setup upon consumers. If you allow consumers to easily overwrite the defaults they can eg use that mechanism to ensure the shared libraries will be located next to a binary their project builds, which is required on Windows to run the executable without having to manually modify the PATH to include all directories where the dependencies are located, ie consumers can ensure that the executable can be run from the build tree by changing the default output directory of your library target.

You thus shouldn't set the target properties, and instead set the defaults for these properties by setting

if (NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib/static")
endif()

if (NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
endif()

if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
endif()

to make it more convenient for consumers to change the output location of all targets all at once without having to set the properties manually for each target again.

Whether you use ${PROJECT_BINARY_DIR} or ${CMAKE_BINARY_DIR} then is largely irrelevant, but I personally prefer to use ${PROJECT_BINARY_DIR} because it ensures there will be no conflicts, even if two subprojects chose the same name for their target (eg several targets might define an executable that is just called tests ).

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