Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,30 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: cmake -S test/cmake_consumer -B builddir-cmake
- run: cmake --build builddir-cmake
- run: ./builddir-cmake/consumer
- name: add_subdirectory
run: |
cmake -S test/cmake_consumer -B builddir-cmake
cmake --build builddir-cmake
./builddir-cmake/consumer
- name: install
run: |
cmake -S . -B builddir-install -DCMAKE_INSTALL_PREFIX="$PWD/prefix"
cmake --build builddir-install --target install
# Asking for major version 1 rather than the exact one, so this does not need editing on
# every release. SameMajorVersion is the compatibility the config declares.
- name: find_package
run: |
cmake -S test/cmake_consumer/installed -B builddir-find \
-DCMAKE_PREFIX_PATH="$PWD/prefix" -DSVECTOR_REQUIRED_VERSION=1
cmake --build builddir-find
./builddir-find/consumer-installed
# The happy path passing says nothing about whether the version is actually checked.
- name: a version that is not installed has to be refused
run: |
if cmake -S test/cmake_consumer/installed -B builddir-badver \
-DCMAKE_PREFIX_PATH="$PWD/prefix" -DSVECTOR_REQUIRED_VERSION=99 >/dev/null 2>&1; then
echo "::error::find_package accepted version 99, so it is not checking versions"
exit 1
fi
- name: pkg-config
run: PKG_CONFIG_PATH="$PWD/prefix/share/pkgconfig" pkg-config --cflags --modversion svector
85 changes: 73 additions & 12 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,80 @@ project("svector"
DESCRIPTION " Compact SVO optimized vector for C++17 or higher"
HOMEPAGE_URL "https://github.com/martinus/svector")

# determine whether this is a standalone project or included by other projects
set(_svector_is_included ON)
include(GNUInstallDirs)

# PROJECT_IS_TOP_LEVEL only arrived in CMake 3.21 and the floor here is 3.12, so this is spelled
# by hand.
set(_svector_is_top_level OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(_svector_is_included OFF)
set(_svector_is_top_level ON)
endif()

if(_svector_is_included)
add_library(svector INTERFACE)
add_library(svector::svector ALIAS svector)
target_compile_features(svector INTERFACE cxx_std_17)
target_include_directories(
svector
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
# Defined unconditionally. It used to exist only when svector was pulled in with
# add_subdirectory, which meant configuring this repository on its own produced nothing at all --
# see issue #48, where exactly that looked like the project was broken. An install also needs a
# target to export.
add_library(svector INTERFACE)
add_library(svector::svector ALIAS svector)
target_compile_features(svector INTERFACE cxx_std_17)
target_include_directories(
svector
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)

# CMake still never builds or runs the tests, that is meson's job. What it does now is install,
# so that find_package(svector) works and packagers have something to call.
#
# Only when svector is the project being built: a parent that pulled it in with add_subdirectory
# should not find svector's headers turning up in its own install.
if(_svector_is_top_level)
include(CMakePackageConfigHelpers)

set(_svector_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/svector")

install(TARGETS svector EXPORT svectorTargets)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
install(EXPORT svectorTargets
FILE svectorTargets.cmake
NAMESPACE svector::
DESTINATION "${_svector_cmakedir}")

# ARCH_INDEPENDENT stops the version file rejecting a package whose word size differs from
# the consumer's, which for a header only library is not a real incompatibility. It needs
# CMake 3.14, above the floor, so it is added only where it exists.
set(_svector_version_args)
if(NOT CMAKE_VERSION VERSION_LESS 3.14)
list(APPEND _svector_version_args ARCH_INDEPENDENT)
endif()

# The version comes from project() above, which scripts/lint/lint-version.py keeps in step
# with the ANKERL_SVECTOR_VERSION_* macros, so a package can never claim a version the
# header does not. SameMajorVersion is the compatibility the header's own semver comment
# promises.
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/svectorConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
${_svector_version_args})

configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/svectorConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/svectorConfig.cmake"
INSTALL_DESTINATION "${_svector_cmakedir}")

install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/svectorConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/svectorConfigVersion.cmake"
DESTINATION "${_svector_cmakedir}")

