问题
I'm using the following src/CMakeLists.txt
:
cmake_minimum_required(VERSION 3.1.0)
project(foo)
add_library(foo SHARED foo.cpp)
set_target_properties(foo
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<CONFIG>/subdir
)
And on Windows, I'm building the library using:
mkdir build
cd build
cmake ../src
cmake --build .
Output File: ~/build/Debug/foo.dll
Expected Output File: ~/build/Debug/subdir/foo.dll
What am I doing wrong?
It works fine on platforms other than Windows, and it seems like it should work according to the following documentation:
- add_library
- set_target_properties
- LIBRARY_OUTPUT_DIRECTORY
- cmake-generator-expressions.
回答1:
Short answer
On Windows, unlike other platforms, you should use RUNTIME_OUTPUT_DIRECTORY
instead of LIBRARY_OUTPUT_DIRECTORY
to specify the output directory of a shared library.
Long answer
This is documented on the CMake documentation about Output Artifacts:
Runtime Output Artifacts
A runtime output artifact of a buildsystem target may be:
- The executable file (e.g. .exe) of an executable target created by the add_executable() command.
- On DLL platforms: the executable file (e.g. .dll) of a shared library target created by the add_library() command with the SHARED option. The RUNTIME_OUTPUT_DIRECTORY and RUNTIME_OUTPUT_NAME target properties may be used to control runtime output artifact locations and names in the build tree.
Library Output Artifacts
A library output artifact of a buildsystem target may be:
- The loadable module file (e.g. .dll or .so) of a module library target created by the add_library() command with the MODULE option.
- On non-DLL platforms: the shared library file (e.g. .so or .dylib) of a shared library target created by the add_library() command with the SHARED option. The LIBRARY_OUTPUT_DIRECTORY and LIBRARY_OUTPUT_NAME target properties may be used to control library output artifact locations and names in the build tree.
But why would CMake make such a difference between DLL platforms (Windows) and non-DLL platforms (macOS, Linux, etc.)?
I couldn't find a source documenting this design decision, but I believe the rationale is that Windows does not support the concept of rpath
, that is, .exe
files can't store internally the location of their dependent .dll
files. Therefore, on Windows, .dll
files are often stored in the same folder as .exe
files to make sure that the DLLs are found at runtime. Instead, on Unix systems, shared library files are often stored in a separate lib
folder, while application binaries are stored in a bin
folder, which is not a problem because binaries can store the location of their dependencies using rpath
.
In conclusion, it makes sense for cross-platform development to define both LIBRARY_OUTPUT_DIRECTORY
and RUNTIME_OUTPUT_DIRECTORY
, like so:
cmake_minimum_required(VERSION 3.1.0)
project(foo)
add_library(foo SHARED foo.cpp)
set_target_properties(foo
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<CONFIG>/lib
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<CONFIG>/bin
)
来源:https://stackoverflow.com/questions/56514533/how-to-specify-the-output-directory-of-a-given-dll