最近做一个基于minigui/mgncs的项目,在开发阶段因为是在ubuntu下基于minigui的模拟器开发,所以编译时都是标准的动态库连接。没啥问题,很顺序。
现在项目功能开发告一段落,要向嵌入式平台移植了,就要把编译改为全静态连接(--static)。问题就来了。

编译正常,连接时报了如下一大堆错误:

/usr/lib/x86_64-linux-gnu/libxml2.a(nanohttp.o): In function `xmlNanoHTTPConnectHost':
(.text+0x924): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/x86_64-linux-gnu/libxml2.a(nanohttp.o): In function `xmlNanoHTTPConnectHost':
(.text+0x9f4): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/x86_64-linux-gnu/libxml2.a(xpath.o): In function `xmlXPathCastNumberToString':
(.text+0xa3d7): undefined reference to `log10'
/usr/lib/x86_64-linux-gnu/libxml2.a(xmlschemastypes.o): In function `xmlSchemaGetCanonValue':
(.text+0xb84e): undefined reference to `trunc'
/usr/lib/x86_64-linux-gnu/libxml2.a(xmlschemastypes.o): In function `xmlSchemaGetCanonValue':
(.text+0xb89a): undefined reference to `trunc'
/usr/lib/x86_64-linux-gnu/libxml2.a(xzlib.o): In function `xz_head':
(.text+0x69e): undefined reference to `lzma_auto_decoder'
/usr/lib/x86_64-linux-gnu/libxml2.a(xzlib.o): In function `xz_head':
(.text+0x76e): undefined reference to `lzma_properties_decode'
/usr/lib/x86_64-linux-gnu/libxml2.a(xzlib.o): In function `xz_decomp':
(.text+0x11a0): undefined reference to `lzma_code'
/usr/lib/x86_64-linux-gnu/libxml2.a(xzlib.o): In function `__libxml2_xzclose':
(.text+0x1f95): undefined reference to `lzma_end'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `openIcuConverter':
(.text+0x104b): undefined reference to `ucnv_open_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `openIcuConverter':
(.text+0x1077): undefined reference to `UCNV_FROM_U_CALLBACK_STOP_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `openIcuConverter':
(.text+0x107c): undefined reference to `ucnv_setFromUCallBack_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `openIcuConverter':
(.text+0x109b): undefined reference to `ucnv_open_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `openIcuConverter':
(.text+0x10b7): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `openIcuConverter':
(.text+0x10eb): undefined reference to `UCNV_TO_U_CALLBACK_STOP_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `openIcuConverter':
(.text+0x10f0): undefined reference to `ucnv_setToUCallBack_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `closeIcuConverter':
(.text+0x111d): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `closeIcuConverter':
(.text+0x1126): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlFindCharEncodingHandler':
(.text+0x2793): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlFindCharEncodingHandler':
(.text+0x279d): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlFindCharEncodingHandler':
(.text+0x27b3): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o):(.text+0x27bc): more undefined references to `ucnv_close_55' follow
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncFirstLineInt':
(.text+0x2f6e): undefined reference to `ucnv_convertEx_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncFirstLine':
(.text+0x3270): undefined reference to `ucnv_convertEx_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncFirstLineInput':
(.text+0x365a): undefined reference to `ucnv_convertEx_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncInput':
(.text+0x3a47): undefined reference to `ucnv_convertEx_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncInFunc':
(.text+0x3de7): undefined reference to `ucnv_convertEx_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o):(.text+0x4197): more undefined references to `ucnv_convertEx_55' follow
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncCloseFunc':
(.text+0x4bb0): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncCloseFunc':
(.text+0x4bba): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncCloseFunc':
(.text+0x4bdd): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlCharEncCloseFunc':
(.text+0x4be7): undefined reference to `ucnv_close_55'
/usr/lib/x86_64-linux-gnu/libxml2.a(encoding.o): In function `xmlByteConsumed':
(.text+0x4f2d): undefined reference to `ucnv_convertEx_55'
collect2: error: ld returned 1 exit status

可以发现,问题都来自于mgncs依赖的xml2这个库。分析问题原因花了好长时间,找到原因倒是很简单:

xml2这个库其实还依赖其他的库

用ldd命令查看libxml2.so的依赖库:

$ ldd /usr/lib/x86_64-linux-gnu/libxml2.solinux-vdso.so.1 =>  (0x00007ffd7fbaa000)libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ffb86d88000)libicuuc.so.55 => /usr/lib/x86_64-linux-gnu/libicuuc.so.55 (0x00007ffb869f4000)libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007ffb867da000)liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007ffb865b8000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffb862af000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffb85ee5000)/lib64/ld-linux-x86-64.so.2 (0x00007ffb87347000)libicudata.so.55 => /usr/lib/x86_64-linux-gnu/libicudata.so.55 (0x00007ffb8442e000)libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ffb840ac000)libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ffb83e96000)

