feat(build): install/export rules, umbrella header, verified consumer
This commit is contained in:
1 parent
377cca8e9b
commit
0972903d27
11 files changed
+333
-7
No files matched your search
@@ -0,0 +1,23 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
# Package config for `plot`. Include it with
|
||||
#
|
||||
# find_package(plot 0.1 REQUIRED)
|
||||
# target_link_libraries(your_target PRIVATE plot::core)
|
||||
#
|
||||
# `plot::core` is the library, and carries no third-party dependency at all. The
|
||||
# adapter targets (`plot::glfw`, `plot::qt6`, `plot::gtk4`) are here only when
|
||||
# their toolkit could be promised to a consumer: an adapter whose toolkit the
|
||||
# build fetched with FetchContent is deliberately not installed, because this
|
||||
# file has nothing to point a consumer at -- see the build's configure log for
|
||||
# which adapters were exported and which were skipped, and why.
|
||||
#
|
||||
# Those toolkits are re-found below, before plotTargets.cmake is included: the
|
||||
# adapter targets name them in their own link interfaces, so the imported targets
|
||||
# have to exist first.
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
@PLOT_ADAPTER_DEPENDENCIES@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/plotTargets.cmake")
|
||||
|
||||
check_required_components(plot)
|
||||
@@ -0,0 +1,22 @@
|
||||
# LeakSanitizer suppressions for the `linux-asan` build (PLOT_SANITIZE=address).
|
||||
# Pointed at by tests/CMakeLists.txt, which sets ASAN_OPTIONS on the test itself
|
||||
# so `ctest --test-dir build/asan` gets it however it is launched.
|
||||
#
|
||||
# The boundary this file exists to hold: a sanitizer report from *our* code is a
|
||||
# finding and must fail the run, so nothing here may ever suppress a frame under
|
||||
# include/plot/ or src/. Only the GL driver may be named -- an EGL/GL stack
|
||||
# (Mesa's libEGL, libgallium, libglapi, radeonsi's ACO, or the LLVM JIT behind
|
||||
# llvmpipe) is a system library this project does not build and cannot fix, and
|
||||
# it is loaded only by the headless EGL context the GL tests create.
|
||||
#
|
||||
# It is currently empty of entries on purpose. The asan suite runs clean against
|
||||
# the installed driver -- 127 cases, no report of any origin (the leak checker was
|
||||
# confirmed live with a deliberate 1 KB leak, which does report and exit 1) -- and
|
||||
# a suppression nobody has needed is a suppression nobody can justify. If a driver
|
||||
# report does appear, add the narrowest entry that names the library, e.g.
|
||||
#
|
||||
# leak:libEGL.so
|
||||
# leak:libgallium*
|
||||
#
|
||||
# and leave the count in the commit message. The shape is `leak:<substring of a
|
||||
# frame in the stack>`; ASan takes the same list through ASAN_OPTIONS.
|
||||
@@ -16,6 +16,62 @@ option(PLOT_BUILD_GLFW "Build the GLFW adapter and demo" OFF)
|
||||
option(PLOT_BUILD_IMGUI "Build the Dear ImGui adapter and demo" OFF)
|
||||
option(PLOT_BUILD_QT6 "Build the Qt6 adapter and demo" OFF)
|
||||
option(PLOT_BUILD_GTK4 "Build the GTK4 adapter and demo" OFF)
|
||||
option(PLOT_INSTALL "Generate install and export rules (find_package(plot))" ON)
|
||||
set(PLOT_SANITIZE "" CACHE STRING
|
||||
"Sanitizers to build with, as the list a -fsanitize= flag takes (e.g. address); empty for none")
|
||||
|
||||
# Sanitizer flags go on every target in this project, fetched third-party sources
|
||||
# included: a partially instrumented build reports as loudly about the
|
||||
# instrumentation gap as about any real bug. The flags are one -fsanitize= list
|
||||
# (PLOT_SANITIZE) rather than a set of per-sanitizer options so the preset, the
|
||||
# tests' runtime environment and this file cannot disagree about what is on.
|
||||
if(PLOT_SANITIZE)
|
||||
add_compile_options(-fsanitize=${PLOT_SANITIZE} -fno-omit-frame-pointer)
|
||||
add_link_options(-fsanitize=${PLOT_SANITIZE})
|
||||
endif()
|
||||
|
||||
# Read by tests/CMakeLists.txt, which points ASAN_OPTIONS at this project's
|
||||
# suppressions file when the address sanitizer is on.
|
||||
string(REPLACE "," ";" PLOT_SANITIZE_LIST "${PLOT_SANITIZE}")
|
||||
if("address" IN_LIST PLOT_SANITIZE_LIST)
|
||||
set(PLOT_ASAN_ENABLED TRUE)
|
||||
endif()
|
||||
|
||||
# --- install / export bookkeeping --------------------------------------------
|
||||
#
|
||||
# An adapter can only be installed and exported when its toolkit can be found
|
||||
# again on the consumer's machine. A dependency resolved by find_package() or
|
||||
# pkg-config can be: the installed config file re-finds it with the very same
|
||||
# call. A dependency that FetchContent supplied cannot -- there is nothing on the
|
||||
# consumer's machine to point at, and promising it would make every consumer
|
||||
# clone and build that toolkit at the same revision -- so those adapters stay out
|
||||
# of the export set and the configure log says why (see each adapter's
|
||||
# CMakeLists.txt for its own resolution order).
|
||||
#
|
||||
# The results are global properties, because the adapters decide inside their own
|
||||
# subdirectory while the install rules run at the top level. A property rather
|
||||
# than a cache entry: a cache value cannot hold the newlines a snippet of
|
||||
# find_dependency() calls needs, and nothing here has to survive the configure
|
||||
# pass that produced it.
|
||||
|
||||
# Records one adapter's install/export decision and prints it. `dependency` is
|
||||
# the config-file snippet that re-creates the toolkit's imported target before
|
||||
# plotTargets.cmake is included; it is empty when the target is not exported.
|
||||
function(plot_record_adapter_export target exportable reason dependency)
|
||||
if(NOT exportable)
|
||||
message(STATUS "plot: not exporting ${target}: ${reason}")
|
||||
elseif(NOT PLOT_INSTALL)
|
||||
message(STATUS "plot: not exporting ${target}: PLOT_INSTALL is OFF")
|
||||
else()
|
||||
set_property(GLOBAL APPEND PROPERTY PLOT_ADAPTER_EXPORT_TARGETS "${target}")
|
||||
# Read-modify-write, not APPEND: the snippets are one block of C++-style
|
||||
# lines that must be substituted into one file, and a property read back is a
|
||||
# list -- APPEND would join them with the separator ';' instead of a newline.
|
||||
get_property(plot_dependencies GLOBAL PROPERTY PLOT_ADAPTER_DEPENDENCIES)
|
||||
set_property(GLOBAL PROPERTY PLOT_ADAPTER_DEPENDENCIES "${plot_dependencies}${dependency}")
|
||||
message(STATUS "plot: exporting ${target}: ${reason}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Apply the project warning set to a first-party target. Warnings are never
|
||||
# suppressed per file.
|
||||
@@ -38,15 +94,22 @@ endfunction()
|
||||
# GLFW (the last resort, because it needs the network). The result is cached in
|
||||
# PLOT_GLFW_DEP, so a build with several adapters enabled discovers -- and at
|
||||
# worst fetches -- exactly one copy. Sets <out_var> to the target to link.
|
||||
#
|
||||
# PLOT_GLFW_DEP_ORIGIN records which of the three supplied it, because only the
|
||||
# first two can be promised to a consumer of an installed adapter (see
|
||||
# plot_record_adapter_export()).
|
||||
function(plot_find_glfw out_var)
|
||||
if(NOT DEFINED PLOT_GLFW_DEP)
|
||||
set(plot_glfw_dep "")
|
||||
set(plot_glfw_origin "")
|
||||
|
||||
find_package(glfw3 3.3 QUIET)
|
||||
if(TARGET glfw)
|
||||
set(plot_glfw_dep glfw)
|
||||
set(plot_glfw_origin find_package)
|
||||
elseif(TARGET glfw3::glfw3)
|
||||
set(plot_glfw_dep glfw3::glfw3)
|
||||
set(plot_glfw_origin find_package)
|
||||
endif()
|
||||
|
||||
if(NOT plot_glfw_dep)
|
||||
@@ -55,6 +118,7 @@ function(plot_find_glfw out_var)
|
||||
pkg_check_modules(GLFW_PC QUIET IMPORTED_TARGET glfw3)
|
||||
if(TARGET PkgConfig::GLFW_PC)
|
||||
set(plot_glfw_dep PkgConfig::GLFW_PC)
|
||||
set(plot_glfw_origin pkg-config)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -72,12 +136,29 @@ function(plot_find_glfw out_var)
|
||||
GIT_SHALLOW TRUE)
|
||||
FetchContent_MakeAvailable(glfw)
|
||||
set(plot_glfw_dep glfw)
|
||||
set(plot_glfw_origin FetchContent)
|
||||
endif()
|
||||
|
||||
set(PLOT_GLFW_DEP "${plot_glfw_dep}" CACHE INTERNAL
|
||||
"GLFW target the plot adapters link against")
|
||||
set(PLOT_GLFW_DEP_ORIGIN "${plot_glfw_origin}" CACHE INTERNAL
|
||||
"How plot resolved GLFW: find_package, pkg-config or FetchContent")
|
||||
message(STATUS "plot: GLFW adapter dependency: ${plot_glfw_dep}")
|
||||
endif()
|
||||
|
||||
set(${out_var} "${PLOT_GLFW_DEP}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# The find_dependency() snippet that re-creates an exported adapter's toolkit
|
||||
# target on a consumer's machine, for the toolkits a config file can re-find.
|
||||
# Adapters call these when they record their export decision; the snippets are
|
||||
# substituted into cmake/plotConfig.cmake.in.
|
||||
function(plot_glfw_dependency_snippet out_var)
|
||||
if(PLOT_GLFW_DEP_ORIGIN STREQUAL "find_package")
|
||||
set(${out_var} "find_dependency(glfw3 3.3)\n" PARENT_SCOPE)
|
||||
else()
|
||||
set(${out_var}
|
||||
"find_dependency(PkgConfig)\npkg_check_modules(GLFW_PC REQUIRED IMPORTED_TARGET glfw3)\n"
|
||||
PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
Reference in new issue
Block a user