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