所以虽然连接动态库时很简单,只需要加上-lxml2就可以了,但在静态连接时,就要把xml2所依赖的所有库都要加上,用pkg-config命令就可以查看xml2静态连接和动态连接所需要的参数,如下

# 动态库连接只需要-lxml2
$ pkg-config --libs libxml-2.0
-lxml2
# 静态库连接则需要一堆的库
$ pkg-config --static --libs libxml-2.0
-lxml2 -licui18n -licuuc -licudata -lz -llzma -lm

于是我按照上面pkg-config命令的输出加上静态连接相应的参数,再次编译,这下总该没事了吧?
然而又是一堆连接错误,如下

/usr/lib/x86_64-linux-gnu/libxml2.a(threads.o): In function `xmlRMutexLock':
(.text+0x1ff): undefined reference to `pthread_cond_wait'
/usr/lib/x86_64-linux-gnu/libxml2.a(threads.o): In function `xmlRMutexUnlock':
(.text+0x285): undefined reference to `pthread_cond_signal'
/usr/lib/x86_64-linux-gnu/libxml2.a(threads.o): In function `xmlIsMainThread':
(.text+0x4a8): undefined reference to `pthread_cond_wait'
/usr/lib/x86_64-linux-gnu/libxml2.a(threads.o): In function `xmlIsMainThread':
(.text+0x4d1): undefined reference to `pthread_cond_signal'
/usr/lib/x86_64-linux-gnu/libxml2.a(threads.o): In function `xmlInitThreads':
(.text+0x5e0): undefined reference to `pthread_cond_wait'
/usr/lib/x86_64-linux-gnu/libxml2.a(threads.o): In function `xmlInitThreads':
(.text+0x609): undefined reference to `pthread_cond_signal'
/usr/lib/x86_64-linux-gnu/libicuuc.a(putil.ao): In function `uprv_dl_open_55':
(.text+0x18c2): undefined reference to `dlopen'
/usr/lib/x86_64-linux-gnu/libicuuc.a(putil.ao): In function `uprv_dlsym_func_55':
(.text+0x190d): undefined reference to `dlsym'
/usr/lib/x86_64-linux-gnu/libicuuc.a(putil.ao): In function `uprv_dl_close_55':
(.text+0x18f1): undefined reference to `dlclose'
/usr/lib/x86_64-linux-gnu/libicuuc.a(umutex.ao): In function `icu_55::umtx_initImplPreInit(icu_55::UInitOnce&)':
(.text+0xaf): undefined reference to `pthread_cond_wait'
/usr/lib/x86_64-linux-gnu/libicuuc.a(umutex.ao): In function `icu_55::umtx_initImplPostInit(icu_55::UInitOnce&)':
(.text+0x10e): undefined reference to `pthread_cond_broadcast'
/usr/lib/x86_64-linux-gnu/libicuuc.a(umutex.ao): In function `umtx_condWait_55':
(.text+0x4f): undefined reference to `pthread_cond_wait'
/usr/lib/x86_64-linux-gnu/libicuuc.a(umutex.ao): In function `umtx_condBroadcast_55':
(.text+0x61): undefined reference to `pthread_cond_broadcast'
/usr/lib/x86_64-linux-gnu/libicuuc.a(umutex.ao): In function `umtx_condSignal_55':
(.text+0x71): undefined reference to `pthread_cond_signal'

可以看出原来的问题解决了,但是新问题来了,不过这次的问题倒简单,一看就明白,就是找不到pthread,dl这两个库(pthread_开头的引用都是pthread相关函数,dl开头的函数dlopen,dlclose都是dl库的函数)
其实前面用ldd命令查看libxml2.so的依赖库时,就显示有dl库。但不知道为什么没有显示pthread库。

于是再为xml2库加上-lpthread -ldl就可以编译通过了(-lpthread -ldl的先后顺序没有关系)
下面就是静态连接xml2的完整连接参数:

-lxml2 -licui18n -licuuc -licudata -lz -llzma -lm -lpthread -ldl
# 实际测试没有-licui18n也是可以连接通过的

你真的需要xml2码?

编译通过之后,满心欢喜,顺序查看了一下编译后的executable文件大小,吓我一大跳:44MB!!!

立即就崩溃了,目标平台上内存才32MB,这么大的可执行文件没法用呐。项目中用到的这么多连接库,到底哪个是最大的呢?幸运的是很快就找到了最大的连接库,就是-licudata

