diff --git a/.github/workflows/build-and-run.yaml b/.github/workflows/build-and-run.yaml index 1a6f3fd..b3dd4a5 100644 --- a/.github/workflows/build-and-run.yaml +++ b/.github/workflows/build-and-run.yaml @@ -62,7 +62,7 @@ jobs: - name: Build s2geography run: | cd build - cmake .. -Dabsl_DIR=`pwd`/../dist/lib/cmake/absl -DS2GEOGRAPHY_BUILD_EXAMPLES=ON -DS2GEOGRAPHY_BUILD_TESTS=ON -DS2GEOGRAPHY_CODE_COVERAGE=ON + cmake .. -Dabsl_DIR=`pwd`/../dist/lib/cmake/absl -DS2GEOGRAPHY_BUILD_EXAMPLES=ON -DS2GEOGRAPHY_BUILD_TESTS=ON -DS2GEOGRAPHY_CODE_COVERAGE=ON -DCMAKE_CXX_STANDARD=11 -DBUILD_SHARED_LIBS=OFF cmake --build . cmake --install . --prefix ../dist diff --git a/CMakeLists.txt b/CMakeLists.txt index 41a1c9c..028ef12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,29 +5,138 @@ message(STATUS "Building using CMake version: ${CMAKE_VERSION}") project(S2Geography) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard to build with") +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(ABSL_ENABLE_INSTALL ON) -option(S2GEOGRAPHY_BUILD_TESTS "Build tests" OFF) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/third_party/cmake") +option(S2GEOGRAPHY_BUILD_TESTS "Build tests" OFF) option(S2GEOGRAPHY_CODE_COVERAGE "Enable coverage reporting" OFF) -add_library(coverage_config INTERFACE) - option(S2GEOGRAPHY_BUILD_EXAMPLES "Build s2geography examples" OFF) -option(BUILD_SHARED_LIBS "Build using shared libraries" OFF) +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) + +# Dependencies +# ------------ + +# openssl on Apple / Homebrew (dependency via s2geometry) +# copied from Arrow +# (copyright The Apache Software Foundation, Apache License, Version 2.0) + +if(APPLE AND NOT OPENSSL_ROOT_DIR) + find_program(BREW_PROG brew) + if(BREW_PROG) + execute_process(COMMAND ${BREW_PROG} --prefix "openssl@1.1" + OUTPUT_VARIABLE OPENSSL11_BREW_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(OPENSSL11_BREW_PREFIX) + set(OPENSSL_ROOT_DIR ${OPENSSL11_BREW_PREFIX}) + else() + execute_process(COMMAND ${BREW_PROG} --prefix "openssl" + OUTPUT_VARIABLE OPENSSL_BREW_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(OPENSSL_BREW_PREFIX) + set(OPENSSL_ROOT_DIR ${OPENSSL_BREW_PREFIX}) + endif() + endif() + endif() +endif() + +# s2geometry + +if(DEFINED ENV{CONDA_PREFIX}) + set(S2GEOGRAPHY_S2_SOURCE_DEFAULT "CONDA") +else() + set(S2GEOGRAPHY_S2_SOURCE_DEFAULT "AUTO") +endif() + +set(S2GEOGRAPHY_S2_SOURCE + "${S2GEOGRAPHY_S2_SOURCE_DEFAULT}" + CACHE STRING "Method to use for acquiring the s2geometry dependency") + +message(STATUS "Using ${S2GEOGRAPHY_S2_SOURCE} approach to find s2geometry") + +macro(build_s2) + message(STATUS "Building s2geometry from source (version 0.10.0)") + + FetchContent_Declare( + s2 + GIT_REPOSITORY https://github.com/google/s2geometry.git + GIT_TAG tags/v0.10.0 + GIT_SHALLOW TRUE) + FetchContent_MakeAvailable(s2) + + set_property(TARGET s2 PROPERTY CXX_STANDARD ${CMAKE_CXX_STANDARD}) + + # this might be needed since s2geometry includes it in general + # but not for any target explicilty? + find_package(OpenSSL) + target_include_directories(s2 INTERFACE ${OPENSSL_INCLUDE_DIR}) +endmacro() + +if(${S2GEOGRAPHY_S2_SOURCE} STREQUAL "CONDA") + set(S2_ROOT_DIR "$ENV{CONDA_PREFIX}") + set(S2_SOURCE "SYSTEM") +elseif(${S2GEOGRAPHY_S2_SOURCE} STREQUAL "BREW") + # required for Homebrew installed s2geometry headers to find OpenSSL headers + find_package(OpenSSL) + include_directories(${OPENSSL_INCLUDE_DIR}) + set(S2_SOURCE "SYSTEM") +else() + set(S2_SOURCE ${S2GEOGRAPHY_S2_SOURCE}) +endif() + +if(${S2_SOURCE} STREQUAL "AUTO") + find_package(s2 QUIET) + if(${s2_FOUND}) + message(STATUS "Found s2: ${s2_INCLUDE_DIRS}") + else() + build_s2() + endif() +elseif(${S2_SOURCE} STREQUAL "BUNDLED") + build_s2() +elseif(${S2_SOURCE} STREQUAL "SYSTEM") + find_package(s2 REQUIRED) + if(NOT ${s2_FOUND}) + message(FATAL_ERROR "Couldn't find s2geometry") + endif() +endif() + +# Abseil (bundled build not supported) -FetchContent_Declare( - s2 - GIT_REPOSITORY https://github.com/google/s2geometry.git - GIT_TAG tags/v0.10.0 - GIT_SHALLOW TRUE) -FetchContent_MakeAvailable(s2) +find_package(absl REQUIRED) +if(${absl_FOUND}) + get_target_property(ABSL_INCLUDE_DIRS absl::memory INTERFACE_INCLUDE_DIRECTORIES) + message(STATUS "Found absl: ${ABSL_INCLUDE_DIRS}/absl") +else() + message(FATAL_ERROR "Couldn't find absl") +endif() + +# GTest (always bundled) + +if(S2GEOGRAPHY_BUILD_TESTS) + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest + GIT_TAG tags/release-1.12.0 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(googletest) + + # do not install googletest by default when running cmake --install + set_property(DIRECTORY ${googletest_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES) + + if(S2GEOGRAPHY_CODE_COVERAGE) + add_library(coverage_config INTERFACE) + endif() +endif() + +# Build s2geography +# ----------------- + +include_directories(src) -include_directories(src ${OPENSSL_INCLUDE_DIR}) -include_directories(src ${ABSL_INCLUDE_DIR}) add_library(s2geography src/s2geography/accessors-geog.cc src/s2geography/coverings.cc @@ -43,26 +152,9 @@ add_library(s2geography set_target_properties(s2geography PROPERTIES POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}) -target_link_libraries(s2geography s2) - -if(BUILD_EXAMPLES) - add_executable(example-simple examples/example-simple/example-simple.cc) - target_link_libraries(example-simple PUBLIC s2geography s2) -endif() - -install(TARGETS s2geography DESTINATION lib) -install(DIRECTORY src/ DESTINATION include FILES_MATCHING PATTERN "*.h") - -if(S2GEOGRAPHY_BUILD_EXAMPLES) - install(TARGETS example-simple DESTINATION examples) -endif() +target_link_libraries(s2geography s2 absl::memory absl::str_format) if(S2GEOGRAPHY_BUILD_TESTS) - FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/release-1.11.0.zip - ) - FetchContent_MakeAvailable(googletest) enable_testing() add_executable(distance_test src/s2geography/distance_test.cc) @@ -73,9 +165,24 @@ if(S2GEOGRAPHY_BUILD_TESTS) target_link_libraries(s2geography coverage_config) endif() - target_link_libraries(distance_test s2geography gtest_main) + target_link_libraries(distance_test s2geography GTest::gtest_main) include(GoogleTest) gtest_discover_tests(distance_test) +endif() + +if(S2GEOGRAPHY_BUILD_EXAMPLES) + add_executable(example-simple examples/example-simple/example-simple.cc) + target_link_libraries(example-simple PUBLIC s2geography s2) +endif() +# Install s2geography +# ------------------- + +install(TARGETS s2geography DESTINATION lib) +install(DIRECTORY src/ DESTINATION include FILES_MATCHING PATTERN "*.h") + +if(S2GEOGRAPHY_BUILD_EXAMPLES) + install(TARGETS example-simple DESTINATION examples) endif() + diff --git a/CMakeUserPresets.json.example b/CMakeUserPresets.json.example index fb0bdcf..f5f47de 100644 --- a/CMakeUserPresets.json.example +++ b/CMakeUserPresets.json.example @@ -15,6 +15,8 @@ "BUILD_SHARED_LIBS": "OFF", "S2GEOGRAPHY_BUILD_EXAMPLES": "ON", "S2GEOGRAPHY_BUILD_TESTS": "ON", + "S2GEOGRAPHY_FETCH_S2GEOMETRY": "ON", + "S2GEOGRAPHY_FETCH_GTEST": "ON", "absl_DIR": "${sourceDir}/build/abseil-dist/lib/cmake/absl", "CMAKE_BUILD_TYPE": "Debug", "CMAKE_CXX_FLAGS_DEBUG": "-g" diff --git a/README.md b/README.md index 9ad28c2..61de36c 100644 --- a/README.md +++ b/README.md @@ -49,46 +49,96 @@ Many operations in S2 require a `S2ShapeIndex` as input. This concept is similar The s2geography library sits on top of the s2geometry library, and you can and should use s2 directly! -## Installation +## Build and Installation (from source) -s2geography depends on s2geometry, which depends on [Abseil](https://github.com/abseil/abseil-cpp) and OpenSSL. You will need to install Abseil from source and install it to the same place you install s2geography (e.g., the homebrew/distributed versions are unlikely to work). Configure with `cmake -Dabsl_DIR=.../cmake/absl`, where `.../cmake/absl` contains the `abslConfig.cmake` file. You may also need to specify the location of OpenSSL using `-DOPENSSL_ROOT_DIR=/path/to/openssl@1.1`. The s2 library is fetched and built using CMake's FetchContent module, so you don't need to clone it separately. +There is no s2geography package available yet. If you want to use it, you need to build it from source. You can download the source by cloning this repository: -The project is structured such that the VSCode `cmake` integration is triggered when the folder is open (if the default build doesn't work, consider adding `CMakeUserPresets.json` to configure things like the install directory, absl_DIR, or the location of OpenSSL). +```bash +git clone https://github.com/paleolimbot/s2geography.git +``` + +### Requirements + +- [CMake](https://cmake.org/) +- s2geometry +- [Abseil](https://github.com/abseil/abseil-cpp) +- OpenSSL (via s2geometry) -For example, the GitHub Actions Ubuntu runner is configured like this: +### Conda + +All the required dependencies above are available on conda-forge. You can install them using conda (or mamba): ```bash -# clone this repo -git clone https://github.com/paleolimbot/s2geography.git +conda install cmake libabseil s2geometry openssl -c conda-forge +``` -# build abseil-cpp in the build/ directory, install to dist/ -mkdir s2geography/build && cd s2geography/build -git clone https://github.com/abseil/abseil-cpp.git -cmake abseil-cpp -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_CXX_STANDARD=11 -DABSL_ENABLE_INSTALL=ON -cmake --build abseil-cpp -cmake --install abseil-cpp --prefix ../dist +### Homebrew (MacOS) -# build s2geography (also fetches and builds s2) -cmake .. -Dabsl_DIR=`pwd`/../dist/lib/cmake/absl -DS2GEOGRAPHY_BUILD_TESTS=ON +Alternatively, you can install the required dependencies on MacOS with Homebrew: + +``` bash +brew install cmake abseil s2geometry openssl +``` + +### Build using CMake + +s2geography uses CMake to build the library. You first need to configure the build, e.g, using the following commands (from where the source has been downloaded or cloned): + +```bash +mkdir build +cd build +cmake .. -DS2GEOGRAPHY_S2_SOURCE=AUTO -DCMAKE_CXX_STANDARD=17 cmake --build . -cmake --install . --prefix ../dist ``` -Locally (M1 mac), I have to add `-DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl@1.1` to `cmake ..` when building s2geography. +The CMake option `S2GEOGRAPHY_S2_SOURCE` specifies the method to use for acquiring s2geometry: + +- `AUTO`: try to find s2geometry on the system default locations or download and build it from source if not found (default) +- `BUNDLED`: download and build s2geometry automatically from source +- `SYSTEM`: use s2geometry installed on one of the system default locations +- `CONDA`: use s2geometry installed in a conda environment (automatically selected when the environment is active) +- `BREW`: use s2geometry (and OpenSSL) installed with Homebrew + +Note: s2geography does not support automatically acquiring and building Abseil and OpenSSL from source. If you don't have installed those libraries with conda or Homebrew, you might need to manually specify their location using the CMake options`absl_DIR` and `OPENSSL_ROOT_DIR`. + +The CMake option `CMAKE_CXX_STANDARD` should be set according to the standard used to build Abseil and s2geometry (C++17 is set by default). + +The project is structured such that the VSCode CMake integration is triggered when the folder is open (if the default build doesn't work, consider adding `CMakeUserPresets.json` to configure things like the install directory, absl_DIR, or the location of OpenSSL). + +### Install + +After building the library, you can install it using: + +```bash +cmake --install . --prefix ../dist +``` ## Development -The easiest way to get started with s2geography development is using VSCode with the C/C++ and CMake extensions. See the CMakeUserPresets.json.example file for a possible test/configuration preset that will build and run the tests and the examples. You can also invoke `ctest` directly to run tests: +s2geography provides units tests that can be built and run using [GTest](https://github.com/google/googletest). To enable it, use the CMake option `S2GEOGRAPHY_BUILD_TESTS=ON` (GTest will be downloaded and built automatically): ```bash -cd build cmake .. -DS2GEOGRAPHY_BUILD_TESTS=ON cmake --build . +``` + +You can then run the tests using `ctest`: + +```bash ctest -T test --output-on-failure . ``` -You can run specific tests using `ctest`'s `-R` flag: +You can also run specific tests using `ctest`'s `-R` flag: ```bash ctest -T test . -R "Distance$" ``` + +s2geography also provides some examples that can be build using: + +```bash +cmake .. -DS2GEOGRAPHY_BUILD_EXAMPLES=ON +cmake --build . +``` + +For VSCode users (with the C/C++ and CMake extensions), the CMakeUserPresets.json.example file shows a possible test/configuration preset that will build and run the tests and the examples. diff --git a/third_party/cmake/Finds2.cmake b/third_party/cmake/Finds2.cmake new file mode 100644 index 0000000..ce68875 --- /dev/null +++ b/third_party/cmake/Finds2.cmake @@ -0,0 +1,78 @@ +# The MIT License (MIT) +# +# Copyright (c) 2020 Benoit Bovy +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# +# FindS2 +# ------ +# +# Find S2 (S2Geometry) include directories and libraries. +# +# This module will set the following variables: +# +# S2_FOUND - System has S2 +# S2_INCLUDE_DIRS - The S2 include directories +# S2_LIBRARIES - The libraries needed to use S2 +# +# This module will also create the "tbb" target that may be used when building +# executables and libraries. + +include(FindPackageHandleStandardArgs) + +find_path(s2_INCLUDE_DIR s2cell.h + HINTS + ENV S2_ROOT + ENV S2_DIR + ${S2_ROOT_DIR} + PATH_SUFFIXES + include/s2 + ) + +find_library(s2_LIBRARY + NAMES s2 + HINTS + ENV S2_ROOT + ENV S2_DIR + ${S2_ROOT_DIR} + PATH_SUFFIXES + lib + libs + Library + ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(s2 + REQUIRED_VARS s2_INCLUDE_DIR s2_LIBRARY + ) + +if(S2_FOUND) + set(s2_INCLUDE_DIRS ${s2_INCLUDE_DIR}) + set(s2_LIBRARIES ${s2_LIBRARY}) + + add_library(s2 SHARED IMPORTED) + set_target_properties(s2 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${s2_INCLUDE_DIRS} + IMPORTED_LOCATION ${s2_LIBRARIES} + IMPORTED_IMPLIB ${s2_LIBRARIES} + ) + + mark_as_advanced(s2_INCLUDE_DIRS s2_LIBRARIES) +endif()