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?
# 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)
.
+-- 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
# 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)
.
+-- 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 (e.g. 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 e.g. 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, i.e. 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 (e.g. several targets might define an executable that is just called tests
).