Summary: | Build error with clang: undefined reference to `sigrok::EnumValue<sigrok::LogLevel, sr_loglevel>::_values' | ||
---|---|---|---|
Product: | PulseView | Reporter: | Uwe Hermann <uwe> |
Component: | Other | Assignee: | Nobody <nobody> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | martin-sigrokbugs, uffe |
Priority: | Normal | ||
Version: | unreleased development snapshot | ||
Target Milestone: | --- | ||
Hardware: | All | ||
OS: | All | ||
Attachments: | libsigrok-bindings-cxx-enums-cpp.patch |
Description
Uwe Hermann
2015-01-03 23:41:54 CET
Hi, Follow up: regarding the pulseview link problems using clang/clang++ The problem seems to be related to the use of option -fvisibility=hidden and the "SR_API" visibility attributes. The problem seems to occour because of references from outside the libsigrokxx library to some of the classes (inside libsigrokxx) that use static initialization through explicit template specialization. Modifying the autogenerated bindings/cxx/enums.cpp by hand (see diff below) - adding "SR_API" to the explicit template specialization fixes the problem and pulseview is able to compile,link and execute. One problem is that bindings/cxx/enums.cpp is autogenerated. The puzzle, that I'm too tired to solve right now, is why the problem only relates to classes "LogLevel" and "TriggerMatchType" ? There are lots of other classes based on the EnumValue template that does not have this problem - and they all use the same approach for (static) initialization through explicit template specialization... I need to sleep now /Uffe --- bindings/cxx/enums.cpp.orig 2015-01-04 06:11:07.623170506 +0100 +++ bindings/cxx/enums.cpp 2015-01-04 06:11:47.577080031 +0100 @@ -11,7 +11,7 @@ const LogLevel * const LogLevel::INFO = &LogLevel::_INFO; const LogLevel * const LogLevel::DBG = &LogLevel::_DBG; const LogLevel * const LogLevel::SPEW = &LogLevel::_SPEW; -template<> const std::map<const enum sr_loglevel, const LogLevel * const> EnumValue<LogLevel, enum sr_loglevel>::_values = { +template<> SR_API const std::map<const enum sr_loglevel, const LogLevel * const> EnumValue<LogLevel, enum sr_loglevel>::_values = { {SR_LOG_NONE, LogLevel::NONE}, {SR_LOG_ERR, LogLevel::ERR}, {SR_LOG_WARN, LogLevel::WARN}, @@ -344,7 +344,7 @@ const TriggerMatchType * const TriggerMatchType::EDGE = &TriggerMatchType::_EDGE; const TriggerMatchType * const TriggerMatchType::OVER = &TriggerMatchType::_OVER; const TriggerMatchType * const TriggerMatchType::UNDER = &TriggerMatchType::_UNDER; -template<> const std::map<const enum sr_trigger_matches, const TriggerMatchType * const> EnumValue<TriggerMatchType, enum sr_trigger_matches>::_values = { +template<> SR_API const std::map<const enum sr_trigger_matches, const TriggerMatchType * const> EnumValue<TriggerMatchType, enum sr_trigger_matches>::_values = { {SR_TRIGGER_ZERO, TriggerMatchType::ZERO}, {SR_TRIGGER_ONE, TriggerMatchType::ONE}, {SR_TRIGGER_RISING, TriggerMatchType::RISING}, /Uffe Created attachment 111 [details]
libsigrok-bindings-cxx-enums-cpp.patch
Sorry about the cross-spamming - I saw the bug ticket after having sent my email to the mailinglist /Uffe That change needs to be applied to enums.py, which generates enums.cpp: diff --git a/bindings/cxx/enums.py b/bindings/cxx/enums.py index 53bd000..aed4212 100644 --- a/bindings/cxx/enums.py +++ b/bindings/cxx/enums.py @@ -138,7 +138,7 @@ for enum, (classname, classbrief) in classes.items(): file=code) # Define map of enum values to constants - print('template<> const std::map<const enum %s, const %s * const> EnumValue<%s, enum %s>::_values = {' % ( + print('template<> const SR_API std::map<const enum %s, const %s * const> EnumValue<%s, enum %s>::_values = {' % ( enum_name, classname, classname, enum_name), file=code) for name, trimmed_name in zip(member_names, trimmed_names): print('\t{%s, %s::%s},' % (name, classname, trimmed_name), file=code) The change is verified with clang on both ArchLinux and FreeBSD-10.1 pulseview compiles, links and executes with success. Is there something that I'm missing here - why the need for the change ? As I wrote earlier in this case: why the problem only relates to classes "LogLevel" and "TriggerMatchType" ? There are lots of other classes based on the EnumValue template that does not have this problem - and they all use the same approach for (static) initialization through explicit template specialization... /Uffe The _values map will only be needed if the get() or values() static methods from the EnumValue class template are used. E.g. for TriggerMatchType, PV calls this in pv/view/logicsignal.cpp, lines 238 and 387 in revision 5164bbd9. Yes, but shouldn't it be sufficient to have SR_API in the .hpp header file and not in the .cpp file ? Fixed in dc7125bb7cfe34f63695ea928dda17594dfac3d2, thanks guys! I tested on Linux with clang(++) 3.5, which was having the problem before (and doesn't anymore). (In reply to comment #7) > Yes, but shouldn't it be sufficient to have SR_API in the .hpp header file > and not in the .cpp file ? For normal symbols yes, but this is a template specialisation. I have no idea what the rules ought to be for that really. If you can confirm this shouldn't be required then file a clang bug, but we'll still need this fix for now. |