本文重点介绍C/C++源码工程的编译链接,编译器gcc/g++的安装配置略过...
1. 安装配置gcc g++
2. 创建文件 test.h /test.c / file.h / file.cpp
3. 编译.o库: gcc -c / g++ -c
链接生成静态库.a库: ar -r
链接生成动态库.soK库:gcc -shared -o/ g++ -shared -o
编译可执行程序并链接.a或.so 库 g++ -o file file.cpp -L. -ltest / gcc -o test test.c -L. -lfile
运行可执行程序 ./file / ./test
note:l指定库名称,优先链接so动态库,没有动态库再链接.a静态库;
如果链接的是静态库就可以直接运行了,如果链接的是动态库可能会提示:./cppmain: error while loading shared libraries: libCAdd.so: cannot open shared object file: No such file or directory,是因为Linux系统程序和Windows不一样,Linux系统只会从系统环境变量指定的路径加载动态库,可以把生成的动态库放到系统目录,或者执行export LD_LIBRARY_PATH=./设置当前路径为系统链接库目录就可以了。
3.1 编译 C调C++库
a. 编译C++ .o 库: g++ -c file.cpp
b. 链接生成静态 .a库: ar -r libfile.a file.o
c. 编译C文件并链接 .a库生成可执行程序: gcc -o test test.c -L. -llibfile
d. 运行可执行程序: ./test
3.2 编译C++调C库
a. 编译C .o库: gcc -c test.c
b. 链接生成静态.a 库: ar -r libtest.a test.o
c. 编译C++文件并链接.a 库生成可执行程序: g++ file file.cpp -L. -llibtest
d. 运行可执行程序: ./file
4. 查看符号表:
$ nm test.o
0000000000000000 T test
$ nm test1.o
0000000000000000 T _Z4testiPc
C语言编译后的函数符号还是原函数名,而C++编译后的函数符号由test变成了_Z4testiPc,test前面有个数字4应该是函数名长度,test后面i Pc应该就是函数的参数签名。C++之所以这样规定编译后的函数符号是因为对面对象的C++具有函数重载功能,以此来区分不同的函数。
5. linux下的.o .a .so
.o,是目标文件,相当于windows中的.obj文件
.a为静态库,是好多个.o合在一起,用于静态连接
.so 为共享库,是shared object,用于动态连接的,相当于windows下的dll
程序的运行都要经过编译和链接两个步骤。假如文件test.c,使用命令gcc -c test.c进行编译,生成test.o中间文件,使用命令ar -r libtest.a test.o可以生成libadd.a静态库文件。静态库文件其实就是对.o中间文件进行的封装,使用nm libtest.a命令可以查看其中封装的中间文件以及函数符号。
链接静态库就是链接静态库中的.o文件,这和直接编译多个文件再链接成可执行文件一样。
动态链接库是程序执行的时候直接调用的“插件”,使用命令gcc -shared -o libtest.so test.c生成so动态库。
动态库链接的时候可以像静态库一样链接,告诉编译器函数的定义在这个静态库中(避免找不到函数定义的错误),只是不把这个so打包到可执行文件中。如果没有头文件的话,可以使用dlopen/dlsum函数手动去加载相应的动态库
6.linux下的Makefile编写:
6.1 纯C或纯C++文件:
test: test.o test1.o test2.o
gcc test.o test1.o test2.o -o libtest #-o链接成可执行程序
test.o: test.c
gcc -c test.c -o test.o #加-c 指定生成为可重链接.o文件
test1.o: test1.c
gcc -c test1.c -o test1.o
test2.o: test2.c
gcc -c test2.c -o test2.o
.PHONY:clean
clean:
-rm -rf *.o libtest
每个命令行前必须要有tab符号(如Makefile中书写方法);
上面的Makefile文件就是要编译出一个libtest的可执行文件;
test:test.o test1.o test2.o :test依赖于test.o test1.o、test2.o三个目标文件;
gcc test.o test1.o test2.o -o libtest:编译出可执行文件libtest, -o表示指定可执行文件的名称;
test.o: test.c: test.o 依赖于 test.c 文件;
gcc -c test.c -o test.o 编译出test.o文件,-c表示只把给它的文件编译成目标文件,用源码文件的文件名命名,但把其后缀由“.c”变成“.o”;也可以省略 -o test.o ,编译器默认生成test.o
clean:
rm -rf *.o firstTest:当键入make clean的时候,会删除所有.o文件和libtest文件
如果要编译c++文件,把gcc改成g++即可。如果一行写的内容过多,可以用“\”来分解多行,注意“\”后面不加空格.
6.2 C/C++混合编译:
CC = gcc
C++ = g++
LINK = g++
#LIBS = -lz -lm -lpcre(#如果还要链接其他库如libz、libm、libpcre等,加上这句)
#must add -fPIC option
CCFLAGS = $(COMPILER_FLAGS) -c -g -fPIC
C++FLAGS = $(COMPILER_FLAGS) -c -g -fPIC
TARGET=libtestmain
INCLUDES = -I. -I../../
C++FILES = testmain.cpp
CFILES = test.c test1.c test2.c
OBJFILE = $(CFILES:.c=.o) $(C++FILES:.cpp=.o)
all:$(TARGET)
$(TARGET): $(OBJFILE)
$(LINK) $^ $(LIBS) -Wall -fPIC (编so加 -shared)-o $@
%.o:%.c
$(CC) -o $@ $(CCFLAGS) $< $(INCLUDES)
%.o:%.cpp
$(C++) -o $@ $(C++FLAGS) $< $(INCLUDES)
install:
tsxs -i -o $(TARGET)
clean:
rm -rf $(TARGET)
rm -rf $(OBJFILE)
上面的Makefile是实现编译C文件编译成.o,然后一起连接到cpp编译的.o(或.so)上编译出可执行文件;
note:
a.如果LIBS的位置放置不对,这几个基础库将不会编进so中。LIBS只应该在最后链接为so时才调用,前面编译c和cpp文件时用不到。
b.c源文件放到CFILES宏后面, cpp文件放到C++Files宏后面,第三方库放到LIBS宏后面,头文件的包含路径放到INCLUDES后面,库文件的包含路径放到使用-L./等表达式放到LIBS中的开头即可。
c.这里严格区分c和cpp文件的目的是,c文件使用gcc编译,而cpp文件会使用g++编译,它们必须严格区分开。
以上示例代码:https://github.com/zhulinyu/mytest.git