From 17edeb1eb6056c6b87e7e15297b0599f1008b5ef Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 9 Jun 2021 11:48:31 +0200 Subject: [PATCH] Allow building against system libs instead of bundled dependencies When DIP_BUILD_BUNDLED_DEPENDENCIES=OFF is passed to cmake, we will rely on find_package to find Eigen3, zlib, jpeg, ics and tiff libraries. The fftw_api.h header will always be used, as it's not public API that's included in the fftw3 package on ArchLinux e.g. The default for this option is still ON, i.e. this is an opt-in feature. Change-Id: I4ed9095eefbfd889642d1c3d42b3d9af0dfc15ae --- CMakeLists.txt | 3 ++ dependencies/libics/CMakeLists.txt | 4 +- dependencies/libtiff/CMakeLists.txt | 6 +-- pydip/CMakeLists.txt | 6 ++- src/CMakeLists.txt | 60 ++++++++++++++++----- tools/FindEigen3.cmake | 83 +++++++++++++++++++++++++++++ tools/FindICS.cmake | 48 +++++++++++++++++ 7 files changed, 191 insertions(+), 19 deletions(-) create mode 100644 tools/FindEigen3.cmake create mode 100644 tools/FindICS.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 96546898a..ee1c37580 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,9 @@ endif() set(DIP_SHARED_LIBRARY ON CACHE BOOL "Build a shared library (off for static library)") set(BUILD_SHARED_LIBS ${DIP_SHARED_LIBRARY}) +# build bundled dependencies or use find_package? +set(DIP_BUILD_BUNDLED_DEPENDENCIES ON CACHE BOOL "Build the bundled dependencies or use find_package otherwise") + # Installation path set(CMAKE_INSTALL_PREFIX "${CMAKE_BUILD_TYPE}" CACHE PATH "Installation directory") set(DOCUMENTATION_OUTPUT share/doc/DIPlib) diff --git a/dependencies/libics/CMakeLists.txt b/dependencies/libics/CMakeLists.txt index 572f64bb1..a24ebbd6d 100644 --- a/dependencies/libics/CMakeLists.txt +++ b/dependencies/libics/CMakeLists.txt @@ -100,8 +100,8 @@ endif(UNIX) #endif() # DIPlib-specific zlib -if(TARGET zlibstatic) - target_link_libraries(libics PRIVATE zlibstatic) +if(TARGET ZLIB::ZLIB) + target_link_libraries(libics PRIVATE ZLIB::ZLIB) target_compile_definitions(libics PUBLIC -DICS_ZLIB) endif() diff --git a/dependencies/libtiff/CMakeLists.txt b/dependencies/libtiff/CMakeLists.txt index 8d08268e1..2dd46696c 100644 --- a/dependencies/libtiff/CMakeLists.txt +++ b/dependencies/libtiff/CMakeLists.txt @@ -378,7 +378,7 @@ set(MDI_SUPPORT TRUE) # ZLIB set(ZLIB_SUPPORT FALSE) -if(TARGET zlibstatic) +if(TARGET ZLIB::ZLIB) set(ZLIB_SUPPORT TRUE) endif() set(ZIP_SUPPORT ${ZLIB_SUPPORT}) @@ -468,10 +468,10 @@ if(M_LIBRARY) list(APPEND TIFF_LIBRARY_DEPS ${M_LIBRARY}) endif() if(ZLIB_SUPPORT) - list(APPEND TIFF_LIBRARY_DEPS zlibstatic) + list(APPEND TIFF_LIBRARY_DEPS ZLIB::ZLIB) endif() if(JPEG_SUPPORT) - list(APPEND TIFF_LIBRARY_DEPS jpeg) + list(APPEND TIFF_LIBRARY_DEPS JPEG::JPEG) endif() if(JPEG12_LIBRARIES) list(APPEND TIFF_LIBRARY_DEPS ${JPEG12_LIBRARIES}) diff --git a/pydip/CMakeLists.txt b/pydip/CMakeLists.txt index 145e7d3ab..239a9528b 100644 --- a/pydip/CMakeLists.txt +++ b/pydip/CMakeLists.txt @@ -1,5 +1,9 @@ set(PYBIND11_PYTHON_VERSION ${PYTHON_VERSION}) # Avoid a warning message -add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/pybind11" "${PROJECT_BINARY_DIR}/pybind11" EXCLUDE_FROM_ALL) +if(DIP_BUILD_BUNDLED_DEPENDENCIES) + add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/pybind11" "${PROJECT_BINARY_DIR}/pybind11" EXCLUDE_FROM_ALL) +else() + find_package(pybind11 REQUIRED) +endif() # Find sources file(GLOB DIP_PYTHON_SRC "${CMAKE_CURRENT_LIST_DIR}/src/*.cpp" "${CMAKE_CURRENT_LIST_DIR}/src/*.h") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b9df17b4..bd338740c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,7 +68,17 @@ endif() # that uses DIPlib, hence we define a variable here that removes all of DocTest from the DIPlib sources. set(DIP_ENABLE_DOCTEST ON CACHE BOOL "Turn off to not include doctest.h in the library headers") if(DIP_ENABLE_DOCTEST) - target_include_directories(DIP PRIVATE "${PROJECT_SOURCE_DIR}/dependencies/doctest") + if(DIP_BUILD_BUNDLED_DEPENDENCIES) + list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/dependencies/doctest") + add_library(doctest INTERFACE) + target_include_directories(doctest INTERFACE "${PROJECT_SOURCE_DIR}/dependencies/doctest") + add_library(doctest::doctest ALIAS doctest) + else() + find_package(doctest REQUIRED) + # upstream doctest wants includes of the form but diplib uses just doctest.h + target_include_directories(DIP PRIVATE "$/doctest") + endif() + target_link_libraries(DIP PRIVATE doctest::doctest) target_compile_definitions(DIP PRIVATE DIP_CONFIG_ENABLE_DOCTEST DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES @@ -95,7 +105,12 @@ endif() set(HAS_128_INT ${HAS_128_INT} PARENT_SCOPE) # Eigen -target_include_directories(DIP PRIVATE "${PROJECT_SOURCE_DIR}/dependencies/eigen3") +if(DIP_BUILD_BUNDLED_DEPENDENCIES) + target_include_directories(DIP PRIVATE "${PROJECT_SOURCE_DIR}/dependencies/eigen3") +else() + find_package(Eigen3 REQUIRED) + target_include_directories(DIP PRIVATE ${EIGEN3_INCLUDE_DIR}) +endif() target_compile_definitions(DIP PRIVATE EIGEN_MPL2_ONLY # This makes sure we only use parts of the Eigen library that use the MPL2 license or more permissive ones. EIGEN_DONT_PARALLELIZE) # This to prevent Eigen algorithms trying to run in parallel -- we parallelize at a larger scale. @@ -103,31 +118,51 @@ target_compile_definitions(DIP PRIVATE # zlib (for use in libics and libtiff) set(DIP_ENABLE_ZLIB ON CACHE BOOL "Enable zlib compression in ICS and TIFF (deflate)") if(DIP_ENABLE_ZLIB) - add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/zlib" "${PROJECT_BINARY_DIR}/zlib" EXCLUDE_FROM_ALL) + if(DIP_BUILD_BUNDLED_DEPENDENCIES) + add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/zlib" "${PROJECT_BINARY_DIR}/zlib" EXCLUDE_FROM_ALL) + add_library(ZLIB::ZLIB ALIAS zlibstatic) + else() + find_package(ZLIB REQUIRED) + endif() endif() # libjpeg (for use in libtiff) set(DIP_ENABLE_JPEG ON CACHE BOOL "Enable JPEG file support and compression in TIFF") if(DIP_ENABLE_JPEG) - add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/libjpeg" "${PROJECT_BINARY_DIR}/libjpeg" EXCLUDE_FROM_ALL) - target_link_libraries(DIP PRIVATE jpeg) + if(DIP_BUILD_BUNDLED_DEPENDENCIES) + add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/libjpeg" "${PROJECT_BINARY_DIR}/libjpeg" EXCLUDE_FROM_ALL) + add_library(JPEG::JPEG ALIAS jpeg) + else() + find_package(JPEG REQUIRED) + endif() + target_link_libraries(DIP PRIVATE JPEG::JPEG) target_compile_definitions(DIP PRIVATE DIP_CONFIG_HAS_JPEG) endif() # libics set(DIP_ENABLE_ICS ON CACHE BOOL "Enable ICS file support") if(DIP_ENABLE_ICS) - set(LIBICS_INCLUDE_CPP Off) # TODO: we should start using the C++ interface - add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/libics" "${PROJECT_BINARY_DIR}/libics" EXCLUDE_FROM_ALL) - target_link_libraries(DIP PRIVATE libics) + if(DIP_BUILD_BUNDLED_DEPENDENCIES) + set(LIBICS_INCLUDE_CPP Off) # TODO: we should start using the C++ interface + add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/libics" "${PROJECT_BINARY_DIR}/libics" EXCLUDE_FROM_ALL) + add_library(ICS::ICS ALIAS libics) + else() + find_package(ICS REQUIRED) + endif() + target_link_libraries(DIP PRIVATE ICS::ICS) target_compile_definitions(DIP PRIVATE DIP_CONFIG_HAS_ICS) endif() # libtiff set(DIP_ENABLE_TIFF ON CACHE BOOL "Enable TIFF file support") if(DIP_ENABLE_TIFF) - add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/libtiff" "${PROJECT_BINARY_DIR}/libtiff" EXCLUDE_FROM_ALL) - target_link_libraries(DIP PRIVATE tiff) + if(DIP_BUILD_BUNDLED_DEPENDENCIES) + add_subdirectory("${PROJECT_SOURCE_DIR}/dependencies/libtiff" "${PROJECT_BINARY_DIR}/libtiff" EXCLUDE_FROM_ALL) + add_library(TIFF::TIFF ALIAS tiff) + else() + find_package(TIFF REQUIRED) + endif() + target_link_libraries(DIP PRIVATE TIFF::TIFF) target_compile_definitions(DIP PRIVATE DIP_CONFIG_HAS_TIFF) endif() @@ -157,8 +192,7 @@ install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/" DESTINATION include # DIPlib unit tests if(DIP_ENABLE_DOCTEST) add_executable(unit_tests EXCLUDE_FROM_ALL "${CMAKE_CURRENT_LIST_DIR}/library/unit_tests.cpp") - target_include_directories(unit_tests PRIVATE "${PROJECT_SOURCE_DIR}/dependencies/doctest") - target_link_libraries(unit_tests PRIVATE DIP) + target_link_libraries(unit_tests PRIVATE DIP doctest::doctest) target_compile_definitions(unit_tests PRIVATE DIP_IMPLEMENT_UNIT_TESTS DIP_CONFIG_ENABLE_DOCTEST @@ -171,7 +205,7 @@ if(DIP_ENABLE_DOCTEST) set_target_properties(unit_tests PROPERTIES INSTALL_RPATH "$ORIGIN") endif() else() - include("${PROJECT_SOURCE_DIR}/dependencies/doctest/doctest_force_link_static_lib_in_target.cmake") + include(doctest_force_link_static_lib_in_target.cmake) doctest_force_link_static_lib_in_target(unit_tests DIP) # This pulls in all object files from the static DIP library endif() add_custom_target(check COMMAND unit_tests) diff --git a/tools/FindEigen3.cmake b/tools/FindEigen3.cmake new file mode 100644 index 000000000..98ab43d9e --- /dev/null +++ b/tools/FindEigen3.cmake @@ -0,0 +1,83 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version + +# Copyright (c) 2006, 2007 Montel Laurent, +# Copyright (c) 2008, 2009 Gael Guennebaud, +# Copyright (c) 2009 Benoit Jacob +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION + "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match + "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match + "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match + "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if(EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + +else(EIGEN3_INCLUDE_DIR) + + find_path( + EIGEN3_INCLUDE_DIR + NAMES signature_of_eigen3_matrix_library + PATHS ${CMAKE_INSTALL_PREFIX}/include ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) diff --git a/tools/FindICS.cmake b/tools/FindICS.cmake new file mode 100644 index 000000000..be7ba45af --- /dev/null +++ b/tools/FindICS.cmake @@ -0,0 +1,48 @@ +# Copyright (C) 2021 LuaDist. +# Created by Peter Kapec +# Modified by Cris Luengo to look for GLFW instead of FreeGLUT, and set a target. +# Modified by Milian Wolff to look for ICS instead of GLFW, and set a target. +# Redistribution and use of this file is allowed according to the terms of the MIT license. +# For details see the COPYRIGHT file distributed with LuaDist. +# Note: +# Searching headers and libraries is very simple and is NOT as powerful as scripts +# distributed with CMake, because LuaDist defines directories to search for. +# Everyone is encouraged to contact the author with improvements. Maybe this file +# becomes part of CMake distribution sometime. + +# - Find ICS +# Find the native ICS headers and libraries. +# +# ICS_INCLUDE_DIRS - where to find libics.h +# ICS_LIBRARIES - List of libraries when using ICS. +# ICS_FOUND - True if ICS found. +# ICS::ICS - Target to link to (automatically sets include directories and linked libraries) + +# Look for the header file. +find_path(ICS_INCLUDE_DIR NAMES libics.h) + +# Look for the library. +find_library(ICS_LIBRARY NAMES ics) + +# Handle the QUIETLY and REQUIRED arguments and set ICS_FOUND to TRUE if all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ICS DEFAULT_MSG ICS_LIBRARY ICS_INCLUDE_DIR) + +# Copy the results to the output variables. +if(ICS_FOUND) + set(ICS_LIBRARIES ${ICS_LIBRARY}) + set(ICS_INCLUDE_DIRS ${ICS_INCLUDE_DIR}) + if (NOT TARGET ICS::ICS) + add_library(ICS::ICS UNKNOWN IMPORTED) + set_target_properties(ICS::ICS PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${ICS_INCLUDE_DIRS}" + IMPORTED_LOCATION "${ICS_LIBRARY}") + endif() + message(STATUS "ICS found: ${ICS_LIBRARY} -- ${ICS_INCLUDE_DIR}") +else() + set(ICS_LIBRARIES) + set(ICS_INCLUDE_DIRS) + message(STATUS "ICS not found") +endif() + +mark_as_advanced(ICS_INCLUDE_DIRS ICS_LIBRARIES)