pothosware / SoapySDR

Vendor and platform neutral SDR support library.
https://github.com/pothosware/SoapySDR/wiki
Boost Software License 1.0
1.09k stars 176 forks source link

Build fails: undefined symbol: SoapySDR::KwargsToString #429

Closed yurivict closed 3 weeks ago

yurivict commented 5 months ago
ld: error: undefined symbol: SoapySDR::KwargsToString(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>> const&)

I think that there is another bug: why is SoapySDR even involved when the option SOAPYSDR is set to false by default?

Version: 1.0.0-alpha1 SoapySDR-0.8.1 clang-16 FreeBSD 14.0

RalphSteinhagen commented 3 weeks ago

This seems to be a ABI linking error.

By default SoapySDR seems to do C++ linkage which is OK when you build both your application and Soapy with the same compiler and [std]libc++. As soon as these do not match (e.g. app with stdlibc++ and soapy with libc++, or different compiler versions) then there is an ABI mismatch.

I tried to work around this using soapy's C-API which helps because of the C-Linkage (which has more ABI guarantees):

See for example here. PRO: linkage isn't a problem anymore. CON: you have C-style resource management where there might be memory leaks and ASAN issues (N.B. we are investigating the latter).

zuckschwerdt commented 3 weeks ago

Thanks! Closing as it's not likely that we can work around (or even warn on) C++ ABI mismatch. But do comment and update if there is anything to improve here.

RalphSteinhagen commented 3 weeks ago

In the link I provided, there is a C++ wrapper around the C-API that makes builds between different compilers and [std]libc++ compatible. The path through the extern "C" linkage works.

Maybe this could be integrated into SoapySDR?

Similarly, to detect these types and other CI-related issue, it might be worthwhile to incorporate something similar to this: https://github.com/JuliaTelecom/SoapyLoopback in the SoapySDR core. That would help debugging, unit tests, and fixing ASAN, UBSAN, and TSAN issues much easier IMO.

Maybe @guruofquality, @cjcliffe, and/or others who seemed to have worked a lot on this may help?

zuckschwerdt commented 3 weeks ago

Avoiding the C++ ABI will of course help. We can't provide a compiled C++ wrapper since part of that solution is to build that wrapper with the ABI expectations of your projects.

On the other hand I had good success with these bugs in the past by methodically tracking down and avoiding risky API (on parts like polymorphism and implicit bahaviour). But "dumbing down" the C++ API will likely be breaking.

zuckschwerdt commented 3 weeks ago

Btw, the original error shows a safety feature in action: libc++ uses inline namespaces to help ensure that ABI incompatible types cannot be mistaken for one another; if an interface uses libc++ std::string directly a library expecting libstdc++ std::string will not link to the interface, because the actual symbols are different: std::string vs. std::__1::string. The only way out of that incompatibility would be to forgo std::string -- not really an option for the C++ API.

RalphSteinhagen commented 3 weeks ago

@zuckschwerdt my proposal is not to forgo the C++ API but rather use an immediate C++ -> C-API (ABI backward/forward compatibility) -> C++ API between the user's application and soapy abstraction.

This is also used in other C++-based libraries, for example, libzmq to allow for non-C++ API bindings (Python, etc.).

zuckschwerdt commented 3 weeks ago

but rather use an immediate C++ -> C-API (ABI backward/forward compatibility) -> C++ API

Understood. But that would have to be source and can't be provided with the Soapy lib (except maybe as a header-only thing).