New user self-registration is currently disabled. Please email eigen-core-team @ lists.tuxfamily.org if you need an account.
Bug 1213 - GCC undefined reference link error caused by anonymous enum values in default Matrix template options argument
GCC undefined reference link error caused by anonymous enum values in default...
Status: RESOLVED FIXED
Product: Eigen
Classification: Unclassified
Component: Core - general
3.2
All All
: High Unit Test Required
Assigned To: Nobody
:
Depends on:
Blocks: 3.3
  Show dependency treegraph
 
Reported: 2016-04-27 14:38 UTC by D Kessler
Modified: 2016-05-18 12:04 UTC (History)
3 users (show)



Attachments
Source and Makefile demonstrating linker error using GCC 4.8.2 (1.31 KB, application/x-gzip)
2016-04-27 14:38 UTC, D Kessler
no flags Details
Give enums a name (3.76 KB, patch)
2016-05-06 09:37 UTC, Christoph Hertzberg
no flags Details | Diff

Description D Kessler 2016-04-27 14:38:31 UTC
Created attachment 701 [details]
Source and Makefile demonstrating linker error using GCC 4.8.2

Not sure if this is a bug in GCC or a difference in interpretation of the C++ standard, but we've run into a tricky link error when using the Eigen Matrix class in a templated function defined in a library that is used by another library. The attached code demonstrates the problem, which occurs with GCC 4.2.8 on an Ubuntu Linux system, although it appears to be the same problem as discussed on http://stackoverflow.com/questions/24730981/undefined-reference-error-from-gcc-using-a-template-with-a-stdvector-and-an-ei

The specific error, for the attached example, is:

./libitest.a(testilib.o): In function `TriangulateIt(std::vector<Eigen::Matrix<float, 3, 1, 0, 3, 1>, std::allocator<Eigen::Matrix<float, 3, 1, 0, 3, 1> > > const&)':
testilib.cpp:(.text+0x14): undefined reference to `bool TriangulatePolygon<float, 3>(std::vector<Eigen::Matrix<float, 3, 1, ((Eigen::._86)0)|((((3)==(1))&&((1)!=(1)))?((Eigen::._86)1) : ((((1)==(1))&&((3)!=(1)))?((Eigen::._86)0) : ((Eigen::._86)0))), 3, 1>, std::allocator<Eigen::Matrix<float, 3, 1, ((Eigen::._86)0)|((((3)==(1))&&((1)!=(1)))?((Eigen::._86)1) : ((((1)==(1))&&((3)!=(1)))?((Eigen::._86)0) : ((Eigen::._86)0))), 3, 1> > > const&)'

The issue seems to be the use of anonymous enum values in the expression defining the default value for the options parameter of the Matrix template, and that GCC is not fully evaluating the expression before storing the template function signature in a library. Further, the type name generated for anonymous enums ("Eigen::._86" in the error above) appears to use a counter, which can be different for different compilation units (in the example provided, the type name is different for the testlib and testilib libraries, where the function definition is in the testlib library and is being referenced by the testilib library).

One solution is to explicitly provide a value for the fourth, "options" template argument of the Matrix class, as in this example from the attached files:

#define VecDT_  Eigen::Matrix<T,dim,1,0>

Another solution that appears to work is to provide a name for the anonymous enum involved, defined in Constants.h. For example (adding "MatrixOptionsType"):

/** \ingroup enums
  * Enum containing possible values for the \p _Options template parameter of
  * Matrix, Array and BandMatrix. */
enum MatrixOptionsType {
  /** Storage order is column major (see \ref TopicStorageOrders). */
  ColMajor = 0,
  /** Storage order is row major (see \ref TopicStorageOrders). */
  RowMajor = 0x1,  // it is only a coincidence that this is equal to RowMajorBit -- don't rely on that
  /** Align the matrix itself if it is vectorizable fixed-size */
  AutoAlign = 0,
  /** Don't require alignment for the matrix itself (the array of coefficients, if dynamically allocated, may still be requested to be aligned) */ // FIXME --- clarify the situation
  DontAlign = 0x2
};

I haven't worked with the interior of the Eigen code to know if this is a reasonable solution, or if the burden should be on the user of the Eigen library to avoid the GCC issue by explicitly giving a value for the Matrix options template parameter.

Note that a colleague has reported to me that the problem still occurs in Eigen 3.3beta1, but that it doesn't occur unless the code is compiled with the -march=native.
Comment 1 Christoph Hertzberg 2016-04-28 09:58:35 UTC
I can confirm this.

We could solve this issue by declaring
  ColMajor, RowMajor, AutoAlign, DontAlign
as static const int, instead of as enum. (We'll probably need to do the same for other constants)

I'm not sure if this breaks anything.

Somewhat related (but not quite the same) are Bug 1207 and this discussion:
http://thread.gmane.org/gmane.comp.lib.eigen/4960
Comment 2 Christoph Hertzberg 2016-04-28 10:08:58 UTC
For the record: I tested with g++-4.8.4 (which has the issue) and with clang++-3.6 (which apparently does not have it).

And as you stated, giving the enum a name also solves the issue.
Comment 3 D Kessler 2016-04-28 13:34:44 UTC
Thanks.

From an outsider's perspective, it seems that giving the enum a name is the least disruptive solution noted so far, but I'm sure I'm not aware of all of the internal issues involved.

In your opinion, is this actually a bug in GCC? Should I be submitting a bug report with that group?
Comment 4 Gael Guennebaud 2016-05-04 11:14:38 UTC
I would also go for naming the enum.
Comment 5 Christoph Hertzberg 2016-05-06 09:37:58 UTC
Created attachment 703 [details]
Give enums a name

Attached is a suggestion for naming the currently unnamed enums. Any objections or other/better suggestions? 
Once we name them, the names will likely stay for a while.
Comment 6 Christoph Hertzberg 2016-05-11 17:30:27 UTC
I pushed it here:
https://bitbucket.org/eigen/eigen/commits/3a39911ae75

As long as 3.3 is not released feel free to change the naming.
We should still write a unit test and consider backporting to 3.2
Comment 8 Gael Guennebaud 2016-05-18 12:04:14 UTC
Add regression unit test: https://bitbucket.org/eigen/eigen/commits/c432bf8301a3

Note You need to log in before you can comment on or make changes to this bug.