CMake: Ground the documented CMake behavior in tests
libeigen/eigen!2861 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
co-authored by
Rasmus Munk Larsen
parent
cd5b44a5ad
commit
18f650509b
@@ -110,6 +110,34 @@ that is impractical, that it reaches the new code by construction.
|
||||
- Exercise the customization points users are documented to have (custom scalars, functors without declared traits),
|
||||
not only the built-in specializations that happen to satisfy a new precondition.
|
||||
|
||||
## Build-System Tests
|
||||
|
||||
[`test/buildsystem`](../test/buildsystem) holds the coverage for Eigen's own CMake surface: what an install tree
|
||||
contains, what `find_package(Eigen3)` and the version ranges in
|
||||
[`cmake/Eigen3ConfigVersion.cmake.in`](../cmake/Eigen3ConfigVersion.cmake.in) accept, and how an embedding project
|
||||
opts out of Eigen's install rules. They exist because those are claims
|
||||
[`doc/TopicCMakeGuide.dox`](../doc/TopicCMakeGuide.dox) makes to users and nothing else checks; the blocking
|
||||
documentation job only builds the docs, it does not run what they describe.
|
||||
|
||||
```bash
|
||||
cmake -G Ninja -S . -B build -DEIGEN_BUILD_TESTING=ON
|
||||
cmake -E chdir build ctest -L buildsystem --output-on-failure
|
||||
```
|
||||
|
||||
`ctest --test-dir` would be the shorter spelling, but that option arrived in CMake 3.20; the 3.17 Eigen supports
|
||||
accepts and ignores it, inspects the source directory instead, reports that no tests were found, and exits
|
||||
successfully.
|
||||
|
||||
No target needs building first: each scenario runs its own nested configure, build, and install into the CTest
|
||||
binary directory. Add a claim by dropping a scenario in `scenarios/` and naming it in the list in
|
||||
`test/buildsystem/CMakeLists.txt`; the driver `run_scenario.cmake` supplies the assertion helpers.
|
||||
|
||||
Two hazards specific to these tests. Eigen calls `export(PACKAGE Eigen3)`, so CMake's user package registry names
|
||||
every Eigen build tree on the machine — a `find_package` scenario must disable both registries and assert the package
|
||||
came from the prefix it installed, or it passes without reading that prefix at all. And because CMake registers the
|
||||
tests, a guard that stops matching yields an empty selection rather than a failure, so the CI job runs `ctest` with
|
||||
`--no-tests=error`.
|
||||
|
||||
## Configurations The Test Suite Cannot See
|
||||
|
||||
- In the default host-test configuration, no test compiles an `EIGEN_NO_DEBUG` code path: `test/main.h` undefines
|
||||
|
||||
@@ -15,6 +15,8 @@ core.*
|
||||
*.bak
|
||||
*~
|
||||
*.build*
|
||||
# Keep the build-system test job's script, whose name matches the rule above.
|
||||
!ci/scripts/test.buildsystem.script.sh
|
||||
.tidy-build/
|
||||
*.moc.*
|
||||
*.moc
|
||||
|
||||
@@ -754,6 +754,10 @@ if (EIGEN_BUILD_TESTING)
|
||||
add_subdirectory(failtest EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# Build-system integration tests. These build nothing in this project, so
|
||||
# they need no place in either target above.
|
||||
add_subdirectory(test/buildsystem)
|
||||
|
||||
ei_testing_print_summary()
|
||||
|
||||
if (EIGEN_SPLIT_TESTSUITE)
|
||||
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# Configures Eigen and runs only the build-system integration tests under
|
||||
# test/buildsystem.
|
||||
#
|
||||
# This job builds and consumes no artifact, unlike the paired build/test jobs:
|
||||
# each scenario drives its own nested configure, build, and install, so the
|
||||
# enclosing build directory holds nothing but the CTest definitions. For the
|
||||
# same reason the job stays off the content-addressed pass cache, which keys on
|
||||
# a test's executable; these tests have none, so a recorded pass would outlive
|
||||
# any change to Eigen's CMake files.
|
||||
|
||||
set -ex
|
||||
|
||||
rootdir=$(pwd)
|
||||
mkdir -p "${EIGEN_CI_BUILDDIR}"
|
||||
cd "${EIGEN_CI_BUILDDIR}"
|
||||
|
||||
# The scenarios configure Eigen themselves with whatever options they need, so
|
||||
# this configure only has to register the tests.
|
||||
#
|
||||
# EIGEN_CI_ADDITIONAL_ARGS carries several -D options in a single variable and
|
||||
# has to word-split; ci/build.linux.gitlab-ci.yml documents that contract for
|
||||
# the jobs that set it. Every other expansion here is a single word.
|
||||
# shellcheck disable=SC2086
|
||||
cmake -G Ninja \
|
||||
"-DCMAKE_C_COMPILER=${EIGEN_CI_C_COMPILER}" \
|
||||
"-DCMAKE_CXX_COMPILER=${EIGEN_CI_CXX_COMPILER}" \
|
||||
-DEIGEN_BUILD_TESTING=ON \
|
||||
-DEIGEN_BUILD_DOC=OFF \
|
||||
-DEIGEN_BUILD_DEMOS=OFF \
|
||||
-DEIGEN_BUILD_BLAS=OFF \
|
||||
-DEIGEN_BUILD_LAPACK=OFF \
|
||||
${EIGEN_CI_ADDITIONAL_ARGS} "${rootdir}"
|
||||
|
||||
# --no-tests=error matters more here than in the paired test jobs: everything
|
||||
# that registers these tests is itself CMake, so a guard in
|
||||
# test/buildsystem/CMakeLists.txt that stops matching would otherwise leave
|
||||
# ctest reporting success over an empty selection.
|
||||
ctest -L buildsystem --output-on-failure --no-tests=error "-j${NPROC}"
|
||||
|
||||
cd "${rootdir}"
|
||||
|
||||
set +x
|
||||
@@ -731,3 +731,61 @@ test:linux:aarch64:clang-14:default:smoketest:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
tags:
|
||||
- saas-linux-small-arm64
|
||||
|
||||
##### Build-System Integration #################################################
|
||||
|
||||
# Grounds the CMake behavior doc/TopicCMakeGuide.dox documents: find_package
|
||||
# against an installed tree, the version-range contract of the hand-written
|
||||
# Eigen3ConfigVersion.cmake, embedding via add_subdirectory, and the ways an
|
||||
# embedding project opts out of Eigen's install rules.
|
||||
#
|
||||
# Self-contained, so it neither extends .test:linux nor needs a build job: the
|
||||
# scenarios run their own nested configures against the checkout, and the
|
||||
# enclosing build directory holds only the CTest definitions. Staying off
|
||||
# .test:linux also keeps it off the pass cache, which keys on a test's
|
||||
# executable -- these tests have none, so a recorded pass would outlive any
|
||||
# change to Eigen's CMake files.
|
||||
#
|
||||
# Cheap -- a nested configure and a small compile per scenario, six seconds of
|
||||
# script on the runner, inside a job that takes half a minute once the image
|
||||
# pull and checkout are counted -- but still gated on the files that can make
|
||||
# it fail rather than run on every merge request: Eigen's own CMake surface,
|
||||
# the guide it grounds, and the job's own definition and script. A push to the
|
||||
# default branch runs it unconditionally, as the backstop for whatever the path
|
||||
# list does not anticipate.
|
||||
#
|
||||
# Not behind the all-tests label, unlike the documentation job it complements:
|
||||
# that label is why an incorrect claim in the CMake guide reached a release
|
||||
# unnoticed, and an MR that edits these files is exactly the MR that needs the
|
||||
# answer before merge rather than after.
|
||||
test:linux:buildsystem:
|
||||
extends: .common:linux:cross
|
||||
image: ${EIGEN_CI_IMAGE_LINUX_AMD64_SMOKETEST_BUILD}
|
||||
stage: test
|
||||
needs: []
|
||||
variables:
|
||||
EIGEN_CI_TARGET_ARCH: x86_64
|
||||
EIGEN_CI_CROSS_TARGET_TRIPLE: x86_64-linux-gnu
|
||||
EIGEN_CI_C_COMPILER: gcc-10
|
||||
EIGEN_CI_CXX_COMPILER: g++-10
|
||||
EIGEN_CI_SKIP_APT: "true"
|
||||
script:
|
||||
- . ci/scripts/test.buildsystem.script.sh
|
||||
tags:
|
||||
- saas-linux-medium-amd64
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- CMakeLists.txt
|
||||
- cmake/**/*
|
||||
- Eigen/Version
|
||||
- blas/CMakeLists.txt
|
||||
- lapack/CMakeLists.txt
|
||||
- unsupported/**/CMakeLists.txt
|
||||
- doc/TopicCMakeGuide.dox
|
||||
- test/buildsystem/**/*
|
||||
- ci/test.linux.gitlab-ci.yml
|
||||
- ci/scripts/test.buildsystem.script.sh
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
- if: $CI_PIPELINE_SOURCE == "web"
|
||||
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
|
||||
+31
-6
@@ -36,12 +36,15 @@ instances of %Eigen installed, `find_package` will use the first one
|
||||
encountered. To request a specific version of %Eigen, use the `<version>`
|
||||
option in `find_package`:
|
||||
```
|
||||
find_package(Eigen3 3.4 REQUIRED NO_MODULE) # Restricts to 3.4.z
|
||||
find_package(Eigen3 3.4 REQUIRED NO_MODULE) # Any version >=3.4 but <4.0.0.
|
||||
```
|
||||
Starting with Eigen 3.4.1, we also support a range spanning major versions:
|
||||
```
|
||||
find_package(Eigen3 3.4...5 REQUIRED NO_MODULE) # Any version >=3.4.1 but <6.0.0.
|
||||
```
|
||||
\note Version ranges are `find_package` syntax introduced in %CMake 3.19. Older %CMake
|
||||
passes `3.4...5` through as a single version string, which `Eigen3ConfigVersion.cmake`
|
||||
cannot parse and therefore rejects.
|
||||
|
||||
Do not forget to set the <a href="https://cmake.org/cmake/help/v3.7/variable/CMAKE_PREFIX_PATH.html">\c CMAKE_PREFIX_PATH </a> variable if Eigen is not installed in a default location or if you want to pick a specific version. For instance:
|
||||
\code{.sh}
|
||||
@@ -81,7 +84,6 @@ FetchContent_Declare(
|
||||
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
||||
GIT_TAG master
|
||||
GIT_SHALLOW TRUE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(Eigen)
|
||||
|
||||
@@ -106,10 +108,33 @@ FetchContent_MakeAvailable(Eigen)
|
||||
\subsection title_fetchcontent_exclude Using EXCLUDE_FROM_ALL
|
||||
|
||||
Projects that depend on %Eigen should typically exclude installing %Eigen by
|
||||
default to avoid overwriting a previous installation. Pass
|
||||
\c EXCLUDE_FROM_ALL in the \c FetchContent_Declare call (as shown above) or
|
||||
the equivalent \c add_subdirectory option so that %Eigen's install rules are
|
||||
not included in the default install target.
|
||||
default to avoid overwriting a previous installation. Passing
|
||||
\c EXCLUDE_FROM_ALL to \c add_subdirectory drops %Eigen's install rules, and in
|
||||
addition keeps %Eigen's targets out of the default build. That form works on
|
||||
every %CMake version %Eigen supports:
|
||||
\code{.cmake}
|
||||
add_subdirectory(path/to/eigen eigen-build EXCLUDE_FROM_ALL)
|
||||
\endcode
|
||||
|
||||
\c FetchContent_Declare accepts the same keyword, but only from %CMake 3.28
|
||||
onwards, so a project using it has to say so:
|
||||
\code{.cmake}
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
Eigen
|
||||
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
||||
GIT_TAG master
|
||||
GIT_SHALLOW TRUE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(Eigen)
|
||||
\endcode
|
||||
|
||||
\warning %CMake 3.17 through 3.27 accept \c EXCLUDE_FROM_ALL in
|
||||
\c FetchContent_Declare without complaint and ignore it, so %Eigen is installed
|
||||
anyway.
|
||||
|
||||
\subsection title_fetchcontent_cmake330 Note for CMake 3.30 and later
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# Build-system integration tests. Each scenario drives a real configure,
|
||||
# build, and install of Eigen through CMake and asserts a claim that
|
||||
# doc/TopicCMakeGuide.dox makes about consuming Eigen, so documented CMake
|
||||
# behavior cannot drift from the tree without a test failing.
|
||||
#
|
||||
# Registered only for a top-level, non-cross-compiling build: a scenario
|
||||
# configures and runs a nested project, which needs a usable host toolchain
|
||||
# rather than the artifacts of the enclosing build.
|
||||
|
||||
if(NOT PROJECT_IS_TOP_LEVEL OR CMAKE_CROSSCOMPILING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(EIGEN_BUILDSYSTEM_SCENARIOS
|
||||
find_package
|
||||
find_package_version_reject
|
||||
add_subdirectory
|
||||
install_default
|
||||
exclude_from_all
|
||||
)
|
||||
|
||||
# find_package version ranges are CMake 3.19 syntax. On the 3.17 Eigen still
|
||||
# supports, "3.4...5" reaches Eigen3ConfigVersion.cmake as one unparsable
|
||||
# version string and the consumer configure fails, so the claim this scenario
|
||||
# tests cannot be stated there at all.
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
|
||||
list(APPEND EIGEN_BUILDSYSTEM_SCENARIOS find_package_version_range)
|
||||
endif()
|
||||
|
||||
# EIGEN_BUILD_PKGCONFIG only exists off Windows, so the scenario asserting
|
||||
# that it suppresses eigen3.pc has nothing to assert there.
|
||||
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
list(APPEND EIGEN_BUILDSYSTEM_SCENARIOS pkgconfig_off)
|
||||
endif()
|
||||
|
||||
set(EIGEN_BUILDSYSTEM_CONFIG "${CMAKE_BUILD_TYPE}")
|
||||
if(NOT EIGEN_BUILDSYSTEM_CONFIG)
|
||||
set(EIGEN_BUILDSYSTEM_CONFIG "Release")
|
||||
endif()
|
||||
|
||||
foreach(scenario IN LISTS EIGEN_BUILDSYSTEM_SCENARIOS)
|
||||
add_test(NAME buildsystem_${scenario}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DEIGEN_SOURCE_DIR=${Eigen_SOURCE_DIR}"
|
||||
"-DSCENARIO=${scenario}"
|
||||
"-DWORK_DIR=${CMAKE_CURRENT_BINARY_DIR}/${scenario}"
|
||||
"-DGENERATOR=${CMAKE_GENERATOR}"
|
||||
"-DC_COMPILER=${CMAKE_C_COMPILER}"
|
||||
"-DCXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DBUILD_CONFIG=${EIGEN_BUILDSYSTEM_CONFIG}"
|
||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/run_scenario.cmake")
|
||||
# Each scenario runs several nested CMake invocations; the default 1500s
|
||||
# ceiling is ample, but a hung nested build should fail rather than hang.
|
||||
set_tests_properties(buildsystem_${scenario} PROPERTIES
|
||||
LABELS "buildsystem" TIMEOUT 900)
|
||||
endforeach()
|
||||
@@ -0,0 +1,29 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# Consumes an installed Eigen exactly the way doc/TopicCMakeGuide.dox opens:
|
||||
# find_package plus target_link_libraries against Eigen3::Eigen.
|
||||
# EIGEN_VERSION_SPEC carries the optional version argument so one project can
|
||||
# stand in for the plain, ranged, and rejected forms the guide documents.
|
||||
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
project(eigen_installed_consumer CXX)
|
||||
|
||||
find_package(Eigen3 ${EIGEN_VERSION_SPEC} REQUIRED NO_MODULE)
|
||||
|
||||
# Prove the package came from the install tree the scenario built. Eigen calls
|
||||
# export(PACKAGE Eigen3), so an unrelated build tree recorded in CMake's user
|
||||
# package registry can satisfy find_package and leave the scenario asserting
|
||||
# nothing about what it installed.
|
||||
if(EIGEN_EXPECTED_PREFIX)
|
||||
get_filename_component(eigen_found_dir "${Eigen3_DIR}" REALPATH)
|
||||
get_filename_component(eigen_expected_prefix "${EIGEN_EXPECTED_PREFIX}" REALPATH)
|
||||
string(FIND "${eigen_found_dir}" "${eigen_expected_prefix}/" eigen_prefix_position)
|
||||
if(NOT eigen_prefix_position EQUAL 0)
|
||||
message(FATAL_ERROR
|
||||
"found Eigen3 at ${eigen_found_dir}, expected it under ${eigen_expected_prefix}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable(consumer ../main.cpp)
|
||||
target_link_libraries(consumer Eigen3::Eigen)
|
||||
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: The Eigen Authors
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Consumer program shared by the build-system integration tests. It exists to
|
||||
// prove that the Eigen a scenario assembled is usable, so it exercises a
|
||||
// header, a template instantiation, and a computed result rather than only
|
||||
// including <Eigen/Dense>. The marker on the last line is what the driver
|
||||
// matches; a run that ends early fails the scenario.
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
int main() {
|
||||
Eigen::Matrix3d m = Eigen::Matrix3d::Identity();
|
||||
m(0, 1) = 2.0;
|
||||
m(2, 0) = -1.0;
|
||||
|
||||
// Unit triangular up to the (2,0) entry, so the determinant is exactly one
|
||||
// in binary floating point and needs no tolerance.
|
||||
if (m.determinant() != 1.0) {
|
||||
std::printf("determinant was %f, expected 1\n", m.determinant());
|
||||
return 1;
|
||||
}
|
||||
|
||||
Eigen::Vector3d v = m * Eigen::Vector3d(1.0, 1.0, 1.0);
|
||||
if (v(0) != 3.0) {
|
||||
std::printf("product gave %f, expected 3\n", v(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::printf("eigen-ok\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# Embeds Eigen the way doc/TopicCMakeGuide.dox describes for FetchContent:
|
||||
# the options are forced before Eigen is added, then Eigen3::Eigen is linked.
|
||||
# FetchContent_MakeAvailable reduces to this add_subdirectory call, so driving
|
||||
# add_subdirectory directly tests the same path without a network fetch.
|
||||
#
|
||||
# EIGEN_USE_EXCLUDE_FROM_ALL selects the variant the guide's EXCLUDE_FROM_ALL
|
||||
# section describes.
|
||||
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
project(eigen_subproject_consumer CXX)
|
||||
|
||||
# The consumer runs a test of its own, so the scenario can require that CTest
|
||||
# in this build directory sees exactly that one test. Without a test to find,
|
||||
# "Eigen contributed nothing" and "CTest read the wrong directory" produce the
|
||||
# same empty listing. enable_testing() precedes add_subdirectory so that any
|
||||
# test Eigen registered would be generated into this tree too.
|
||||
enable_testing()
|
||||
|
||||
set(EIGEN_BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||
set(EIGEN_BUILD_DOC OFF CACHE BOOL "" FORCE)
|
||||
set(EIGEN_BUILD_DEMOS OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||
|
||||
if(EIGEN_USE_EXCLUDE_FROM_ALL)
|
||||
add_subdirectory("${EIGEN_SOURCE_DIR}" eigen-build EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
add_subdirectory("${EIGEN_SOURCE_DIR}" eigen-build)
|
||||
endif()
|
||||
|
||||
add_executable(consumer ../main.cpp)
|
||||
target_link_libraries(consumer Eigen3::Eigen)
|
||||
add_test(NAME consumer_runs COMMAND consumer)
|
||||
|
||||
# The consumer's own install rule must keep working whatever Eigen's does, so
|
||||
# the scenarios can tell "Eigen installed nothing" apart from "nothing ran".
|
||||
install(TARGETS consumer RUNTIME DESTINATION bin)
|
||||
@@ -0,0 +1,255 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# Driver for the build-system integration tests. Run in script mode:
|
||||
#
|
||||
# cmake -DEIGEN_SOURCE_DIR=<src> -DSCENARIO=<name> -DWORK_DIR=<dir>
|
||||
# -DGENERATOR=<gen> -DCXX_COMPILER=<path> -DBUILD_CONFIG=<cfg>
|
||||
# -P run_scenario.cmake
|
||||
#
|
||||
# The driver defines the helpers below and then includes
|
||||
# scenarios/${SCENARIO}.cmake, which performs the assertions. A failed
|
||||
# assertion aborts with FATAL_ERROR, which CTest reports as a test failure.
|
||||
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
|
||||
foreach(var EIGEN_SOURCE_DIR SCENARIO WORK_DIR GENERATOR BUILD_CONFIG)
|
||||
if(NOT DEFINED ${var})
|
||||
message(FATAL_ERROR "run_scenario.cmake requires -D${var}=<value>")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(BS_CONSUMER_DIR "${CMAKE_CURRENT_LIST_DIR}/consumers")
|
||||
set(BS_PREFIX "${WORK_DIR}/prefix")
|
||||
|
||||
# The parts of Eigen's own build that no scenario inspects are slow to
|
||||
# configure and drag in tools a scenario should not depend on.
|
||||
set(BS_EIGEN_QUIET_OPTIONS
|
||||
-DEIGEN_BUILD_TESTING=OFF
|
||||
-DEIGEN_BUILD_DOC=OFF
|
||||
-DEIGEN_BUILD_DEMOS=OFF
|
||||
-DEIGEN_BUILD_BLAS=OFF
|
||||
-DEIGEN_BUILD_LAPACK=OFF
|
||||
)
|
||||
|
||||
# Eigen calls export(PACKAGE Eigen3), so CMake's user package registry names
|
||||
# every Eigen build tree on the machine. A find_package scenario that let the
|
||||
# registry answer would pass without ever reading the install tree it just
|
||||
# built, so every such configure disables both registries and additionally
|
||||
# asserts, in the consumer project, that the package came from BS_PREFIX.
|
||||
set(BS_FIND_PACKAGE_ISOLATION
|
||||
-DCMAKE_FIND_USE_PACKAGE_REGISTRY=OFF
|
||||
-DCMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY=OFF
|
||||
)
|
||||
|
||||
# Start from an empty work directory so a rerun cannot observe a previous
|
||||
# run's cache or install tree.
|
||||
file(REMOVE_RECURSE "${WORK_DIR}")
|
||||
file(MAKE_DIRECTORY "${WORK_DIR}")
|
||||
|
||||
function(bs_fail message)
|
||||
message(FATAL_ERROR "[${SCENARIO}] ${message}")
|
||||
endfunction()
|
||||
|
||||
# Runs a command, failing the scenario with its merged output unless the exit
|
||||
# status matches EXPECT_RESULT. EXPECT_RESULT accepts a number or the word
|
||||
# FAILURE, which admits any non-zero status.
|
||||
function(bs_run)
|
||||
cmake_parse_arguments(BS "" "WHAT;EXPECT_RESULT;OUTPUT_VARIABLE" "COMMAND" ${ARGN})
|
||||
if(NOT DEFINED BS_EXPECT_RESULT)
|
||||
set(BS_EXPECT_RESULT 0)
|
||||
endif()
|
||||
execute_process(COMMAND ${BS_COMMAND}
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_VARIABLE output
|
||||
ERROR_VARIABLE output)
|
||||
if(BS_EXPECT_RESULT STREQUAL "FAILURE")
|
||||
if(result EQUAL 0)
|
||||
bs_fail("${BS_WHAT} was expected to fail but succeeded\n----\n${output}\n----")
|
||||
endif()
|
||||
elseif(NOT result EQUAL BS_EXPECT_RESULT)
|
||||
bs_fail("${BS_WHAT} exited ${result}, expected ${BS_EXPECT_RESULT}\n----\n${output}\n----")
|
||||
endif()
|
||||
if(BS_OUTPUT_VARIABLE)
|
||||
set(${BS_OUTPUT_VARIABLE} "${output}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Eigen's own project() call enables C as well as CXX, so a nested configure of
|
||||
# Eigen needs both compilers. An image whose compilers are versioned names such
|
||||
# as gcc-10/g++-10, with no plain cc on PATH, has none to detect on its own.
|
||||
function(bs_cmake_compiler_args out_var)
|
||||
set(args "")
|
||||
if(C_COMPILER)
|
||||
list(APPEND args "-DCMAKE_C_COMPILER=${C_COMPILER}")
|
||||
endif()
|
||||
if(CXX_COMPILER)
|
||||
list(APPEND args "-DCMAKE_CXX_COMPILER=${CXX_COMPILER}")
|
||||
endif()
|
||||
set(${out_var} "${args}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Configures <src> into <bin>. Remaining arguments are passed to CMake.
|
||||
function(bs_configure what src bin)
|
||||
bs_cmake_compiler_args(compiler_args)
|
||||
bs_run(WHAT "configure ${what}"
|
||||
COMMAND ${CMAKE_COMMAND} -S "${src}" -B "${bin}" -G "${GENERATOR}"
|
||||
"-DCMAKE_BUILD_TYPE=${BUILD_CONFIG}" ${compiler_args} ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# Configures <src> expecting failure, returning the output through <output_var>.
|
||||
function(bs_configure_expect_failure what src bin output_var)
|
||||
bs_cmake_compiler_args(compiler_args)
|
||||
bs_run(WHAT "configure ${what}" EXPECT_RESULT FAILURE OUTPUT_VARIABLE output
|
||||
COMMAND ${CMAKE_COMMAND} -S "${src}" -B "${bin}" -G "${GENERATOR}"
|
||||
"-DCMAKE_BUILD_TYPE=${BUILD_CONFIG}" ${compiler_args} ${ARGN})
|
||||
set(${output_var} "${output}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(bs_build what bin)
|
||||
bs_run(WHAT "build ${what}"
|
||||
COMMAND ${CMAKE_COMMAND} --build "${bin}" --config "${BUILD_CONFIG}" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
function(bs_install what bin)
|
||||
bs_run(WHAT "install ${what}"
|
||||
COMMAND ${CMAKE_COMMAND} --install "${bin}" --config "${BUILD_CONFIG}")
|
||||
endfunction()
|
||||
|
||||
# Configures Eigen as a top-level project and installs it into BS_PREFIX.
|
||||
# Remaining arguments are passed to the Eigen configure.
|
||||
function(bs_install_eigen)
|
||||
bs_configure("Eigen" "${EIGEN_SOURCE_DIR}" "${WORK_DIR}/eigen-build"
|
||||
"-DCMAKE_INSTALL_PREFIX=${BS_PREFIX}"
|
||||
${BS_EIGEN_QUIET_OPTIONS} ${ARGN})
|
||||
bs_install("Eigen" "${WORK_DIR}/eigen-build")
|
||||
endfunction()
|
||||
|
||||
# Every file in the install prefix, as paths relative to it. Matching against
|
||||
# this list rather than globbing absolute paths keeps the assertions
|
||||
# independent of how deep INCLUDE_INSTALL_DIR happens to be.
|
||||
function(bs_installed_files out_var)
|
||||
set(found "")
|
||||
if(EXISTS "${BS_PREFIX}")
|
||||
file(GLOB_RECURSE absolute LIST_DIRECTORIES false "${BS_PREFIX}/*")
|
||||
foreach(path IN LISTS absolute)
|
||||
file(RELATIVE_PATH relative "${BS_PREFIX}" "${path}")
|
||||
list(APPEND found "${relative}")
|
||||
endforeach()
|
||||
endif()
|
||||
list(SORT found)
|
||||
set(${out_var} "${found}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# A readable excerpt of the install tree for failure messages.
|
||||
function(bs_installed_summary out_var)
|
||||
bs_installed_files(all)
|
||||
list(LENGTH all count)
|
||||
set(excerpt "${all}")
|
||||
if(count GREATER 20)
|
||||
list(SUBLIST excerpt 0 20 excerpt)
|
||||
list(APPEND excerpt "... and ${count} files in total")
|
||||
endif()
|
||||
string(REPLACE ";" "\n " excerpt "${excerpt}")
|
||||
set(${out_var} "${count} file(s) installed:\n ${excerpt}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(bs_matching_installed_files regex out_var)
|
||||
bs_installed_files(all)
|
||||
set(hits "")
|
||||
foreach(path IN LISTS all)
|
||||
if(path MATCHES "${regex}")
|
||||
list(APPEND hits "${path}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(${out_var} "${hits}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(bs_assert_installed regex what)
|
||||
bs_matching_installed_files("${regex}" hits)
|
||||
if(NOT hits)
|
||||
bs_installed_summary(summary)
|
||||
bs_fail("expected ${what} matching /${regex}/ in the install tree; ${summary}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(bs_assert_not_installed regex what)
|
||||
bs_matching_installed_files("${regex}" hits)
|
||||
if(hits)
|
||||
string(REPLACE ";" "\n " listing "${hits}")
|
||||
bs_fail("expected no ${what} in the install tree, found:\n ${listing}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Asserts the install tree holds nothing Eigen contributes: headers from the
|
||||
# supported and unsupported trees, the signature file, eigen3.pc, and the
|
||||
# CMake package files.
|
||||
function(bs_assert_no_eigen_installed)
|
||||
bs_assert_not_installed("/Eigen/Core$" "supported Eigen header")
|
||||
bs_assert_not_installed("/unsupported/Eigen/Tensor$" "unsupported Eigen header")
|
||||
bs_assert_not_installed("signature_of_eigen3_matrix_library$" "Eigen signature file")
|
||||
bs_assert_not_installed("eigen3\\.pc$" "eigen3.pc")
|
||||
bs_assert_not_installed("Eigen3Config\\.cmake$" "Eigen3 CMake package")
|
||||
bs_assert_not_installed("Eigen3Targets.*\\.cmake$" "Eigen3 CMake targets")
|
||||
endfunction()
|
||||
|
||||
# Asserts the install tree holds the headers a consumer needs.
|
||||
function(bs_assert_eigen_headers_installed)
|
||||
bs_assert_installed("/Eigen/Core$" "supported Eigen header")
|
||||
bs_assert_installed("/Eigen/Dense$" "Eigen/Dense umbrella")
|
||||
bs_assert_installed("/unsupported/Eigen/Tensor$" "unsupported Eigen header")
|
||||
bs_assert_installed("signature_of_eigen3_matrix_library$" "Eigen signature file")
|
||||
endfunction()
|
||||
|
||||
# The version Eigen3ConfigVersion.cmake will carry, read from the same header
|
||||
# the top-level CMakeLists parses. Deriving the version constraints a scenario
|
||||
# tests from this keeps them meaningful across a release bump instead of
|
||||
# pinning them to whatever version happened to be current.
|
||||
function(bs_eigen_package_version out_major out_minor out_patch)
|
||||
file(READ "${EIGEN_SOURCE_DIR}/Eigen/Version" header)
|
||||
foreach(component MAJOR MINOR PATCH)
|
||||
# Test the match itself, not CMAKE_MATCH_1: a legitimate component value of
|
||||
# 0 is false to if().
|
||||
string(REGEX MATCH "define[ \t]+EIGEN_${component}_VERSION[ \t]+([0-9]+)" matched "${header}")
|
||||
if(NOT matched)
|
||||
bs_fail("could not read EIGEN_${component}_VERSION from Eigen/Version")
|
||||
endif()
|
||||
set(value_${component} "${CMAKE_MATCH_1}")
|
||||
endforeach()
|
||||
set(${out_major} "${value_MAJOR}" PARENT_SCOPE)
|
||||
set(${out_minor} "${value_MINOR}" PARENT_SCOPE)
|
||||
set(${out_patch} "${value_PATCH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(bs_find_consumer_executable bin out_var)
|
||||
foreach(candidate
|
||||
"${bin}/consumer" "${bin}/consumer.exe"
|
||||
"${bin}/${BUILD_CONFIG}/consumer" "${bin}/${BUILD_CONFIG}/consumer.exe")
|
||||
if(EXISTS "${candidate}")
|
||||
set(${out_var} "${candidate}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
set(${out_var} "" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Builds a consumer project and runs it, failing unless it prints the marker
|
||||
# its source promises. Running it is what proves the headers a scenario
|
||||
# assembled are usable, not merely present.
|
||||
function(bs_build_and_run_consumer what bin)
|
||||
bs_build("${what}" "${bin}")
|
||||
bs_find_consumer_executable("${bin}" consumer_exe)
|
||||
if(NOT consumer_exe)
|
||||
bs_fail("${what}: built no consumer executable under ${bin}")
|
||||
endif()
|
||||
bs_run(WHAT "run ${what}" OUTPUT_VARIABLE output COMMAND "${consumer_exe}")
|
||||
if(NOT output MATCHES "eigen-ok")
|
||||
bs_fail("${what}: consumer ran but did not print its marker\n----\n${output}\n----")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(BS_SCENARIO_FILE "${CMAKE_CURRENT_LIST_DIR}/scenarios/${SCENARIO}.cmake")
|
||||
if(NOT EXISTS "${BS_SCENARIO_FILE}")
|
||||
message(FATAL_ERROR "no such scenario: ${BS_SCENARIO_FILE}")
|
||||
endif()
|
||||
include("${BS_SCENARIO_FILE}")
|
||||
@@ -0,0 +1,29 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# doc/TopicCMakeGuide.dox: Eigen can be embedded without installing it first,
|
||||
# applying the guide's "Disabling Eigen build options" snippet beforehand. The
|
||||
# consumer project sets exactly those options, so this covers both claims:
|
||||
# Eigen3::Eigen is usable from a sub-project, and an embedded Eigen contributes
|
||||
# nothing to the enclosing project's tests.
|
||||
|
||||
bs_configure("embedding consumer" "${BS_CONSUMER_DIR}/subproject" "${WORK_DIR}/consumer"
|
||||
"-DEIGEN_SOURCE_DIR=${EIGEN_SOURCE_DIR}")
|
||||
bs_build_and_run_consumer("embedding consumer" "${WORK_DIR}/consumer")
|
||||
|
||||
# Embedding Eigen must leave the enclosing project's test list alone: the
|
||||
# consumer registers one test of its own, and that must be all CTest reports.
|
||||
#
|
||||
# CTest gained --test-dir in CMake 3.20. On the 3.17 Eigen supports it is
|
||||
# accepted and ignored, leaving CTest to inspect its own working directory --
|
||||
# which is the outer Eigen build tree, whose tests would then be reported as
|
||||
# the consumer's. Select the consumer build directory by changing into it.
|
||||
bs_run(WHAT "list tests of the embedding consumer" OUTPUT_VARIABLE tests
|
||||
COMMAND ${CMAKE_COMMAND} -E chdir "${WORK_DIR}/consumer"
|
||||
${CMAKE_CTEST_COMMAND} -N)
|
||||
if(NOT tests MATCHES "consumer_runs")
|
||||
bs_fail("CTest did not inspect the consumer build directory\n----\n${tests}\n----")
|
||||
endif()
|
||||
if(NOT tests MATCHES "Total Tests: 1")
|
||||
bs_fail("embedding Eigen changed the enclosing project's test list:\n----\n${tests}\n----")
|
||||
endif()
|
||||
@@ -0,0 +1,23 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# doc/TopicCMakeGuide.dox: passing EXCLUDE_FROM_ALL to add_subdirectory "drops
|
||||
# Eigen's install rules". CMake documents this on the EXCLUDE_FROM_ALL
|
||||
# directory property rather than on add_subdirectory, and the wording only
|
||||
# appeared in recent releases, so the behavior is worth pinning at whatever
|
||||
# CMake version is running the suite.
|
||||
#
|
||||
# The guide's separate warning -- that FetchContent_Declare ignores the keyword
|
||||
# before CMake 3.28 -- cannot be checked here, because a scenario only ever has
|
||||
# the one CMake that launched it.
|
||||
|
||||
bs_configure("embedding consumer with EXCLUDE_FROM_ALL" "${BS_CONSUMER_DIR}/subproject"
|
||||
"${WORK_DIR}/consumer"
|
||||
"-DEIGEN_SOURCE_DIR=${EIGEN_SOURCE_DIR}"
|
||||
"-DCMAKE_INSTALL_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_USE_EXCLUDE_FROM_ALL=ON")
|
||||
bs_build_and_run_consumer("embedding consumer with EXCLUDE_FROM_ALL" "${WORK_DIR}/consumer")
|
||||
bs_install("embedding consumer with EXCLUDE_FROM_ALL" "${WORK_DIR}/consumer")
|
||||
|
||||
bs_assert_no_eigen_installed()
|
||||
bs_assert_installed("bin/consumer" "the consumer's own executable")
|
||||
@@ -0,0 +1,29 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# doc/TopicCMakeGuide.dox: an installed Eigen is consumed with
|
||||
# find_package(Eigen3 REQUIRED NO_MODULE) and target_link_libraries against
|
||||
# Eigen3::Eigen. Also pins what a default top-level install contains, since
|
||||
# every later scenario asserting an absence is only meaningful against it.
|
||||
|
||||
bs_install_eigen()
|
||||
|
||||
bs_assert_eigen_headers_installed()
|
||||
bs_assert_installed("Eigen3Config\\.cmake$" "Eigen3 CMake package")
|
||||
bs_assert_installed("Eigen3ConfigVersion\\.cmake$" "Eigen3 package version file")
|
||||
bs_assert_installed("Eigen3Targets\\.cmake$" "Eigen3 exported targets")
|
||||
bs_assert_installed("/Eigen/Version$" "generated Eigen/Version header")
|
||||
|
||||
# pkgconfig_off only asserts that eigen3.pc is absent, so without the positive
|
||||
# case here it would stay green even if pkg-config installation broke for every
|
||||
# configuration. EIGEN_BUILD_PKGCONFIG, and with it eigen3.pc, exists only
|
||||
# where the top-level CMakeLists offers the option.
|
||||
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
bs_assert_installed("eigen3\\.pc$" "eigen3.pc")
|
||||
endif()
|
||||
|
||||
bs_configure("consumer" "${BS_CONSUMER_DIR}/installed" "${WORK_DIR}/consumer"
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
bs_build_and_run_consumer("consumer" "${WORK_DIR}/consumer")
|
||||
@@ -0,0 +1,54 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# doc/TopicCMakeGuide.dox: "we also support a range spanning major versions",
|
||||
# spelled find_package(Eigen3 3.4...5 REQUIRED NO_MODULE). The claim rests on
|
||||
# the hand-written cmake/Eigen3ConfigVersion.cmake.in, whose inclusive upper
|
||||
# bound admits everything below <max>+1, so the range has to be exercised
|
||||
# against a real installed package rather than reasoned about.
|
||||
#
|
||||
# The upper bound is taken from Eigen's own major version, which is what makes
|
||||
# the documented "3.4...5" span the current release; writing 5 here instead
|
||||
# would turn this into a failing test the day Eigen 6 ships.
|
||||
#
|
||||
# test/buildsystem/CMakeLists.txt registers this scenario only for CMake 3.19
|
||||
# and newer, which is where find_package learned range syntax.
|
||||
|
||||
bs_install_eigen()
|
||||
bs_eigen_package_version(major minor patch)
|
||||
|
||||
bs_configure("consumer with range 3.4...${major}" "${BS_CONSUMER_DIR}/installed"
|
||||
"${WORK_DIR}/consumer"
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_VERSION_SPEC=3.4...${major}"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
bs_build_and_run_consumer("consumer with a version range" "${WORK_DIR}/consumer")
|
||||
|
||||
# An in-range success alone would also be produced by a range branch that
|
||||
# accepted every range, and find_package_version_reject cannot catch that: it
|
||||
# only reaches the non-range branch. Bracket the installed version instead, so
|
||||
# a bound that stops being enforced fails here.
|
||||
math(EXPR above_major "${major}+1")
|
||||
math(EXPR above_major_end "${major}+2")
|
||||
bs_configure_expect_failure("consumer with range ${above_major}...${above_major_end}"
|
||||
"${BS_CONSUMER_DIR}/installed" "${WORK_DIR}/consumer-above" output
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_VERSION_SPEC=${above_major}...${above_major_end}"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
if(NOT output MATCHES "Eigen3")
|
||||
bs_fail("configure failed for some reason other than the version check\n----\n${output}\n----")
|
||||
endif()
|
||||
|
||||
# "...<" is the exclusive upper bound, so this range stops just below the
|
||||
# installed major and must not match it.
|
||||
bs_configure_expect_failure("consumer with range 1...<${major}"
|
||||
"${BS_CONSUMER_DIR}/installed" "${WORK_DIR}/consumer-below" output
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_VERSION_SPEC=1...<${major}"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
if(NOT output MATCHES "Eigen3")
|
||||
bs_fail("configure failed for some reason other than the version check\n----\n${output}\n----")
|
||||
endif()
|
||||
@@ -0,0 +1,71 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# The complement of find_package_version_range: without a rejection case, a
|
||||
# version file that accepted everything would pass that test.
|
||||
#
|
||||
# The non-range branch of cmake/Eigen3ConfigVersion.cmake.in accepts a package
|
||||
# whose version is at least the requested one and below the next major, so a
|
||||
# bare "3.4" spans >=3.4 to <4.0.0 rather than 3.4.z. Rejecting a request one
|
||||
# major above the installed package would hold under either reading, so the
|
||||
# cases below pin the implemented one: both bounds, plus -- whenever the
|
||||
# installed version leaves room to state it -- a minor below the installed one
|
||||
# that must still be accepted.
|
||||
|
||||
bs_install_eigen()
|
||||
bs_eigen_package_version(major minor patch)
|
||||
|
||||
if(major LESS 4)
|
||||
bs_fail("this scenario assumes Eigen's major version is at least 4, got ${major}")
|
||||
endif()
|
||||
|
||||
# Upper bound: an earlier major must not answer, whatever its minor.
|
||||
bs_configure_expect_failure("consumer pinned to 3.4" "${BS_CONSUMER_DIR}/installed"
|
||||
"${WORK_DIR}/consumer-old" output
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_VERSION_SPEC=3.4"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
if(NOT output MATCHES "Eigen3")
|
||||
bs_fail("configure failed for some reason other than the version check\n----\n${output}\n----")
|
||||
endif()
|
||||
|
||||
math(EXPR too_new "${major}+1")
|
||||
bs_configure_expect_failure("consumer requiring ${too_new}" "${BS_CONSUMER_DIR}/installed"
|
||||
"${WORK_DIR}/consumer-new" output
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_VERSION_SPEC=${too_new}"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
if(NOT output MATCHES "Eigen3")
|
||||
bs_fail("configure failed for some reason other than the version check\n----\n${output}\n----")
|
||||
endif()
|
||||
|
||||
# Lower bound: a patch above the installed one is inside the same major and must
|
||||
# still be rejected, which a file that only compared majors would not do.
|
||||
math(EXPR next_patch "${patch}+1")
|
||||
bs_configure_expect_failure("consumer requiring ${major}.${minor}.${next_patch}"
|
||||
"${BS_CONSUMER_DIR}/installed"
|
||||
"${WORK_DIR}/consumer-patch" output
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_VERSION_SPEC=${major}.${minor}.${next_patch}"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
if(NOT output MATCHES "Eigen3")
|
||||
bs_fail("configure failed for some reason other than the version check\n----\n${output}\n----")
|
||||
endif()
|
||||
|
||||
# The case that separates ">=X.Y, <X+1.0.0" from "X.Y.z": an older minor of the
|
||||
# installed major must be accepted. Only statable once the release series has
|
||||
# moved past .0, so it is a control the scenario adds when it can rather than a
|
||||
# requirement on the version number.
|
||||
if(minor GREATER 0)
|
||||
math(EXPR previous_minor "${minor}-1")
|
||||
bs_configure("consumer requiring ${major}.${previous_minor}" "${BS_CONSUMER_DIR}/installed"
|
||||
"${WORK_DIR}/consumer-minor"
|
||||
"-DCMAKE_PREFIX_PATH=${BS_PREFIX}"
|
||||
"-DEIGEN_EXPECTED_PREFIX=${BS_PREFIX}"
|
||||
"-DEIGEN_VERSION_SPEC=${major}.${previous_minor}"
|
||||
${BS_FIND_PACKAGE_ISOLATION})
|
||||
bs_build_and_run_consumer("consumer requiring an older minor" "${WORK_DIR}/consumer-minor")
|
||||
endif()
|
||||
@@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# doc/TopicCMakeGuide.dox: "Eigen's install rules are enabled even when it is
|
||||
# built as a sub-project." This is the baseline that makes exclude_from_all
|
||||
# meaningful -- without it, a build that installed nothing at all would satisfy
|
||||
# that scenario too.
|
||||
|
||||
bs_configure("embedding consumer" "${BS_CONSUMER_DIR}/subproject" "${WORK_DIR}/consumer"
|
||||
"-DEIGEN_SOURCE_DIR=${EIGEN_SOURCE_DIR}"
|
||||
"-DCMAKE_INSTALL_PREFIX=${BS_PREFIX}")
|
||||
bs_build("embedding consumer" "${WORK_DIR}/consumer")
|
||||
bs_install("embedding consumer" "${WORK_DIR}/consumer")
|
||||
|
||||
bs_assert_eigen_headers_installed()
|
||||
bs_assert_installed("bin/consumer" "the consumer's own executable")
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: The Eigen Authors
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# doc/TopicCMakeGuide.dox lists EIGEN_BUILD_PKGCONFIG among the options an
|
||||
# embedding project turns off. find_package already pins that a default
|
||||
# top-level install ships eigen3.pc, so this pins that the option suppresses
|
||||
# it, and that the headers are unaffected either way.
|
||||
|
||||
bs_install_eigen(-DEIGEN_BUILD_PKGCONFIG=OFF)
|
||||
|
||||
bs_assert_not_installed("eigen3\\.pc$" "eigen3.pc")
|
||||
bs_assert_eigen_headers_installed()
|
||||
Reference in New Issue
Block a user