Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cmake install #4326

Merged
merged 8 commits into from
Nov 24, 2023
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
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
Loading