$ ll -h /usr/lib/x86_64-linux-gnu/libicudata.so.55.1
-rw-r--r-- 1 root root 25M 3月  27  2018 /usr/lib/x86_64-linux-gnu/libicudata.so.55.1

ICU 是开源项目, 提供了最新的unicode标准,字符集转换, 以及超过300个国家的本地数据, 比如数字,时间和信息显示格式等,以及不同语言下的文本排序,日历相关的日期时间操作等。
详细内容可以访问: http://userguide.icu-project.org/

这个libicudata.so.55.1动态库就是ICU库用到的数据。

是不是可以通过自己编译减小icudata的大小?
如何编译ICU?
这又是一个要好一阵折腾的事儿,头大了。
这样被一个又一个出现的问题牵着鼻子走,何时是个头呢?
我打算跳出这个工作思路。
回头看mgncs的编译脚本,在${libmgncs-1.2.0}/configure.ac中找到下面的代码。
原来可以通过--enable-dbxml命令行参数控制是否使用xml2 !

AC_ARG_ENABLE(dbxml,
[ --enable-dbxml    enable libxml2 datasource support <default=yes>],
build_datasource_xml=$enableval)if test "x$build_datasource_xml" = "xyes"; thenAC_CHECK_LIB(xml2, xmlFree,DEP_LIBS="$DEP_LIBS -lxml2",build_datasource_xml=no)
fiif test "x$build_datasource_xml" = "xyes"; thenAC_DEFINE(_MGNCSDB_DATASOURCE, 1,[Define if support datasource])AC_DEFINE(_MGNCSDB_XML, 1,[Define if support xml datasource])CPPFLAGS="$CPPFLAGS -I/usr/include/libxml2"
fi

进一步查看_MGNCSDB_XML_MGNCSDB_DATASOURCE宏定义所涉及的代码,就搞明白了如果在mgncs中禁用xml2,就会禁用mxmlds.h这个接口文件定义的所有功能。

mxmlds.h会不会被应用项目用到呢?

mxmlds.h用于读写xml文件,MiniStudio中生成的资源文件就是xml格式,所以这个模块应该就是用于读写xml格式的资源文件,而在程序编译运行的时候,资源文件已经编译成.res的二进制文件了不再需要xml解析。
事实上,mgncs根本没有把这个mxmlds.h文件release出来,只是mgncs内部配合MiniStudio时使用的,所以编译目标平台的mgncs库时禁用它完全没问题。
于是如下在编译mgncs时加上--enable-dbxml=no,重新编译mgncs。

./configure \--host=$host \--prefix=$sh_folder/release/$mgncs_folder/$host \--enable-develmode     \--enable-dbxml=no \MINIGUI_CFLAGS="-I$sh_folder/release/$minigui_folder/$host/include" \MGUTILS_CFLAGS="-I$sh_folder/release/$mgutils_folder/$host/include" \MINIGUI_LIBS="-L$sh_folder/release/$minigui_folder/$host/lib -l:libminigui_ths.a -ljpeg -lpng -lm -lfreetype -lz -lpng12 -lfreetype -lpthread" \MGUTILS_LIBS="-L$sh_folder/release/$mgutils_folder/$host/lib -l:libmgutils.a -ljpeg -lpng -lm -lfreetype -lz -lpng12 -lfreetype -lpthread" \MGPLUS_CFLAGS="-I$sh_folder/release/$mgplus_folder/$host/include" \MGPLUS_LIBS="-L$sh_folder/release/$mgplus_folder/$host/lib -l:libmgplus.a -lfreetype -lpthread -lstdc++" \|| exit -1make -j8  || exit -1
make install

编译通过后再ldd查看libmgncs.so的信赖库,已经没有xml2了。

$ ldd release/libmgncs-1.2.0/x86_64-linux-gnu/lib/libmgncs-1.2.so.0linux-vdso.so.1 =>  (0x00007fff449c2000)libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe8e8a22000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe8e8719000)libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007fe8e846f000)libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe8e8252000)libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe8e803c000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe8e7c72000)/lib64/ld-linux-x86-64.so.2 (0x00007fe8e9305000)libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fe8e7a58000)libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007fe8e7833000)

再用没有了xml2依赖的mgncs库作项目的静态编译。executable文件的体积变成了17MB,再经过strip后,只剩下8MB.虽然还是偏大,但这是Debug版,还没有优化,这个体积算是正常啦。

