文章目录
- 概要
- 整体架构流程
- 技术名词解释
- 技术细节
- 在启动器中为子进程设置路径和环境。
- 如何迅速找齐所有的DLL
- 小结
- 附件
概要
新接触软件定义无线电(SDR)的朋友一般都会一股脑的安装一些现有的SDR平台。无论是GNURadio还是SDR++、SDRSharp、SDRAngel,几乎都是要一顿操作猛如虎,安装很多依赖项。如果恰好在一台崭新的windows计算机上安装了多个平台,还可能因为环境变量的污染,导致一些问题。比如libusb版本不同,使得一些SDR设备工作不正常。
当自己跃跃欲试,想像我一样构造自己的SDR上位机平台时,必然也会遇到依赖性的问题。由于特别喜欢路径无关的绿色软件,自己总想着找个办法,使得SDR程序拷贝到一个崭新的计算机上直接可以点开运行,并驱动我的山寨USRP B205mini。经过一段时间的研究,我发现使用MSYS2 Qt环境可以实现这种绿色版本的发布包。
整体架构流程
整体思路是用一个启动器作为运行时路径、环境变量的维护者,而非污染全局PATH和环境变量。
主要步骤:
- 正确编译软件。
- 拷贝可执行文件到发布文件夹。
- 使用 windeployqt6 拷贝基础的Qt6依赖(插件、库)。
- 使用拷贝命令拷贝所有库到主发布文件夹。
- 在启动程序中,设置进程内的环境变量,指明Qt库、UHD驱动库的位置,这样启动的子进程都将共享当前的环境。
- 把编译环境下的Qt文件夹、UHD文件夹临时改名,以确保不会因为全局PATH污染,漏掉DLL没有拷贝。
- 启动程序并全功能运行,包括可能的数据库、网络、Charts功能。这样保证大多数依赖的DLL被占用。
- 在程序运行时,把冗余的DLL全选,删除。删不掉的就是需要的。
- 找一台空白虚机,拷贝过去测试。如果缺少文件,用ldd或者dumpbin或者Dependencies 查看依赖。
- 打包发布
技术名词解释
-
windeployqt6 :是Qt的一个工具,用于自动化部署Qt应用程序所需的依赖项。当您使用Qt创建Windows应用程序时,您通常需要将一些Qt库和其他依赖项打包到您的应用程序中,以确保在其他计算机上运行时具有所需的依赖项。windeployqt6可以自动检测并将所有必要的依赖项复制到您的应用程序目录中,以便您可以将其部署到其他计算机上。但是它在MSYS2下不会递归复制依赖,复制的Qt库仍旧依赖额外的动态库。因此,需要使用其他方法补充过去。
-
UHD 库 :UHD(USRP Hardware Driver)是Ettus Research公司开发的一种驱动软件,用于与USRP(Universal Software Radio Peripheral)软件定义无线电硬件交互。UHD提供了一个跨平台的API,支持多种操作系统和编程语言,可以轻松地访问和控制USRP硬件的功能。UHD库提供了一系列函数和类,用于控制USRP设备的各种参数和功能,包括频率、增益、带宽、采样率、同步、校准等。同时,UHD也支持通过网络连接多个USRP设备,以实现更高级别的应用。
技术细节
在启动器中为子进程设置路径和环境。
静态编译启动器可以使得启动器本身不需要Qt库的支持。主要用到的是 qget/putenv 函数。
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
//Change CurrentDir
QDir dir("/");
dir.setCurrent(app.applicationDirPath());
//set Plugin PATH
QSettings settings(QCoreApplication::applicationFilePath()+".ini",QSettings::IniFormat);
QString plgPath = settings.value("settings/QT_PLUGIN_PATH",QCoreApplication::applicationDirPath()).toString();
QString uhdPath = settings.value("settings/UHD_PKG_PATH",QCoreApplication::applicationDirPath()+"/../uhd").toString();
QDir dir_plg (plgPath), dir_uhd(uhdPath);
plgPath = dir_plg.absolutePath();
uhdPath = dir_uhd.absolutePath();
QString strUHDPath = qgetenv("UHD_PKG_PATH");
if (!strUHDPath.length())
{
strUHDPath = uhdPath;
qputenv("UHD_PKG_PATH",strUHDPath.toUtf8());
}
QString strPluginPath = qgetenv("QT_PLUGIN_PATH");
if (strPluginPath.length())
strPluginPath += ";";
strPluginPath += plgPath;
qputenv("QT_PLUGIN_PATH",strPluginPath.toUtf8());
QString strExePath = qgetenv("PATH");
if (strExePath.length())
strExePath += ";";
strExePath += strUHDPath+"\\bin;";
strExePath += QCoreApplication::applicationDirPath();
qputenv("PATH",strExePath.toUtf8());
//...
启动真正的程序并隐藏自己。
}
如何迅速找齐所有的DLL
虽然有各种依赖项工具,但对上百个dll依赖而言,一个个找太难了。这里就要用到一种暴力的方法,且只对windows有效(Linux下程序运行时不会锁死可执行文件和库)。
拷贝全部可能的依赖到可执行文件夹,而后运行程序,并全选DLL、删除。这样,会剩下一些删不掉的。
注意事项:
- 一些延迟加载的插件不一定被加载。比如QtSql可能只有在真实连接到 mysql时,libmariadb.dll以及libssl等才被占用。所以,万一没有找全,再用Dependencies 查看相应qsql插件的依赖,针对性就很强了。
- 解决冲突的依赖。如果两个程序依赖同名的dll,但dll的版本要求不同,则需要把这两个程序和独到的依赖拎出来,放到独立的文件夹下。windows下,会优先匹配本文件夹的库。这是与Linux的重大不同。
小结
使用该方法,我们整合了 taskBus SDR发布包,除了 PCAP驱动需要安装外,其余的设施全部都是绿色版直接运行。
相关代码和文件夹参考
https://gitcode.net/coloreaglestdio/taskbus
https://gitcode.com/colorEagleStdio/taskbus/overview
以及我的SDR专栏。
附件
E:\Publish\taskbus.uhd4.6_20240509
|
+---bin
| | default_mods.text
| | lame.exe
| | libb2-1.dll
| | libbrotlicommon.dll
| | libbrotlidec.dll
| | libbz2-1.dll
| | libcrypto-3-x64.dll
| | libcurl-4.dll
| | libdeflate.dll
| | libdouble-conversion.dll
| | libfftw3-3.dll
| | libfreetype-6.dll
| | libgcc_s_seh-1.dll
| | libglib-2.0-0.dll
| | libgraphite2.dll
| | libharfbuzz-0.dll
| | libiconv-2.dll
| | libicudt74.dll
| | libicuin74.dll
| | libicuuc74.dll
| | libidn2-0.dll
| | libintl-8.dll
| | libjasper.dll
| | libjbig-0.dll
| | libjpeg-8.dll
| | liblcms2-2.dll
| | libLerc.dll
| | liblzma-5.dll
| | libmariadb.dll
| | libmd4c.dll
| | libmng-2.dll
| | libnghttp2-14.dll
| | libpcre2-16-0.dll
| | libpcre2-8-0.dll
| | libpng16-16.dll
| | libpq.dll
| | libpsl-5.dll
| | libsharpyuv-0.dll
| | libssh2-1.dll
| | libssl-3-x64.dll
| | libstdc++-6.dll
| | libtiff-6.dll
| | libtommath-1.dll
| | libunistring-5.dll
| | libwebp-7.dll
| | libwebpdemux-2.dll
| | libwebpmux-3.dll
| | libwinpthread-1.dll
| | libzstd.dll
| | Qt6Charts.dll
| | Qt6Core.dll
| | Qt6Gui.dll
| | Qt6Multimedia.dll
| | Qt6Network.dll
| | Qt6OpenGL.dll
| | Qt6OpenGLWidgets.dll
| | Qt6Pdf.dll
| | Qt6Sql.dll
| | Qt6Svg.dll
| | Qt6Widgets.dll
| | taskBusConsole.exe
| | taskBusConsole.ini
| | taskBusConsole.text
| | taskBusPlatform.exe (启动程序)
| | taskBusPlatform.exe.ini
| | zlib1.dll
| |
| +---generic
| | qtuiotouchplugin.dll
| |
| +---iconengines
| | qsvgicon.dll
| |
| +---imageformats
| | qgif.dll
| | qicns.dll
| | qico.dll
| | qjp2.dll
| | qjpeg.dll
| | qmng.dll
| | qpdf.dll
| | qsvg.dll
| | qtga.dll
| | qtiff.dll
| | qwbmp.dll
| | qwebp.dll
| |
| +---networkinformation
| | qglib.dll
| | qnetworklistmanager.dll
| |
| +---platforms
| | qwindows.dll
| |
| +---styles
| | qmodernwindowsstyle.dll
| |
| |
| +---tls
| | qcertonlybackend.dll
| | qopensslbackend.dll
| | qschannelbackend.dll
| |
| \---translations
| qt_zh_CN.qm
| qt_zh_TW.qm
|
+---course
| | 8psk_network_A.tbj
| | 8psk_network_B.tbj
| |
| +---a0common
| | a0simplechannel.exe
| |
| +---a1frame
| | a1frame_askdem.exe
| | a1frame_askmod.exe
| | a1frame_decap.exe
| | a1frame_encap.exe
| |
| \---a2psk
| a2psk_decap.exe
| a2psk_dem.exe
| a2psk_encap.exe
| a2psk_mod.exe
|
+---examples
| | adsb_reciever.tbj
| | adsb_rtlsdr.tbj
| | example_nodejs.tbj
| | example_python.tbj
| | example_python2.tbj
| | mp3_player.tbj
| | pluto_fmradio.tbj
| | readme.txt
| | rtl_sdr_fm_wrapper.tbj
| | soundcard.tbj
| | soundcard_antiblocking.tbj
| | soundcard_client.tbj
| | soundcard_server.tbj
| | subproject.tbj
| | usrp_b210_dualio.tbj
| | usrp_fmp3_emit.tbj
| | usrp_fm_emitter.tbj
| | usrp_fm_reciever.tbj
| | usrp_fm_wrapper.tbj
| | usrp_sample_replay.tbj
| | voice_spec.exe
| | voice_spec.exe.ini
| | voice_spec.tbj
| | voice_spec.text
| |
|
|
+---modules
| | control_pannel.exe
| | control_pannel.md
| | filter_fir.exe
| | mod_fm.exe
| | mod_fm_dem.exe
| | network_p2p.exe
| | resample_pqfraction.exe
| | sink_file.exe
| | sink_file.md
| | sink_plots.exe
| | sink_soundcard.exe
| | sink_SQL.exe
| | source_files.exe
| | source_soundcard.exe
| | transform_fft.exe
| | wrapper_stdio.exe
| |
| +---network_p2p.handbook
| | network_p2p.md
| | ui.jpg
| |
| +---plutosdr
| | libiconv-2.dll
| | libiio.a
| | libiio.dll
| | libiio.dll.a
| | liblzma-5.dll
| | libserialport-0.dll
| | libusb-1.0.dll
| | libxml2-2.dll
| | sink_plutosdr.exe
| | source_plutosdr.exe
| | zlib1.dll
| |
| +---usrp
| | uhd_usrp_continous.exe
| | uhd_usrp_io.exe
| |
| \---wrapper_scripts
| wrapper_scripts.exe
|
+---pcap_hub
| pcapHub.exe
|
+---qplanetosm
| | libqtvplugin_geomarker.dll1.ini
| | libqtvplugin_grid.dll1.ini
| | libqtwidget_planetosm_designer.dll.a
| | qtviewer_planetosm.exe
| | qtviewer_planetosm.exe.ini
| | qtvplugin_geomarker.dll
| | qtvplugin_grid.dll
| | qtwidget_planetosm.dll
| | test_container.exe
| | test_container.exe.ini
| |
|
|
+---rtl_sdr
| libusb-1.0.dll
| pthreadVC2.dll
| rtlsdr.dll
| rtl_adsb.exe
| rtl_biast.exe
| rtl_eeprom.exe
| rtl_fm.exe
| rtl_ir.exe
| rtl_power.exe
| rtl_raw2wav.exe
| rtl_sdr.exe
| rtl_tcp.exe
| rtl_test.exe
| rtl_udp.exe
| rtl_wavestat.exe
| rtl_wavestream.exe
| vcruntime140.dll
|
|
\---uhd
|
+---bin
| libusb-1.0.dll
| rfnoc_image_builder
| uhd.dll
| uhd_adc_self_cal.exe
| uhd_cal_rx_iq_balance.exe
| uhd_cal_tx_dc_offset.exe
| uhd_cal_tx_iq_balance.exe
| uhd_config_info.exe
| uhd_find_devices.exe
| uhd_image_loader.exe
| uhd_usrp_probe.exe
| usrpctl
|
|
|
\---share
|
\---uhd
| FastSendDatagramThreshold.reg
|
+---cal
| cal_metadata.fbs
| dsa_cal.fbs
| iq_cal.fbs
| pwr_cal.fbs
|
+---images
| erllc_uhd.cat
| erllc_uhd_b100.inf
| erllc_uhd_b200.inf
| erllc_uhd_b200mini.inf
| ...
| usrp_x440_fpga_X4_400.dts
| usrp_x440_fpga_X4_400.dts.md5
| usrp_x440_fpga_X4_400.rpt
| WdfCoInstaller01009.dll
| winusbcoinstaller2.dll
|
\---rfnoc
+---blocks
| addsub.yml
| axi_ram_fifo.yml
| ddc.yml
| duc.yml
| fft_1x64.yml
| fir_filter.yml
| fosphor.yml
| keep_one_in_n.yml
| logpwr.yml
| moving_avg.yml
| null_src_sink.yml
| radio.yml
| replay.yml
| siggen.yml
| split_stream.yml
| switchboard.yml
| vector_iir.yml
| window.yml
|
\---core
e310_bsp.yml
e320_bsp.yml
io_signatures.yml
n300_bsp.yml
n310_bsp.yml
n320_bsp.yml
rfnoc_imagebuilder_args.json
x300_bsp.yml
x310_bsp.yml
x410_bsp.yml
x440_bsp.yml