Why don't you need to do target_link_libraries when using Eigen with pybind11

Question:

I was trying to compile this example.cpp from a pybind11 tutorial called pybind11_examples on GitHub

#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>

#include <Eigen/LU>
#include <iostream>

// ----------------
// regular C++ code
// ----------------

Eigen::MatrixXd mul(const Eigen::MatrixXd &xs, double fac)
{
    std::cout << "Double" << std::endl;
    return fac*xs;
}

Eigen::MatrixXi mul(const Eigen::MatrixXi &xs, int    fac)
{
    std::cout << "Int" << std::endl;
    return fac*xs;
}

// ----------------
// Python interface
// ----------------

namespace py = pybind11;

PYBIND11_MODULE(example,m)
{
  m.doc() = "pybind11 example plugin";

  // N.B. the order here is crucial, in the reversed order every "int" is converted to a "double"
  m.def("mul", py::overload_cast<const Eigen::MatrixXi &,int   >(&mul) );
  m.def("mul", py::overload_cast<const Eigen::MatrixXd &,double>(&mul) );
}

and the corresponding CMakeLists.txt file is

cmake_minimum_required(VERSION 2.8.12)
project(example)

set (CMAKE_CXX_STANDARD 14)

find_package( PkgConfig )
pkg_check_modules( EIGEN3 REQUIRED eigen3 )
include_directories( ${EIGEN3_INCLUDE_DIRS} )

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

One confusion I have is why do we not need to link Eigen with example. Is it because Eigen is a header-only library so include_directories is enough? Then what should I do for non-header-only libraries?

Thanks in advance!

Asked By: QualsPassed

||

Answers:

EDIT: To answer your question regarding what to do with non-header-only libraries:

Pybind11’s pybind11_add_module works the same way as CMakes add_executable or add_library it defines a target (first argument) that you can then link against. In your case:

#Rest of the CMakeLists.txt...

pybind11_add_module(example example.cpp)

target_link_libraries(example my_library)

#Rest of the CMakeLists.txt...

As was already posted by @user253751 in the comments. Eigen is a header only library. You can see for yourself on their homepage:

Requirements


Eigen doesn’t have any dependencies other than the C++ standard library.

We use the CMake build system, but only to build the documentation and unit-tests, and to automate installation. If you just want to use Eigen, you can use the header files right away. There is no binary library to link to, and no configured header file. Eigen is a pure template library defined in the headers.

Answered By: Milan Š.

More on the target_link_library problem, I tried the following CMakeLists.txt

cmake_minimum_required(VERSION 2.8.12)
project(example)

set (CMAKE_CXX_STANDARD 14)

find_package(Eigen3 3.3)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)
target_link_libraries(example Eigen3::Eigen)

And it gives me the following error:

CMake Error at CMakeLists.txt:14 (target_link_libraries):
  The keyword signature for target_link_libraries has already been used with
  the target "example".  All uses of target_link_libraries with a target must
  be either all-keyword or all-plain.

  The uses of the keyword signature are here:

   * pybind11/tools/pybind11Tools.cmake:179 (target_link_libraries)
   * pybind11/tools/pybind11Tools.cmake:211 (target_link_libraries)

This is because the two lines mentioned above are calling target_link_libraries as

179: target_link_libraries(${target_name} PRIVATE pybind11::module)
211: target_link_libraries(${target_name} PRIVATE pybind11::lto)

This causes an error because, as mentioned in the error message:

all uses of target_link_libraries with a target must be either all-keyword or all-plain.

all-keyword refers to including PRIVATE|PUBLIC|INTERFACE in the target_link_libraries call as in the above two lines.

all-plain refers to not including PRIVATE|PUBLIC|INTERFACE in the target_link_libraries command, for example:

target_link_libraries(example Eigen3::Eigen)

We must pick one of the above ways to use the target_link_libraries command within a single CMakeLists.txt file. Since pybind11 made that choice for us using a keyword call, we must also do the same. So if we use

target_link_libraries(example PRIVATE Eigen3::Eigen)

it will successfully compile. If we use PUBLIC instead of PRIVATE, it will also successfully compile.

Answered By: QualsPassed
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.