cmakegeographic-lib

Finding GeographicLib in CMake on Debian


On Debian, I've installed cmake and geographiclib like so:

stew@stewbian:~$apt-get install build-essential cmake libgeographic-dev

My CMakeLists.txt file looks like so:

cmake_minimum_required(VERSION 3.7)
project(geoexample)

find_package(GeographicLib REQUIRED)

add_executable(geoexample main.cpp)

target_include_directories(geoexample PRIVATE ${GeographicLib_INCLUDE_DIRS})
target_compile_definitions(geoexample PRIVATE ${GeographicLib_DEFINITIONS})
target_link_libraries     (geoexample         ${GeographicLib_LIBRARIES})

My main.cpp is also very simple (taken directly from examples):

#include <iostream>
#include <GeographicLib/Geodesic.hpp>
using namespace std;
using namespace GeographicLib;
int main() {
    const Geodesic& geod = Geodesic::WGS84();
    // Distance from JFK to LHR
    double
      lat1 = 40.6, lon1 = -73.8, // JFK Airport
      lat2 = 51.6, lon2 = -0.5;  // LHR Airport
    double s12;
    geod.Inverse(lat1, lon1, lat2, lon2, s12);
    cout << s12 / 1000 << " km\n";
    return 0;
}

When I run mkdir build && cd build && cmake .. I get

stew@stewbian:~/src/geoexample/build$ cmake ..
CMake Error at CMakeLists.txt:3 (find_package):
  By not providing "FindGeographicLib.cmake" in CMAKE_MODULE_PATH this
  project has asked CMake to find a package configuration file provided by
  "GeographicLib", but CMake did not find one.

I think that by default, cmake searches /usr/share/cmake-3.7/Modules, but libgeographic-dev seems to have installed its Find*.cmake to /usr/share/cmake/geographiclib/FindGeographicLib.cmake. That's frustrating, but myself (plus everyone who will ever need to compile my code) should be able to use a work-around for this simple case (it wouldn't work so well if I need to also include something like FindBoost.cmake from the old location).

stew@stewbian:~/src/geoexample/build$ cmake .. -DCMAKE_MODULE_PATH=/usr/share/cmake/geographiclib
CMake Error at /usr/share/cmake-3.7/Modules/FindPackageHandleStandardArgs.cmake:138 (message):
  Could NOT find GeographicLib (missing: GeographicLib_LIBRARY_DIRS
  GeographicLib_INCLUDE_DIRS)
Call Stack (most recent call first):
  /usr/share/cmake-3.7/Modules/FindPackageHandleStandardArgs.cmake:378 (_FPHSA_FAILURE_MESSAGE)
  /usr/share/cmake/geographiclib/FindGeographicLib.cmake:28 (find_package_handle_standard_args)
  CMakeLists.txt:4 (find_package)


-- Configuring incomplete, errors occurred!

Now I'm not sure what to do here. I can confirm that libgeographic-dev package installed /usr/lib/x86_64-linux-gnu/libGeographic.a and /usr/lib/x86_64-linux-gnu/libGeographic.so


