[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

How to build compatible packages that use Eigen?



Hi. I'm packaging something that uses Eigen, and I'm running into a
persistent compatibility issue I don't currently know how to solve. Help
appreciated.

Here's the problem. Eigen is a C++ header-only library that's heavy into
templating. So all the functions inside Eigen produce weak symbols, and
usually the linker will see many identical copies of the same weak
symbol, from each compile unit and shared object being linked. The
linker picks ONE of the weak definitions. This is the intended behavior
in C++ because every copy is supposed to be identical. But in Eigen
they're not identical: it does different things based on preprocessor
defines, and you get crashes.

Here's a simplified illustration of what happens.


eigen3/Eigen/src/Core/util/Memory.h contains:

  EIGEN_DEVICE_FUNC inline void* aligned_malloc(std::size_t size)
  {
    check_that_malloc_is_allowed();

    void *result;
    #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED

      EIGEN_USING_STD(malloc)
      result = malloc(size);

      #if EIGEN_DEFAULT_ALIGN_BYTES==16
      eigen_assert((size<16 || (std::size_t(result)%16)==0) && "System's malloc returned an unaligned pointer. Compile with EIGEN_MALLOC_ALREADY_ALIGNED=0 to fallback to handmade aligned memory allocator.");
      #endif
    #else
      result = handmade_aligned_malloc(size);
    #endif

    if(!result && size)
      throw_std_bad_alloc();

    return result;
  }

  EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr)
  {
    #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED

      EIGEN_USING_STD(free)
      free(ptr);

    #else
      handmade_aligned_free(ptr);
    #endif
  }

The EIGEN_DEFAULT_ALIGN_BYTES and EIGEN_MALLOC_ALREADY_ALIGNED macros
can vary based on things like __SSE__ and __AVX__ and such.

Now let's say you're packaging a library. Let's call it libg2o. This is
NOT header-only, and somewhere it does #include <Eigen/....> which
eventually includes Memory.h. The libg2o.so that ends up in the
"libg2o0" package then gets a weak symbol for "aligned_malloc" and
"aligned_free" that encodes the compiler flags that were used when
building libg2o.so.

So far so good.

Now let's say you have a user. They're writing a program that uses both
libg2o and Eigen. They're writing their own application, not intended to
go into Debian. So they build with -msse -mavx and all the other fun
stuff. THEIR weak copies of "aligned_malloc" and "aligned_free" are
different and incompatible with the copies in libg2o. And the
application is then likely to crash because at least something somewhere
will be allocated with one copy and deallocated with another.

This is just terrible design from the eigen and c++ people, but that's
what we have. Has anybody here run into this? How does one build the
libg2o package so that users don't crash their application when using
it? I tried to demand maximum alignment in libg2o, which fixes some
things but not all. Currently debugging to find a better solution, but I
suspect somebody has already fought this.

Thanks


Reply to: