一、编译器
1、程序编译过程(gcc/g++)
(1)预处理:将所有头文件、宏定义、内联函数展开
gcc -E main.c main.ii
(2)编译:将c语言或c++程序编译为汇编
gcc -S main.ii main.s
(3)汇编:将汇编语言编译为二进制可执行(机器可以解读)程序
gcc -c main.s main.o
(4)链接:将多个程序根据调用关系连接在一个程序,动态库除外(动态库是程序在执行到需要链接的位置通过地址跳转实现调用)
gcc main.o -o main (-o 为输出执行可执行文件)
2、编译器(gcc/g++)
-c 对源文件编译,不链接生成可执行文件
-g 在生成的可执行文件中加入调试信息(gdb调制工具)
-o [0,1,2,3] 对生成代码使用优化,优化级别,默认为2
-I /usr/include 在编译源代码时增加一个搜索头文件的目录
-L /usr/lib 在编译时增加一个库目录
-l pthread 添加库libpthread.os
-w 编译时禁止所有警告
-W warning 允许产生warning类型的警告
-fPIC 编译动态链接库,可以使用dlopen在任意目录调用
-static 静态编译,将依赖的库静态编译到可执行文件
3、生成静态库库文件选项(ar)
c 创建库
v 显示编译过程
r 如何模块在动态库已存在,替换原有模块
ar cvr libfun.a
4、链接器(ld/arm-linux-ld)
(1)选项
-T 指定链接脚本
-o 输出最终可执行二进制文件
-Ttext 指定代码段的起始地址
-Tdata 指定数据段的起始地址
-Tbss 指定未初始化数据段的起始地址
Makefile:
all:start.o
arm-linux-ld -Text 0x30000000 -o start_elf $^
# arm-linux-ld -Tleds.lds -o start_elf $^
%.0:%.S
arm-linux-gcc -g -o $@ $^ -c
clean:
rm *.o *.elf
(2)链接器脚本
SECTIONS{
. = 0x30000000; #指出起始地址
. = ALIGN(4); #指出该地址四字节对其
.text :
{
main.o (.text)
*(.text)
}
. = ALIGN(4);
.data :
{
*(.data)
}
. = ALIGN(4);
bss_start = .;
.bss :
{
*(.bss)
}
bss_end = .;
}
5、拷贝工具(objcopy/arm-linux-objcopy)
-O binary //输出格式
-S //不拷贝符号信息
6、反编译(objdump/arm-linux-objcopy)
-D //反汇编,包括所有section
-m arm //指出指令集架构为arm
二、Makefile
1、语法规则
(1)基础语法
[目标]:[依赖1 依赖1]
[TAB]命令1
[TAB]命令2
(2)注释
# Makefile使用‘#’符号注释,为单行注释
(3)变量使用(默认变量)
$? 所有时间戳比目标文件晚的依赖文件
$@ 目标文件的完整名称
$^ 所有不重复的依赖文件(展开以空格间隔)
gcc $^ -o $@
(4)变量赋值(自定义)
SRC = main.c test.c
SRC += helloWorld.c
CC = gcc
$(CC) $(SRC) -o $@
(5)关闭回显(在执行命令时,不显示执行内容)
@gcc main.c -o app
(6)命令失败后不影响后续命令
-gcc main.c -o app #当前语句失败,不影响后续命令
-gcc test.c -o test
(7)清理编译结果
# .PHONY为申明为目标,当执行make clean后会执行跳过之前的语句,直接执行clean
.PHONY:clean
clean:
rm *.o app