1、gcc编译器
工作流程
预处理
hello.i
展开头文件
删除注释
宏处理gcc -E test.c -o test.i // -o表示输出到某个文件中去
编译器
hello.s
汇编文件gcc -S test.i -o test.s
汇编器
hello.o
二进制文件gcc -c test.s -o test.o
链接器
a.out
连接库 调用库函数
生成可执行文件gcc test.o -o test
一步生成可执行程序
gcc test.c -o test
gcc 常用参数
-v //参看gcc版本号 -E //生成预处理文件 -S //生成汇编文件 /*重要*/ -c //只编译 生成.o文件 通常称为目标文件** -o //指定生成的目标文件的名字** /*库文件参数*/ -I // 指定头文件所在的路径** -L // 指定库文件所在的路径** -l //指定库的名字** /*调试*/ -g //包含调试信息,使用gdb调试需要添加-g参数** /*其它*/ -On n=0~3 // 编译器自动优化 数字越大优化的越多
-D 编译时定义宏
代码
#include<stdlib.h> #include<unistd.h> int main( int argc, char *argv[]) { int a; int b; char *p; printf("this is main!\n"); printf("max==[%d]",MAX); #if printf("hello world\n"); #endif //sleep(10); return 0; }
//定义宏 gcc -D MAX=100 test.c -o test
2、静态库和动态(共享)库
库的基本概念
就是二进制的源代码文件
优点提高效率
保密如何使用
头文件–包含了库函数的声明
库文件–包含了库函数的代码实现分类
静态库
动态库
数据准备
head.h
//函数的声明 void fun1(); void fun2();
fun1.c
#include<stdio.h> void fun1() { printf("this is fun1\n"); }
fun2.c
#include<stdio.h> void fun2() { printf("this is fun2\n"); }
main.c
#include<stdio.h> #include<stdlib.h> #include"head.h" int main(int argc, char *argv[]) { printf("this is main!\n"); int i = 0; for(i=0;i<argc;i++) { printf("[%d]:[%s]\n",i,argv[i]); } fun1(); fun2(); return 0; }
结果
静态库
可执行程序运行前就已经加入到可执行程序中
前缀 lib
后缀 .a
例如 libtest.a
制作和使用静态库
步骤一:将库文件生成可执行文件.o
gcc -c fun1.c fun2.c
步骤二:打包成.a文件------库文件生成
ar rcs libtest1.a fun1.o fun2.o //ar 打包文件 //rcs 参数 r更新 c创建 s索引
步骤三:使用静态库 头文件所在路径 库文件所在路径 库文件名字
gcc -o main mian.c -I./ -L./ -l test1 //谁用谁需要加头文件 //-I: 指定头文件所在的路径** //-L: 指定库文件所在的路径** //-l 指定库的名字** libtest1.a 去掉前缀后缀 才是库文件的名字 test1
动态库
特点:
程序运行时被载入
优点
1、不同的应用程序 共享同一份库 避免了空间的浪费
2、**部署升级更新方便,**只需替代动态库后重启就行了
缺点
1、加载速度慢
2、移植性差
共享库的制作
1、生成目标文件.o 此时要加编译选项:-fpic
gcc -fpic -c fun1.c fun2.c
2、将.o文件编译成库文件:gcc -shared
gcc -shared fun1.o fun2.o -o libtest2.so
3、使用动态库,与静态库使用方式相同
gcc -o main2 main.c -I./include -L./lib -l test2 //-I: 指定头文件所在的路径** //-L: 指定库文件所在的路径** //-l 小L:指定库的名字** libtest1.a 去掉前缀后缀 才是库文件的名字 test1
加载器
查看可执行程序所依赖的库文件
file 文件名//查看文件类型 ldd 文件名//查看文件所依赖的库
需要知道所依赖库的文件,知道库文件的绝对路径。
解决方法如下:
如何让系统找到动态库
系统默认查找路径:
对于elf格式的可执行程序,是由ld-linux.so*完成的,它先后搜索elf文件的**DT_RPATH段** //1.程序中已确定了 --- 找不到(库文件移动) **环境变量LD_LIBRARY_PATH** //2. // .bashrc // echo $LD_LIBRARY_PATH **/etc/ld.so.cache 文件列表** //3.系统级别不建议采用 **/lib/, /usr/lib 目录** //4.系统目录不建议拷贝到此处
解决方法:
一、拷贝到 /usr/lib 目录二、环境变量LD_LIBRARY_PATH
1、临时设置(重启后消失)//添加环境变量 export LD_LIBRARY_PATH=$LD_LIBRARY_PAT:库文件路径 //查看环境变量 echo $LD_LIBRARY_PATH
$LD_LIBRARY_PAT: 表示追加
2、永久设置(开发时使用)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库文件路径//(库位路径一般设置到 /home/itcast/lib)
将上述代码设置到~/.bashrc文件中,
然后执行下列三种办法之一:
2.1 执行 . ~/.bashrc 使配置文件生效(第一个.后面有一个空格 该点为一个命令)
2.2 执行 source ~/.bashrc 配置文件生效
2.3 退出当前终端,然后在此登入也可以是配置文件生效3.永久设置
export LD_LIBRARY_PATH=export LD_LIBRARY_PATH:库文件路径 //设置到/etc/profile文件中
3、makefile
自动编译 工程化实现
1、用来管理项目工程文件,通过执行make命令,解析执行makefile文件
2、makefile 命名 :makefile或者 Makefile
makefile 基本规则
语法
目标:依赖
(tab) 命令三要素:
1、目标:要生成的目标文件
2、依赖: 目标文件由哪些文件生成
3、命令:通过执行该命令由依赖文件生成目标注释
makefile中用#
用列模式插入多行注释
makefile工作原理
执行顺序
是否更新
第一个样例(最简单的)
1、vi makefile
2、编写
语法:目标:依赖 (tab) 命令
案例:
main: main.c fun1.c fun2.c sum.c gcc -o main main.c fun1.c fun2.c sum.c
3、
make只用输入make就行了
缺点:
更改一个.c文件
所有都会重新编译
第二个样例(防止重复编译/部分函数更改时)
优点:
只编译改动过的文件main: main.o fun1.o fun2.o sum.o gcc -o main main.o fun1.o fun2.o sum.o main.o: main.c gcc -c main.c -I./ fun1.o: fun1.c gcc -c fun1.c fun2.o: fun2.c gcc -c fun2.c sum.o: sum.c gcc -c sum.c
缺点:
编写麻烦
makefile基本变量
类似于C语言中的宏定义
三种类型普通变量
自带变量
自动变量
普通变量
1、普通变量定义直接用 =
2、使用变量值用 $(变量名)foo = abc #定义变量名 bar = $(foo)#使用自定义变量名
自带变量
makefile 中提供了一些**变量(大写)**供用户使用
CC = gcc #arm-linux-gcc CPPFLAGS:C预处理的选项 -I CFLAGS: C编译器的选项 选项 说明 -c 用于把源码文件编译成 .o 对象文件,不进行链接过程 -o 用于连接生成可执行文件,在其后可以指定输出文件的名称 -g 用于在生成的目标可执行文件中,添加调试信息,可以使用GDB进行调试 -Idir 用于把新目录添加到include路径上,可以使用相对和绝对路径,“-I.”、“-I./include”、“-I/opt/include” -Wall 生成常见的所有告警信息,且停止编译,具体是哪些告警信息,请参见GCC手册,一般用这个足矣! -w 关闭所有告警信息 -O 表示编译优化选项,其后可跟优化等级0\1\2\3,默认是0,不优化 -fPIC 用于生成位置无关的代码 -v (在标准错误)显示执行编译阶段的命令,同时显示编译器驱动程序,预处理器,编译器的版本号 LDFAGS: 链接器选项 -L -l
自动变量
只能在规则中的命令使用
$@: 表示规则中的目标 $<:表示规则中的第一个条件 $^: 表示规则中的所有条件 自动去重
第三个样例(简化变量书写)
target = main
objects = main.o fun1.o fun2.o sum.o
CC = GCC
CPPFLAGS = -I./
$(target): $(objects)
$(CC) -o $@ $^
main.o: main.c
$(CC) -c $< $(CPPFLAGS)
fun1.o: fun1.c
$(CC) -c $<
fun2.o: fun2.c
$(CC) -c $<
sum.o: sum.c
$(CC) -c $<
makefile模式规则
main.o:main.c 可以看做 xxx.o:xxx.c
前后必须一致语法
%.o:%.c
第四个样例(减少重复书写)
target = main
objects = main.o fun1.o fun2.o sum.o
CC = GCC
CPPFLAGS = -I./
$(target): $(objects)
$(CC) -o $@ $^
%.o: %.c
$(CC) -c $< $(CPPFLAGS)
#fun1.o: fun1.c
# $(CC) -c $<
#fun2.o: fun2.c
# $(CC) -c $<
#sum.o: sum.c
# $(CC) -c $<
makefile函数
常用:
1. wildcard- 查找指定'目录'下的指定类型的文件 src=$(wildcard*.c) #找到当前目录里所有后缀为.c赋给 src 2. patsubst - 匹配替换 obj = $(patsubst %.c,%.o,$(src)) #把src变量里所有的后缀为.c的文件替换成.o 例如:当前目录下有a.c b.c c.c src = $(wildcard*.c) --------> src = a.c b.c c.c obj = $(patsubst %.c,%.o, $(src)) -------> obj = a.o b.o c.o
第五个样例(函数操作)
target = main
src=$(wildcard*.c)
objects = $(patsubst %.c,%.o,$(src))
CC = GCC
CPPFLAGS = -I./
$(target): $(objects)
$(CC) -o $@ $^
%.o: %.c
$(CC) -c $< $(CPPFLAGS)
makefile的清理操作
清除生成的中间文件 .o文件 最终文件
第六个样例
make 默认执行第一个目标main (终极目标)
执行清楚操作
make clean如果直接输入make执行的是第一个目标
target = main
src=$(wildcard*.c)
objects = $(patsubst %.c,%.o,$(src))
CC = GCC
CPPFLAGS = -I./
$(target): $(objects)
$(CC) -o $@ $^
%.o: %.c
$(CC) -c $< $(CPPFLAGS)
#清除了.o文件
.PHONY:clean #如果多次clean,系统检测更新,而clean创建日期较新----将clean 生成为伪目标 不再检测更新了
clean: #目标为clean 没有依赖
rm $(objects) $(target) #命令
# rm -f 强制执行
注意:
1、使第一条命令不影响第二条命令
当第一条命令出错时
仍然执行第二条命令
clean:
-rm -r xxxxxxxx #-rm 失败不停止
rm -f $(objects) $(target)
ALL
一个Makefile中只有一个最终目标(就是第一个目标),ALL可以生成多个最终目标
all : main1 main2
main1 : main1.o
gcc main1.o -o main1
main2 : main2.o
gcc main2.o -o main2
%.o : %.c
gcc -c $< -o $@
实战案例
1 #使用的编译器
2 CC = gcc
3 #预处理参数
4 CPPLFAGS = -I /usr/include/fastdfs \
5 -I /usr/include/fastcommon \
6 -I ./
7 #头文件路径
8 CFLAGS = -Wall#编译器选项
9
10 #需要链接的动态库
11 LIBS = -l fdfsclient
12 #子目标
13 upload_fdfs = ./upload
14 #最终目标(多个子目标)
15 target=$(upload_fdfs)
16 ALL:$(target)
17 #依赖目标
18 objects= ./fdfs_api.o ./make_log.o ./main.o
19
20 #生成一个子目标
21 $(upload_fdfs): $(objects)
22 $(CC) $^ -o $@ $(LIBS)
23
24 #生成所有的.o文件
25 %.o:%.c
26 $(CC) -c $< -o $@ $(CPPLFAGS) $(CFLAGS)
27
28 #清楚操作
29 clean:
30 -rm -rf *.o $(target)
31 #声明伪文件
32 .PHONY:clean ALL