minigui:静态编译连接mgncs库时遇到的xml2的问题相关推荐

  1. qt html 库段错误,连接Qwt库时Qt代码中的分段错误

    我试图用一些Qwt小部件创建一个Qt  应用程序,但是当我尝试链接Qwt库时,我发现Qt代码中存在分段错误.我使用的是非常简单的Qt程序,只弹出一个空白窗口:连接Qwt库时Qt代码中的分段错误 #in ...

  2. 进程编译连接动态库,需要将动态库改为lib***.so

    1.本身该库可能编译成npuDetect.so,但是需要改其名字为libnpuDetect.so,CMakelists才能找到该库 2.进程中连接动态库,如果该库还依赖别的动态库,则需要继续把其他的库 ...

  3. 使用std::thread线程相关函数,-static静态编译的程序运行时的一些常见错误

    使用std::thread的应用程序,编译时如果是动态链接pthread线程库运行正常,-static静态链接时在某些平台下可能会遇到一些意外错误.如常见编译命令:g++ -std=C++11 tes ...

  4. configure 查找依赖库_Rust在编译Android的库时,如何设定依赖的第三方库引用的C/C++的动态库的搜索路径?...

    谢邀.不懂android,也不懂OpenCL.但是我尝试了解了一下你的问题. 既然你用了第三方库,那就得查源码了.翻开ocl 库的源码搜android关键字,很容易定位到下面代码. #https:// ...

  5. Android应用控制LED(静态编译LED驱动)

     此文章是Android应用控制底层硬件的小实验,记录下来,以防后面忘记如何操作.后面也可以按照此流程进行其他开发 开发平台:DMATEK PAD-4412 内核:Linux3.2.0 系统:An ...

  6. java zlib1.dll,zlib1.2.11静态编译

    1.进入官网http://zlib.net/,下载且解压zlib1211.zip: 2. 打开已解压的zlib-1.2.11目录,找到win32文件夹 3.将Makefile.msc复制到上一层,也就 ...

  7. Java静态编译技术:突破Java“冷启动”桎梏,实现启动性能“质”的飞跃

    自1996年诞生以来,Java语言长期在最受欢迎的编程语言排行榜中占据领先地位.除了语言本身的优秀特性之外,Java语言持续演进.不断发展也是它能够保持长盛不衰的重要原因. |Java市场份额不断下降 ...

  8. vs可以调用java接口吗_关于vs2010下编译dll动态库,JNA接口在java中调用的问题

    最近在搞关于把vs2010中的project,使之能够在Java下面运行,有一个调用本地接口的问题,JNI那个涉及到复杂细节太多,就使用了最新的JNA(java native access) 网上也给 ...

  9. Linux下静态库和动态库的编译连接

    http://blog.sina.com.cn/s/blog_4090ba590100t3nu.html .a文件 gcc -c test.c  ar rc libtest.a test.o  ran ...

最新文章

  1. 使用Git向GitHub上传代码
  2. before伪类的超有用应用技巧——水平菜单竖线分隔符
  3. 关于linkedin的network的观察和自己的职业道路的追求
  4. 辽宁活跃ip段_有泰国女排影子!激情辽宁女排,打出快乐排球,输了比赛赢了球迷...
  5. mysql 传统数据恢复_mysql 数据恢复实例
  6. http代理的脚本http_proxy.py
  7. php 如何设置后台,phpcms怎么重新设置后台网址
  8. k8s核心技术-Pod(调度策略)_影响Pod调度(资源限制和节点选择器)---K8S_Google工作笔记0025
  9. 迫切想要成功之后的喜悦感,失败太久有点心灵上小小的打击,还需要继续前进。...
  10. 智能家居至今未落地 究其原因是没想好怎么分蛋糕
  11. spring-第十九篇AOP面向切面编程之增强处理的优先级
  12. 亲测可用企业级自动发卡平台PHP系统源码
  13. python:库文件整理
  14. 《Python金融大数据风控建模实战》 第15章 神经网络模型
  15. 戏说面向对象程序设计
  16. 字体图标转png透明图标——小程序开发用
  17. 揭秘大众点评的大数据实时计算
  18. 基于AVX256指令集和多线程优化的双机计算加速程序
  19. NFT这么香,到底解决了什么问题?
  20. 基于matlab的静电场边值,典型静电场场图解析解(含Matlab程序).pdf

热门文章

  1. php线路图,HTML5绘制上海地铁线路图-大前端
  2. l1-044. 稳赢c语言,L1-044 稳赢 (15 分)(解析有坑点)
  3. 深入理解 Java 泛型
  4. 区块链前后端交互过程
  5. 【C语言】打印数字金字塔
  6. Linux驱动_i2c驱动(ap3216c)
  7. android jni中的java调c的两种方法
  8. 九.配置SMB共享(Samba共享)
  9. 计算机网络---DHCP和自动配置
  10. Python专辑-QQ机器人1:基础功能实现