Newer
Older
cmake_minimum_required(VERSION 3.18)
# --------------------------------------------------------------------------------------------------
# Imagefusion project and default build type
# --------------------------------------------------------------------------------------------------
project(imagefusion VERSION 0.0.1)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Release or Debug")
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
# --------------------------------------------------------------------------------------------------
# Include some additional CMake modules
# --------------------------------------------------------------------------------------------------
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
include(TargetArch) # architecture
include(MiscUtils) # OS (is_symbol_defined)
include(CheckCXXCompilerFlag) # CHECK_CXX_COMPILER_FLAG
include(CheckCXXSymbolExists)
include(FetchContent)
# --------------------------------------------------------------------------------------------------
# Fix RPATH
# --------------------------------------------------------------------------------------------------
# use, i.e. don't skip the full RPATH for the build tree
set(CMAKE_SKIP_BUILD_RPATH FALSE)
# when building, don't use the install RPATH already (but later on when installing)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
# the RPATH to be used when installing, but only if it's not a system directory
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
if("${isSystemDir}" STREQUAL "-1")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
endif("${isSystemDir}" STREQUAL "-1")
# --------------------------------------------------------------------------------------------------
# Set source and header files
# --------------------------------------------------------------------------------------------------
include_directories(include)
src/image.cpp
src/geoinfo.cpp
src/starfm.cpp
src/estarfm.cpp
src/fitfc.cpp
src/fileformat.cpp
# --------------------------------------------------------------------------------------------------
# General compiler settings
# --------------------------------------------------------------------------------------------------
# release implies -O3 -DNDEBUG (on gcc)
# debug implies -g (on gcc)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_compile_options(-Wall -Wextra -Wno-missing-braces)
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
if(COMPILER_SUPPORTS_MARCH_NATIVE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
endif()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
add_compile_options(-LC_ALL=en_US.UTF-8)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON) # required for spdlog, since it is compiled as static lib, but linked into imagefusion, which is a dynamic lib.
add_compile_options(-pthread)
# set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) # Link Time Optimization (-flto -fno-fat-lto-objects) # does not work
check_cxx_symbol_exists(std::filesystem::path::preferred_separator filesystem HAS_FILESYSTEM_HEADER)
if(NOT HAS_FILESYSTEM_HEADER)
add_definitions(-DNO_FS_SUPPORT)
else() # filesystem header is there, but might have to be linked
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9) # gcc and clang require to link explicitly against filesystem before version 9
link_libraries(stdc++fs)
endif()
# --------------------------------------------------------------------------------------------------
# Find external libs
# --------------------------------------------------------------------------------------------------
option(IMAGEFUSION_FIND_LIB "Try to find and use a preinstalled libimagefusion, instead of building it" ON)
if(DEFINED ENV{IMAGEFUSION_FIND_LIB})
set(IMAGEFUSION_FIND_LIB $ENV{IMAGEFUSION_FIND_LIB})
endif()
if(IMAGEFUSION_FIND_LIB)
find_package(Imagefusion QUIET)
if(Imagefusion_FOUND)
message(STATUS "Found Imagefusion: ${Imagefusion_CONFIG}, Lib: ${Imagefusion_LIBRARY}")
endif()
endif()
# add site-packages to search path, since for python build, we prefer to use python dependencies... this is e. g. miniconda3/lib/python3.8/site-packages/pybind11/share/cmake/pybind11... does this help finding other packages??
if(SKBUILD)
execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "import pybind11; print(pybind11.get_cmake_dir())"
OUTPUT_VARIABLE _tmp_dir
OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ECHO STDOUT)
# message("Searching also in ${_tmp_dir} for CMake files.")
list(APPEND CMAKE_PREFIX_PATH "${_tmp_dir}")
endif()
# directly fetch pybind11, since distribution version (Ubuntu 20.04) is probably way too old for C++17
FetchContent_Declare(pybind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git
FetchContent_MakeAvailable(pybind11)
find_package(OpenCV REQUIRED core imgproc)
include_directories(${OpenCV_INCLUDE_DIRS})
set(LIBS ${LIBS} ${OpenCV_LIBS})
#message(STATUS "Found OpenCV: ${OpenCV_INCLUDE_DIRS}, ${OpenCV_LIBS}")
find_package(GDAL REQUIRED) # custom cmake module in cmake/Modules
set(TARGETS ${TARGETS} "GDAL::GDAL")
find_package(Boost OPTIONAL_COMPONENTS unit_test_framework)
set(TARGETS ${TARGETS} "Boost::boost") # include headers
find_package(Armadillo REQUIRED)
include_directories(${ARMADILLO_INCLUDE_DIRS})
set(LIBS ${LIBS} ${ARMADILLO_LIBRARIES})
#message(STATUS "Found Armadillo: ${ARMADILLO_INCLUDE_DIRS}, ${ARMADILLO_LIBRARIES}")
find_package(OpenMP)
if(OPENMP_CXX_FOUND OR OPENMP_FOUND)
set(TARGETS ${TARGETS} "OpenMP::OpenMP_CXX")
add_definitions(-DWITH_OMP)
set(SOURCES_TEST
${SOURCES_TEST}
)
endif()
find_package(spdlog QUIET)
if(fmt_FOUND)
set(SPDLOG_TEST_LIBS spdlog fmt)
else()
set(SPDLOG_TEST_LIBS spdlog)
endif()
# # This syntax requires CMake 3.25, which ships with Ubuntu 23.04 and Debian bookworm...
# try_compile(SPDLOG_COMPILE_SUCCESS
# PROJECT "spdlogtest"
# SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/spdlog-compile-test")
# # ...use older syntax for now.
try_compile(SPDLOG_COMPILE_SUCCESS
"${CMAKE_CURRENT_BINARY_DIR}/spdlog-compile-test"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/spdlog-compile-test/main.cpp"
LINK_LIBRARIES ${SPDLOG_TEST_LIBS}
OUTPUT_VARIABLE TESTOUTPUT
CXX_STANDARD ${CMAKE_CXX_STANDARD}
CXX_STANDARD_REQUIRED ON)
endif()
if(spdlog_FOUND AND SPDLOG_COMPILE_SUCCESS)
get_target_property(spdlog_LOCATION spdlog::spdlog IMPORTED_LOCATION_NONE)
message(STATUS "Found spdlog v${spdlog_VERSION}: ${spdlog_LOCATION}")
FetchContent_Declare(spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.12.0)
FetchContent_MakeAvailable(spdlog) # checks also for compiler options, so set them before!
set(TARGETS ${TARGETS} "spdlog::spdlog")
# --------------------------------------------------------------------------------------------------
# Output directories
# --------------------------------------------------------------------------------------------------
# for all targets except testimagefusion, testimagefusion outputs will be overwritten in tests/CMakeLists.txt
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# --------------------------------------------------------------------------------------------------
# Build targets
# --------------------------------------------------------------------------------------------------
# documentation targets (doc and docinternal)
option(IMAGEFUSION_BUILD_DOC "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
if(IMAGEFUSION_BUILD_DOC)
message(FATAL_ERROR "Doxygen is needed to build the documentation. If you do not want to build the documentation, just deselect the CMake option IMAGEFUSION_BUILD_DOC.")
set(doxyfile ${CMAKE_CURRENT_SOURCE_DIR}/doc/doxyfile)
set(doxyfile_internal ${CMAKE_CURRENT_SOURCE_DIR}/doc/doxyfileinternal)
COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
add_custom_target(docinternal
COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile_internal}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
endif()
# testimagefusion target
if(Boost_UNIT_TEST_FRAMEWORK_FOUND AND CMAKE_PROJECT_NAME STREQUAL imagefusion)
# message("Found Boost unit_test_framework: ${Boost_INCLUDE_DIRS}, ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}")
if(NOT Imagefusion_FOUND)
add_library(imagefusion SHARED ${SOURCES_LIB})
if(SKBUILD)
# make lib relocateable, i. e. searches at install location for dependend libs, like libgdal.so even if copied in miniconda3/lib/
set_target_properties(imagefusion PROPERTIES INSTALL_RPATH \$ORIGIN)
endif()
target_include_directories(imagefusion INTERFACE "$<INSTALL_INTERFACE:${GDAL_INCLUDE_DIR};include/imagefusion>")
target_link_libraries(imagefusion PUBLIC ${TARGETS} ${LIBS})
add_library(imagefusion::imagefusion ALIAS imagefusion)
endif()
# uninstall target (see https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
if(NOT TARGET uninstall)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
option(IMAGEFUSION_BUILD_PYTHON_INTERFACE "Build the python interface (target 'imfupython') by default in target all" ON)
if(DEFINED ENV{IMAGEFUSION_BUILD_PYTHON_INTERFACE})
set(IMAGEFUSION_BUILD_PYTHON_INTERFACE $ENV{IMAGEFUSION_BUILD_PYTHON_INTERFACE})
endif()
if(IMAGEFUSION_BUILD_PYTHON_INTERFACE)
add_library(imfupython MODULE python/src/interface.cpp)
set_target_properties(imfupython PROPERTIES PREFIX "")
set_target_properties(imfupython PROPERTIES OUTPUT_NAME "_imagefusion")
set_target_properties(imfupython PROPERTIES CXX_VISIBILITY_PRESET "hidden")
if(SKBUILD)
# make interface lib relocateable, i. e. searches relative to install location for libimagefusion.so, e. g. miniconda3/lib/libimagefusion.so is found from miniconda3/lib/python3.8/site-packages/imagefusion/
set_target_properties(imfupython PROPERTIES INSTALL_RPATH \$ORIGIN/../../..)
endif()
target_link_libraries(imfupython PRIVATE pybind11::module
PRIVATE imagefusion::imagefusion
PRIVATE GDAL::GDAL)
# --------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------
if(NOT DEFINED IMAGEFUSION_MASTER_PROJECT)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(IMAGEFUSION_MASTER_PROJECT ON)
else()
set(IMAGEFUSION_MASTER_PROJECT OFF)
endif()
endif()
option(IMAGEFUSION_INSTALL "Generate the install target" ${IMAGEFUSION_MASTER_PROJECT})
if(IMAGEFUSION_INSTALL)
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# install documentation
is_symbol_defined(symdef __linux__)
if(symdef)
# install directory structure
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doc/html/)
install(FILES doc/doc.html
DESTINATION share/doc/imagefusion
COMPONENT doc)
install(DIRECTORY doc/html
DESTINATION share/doc/imagefusion
COMPONENT doc)
endif()
endif()
is_symbol_defined(symdef _WIN32)
if(symdef)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doc/html/")
install(FILES doc/doc.html
DESTINATION doc
COMPONENT doc)
install(DIRECTORY doc/html
DESTINATION doc
COMPONENT doc)
endif()
endif()
is_symbol_defined(symdef __APPLE__)
if(symdef)
# FIXME: Don't know where macOS likes to have documentation
endif()
# install library and header
if(NOT Imagefusion_FOUND)
install(TARGETS imagefusion
EXPORT ImagefusionTargets
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT lib)
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
COMPONENT dev
FILES_MATCHING PATTERN "*.h")
endif()
# install python interface library into package dir (where also __init__.py resides)
if(IMAGEFUSION_BUILD_PYTHON_INTERFACE)
if(SKBUILD)
# find relative python path, like './lib/python3.8/site-packages' (destination with pip as user), from: https://stackoverflow.com/a/40006251/2414411
execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
from distutils import sysconfig as sc
print(sc.get_python_lib(prefix='.', plat_specific=True))" # the prefix '.' makes the difference
OUTPUT_VARIABLE PYTHON_SITE
OUTPUT_STRIP_TRAILING_WHITESPACE)
else()
# find relative python path, like 'lib/python3/dist-packages' (destination for make install as root user), from: https://stackoverflow.com/a/40006251/2414411
execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
from distutils import sysconfig as sc
print(sc.get_python_lib(prefix='', plat_specific=True))"
OUTPUT_VARIABLE PYTHON_SITE
OUTPUT_STRIP_TRAILING_WHITESPACE)
# only required when not installing with pip
install(FILES "python/__init__.py"
DESTINATION "${PYTHON_SITE}/${PROJECT_NAME}"
COMPONENT python)
endif()
install(TARGETS imfupython
LIBRARY DESTINATION "${PYTHON_SITE}/${PROJECT_NAME}"
COMPONENT python)
endif()
# Export CMake config file (for use in external projects)
if(NOT Imagefusion_FOUND)
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/imagefusion/ImagefusionConfigVersion.cmake"
VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}"
COMPATIBILITY AnyNewerVersion
)
export(EXPORT ImagefusionTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/imagefusion/ImagefusionTargets.cmake"
NAMESPACE imagefusion::
)
configure_file(cmake/ImagefusionConfig.cmake
"${CMAKE_CURRENT_BINARY_DIR}/imagefusion/ImagefusionConfig.cmake"
COPYONLY
)
set(ConfigPackageLocation "${CMAKE_INSTALL_LIBDIR}/cmake/imagefusion")
install(EXPORT ImagefusionTargets
FILE ImagefusionTargets.cmake
NAMESPACE imagefusion::
DESTINATION ${ConfigPackageLocation}
COMPONENT dev
)
install(FILES cmake/ImagefusionConfig.cmake
"${CMAKE_CURRENT_BINARY_DIR}/imagefusion/ImagefusionConfigVersion.cmake"
DESTINATION ${ConfigPackageLocation}
COMPONENT dev
)
endif()
# packaging with CPack
include(cmake/ImagefusionCPack.cmake)
# --------------------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------
if(SKBUILD)
# make binaries relocateable, i. e. searches relative to install location for libimagefusion
set(CMAKE_INSTALL_RPATH \$ORIGIN/../lib)
endif()
# must be added after the installation part
option(IMAGEFUSION_BUILD_UTILS "Build the utilities (starfm, imggeocrop, ...) by default in target all" ON)
if(DEFINED ENV{IMAGEFUSION_BUILD_UTILS})
set(IMAGEFUSION_BUILD_UTILS $ENV{IMAGEFUSION_BUILD_UTILS})
endif()
if(IMAGEFUSION_BUILD_UTILS)
add_subdirectory("utils")
endif()
# --------------------------------------------------------------------------------------------------
# Fix for QtCreator IDE, meaningless for CMake
# --------------------------------------------------------------------------------------------------
# if you add a header file run "cmake .." in build again to update QTCreator
file(GLOB_RECURSE HeaderFiles "include/*.h")
file(GLOB_RECURSE TestHeaderFiles "tests/*.h")
file(GLOB_RECURSE TestHeaderFiles "utils/*.h")
add_custom_target(headers SOURCES ${HeaderFiles} ${TestHeaderFiles})