Skip to content
Open
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
16 changes: 16 additions & 0 deletions .github/workflows/build-and-test-ipc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,29 @@ on:
- main
paths:
- 'CMakeLists.txt'
- 'cmake/**'
- 'ci/scripts/test_cmake_package.py'
- '.github/workflows/build-and-test-ipc.yaml'
- 'src/nanoarrow/**'

permissions:
contents: read

jobs:
test-cmake-package:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.x"
- name: Test CMake package exports
run: python ci/scripts/test_cmake_package.py --build-dir build/package-tests

test-c-ipc:

runs-on: ubuntu-latest
Expand Down
19 changes: 11 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -216,19 +216,20 @@ if(NANOARROW_IPC)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
add_library(nanoarrow::flatccrt ALIAS flatccrt)

elseif(NOT NANOARROW_FLATCC_ROOT_DIR)
add_library(flatccrt STATIC IMPORTED)
set_target_properties(flatccrt
add_library(nanoarrow::flatccrt STATIC IMPORTED)
set_target_properties(nanoarrow::flatccrt
PROPERTIES IMPORTED_LOCATION
"${NANOARROW_FLATCC_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}flatccrt${CMAKE_STATIC_LIBRARY_SUFFIX}"
INTERFACE_INCLUDE_DIRECTORIES
"${NANOARROW_FLATCC_INCLUDE_DIR}")

elseif(NOT NANOARROW_FLATCC_INCLUDE_DIR)
set(NANOARROW_FLATCC_INCLUDE_DIR "${NANOARROW_FLATCC_ROOT_DIR}/include")
add_library(flatccrt STATIC IMPORTED)
set_target_properties(flatccrt
add_library(nanoarrow::flatccrt STATIC IMPORTED)
set_target_properties(nanoarrow::flatccrt
PROPERTIES IMPORTED_LOCATION
"${NANOARROW_FLATCC_ROOT_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}flatccrt${CMAKE_STATIC_LIBRARY_SUFFIX}"
IMPORTED_LOCATION_DEBUG
Expand All @@ -239,6 +240,8 @@ if(NANOARROW_IPC)
"${NANOARROW_FLATCC_INCLUDE_DIR}")
endif()

get_target_property(NANOARROW_FLATCC_EXTERNAL nanoarrow::flatccrt IMPORTED)

if(NANOARROW_IPC_WITH_ZSTD)
find_package(zstd REQUIRED)
set(NANOARROW_IPC_EXTRA_FLAGS "-DNANOARROW_IPC_WITH_ZSTD")
Expand Down Expand Up @@ -303,12 +306,12 @@ if(NANOARROW_IPC)

add_library(nanoarrow_ipc_static STATIC ${NANOARROW_IPC_BUILD_SOURCES})
target_link_libraries(nanoarrow_ipc_static
PRIVATE flatccrt ${NANOARROW_IPC_EXTRA_LIBS}
PRIVATE nanoarrow::flatccrt ${NANOARROW_IPC_EXTRA_LIBS}
PUBLIC nanoarrow_static nanoarrow_coverage_config)

add_library(nanoarrow_ipc_shared SHARED ${NANOARROW_IPC_BUILD_SOURCES})
target_link_libraries(nanoarrow_ipc_shared
PRIVATE flatccrt ${NANOARROW_IPC_EXTRA_LIBS_SHARED}
PRIVATE nanoarrow::flatccrt ${NANOARROW_IPC_EXTRA_LIBS_SHARED}
PUBLIC nanoarrow_shared nanoarrow_coverage_config)

install(FILES src/nanoarrow/nanoarrow_ipc.h src/nanoarrow/nanoarrow_ipc.hpp
Expand Down Expand Up @@ -343,7 +346,7 @@ if(NANOARROW_IPC AND (NANOARROW_BUILD_INTEGRATION_TESTS OR NANOARROW_BUILD_TESTS
target_link_libraries(nanoarrow_ipc_integration
PRIVATE nanoarrow_testing_static
nanoarrow_ipc_static
flatccrt
nanoarrow::flatccrt
nanoarrow_coverage_config
${NANOARROW_IPC_EXTRA_LIBS})
endif()
Expand Down Expand Up @@ -760,7 +763,7 @@ if(NANOARROW_BUILD_TESTS)
nanoarrow_coverage_config)

if(NOT (name MATCHES "_hpp_"))
target_link_libraries(nanoarrow_ipc_${name}_test flatccrt)
target_link_libraries(nanoarrow_ipc_${name}_test nanoarrow::flatccrt)
endif()

if(Arrow_FOUND)
Expand Down
188 changes: 188 additions & 0 deletions ci/scripts/test_cmake_package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

"""Exercise build-tree and installed CMake packages without test dependencies."""

import argparse
import pathlib
import shutil
import subprocess


def run(*args):
subprocess.run([str(arg) for arg in args], check=True)


def configure(source, build, config, *options):
run(
"cmake",
"-S",
source,
"-B",
build,
f"-DCMAKE_BUILD_TYPE={config}",
*options,
)


def build_and_install(build, config):
run("cmake", "--build", build, "--config", config, "--parallel", "2")
run("cmake", "--install", build, "--config", config)


def consume(source, build, prefix, config, caller_first):
configure(
source,
build,
config,
f"-DCMAKE_PREFIX_PATH={prefix.as_posix()}",
f"-DCALLER_FLATCC_FIRST={caller_first}",
)
run("cmake", "--build", build, "--config", config, "--parallel", "2")
run("ctest", "--test-dir", build, "-C", config, "--output-on-failure")


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--build-dir", required=True, type=pathlib.Path)
args = parser.parse_args()
root = args.build_dir.resolve()
root.mkdir(parents=True, exist_ok=True)
source = pathlib.Path(__file__).resolve().parents[2]

# Build a real external runtime with the same layout as a package manager.
fixture = root / "flatcc"
fixture.mkdir()
(fixture / "CMakeLists.txt").write_text(
"""cmake_minimum_required(VERSION 3.14)
project(flatcc_fixture LANGUAGES C)
if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
set(CMAKE_DEBUG_POSTFIX _d)
endif()
add_library(flatccrt STATIC
"${FLATCC_SOURCE}/src/runtime/builder.c"
"${FLATCC_SOURCE}/src/runtime/emitter.c"
"${FLATCC_SOURCE}/src/runtime/verifier.c"
"${FLATCC_SOURCE}/src/runtime/refmap.c")
target_include_directories(flatccrt PRIVATE "${FLATCC_SOURCE}/include")
set_target_properties(flatccrt PROPERTIES POSITION_INDEPENDENT_CODE ON)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(destination debug/lib)
else()
set(destination lib)
endif()
install(TARGETS flatccrt ARCHIVE DESTINATION "${destination}")
install(DIRECTORY "${FLATCC_SOURCE}/include/" DESTINATION include)
""",
encoding="utf-8",
)

consumer = root / "consumer"
consumer.mkdir()
(consumer / "CMakeLists.txt").write_text(
"""cmake_minimum_required(VERSION 3.14)
project(nanoarrow_package_consumer LANGUAGES C)
if(CALLER_FLATCC_FIRST)
add_library(flatccrt STATIC IMPORTED)
endif()
find_package(nanoarrow CONFIG REQUIRED)
if(NOT CALLER_FLATCC_FIRST)
add_library(flatccrt STATIC IMPORTED)
endif()
add_executable(consumer main.c)
target_link_libraries(consumer PRIVATE nanoarrow::nanoarrow_ipc_static)
enable_testing()
add_test(NAME nanoarrow-ipc-runtime COMMAND consumer)
""",
encoding="utf-8",
)
(consumer / "main.c").write_text(
"""#include <nanoarrow/nanoarrow_ipc.h>
int main(void) {
struct ArrowIpcDecoder decoder;
int result = ArrowIpcDecoderInit(&decoder);
if (result != 0) return result;
ArrowIpcDecoderReset(&decoder);
return 0;
}
""",
encoding="utf-8",
)

for mode in ("external-root", "external-dirs", "vendored"):
prefix = root / f"{mode}-prefix"
configs = ("Release", "Debug")
if mode != "vendored":
for config in configs:
build = root / f"{mode}-flatcc-{config}"
configure(
fixture,
build,
config,
f"-DFLATCC_SOURCE={(source / 'thirdparty' / 'flatcc').as_posix()}",
f"-DCMAKE_INSTALL_PREFIX={prefix.as_posix()}",
*(["-DCMAKE_DEBUG_POSTFIX="] if mode == "external-dirs" else []),
)
build_and_install(build, config)

for config in configs:
build = root / f"{mode}-nanoarrow-{config}"
options = [
"-DNANOARROW_IPC=ON",
"-DCMAKE_INSTALL_LIBDIR=lib",
"-DCMAKE_DEBUG_POSTFIX=_d",
f"-DCMAKE_INSTALL_PREFIX={prefix.as_posix()}",
]
if mode == "external-root":
options.append(f"-DNANOARROW_FLATCC_ROOT_DIR={prefix.as_posix()}")
elif mode == "external-dirs":
include_dir = prefix / "include"
lib_dir = prefix / ("debug/lib" if config == "Debug" else "lib")
options.extend(
[
f"-DNANOARROW_FLATCC_INCLUDE_DIR={include_dir.as_posix()}",
f"-DNANOARROW_FLATCC_LIB_DIR={lib_dir.as_posix()}",
]
)
configure(source, build, config, *options)
build_and_install(build, config)
for caller_first in ("ON", "OFF"):
consume(
consumer,
root / f"{mode}-build-consumer-{config}-{caller_first}",
build,
config,
caller_first,
)

relocated = root / f"{mode}-relocated"
shutil.move(prefix, relocated)
for config in configs:
for caller_first in ("ON", "OFF"):
consume(
consumer,
root / f"{mode}-installed-consumer-{config}-{caller_first}",
relocated,
config,
caller_first,
)

print("All CMake package consumers passed.")


if __name__ == "__main__":
main()
37 changes: 36 additions & 1 deletion cmake/config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,46 @@
# specific language governing permissions and limitations
# under the License.


@PACKAGE_INIT@

cmake_minimum_required(VERSION @CMAKE_MINIMUM_REQUIRED_VERSION@)

if("@NANOARROW_FLATCC_EXTERNAL@" AND NOT TARGET nanoarrow::flatccrt)
find_library(nanoarrow_FLATCCRT_LIBRARY
NAMES flatccrt
HINTS "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@"
"@NANOARROW_FLATCC_LIB_DIR@" "@NANOARROW_FLATCC_ROOT_DIR@/lib")
find_library(nanoarrow_FLATCCRT_LIBRARY_DEBUG
NAMES flatccrt_d flatccrt
HINTS "${PACKAGE_PREFIX_DIR}/debug/@CMAKE_INSTALL_LIBDIR@"
"@NANOARROW_FLATCC_ROOT_DIR@/debug/lib" "@NANOARROW_FLATCC_LIB_DIR@"
${CMAKE_PREFIX_PATH}
PATH_SUFFIXES debug/@CMAKE_INSTALL_LIBDIR@
NO_DEFAULT_PATH)
if(NOT nanoarrow_FLATCCRT_LIBRARY AND NOT nanoarrow_FLATCCRT_LIBRARY_DEBUG)
set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)
set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE
"nanoarrow IPC requires the external flatcc runtime library")
return()
endif()

add_library(nanoarrow::flatccrt UNKNOWN IMPORTED)
if(nanoarrow_FLATCCRT_LIBRARY)
set_property(TARGET nanoarrow::flatccrt
APPEND
PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_property(TARGET nanoarrow::flatccrt PROPERTY IMPORTED_LOCATION_RELEASE
"${nanoarrow_FLATCCRT_LIBRARY}")
endif()
if(nanoarrow_FLATCCRT_LIBRARY_DEBUG)
set_property(TARGET nanoarrow::flatccrt
APPEND
PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_property(TARGET nanoarrow::flatccrt
PROPERTY IMPORTED_LOCATION_DEBUG "${nanoarrow_FLATCCRT_LIBRARY_DEBUG}")
endif()
endif()

include("${CMAKE_CURRENT_LIST_DIR}/nanoarrow-targets.cmake" REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/nanoarrow-config-version.cmake" REQUIRED)

Expand Down
18 changes: 18 additions & 0 deletions examples/cmake-ipc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,21 @@ cat ../schema-valid.arrows | ./example_cmake_ipc_app
cat ../invalid.arrows | ./example_cmake_ipc_app
# Expected 0xFFFFFFFF at start of message but found 0xFFFFFF00
```

## Consuming an installed package

An installed nanoarrow package built with `NANOARROW_IPC=ON` can also be used
without `FetchContent`:

```cmake
find_package(nanoarrow CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE nanoarrow::nanoarrow_ipc_static)
```

When nanoarrow is built against an external flatcc runtime, package discovery
resolves that runtime as `nanoarrow::flatccrt`, including separate Debug and
Release libraries where available. Consumers do not need to create a
`flatccrt` target. If flatcc is installed in a separate prefix, include that
prefix in `CMAKE_PREFIX_PATH`. The `nanoarrow_FLATCCRT_LIBRARY` and
`nanoarrow_FLATCCRT_LIBRARY_DEBUG` cache variables can also select explicit
runtime library paths.
Loading