Linux 动态库和静态库
七月 19, 2025
次阅读
静态库创建
我们先设计一个简单的头文件及实现方法:
// mymath.h
#ifndef _MY_MATH_H_
#define _MY_MATH_H_ 1
#include <iostream>
extern int my_errno;
int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int divi(int x, int y);
#endif
// mymath.cc
#include "mymath.h"
int my_errno = 0;
int add(int x, int y) { return x + y; }
int sub(int x, int y) { return x - y; }
int mul(int x, int y) { return x * y; }
int divi(int x, int y)
{
if(y == 0){
my_errno = 1;
return -1;
}
return x / y;
}
通过 makefile 实现库的封装:
lib=libmymath.a
$(lib):mymath.o
ar -rc $@ $^
mymath.o:mymath.cc
g++ -c $^
.PHONY:clean
clean:
rm -rf *.o *.a
output:
mkdir -p ./lib/include
mkdir -p ./lib/mymathlib
cp *.h ./lib/include
cp *.a ./lib/mymathlib
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ make 2 ↵
g++ -c mymath.cc
ar -rc libmymath.a mymath.o
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ make output
mkdir -p ./lib/include
mkdir -p ./lib/mymathlib
cp *.h ./lib/include
cp *.a ./lib/mymathlib
这样一来,静态库就被存放到了 ./lib/mymathlib 下面,接下来我们写一段代码试一试能不能将该库使用起来:
#include <iostream>
#include "mymath.h"
int main()
{
int n = divi(10, 0);
std::cout << n << ", errno: " << my_errno << std::endl;
return 0;
}
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ g++ -o main.o main.cc
/usr/bin/ld: /tmp/ccD6e3Zl.o: warning: relocation against `my_errno' in read-only section `.text'
/usr/bin/ld: /tmp/ccD6e3Zl.o: in function `main':
main.cc:(.text+0x13): undefined reference to `divi(int, int)'
/usr/bin/ld: main.cc:(.text+0x48): undefined reference to `my_errno'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
编译器无法找到我们定义的函数,这是因为我们并没有指定我们的文件所在路径,于是我们加上 -I选项 从而指定我们的头文件所在路径
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ g++ -o main.o main.cc -I ./lib/include/
/usr/bin/ld: /tmp/cc3M4mQd.o: warning: relocation against `my_errno' in read-only section `.text'
/usr/bin/ld: /tmp/cc3M4mQd.o: in function `main':
main.cc:(.text+0x13): undefined reference to `divi(int, int)'
/usr/bin/ld: main.cc:(.text+0x48): undefined reference to `my_errno'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
但是我们并没有告诉编译器我们的动态库在哪里,于是我们通过 -L 指定库路径,通过 -l 指定库名:
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ g++ -o main.o main.cc -I ./lib/include/ -L ./lib/mymathlib/ -lmymath
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ./main.o
-1, errno: 1
可以看到,这么一来,静态库就被我们调用起来了,需要注意的是,库名指定是需要去掉前缀(lib)和后缀(.a)的,且建议将 -l 和库名写在一起
而若我们直接将对应的头文件和库文件链接到系统当中,就可以直接使用该头文件了,但需要注意的是,我们仍然需要指定库名,毕竟你这也不是原生库,编译器是不知道你这个库在哪里的
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ sudo ln -s /home/ljx/linux_review/dy_st_lib/lib/mymathlib/libmymath.a /lib64/libmymath.a
# 检查是否链接成功
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ll /lib64/libmymath.a
lrwxrwxrwx 1 root root 58 Jul 19 17:45 /lib64/libmymath.a -> /home/ljx/linux_review/dy_st_lib/lib/mymathlib/libmymath.a
# 检查是否链接成功
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ sudo ln -s /home/ljx/linux_review/dy_st_lib/lib/include/mymath.h /usr/include/mymath.h
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ll /usr/include/mymath.h
lrwxrwxrwx 1 root root 53 Jul 19 17:46 /usr/include/mymath.h -> /home/ljx/linux_review/dy_st_lib/lib/include/mymath.h
然后我们就可以直接编译该代码了:
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ g++ -o main.o main.cc -lmymath
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ./main.o
-1, errno: 1
动态库创建
同样,先设计一个简单的头文件和实现方法
mylog 方法
// mylog.h
#ifndef _MYLOG_H_
#define _MYLOG_H_ 1
#include <iostream>
#include <chrono>
#include <ctime>
void mylog(const char *s);
#endif
//mylog.cc
#include "mylog.h"
void mylog(const char *s)
{
// 获取当前时间点
auto now = std::chrono::system_clock::now();
// 转换为time_t类型
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
// 转换为本地时间
std::tm* local_time = std::localtime(&now_time);
std::cout << std::asctime(local_time) << ": " << s << std::endl;
}
myprint 方法
// myprint.h
#ifndef _MYPRINT_H_
#define _MYPRINT_H_ 1
#include <iostream>
void print(const char *s);
#endif
// myprint.cc
#include "myprint.h"
void print(const char *s)
{
std::cout << s << std::endl;
}
我们同样通过 makefile 实现对动态库的封装
static_lib=libmymath.a
dynamic_lib=libmymethod.so
.PHONY:all
all:$(static_lib) $(dynamic_lib)
$(static_lib):mymath.o
ar -rc $@ $^
mymath.o:mymath.cc
g++ -c $^
$(dynamic_lib):mylog.o myprint.o
g++ -fPIC -shared -o $@ $^
mylog.o:mylog.cc
g++ -fPIC -c $^
myprint.o:myprint.cc
g++ -fPIC -c $^
.PHONY:clean
clean:
rm -rf *.o *.a *.so mylib
output:
mkdir -p ./mylib/include
mkdir -p ./mylib/lib
cp *.h ./mylib/include
cp *.a ./mylib/lib
cp *.so ./mylib/lib
需要注意的是,编译动态库是需要与位置无关码的
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ make
g++ -c mymath.cc
ar -rc libmymath.a mymath.o
g++ -fPIC -c mylog.cc
g++ -fPIC -c myprint.cc
g++ -fPIC -shared -o libmymethod.so mylog.o myprint.o
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ make output
mkdir -p ./mylib/include
mkdir -p ./mylib/lib
cp *.h ./mylib/include
cp *.a ./mylib/lib
cp *.so ./mylib/lib
下面是测试代码:
#include <iostream>
#include "mymath.h"
#include "mylog.h"
#include "myprint.h"
int main()
{
int n = divi(10, 0);
std::cout << n << ", errno: " << my_errno << std::endl;
mylog("hello, linux!");
print("hello, dynamic library!");
return 0;
}
我们尝试编译:
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ g++ -o main.o main.cc -I ./mylib/lib/include/ -L ./mylib/lib/ -lmymath -lmymethod
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ./main.o
./main.o: error while loading shared libraries: libmymethod.so: cannot open shared object file: No such file or directory
我们会发现,程序加载是需要静态库的,而我们并没有指定静态库所在路径,以下是指定静态库路径的四种方法
1、将动态库拷贝到 /lib64 路径下
该方法和软链接相似,因此不做示例演示
2、将动态库软链接到 /lib64 路径下
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ sudo ln -s /home/ljx/linux_review/dy_st_lib/mylib/lib/libmymethod.so /usr/lib/libmymethod.so
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ll /usr/lib/libmymethod.so
lrwxrwxrwx 1 root root 57 Jul 19 22:56 /usr/lib/libmymethod.so -> /home/ljx/linux_review/dy_st_lib/mylib/lib/libmymethod.so
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ./main.o
-1, errno: 1
Sat Jul 19 22:56:40 2025
: hello, linux!
hello, dynamic library!
3、将环境变量导入 LD_LIBRARY_PATH
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ export LD_LIBRARY_PATH=/home/ljx/linux_review/dy_st_lib/mylib/lib:$LD_LIBRARY_PATH
╭─ljx@VM-16-15-debian ~/linux_review/dy_st_lib
╰─➤ ./main.o
-1, errno: 1
Sat Jul 19 22:58:28 2025
: hello, linux!
hello, dynamic library!
4、将路径写入 /etc/ld.so.conf.d/ 目录下的任意一个文件当中,然后 ldconfig
查看评论