GCC 相关汇总
Created|Updated
|Post Views:
GCC 相关汇总
◇ 编译过程
一个 C/C++ 文件要经过预处理 (preprocessing)、编译 (compilation)、汇编 (assembly) 和链接 (linking)
等 4 步才能变成可执行文件:
-
预处理 (Preprocessing): 在编译过程的开始阶段,预处理器会处理源代码。这包括宏替换、头文件包含、条件编译等操作。
-
编译 (Compilation): 编译器将预处理后的源代码转换为汇编语言或直接生成目标机器代码。
-
汇编 (Assembly): 汇编器将汇编语言代码转换为机器代码。在一些高级语言的编译过程中,这一步骤可能被省略。
-
链接 (Linking): 链接器将多个目标文件及其依赖关系合并成一个可执行文件。这包括解决符号引用、地址重定向等操作。
flowchart TD
hello.c --"预处理:(xxx-gcc -E -o hello.i hello.c)"-->
hello.i --"编译:(xxx-gcc -S -o hello.s hello.i)"-->
hello.s --"汇编:(xxx-gcc -c -o hello.o hello.s)"-->
hello.o --"链接:(xxx-gcc -o hello hello.o other.o)"-->
hello
◇ 常用命令
▷ 动态库相关
制作和使用:
1 2 3 4 5 6
| gcc -c -o main.o main.c gcc -c -o sub.o sub.c
gcc -shared -o libsub.so sub.o sub2.o sub3.o gcc -o test main.o -lsub -L /path/to/libsub.so/
|
运行:
先把 libusb.so
放到 PC 或板子上的 /lib
目录,然后就可以运行 test
程序。
或者放在某个自定义目录 /a
,然后执行:
1 2
| export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a ./test
|
如果想要当前用户永久生效,可以修改 ~/.bashrc
文件,末尾添加:
1
| export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a
|
然后运行以下命令,使其在当前终端中立即生效:
▷ 静态库相关
制作和使用:
1 2 3 4 5 6 7
| gcc -c -o main.o main.c gcc -c -o sub.o sub.c
ar crs libsub.a sub.o sub2.o sub3.o
gcc -o test main.o libsub.a
|
运行:
程序中已包含,不需要把静态库 libsub.a
放到板子上。
▷ 其它命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| gcc -c -o hello.o hello.c
gcc -E main.c
gcc -E -dM
gcc -E -dM main.c > 1.txt
echo 'main(){}' | gcc -E -v -
gcc -Wall -c main.c
gcc -I xxx
$ gcc -M example.c example.o: example.c header1.h header2.h
gcc -M -MF example.d example.c
gcc -c -o example.o example.c -MD -MF example.d
gcc -Wp,-MD,abc.dep -c -o main.o main.c
gcc -o hello hello.c -v
|
◇ Makefile
▷ 简单使用
- 目标相关
1 2 3 4 5 6 7 8 9 10
| test: a.o b.o c.o gcc -o test $^
%.o: %.c gcc -c -o $@ $<
clean: rm *.o test
.PHONY: clean
|
执行 make
,即生成第一个目标 test
。
执行 make clean
,执行 clean
目标。
.PHONY
是一个特殊的目标,用于指定一些伪目标 (phony targets)。伪目标通常是不生成对应文件的目标,而是执行一些特定的操作。
使用 .PHONY
可以避免与实际文件名相冲突的问题,如果有一个叫 clean
的文件存在,make
可能会认为 clean
文件是最新的,从而跳过执行清理操作。通过声明 .PHONY
,告诉 make
不要考虑文件名,而总是执行 clean
目标下的命令。
- 赋值相关
1 2 3 4 5 6 7 8 9 10 11
| A := $(C) B = $(C) C = abc D ?= xyz
all: @echo A = $(A) @echo B = $(B) @echo D = $(D)
c += 123
|
make D = 321
的结果:
- 函数相关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| A = a b c
B = $(foreach f, $(A), $(f).o)
C = a b c d/
D = $(filter %/, $(C)) E = $(filter-out %/, %(C))
F = $(wildcard *.c)
F2 = a.c b.c c.c d.c e.c abc
F3 = $(wildcard $(F2))
dep_F = $(patsubst %.c, %.d, $(F2))
all: @echo B = $(B) @echo D = $(D) @echo E = $(E) @echo F = $(F) @echo F3 = $(F3) @echo dep_F = $(dep_F)
|
结果:
1 2 3 4 5 6 7 8 9 10
| $ ls a.c b.c c.c Malefile
$ make B = a.o b.o c.o D = d/ E = a b c F = a.c b.c c.c F3 = a.c b.c c.c dep_F = a.d b.d c.d d.d e.d abc
|
- 依赖相关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| objs = a.o b.o c.o
dep_files := $(patsubst %, .%.d, $(objs)) dep_files := $(wildcard $(dep_files))
CFLAGS = -Werror -Iinclude
test: $(objs) gcc -o $@ $^
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 distclean
|
▷ 一个模板
地址:链接
◇ 交叉编译
以 arm 为例:
1 2 3 4 5
| sudo mkdir /usr/local/arm
sudo tar -jxvf cross-4.2.2-eabi.tar.bz2 -C /usr/local/arm/
|
j
告诉 tar
使用 bzip2
解压缩。在 tar
中,j
通常表示使用 bzip2
压缩。
解压成功后,修改 PATH
环境变量:
1 2 3 4
| sudo vim /etc/profile
vim ~/.bashrc
|
在文件为加入交叉编译器 arm-linux-
所在的路径:
1 2 3 4 5 6
| export PATH=$PATH:/usr/local/arm/4.2.2-eabi/usr/bin
# 另一个例子 # export ARCH=arm # export CROSS_COMPILE=arm-linux-gnueabihf- # export PATH=$PATH:/path/to/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linuxgnueabihf/bin
|
更新一下配置文件 /etc/profile
:
1 2 3 4
| source /etc/profile
source ~/.bashrc
|
测试:
或者写一个测试程序 helloworld
,交叉编译下,看是否能在开发板上运行:
1 2 3 4 5 6 7 8 9
| arm-linux-gcc helloworld.c -o helloworld
sudo cp ./helloworld /nfsboot
./helloworld
|
◇ 交叉调试工具 GDB
◇ 参考内容
- 【嵌入式Linux学习】6、交叉编译环境的搭建,单文件编译Hello Linux!. https://bbs.huaweicloud.com/blogs/333600
- 交叉编译和交叉调试环境搭建及使用. https://developer.aliyun.com/article/244367