diff --git a/cmake/FindMimalloc.cmake b/cmake/FindMimalloc.cmake index 9ac939c40..f6f14f937 100644 --- a/cmake/FindMimalloc.cmake +++ b/cmake/FindMimalloc.cmake @@ -40,8 +40,18 @@ if(NOT Mimalloc_FOUND) add_library(mimalloc ${MIMALLOC_SOURCES}) sourcemeta_add_default_options(PRIVATE mimalloc) + # Link the resolved thread library rather than the imported target, as the + # latter obliges every consumer of the exported package to run FindThreads, + # whose try_compile cannot run inside build systems that read the export by + # tracing CMake instead of calling it. The imported target also carries a + # compile option on the platforms whose threads need one, which we set here find_package(Threads REQUIRED) - target_link_libraries(mimalloc PRIVATE Threads::Threads) + if(THREADS_HAVE_PTHREAD_ARG) + target_compile_options(mimalloc PRIVATE -pthread) + endif() + if(CMAKE_THREAD_LIBS_INIT) + target_link_libraries(mimalloc PRIVATE "${CMAKE_THREAD_LIBS_INIT}") + endif() target_include_directories(mimalloc PUBLIC "$" @@ -145,8 +155,6 @@ if(NOT Mimalloc_FOUND) COMPONENT sourcemeta_core_dev) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/mimalloc-config.cmake - "include(CMakeFindDependencyMacro)\n" - "find_dependency(Threads)\n" "include(\"\${CMAKE_CURRENT_LIST_DIR}/mimalloc.cmake\")\n" "check_required_components(\"mimalloc\")\n") install(FILES diff --git a/cmake/FindPCRE2.cmake b/cmake/FindPCRE2.cmake index 21756978b..ad73b552d 100644 --- a/cmake/FindPCRE2.cmake +++ b/cmake/FindPCRE2.cmake @@ -201,6 +201,7 @@ if(NOT PCRE2_FOUND) NAMELINK_COMPONENT sourcemeta_core_dev ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT sourcemeta_core_dev) + sourcemeta_library_export_flatten(pcre2) install(EXPORT pcre2 DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/pcre2" NAMESPACE PCRE2:: diff --git a/cmake/common/targets/library.cmake b/cmake/common/targets/library.cmake index 8085dee0d..94a817177 100644 --- a/cmake/common/targets/library.cmake +++ b/cmake/common/targets/library.cmake @@ -133,6 +133,32 @@ function(sourcemeta_library) endif() endfunction() +# A static library records its private dependencies as $ in the +# exported link interface. Build systems that read the export without evaluating +# generator expressions drop those entries and lose the transitive link closure, +# so unwrap them for the installed interface. The build interface keeps the +# wrapper, so that consumers within this project do not start inheriting the +# usage requirements that a private dependency is not meant to hand them +function(sourcemeta_library_export_flatten TARGET_NAME) + get_target_property(SOURCEMETA_LIBRARY_INTERFACE + ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + if(SOURCEMETA_LIBRARY_INTERFACE) + set(SOURCEMETA_LIBRARY_FLATTENED) + foreach(entry IN LISTS SOURCEMETA_LIBRARY_INTERFACE) + string(REGEX REPLACE "^\\$$" "\\1" unwrapped "${entry}") + if(unwrapped STREQUAL entry) + list(APPEND SOURCEMETA_LIBRARY_FLATTENED "${entry}") + else() + list(APPEND SOURCEMETA_LIBRARY_FLATTENED + "$" + "$") + endif() + endforeach() + set_property(TARGET ${TARGET_NAME} + PROPERTY INTERFACE_LINK_LIBRARIES ${SOURCEMETA_LIBRARY_FLATTENED}) + endif() +endfunction() + function(sourcemeta_library_install) cmake_parse_arguments(SOURCEMETA_LIBRARY "" "NAMESPACE;PROJECT;NAME;VARIANT" "" ${ARGN}) @@ -173,6 +199,12 @@ function(sourcemeta_library_install) NAMELINK_COMPONENT ${COMPONENT_NAME}_dev ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT ${COMPONENT_NAME}_dev) + # Deferred, as callers link their dependencies after installing the target. + # The target name is expanded into the deferred call, as its arguments are + # not evaluated until the call runs, by which point the variable is gone + cmake_language(EVAL CODE + "cmake_language(DEFER CALL sourcemeta_library_export_flatten ${TARGET_NAME})") + install(EXPORT ${TARGET_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${SOURCEMETA_LIBRARY_PROJECT}" NAMESPACE ${NAMESPACE_PREFIX}