照着https://www.cnblogs.com/oxspirt/p/7344371.html这篇文章做了一个小实验,以下是我的笔记整理。关于动态库还有一些疑惑,再次也记录一下。
gcc几个参数的功能:
-I dir :将目录dir添加到要搜索头文件的目录列表中,且搜索顺序优先于系统库。(在你使用 #include “file” 的时候, gcc/g++ 会先在当前目录查找你所制定的头文件, 如果没有找到, 他回到默认的头文件目录找, 如果使用 -I 制定了目录,他会先在你所指定的目录查找, 然后再按常规的顺序去找。对于 #include, gcc/g++ 会到 -I 制定的目录查找, 查找不到, 然后将到系统的默认的头文件目录查找 。此时如果找不到头文件会在编译期报错)
-Ldir :增加该目录到能够被-l搜索到的列表中。(Add directory dir to the list of directories to be searched for -l.指定编译的时候,搜索库的路径。比如你自己的库,可以用它指定目录,不然编译器将只在标准库的目录找。这个dir就是目录的名称。)
-l library:链接时搜索名为library的库。(如果没有找到该名称的库则会在链接时报错。注意不是编译时了,这是已经通过了编译,在链接阶段找函数实现时,发现找不到)
示例
三个程序放在文件夹~/testso中
程序1: hello.h
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif
程序2:hello.c
#include <stdio.h>
void hello(const char *name) {
printf("Hello %s!\n", name);
}
程序3:main.c
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
问题的提出
注意:这个时候,我们编译好的hello.o是无法通过gcc –o 编译的,这个道理非常简单,
hello.c是一个没有main函数的.c程序,因此不够成一个完整的程序,如果使用gcc –o 编译并连接它,GCC将报错(undefined reference to `main’)。
==无论静态库,还是动态库,都是由.o文件创建的。==因此,我们必须将源程序hello.c通过gcc先编译成.o文件。
这个时候我们有三种思路:
1) 通过编译多个源文件,直接将目标代码合成一个.o文件。
2) 通过创建静态链接库libmyhello.a,使得main函数调用hello函数时可调用静态链接库。
3) 通过创建动态链接库libmyhello.so,使得main函数调用hello函数时可调用静态链接库。
思路一:编译多个源文件
[root@192 testso]# gcc -c hello.c
[root@192 testso]# gcc -c main.c
[root@192 testso]# gcc -o hello hello.o main.o
[root@192 testso]# ls
hello hello.c hello.h hello.o main.c main.o
[root@192 testso]# ./hello
hello everyone!
gcc -c 代表汇编生成.o文件后就停止,不进行最后一步的链接。
思路二:静态链接库
[root@192 testso]# ls
hello.c hello.h main.c
[root@192 testso]# gcc -c hello.c
[root@192 testso]# ar rcs libmyhello.a hello.o
[root@192 testso]# ls //可以看到这里我们的静态库已经制作完毕
hello.c hello.h hello.o libmyhello.a main.c
//-L.代表着我们对于myhello的搜索位置是当前目录,也就是我们libmyhello.a的位置是当前目录,如果将其移动到其他的目录中,这个-L<dir>应该随之修改。
[root@192 testso]# gcc -o hello main.c -static -L. -lmyhello
[root@192 testso]# ./hello
hello everyone!
我在运行 gcc -o hello main.c -static -L. -lmyhello这个命令时报错:/usr/bin/ld: 找不到 -lc,原因是在新版本的linux 系统下安装 glibc-devel、glibc和gcc-c++时,都不会安装libc.a. 只安装libc.so. 所以当使用-static时,libc.a不能使用。只能报找不到libc了。解决方式:安装 glibc-static sudo yum install glibc-static(参考https://blog.csdn.net/whatday/article/details/99421837)
思路三、动态链接库(共享函数库)
[root@192 testso]# ls
hello.c hello.h main.c
[root@192 testso]# gcc -shared -fPIC -c hello.c
[root@192 testso]# ls
hello.c hello.h hello.o main.c
[root@192 testso]# gcc -shared -fPIC -o libmyhello.so hello.o
[root@192 testso]# ls
hello.c hello.h hello.o libmyhello.so main.c
[root@192 testso]# gcc -o hello main.c -L. -lmyhello
./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory
错误提示,找不到动态库文件libmyhello.so。程序在运行时,会查找需要的动态库文件,顺序参考后文介绍。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。有多种方法可以解决,(这里我试了三种方式,从头到尾做了一遍,才能够正常运行程序,目前也不太理解)
(1)我们将文件 libmyhello.so复制到目录/usr/lib中,再试试。
$ sudo mv libmyhello.so /usr/lib
(2)既然连接器会搜寻LD_LIBRARY_PATH所指定的目录,那么我们可以将这个环境变量设置成当前目录:
export LD_LIBRARY_PATH=$(pwd)
(3)sudo ldconfig ~/testso
注: 当用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下”ldconfig 目录名”这个命令。此命令的功能在于让ldconfig将指定目录下的动态链接库被系统共享起来,意即:在缓存文件/etc/ld.so.cache中追加进指定目录下的共享库.本例让系统共享了~/tests目录下的动态链接库。
搜索路径
目前还不太懂,先记下来把,日后再看。
静态库链接时搜索路径顺序:
ld会去找GCC命令中的参数-L
再找gcc的环境变量LIBRARY_PATH
再找内定目录 /lib /usr/lib /usr/local/lib 这是当初compile gcc时写在程序内的
动态链接时、执行时搜索路径顺序:
编译目标代码时指定的动态库搜索路径;
环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
配置文件/etc/ld.so.conf中指定的动态库搜索路径;
默认的动态库搜索路径/lib;
默认的动态库搜索路径/usr/lib。