Add namespace qualified Ceres::ceres CMake target
- This reflects modern CMake style, and also provides a measure of
protection against missing find_package() imports in downstream
clients resulting in linker errors when 'ceres' matches the compiled
library and not the imported target.
- The original 'ceres' target remains, as a local imported interface
target created by CeresConfig for backwards compatibility.
Change-Id: Ie9ed8de9b7059bc0cae1ae5002bb94d8fe617188
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a0de03..76e08d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -729,6 +729,7 @@
# imported library targets for Ceres (with dependency relations) which can be
# used in target_link_libraries() calls in the client project to use Ceres.
install(EXPORT CeresExport
+ NAMESPACE Ceres::
DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR} FILE CeresTargets.cmake)
# Save the relative path from the installed CeresConfig.cmake file to the
@@ -784,7 +785,9 @@
# Analogously to install(EXPORT ...), export the Ceres target from the build
# directory as a package called Ceres into the local CMake package registry.
- export(TARGETS ceres FILE ${Ceres_BINARY_DIR}/CeresTargets.cmake)
+ export(TARGETS ceres
+ NAMESPACE Ceres::
+ FILE ${Ceres_BINARY_DIR}/CeresTargets.cmake)
export(PACKAGE ${CMAKE_PROJECT_NAME})
# Configure a CeresConfig.cmake file for the export of the Ceres build
diff --git a/cmake/CeresConfig.cmake.in b/cmake/CeresConfig.cmake.in
index 94099a9..7ad5bed 100644
--- a/cmake/CeresConfig.cmake.in
+++ b/cmake/CeresConfig.cmake.in
@@ -262,7 +262,7 @@
include(${CERES_CURRENT_CONFIG_DIR}/CeresTargets.cmake)
endif (NOT TARGET ceres AND NOT Ceres_BINARY_DIR)
# Set the expected XX_LIBRARIES variable for FindPackage().
-set(CERES_LIBRARIES ceres)
+set(CERES_LIBRARIES Ceres::ceres)
# Reset CMake module path to its state when this script was called.
set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH})
@@ -320,3 +320,11 @@
# Ceres_FOUND is not (explicitly, i.e. undefined does not count) set
# to FALSE.
set(CERES_FOUND TRUE)
+
+if (NOT TARGET ceres)
+ # For backwards compatibility, create a local 'alias' target with the
+ # non-namespace-qualified Ceres target name. Note that this is not a
+ # true ALIAS library in CMake terms as they cannot point to imported targets.
+ add_library(ceres INTERFACE IMPORTED)
+ set_target_properties(ceres PROPERTIES INTERFACE_LINK_LIBRARIES Ceres::ceres)
+endif()
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
index c6ddfff..3a6a5d4 100644
--- a/docs/source/installation.rst
+++ b/docs/source/installation.rst
@@ -849,13 +849,13 @@
# helloworld
add_executable(helloworld helloworld.cc)
- target_link_libraries(helloworld ${CERES_LIBRARIES})
+ target_link_libraries(helloworld Ceres::ceres)
Irrespective of whether Ceres was installed or exported, if multiple
versions are detected, set: ``Ceres_DIR`` to control which is used.
If Ceres was installed ``Ceres_DIR`` should be the path to the
directory containing the installed ``CeresConfig.cmake`` file
-(e.g. ``/usr/local/share/Ceres``). If Ceres was exported, then
+(e.g. ``/usr/local/lib/cmake/Ceres``). If Ceres was exported, then
``Ceres_DIR`` should be the path to the exported Ceres build
directory.
@@ -998,7 +998,7 @@
directory is exported into the local CMake package registry (see
:ref:`section-install-vs-export`), in addition to the public headers
and compiled libraries, a set of CMake-specific project configuration
-files are also installed to: ``<INSTALL_ROOT>/share/Ceres`` (if Ceres
+files are also installed to: ``<INSTALL_ROOT>/lib/cmake/Ceres`` (if Ceres
is installed), or created in the build directory (if Ceres' build
directory is exported). When `find_package
<http://www.cmake.org/cmake/help/v3.2/command/find_package.html>`_ is
@@ -1013,9 +1013,9 @@
Which is written by the developers of the project, and is
configured with the selected options and installed locations when
- the project is built and defines the CMake variables:
- ``<PROJECT_NAME>_INCLUDE_DIRS`` & ``<PROJECT_NAME>_LIBRARIES``
- which are used by the caller to import the project.
+ the project is built and imports the project targets and/or defines
+ the legacy CMake variables: ``<PROJECT_NAME>_INCLUDE_DIRS`` &
+ ``<PROJECT_NAME>_LIBRARIES`` which are used by the caller.
The ``<PROJECT_NAME>Config.cmake`` typically includes a second file
installed to the same location:
@@ -1030,32 +1030,26 @@
project using ``add_library()``. However, imported targets refer to
objects that have already been built by a different CMake project.
Principally, an imported target contains the location of the compiled
-object and all of its public dependencies required to link against it.
-Any locally declared target can depend on an imported target, and
-CMake will manage the dependency chain, just as if the imported target
-had been declared locally by the current project.
+object and all of its public dependencies required to link against it
+as well as all required include directories. Any locally declared target
+can depend on an imported target, and CMake will manage the dependency
+chain, just as if the imported target had been declared locally by the
+current project.
Crucially, just like any locally declared CMake target, an imported target is
identified by its **name** when adding it as a dependency to another target.
-Thus, if in a project using Ceres you had the following in your CMakeLists.txt:
+Since v2.0, Ceres has used the target namespace feature of CMake to prefix
+its export targets: ``Ceres::ceres``. However, historically the Ceres target
+did not have a namespace, and was just called ``ceres``.
-.. code-block:: cmake
-
- find_package(Ceres REQUIRED)
- message("CERES_LIBRARIES = ${CERES_LIBRARIES}")
-
-You would see the output: ``CERES_LIBRARIES = ceres``. **However**,
-here ``ceres`` is an **imported target** created when
-``CeresTargets.cmake`` was read as part of ``find_package(Ceres
-REQUIRED)``. It does **not** refer (directly) to the compiled Ceres
-library: ``libceres.a/so/dylib/lib``. This distinction is important,
-as depending on the options selected when it was built, Ceres can have
-public link dependencies which are encapsulated in the imported target
-and automatically added to the link step when Ceres is added as a
-dependency of another target by CMake. In this case, linking only
-against ``libceres.a/so/dylib/lib`` without these other public
-dependencies would result in a linker error.
+Whilst an alias target called ``ceres`` is still provided in v2.0 for backwards
+compatibility, it creates a potential drawback, if you failed to call
+``find_package(Ceres)``, and Ceres is installed in a default search path for
+your compiler, then instead of matching the imported Ceres target, it will
+instead match the installed libceres.so/dylib/a library. If this happens you
+will get either compiler errors for missing include directories or linker errors
+due to missing references to Ceres public dependencies.
Note that this description applies both to projects that are
**installed** using CMake, and to those whose **build directory is
@@ -1119,26 +1113,6 @@
.. code-block:: cmake
- # Importing Ceres in FooConfig.cmake using CMake 2.8.x style.
- #
- # When configure_file() is used to generate FooConfig.cmake from
- # FooConfig.cmake.in, @Ceres_DIR@ will be replaced with the current
- # value of Ceres_DIR being used by Foo. This should be passed as a hint
- # when invoking find_package(Ceres) to ensure that the same install of
- # Ceres is used as was used to build Foo.
- set(CERES_DIR_HINTS @Ceres_DIR@)
-
- # Forward the QUIET / REQUIRED options.
- if (Foo_FIND_QUIETLY)
- find_package(Ceres QUIET HINTS ${CERES_DIR_HINTS})
- elseif (Foo_FIND_REQUIRED)
- find_package(Ceres REQUIRED HINTS ${CERES_DIR_HINTS})
- else ()
- find_package(Ceres HINTS ${CERES_DIR_HINTS})
- endif()
-
-.. code-block:: cmake
-
# Importing Ceres in FooConfig.cmake using CMake 3.x style.
#
# In CMake v3.x, the find_dependency() macro exists to forward the REQUIRED
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 3d86be8..a6b3f5d 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -36,22 +36,22 @@
endif()
add_executable(helloworld helloworld.cc)
-target_link_libraries(helloworld ceres)
+target_link_libraries(helloworld Ceres::ceres)
add_executable(helloworld_numeric_diff helloworld_numeric_diff.cc)
-target_link_libraries(helloworld_numeric_diff ceres)
+target_link_libraries(helloworld_numeric_diff Ceres::ceres)
add_executable(helloworld_analytic_diff helloworld_analytic_diff.cc)
-target_link_libraries(helloworld_analytic_diff ceres)
+target_link_libraries(helloworld_analytic_diff Ceres::ceres)
add_executable(curve_fitting curve_fitting.cc)
-target_link_libraries(curve_fitting ceres)
+target_link_libraries(curve_fitting Ceres::ceres)
add_executable(rosenbrock rosenbrock.cc)
-target_link_libraries(rosenbrock ceres)
+target_link_libraries(rosenbrock Ceres::ceres)
add_executable(curve_fitting_c curve_fitting.c)
-target_link_libraries(curve_fitting_c ceres)
+target_link_libraries(curve_fitting_c Ceres::ceres)
# Force CMake to link curve_fitting_c using the C linker, this is important
# when Ceres was compiled using C++11 to ensure that -std=c++11 is not passed
# through.
@@ -64,51 +64,51 @@
endif (NOT MSVC)
add_executable(ellipse_approximation ellipse_approximation.cc)
-target_link_libraries(ellipse_approximation ceres)
+target_link_libraries(ellipse_approximation Ceres::ceres)
add_executable(robust_curve_fitting robust_curve_fitting.cc)
-target_link_libraries(robust_curve_fitting ceres)
+target_link_libraries(robust_curve_fitting Ceres::ceres)
add_executable(simple_bundle_adjuster simple_bundle_adjuster.cc)
-target_link_libraries(simple_bundle_adjuster ceres)
+target_link_libraries(simple_bundle_adjuster Ceres::ceres)
if (GFLAGS)
add_executable(powell powell.cc)
- target_link_libraries(powell ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(powell Ceres::ceres ${GFLAGS_LIBRARIES})
add_executable(nist nist.cc)
- target_link_libraries(nist ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(nist Ceres::ceres ${GFLAGS_LIBRARIES})
if (MSVC)
target_compile_options(nist PRIVATE "/bigobj")
endif()
add_executable(more_garbow_hillstrom more_garbow_hillstrom.cc)
- target_link_libraries(more_garbow_hillstrom ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(more_garbow_hillstrom Ceres::ceres ${GFLAGS_LIBRARIES})
add_executable(circle_fit circle_fit.cc)
- target_link_libraries(circle_fit ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(circle_fit Ceres::ceres ${GFLAGS_LIBRARIES})
add_executable(bundle_adjuster
bundle_adjuster.cc
bal_problem.cc)
- target_link_libraries(bundle_adjuster ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(bundle_adjuster Ceres::ceres ${GFLAGS_LIBRARIES})
add_executable(libmv_bundle_adjuster
libmv_bundle_adjuster.cc)
- target_link_libraries(libmv_bundle_adjuster ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(libmv_bundle_adjuster Ceres::ceres ${GFLAGS_LIBRARIES})
add_executable(libmv_homography
libmv_homography.cc)
- target_link_libraries(libmv_homography ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(libmv_homography Ceres::ceres ${GFLAGS_LIBRARIES})
add_executable(denoising
denoising.cc
fields_of_experts.cc)
- target_link_libraries(denoising ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(denoising Ceres::ceres ${GFLAGS_LIBRARIES})
add_executable(robot_pose_mle
robot_pose_mle.cc)
- target_link_libraries(robot_pose_mle ceres ${GFLAGS_LIBRARIES})
+ target_link_libraries(robot_pose_mle Ceres::ceres ${GFLAGS_LIBRARIES})
endif (GFLAGS)
diff --git a/examples/sampled_function/CMakeLists.txt b/examples/sampled_function/CMakeLists.txt
index 57f31d1..8a17cad 100644
--- a/examples/sampled_function/CMakeLists.txt
+++ b/examples/sampled_function/CMakeLists.txt
@@ -29,4 +29,4 @@
# Author: vitus@google.com (Michael Vitus)
add_executable(sampled_function sampled_function.cc)
-target_link_libraries(sampled_function ceres)
+target_link_libraries(sampled_function Ceres::ceres)
diff --git a/examples/slam/pose_graph_2d/CMakeLists.txt b/examples/slam/pose_graph_2d/CMakeLists.txt
index d654e8c..2b35c7f 100644
--- a/examples/slam/pose_graph_2d/CMakeLists.txt
+++ b/examples/slam/pose_graph_2d/CMakeLists.txt
@@ -35,5 +35,5 @@
pose_graph_2d.cc
pose_graph_2d_error_term.h
types.h)
- target_link_libraries(pose_graph_2d ceres ${GFLAGS_LIBRARIES})
-endif (GFLAGS)
\ No newline at end of file
+ target_link_libraries(pose_graph_2d Ceres::ceres ${GFLAGS_LIBRARIES})
+endif (GFLAGS)
diff --git a/examples/slam/pose_graph_3d/CMakeLists.txt b/examples/slam/pose_graph_3d/CMakeLists.txt
index 2c5fdc3..b75e2ce 100644
--- a/examples/slam/pose_graph_3d/CMakeLists.txt
+++ b/examples/slam/pose_graph_3d/CMakeLists.txt
@@ -30,5 +30,5 @@
if (GFLAGS)
add_executable(pose_graph_3d pose_graph_3d.cc)
- target_link_libraries(pose_graph_3d ceres ${GFLAGS_LIBRARIES})
-endif (GFLAGS)
\ No newline at end of file
+ target_link_libraries(pose_graph_3d Ceres::ceres ${GFLAGS_LIBRARIES})
+endif (GFLAGS)
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index 3711222..80125c9 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -346,6 +346,9 @@
LIBRARY DESTINATION lib${LIB_SUFFIX}
ARCHIVE DESTINATION lib${LIB_SUFFIX})
+# Create a local alias target that matches the expected installed target.
+add_library(Ceres::ceres ALIAS ceres)
+
if (BUILD_TESTING AND GFLAGS)
add_library(gtest gmock_gtest_all.cc gmock_main.cc)
target_include_directories(gtest PUBLIC ${Ceres_SOURCE_DIR}/internal/ceres)
@@ -364,11 +367,11 @@
if (MINIGLOG)
# When using miniglog, it is compiled into Ceres, thus Ceres becomes
# the library against which other libraries should link for logging.
- target_link_libraries(gtest PUBLIC gflags ceres)
- target_link_libraries(test_util PUBLIC ceres gtest)
+ target_link_libraries(gtest PUBLIC gflags Ceres::ceres)
+ target_link_libraries(test_util PUBLIC Ceres::ceres gtest)
else (MINIGLOG)
target_link_libraries(gtest PUBLIC gflags ${GLOG_LIBRARIES})
- target_link_libraries(test_util PUBLIC ceres gtest ${GLOG_LIBRARIES})
+ target_link_libraries(test_util PUBLIC Ceres::ceres gtest ${GLOG_LIBRARIES})
endif (MINIGLOG)
macro (CERES_TEST NAME)
@@ -382,7 +385,7 @@
${Ceres_SOURCE_DIR}/internal/ceres
${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
- target_link_libraries(${NAME}_test PUBLIC test_util ceres gtest)
+ target_link_libraries(${NAME}_test PUBLIC test_util Ceres::ceres gtest)
if (BUILD_SHARED_LIBS)
# Define gtest-specific shared library flags for linking.
append_target_property(${NAME}_test COMPILE_DEFINITIONS
@@ -491,7 +494,7 @@
endif (BUILD_TESTING AND GFLAGS)
macro(add_dependencies_to_benchmark BENCHMARK_TARGET)
- target_link_libraries(${BENCHMARK_TARGET} PUBLIC ceres benchmark::benchmark)
+ target_link_libraries(${BENCHMARK_TARGET} PUBLIC Ceres::ceres benchmark::benchmark)
target_include_directories(${BENCHMARK_TARGET} PUBLIC
${Ceres_SOURCE_DIR}/internal
${Ceres_SOURCE_DIR}/internal/ceres