Skip to content
Merged
94 changes: 94 additions & 0 deletions src/PackageProject.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 "$<TARGET_FILE_DIR:${_target_name}>"
COMMAND "${CMAKE_COMMAND}" -E copy -t "$<TARGET_FILE_DIR:${_target_name}>"
"$<TARGET_RUNTIME_DLLS:${_target_name}>")
set(_runtime_copy_options COMMAND_EXPAND_LISTS)
else()
if(NOT _runtime_libraries)
continue()
endif()
set(_runtime_copy_commands
COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:${_target_name}>")
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}"
"$<TARGET_FILE_DIR:${_target_name}>")
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``
Expand Down Expand Up @@ -248,13 +338,17 @@ 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
"${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}$<$<CONFIG:Debug>:/debug>/bin"
"${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}$<$<CONFIG:Debug>:/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
Expand Down
36 changes: 22 additions & 14 deletions tests/myproj/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
3 changes: 3 additions & 0 deletions tests/myproj/conanfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
[requires]
docopt.cpp/0.6.3

[options]
docopt.cpp/*:shared=True

[generators]
CMakeDeps
27 changes: 23 additions & 4 deletions tests/myproj/src/main/main.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// test external pac
#include <docopt/docopt.h>
#include <Eigen/Dense>
#include <fmt/core.h>
#include <fmt/ostream.h>
#include <fmt/ranges.h>

// test std libraries
#include <iostream>

Check warning on line 9 in tests/myproj/src/main/main.cpp

View workflow job for this annotation

GitHub Actions / Test (macos-14, gcc, true)

included header iostream is not used directly [misc-include-cleaner]

Check warning on line 9 in tests/myproj/src/main/main.cpp

View workflow job for this annotation

GitHub Actions / Test (macos-14, llvm-19, true)

included header iostream is not used directly [misc-include-cleaner]
#include <map>
#include <string>
#include <string_view>

Expand All @@ -15,15 +18,31 @@
#include <cstdint>
#include <cstring>

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<std::string, docopt::value> 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
Expand Down
2 changes: 1 addition & 1 deletion tests/vcpkg-parallel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Loading