1、编译器除了gcc、g++还有什么?常用编译选项&编译相关问题
答:linux中常用的还有EGCS 和 PGCC等编译器,最常用的肯定是gnu c compiler即GCC。
(0)链接器ld是一个命令,来源可能是“LoaDer”or “Link eDitor”。
ld命令:GNU链接器,将目标文件与库链接为可执行程序或库文件;格式为” ld [opt] <objfile...>”;
(1)-g:生成调试信息。
(2)-o:指定输出文件名。
(3)-E:只输出预编译结果→即生成.i文件
(4)-S:输出汇编代码。
(5)-c:只编译不链接,生成可重定位文件。
(6)-O:指定编译优化级。O0→O3,优化程度逐渐增强。
(7)-Wall:显示所有警告信息(Warning all)。
注:.o是目标文件、.a是静态库(理解为若干.o的打包)、.so是动态库(共享库)。
(8)-fPIC:(Position Independent Code)编译生成与位置无关代码——使.so文件的代码段变为真正意义上的共享。
(9)-shared:如果想创建动态链接库可以使用此选项结合上面的fPIC。
注:上面两个选项是创建动态链接库时候用的(编译可执行文件的时候不用)。
/*-----------生成一个so文件的实例------------------
* # -shared 为链接库 让编译器知道是要编译一个共享库
* # -fPIC(Position Independent Code) 编译生成代码与位置无关
*/
int max(int a,int b)
{
return a>b?a:b;
}
/*
* gcc -Wall -g -fPIC -c max.c -o max.o
* gcc -shared max.o -o max.so
* -g -Wall 供调试使用,不是必须的<br> * 或者<br> * gcc max.c -fPIC -shared -o max.so
*/
(10)-w:关闭所有警告,一般不建议使用。
(11)-Wl:是为了将后面的option传递给链接器。
(12)soname:影响一个可执行文件在链接器ld加载动态链接库时实际查找的动态库文件名。
C/C++:GCC/G++ -Wl,-soname 链接选项作用_test1280-CSDN博客
(13)“-I”(大写i),“-L”(大写l),“-l”(小写l)及其区别:
1)-I(大写的i):将后面的路径作为第一个寻找头文件的目录;
2)-L:指定链接的动态库/静态库路径(一般和下面的小写l共用),-L.表示当前目录;
比如把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L /aaa/bbb/ccc -ltest
gcc -I -L -l 区别_证心的博客-CSDN博客 (库文件名的头lib和尾.so去掉就是库名了)
3)-l(小写的l):指定需要链接的库的名字,-l参数紧接着就是库名(一般和上面的-L共用)。
2、库的命令规则:
(1)库名和库文件名不是一个东西。对静态库来说其库名为”zstest”,则库文件名就为libzstest.a。动态库的命令规则与静态库相同,不过其后缀名为”.so”。即库文件名称为”libzstest.so”,就可以知道库名称为“zstest”。(注:库名就是我们写编译语句g++时候所要引用的库的名称;库文件名就是这个库所对应的实实在在的文件的文件名)
(2)在实际使用中libxxx.so大多情况只是一个链接(软链),它链接到一个具体的包含版本信息的库文件libxxx.so.xx,例如”cd /usr/lib”可以看到很多这种例子。当然我们也可以自己使用ln命令来制作链接“ln -s libxxxx.so.xx libxxxx.so”。
(3)动态链接库路径。系统默认在/usr/lib和/usr/local/lib两个库目录搜索。自己定义的库先把要额外指定路径或者拷贝到这两个目录下。自己额外指定路径总共有三种方式:
1)将当前路径添加到/etc/ld.so.conf文件中或者/etc/ld.so.conf.d目录下的一个文件(推荐);
2)通过设置“LD_LIBRARY_PATH”环境变量。这个变量是告诉loader在哪些目录中可以找到共享库。例如在.bashrc或.cshrc增加:export LD_LIBRARY_PATH = /usr/local/gcc9/lib64:$LD_LIBRARY_PATH
3)通过编译选项-Wl,-rpath执行动态搜索的路径。
一般推荐使用第一种方法,操作方法如下:
检查 /etc/ld.so.conf 文件,如果其中缺少 /usr/local/lib 目录,就添加进去。但是注意:在修改了 /etc/ld.so.conf文件或者在系统中安装了新的函数库之后,需要运行一个命令:ldconfig,该命令用来刷新系统的共享库缓存,即 /etc/ld.so.cache 文件。
(4)关于/etc/ld.so.conf。许多开放源代码的程序或函数都会默认将自己安装到/usr/local目录下的相应位置(如/usr/local/bin 或 /usr/local/lib),以便与系统自身的程序或函数库相区别。而许多 Linux 系统的/etc/ld.so.conf 文件中默认又不包含该目录。因而常常出现已经安装了共享库,但是却无法找到共享库的情况。
(5)ldconfig: 简单来讲两个作用。1)将添加在“/etc/ld.so.conf”文件的哪些目录下的动态库加载到内存(缓存cache中); 2)同时将“/etc/ld.so.conf”中的信息记一份到缓存文件“/etc/ld.so.cache”中。
(6)为什么有了“/etc/ld.so.conf”后还要有"/etc/ld.so.cache"?
答:/etc/ld.so.conf文件包含了一个所有目录的清单(lib和/usr/lib除外,这两个会自动包含其中),动态装入器将在其中查找共享库。但是我们必须将它转换到ld.so.cache中后动态装入器才能“看到”这一信息。这个转换操作就是通过ldconfig来实现的。也就是说为了减少共享库系统的库搜索时间,共享库系统维护了一个共享库 so 名称的缓存文件/etc/ld.so.cache。因此,在安装新的共享库之后一定要运行 ldconfig 刷新该缓存。
注:动态库存在版本不一致的问题,少用就对了。尤其是我们在205机器上编译可执行文件,207机器执行这个可执行文件的时候更要慎重。如果非要使用动态链接库的话要确保在执行这个文件的机器中实际链接的so确实是你编译的时候想用的那个so文件。
3、编译规则总结与示例
头文件:就是我们常说的.h文件
源文件:就是.cpp/.cc/.c文件
目标文件:由.cpp/.cc/.c编译得到,如"gcc -c hello.c"就得到 hello.o
静态库:一个或多个目标文件ar即得到静态库,如"ar -cr libmyhello.a hello.o"就得到libmyhello.a
动态库:由.o文件等经"-shared -fPIC"选项即可创建动态"gcc -shared -fPIC -o libmyhello.so hello.o"即可得到动态库文件libmyhello.so。
编译链接: gcc -o hello main.c -L. -lmyhello
/***************************************************************
其实所谓的gcc/g++编译它本身非常的简单,无非就是把该链接进来的都链接进来罢了。
链接的项无非是:
(1)源文件:直接把文件名填上去好了如hello_mongoc.c;
(2).o文件:目标文件,和源文件的引用一样.把完整的目标文件路径贴上去即可./update.o;
(3).a文件:就是静态库;引用方法两种皆可:
1)和源文件/目标文件一样把完整的静态库路径贴上去即可如/path/libtlist_api.a;
2)-L {静态库路径} -l{静态库名}形式引用
(4).so文件:就是动态库。其实和静态库差不多,可以通过选项参数链 也可以直接指定完整路径。
1)和源文件/目标文件一样把完整的静态库路径贴上去即可如/usr/bin/libcurl.so.4.5.0;/data/comm_code/install/lib64/libssl.so.1.0.0
2)稍微复杂点,引入格式是 "-L {动态库路径} -l{动态库名1} -l{动态库名2}"
1)注意这里的动态库名和动态库文件名的区别。动态库文件名=lib{动态库名}.so
2)动态库如果是在默认搜索路径的话就没这么多事,直接 -lmongoc-1.0 这种就可以了。
①默认搜索路径一般是 usr/local/lib usr/lib 等
②我们也可以通过 /etc/ld.so.conf 来添加动态库的搜索路径;
3)如果是动态库的话要求执行的机器上的库与编译机器的动态库完全一致,否则会不能执行;
****************************************************************/
(5)头文件:用如下所示的-I(大写I)把头文件路径包含进来即可;
#默认是这个样子的
gcc -o hello_mongoc hello_mongoc.c \
-I/usr/local/include/libbson-1.0 -I/usr/local/include/libmongoc-1.0 \
-lmongoc-1.0 -lbson-1.0
#保证如下路径有头文件和动态库文件后如下都是可以的
gcc -o hello_mongoc hello_mongoc.c \
-I/mystudy/mongodb -I/mystudy/mongodb \
-lmongoc-1.0 -lbson-1.0
#保证如下路径有头文件和动态库文件后如下都是可以的
gcc -o hello_mongoc hello_mongoc.c \
-I/mystudy/mongodb -I/mystudy/mongodb \
-L /mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc -lmongoc-1.0 \
-L /mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libbson -lbson-1.0
#直接指定东泰路的绝对路径按照元问及那的形式链也是完全可以的
g++ main_raw.cpp /usr/bin/libcurl.so.4.5.0 /data/comm_code/install/lib64/libssl.so.1.0.0 /data/comm_code/install/lib/libz.a -I/data/comm_code/install/include -o curl_raw
#如下为几个实例
g++ -I/data/comm_code/install/include read.cpp im_msg_body.pb.cc C2CType0x211_SubC2CType0x4.pb.cc conn_head.pb.cc hummer_resv_21.pb.cc TCPClient.cpp libtlist_api.a /data/comm_code/install/lib/libprotobuf.a -o reader
g++ -std=c++11 -o update_data ./update.o ./conn_head.pb.o ./C2CType0x211_SubC2CType0x4.pb.o ./hummer_resv_21.pb.o ./im_msg_body.pb.o ./TCPClient.o libtlist_api.a /data/comm_code/install/lib/libprotobuf.a
g++ -I/data/comm_code/install/include read.cpp im_msg_body.pb.cc TCPClient.cpp libtlist_api.a /data/comm_code/install/lib/libprotobuf.a -o reader
g++ -std=c++11 HttpClient.cpp cos_helper.cpp main.cpp TCPClient.cpp redis_helper.cpp spp_redis_helper.cpp ./lib/libhiredis.a -o test -I /data/comm_code/install/include/ -I ./include/hiredis/ -L /data/comm_code/install/lib64/ -lcurl -lssl -lcrypto
4、pkg-config详解(开源库的.pc文件)
1、什么是pkg-config
pkg-config是linux下的命令,用于获得某一个库/模块的所有编译相关信息。
首先我们可以执行“pkg-config --list-all”语句查看当前机器的pkg-config的所有模块信息,如下:
pkg-config --list-all
protobuf-lite Protocol Buffers - Google's Data Interchange Format
openssl OpenSSL - Secure Sockets Layer and cryptography libraries and tools
formw formw - ncurses 5.9 add-on library
xcb-dri2 XCB DRI2 - XCB DRI2 Extension
kbproto KBProto - KB extension headers
xcb-composite XCB Composite - XCB Composite Extension
zlib zlib - zlib compression library
libselinux libselinux - SELinux utility library
protobuf Protocol Buffers - Google's Data Interchange Format
………………
然后我们就可以针对已经存在的模块看下这里面究竟包括了什么信息,如下:
[root@VM_50_94_centos /usr/local/include]# pkg-config protobuf --libs --cflags
-pthread -I/usr/local/include -L/usr/local/lib -lprotobuf
#或者分别展示libs、cflags也是可以的
[root@VM_50_94_centos /usr/local/include]# pkg-config protobuf --libs
-L/usr/local/lib -lprotobuf
[root@VM_50_94_centos /usr/local/include]# pkg-config protobuf --cflags
-pthread -I/usr/local/include
#后面会演示引用别人的libmongoc-static-1.0.pc文件
[root@VM_50_94_centos /usr/local/include]# pkg-config libmongoc-static-1.0 --cflags
-DMONGOC_STATIC -DBSON_STATIC -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0
2、为什么要有pkg-config
从上面的例子可以看出,pkg-config给出了protobuf、libmongoc-static-1.0等的头文件和库依赖的关系信息。这带来的好处就是:
所有用到libmongoc-static-1.0的其他程序在编译的时候只需要串上“pkg-config libmongoc-static-1.0 --cflags”就不在需要自己去找libmongoc-static-1.0的头文件在哪里、要依赖哪些链接库以及这些链接库分别在哪里了。省时省力!!
所以说一般情况下我们引入供第三方使用的库的时候不管是动态库还是静态库都会有对应的pc文件,这样使用者就不用自己手动写你的这个库依赖于哪些库,只需要一段“pkg-config [YOUR_LIB] –libs –cflags”就包括全部了。
3、pkg-config的信息从哪儿来?
总共有两种途径:
(1)取系统的/usr/lib/pkgconfig下的所有*.pc文件。如下:
(2)另外就是PKG_CONFIG_PATH环境变量所指向的路径下的所有*.pc文件。
这个添加的方法就是常规的修改环境变量的方法了,参照这里。
运行或者说引用的时候pkg-config工具将按照设置路径的先后顺序进行搜索,直到找到指定的.pc文件为止。
4、*.pc文件解析
我们知道第三方库的使用主要涉及头文件路径的设置,库的路径设置以及动态库的环境变量设置。前面也提到一般情况下第三方库都会提供一个.pc文件,pkg-config程序通过读取这个*.pc文件就可以获取库的头文件位置和依赖的库的信息;然后告知编译器,进而实现库的自动化使用。一般来讲*.pc文件的大体格式如下:
-
prefix:
一般是指定库的默认安装路径 -
exec_prefix:
一般是指库的另外指定的安装路径 -
inludedir:
指定库的头文件路径 -
libdir:
指定库的lib文件的路径 -
Name:
指定库的名称,比如笔者使用的SQLite数据库 -
Description:
表示库的描述 -
Version:
是版本号 -
Cflags:
是gcc链接头文件的指令,以-I
紧接头文件路径设置 -
Libs:
是gcc链接lib文件的指令, 是-L
紧接lib文件路径,-l
紧接所使用的lib的名字。
5、pkg-config命令
可以使用pkg-config -help来查看,但实际上有用的参数最上面已经演示过了。
#查看pkg-config的所有模块信息
pkg-config --list --all
#查看头文件信息
pkg-config [NAME] –cflags
#查看库信息
pkg-config [NAME] –libs
6、如何引用第三方库的pc文件
就是上面第3步中的两个方法。这里我修改了/etc/profile文件,完事后记得 source /etc/profile 才生效。
例子1:动态库的pc文件
假设写了libfoo.so,库会被安装到/usr/local/lib/,头文件会放到/usr/local/include/foo。那么,pc文件可以这么写。
prefix=/usr/local
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib
Name: foo
Description: The foo library
Version: 1.0.0
Cflags: -I${includedir}/foo
Libs: -L${libdir} -lfoo
例子 2:静态库的pc文件
这里有个非常值得注意的点,那就是我们该如何使用一个链接其他动态库的静态库。强烈推荐 这篇文章 好好看看。
这里说一下结论。如果我有个静态库libXXX.a,它依赖了很多其他动态库libAA.so,libBB.so,那么第三方程序main.c要使用libXXX.a时,编译时还得链接libAA.so,libBB.so(即编译的时候需要指定这些so)。
如何让第三方程序可以不用操心我的这个libXXX.a到底依赖了什么?很简单,就是为这里的libXXX.a写一个.pc文件。
我自己在尝试使用mongo的静态库(libmongoc-static-1.0.a/libbson-static-1.0.a)编译一个可执行文件的时候就遇到了这个问题。报错见末尾附录,总的来讲全是未定义的引用。
gcc -o hello_mongoc hello_mongoc.c -I/mystudy/mongodb \
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a \
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libbson/libbson-static-1.0.a
最开始我的困惑和这篇文章的作者是一样的,那就是这里利用的是编译好了的.a文件,和pthread_join、pthread_once为什么还会有关系呢?pkg-config 详解_newchenxf的专栏-CSDN博客_pkg-config
答案就是前面讲的 第三方程序还是要链接其引用的静态库所依赖的那些动态库的。
那现在问题又来了一个个的手动添加.a依赖的库不得累死了?好在mongo的第三方库也提供了.pc文件。
于是我们只要这样就可以了,如下:
#其实就是把pkg-config --libs --cflags libmongoc-static-1.0的内容串到gcc后面
gcc -o hello_mongoc hello_mongoc.c $(pkg-config --libs --cflags libmongoc-static-1.0)
当然,我们也可以打开pc文件或者将pkg-config --libs --cflags libmongoc-static-1.0的输出直接串在gcc后面,如下:
#首先输出依赖信息
[root@VM_50_94_centos /mystudy/mongodb]# pkg-config --libs --cflags libmongoc-static-1.0
-DMONGOC_STATIC -DBSON_STATIC -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0 -pthread /usr/lib64/librt.so /usr/lib64/libm.so -L/usr/local/lib64 -lmongoc-static-1.0 -lssl -lcrypto -lrt -lresolv -lz -lbson-static-1.0
#把依赖信息串到gcc后面
gcc -o hello_mongoc hello_mongoc.c -DMONGOC_STATIC -DBSON_STATIC -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0 -pthread /usr/lib64/librt.so /usr/lib64/libm.so -L/usr/local/lib64 -lmongoc-static-1.0 -lssl -lcrypto -lrt -lresolv -lz -lbson-static-1.0
5、Linux中的./configure、make、make install
Linux环境下载源码进行编译和安装的步骤通常就是./configure、make、make install。其实上述指令是使用GNU的AUTOCONF和AUTOMAKE产生的程序的典型的安装步骤。
对于configure可能还是有一些可选参数的,可以通过-h来查看。
0、GNU build system
上述软件编译和安装的框架其实是有一套标准的,即GNU项目提出的GNU build system。GNU Build System指的是这样一种源码编译系统:它符合GNU Coding Standards标准,有configure脚本、Makefile脚本等,并且这些脚本遵循一定的最小接口规范,使得用户可以使用一些简单的命令(如:./configure,make,make install)在不同的系统架构上编译并安装GNU工程。
为了让你的源码实现这样的标准(即使用你的源码的人也可以轻松地在他的电脑上从简单的命令编译和安装你写的软件),除了自己手写configure和Makefile.in脚本之外还有更简单的方法。就是使用Autotools来帮助你从一堆源码中生成脚本。
Autotools就是一系列帮助开发人员建立GNU Build System的开发套件。用于自动编译源码并实现类Unix系统间的可移植性。这个工具出现的原因是因为软件的可移植性面临巨大的挑战:系统间的C编译器不同、库函数不兼容等。如果简单使用预编译指令(#ifdef)来为不同的系统指定专用的代码块,那么由于开发环境的差别实现是太大了,就要求开发人员需要有很全面的技术知识,实现起来十分困难。Autotool的目的就是为了解决这一难题。当然,前面也说到可以通过自己写configure和Makefile.in脚本来克服这种移植性问题(许多牛人就是这么干的)。
automake和autoconf就是为一组源码建立一个可移植的Makefile系统的工具。
1、三个指令
(1)、./configure用来检测安装平台的目标特征生成Makefile文件。
Linux平台有不同的配置,这些需要通过configure来确定。比如说编译器是cc还是gcc、不同库文件所在的目录等。执行configure后还会生成Makefile文件,Makefile文件则规定了用什么编译器以及编译参数等。configure是一个shell脚本。我们可以通过在configure后加上参数来对安装进行控制,比如./configure –prefix=/usr 意思是将该软件安装在 /usr 下面,执行文件就会安装在 /usr/bin(而不是默认的 /usr/local/bin)。同时一些软件的配置文件你可以通过指定 –sys-config= 参数进行设定。有一些软件还可以加上 –with、–enable、–without、–disable 等等参数对编译加以控制,你可以通过允许 ./configure –help 察看详细的说明帮助。
(2)、make 就是读取Makefile中的指令进行编译。
(3)、make install是用来安装的。他也是读取Makefile的指令,安装到指定的位置。
6、常用工具指令
(1)查看可执行文件的库依赖——ldd
使用ldd可以查看可执行文件的库依赖(不确定引用到哪些库的时候还是非常有用的)
/etc/ld.so.conf 文件中包含有默认的共享库搜索路径,要研究下。linux-->ldd命令的介绍_Hitvz的博客-CSDN博客_ldd命令
ldd:列出动态库依赖关系(list dynamic dependencies)
注:对于找不到的库会出现 not found。
(2)objdump查看依赖哪些库(效果和ldd其实差不多)
objdump -x libcurl.so.4.5.0 | grep NEEDED
objdump -x libcurl.so.4.5.0 > objdump.txt
(3)列出动态库、静态库的符号信息 —— nm
nm不是ni mei,也不是ni ma; 是names的缩写。
使用方法如下:
查看libXXX.a到底有没有把pthread_create函数的实现打包进来。
U表示仅仅调用而没有定义,也就是说该静态库并不独立,而是依赖于其他库(这里就是libpthread.so)。
[root@VM_50_94_centos /mystudy/mongodb]# gcc -o hello_mongoc hello_mongoc.c -I/mystudy/mongodb \
> /mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a \
> /mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libbson/libbson-static-1.0.a
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-client.c.o): In function `_mongoc_get_rr_search':
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-counters.c.o): In function `_mongoc_counters_cleanup':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-counters.c:141: undefined reference to `shm_unlink'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-counters.c.o): In function `mongoc_counters_alloc':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-counters.c:177: undefined reference to `shm_open'
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-counters.c:204: undefined reference to `shm_unlink'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-init.c.o): In function `mongoc_init':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-init.c:157: undefined reference to `pthread_once'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-init.c.o): In function `mongoc_cleanup':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-init.c:202: undefined reference to `pthread_once'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-log.c.o): In function `mongoc_log_set_handler':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-log.c:53: undefined reference to `pthread_once'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-log.c.o): In function `mongoc_log':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-log.c:81: undefined reference to `pthread_once'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(common-b64.c.o): In function `_mongoc_common_bson_b64_pton':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/common/common-b64.c:526: undefined reference to `pthread_once'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(common-thread.c.o): In function `_mongoc_common_thread_create':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/common/common-thread.c:24: undefined reference to `pthread_create'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(common-thread.c.o): In function `_mongoc_common_thread_join':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/common/common-thread.c:28: undefined reference to `pthread_join'
/mystudy/mongodb/mongo-c-driver-1.17.1/cmake-build/src/libmongoc/libmongoc-static-1.0.a(mongoc-rand-openssl.c.o): In function `_mongoc_rand_bytes':
/mystudy/mongodb/mongo-c-driver-1.17.1/src/libmongoc/src/mongoc/mongoc-rand-openssl.c:31: undefined reference to `RAND_bytes'