org-howto/articles/2023/10/inconsistent-eigen-package.org
Roland Conybeare 3b66752c5c
All checks were successful
Deploy / publish (push) Successful in 14s
bugfix: fix broken forgejo links
2026-06-18 08:32:16 -04:00

158 lines
5.2 KiB
Org Mode

#+title: [2023] inconsistent eigen package
# ----------------------------------------------------------------
#+tags: @eigen @cmake
# ----------------------------------------------------------------
#+description: inconsistent eigen package
#
# org-publish options
#
# ^:{} require a_{b} before assuming that b should be subscripted.
# without this option a_b will automatically subscript b.
#+options: ^:{}
#
# emacs-specific options
#+startup: showall
#
# html exporter options
#+language: en
#+keywords: c++ gcc preprocessor
#+setupfile: ../../../ext/fniessen/theme-readtheorg.setup
#
#+html_head: <link rel="shortcut icon" type="image/x-icon" href="/web/img/favicon.ico" />
#+html_link_home: ../../../index.html
#
# not using: prefer theme-readtheorg
# +infojs_opt: view:showall mouse:#ffc0c0 toc:nil ltoc:nil path:/web/ext/orginfo/org-info.js
# +html_head: <link rel="stylesheet" type="text/css" href="/web/css/primary.css" />
* TL;DR
Eigen cmake support seems to be inconsistent
* Setup
- library [[https://conybeare.us/git/roland/xo-kalmanfilter][xo-kalmanfilter]] depends on eigen
- library [[https://conybeare.us/git/roland/xo-pykalmanfilter][xo-pykalmanfilter]] depends on =xo-kalmanfilter=
- the project [[https://conybeare.us/git/roland/xo-umbrella2][xo-umbrella2]] incorporates both codebases (along with others) into a single source tree
(using git subrepo).
- alternatively, can build+install libraries independently (in bottom-up dependency order),
We call this last a 'vanilla build', since it follows standard practice for installing 3rd-party libraries.
In a so-called vanilla build, we use cmake's =find_package()= support to acquire each dependency.
In a vanilla build, When cmake builds a library, it obtains its dependencies from their final install location.
Contrast this with the submodule build: here, when cmake build a library, it obtains its dependencies from the build tree
* Problem
- submodule build works as expected; compile flags include required =-Ipath/to/eigen/eigen3=,
so c++ code like this compiles
#+begin_src c++
#include <Eigen/Dense>
#+end_src
- vanilla build fails:
when compiling xo-pykalmanfilter, the header path for eigen is given as =-Ipath/to/eigen=
instead of =-Ipath/to/eigen/eigen3=, so now need this to compile instead:
#+begin_src c++
#include <eigen3/Eigen/Dense>
#+end_src
* Details
- =xo-kalmanfilter= specifies eigen dependency in the approved manner:
#+begin_src cmake
# xo-kalmanfilter/src/kalmanfilter/CMakeLists.txt
set(SELF_LIB xo_kalmanfilter)
..
xo_external_target_dependency(${SELF_LIB} Eigen3 Eigen3::Eigen)
#+end_src
which expands as if we had written:
#+begin_src cmake
find_package(Eigen3 CONFIG REQUIRED)
target_link_libraries(${SELF_LIB} PUBLIC Eigen3::Eigen)
#+end_src
This works as expected in submodule build.
In submodule build, codebases =xo-kalmanfilter= and =xo-pykalmanfilter= (amongst others) are incorporated
into a single source tree:
#+begin_src cmake
# xo-sm2/CMakeLists.txt
set(XO_SUBMODULE_BUILD True)
..
add_subdirectory(repo/xo-kalmanfilter)
add_subdirectory(repo/xo-pykalmanfilter)
#+end_src
- =xo-pykalmanfilter= specifies =xo-kalmanfilter= dependency:
#+begin_src cmake
# xo-pykalmanfilter/src/pykalmanfilter/CMakeLists.txt
set(SELF_LIB pykalmanfilter)
..
xo_pybind11_dependency(${SELF_LIB} xo_kalmanfilter)
#+end_src
which expands differently, depending on build type.
In submodule build, as if we had written:
#+begin_src cmake
target_include_directories(${SELF_LIB} PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/repo/xo_kalmanfilter/include>)
target_include_directories(${SELF_LIB} PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/repo/xo_kalmanfilter/include>)
target_link_libraries(${SELF_LIB} PUBLIC xo_kalmanfilter)
#+end_src
In vanilla build, =xo_pybind11_dependency()= expands differently:
#+begin_src cmake
find_package(xo_kalmanfilter CONFIG REQUIRED)
..
target_link_libraries(${SELF_LIB} PUBLIC xo_kalmanfilter)
#+end_src
- =xo-kalmanfilter= provides support for cmake =find_package()=:
#+begin_src cmake
# xo-kalmanfilter/cmake/xo_kalmanfilterConfig.cmake.in
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(reactor)
find_dependency(eigen3)
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components("@PROJECT_NAME@")
#+end_src
and generated =xo_kalmanfilterTargets.cmake= file contains:
#+begin_src cmake
# Create imported target xo_kalmanfilter
add_library(xo_kalmanfilter SHARED IMPORTED)
set_target_properties(xo_kalmanfilter PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;${_IMPORT_PREFIX}/include/xo/kalmanfilter"
INTERFACE_LINK_LIBRARIES "reactor;Eigen3::Eigen"
)
#+end_src
which.. doesn't look wrong :)
Evidence points to an inconsistency in Eigen-provided cmake support, if not in cmake proper.
* Workaround
It's sufficient to restate the eigen dependency in =xo-pykalmanfilter=:
#+begin_src cmake
# xo_pykalmanfilter/src/pykalmanfilter/CMakeLists.txt
set(SELF_LIB pykalmanfilter)
...
xo_external_target_dependency(${SELF_LIB} Eigen3 Eigen3::Eigen)
#+end_src