> On 18/11/2015 11:27, [email protected] wrote: >>> On 11/16/2015 09:26 AM, Florent Castelli wrote: >>>> But one thereâs one thing that comes to mind. Some compiled >>>> libraries >>>> have dependencies on other compiled libraries. >>>> Donât you think it would make sense to teach FindBoost about those >>>> so we link everything properly? >>>> >>>> And also maybe add the native dependencies for some modules that >>>> have one like maybe pthread or openssl. >>>> Though, this might be hard to get right in a cross platform way. >>> >>> Please look at adding these. The imported targets should come >>> with all usage requirements as if they were provided by upstream >>> Boost. It may be tricky to get right on all platforms but if we >>> do not do it then application code will have to do it instead. >> >> I have made a first attempt at this. I suspect it will need some >> refinement, but hopefully useful as a starting point. Please see the >> attached patch. I'd certainly be very appreciative of any comments. > > [...] > > Did anyone have a chance to look at this yet? I'd very much like to get > this to a state where it can be included. The performance is something > I'd like to improve, and I hope someone might have a suggestion for > speeding up the parsing overhead.
I have improved the parsing speed somewhat and added some progress diagnostics to inform the user what's happening to compensate for the time it takes to process the dependencies. It's still slower than I'd ideally like, but it's a bit better. If there's any way to make it even faster I'd be interested. I think what's there is technically correct though. Regards, Roger
>From ea6e84be917f577be92f6c53cbdc829723d589b7 Mon Sep 17 00:00:00 2001 From: Roger Leigh <[email protected]> Date: Mon, 16 Nov 2015 13:21:33 +0000 Subject: [PATCH] FindBoost: Add imported targets --- Modules/FindBoost.cmake | 224 ++++++++++++++++++++++++++++++++++++ Tests/CMakeLists.txt | 6 +- Tests/FindBoost/CMakeLists.txt | 10 ++ Tests/FindBoost/Test/CMakeLists.txt | 18 +++ Tests/FindBoost/Test/main.cxx | 26 +++++ 5 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 Tests/FindBoost/CMakeLists.txt create mode 100644 Tests/FindBoost/Test/CMakeLists.txt create mode 100644 Tests/FindBoost/Test/main.cxx diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake index 33e6a49..6929067 100644 --- a/Modules/FindBoost.cmake +++ b/Modules/FindBoost.cmake @@ -54,6 +54,33 @@ # Boost_<C>_LIBRARY_DEBUG - Component <C> library debug variant # Boost_<C>_LIBRARY_RELEASE - Component <C> library release variant # +# The following :prop_tgt:`IMPORTED` targets are also defined:: +# +# Boost::boost - Target for header-only dependencies +# (Boost include directory) +# Boost::<C> - Target for specific component dependency +# (shared or static library); <C> is lower- +# case +# Boost::diagnostic_definitions - interface target to enable diagnostic +# information about Boost's automatic linking +# during compilation (adds BOOST_LIB_DIAGNOSTIC) +# Boost::disable_autolinking - interface target to disable automatic +# linking with MSVC (adds BOOST_ALL_NO_LIB) +# Boost::dynamic_linking - interface target to enable dynamic linking +# linking with MSVC (adds BOOST_ALL_DYN_LINK) +# +# Implicit dependencies such as Boost::filesystem requiring +# Boost::system will be automatically detected and satisfied, even +# if system is not specified when using find_package and if +# Boost::system is not added to target_link_libraries. If using +# Boost::thread, then Thread::Thread will also be added automatically. +# +# It is important to note that the imported targets behave differently +# than variables created by this module: multiple calls to +# find_package(Boost) in the same directory or sub-directories with +# different options (e.g. static or shared) will not override the +# values of the targets created by the first call. +# # Users may set these hints or results as cache entries. Projects # should not read these entries directly but instead use the above # result variables. Note that some hint names start in upper-case @@ -142,6 +169,14 @@ # add_executable(foo foo.cc) # endif() # +# Example to find Boost libraries and use imported targets:: +# +# find_package(Boost 1.56 REQUIRED COMPONENTS +# date_time filesystem iostreams) +# add_executable(foo foo.cc) +# target_link_libraries(foo Boost::date_time Boost::filesystem +# Boost::iostreams) +# # Example to find Boost headers and some *static* libraries:: # # set(Boost_USE_STATIC_LIBS ON) # only find static libs @@ -472,6 +507,104 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret) endfunction() # +# Determine header dependencies on libraries using the embedded dependency information. +# +# component - the component to check (uses all headers from boost/${component}) +# includedir - the path to the Boost headers +# _ret - list of library dependencies +# +function(_Boost_COMPONENT_DEPENDENCIES component includedir _ret) + # _boost_unprocessed_headers - list of headers requiring parsing + # _boost_processed_headers - headers already parsed (or currently being parsed) + # _boost_new_headers - new headers discovered for future processing + + message(STATUS "Finding dependencies for Boost::${component}") + + # Start by finding all headers for the component; header dependencies will be solved by future passes + file(GLOB_RECURSE _boost_unprocessed_headers RELATIVE "${includedir}" "${includedir}/boost/${component}/*") + + while(_boost_unprocessed_headers) + list(APPEND _boost_processed_headers ${_boost_unprocessed_headers}) + foreach(header ${_boost_unprocessed_headers}) + if(EXISTS "${includedir}/${header}") + file(STRINGS "${includedir}/${header}" _boost_header_includes REGEX "^#[ \t]*include[ \t]*<boost/[^>][^>]*>") + file(STRINGS "${includedir}/${header}" _boost_header_deps REGEX "^#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_") + + foreach(line ${_boost_header_includes}) + string(REGEX REPLACE "^#[ \t]*include[ \t]*<(boost/[^>][^>]*)>.*" "\\1" _boost_header_match "${line}") + list(FIND _boost_processed_headers "${_boost_header_match}" _boost_header_processed) + list(FIND _boost_new_headers "${_boost_header_match}" _boost_header_new) + if (_boost_header_processed EQUAL -1 AND _boost_header_new EQUAL -1) + list(APPEND _boost_new_headers ${_boost_header_match}) + endif() + endforeach() + foreach(line ${_boost_header_deps}) + string(REGEX REPLACE "^#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_([^ \t][^ \t]*).*" "\\1" _boost_component_match "${line}") + list(FIND _boost_DEPS "${_boost_component_match}" _boost_dep_found) + if(_boost_component_match STREQUAL "bzip2" OR _boost_component_match STREQUAL "zlib") + # These components may or may not be required; not + # possible to tell without knowing where and when + # BOOST_BZIP2_BINARY and BOOST_ZLIB_BINARY are defined. + # If building against an external zlib or bzip2, this is + # undesirable. + continue() + endif() + # Don't add self as dependency. + if (_boost_dep_found EQUAL -1 AND NOT "${_boost_component_match}" STREQUAL "${component}") + list(APPEND _boost_DEPS "${_boost_component_match}") + endif() + endforeach() + endif() + endforeach() + set(_boost_unprocessed_headers ${_boost_new_headers}) + unset(_boost_new_headers) + endwhile() + set(${_ret} ${_boost_DEPS} PARENT_SCOPE) + string(TOUPPER ${component} uppercomponent) + set(_Boost_${uppercomponent}_DEPENDENCIES ${_boost_DEPS} PARENT_SCOPE) + + string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_boost_DEPS}") + if (NOT _boost_DEPS_STRING) + set(_boost_DEPS_STRING "(none)") + endif() + message(STATUS "Finding dependencies for Boost::${component}: ${_boost_DEPS_STRING}") + +endfunction() + +# +# Determine if any missing dependencies require adding to the component list. +# +# componentvar - the component list variable name +# includedir - the path to the Boost headers +# +function(_Boost_MISSING_DEPENDENCIES componentvar includedir) + # _boost_unprocessed_components - list of components requiring processing + # _boost_processed_components - components already processed (or currently being processed) + # _boost_new_components - new components discovered for future processing + # + list(APPEND _boost_unprocessed_components ${${componentvar}}) + + while(_boost_unprocessed_components) + list(APPEND _boost_processed_components ${_boost_unprocessed_components}) + foreach(component ${_boost_unprocessed_components}) + _Boost_COMPONENT_DEPENDENCIES("${component}" "${includedir}" _boost_component_deps) + string(TOUPPER ${component} uppercomponent) + set(_Boost_${uppercomponent}_DEPENDENCIES ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) + foreach(componentdep ${_boost_component_deps}) + list(FIND _boost_processed_components "${componentdep}" _boost_component_found) + list(FIND _boost_new_components "${componentdep}" _boost_component_new) + if (_boost_component_found EQUAL -1 AND _boost_component_new EQUAL -1) + list(APPEND _boost_new_components ${componentdep}) + endif() + endforeach() + endforeach() + set(_boost_unprocessed_components ${_boost_new_components}) + unset(_boost_new_components) + endwhile() + set(${componentvar} ${_boost_processed_components} PARENT_SCOPE) +endfunction() + +# # End functions/macros # #------------------------------------------------------------------------------- @@ -562,6 +695,16 @@ if(Boost_DEBUG) "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}") endif() +# Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It +# will only contain any interface definitions on WIN32, but is created +# on all platforms to keep end user code free from platform dependent +# code. Also provide convenience targets to disable autolinking and +# enable dynamic linking. +if(NOT TARGET Boost::diagnostic_definitions) + add_library(Boost::diagnostic_definitions INTERFACE IMPORTED) + add_library(Boost::disable_autolinking INTERFACE IMPORTED) + add_library(Boost::dynamic_linking INTERFACE IMPORTED) +endif() if(WIN32) # In windows, automatic linking is performed, so you do not have # to specify the libraries. If you are linking to a dynamic @@ -581,6 +724,12 @@ if(WIN32) # code to emit a #pragma message each time a library is selected # for linking. set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") + set_target_properties(Boost::diagnostic_definitions PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC") + set_target_properties(Boost::disable_autolinking PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB") + set_target_properties(Boost::dynamic_linking PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK") endif() _Boost_CHECK_SPELLING(Boost_ROOT) @@ -979,6 +1128,17 @@ if(Boost_VERSION AND Boost_FIND_COMPONENTS) endif() endif() +# Additional components may be required via component dependencies. +# Add any missing components to the list. +_Boost_MISSING_DEPENDENCIES(Boost_FIND_COMPONENTS "${Boost_INCLUDE_DIR}") + +# If thread is required, get the thread libs as a dependency +list(FIND Boost_FIND_COMPONENTS thread _Boost_THREAD_DEPENDENCY_LIBS) +if(NOT _Boost_THREAD_DEPENDENCY_LIBS EQUAL -1) + include(CMakeFindDependencyMacro) + find_dependency(Threads) +endif() + # If the user changed any of our control inputs flush previous results. if(_Boost_CHANGE_LIBDIR OR _Boost_CHANGE_LIBNAME) foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED}) @@ -1222,6 +1382,70 @@ else() endif() # ------------------------------------------------------------------------ +# Add imported targets +# ------------------------------------------------------------------------ + +if(Boost_FOUND) + # For header-only libraries + if(NOT TARGET Boost::boost) + add_library(Boost::boost INTERFACE IMPORTED) + if(Boost_INCLUDE_DIRS) + set_target_properties(Boost::boost PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") + endif() + endif() + + foreach(COMPONENT ${Boost_FIND_COMPONENTS}) + if(NOT TARGET Boost::${COMPONENT}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + if(Boost_${UPPERCOMPONENT}_FOUND) + if(Boost_USE_STATIC_LIBS) + add_library(Boost::${COMPONENT} STATIC IMPORTED) + else() + # Even if Boost_USE_STATIC_LIBS is OFF, we might have static + # libraries as a result. + add_library(Boost::${COMPONENT} UNKNOWN IMPORTED) + endif() + if(Boost_INCLUDE_DIRS) + set_target_properties(Boost::${COMPONENT} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") + endif() + if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY}") + set_target_properties(Boost::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${Boost_${UPPERCOMPONENT}_LIBRARY}") + endif() + if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") + set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(Boost::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") + endif() + if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") + set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(Boost::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" + IMPORTED_LOCATION_RELEASE "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") + endif() + if(_Boost_${UPPERCOMPONENT}_DEPENDENCIES) + unset(_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES) + foreach(dep ${_Boost_${UPPERCOMPONENT}_DEPENDENCIES}) + list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Boost::${dep}) + endforeach() + if(COMPONENT STREQUAL "thread") + list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Threads::Threads) + endif() + set_target_properties(Boost::${COMPONENT} PROPERTIES + INTERFACE_LINK_LIBRARIES "${_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}") + endif() + endif() + endif() + endforeach() +endif() + +# ------------------------------------------------------------------------ # Notification to end user about what was found # ------------------------------------------------------------------------ diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 5fd7159..4b0d40d 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1356,7 +1356,11 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release endif() endif() - if(CMake_TEST_FindGSL) + if(CMake_TEST_FindBoost) + add_subdirectory(FindBoost) + endif() + +if(CMake_TEST_FindGSL) add_subdirectory(FindGSL) endif() if(CMake_TEST_FindJsonCpp) diff --git a/Tests/FindBoost/CMakeLists.txt b/Tests/FindBoost/CMakeLists.txt new file mode 100644 index 0000000..259ee26 --- /dev/null +++ b/Tests/FindBoost/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindBoost.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindBoost/Test" + "${CMake_BINARY_DIR}/Tests/FindBoost/Test" + ${build_generator_args} + --build-project TestFindBoost + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) diff --git a/Tests/FindBoost/Test/CMakeLists.txt b/Tests/FindBoost/Test/CMakeLists.txt new file mode 100644 index 0000000..ce50fc7 --- /dev/null +++ b/Tests/FindBoost/Test/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.1) +project(TestFindBoost CXX) +include(CTest) + +find_package(Boost REQUIRED COMPONENTS filesystem thread) + +add_executable(test_boost_tgt main.cxx) +target_link_libraries(test_boost_tgt + Boost::dynamic_linking + Boost::disable_autolinking + Boost::filesystem + Boost::thread) +add_test(NAME test_boost_tgt COMMAND test_boost_tgt) + +add_executable(test_boost_var main.cxx) +target_include_directories(test_boost_var PRIVATE ${Boost_INCLUDE_DIRS}) +target_link_libraries(test_boost_var PRIVATE ${Boost_FILESYSTEM_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${Boost_THREAD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +add_test(NAME test_boost_var COMMAND test_boost_var) diff --git a/Tests/FindBoost/Test/main.cxx b/Tests/FindBoost/Test/main.cxx new file mode 100644 index 0000000..0f44f30 --- /dev/null +++ b/Tests/FindBoost/Test/main.cxx @@ -0,0 +1,26 @@ +#include <boost/filesystem.hpp> +#include <boost/thread.hpp> + +namespace +{ + + boost::mutex m1; + boost::recursive_mutex m2; + + void + threadmain() + { + boost::lock_guard<boost::mutex> lock1(m1); + boost::lock_guard<boost::recursive_mutex> lock2(m2); + + boost::filesystem::path p(boost::filesystem::current_path()); + } + +} + +int main() { + boost::thread foo(threadmain); + foo.join(); + + return 0; +} -- 2.5.0
-- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake-developers
