OVERVIEW
- 1.编译动态链接库
- (1)编译动态库
- (2)链接动态库
- (3)运行时使用动态库
- 2.编译静态链接库
- (1)编译静态库
- (2)链接静态库
- (3)运行时使用静态库
- 3.make install
1.编译动态链接库
动态链接库:不会把代码编译到二级制文件中,而是在运行时才去加载,所以只需要维护一个地址即可,
动态库编译完成之后需要发布,否则程序运行时找不到,
windows环境下动态库为.dll、linux环境下动态库为.so
-
编译成
.o
文件:g++ -c -fpic soTest.cpp -o soTest.o
-
编译动态库:
g++ -shared soTest.o -o libsoTest.so
- -c:得到二进制文件aTest.o
- -shared:共享
- -fPIC:产生位置无关的代码,
- -l:小写l,指定动态库,
- -L:手动指定库文件搜索目录,默认只链接共享目录,
- -I:大写i,指定头文件目录(默认当前目录),
-
链接成执行文件:
g++ [.cpp] -l [libName] -L [libPath] -o [test.out]
g++ soTest.cpp -shared -fPIC -o libsoTest.so
(1)编译动态库
文件目录结构如下,将其打包成动态库,
// soTest.h
#ifndef _SOTEST_H
#define _SOTEST_H#include <iostream>
using namespace std;class soTest {
public:void func1();virtual void func2();virtual void func3() = 0;
};#endif
// soTest.cpp
#include "soTest.h"void soTest::func1()
{cout << "this is func1" << endl;
}void soTest::func2()
{cout << "this is func2" << endl;
}
# makefile
libsoTest.so:$(CXX) soTest.cpp -shared -fPIC -L ./ -o libsoTest.so
clean:$(RM) libsoTest.so
使用make libsoTest.so 命令成功完成对 libsoTest.so
动态库的打包操作,
(2)链接动态库
在动态库成功打包出来之后,在其他项目中通过引入 soTest.h
与 libsoTest.so
文件,来使用打包好的动态库,
文件目录结构如下,将第三方动态库动态载入,编译自己的项目,
//test.cpp
#include <iostream>
#include "soTest.h"
using namespace std;class Test:public soTest{
public:void func2() {cout << "Test:this is func2" << endl;}void func3() {cout << "Test:this is func3" << endl;}
};int main() {Test t1;t1.func1();t1.func2();t1.func3();return 0;
}
# makefile
test:$(CXX) test.cpp -lsoTest -L ./ -I ./ -o test.out
clean:$(RM) *.out
使用make test 命令成功完成第三方动态库的链接,编译成功目录下出现 test.out
的可执行文件,
(3)运行时使用动态库
由于动态库的特点,若只在编译时使用的动态库,而运行时没有指定动态库位置,则程序将无法正常运行,
即动态库编译完成之后需要进行发布操作,否则程序运行时会找不到动态库位置而产生报错,如下所示:
./a.out: error while loading shared libraries: libsoTest.so: cannot open shared object file: No such file or directory
-
解决方案1:将动态库so文件拷贝到对应的目录下(发布),才能运行程序
-
linux下默认动态库路径配置文件:
/etc/ld.so.conf
、/etc/ld.so.conf.d/*.conf
-
/usr/lib
-
/usr/local/lib
-
-
解决方案2:运行时手动指定动态库的所在目录
mac环境:
DYLD_LIBARY_PATH=./your_lib_path
export DYLD_LIBARY_PATH
linux环境:
LD_LIBARY_PATH=./your_lib_path
export LD_LIBARY_PATH
2.编译静态链接库
静态链接库:会将库中的代码编译到二进制文件中,当程序编译完成后,该库文件可以删除,
与静态库不同的是,动态链接库必须与程序同时部署,还要保证程序能正常加载得到的库文件。静态库可以不用部署已经加载到程序中,而且运行时的速度更快,
但是会导致程序体积更大,并且库中的内容如果有更新,则需要重新编译生成程序,
windows环境下动态库为.lib、linux环境下动态库为.a
-
编译成
.o
文件:g++ -c aTest.cpp -o aTest.o
-
编译静态库:
ar -r libaTest.a aTest.o
- -c:得到二进制文件aTest.o
- ar:备份压缩命令,将目标文件打包成静态链接库,
- -r:将文件插入备存文件中,
-
链接成执行文件:
g++ [.cpp] [.a] -o [test.out]
g++ [.cpp] -l [libName] -L [libPath] -o [test.out]
(1)编译静态库
文件目录结构如下,将其打包成静态库,
// aTest.h
#ifndef _ATEST_H
#define _ATEST_H#include<iostream>
using namespace std;class aTest{
public:void func1();
};#endif
// aTest.cpp
#include "aTest.h"void aTest::func1()
{cout << "aTest:func1" << endl;
}
# makefile
libaTest.a:$(CXX) -c aTest.cpp -L ./ -I ./ -o aTest.o$(AR) -r libaTest.a aTest.o
clean:$(RM) *.a *.o
使用make libaTest.a 命令成功完成对 libaTest.a
静态库的打包操作,
(2)链接静态库
在静态库成功打包出来之后,在其他项目中通过引入 aTest.h
与 libaTest.a
文件,来使用打包好的静态库,
文件目录结构如下,将第三方静态库动态载入,编译自己的项目,
// test.cpp
#include <iostream>
#include "aTest.h"
using namespace std;int main() {aTest t1;t1.func1();return 0;
}
# makefile
test:$(CXX) test.cpp -laTest -L ./ -I ./ -o test.out
clean:$(RM) *.out
使用make test 命令成功完成第三方静态库的链接,编译成功目录下出现 test.out
的可执行文件,
(3)运行时使用静态库
由于静态库的特点,在编译时已经将库中的代码编译到二进制文件中,当编译完成后,该库文件可以删除,并且程序可以直接运行,
3.make install
-
make,编译链接:
将源文件,编译成二进制的可执行文件(包括各种库文件)
-
make install,配置相关的运行环境:
创建目录,将可执行文件拷贝到指定目录(安装目录)
加全局可执行的路径
加全局的启动停止脚本
-
make clean
重置编译环境,删除无关文件
TARGET:=my_test
OBJ:=$(TARGET).osCC:=g++PATHS:=/tmp/test/
BIN:=/usr/local/bin/START_SH:=$(PATHS)$(TARGET)
STOP_SH:=$(PATHS)$(TARGET)$(TARGET):$(OBJ)install:$(TARGET)if [ -d $(PATHS) ]; \then echo $(PATHS) exist; \else \mkdir $(PATHS); \cp $(TARGET) $(PATHS); \ln -sv $(PATHS)$(TARGET) $(BIN); \touch $(LOG); \chmod a+rwx $(LOG); \echo "$(TARGET)>$(LOG) & echo $(TARGET) running...">$(PATHS)$(START_SH); \echo "killall $(TARGET)">$(PATHS)$(START_SH); \chmod a+x $(PATHS)$(START_SH); \chmod a+x $(PATHS)$(STOP_SH); \ln -sv $(PATHS)$(START_SH) $(BIN); \ln -sv $(PATHS)$(STOP_SH) $(BIN); \fi;clean:$(RM) $(TARGET) $(OBJ) $(BIN)$(TARGET) $(BIN)$(START_SH) $(BIN)$(STOP_SH)$(RM) -rf $(PATHS).PHONY:clean install