Solution

  • I wrote my own FindGeographicLib.cmake to find this and installed it in a subfolder of my project. Then I pointed ${CMAKE_MODULES_PATH} to this folder in my project's CMakeLists.txt:

    list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/modules)
    

    I started by adding the one deployed by libgeographic-dev:

    cp /usr/share/cmake/geographiclib/FindGeographicLib.cmake ./modules/FindGeographicLib.cmake
    

    Unfortunately, that didn't work out of the box. The library was found at /usr/lib/x86_64-linux-gnu/libGeographic.so and the extra x86_64-linux-gnu wasn't handled well by the script. It tried (and failed) to find the headers in /usr/lib/include. I made some tweaks to the scripts to also check for this case and now I have a working solution.

    The new FindGeographicLib.cmake is shown below. My changes are indicated with comments to the right of the applicable lines.

    # Look for GeographicLib
    #
    # Sets
    #  GeographicLib_FOUND = TRUE
    #  GeographicLib_INCLUDE_DIRS = /usr/local/include
    #  GeographicLib_LIBRARIES = /usr/local/lib/libGeographic.so
    #  GeographicLib_LIBRARY_DIRS = /usr/local/lib
    
    find_library (GeographicLib_LIBRARIES Geographic
      PATHS "${CMAKE_INSTALL_PREFIX}/../GeographicLib/lib")
    
      if (GeographicLib_LIBRARIES)
      get_filename_component (GeographicLib_LIBRARY_DIRS
        "${GeographicLib_LIBRARIES}" PATH)
    
      get_filename_component (_ROOT_DIR "${GeographicLib_LIBRARY_DIRS}" PATH)
      set (GeographicLib_INCLUDE_DIRS "${_ROOT_DIR}/include")
      set (GeographicLib_BINARY_DIRS "${_ROOT_DIR}/bin")
      if (NOT EXISTS "${GeographicLib_INCLUDE_DIRS}/GeographicLib/Config.h")
        get_filename_component(_ROOT_DIR "${_ROOT_DIR}" PATH)                     # Added to script
        set (GeographicLib_INCLUDE_DIRS "${_ROOT_DIR}/include")                   # Added to script
        set (GeographicLib_BINARY_DIRS "${_ROOT_DIR}/bin")                        # Added to script
        if (NOT EXISTS "${GeographicLib_INCLUDE_DIRS}/GeographicLib/Config.h")    # Added to script
          unset (GeographicLib_INCLUDE_DIRS)
          unset (GeographicLib_LIBRARIES)
          unset (GeographicLib_LIBRARY_DIRS)
          unset (GeographicLib_BINARY_DIRS)
        endif()                                                                   # Added to script
      endif ()
      unset (_ROOT_DIR)                                                           # Moved below if() statements
    endif ()
    
    include (FindPackageHandleStandardArgs)
    find_package_handle_standard_args (GeographicLib DEFAULT_MSG
      GeographicLib_LIBRARY_DIRS GeographicLib_LIBRARIES GeographicLib_INCLUDE_DIRS)
    mark_as_advanced (GeographicLib_LIBRARY_DIRS GeographicLib_LIBRARIES
      GeographicLib_INCLUDE_DIRS)
    

    Edit (2024):

    Debian Bookworm has been out for a while, and that release of debian renamed GeographicLib from libgeographic to libGeographicLib. But we can still have a script that works for both versions by using the NAMES part of find_library()

    # Look for GeographicLib
    #
    # Sets
    #  GeographicLib_FOUND = TRUE
    #  GeographicLib_INCLUDE_DIRS = /usr/local/include
    #  GeographicLib_LIBRARIES = /usr/local/lib/libGeographic.so
    #  GeographicLib_LIBRARY_DIRS = /usr/local/lib
    
    find_library (GeographicLib_LIBRARIES
      NAMES Geographic GeographicLib
      PATHS "${CMAKE_INSTALL_PREFIX}/../GeographicLib/lib")
    
      if (GeographicLib_LIBRARIES)
      get_filename_component (GeographicLib_LIBRARY_DIRS
        "${GeographicLib_LIBRARIES}" PATH)
    
      get_filename_component (_ROOT_DIR "${GeographicLib_LIBRARY_DIRS}" PATH)
      set (GeographicLib_INCLUDE_DIRS "${_ROOT_DIR}/include")
      set (GeographicLib_BINARY_DIRS "${_ROOT_DIR}/bin")
      if (NOT EXISTS "${GeographicLib_INCLUDE_DIRS}/GeographicLib/Config.h")
        get_filename_component(_ROOT_DIR "${_ROOT_DIR}" PATH)
        set (GeographicLib_INCLUDE_DIRS "${_ROOT_DIR}/include")
        set (GeographicLib_BINARY_DIRS "${_ROOT_DIR}/bin")
        if (NOT EXISTS "${GeographicLib_INCLUDE_DIRS}/GeographicLib/Config.h")
          unset (GeographicLib_INCLUDE_DIRS)
          unset (GeographicLib_LIBRARIES)
          unset (GeographicLib_LIBRARY_DIRS)
          unset (GeographicLib_BINARY_DIRS)
        endif()
      endif ()
      unset (_ROOT_DIR)
    endif ()
    
    include (FindPackageHandleStandardArgs)
    find_package_handle_standard_args (GeographicLib DEFAULT_MSG
      GeographicLib_LIBRARY_DIRS GeographicLib_LIBRARIES GeographicLib_INCLUDE_DIRS)
    mark_as_advanced (GeographicLib_LIBRARY_DIRS GeographicLib_LIBRARIES
      GeographicLib_INCLUDE_DIRS)