Linux GCC/G++使用
GCC如何完成
格式:
gcc [选项] 要编译的文件 [选项] [目标文件]
常用选项:
-E
:让gcc
在预处理结束后停止编译过程,输出.i
的C语言原始文件。-S
:该选项只是进行编译而不是进行汇编,最终生成汇编代码的.s
文件。-o <filename>
:指定输出目标文件名。-c
:仅编译,不链接,输出.o
二进制目标文件。
程序从源代码到可执行文件,经过预处理、编译、汇编与链接四个步骤:
- 预处理:展开头文件、宏替换、条件编译处理,生成经过预处理的
.i
文件。
示例:
gcc -E hello.c -o hello.i
- 编译:语法检查与生成汇编代码,检查无误生成汇编语言的
.s
文件。
示例:
gcc -S hello.i -o hello.s
- 汇编:将编译阶段生成的
.s
汇编代码转换为机器码,生成.o
目标文件。
示例:
gcc -c hello.s -o hello.o
- 链接:合并目标文件和库,生成可执行文件(如
.out
)。
示例:
gcc hello.o -o hello
程序流程图:
graph LR;![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2281bed57cab457e98467f0bf078fbcb.jpeg#pic_center)
A[源代码文件 .c] --> B[预处理 .i]B --> C[编译 .s]C --> D[汇编 .o]D --> E[链接 可执行文件]
动态链接与静态链接
动态链接
在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时
链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为.so
。
静态链接
静态链接时,程序包含所有依赖库的代码,生成的可执行文件较大,但无需外部库即可独立运行。其后缀名一般为.a
。
可以使用
file
命令查看文件是动态链接还是静态链接:$ file /path/to/your/program /path/to/your/program: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=0x4a00b217499069528e862542e52e31418370a71b, not stripped
上述输出中的“statically linked”表明该文件是静态链接的。对于动态链接的文件,输出中则会显示“dynamically linked”。
此外可以使用
ldd
命令查看所使用的库函数:$ ldd /path/to/your/program linux-vdso.so.1 => (0x00007fffe3ff9000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f93b7d67000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f93b79ab000) ...
从
libc.so
中去掉lib
前缀和.so
后缀,可以看出它是调用了C语言的标准库。
Makefile 的深入理解与应用
在 Linux 或 Unix 系统中,Makefile 是一种用于自动化构建过程的脚本文件,它告诉 make
程序如何编译和链接源代码来创建可执行文件。Makefile 文件可以命名为 makefile
、Makefile
或者任何其他名字,但是使用大写的 Makefile
是一个常见的约定。
示例 Makefile
在 Makefile 中,规则是构建过程的核心,它们告诉 make
如何以及何时更新目标文件。规则的基本语法如下:
target: dependenciescommands
- target:规则的目标,通常是需要构建的文件。
- dependencies:目标的依赖项,即创建目标所需的文件。
- commands:一系列 shell 命令,用于构建目标。
以下是一个简单的 Makefile 示例,用于编译 change.c
并生成可执行文件 mycode
:
mycode: change.cgcc -o mycode change.c
规则解析
在这个示例中,mycode
是一个目标,change.c
是它的依赖项。当 make
运行时,如果 change.c
比 mycode
新或者 mycode
不存在,那么 make
将执行规则中定义的命令来编译 change.c
。
伪目标 .PHONY
伪目标用于执行非文件相关的任务,如清理或初始化等。由于伪目标并不对应于文件系统中的文件,因此不会受到时间戳的影响,每次都会执行其命令。使用 .PHONY
关键字可以显式地将目标标记为伪目标:
.PHONY: clean
clean:rm -f *.o mycode
这里 clean
目标用于删除所有 .o
文件和 mycode
文件,即使这些文件不存在,make
也会尝试执行这个目标。
Makefile 中的 Tab 字符
在 Makefile 中,命令必须使用 Tab 字符来缩进,而不是空格。这是因为 make
解释器期望 Tab 来标识命令行。
更新文件时间戳
make
会检查目标和依赖项的修改时间戳。如果任何一个依赖项的修改时间比目标晚,或者目标不存在,那么 make
将执行相应的命令来更新目标。
为了触发重新编译,可以使用 touch
命令更新文件的时间戳。例如,如果修改了 change.c
文件的内容,但是时间戳没有改变,可以运行:
touch change.c
这将更新 change.c
的时间戳,使 make
认为文件已经被修改,并触发重新编译。