diff --git a/src/PackageProject.cmake b/src/PackageProject.cmake index 71553534..01a81304 100644 --- a/src/PackageProject.cmake +++ b/src/PackageProject.cmake @@ -2,6 +2,8 @@ include_guard() include("${CMAKE_CURRENT_LIST_DIR}/Utilities.cmake") +set(_PROJECT_OPTIONS_PACKAGE_PROJECT_MODULE_DIR "${CMAKE_CURRENT_LIST_DIR}") + # Uses ycm (permissive BSD-3-Clause license) and ForwardArguments (permissive MIT license) function(get_property_of_targets) @@ -22,6 +24,94 @@ function(get_property_of_targets) set(${args_OUTPUT} ${_Value} PARENT_SCOPE) endfunction() +#[[ + +``install_conan_runtime`` +========================= + +Copy Conan runtime DLLs next to binary targets after Conan has installed them. This helper is +normally called by ``package_project`` and is safe to call more than once for the same target. + +]] +function(install_conan_runtime) + if(NOT WIN32) + return() + endif() + + foreach(_target_name IN LISTS ARGN) + if(NOT TARGET "${_target_name}") + message(WARNING "install_conan_runtime: ${_target_name} is not a target.") + continue() + endif() + + get_target_property(_target_imported "${_target_name}" IMPORTED) + if(_target_imported) + message(WARNING "install_conan_runtime: ${_target_name} is imported; not copying next to it.") + continue() + endif() + + get_target_property(_target_type "${_target_name}" TYPE) + if(NOT _target_type MATCHES "^(EXECUTABLE|SHARED_LIBRARY|MODULE_LIBRARY)$") + continue() + endif() + + get_target_property(_runtime_already_installed "${_target_name}" + _PROJECT_OPTIONS_CONAN_RUNTIME_INSTALLED + ) + if(_runtime_already_installed) + continue() + endif() + + set(_runtime_libraries) + foreach(_runtime_dir IN LISTS CONAN_RUNTIME_LIB_DIRS) + file(GLOB _runtime_directory_libraries LIST_DIRECTORIES false "${_runtime_dir}/*.dll") + list(APPEND _runtime_libraries ${_runtime_directory_libraries}) + endforeach() + list(REMOVE_DUPLICATES _runtime_libraries) + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.21.0") + set(_runtime_copy_commands + COMMAND "${CMAKE_COMMAND}" -E make_directory "$" + COMMAND "${CMAKE_COMMAND}" -E copy -t "$" + "$") + set(_runtime_copy_options COMMAND_EXPAND_LISTS) + else() + if(NOT _runtime_libraries) + continue() + endif() + set(_runtime_copy_commands + COMMAND "${CMAKE_COMMAND}" -E make_directory "$") + set(_runtime_copy_options) + endif() + foreach(_runtime_library IN LISTS _runtime_libraries) + list(APPEND _runtime_copy_commands + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${_runtime_library}" + "$") + endforeach() + + get_target_property(_target_source_dir "${_target_name}" SOURCE_DIR) + if("${_target_source_dir}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + add_custom_command( + TARGET "${_target_name}" + POST_BUILD + ${_runtime_copy_commands} + ${_runtime_copy_options} + VERBATIM + ) + else() + get_property(_runtime_target_index GLOBAL PROPERTY PROJECT_OPTIONS_CONAN_RUNTIME_TARGET_INDEX) + if(NOT _runtime_target_index) + set(_runtime_target_index 0) + endif() + math(EXPR _runtime_target_index "${_runtime_target_index} + 1") + set_property(GLOBAL PROPERTY PROJECT_OPTIONS_CONAN_RUNTIME_TARGET_INDEX "${_runtime_target_index}") + set(_runtime_target "_project_options_conan_runtime_${_runtime_target_index}") + add_custom_target("${_runtime_target}" ${_runtime_copy_commands} ${_runtime_copy_options} VERBATIM) + add_dependencies("${_target_name}" "${_runtime_target}") + endif() + set_property(TARGET "${_target_name}" PROPERTY _PROJECT_OPTIONS_CONAN_RUNTIME_INSTALLED TRUE) + endforeach() +endfunction() + #[[.rst: ``package_project`` @@ -248,6 +338,7 @@ function(package_project) # Installation of package (compatible with vcpkg, etc) set(_targets_list ${_PackageProject_TARGETS}) unset(_PackageProject_TARGETS) # to avoid ycm conflict + install_conan_runtime(${_targets_list}) set(runtime_dirs) if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.21.0" AND VCPKG_INSTALLED_DIR AND VCPKG_TARGET_TRIPLET) list(APPEND runtime_dirs @@ -255,6 +346,9 @@ function(package_project) "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}$<$:/debug>/lib" ) endif() + if(CONAN_RUNTIME_LIB_DIRS) + list(APPEND runtime_dirs ${CONAN_RUNTIME_LIB_DIRS}) + endif() set(_PackageProject_RUNTIME_DEPENDENCY_SET_ARGS) if(runtime_dirs) set(_PackageProject_RUNTIME_DEPENDENCY_SET_ARGS diff --git a/tests/myproj/CMakeLists.txt b/tests/myproj/CMakeLists.txt index bd537086..e53c5a5a 100644 --- a/tests/myproj/CMakeLists.txt +++ b/tests/myproj/CMakeLists.txt @@ -24,7 +24,18 @@ set(VCPKG_OVERLAY_TRIPLETS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg_triplets") run_vcpkg(VCPKG_URL "https://github.com/microsoft/vcpkg.git" VCPKG_REV "0cb95c860ea83aafc1b24350510b30dec535989a" ENABLE_VCPKG_UPDATE ) -run_conan() +# cspell:ignore cmaketoolchain +if(WIN32) + run_conan( + INSTALL_ARGS + --build=missing + -c tools.system.package_manager:mode=install + -c tools.system.package_manager:sudo=True + -c "tools.cmake.cmaketoolchain:extra_variables={'MSVC':'ON'}" + ) +else() + run_conan() +endif() project(myproj VERSION 0.2.0 LANGUAGES CXX C) @@ -96,21 +107,18 @@ project_options( add_executable(main ./src/main/main.cpp) target_link_libraries(main PRIVATE myproj_project_options myproj_project_warnings) -target_find_dependencies( - main +target_find_dependencies(main PUBLIC - PACKAGE - fmt - CONFIG - PACKAGE - Eigen3 - CONFIG - PACKAGE - docopt - CONFIG + PACKAGE fmt CONFIG + PACKAGE Eigen3 CONFIG + PACKAGE docopt CONFIG ) -target_link_system_libraries(main PRIVATE fmt::fmt Eigen3::Eigen) +if(WIN32) + target_compile_definitions(main PRIVATE DOCOPT_DLL) +endif() + +target_link_system_libraries(main PRIVATE fmt::fmt Eigen3::Eigen docopt) add_subdirectory(libs) @@ -180,7 +188,7 @@ package_project( myproj_project_options myproj_project_warnings PUBLIC_INCLUDES - ${lib2_INCLUDE_DIR22} + ${lib2_INCLUDE_DIR2} ) package_project(NAME myproj_main TARGETS main) diff --git a/tests/myproj/conanfile.txt b/tests/myproj/conanfile.txt index 1a3bf031..4305f5bc 100644 --- a/tests/myproj/conanfile.txt +++ b/tests/myproj/conanfile.txt @@ -3,5 +3,8 @@ [requires] docopt.cpp/0.6.3 +[options] +docopt.cpp/*:shared=True + [generators] CMakeDeps diff --git a/tests/myproj/src/main/main.cpp b/tests/myproj/src/main/main.cpp index 65c8ad70..866ed13c 100644 --- a/tests/myproj/src/main/main.cpp +++ b/tests/myproj/src/main/main.cpp @@ -1,10 +1,13 @@ // test external pac +#include #include #include +#include #include // test std libraries #include +#include #include #include @@ -15,15 +18,31 @@ #include #include -int main() { - fmt::print("Hello from fmt{}", "!"); +static std::string const usage{ +R"(main. + + Usage: + main + main (-h | --help) + main --version + + Options: + -h --help Show this screen. + --version Show version. +)"}; + +int main(int argc, char const* argv[]) { + std::map args{docopt::docopt(usage, {argv + 1, argv + argc}, /*help=*/true, "main 1.0")}; + for (auto const& arg : args) { + fmt::println("{}: {}", arg.first, fmt::streamed(arg.second)); + } Eigen::VectorXd eigen_vec = Eigen::Vector3d(1, 2, 3); - fmt::print("[{}]", fmt::join(eigen_vec, ", ")); + fmt::println("[{}]", fmt::join(eigen_vec, ", ")); #if !defined(__MINGW32__) && !defined(__MSYS__)// TODO fails Eigen::VectorXd eigen_vec2 = Eigen::VectorXd::LinSpaced(10, 0, 1); - fmt::print("[{}]", fmt::join(eigen_vec2, ", ")); + fmt::println("[{}]", fmt::join(eigen_vec2, ", ")); #endif // trigger address sanitizer diff --git a/tests/vcpkg-parallel/CMakeLists.txt b/tests/vcpkg-parallel/CMakeLists.txt index eb255fbe..7a179bae 100644 --- a/tests/vcpkg-parallel/CMakeLists.txt +++ b/tests/vcpkg-parallel/CMakeLists.txt @@ -76,5 +76,5 @@ add_test( "-DVCPKG_REV=${FAKE_VCPKG_REVISION}" "-DEXERCISE_REENTRANT_LOCK=ON" ) set_tests_properties( - vcpkg_parallel_reentrant_configure PROPERTIES FIXTURES_REQUIRED vcpkg_parallel_shared TIMEOUT 5 + vcpkg_parallel_reentrant_configure PROPERTIES FIXTURES_REQUIRED vcpkg_parallel_shared TIMEOUT 30 )