Replace include_directories() with target_include_directories().
- Now that we require CMake >= 3.x, we can roll the definition of the
include directories for clients linking against Ceres into the
exported Ceres CMake target via target_include_directories().
- This removes the requirement for CERES_INCLUDE_DIRS.
Change-Id: Ibe3bbf796339871d66138fc9520053d1766f09a8
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a1fe27f..e37384d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -472,39 +472,6 @@
mark_as_advanced(benchmark_DIR)
endif()
-include_directories(
- include
- internal
- internal/ceres
- ${GLOG_INCLUDE_DIRS})
-
-# Eigen SparseQR generates various compiler warnings related to unused and
-# uninitialised local variables. To avoid having to individually suppress these
-# warnings around the #include statments for Eigen headers across all GCC/Clang
-# versions, we tell CMake to treat Eigen headers as system headers. This
-# results in all compiler warnings from them being suppressed.
-#
-# Note that this is *not* propagated to clients, ie CERES_INCLUDE_DIRS
-# used by clients after find_package(Ceres) does not identify Eigen as
-# as system headers.
-include_directories(SYSTEM ${EIGEN_INCLUDE_DIRS})
-
-if (SUITESPARSE)
- include_directories(${SUITESPARSE_INCLUDE_DIRS})
-endif (SUITESPARSE)
-
-if (CXSPARSE)
- include_directories(${CXSPARSE_INCLUDE_DIRS})
-endif (CXSPARSE)
-
-if (ACCELERATESPARSE)
- include_directories(${AccelerateSparse_INCLUDE_DIRS})
-endif()
-
-if (GFLAGS)
- include_directories(${GFLAGS_INCLUDE_DIRS})
-endif (GFLAGS)
-
if (BUILD_SHARED_LIBS)
message("-- Building Ceres as a shared library.")
# The CERES_BUILDING_SHARED_LIBRARY compile definition is NOT stored in
@@ -651,12 +618,6 @@
include(CreateCeresConfig)
create_ceres_config("${CERES_COMPILE_OPTIONS}"
${Ceres_BINARY_DIR}/config/ceres/internal)
-# Force the location containing the configured config.h to the front of the
-# include_directories list (by default it is appended to the back) to ensure
-# that if the user has an installed version of Ceres in the same location as one
-# of the dependencies (e.g. /usr/local) that we find the config.h we just
-# configured, not the (older) installed config.h.
-include_directories(BEFORE ${Ceres_BINARY_DIR}/config)
add_subdirectory(internal/ceres)
diff --git a/cmake/CeresConfig.cmake.in b/cmake/CeresConfig.cmake.in
index 957b99d..009e32f 100644
--- a/cmake/CeresConfig.cmake.in
+++ b/cmake/CeresConfig.cmake.in
@@ -50,21 +50,15 @@
#
# CERES_VERSION: Version of Ceres found.
#
-# CERES_INCLUDE_DIRS: Include directories for Ceres and the
-# dependencies which appear in the Ceres public
-# API and are thus required to use Ceres.
-#
# CERES_LIBRARIES: Libraries for Ceres and all
# dependencies against which Ceres was
# compiled. This will not include any optional
# dependencies that were disabled when Ceres was
# compiled.
#
-# The following variables are also defined for legacy compatibility
-# only. Any new code should not use them as they do not conform to
-# the standard CMake FindPackage naming conventions.
-#
-# CERES_INCLUDES = ${CERES_INCLUDE_DIRS}.
+# NOTE: There is no equivalent of CERES_INCLUDE_DIRS as the exported
+# CMake target already includes the definition of its public
+# include directories.
# Called if we failed to find Ceres or any of its required dependencies,
# unsets all public (designed to be used externally) variables and reports
@@ -74,6 +68,7 @@
# explicitly set FALSE to denote not found (not merely undefined).
set(Ceres_FOUND FALSE)
set(CERES_FOUND FALSE)
+ unset(CERES_INCLUDE_DIR)
unset(CERES_INCLUDE_DIRS)
unset(CERES_LIBRARIES)
@@ -143,18 +138,6 @@
"outside of CMake after Ceres was built.")
endif (NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR})
- # Set the include directories for Ceres (itself).
- set(CERES_INCLUDE_DIR "${CURRENT_ROOT_INSTALL_DIR}/include")
- if (NOT EXISTS ${CERES_INCLUDE_DIR}/ceres/ceres.h)
- ceres_report_not_found(
- "Ceres install root: ${CURRENT_ROOT_INSTALL_DIR}, "
- "determined from relative path from CeresConfig.cmake install location: "
- "${CERES_CURRENT_CONFIG_DIR}, does not contain Ceres headers. "
- "Either the install directory was deleted, or the install tree was only "
- "partially relocated outside of CMake after Ceres was built.")
- endif (NOT EXISTS ${CERES_INCLUDE_DIR}/ceres/ceres.h)
- list(APPEND CERES_INCLUDE_DIRS ${CERES_INCLUDE_DIR})
-
else(CERES_WAS_INSTALLED)
# Ceres was exported from the build tree.
set(CERES_EXPORTED_BUILD_DIR ${CERES_CURRENT_CONFIG_DIR})
@@ -173,28 +156,6 @@
# with Ceres to find Ceres' dependencies, even if the user has equivalently
# named FindPackage() scripts in their project.
set(CMAKE_MODULE_PATH ${CERES_EXPORTED_SOURCE_DIR}/cmake)
-
- # Set the include directories for Ceres (itself).
- set(CERES_INCLUDE_DIR "${CERES_EXPORTED_SOURCE_DIR}/include")
- if (NOT EXISTS ${CERES_INCLUDE_DIR}/ceres/ceres.h)
- ceres_report_not_found(
- "Ceres exported source directory: ${CERES_EXPORTED_SOURCE_DIR}, "
- "determined from relative path from CeresConfig.cmake exported build "
- "directory: ${CERES_EXPORTED_BUILD_DIR}, does not contain Ceres headers.")
- endif (NOT EXISTS ${CERES_INCLUDE_DIR}/ceres/ceres.h)
- list(APPEND CERES_INCLUDE_DIRS ${CERES_INCLUDE_DIR})
-
- # Append the path to the configured config.h in the exported build directory
- # to the Ceres include directories.
- set(CERES_CONFIG_FILE
- ${CERES_EXPORTED_BUILD_DIR}/config/ceres/internal/config.h)
- if (NOT EXISTS ${CERES_CONFIG_FILE})
- ceres_report_not_found(
- "Ceres exported build directory: ${CERES_EXPORTED_BUILD_DIR}, "
- "does not contain required configured Ceres config.h, it is not here: "
- "${CERES_CONFIG_FILE}.")
- endif (NOT EXISTS ${CERES_CONFIG_FILE})
- list(APPEND CERES_INCLUDE_DIRS ${CERES_EXPORTED_BUILD_DIR}/config)
endif(CERES_WAS_INSTALLED)
# Set the version.
@@ -234,33 +195,24 @@
"dependency: Eigen version ${CERES_EIGEN_VERSION}, please set "
"EIGEN_INCLUDE_DIR.")
endif (EIGEN_FOUND)
-list(APPEND CERES_INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS})
# Glog.
# Flag set during configuration and build of Ceres.
set(CERES_USES_MINIGLOG @MINIGLOG@)
set(CERES_USES_GFLAGS @GFLAGS@)
if (CERES_USES_MINIGLOG)
- set(MINIGLOG_INCLUDE_DIR ${CERES_INCLUDE_DIR}/ceres/internal/miniglog)
- if (NOT CERES_WAS_INSTALLED)
- # When Ceres was exported from the build tree, the miniglog headers
- # will be in Ceres internal source directory, not in the public headers
- # directory (they are copied with the public headers when installed).
- set(MINIGLOG_INCLUDE_DIR
- ${CERES_EXPORTED_SOURCE_DIR}/internal/ceres/miniglog)
- endif()
- if (NOT EXISTS ${MINIGLOG_INCLUDE_DIR})
- ceres_report_not_found(
- "Failed to find miniglog headers in expected include directory: "
- "${MINIGLOG_INCLUDE_DIR}, but Ceres was compiled with MINIGLOG enabled "
- "(in place of glog).")
- endif (NOT EXISTS ${MINIGLOG_INCLUDE_DIR})
- list(APPEND CERES_INCLUDE_DIRS ${MINIGLOG_INCLUDE_DIR})
# Output message at standard log level (not the lower STATUS) so that
# the message is output in GUI during configuration to warn user.
message("-- Found Ceres compiled with miniglog substitute "
"for glog, beware this will likely cause problems if glog is later linked.")
-else (CERES_USES_MINIGLOG)
+else(CERES_USES_MINIGLOG)
+ # As imported CMake targets are not re-exported when a dependent target is
+ # exported, we must invoke find_package(XXX) here to reload the definition
+ # of their targets. Without this, the dependency target names (e.g.
+ # 'gflags-shared') which will be present in the ceres target would not be
+ # defined, and so CMake will assume that they refer to a library name and
+ # fail to link correctly.
+
# Append the locations of glog when Ceres was built to the search path hints.
set(GLOG_WAS_BUILT_WITH_CMAKE @FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION@)
if (GLOG_WAS_BUILT_WITH_CMAKE)
@@ -271,29 +223,19 @@
get_filename_component(CERES_BUILD_GLOG_LIBRARY_DIR @GLOG_LIBRARY@ PATH)
list(APPEND GLOG_LIBRARY_DIR_HINTS ${CERES_BUILD_GLOG_LIBRARY_DIR})
endif()
-
# Search quietly s/t we control the timing of the error message if not found.
find_package(Glog QUIET)
if (GLOG_FOUND)
message(STATUS "Found required Ceres dependency: glog")
- else (GLOG_FOUND)
+ else()
ceres_report_not_found("Missing required Ceres "
"dependency: glog. Searched using GLOG_INCLUDE_DIR_HINTS: "
"${GLOG_INCLUDE_DIR_HINTS} and glog_DIR: ${glog_DIR}.")
- endif (GLOG_FOUND)
- list(APPEND CERES_INCLUDE_DIRS ${GLOG_INCLUDE_DIRS})
+ endif()
# gflags is only a public dependency of Ceres via glog, thus is not required
# if Ceres was built with MINIGLOG.
if (CERES_USES_GFLAGS)
- # If gflags was found as an imported CMake target, we need to call
- # find_packge(Gflags) again here, as imported CMake targets are not
- # re-exported. Without this, the 'gflags-shared' target name which is
- # present in CERES_LIBRARIES in this case would not be defined, and so
- # CMake will assume it is a library name (which it is not) and fail to link.
- #
- # Append the locations of gflags when Ceres was built to the search path
- # hints.
set(GFLAGS_WAS_BUILT_WITH_CMAKE @FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION@)
if (GFLAGS_WAS_BUILT_WITH_CMAKE)
set(gflags_DIR @gflags_DIR@)
@@ -303,7 +245,6 @@
get_filename_component(CERES_BUILD_GFLAGS_LIBRARY_DIR @GFLAGS_LIBRARY@ PATH)
list(APPEND GFLAGS_LIBRARY_DIR_HINTS ${CERES_BUILD_GFLAGS_LIBRARY_DIR})
endif()
-
# Search quietly s/t we control the timing of the error message if not found.
find_package(Gflags QUIET)
if (GFLAGS_FOUND)
@@ -313,9 +254,8 @@
"dependency: gflags. Searched using GFLAGS_INCLUDE_DIR_HINTS: "
"${GFLAGS_INCLUDE_DIR_HINTS} and gflags_DIR: ${gflags_DIR}.")
endif()
- list(APPEND CERES_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIRS})
endif()
-endif (CERES_USES_MINIGLOG)
+endif(CERES_USES_MINIGLOG)
# Import exported Ceres targets, if they have not already been imported.
if (NOT TARGET ceres AND NOT Ceres_BINARY_DIR)
@@ -324,9 +264,6 @@
# Set the expected XX_LIBRARIES variable for FindPackage().
set(CERES_LIBRARIES ceres)
-# Set legacy include directories variable for backwards compatibility.
-set(CERES_INCLUDES ${CERES_INCLUDE_DIRS})
-
# Reset CMake module path to its state when this script was called.
set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH})
diff --git a/cmake/uninstall.cmake.in b/cmake/uninstall.cmake.in
index 06cac80..124deb1 100644
--- a/cmake/uninstall.cmake.in
+++ b/cmake/uninstall.cmake.in
@@ -29,11 +29,6 @@
# Author: arnaudgelas@gmail.com (Arnaud Gelas)
# alexs.mac@gmail.com (Alex Stewart)
-if (COMMAND cmake_policy)
- # Ignore empty elements in LIST() commands.
- cmake_policy(SET CMP0007 OLD)
-endif (COMMAND cmake_policy)
-
if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: "
"\"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
index 00158cf..24ccc0c 100644
--- a/docs/source/installation.rst
+++ b/docs/source/installation.rst
@@ -867,12 +867,11 @@
.. code-block:: cmake
- cmake_minimum_required(VERSION 2.8)
+ cmake_minimum_required(VERSION 3.5)
project(helloworld)
find_package(Ceres REQUIRED)
- include_directories(${CERES_INCLUDE_DIRS})
# helloworld
add_executable(helloworld helloworld.cc)
@@ -886,6 +885,13 @@
``Ceres_DIR`` should be the path to the exported Ceres build
directory.
+ .. NOTE ::
+
+ You do not need to call include_directories(${CERES_INCLUDE_DIRS})
+ as the exported Ceres CMake target already contains the definitions
+ of its public include directories which will be automatically
+ included by CMake when compiling a target that links against Ceres.
+
Specify Ceres components
-------------------------------------
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index 38ba9d4..a6999d8 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -271,6 +271,80 @@
target_link_libraries(ceres ${CERES_LIBRARY_DEPENDENCIES})
endif (BUILD_SHARED_LIBS)
+# Add the Ceres headers to its target.
+#
+# Force the location containing the configured config.h to the front of the
+# include_directories list (by default it is appended to the back) to ensure
+# that if the user has an installed version of Ceres in the same location as one
+# of the dependencies (e.g. /usr/local) that we find the config.h we just
+# configured, not the (older) installed config.h.
+target_include_directories(ceres BEFORE PUBLIC
+ $<BUILD_INTERFACE:${Ceres_BINARY_DIR}/config>)
+target_include_directories(ceres PRIVATE ${Ceres_SOURCE_DIR}/internal)
+target_include_directories(ceres PUBLIC
+ $<BUILD_INTERFACE:${Ceres_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:include>)
+
+# Eigen SparseQR generates various compiler warnings related to unused and
+# uninitialised local variables. To avoid having to individually suppress these
+# warnings around the #include statments for Eigen headers across all GCC/Clang
+# versions, we tell CMake to treat Eigen headers as system headers. This
+# results in all compiler warnings from them being suppressed.
+target_include_directories(ceres SYSTEM PUBLIC ${EIGEN_INCLUDE_DIRS})
+
+# Gather the list of public & private include locations for all enabled optional
+# dependencies to be added to the Ceres target.
+set(CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS "")
+set(CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS "")
+if (MINIGLOG)
+ # Force the miniglog headers to the front of the public include directories
+ # to protect against the case when the user has glog installed in a standard
+ # location (specifically the same as the Ceres install location) but compiled
+ # Ceres with MINIGLOG anyway. Otherwise: "glog/logging.h" in the public Ceres
+ # headers used in client code would match the installed version of glog, not
+ # the miniglog headers, and the client application would fail to link.
+ #
+ # Note that this is an imperfect fix, as we cannot control the include
+ # directories in client projects, and they could easily invert this ordering
+ # themselves (intentionally or otherwise) and so break their build.
+ target_include_directories(ceres BEFORE PUBLIC
+ $<BUILD_INTERFACE:${Ceres_SOURCE_DIR}/internal/ceres/miniglog>
+ $<INSTALL_INTERFACE:include/ceres/internal/miniglog>)
+elseif (NOT FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
+ # Only append glog include directories if the glog found was not a CMake
+ # exported target that already includes them.
+ list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS
+ ${GLOG_INCLUDE_DIRS})
+endif()
+if (SUITESPARSE)
+ list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
+ ${SUITESPARSE_INCLUDE_DIRS})
+endif()
+if (CXSPARSE)
+ list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
+ ${CXSPARSE_INCLUDE_DIRS})
+endif()
+if (ACCELERATESPARSE)
+ list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
+ ${AccelerateSparse_INCLUDE_DIRS})
+endif()
+if (GFLAGS AND NOT FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION)
+ # Only append gflags include directories if the gflags found was not a CMake
+ # exported target that already includes them.
+ list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS
+ ${GFLAGS_INCLUDE_DIRS})
+endif()
+# Add include locations for optional dependencies to the Ceres target without
+# duplication.
+list(REMOVE_DUPLICATES CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS)
+foreach(INC_DIR ${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
+ target_include_directories(ceres PRIVATE ${INC_DIR})
+endforeach()
+list(REMOVE_DUPLICATES CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS)
+foreach(INC_DIR ${CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS})
+ target_include_directories(ceres PUBLIC ${INC_DIR})
+endforeach()
+
install(TARGETS ceres
EXPORT CeresExport
RUNTIME DESTINATION bin
@@ -289,6 +363,7 @@
evaluator_test_utils.cc
numeric_diff_test_utils.cc
test_util.cc)
+ target_include_directories(test_util PUBLIC ${Ceres_SOURCE_DIR}/internal)
if (MINIGLOG)
# When using miniglog, it is compiled into Ceres, thus Ceres becomes
@@ -302,6 +377,11 @@
macro (CERES_TEST NAME)
add_executable(${NAME}_test ${NAME}_test.cc)
+ # Pull in local headers from the generated test directories when ceres_test()
+ # is invoked there, as well as the private headers in this directory which
+ # may be referenced without the 'ceres' path prefix.
+ target_include_directories(${NAME}_test PUBLIC ${CMAKE_CURRENT_LIST_DIR})
+ target_include_directories(${NAME}_test PUBLIC ${Ceres_SOURCE_DIR}/internal/ceres)
target_link_libraries(${NAME}_test test_util ceres gtest)
if (BUILD_SHARED_LIBS)
# Define gtest-specific shared library flags for linking.
@@ -403,13 +483,18 @@
endif (BUILD_TESTING AND GFLAGS)
+macro(add_dependencies_to_benchmark BENCHMARK_TARGET)
+ target_link_libraries(${BENCHMARK_TARGET} ceres benchmark::benchmark)
+ target_include_directories(${BENCHMARK_TARGET} PUBLIC ${Ceres_SOURCE_DIR}/internal)
+endmacro()
+
if (BUILD_BENCHMARKS)
add_executable(autodiff_cost_function_benchmark autodiff_cost_function_benchmark.cc)
- target_link_libraries(autodiff_cost_function_benchmark ceres benchmark::benchmark)
+ add_dependencies_to_benchmark(autodiff_cost_function_benchmark)
add_executable(small_blas_gemv_benchmark small_blas_gemv_benchmark.cc)
- target_link_libraries(small_blas_gemv_benchmark ceres benchmark::benchmark)
+ add_dependencies_to_benchmark(small_blas_gemv_benchmark)
add_executable(small_blas_gemm_benchmark small_blas_gemm_benchmark.cc)
- target_link_libraries(small_blas_gemm_benchmark ceres benchmark::benchmark)
+ add_dependencies_to_benchmark(small_blas_gemm_benchmark)
endif (BUILD_BENCHMARKS)