Closed cjcliffe closed 9 years ago
Cool app, thanks for the bug report!
The modules register their make/find functions using static initialization. Perhaps the action of bundling is stripping out the static initializers out of the modules or the dlopen() isn't calling static initializers when its bundled. Not sure why, but that may be a good place to look.
Possibly the initializers can be decorated with __attribute__((constructor))
https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Tasks/InitializingFrameworks.html
like this:
diff --git a/GrOsmoSDRRegister.in.cpp b/GrOsmoSDRRegister.in.cpp
index a908ce4..03da16c 100644
--- a/GrOsmoSDRRegister.in.cpp
+++ b/GrOsmoSDRRegister.in.cpp
@@ -71,4 +71,5 @@ static SoapySDR::Device *make__@TARGET@(const SoapySDR::Kwargs &args)
return device;
}
+__attribute__((constructor))
static SoapySDR::Registry register__@TARGET@("@TARGET@", &find__@TARGET@, &make__@TARGET@, SOAPY_SDR_ABI_VERSION);
or maybe:
diff --git a/GrOsmoSDRRegister.in.cpp b/GrOsmoSDRRegister.in.cpp
index a908ce4..098510d 100644
--- a/GrOsmoSDRRegister.in.cpp
+++ b/GrOsmoSDRRegister.in.cpp
@@ -71,4 +71,8 @@ static SoapySDR::Device *make__@TARGET@(const SoapySDR::Kwargs &args)
return device;
}
-static SoapySDR::Registry register__@TARGET@("@TARGET@", &find__@TARGET@, &make__@TARGET@, SOAPY_SDR_ABI_VERSION);
+__attribute__((constructor))
+void loadIt(void)
+{
+ SoapySDR::Registry register__@TARGET@("@TARGET@", &find__@TARGET@, &make__@TARGET@, SOAPY_SDR_ABI_VERSION);
+}
Ideally there might be a bundle option to fix this. But if not, let me know if one of these diffs helps -- maybe I will have to engineer a magic registry macro to make this work more portably if that's the case.
No change with either patch; first one reports the following for each module while compiling:
SoapyOsmo/build/register_airspy.cc:75:16: warning: 'constructor' attribute only applies to functions [-Wignored-attributes]
__attribute__((constructor))
Second patch doesn't complain but there's no change in the app bundle list of factories.
I'll poke around and see what bundle options are available.
It might be interesting to add in a test initializer with a print. if its not printed, then the problem is with the initializers not getting called. But if this print is happening, I guess thats a different can or worms... but it might be nice to narrow it down.
diff --git a/GrOsmoSDRRegister.in.cpp b/GrOsmoSDRRegister.in.cpp
index 4f4e605..5c73bf9 100644
--- a/GrOsmoSDRRegister.in.cpp
+++ b/GrOsmoSDRRegister.in.cpp
@@ -90,3 +90,14 @@ static SoapySDR::Device *make__@TARGET@(const SoapySDR::Kwargs &args)
}
static SoapySDR::Registry register__@TARGET@("@TARGET@", &find__@TARGET@, &make__@TARGET@, SOAPY_SDR_ABI_VERSION);
+
+class FooInitializer
+{
+public:
+ FooInitializer(const std::string &name)
+ {
+ std::cout << "Hello from FooInitializer " << name << std::endl;
+ }
+};
+
+static FooInitializer register_foo_test__@TARGET@("@TARGET@");
Example output:
SoapySDRUtil --find="rtl=0"
######################################################
## Soapy SDR -- the SDR abstraction library
######################################################
Hello from FooInitializer airspy
Hello from FooInitializer hackrf
Hello from FooInitializer miri
Hello from FooInitializer rfspace
Hello from FooInitializer rtl
linux; GNU C++ version 4.8.4; Boost_105400; UHD_003.008.004-0-unknown
Found device 0
driver = rtl
label = Realtek RTL2838UHIDIR SN: 00000001
rtl = 0
Hmmm, we may have a different can of worms :)
Third patch results running from CLI build works as expected:
SoapySDR init..
API Version: v0.3.0-g603da6be
ABI Version: v0.3-0
Install root: /usr/local
Module found: /usr/local/lib/SoapySDR/modules/libairspySupport.so
Module found: /usr/local/lib/SoapySDR/modules/libbladeRFSupport.so
Module found: /usr/local/lib/SoapySDR/modules/libhackrfSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librfspaceSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librtlSupport.so
Loading modules... Hello from FooInitializer airspy
Hello from FooInitializer hackrf
Hello from FooInitializer rfspace
Hello from FooInitializer rtl
done
Available factories...airspy, bladerf, hackrf, null, rfspace, rtl
Found device 0
driver = rtl
label = Realtek RTL2838UHIDIR SN: 00000003
rtl = 0
Running from bundled .app still says Hello, but no factories..
SoapySDR init..
API Version: v0.3.0-g603da6be
ABI Version: v0.3-0
Install root: /usr/local
Module found: /usr/local/lib/SoapySDR/modules/libairspySupport.so
Module found: /usr/local/lib/SoapySDR/modules/libbladeRFSupport.so
Module found: /usr/local/lib/SoapySDR/modules/libhackrfSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librfspaceSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librtlSupport.so
Loading modules... Hello from FooInitializer airspy
Hello from FooInitializer hackrf
Hello from FooInitializer rfspace
Hello from FooInitializer rtl
done
Available factories...null
No devices found!
Interesting, it might be that the modules each get a different library data section or something. This time, this is a patch on SoapySDR itself, it prints the registry table address and its size. I'm curious if the addresses differ...
diff --git a/lib/Registry.cpp b/lib/Registry.cpp
index b8d0f37..688f032 100644
--- a/lib/Registry.cpp
+++ b/lib/Registry.cpp
@@ -28,6 +28,9 @@ SoapySDR::Registry::Registry(const std::string &name, const FindFunction &find,
std::cerr << " Rebuild module against installed library..." << std::endl;
return;
}
+ std::cout << "Registering " << name << std::endl;
+ std::cout << "Table size " << getFunctionTable().size() << std::endl;
+ std::cout << "Table addr " << std::hex << size_t(&getFunctionTable()) << std::dec << std::endl;
FunctionsEntry entry;
entry.find = find;
entry.make = make;
The prints might look like this
Loading modules... Registering airspy
Table size 1
Table addr 7f4081d9b4e0
Registering bladerf
Table size 2
Table addr 7f4081d9b4e0
Registering hackrf
Table size 3
Table addr 7f4081d9b4e0
Registering miri
Table size 4
Table addr 7f4081d9b4e0
Registering remote
Table size 5
Table addr 7f4081d9b4e0
Registering rfspace
Table size 6
Table addr 7f4081d9b4e0
Registering rtl
Table size 7
Table addr 7f4081d9b4e0
Interesting result, CLI shows a consistent table addr and table size increments correctly:
Registering null
Table size 0
Table addr 100c5fd30
[..CubicSDR init happens here..]
SoapySDR init..
API Version: v0.3.0-g603da6be
ABI Version: v0.3-0
Install root: /usr/local
Module found: /usr/local/lib/SoapySDR/modules/libairspySupport.so
Module found: /usr/local/lib/SoapySDR/modules/libbladeRFSupport.so
Module found: /usr/local/lib/SoapySDR/modules/libhackrfSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librfspaceSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librtlSupport.so
Loading modules... Registering airspy
Table size 1
Table addr 100c5fd30
Hello from FooInitializer airspy
Registering bladerf
Table size 2
Table addr 100c5fd30
Registering hackrf
Table size 3
Table addr 100c5fd30
Hello from FooInitializer hackrf
Registering rfspace
Table size 4
Table addr 100c5fd30
Hello from FooInitializer rfspace
Registering rtl
Table size 5
Table addr 100c5fd30
Hello from FooInitializer rtl
done
Available factories...airspy, bladerf, hackrf, null, rfspace, rtl
Found device 0
driver = rtl
label = Realtek RTL2838UHIDIR SN: 00000003
rtl = 0
Bundle shows two different addresses between static initializer and loadModules and the table size returns to 0:
Registering null
Table size 0
Table addr 110586d30
[..CubicSDR init happens here..]
SoapySDR init..
API Version: v0.3.0-g603da6be
ABI Version: v0.3-0
Install root: /usr/local
Module found: /usr/local/lib/SoapySDR/modules/libairspySupport.so
Module found: /usr/local/lib/SoapySDR/modules/libbladeRFSupport.so
Module found: /usr/local/lib/SoapySDR/modules/libhackrfSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librfspaceSupport.so
Module found: /usr/local/lib/SoapySDR/modules/librtlSupport.so
Loading modules... Registering null
Table size 0
Table addr 11551ed30
Registering airspy
Table size 1
Table addr 11551ed30
Hello from FooInitializer airspy
Registering bladerf
Table size 2
Table addr 11551ed30
Registering hackrf
Table size 3
Table addr 11551ed30
Hello from FooInitializer hackrf
Registering rfspace
Table size 4
Table addr 11551ed30
Hello from FooInitializer rfspace
Registering rtl
Table size 5
Table addr 11551ed30
Hello from FooInitializer rtl
done
Available factories...null
No devices found!
Thats rich, so the library and modules have two distinct copies of the library's static variables. There's probably some crazy linker flag to fix whatever is going on. Example -flat_namespace
Hah! brilliant -- that was it precisely; setting CMAKE_SHARED_LINKER_FLAGS="-flat_namespace" did the trick; looks there's several similar issues on Google related to Qt Modules and that flag..
Works with both CLI and Bundled version; I'd say it's probably safe to set that as a default for IF(APPLE) .. in CMakeLists.
Thanks!
Lucky guess, glad that worked. This is the patch that I am going to apply to maint and master. Can you give it a final test?
diff --git a/cmake/SoapySDRConfig.cmake b/cmake/SoapySDRConfig.cmake
index 516336a..20cb017 100644
--- a/cmake/SoapySDRConfig.cmake
+++ b/cmake/SoapySDRConfig.cmake
@@ -68,6 +68,12 @@ if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden")
endif()
+if(APPLE)
+ #fixes issue with duplicate module registry when using application bundle
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flat_namespace")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -flat_namespace")
+endif()
+
if(MSVC)
add_compile_options(/wd4503) #'identifier' : decorated name length exceeded, name was truncated
Worked here, I'd say it's good to go
Cool, patched. Thanks https://github.com/pothosware/SoapySDR/commit/0efce23e0b1d8217607c877434fc19c525e85af1
Enjoying using SoapySDR so far; it's been quick to implement and looks like a good fit with my project.
I'm able to build and run my application (CubicSDR) with SoapySDR and run it from the terminal without issue; it finds and loads the modules and lists the factories and works with my rtl-sdr device.
Once bundled into an .app (libraries are imported with otool by cmake I believe) the installed soapy modules are found but none of the factories are available via 'SoapySDR::FindFunctions factories = SoapySDR::Registry::listFindFunctions();' except for 'null'.
Run from cli compiled binary:
Run from bundled app:
Any insight you might have would be great; let me know what I can do to help!