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).os
CC:=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