↓ Skip to main content
  1. Posts/

记录一次因动态库符号表可见性导致的未定义的引用(undefined reference)

·525 words·2 mins
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

编译某代码,发现报错某函数未定义的引用。该函数的是先前编译得到的动态库中。

先去check了该函数的实现,还有接口与头文件中的声明是否统一。发现没有问题。

然后怀疑.cpp文件没有被编译到,于是在该函数中添加

#pragma message("******************************8")

发现的确被编译到了。

使用nm来查看动态库中的符号表,发现也可以找到这个函数的符号。

于是怀疑编译代码的时候没有链接到该动态库。

于是在make的时候打印详细信息。make VERBOSE=1

发现也的确链接了动态库….

见鬼了Orz

然后用readelf -s 来查看动态库,惊讶得发现要找的那个符号的BIND怎么是LOCAL..也就是只有文件内可见。

最后发现…是公司内部的工具和CMakeLists中的add_library冲突…

虽然这个坑的解决方案没什么价值…不过因为这个坑了解了一些之前没有了解的部分,也算值得。

关于动态库的符号可见性:

控制的原因是,如果不控制,那么不同的cpp文件可能有相同的变量名字,如果把所有的符号都暴露,很可能在链接时产生冲突。 另外一个原因是,暴露没有必要的符号,会导致符号表的size变大,从而使得link时速度变慢。

参考资料:

Introduction to symbol visibility

readelf elf文件格式分析

Hiding what’s exposed in a shared library

Why is the new C++ visibility support so useful?

Related

c++11 function 与bind 学习笔记

·315 words·1 min
C++11 std::function 是一种通用、多态的函数封装,它的实例可以对任何可 以调用的目标实体进行存储、复制和调用操作 见下面的例子 1 /* *********************************************** 2 Author :111qqz 3 mail: renkuanze@sensetime.com 4 Created Time :2018年07月19日 星期四 17时41分00秒 5 File Name :bind.cpp 6 ************************************************ */ 7 #include <functional> 8 #include <iostream> 9 using namespace std; 10 float foo( int x,int y,int z){return x+y+z+1.;} 11 int main() 12 { 13 function<int(int,int)>func = foo; 14 int y = 10; 15 function<int(int)>fun = [&]( int value)->int 16 { 17 return 1+value+y; 18 }; 19 cout<<func(15,4,9)<<endl; 20 cout<<fun(8)<<endl; 21 return 0; 22 } std::bind 则是用来绑定函数调用的参数的,它解决的需求是我们有时候可 能并不一定能够一次性获得调用某个函数的全部参数,通过这个函数,我们可以将 部分调用参数提前绑定到函数身上成为一个新的对象,然后在参数齐全后,完成调 用

C++ 记录代码运行时间

·169 words·1 min
以前用的办法太老土啦 看到一个since C++11的方法,我觉得比较优雅 1 #include <iostream> 2 #include <chrono> 3 //#include <ratio> 4 #include <thread> 5 6 void f() 7 { 8 std::this_thread::sleep_for(std::chrono::seconds(1)); 9 } 10 11 int main() 12 { 13 auto t1 = std::chrono::high_resolution_clock::now(); 14 f(); 15 auto t2 = std::chrono::high_resolution_clock::now(); 16 17 // floating-point duration: no duration_cast needed 18 std::chrono::duration<double, std::milli> fp_ms = t2 - t1; 19 20 // integral duration: requires duration_cast 21 auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1); 22 23 // converting integral duration to integral duration of shorter divisible time unit: 24 // no duration_cast needed 25 std::chrono::duration<long, std::micro> int_usec = int_ms; 26 27 std::cout << "f() took " << fp_ms.count() << " ms, " 28 << "or " << int_ms.count() << " whole milliseconds " 29 << "(which is " << int_usec.count() << " whole microseconds)" << std::endl; 30 }

gdb学习笔记

·235 words·1 min
用gdb调试c++的时候,需要添加-g编译选项add_compile_options(-g),并且关掉各种编译优化 如果是多线程程序,可以用info threads 查看每个线程的信息

linux 下C++ 连接mysql 数据库

·243 words·1 min
资料推荐这个:MySQL C API programming tutorial 环境为ubuntu 14.04 lts 需要安装mysql 和mysql 开发包 sudo apt-get install libmysqlclient15-dev mysql-server mysql-client 先在mysql 中建立test数据库和test表格 mysql>create database test; mysql>use test; //切换到test数据库中 mysql> create table test(name varchar(255),num int(10) ); //创建一个叫test的表 mysql>show create table test; //显示刚才创建的表信息 mysql> select * from test; //查询test表中数据 mysql>quit 然后用如下cpp代码连接

C++ STL Algotithms 学习笔记

·1207 words·3 mins
迫于拙劣的cpp水平,这次来记录一些关于STL算法部分的内容。 参考内容是CS106L的course reader Iterator Categories # Iterators分为以下五种: Output Iterators:可以使用 ++;可以用 *myItr = value,不能用 value = *myItr Input Iterators:可以使用 ++;可以用 value = *myItr,不能用 *myItr = value Forward Iterators:可以使用 ++,可以同时用 value = *myItr 和 *myItr = value Bidirectional Iterators:比起 Forward Iterator 多了 --,但是不能 + 或者 += Random-Access Iterators:比起 Bidirectional Iterators 多了 + 和 += Algorithm Naming Conventions # 一些关于STL Algorithm的命名规则