# For the consumers that never touch CMake at all, which is most of what a distribution
# packages.
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/svector.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/svector.pc"
@ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/svector.pc"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig")
endif()
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,23 @@ auto v = ankerl::svector<int, 7>(); // 7 int inline, heap only if it outgrows th
v.push_back(42);
```

Copying that one header into your project is a perfectly good way to use it. If you would rather a build system
did it, take your pick:

```cmake
add_subdirectory(svector) # a submodule, or FetchContent
target_link_libraries(you PRIVATE svector::svector)

find_package(svector 1 REQUIRED) # after cmake --install, or from a package
target_link_libraries(you PRIVATE svector::svector)
```

```meson
svector_dep = dependency('svector') # with subprojects/svector.wrap
```

A `pkg-config` file is installed as well, for builds that use neither.

## How compact can it get?

What is the smallest each implementation can be made, how many `uint8_t` fit inline at that size, and what does
Expand Down Expand Up @@ -290,8 +307,8 @@ A few things are deliberately not the same as `std::vector`:

## Building & Testing

This project uses the [Meson](https://mesonbuild.com/) build system. The `CMakeLists.txt` is a convenience for
consumers and does not build or run the tests.
This project uses the [Meson](https://mesonbuild.com/) build system. The `CMakeLists.txt` is there for consumers
— it defines the target and installs the package — and never builds or runs the tests.

```sh
meson setup builddir
Expand Down
8 changes: 8 additions & 0 deletions cmake/svector.pc.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@

Name: svector
Description: @PROJECT_DESCRIPTION@
URL: @PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
Cflags: -I${includedir}
5 changes: 5 additions & 0 deletions cmake/svectorConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/svectorTargets.cmake")

check_required_components(svector)
13 changes: 12 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,16 @@ project('svector', 'cpp',
])

incdir = include_directories('include')
subdir('test')

# So a parent project can use svector as a meson subproject: with this, its dependency('svector')
# resolves to us through the wrap. There was no way to consume this from meson at all before.
svector_dep = declare_dependency(include_directories: incdir)
meson.override_dependency('svector', svector_dep)

# A parent pulling svector in wants the header, not our test suite and not our headers in its
# install tree.
if not meson.is_subproject()
install_headers('include/ankerl/svector.h', subdir: 'ankerl')
subdir('test')
endif

14 changes: 14 additions & 0 deletions test/cmake_consumer/installed/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.12)
project("svector-find-package-consumer" CXX)

# Consume svector the way someone does after `cmake --install`, or the way a distribution's
# package expects to be used. Point CMAKE_PREFIX_PATH at the install prefix.
#
# SVECTOR_REQUIRED_VERSION exists so CI can also check that a version that is not there is
# actually refused, rather than only checking the happy path.
set(SVECTOR_REQUIRED_VERSION "" CACHE STRING "version to demand from find_package")

find_package(svector ${SVECTOR_REQUIRED_VERSION} REQUIRED)

add_executable(consumer-installed ../main.cpp)
target_link_libraries(consumer-installed PRIVATE svector::svector)
3 changes: 2 additions & 1 deletion test/cmake_consumer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstdio>

// Shared by both consumer projects here, the add_subdirectory one and the find_package one.
// Deliberately shallow: this checks that the CMake target carries the include directory and
// the C++17 requirement, not that svector behaves. The meson suite owns behaviour.
auto main() -> int {
Expand All @@ -13,7 +14,7 @@ auto main() -> int {
return 1;
}

std::printf("consumed svector %d.%d.%d through add_subdirectory\n",
std::printf("consumed svector %d.%d.%d through CMake\n",
ANKERL_SVECTOR_VERSION_MAJOR,
ANKERL_SVECTOR_VERSION_MINOR,
ANKERL_SVECTOR_VERSION_PATCH);
Expand Down
Loading