I have a project which i manage with CMake
and build it with MSVC
.
For Dependency Management i use Conan
with the cmake_find_package
Generator.
The Build it self works without any problems. But i cannot run e.g. the Test Executable without copying the created dll
and the dll
from the dependencies to the Location of the Test Executable
.
This is my conanfile.txt
:
[requires]
gtest/1.10.0
[generators]
cmake_find_package
[options]
gtest:shared=True
gtest:build_gmock=True
This is my CMakeLists.txt
File for the DLL
:
cmake_minimum_required(VERSION 3.14)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "Do not build in-source. Please remove CMakeCache.txt and the CMakeFiles/ directory. Then build out-of-source")
endif()
project("CommandDispatcher" VERSION 1.0.0 LANGUAGES CXX)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
option(BUILD_SHARED_LIBS "Build shared (dynamic) libraries." ON)
option(ENABLE_TESTING "Build with Tests enabled." ON)
include(generate_product_version)
generate_product_version(
VersionFilesOutputVariable
ICON ${CMAKE_CURRENT_SOURCE_DIR}/resources/Product.ico
NAME ${PROJECT_NAME}
VERSION_MAJOR 1
VERSION_MINOR 0
VERSION_PATCH 0
VERSION_REVISION 0
)
add_library(${PROJECT_NAME})
add_library("Product::CommandDispatcher" ALIAS ${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PUBLIC
include/${PROJECT_NAME}/export.hpp
include/${PROJECT_NAME}/command_dispatcher.hpp
PRIVATE
src/command_dispatcher.cpp
src/test.hpp
src/test.cpp
${VersionFilesOutputVariable}
)
target_include_directories(${PROJECT_NAME} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>"
PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>")
set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION 1 VERSION 1.0.0)
if (MSVC)
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX "d")
endif()
include(GenerateExportHeader)
string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
generate_export_header(${PROJECT_NAME}
EXPORT_FILE_NAME ${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/export.hpp
EXPORT_MACRO_NAME ${PROJECT_NAME_UPPER}_EXPORT
STATIC_DEFINE ${PROJECT_NAME_UPPER}_STATIC
)
if(ENABLE_TESTING)
message(STATUS "Build Library as Static Version for testing purpose")
set(PROJECT_NAME_STATIC ${PROJECT_NAME}_static)
add_library(${PROJECT_NAME_STATIC} STATIC)
target_sources(${PROJECT_NAME_STATIC}
PUBLIC
include/${PROJECT_NAME}/export.hpp
include/${PROJECT_NAME}/command_dispatcher.hpp
PRIVATE
src/command_dispatcher.cpp
src/test.hpp
src/test.cpp
)
target_include_directories(${PROJECT_NAME_STATIC} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>"
PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>")
string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
set_target_properties(${PROJECT_NAME_STATIC} PROPERTIES COMPILE_FLAGS -D${PROJECT_NAME_UPPER}_STATIC)
if (MSVC)
# set_target_properties(${PROJECT_NAME_STATIC} PROPERTIES DEBUG_POSTFIX "d")
endif()
message(STATUS "Running Tests for Library ${PROJECT_NAME}")
include(CTest)
enable_testing()
add_subdirectory(tests)
endif()
I build the Library first as a DLL
and also as a static
library for testing purpose (to test also the private Parts of the Library.
This is the CMakeLists.txt
inside the tests
directory:
set(TEST_TARGET_NAME ${PROJECT_NAME}_TEST)
add_executable(${TEST_TARGET_NAME})
target_sources(${TEST_TARGET_NAME}
PRIVATE
ExampleTest.cpp
TestRunner.cpp
)
find_package(GTest)
if(TARGET GTest::GTest)
message(STATUS "Target Found")
target_link_libraries(${TEST_TARGET_NAME} PRIVATE GTest::GTest)
endif()
target_link_libraries(${TEST_TARGET_NAME} PRIVATE ${PROJECT_NAME_STATIC})
add_test(NAME ${TEST_TARGET_NAME}
COMMAND ${TEST_TARGET_NAME}
WORKING_DIRECTORY $<TARGET_FILE_DIR:${TEST_TARGET_NAME}>)
target_include_directories(${TEST_TARGET_NAME} PRIVATE $<TARGET_PROPERTY:${PROJECT_NAME_STATIC},INCLUDE_DIRECTORIES>)
Here i Link against the GTest
Library which was installed with Conan
.
If i run the Build the Results are in the following Folderstructure inside the Build
Directory:
+---build
|
+---Debug
| CommandDispatcherd.dll
+---tests
| |
| \---Debug
| CommandDispatcher_TEST.exe
And the GTest DLLs
are somewhere down my Userfolder/.conan
.
What is a good way to group these things together? E.g. Building the DLL
, Test Exe
and Dependencies DLL
inside a bin/test
folder inside the build
directory?
My first guess was to add the following to the Conanfile.txt
:
[imports]
bin, gmockd.dll -> ./bin/test
bin, gmock_maind.dll -> ./bin/test
bin, gtestd.dll -> ./bin/test
bin, gtest_maind.dll -> ./bin/test
But for this i need to know the name of the builded dlls
.
And also adding the following to the Main CMakeFile.txt
:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
Or should i make the changes depending of the target
with set_target_properties
?
Or is there a better solution out there? ALso for the Conan Part to copy the DLLs to the right place?
Also any improvements for my CMakeFile.txt
are welcome =).
But for this i need to know the name of the builded dlls.
I think you do not need to know name of the dlls. You can setup imports like:
bin, *.dll -> ./bin/test @ root_package=gtest
Note the root_package
parameter, that will tell conan what package to copy dlls from.
More info here: https://docs.conan.io/en/latest/reference/conanfile_txt.html#imports
or in conanfile.py
it can be implemented as:
def imports(self):
self.copy("*.dll", f"bin\\tests", "bin", root_package='gtest')