gcc –E test1.c –o test1.i
gcc –S test1.i –o test1.s
gcc –c test1.s –o test1.o
gcc test1.o –o test1
我们可以指定可执行文件的文件名
cpp文件:以cpp或者cc为后缀,不能用gcc编译,用g++编译
下面体会一下各种过程:
gcc –E test1.c –o test1.i
上面八百多行,都是预处理过程头文件stdio.h展开得到的
gcc -S test.i -o test.s
gcc -c test.s -o test.o
在软件开发中,链接是将一个或多个编译后的目标文件(.o文件)和库文件合并,生成可执行文件或更大的库文件的过程。链接可以是静态的(static)或动态的(dynamic),并且涉及到库文件,这些库可以是静态库(.a文件)或动态库(.so 文件或在Windows上的.dll 文件
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
答案是 :系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用
静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。
gcc hello.o –o hello
gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证
在软件开发中,链接是将一个或多个编译后的目标文件(
.o
文件)和库文件合并,生成可执行文件或更大的库文件的过程。链接可以是静态的(static)或动态的(dynamic),并且涉及到库文件,这些库可以是静态库(.a
文件)或动态库(.so
文件或在Windows上的.dll
文件)。
ld
)将所有用到的库文件的内容复制到最终的可执行文件中。这意味着,运行程序时不需要这些库在系统中存在,因为所有必需的代码都已经包含在单个可执行文件中了。
ld.so
)加载。
.a
(Archive) 格式存储,是多个目标文件的集合。使用静态库时,其内容在编译时整合到最终的可执行文件中。
.so
(Shared Object) 或 .dll
(Dynamic Link Library) 格式存储。动态库在运行时被加载,可以被多个程序共享。
[dyx@VM-8-13-centos ~]$ ll
total 44
-rwxrwxr-x 1 dyx dyx 8968 Sep 22 21:54 a.out
d--------- 2 dyx dyx 4096 Jul 24 17:52 dir
drwxr-xr-x 2 root root 4096 Sep 22 16:06 dir1
-rw-rw-r-- 1 dyx dyx 827 Jul 22 10:03 install.sh
-rwxrwxr-x 1 dyx dyx 8408 Sep 22 22:26 my
drwxr-xr-x 2 root root 4096 Sep 19 17:09 test
-rw-rw-r-- 1 dyx dyx 209 Sep 23 17:15 test.c
[dyx@VM-8-13-centos ~]$ ldd a.out
linux-vdso.so.1 => (0x00007ffdc15d2000)
libstdc++.so.6 => /home/dyx/.VimForCpp/vim/bundle/YCM.so/el7.x86_64/libstdc++.so.6 (0x00007fc019380000)
libm.so.6 => /lib64/libm.so.6 (0x00007fc01907e000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc018e68000)
libc.so.6 => /lib64/libc.so.6 (0x00007fc018a9a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc019701000)
[dyx@VM-8-13-centos ~]$ ls /lib64/libc.so.6
/lib64/libc.so.6
[dyx@VM-8-13-centos ~]$ ls -l /lib64/libc.so.6
lrwxrwxrwx 1 root root 12 Mar 23 2023 /lib64/libc.so.6 -> libc-2.17.so
libc-2.17.so
是 Linux 系统中的一个非常核心的动态库,也被称为 C 标准库。这个库提供了标准 C语言的许多基本功能和服务,包括输入输出操作、字符串处理、内存分配、数学计算等。此外,它还提供了操作系统级别的接口,如系统调用的封装(例如文件操作、进程控制等)。
libc
包含标准 C 函数,如 printf
, malloc
, strncpy
等。open
, read
, write
, fork
, exec
等。libc.so.6
是最常见的符号链接名称,它指向系统中当前 C 标准库的具体版本,比如 libc-2.17.so
。这种符号链接机制允许系统在保持相同库名(libc.so.6
)的情况下升级到新版本的库,而不会打断依赖它的应用程序。libc-2.17
指的是 glibc(GNU C Library)的特定版本。glibc 是大多数 Linux 发行版使用的 libc 实现。libc-2.17.so
是系统中的标准 C 库实现的一个版本,它是许多 Linux 程序运行不可或缺的组成部分。通过 libc.so.6
这样的符号链接,系统能够方便地管理库的版本,而不影响依赖这些库的应用程序。
默认情况,Linux上,一般静态库都是默认没有安装的
sudo yum install -y glibc-static libstdc++-static
make是一个命令 makefile是一个文件
这个 Makefile
的片段定义了如何编译一个名为 mytest
的目标文件,以及如何清理生成的文件。让我们逐行解析这个片段的内容。
Makefile
内容解析
mytest: test.c
gcc -o mytest test.c
.PHONY: clean
clean:
rm -f mytest
第一部分:目标以及规则
mytest: test.c
gcc -o mytest test.c
mytest: test.c
:
mytest
make
尝试构建的一个目标文件(通常是可执行文件)test.c
test.c
。如果 test.c
发生变化,mytest
需要重新构建。gcc -o mytest test.c
:
mytest
的具体命令。第二部分:伪目标 .PHONY
.PHONY: clean
.PHONY: clean
: make
,目标 clean
不是一个文件,也不应被与文件名相混淆。clean
文件)存在时,引起误解和错误。
第三部分:清理规则
clean:
rm -f mytest
clean
rm -f mytest
rm -f mytest
:删除生成的可执行文件 mytest
。-f
:强制删除文件,不显示文件不存在的错误。整体描述:
mytest
: test.c
源文件。gcc -o mytest test.c
。make mytest
或单纯 make
(如果 mytest
是第一个目标)时,make
会检查 test.c
。test.c
更新过或 mytest
不存在,会执行 gcc -o mytest test.c
。make工具使用文件的时间戳来决定哪些目标需要重新构建。具体来说,make会比较目标文件和其依赖文件的修改时间戳。如果依赖文件比目标文件更新,则目标文件需要重新构建。这个机制是通过以下步骤实现的:
清理目标 clean
:
clean
仅作为命令,不是物理文件。make clean
时,命令 rm -f mytest
会运行,删除 mytest
。构建可执行文件:
make
或者
make mytest
这会依据 test.c
编译 mytest
。
清理生成文件:
make clean
这会删除 mytest
,使目录重新变得干净。
1 code.exe:code.o
2 gcc code.o -o code.exe
3 code.o:code.s
4 gcc -c code.s -o code.o
5 code.s:code.i
6 gcc -S code.i -o code.s
7 code.i:code.c
8 gcc -E code.c -o code.i
9
10 .PHONY:clean
11 clean:
12 rm -f code.i code.s code.o code.exe
用 .PHONY 修饰,伪目标的特性是,总是被执行的。
makefile/make会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有相关的依赖方法
这个 Makefile
使用了变量来定义构建目标和源文件路径,以及自动化构建和清理过程。让我们逐行解析这个 Makefile
的内容。
bin=mycode
src=test.c
$(bin):$(src)
@gcc -o $@ $^
@echo "compiler $(src) to $(bin)..."
.PHONY: clean
clean:
@rm -f $(bin)
@echo "clean project..."
定义目标文件和源文件的变量:
bin=mycode
src=test.c
bin
:存储生成的可执行文件名 mycode
。src
:存储源文件名 test.c
。Makefile
的可读性和维护性,尤其是在需要变更文件名时,只需修改变量定义即可。目标和依赖关系
定义构建目标和依赖关系:
$(bin): $(src)
@gcc -o $@ $^
@echo "compiler $(src) to $(bin)..."
自动化变量: @:代表规则中的目标文件。 <:第一个依赖文件。
伪目标和清理规则
定义伪目标和清理规则:
.PHONY: clean
clean:
@rm -f $(bin)
@echo "clean project..."
.PHONY: clean
: clean
被声明为伪目标,表示它只是一个标签,不对应实际文件名。确保即使有同名文件 clean
,也不会造成误会。变量的使用:
bin=mycode
和 src=test.c
定义了构建可执行文件和源文件的变量。使用变量可以增加 Makefile
的灵活性和可读性。构建过程:
mycode
<- test.c
。test.c
变化时,目标文件 mycode
会重新生成。构建命令:
make
这会触发以下操作:
gcc
命令编译 test.c
,生成 mycode
。echo
命令输出编译信息。整个过程如下:
@gcc -o mycode test.c
@echo "compiler test.c to mycode..."
清理过程:
mycode
。清理命令:
make clean
这会触发以下操作:
rm
命令删除 mycode
。echo
命令输出清理信息。整个过程如下:
@rm -f mycode
@echo "clean project..."
通过这个 Makefile
,用户可以方便地编译和清理项目,确保构建过程的自动化和高效性。使用变量不仅使得 Makefile
更加灵活,还提高了可读性和可维护性