Project

General

Profile

Support #23576

Issue with Clang while linking: undefined reference to `std::__1::optional<double>::optional()'

Added by Gianluca Petrillo about 1 month ago. Updated 9 days ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Install / build / code mgmt
Target version:
-
Start date:
11/11/2019
Due date:
% Done:

100%

Estimated time:
Spent time:
Experiment:
DUNE
Co-Assignees:
Duration:

Description

When compiling my own branch feature/gp_wirelessGeometry of larcorealg with Clang 5 (c2 qualifiers) I get a linking error:

[ 66%] Linking CXX shared library ../../lib/liblarcorealg_Geometry.so
CMakeFiles/larcorealg_Geometry.dir/PixelPlane/PixelPlaneGeo.cxx.o: In function `geo::PixelPlaneGeo::PixelPlaneGeo(TGeoNode const&, ROOT::Math::Impl::Transform3D<double>&&, std::__1::basic_regex<char, std::__1::regex_traits<char> > const&)':
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<double>, geo::PlaneGeo::PlaneGeoCoordinatesTag> >::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<unsigned int>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<double>, geo::PlaneGeo::PlaneGeoCoordinatesTag> >::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<unsigned int>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
CMakeFiles/larcorealg_Geometry.dir/PixelPlane/PixelPlaneGeo.cxx.o: In function `geo::PixelPlaneGeo::PixelPlaneGeo(TGeoNode const&, ROOT::Math::Impl::Transform3D<double>&&, std::__1::basic_regex<char, std::__1::regex_traits<char> > const&)':
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<double>, geo::PlaneGeo::PlaneGeoCoordinatesTag> >::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<unsigned int>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<double>, geo::PlaneGeo::PlaneGeoCoordinatesTag> >::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<unsigned int>::optional()'
/dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof/srcs/larcorealg/larcorealg/Geometry/PixelPlane/PixelPlaneGeo.cxx:42: undefined reference to `std::__1::optional<double>::optional()'
/usr/bin/ld: ../../lib/liblarcorealg_Geometry.so: hidden symbol `_ZNSt3__18optionalIjEC1Ev' isn't defined
/usr/bin/ld: final link failed: Nonrepresentable section on output
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [larcorealg/lib/liblarcorealg_Geometry.so] Error 1

This happens with both GNU make and ninja, both prof and debug, only with Clang (c2), not with GCC (e17); compiling that repository only, and compiling more repositories together with that one.
This one was from the compilation of the working area at /dune/app/users/petrillo/LArSoft/projects/PixelGeo/test/c2_prof

Associated revisions

Revision 6c71e8c3 (diff)
Added by Gianluca Petrillo 21 days ago

Fixed linking problem in Clang.

See LArSoft issue #23576.

History

#1 Updated by Kyle Knoepfel 25 days ago

  • Assignee set to Kyle Knoepfel
  • Status changed from New to Assigned

#2 Updated by Kyle Knoepfel 24 days ago

Link failure confirmed on SL7.

#3 Updated by Kyle Knoepfel 24 days ago

  • Status changed from Assigned to Resolved

This is a tricky problem, but I believe I have some sense of what is going on. The relevant struct in this case is:

struct AxisInfo_t {
  /// Direction of this side in local (GDML) plane coordinates;                                                                                                                                                                                                           
  /// modulus is ignored.                                                                                                                                                                                                                                                 
  std::optional<LocalVector_t> dir;
  /// Length of the area covered by pixel along this direction [cm]                                                                                                                                                                                                       
  std::optional<double> length;
  std::optional<unsigned int> nPixels; ///< Number of pixels.                                                                                                                                                                                                             
  /// Size of the side of each pixel (i.e. the pitch) [cm]                                                                                                                                                                                                                
  std::optional<double> pitch;

  /// Returns whether *all* the information is set.                                                                                                                                                                                                                       
  bool isComplete() const;

  /// Removes all information, reverting it to unset.                                                                                                                                                                                                                     
  void clear();
};

In this case, the compiler implicitly declares a default constructor (as mentioned here). On that same webpage, we see the following statement regarding implicit definitions of default constructors.

If the implicitly-declared default constructor is not defined as deleted, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used, and it has exactly the same effect as a user-defined constructor with empty body and empty initializer list. That is, it calls the default constructors of the bases and of the non-static members of this class.

If you click on the link regarding odr usage (emphasis mine), you read:

Informally, an object is odr-used if its value is read (unless it is a compile time constant) or written, its address is taken, or a reference is bound to it; a reference is odr-used if it is used and its referent is not known at compile time; and a function is odr-used if a function call to it is made or its address is taken. If an object, a reference or a function is odr-used, its definition must exist somewhere in the program; a violation of that is usually a link-time error.

In my perusal of the code, I have not found any place where the constructor of AxisInfo_t is actually called. In that case, the constructor is not odr-used, and the compiler is thus free to suppress the definition of the member data constructors (i.e. std::optional<double>::optional()), even if the compiler implicitly declared them. I thus believe that Clang was giving you an accurate error report and GCC was more permissive.

I have found two solutions to this problem thus far, but I would like to do some more analysis before I recommend any particular approach.

#4 Updated by Kyle Knoepfel 24 days ago

  • Status changed from Resolved to Assigned

#5 Updated by Kyle Knoepfel 23 days ago

  • Status changed from Assigned to Resolved

I've done some more digging--you will have this issue with c7 as well. There are two ways to solve this problem. Please let us know if the solutions below are insufficient.

Avoid default arguments of RectPixelGeometry_t{} (recommended)

You'll find that if you make the following changes you will avoid the linking error.

# Remove default arguments
- static RectPixelGeometry_t ReadPixelGeometryFromMetadata(
-   TGeoNode const& startNode, RectPixelGeometry_t const& geo = RectPixelGeometry_t{})
-
- static RectPixelGeometry_t ExtractPixelGeometry(
-    TGeoNode const& startNode, std::regex const& pixelNamePattern,
-    RectPixelGeometry_t const& startValues = RectPixelGeometry_t{})

# Create forwarding functions
+ static RectPixelGeometry_t ReadPixelGeometryFromMetadata(TGeoNode const& startNode)
+ {
+   return ReadPixelGeometryFromMetadata(startNode, RectPixelGeometry_t{});
+ }
+ static RectPixelGeometry_t ReadPixelGeometryFromMetadata(TGeoNode const& startNode, 
+   TGeoNode const& startNode, RectPixelGeometry_t const& geo);
+
+ static RectPixelGeometry_t ExtractPixelGeometry(
+   TGeoNode const& startNode, std::regex const& pixelNamePattern)
+ {
+   return ExtractPixelGeometry(startNode, pixelNamePattern, RectPixelGeometry_t{});
+ }
+ static RectPixelGeometry_t ExtractPixelGeometry(
+   TGeoNode const& startNode, std::regex const& pixelNamePattern,
+   RectPixelGeometry_t const& startValues);

Provide a user-defined default constructor for AxisInfo_t

Another possibility is to provide a user-defined constructor.

struct AxisInfo_t {

  AxisInfo_t(); // User-defined constructor

  /// Direction of this side in local (GDML) plane coordinates;                                                                                                                                                                                                           
  /// modulus is ignored.                                                                                                                                                                                                                                                 
  std::optional<LocalVector_t> dir;
  /// Length of the area covered by pixel along this direction [cm]                                                                                                                                                                                                       
  std::optional<double> length;
  std::optional<unsigned int> nPixels; ///< Number of pixels.                                                                                                                                                                                                             
  /// Size of the side of each pixel (i.e. the pitch) [cm]                                                                                                                                                                                                                
  std::optional<double> pitch;

  /// Returns whether *all* the information is set.                                                                                                                                                                                                                       
  bool isComplete() const;

  /// Removes all information, reverting it to unset.                                                                                                                                                                                                                     
  void clear();
};

And then outside of the class definition, probably in the cc file, define the constructor:

RectPixelGeometry_t::AxisInfo_t::AxisInfo_t() = default;

Minimal example

Please see the minimal examples at https://godbolt.org/z/bAsUzr. GCC and MSVC support your original code, and Clang 8 also supports it.

#6 Updated by Kyle Knoepfel 23 days ago

  • % Done changed from 0 to 100

#7 Updated by Kyle Knoepfel 18 days ago

  • Status changed from Resolved to Feedback

Gianluca, can we close this issue?

#8 Updated by Kyle Knoepfel 11 days ago

Gianluca, can we close this issue?

#9 Updated by Gianluca Petrillo 11 days ago

My answer fell in the void.
I happily adopted the recommended solution, and I thank you for the support.
Case closed, as far as I am concerned.

#10 Updated by Kyle Knoepfel 9 days ago

  • Status changed from Feedback to Closed


Also available in: Atom PDF