嵌入式Linux(四):GCC编译C代码 Makefile编译文件编写

前言

编写嵌入式Linux应用程序时,编译工具使用的一般是交叉编译版本的GCC,使用方式跟GCC一样。本文,记录使用GCC编译的相关命令,以及编写Makefile文件来编译项目。

(一):GCC编译为可执行程序全过程

1.1 四个阶段

C语言代码编译链接成一个可执行程序,需要经过四个阶段。

预编译
编译
汇编
链接
main.c
main.i
mian.s
main.o
可执行程序

(1) 预编译
展开宏,查找头文件目录,main.c -> main.i
(2) 编译
将C/C++代码转换为汇编代码,mian.i->main.s
(3) 汇编
将汇编代码编译为二进制机器码,main.s->main.o
(4) 链接
将多个目标文件(.o)链接成一个可执行程序,main.o->可执行APP

1.2 四个阶段GCC对应的指令

/*hello.c*/
#include <stdio.h>
int main(int args,char **argv){
    if(args>2){
        printf("hello %s !\n",argv[1]);
    }else{
        printf("hello world!\n");
    }
    return 0;
}
//预编译
gcc -E -o hello.i hello.c
//编译
gcc -S -o hello.s hello.i
//汇编
gcc -c -o hello.o hello.s
//链接
gcc -o hello hello.o

(二)GCC编译C语言项目

2.1 完整编译一个项目

//先汇编再链接
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o
./test

2.1.1 main.c

/*main.c*/
#include <stdio.h>
#include "sub.h"
int main(int args,char **argv){
    printf("this main!\n");
    sub_func();
    return 0;
}

2.1.2 sub.c

/*sub.c*/
#include "sub.h"
#include <stdio.h>
void sub_func(){
    printf("this sub function!\n");
}

2.1.3 sub.h

/*sub.h*/
void sub_func();

2.2 尖括号与双引号

 #include <xxx.h>

系统自带的头文件用尖括号括起来,这样编译器会在系统文件目录下查找。

#include "xxx.h"

用户自定义的头文件用双引号括起来,编译器首先会在用户目录下查找,然后再到 C++ 的安装目录(Linux 中可以通过环境变量来设定)中查找,最后在系统文件中查找。

当然,在用gcc编译时,也可指定第一个首先搜索头文件的目录

//从当前路径首先搜索头文件
gcc -c -o main.o main.c -I ./

-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录
-L /home/hello/lib表示将/home/hello/lib目录作为第一个寻找库文件的目录

2.3 制作静态库文件(.a)

使用静态库链接程序时,会将动态库打包到程序里,可以脱离原来的静态库文件运行程序。

//制作目标文件
gcc -c -o sub.o sub.c
//生成静态库
ar crs libsub.a sub.o
//使用静态库编译,需要指定静态库的绝对路径
gcc -o test main.o libsub.a
//测试
./test

2.4 制作动态库 (.so)

使用动态库编译程序时,并没有将动态库添加到可执行程序里,所以程序运行时,需要依赖外部的动态库。可以将动态库移动到 /lib 或 /usr/lib

//生成动态库
gcc -shared -o libsub.so sub.o
//使用动态库编译程序
gcc-o test main.o -lsub -L ./

//测试 需要将动态库移动到 /lib /usr/lib 或者 export LD_LIBRARY_PATH:$LD_LIBRARY_PATH:./
sudo cp libsub.so /lib
./test

(三):Makefile 编写

3.1 Makefile规则

3.1.1 目标依赖

当依赖比目标更新时,执行

目标文件:依赖文件
【TAB】命令

3.1.2 通配符

%.o 
$@	表示目标
$<1个依赖
$^	所有依赖

3.1.3 变量

A := XXX #及时变量
B = XXX  #延时变量,使用时才确定
C ?= XXX #延时变量,只有变量第一次定义才有效
A += hello #附加

3.2 函数

3.2.1 filter

选择指定模板的数据

C = a b c d/
D = $(filter %/,$(c))

3.2.2 filter

选择指定模板的数据

C = a b c d/
D = $(filter %/,$(c))
@echo D = $(D)

3.2.3 filter-out

剔除指定模板的数据

C = a b c d/
D = $(filter-out %/,$(c))
@echo D = $(D)
@echo E = $(E)

3.2.4 wildcard

#取出当前路径所有.c
files = $(wildcard *.c)
files2 = a.c b.c c.c d.c e.c
//取出files2存在的文件
files3 = $(wildcard $(files2))

3.2.5 wildcard

取出并替换

//%.c替换为%.d
dep_files = $(patsubst %.c,%d,$(files2))

3.3 完整的Makefile编译程序

#所有程序文件
objs = main.o test.o
#选择头文件
dep_files := $(patsubst %,.%.d,$(objs))
dep_files := $(wildcard $(dep_files))
#链接
test: $(objs)
	gcc -o test $^
#导入头文件路径
ifneq ($(dep_files),)
include $(dep_files)
endif
#汇编
%.o:%.c
	gcc -c -o $@ $< -MD -MF .$@.d
#清空汇编文件与程序
clean:
	rm *.o test
#删除头文件链接
distclean:
	rm $(dep_files)
	
.PHONY:clean

结语

这些笔记主要是记录韦东山老师视频里关于GCC和Makefile里讲的内容。下面贴下链接
https://www.bilibili.com/video/BV1w4411B7a4?p=39&vd_source=9385b7f8c739b9e3ef3f21ddaebd2eb9

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值