Skip to content

Commit

Permalink
Support cmake install (#4326)
Browse files Browse the repository at this point in the history
### What

* Depends on #4313
* Fixes #4207

Support and document use of CMake install.
Minimal example has a switch to use `find_package`. Not rolling it out
to others because it's just not as ergonomic, don't want to advertise it
all that much. However, the minimal example is used in the sdk package
script to test that install is in order before uploading the package
script (runs locally). I manually tested the case of a rerun install
depend on an arrow system install.

### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested [demo.rerun.io](https://demo.rerun.io/pr/4326) (if
applicable)
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG

- [PR Build Summary](https://build.rerun.io/pr/4326)
- [Docs
preview](https://rerun.io/preview/78027bcbca31e62a27bdea34b563070eda817187/docs)
<!--DOCS-PREVIEW-->
- [Examples
preview](https://rerun.io/preview/78027bcbca31e62a27bdea34b563070eda817187/examples)
<!--EXAMPLES-PREVIEW-->
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)
  • Loading branch information
Wumpf authored Nov 24, 2023
1 parent d5153cb commit f18c4cb
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 14 deletions.
49 changes: 44 additions & 5 deletions docs/content/reference/cpp-sdk-cmake.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ The Rerun C++ SDK is meant to be built from source and everything described on t
Its [CMake build script](https://github.com/rerun-io/rerun/blob/latest/rerun_cpp/CMakeLists.txt)
is ready to be used from outside of the Rerun repo.

## Adding with FetchContent
# Ways of building & using rerun_sdk

The easiest way to add Rerun to your project is using `FetchContent`:
## Download & build via `FetchContent`

By far the easiest way to add Rerun to your project is using `FetchContent`:
```cmake
include(FetchContent)
FetchContent_Declare(rerun_sdk URL
Expand All @@ -19,9 +21,12 @@ FetchContent_MakeAvailable(rerun_sdk)

This will download a bundle with pre-built Rerun C static libraries for most desktop platforms,
all Rerun C++ sources and headers, as well as CMake build instructions for them.
By default this will also download & build [Apache Arrow](https://arrow.apache.org/)'s C++ library which is required to build the Rerun C++. See [Install arrow-cpp](../howto/arrow-cpp-install.md) to learn more about this step and how to use an existing install.
By default this will also download & build [Apache Arrow](https://arrow.apache.org/)'s C++ library which is required to build the Rerun C++. See [Install arrow-cpp](../howto/arrow-cpp-install.md) to learn more about this step and how to use an existing install.

We recommend this `FetchContent` workflow for all usecases since it is the easiest and works without any additional configuration.
All other workflows and configuration are there to best address more specific needs a project setup may haves.

## Adding via subdirectory
## From rerun repository via `add_subdirectory`

Alternatively, you can add the source of `https://github.com/rerun-io/rerun/blob/latest/rerun_cpp/` directly to your own
project and then use `add_subdirectory`.
Expand All @@ -43,12 +48,44 @@ before adding the subdirectory.
but also make additional assumptions about your build environment. For example it will always try to build
`rerun_c` (which the C++ SDK depends on) from its Rust source.

## CMake configuration options
## CMake install for `rerun_sdk`

If you want to pre-build `rerun_sdk` for use with a different build system, or simply have a lot of projects using the same
`rerun_sdk`, it can be useful to use CMake's install command to install a re-usable version of `rerun_sdk` on your system.

To do so, follow these following steps:
* Download and unpack the desired `rerun_cpp_sdk.zip` (e.g https://github.com/rerun-io/rerun/releases/latest/download/rerun_cpp_sdk.zip for the latest version)
* In the directory of the unpacked `rerun_cpp_sdk` run:
* Configure:
* `cmake -B build -S . -DCMAKE_BUILD_TYPE=Release`
* Build:
* `cmake --build build --config Release --target rerun_sdk`
* Install:
* `cmake --install build`
* make sure you have permissions or use a target path, e.g. `--prefix ../rerun_sdk_install`
* Now that you have an install you can use `find_package(rerun_sdk REQUIRED)` in your project
* Make sure that the prefix path or the rerun_sdk location is correctly configured.
* Depending on your install path and OS this may work out of the box or require setting additional CMake variables (e.g. `-DCMAKE_PREFIX_PATH=rerun_sdk_install`)

The exact CMake invocations may need to be adjusted for your needs.

Naturally, you can also integrate `rerun_sdk`'s install into the install of your own libraries and executables.
This is generally only recommended for more advanced CMake setups.

As mentioned previously, by default Rerun's CMake script will download and build Arrow during its build.
Unless configured otherwise (see below) the resulting libraries are part of the `rerun_sdk` install.
⚠️ This does currently not work for dynamic arrow libraries, i.e. if either one of
`RERUN_DOWNLOAD_AND_BUILD_ARROW=OFF` or `RERUN_ARROW_LINK_SHARED=ON` is set,
the install will use `find_package(Arrow)` to locate the Arrow library on your system.

# CMake configuration options

The C++ SDK provides a handful of configuration options.
All of them come with meaningful defaults, so typically you don't have to change any of them,
but they provide important hooks for more complex build setups.

Unless noted otherwise, a CMake install of `rerun_sdk` does **not** expose any of these options.

### `RERUN_DOWNLOAD_AND_BUILD_ARROW`
If enabled, will download a pinned version of the Apache Arrow C++ library and add it to the build.
Otherwise, `find_package` will be used to search for a pre-installed Arrow library.
Expand All @@ -65,6 +102,8 @@ Although enabling shared libraries makes linking faster and reduces binary size,
related to locating the shared libraries at runtime. Depending on your system configuration it is even possible
to pick up a system-version of Arrow instead of the one you built against.

`rerun_sdk` installs that use a system installed Arrow library, can be configured using this option as well.

### `RERUN_C_LIB`
Path to the static Rerun C library to link against.

Expand Down
2 changes: 2 additions & 0 deletions docs/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"dataframe",
"datastructures",
"datatypes",
"DCMAKE",
"deallocate",
"deallocation",
"debuginfo",
Expand Down Expand Up @@ -336,6 +337,7 @@
"ureq",
"urholaukkarinen",
"urlparse",
"usecases",
"usize",
"Vecerik",
"venv",
Expand Down
13 changes: 9 additions & 4 deletions examples/cpp/minimal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ else()

# Set the path to the rerun_c build.
set(RERUN_CPP_URL "https://github.com/rerun-io/rerun/releases/latest/download/rerun_cpp_sdk.zip" CACHE STRING "URL to the rerun_cpp zip.")
option(RERUN_FIND_PACKAGE "Whether to use find_package to find a preinstalled rerun package (instead of using FetchContent)." OFF)

# Download the rerun_sdk
include(FetchContent)
FetchContent_Declare(rerun_sdk URL ${RERUN_CPP_URL})
FetchContent_MakeAvailable(rerun_sdk)
if(RERUN_FIND_PACKAGE)
find_package(rerun_sdk REQUIRED)
else()
# Download the rerun_sdk
include(FetchContent)
FetchContent_Declare(rerun_sdk URL ${RERUN_CPP_URL})
FetchContent_MakeAvailable(rerun_sdk)
endif()

# Rerun requires at least C++17, but it should be compatible with newer versions.
set_property(TARGET example_minimal PROPERTY CXX_STANDARD 17)
Expand Down
77 changes: 74 additions & 3 deletions rerun_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ file(GLOB_RECURSE rerun_sdk_SRC CONFIGURE_DEPENDS
"${RERUN_CPP_SOURCE_DIR}/*.cpp"
)

add_library(rerun_sdk ${rerun_sdk_SRC})
add_library(rerun_sdk ${rerun_sdk_SRC} ${rerun_sdk_PUBLIC_HEADER})

# Make sure the compiler can find include files for rerun when other libraries or executables link to rerun:
target_include_directories(rerun_sdk PUBLIC ${RERUN_CPP_SOURCE_DIR})
target_include_directories(rerun_sdk PUBLIC
$<BUILD_INTERFACE:${RERUN_CPP_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)

# Rerun needs at least C++17.
set_target_properties(rerun_sdk PROPERTIES CXX_STANDARD 17)
Expand Down Expand Up @@ -87,7 +90,7 @@ target_link_libraries(rerun_sdk PRIVATE rerun_c)
# This makes the setup a lot easier on Windows where we otherwise need to put Arrow.dll either in path or copy it with the executable.
# Additionally reduces risk of picking up system libraries on Mac / Linux.
set(RERUN_ARROW_LINK_SHARED_DEFAULT OFF)
option(RERUN_ARROW_LINK_SHARED "Link to the Arrow shared library" ${RERUN_ARROW_LINK_SHARED_DEFAULT})
option(RERUN_ARROW_LINK_SHARED "Link to the Arrow shared library." ${RERUN_ARROW_LINK_SHARED_DEFAULT})
option(RERUN_DOWNLOAD_AND_BUILD_ARROW "If enabled, arrow will be added as an external project and built with the minimal set required by the Rerun C++ SDK" ON)

if(RERUN_DOWNLOAD_AND_BUILD_ARROW)
Expand All @@ -105,6 +108,74 @@ endif()

target_link_libraries(rerun_sdk PRIVATE rerun_arrow_target)

# -----------------------------------------------------------------------------
# Installation.
set(RERUN_SDK_INSTALL_CMAKE_DIR "lib/cmake/rerun_sdk")

# Actual install setup.
install(TARGETS rerun_sdk
EXPORT rerun_sdkTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
INCLUDES DESTINATION include
)

# Add all headers to the install.
install(DIRECTORY "${RERUN_CPP_SOURCE_DIR}/" TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h")

# Add rerun_c to the lib folder.
# CMake doesn't allow installing imported targets which is why we need to add this as a file.
get_target_property(RERUN_C_LIB_LOCATION rerun_c IMPORTED_LOCATION)
install(FILES ${RERUN_C_LIB_LOCATION} DESTINATION lib)

# Similarly, we bundle the arrow library that was used during the build.
# For the moment we only support this when building with the downloaded, static libarrow.
# Otherwise, a system install of arrow has to be used.
get_target_property(RERUN_ARROW_LIB_LOCATION rerun_arrow_target LOCATION)

if(RERUN_DOWNLOAD_AND_BUILD_ARROW AND NOT RERUN_ARROW_LINK_SHARED)
get_target_property(RERUN_ARROW_LIBRARY_FILE rerun_arrow_target LOCATION)
get_target_property(RERUN_ARROW_BUNDLED_DEPENDENCIES_FILE arrow_targetBundledDeps LOCATION)
install(FILES
${RERUN_ARROW_LIBRARY_FILE}
${RERUN_ARROW_BUNDLED_DEPENDENCIES_FILE}
DESTINATION lib
)
endif()

# Export the target to a script.
install(EXPORT rerun_sdkTargets
FILE rerun_sdkTargets.cmake
DESTINATION ${RERUN_SDK_INSTALL_CMAKE_DIR}
)

include(CMakePackageConfigHelpers)

# TODO(#3868): Extract version from rerun.h
set(RERUN_VERSION 0.11.0)

# Package config file, so find_package(rerun_sdk) produces a target.
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/rerun_sdkConfig.cmake" # file needs to follow convention of find_package.
INSTALL_DESTINATION ${RERUN_SDK_INSTALL_CMAKE_DIR}
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)

# Version file for find_package.
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/rerun_sdkConfigVersion.cmake
VERSION ${RERUN_VERSION}
COMPATIBILITY ExactVersion
)

# Add the find_package dependent files.
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/rerun_sdkConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/rerun_sdkConfigVersion.cmake"
DESTINATION ${RERUN_SDK_INSTALL_CMAKE_DIR}
)

# -----------------------------------------------------------------------------
# Add tests if they exist (they are not part of the distribution zip).
# Has direct dpeendency to arrow, so needs to happen last.
Expand Down
52 changes: 52 additions & 0 deletions rerun_cpp/Config.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@PACKAGE_INIT@

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

set(RERUN_LIB_DIR "${CMAKE_CURRENT_LIST_DIR}/../..")

# Setup `rerun_c` (imported libraries can't be exported!)
add_library(rerun_c STATIC IMPORTED GLOBAL)
get_filename_component(RERUN_C_LIB_NAME @RERUN_C_LIB_LOCATION@ NAME)
set_target_properties(rerun_c PROPERTIES IMPORTED_LOCATION "${RERUN_LIB_DIR}/${RERUN_C_LIB_NAME}")
if(APPLE)
target_link_libraries(rerun_c INTERFACE "-framework CoreFoundation" "-framework IOKit")
elseif(UNIX) # if(LINUX) # CMake 3.25
target_link_libraries(rerun_c INTERFACE "-lm -ldl -pthread")
elseif(WIN32)
target_link_libraries(rerun_c INTERFACE ws2_32.dll Bcrypt.dll Userenv.dll ntdll.dll)
endif()

# Setup `rerun_arrow_target` (imported libraries can't be exported and package dependencies need to be re-declared)
# if(@RERUN_DOWNLOAD_AND_BUILD_ARROW@ AND NOT @RERUN_ARROW_LINK_SHARED@)
if(@RERUN_DOWNLOAD_AND_BUILD_ARROW@ AND NOT @RERUN_ARROW_LINK_SHARED@)
message(STATUS "Rerun is using bundled arrow library.")

add_library(rerun_arrow_target STATIC IMPORTED GLOBAL)
get_filename_component(RERUN_ARROW_LIB_NAME @RERUN_ARROW_LIBRARY_FILE@ NAME)
set_target_properties(rerun_arrow_target PROPERTIES IMPORTED_LOCATION "${RERUN_LIB_DIR}/${RERUN_ARROW_LIB_NAME}")

# We have to explicitly opt in the arrow bundled dependencies, otherwise we're missing the symbols for mimalloc.
add_library(arrow_targetBundledDeps STATIC IMPORTED)
get_filename_component(RERUN_ARROW_DEPS_LIB_NAME @RERUN_ARROW_BUNDLED_DEPENDENCIES_FILE@ NAME)
set_target_properties(arrow_targetBundledDeps PROPERTIES IMPORTED_LOCATION "${RERUN_LIB_DIR}/${RERUN_ARROW_DEPS_LIB_NAME}")
target_link_libraries(rerun_arrow_target INTERFACE arrow_targetBundledDeps)
else()
if(@RERUN_ARROW_LINK_SHARED@)
message(WARNING
"Rerun got built with an automatically downloaded version of libArrow,"
"but it was not bundled as part of the install since export of shared libArrow is not supported yet."
"Set RERUN_ARROW_LINK_SHARED to OFF during install or make sure find_package succeeds for Arrow."
)
endif()

find_package(Arrow REQUIRED)

message(STATUS "Rerun is using a system installed libArrow.")
option(RERUN_ARROW_LINK_SHARED "Link to the Arrow shared library" @RERUN_ARROW_LINK_SHARED_DEFAULT@)

if(RERUN_ARROW_LINK_SHARED)
add_library(rerun_arrow_target ALIAS Arrow::arrow_shared)
else()
add_library(rerun_arrow_target ALIAS Arrow::arrow_static)
endif()
endif()
36 changes: 34 additions & 2 deletions scripts/ci/bundle_and_upload_rerun_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,44 @@ def upload_rerun_cpp_sdk(rerun_zip: str, git_hash: str) -> None:
logging.info(f"Uploaded to https://build.rerun.io/commit/{git_hash}/rerun_cpp_sdk.zip")


def test_rerun_cpp(git_hash: str) -> None:
def test_fetch_content(git_hash: str) -> None:
logging.info("Testing uploaded artifact…")

logging.info("-> Testing without installing rerun…")
with tempfile.TemporaryDirectory() as testdir:
shutil.copytree("examples/cpp/minimal/", testdir, dirs_exist_ok=True)
run(["cmake", f"-DRERUN_CPP_URL=https://build.rerun.io/commit/{git_hash}/rerun_cpp_sdk.zip", "."], cwd=testdir)
run(["cmake", "--build", ".", "--parallel", str(multiprocessing.cpu_count())], cwd=testdir)


def test_install(rerun_zip: str) -> None:
logging.info("Testing using an install artifact…")

with tempfile.TemporaryDirectory() as testdir:
# unpacking the rerun_cpp_sdk.zip and installing it to a local directory.
shutil.unpack_archive(rerun_zip, f"{testdir}")
os.makedirs(f"{testdir}/build")
os.makedirs(f"{testdir}/install")
os.makedirs(f"{testdir}/example")
run( # configure
["cmake", "-B", "../build", "."],
cwd=f"{testdir}/rerun_cpp_sdk/",
)
run( # build
["cmake", "--build", "../build", "--target", "rerun_sdk", "--parallel", str(multiprocessing.cpu_count())],
cwd=f"{testdir}/rerun_cpp_sdk/",
)
run( # install
["cmake", "--install", "../build", "--prefix", "../install"],
cwd=f"{testdir}/rerun_cpp_sdk/",
)

# Using the install.
shutil.copytree("examples/cpp/minimal/", f"{testdir}/example", dirs_exist_ok=True)
run(["cmake", "-DRERUN_FIND_PACKAGE=ON", "-DCMAKE_PREFIX_PATH=../install", "."], cwd=f"{testdir}/example")
run(["cmake", "--build", ".", "--parallel", str(multiprocessing.cpu_count())], cwd=f"{testdir}/example")


def main() -> None:
logging.basicConfig(level=logging.INFO)

Expand Down Expand Up @@ -115,11 +144,14 @@ def main() -> None:
logging.info(f"Copying rerun_cpp_sdk bundle to local path from '{rerun_zip}' to '{args.local_path}'")
shutil.copy(rerun_zip, args.local_path)

if args.skip_test is not True:
test_install(rerun_zip)

if args.no_upload is not True:
upload_rerun_cpp_sdk(rerun_zip, git_hash)

if args.skip_test is not True and args.no_upload is not True:
test_rerun_cpp(git_hash)
test_fetch_content(git_hash)


if __name__ == "__main__":
Expand Down

0 comments on commit f18c4cb

Please sign in to comment.