基于Ubuntu编译器操作

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

  • 28
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值