基础
1、与gcc编译c语言程序相关的文件后缀名如下:
单源程序到可执行程序
1、编写一个最简单的C程序: helloworld.c
如下
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
2、编译命令如下:
$ gcc helloworld.c
gcc通过检查命令行中的文件名后缀,就可以确定所编译的是C语言源文件。gcc会采用默认动作是江源文件编译为目标文件,然后江目标文件连接到可执行文件,最后删除目标文件。由于没有指定可执行文件名,所以会生成一个默认的a.out
$ ./a.out
Hello, World!
我们可以用-o指定目标文件名
$ gcc helloworld.c -o hello
$ ./hello
Hello, World!
单源程序到目标文件(.o)
选项-c
会明确指示GCC去编译源代码,但不在硬盘上留下目标文件,且跳过将目标文件连接到可执行程序这一步。
$ gcc -c helloword.c
生成了一个helloword.o
。这种情况下默认输出文件名和输入文件名一样,但以.o
作后缀。
选项-o可用于修改生成的目标文件名。
$ gcc -c helloword.c -o hello.o
ps:在构建目标库的过程中,或在创建目标文件集合的时候,其中的目标文件可用于之后的连接操作,有条命令可以由多个源文件创建出目标文件。下面命令会创建a.o,b.o,c.o
$ gcc -c a.c b.c c.c
多源文件到可执行文件
gcc编译程序可以自动处理连接,甚至在编译多个源文件的时候也可以自动连接。
1、编写程序
hellomain.c
void sayhello(void);
int main() {
sayhello();
return 0;
}
sayhello.c
#include <stdio.h>
int sayhello() {
printf("Hello, World!\n");
return 0;
}
2、执行命令
gcc hellomain.c sayhello.c -o hello
3、效果.
生成可执行文件hello
$ ./hello
Hello, World!
预处理
编译-E
指示编译程序只进行预处理操作。并将结构输出到标准输出上
$ gcc -E helloworld.c
我们也可以将它保存在某个以.i结尾的文件中
$ gcc -E helloworld.c -o helloworld.i
生成汇编语言
-S
指示编译器生成汇编语言代码:
$ gcc -S helloworld.c
生成一个helloworld.s
创建静态库
- 静态库是一些.o文件的集合,他们是由编译程序按照通常的方式生成的。将程序连接到库中的目标文件和将程序连接到目标中的目标文件是一样的。静态库的另一个名字是文档,而管理这些文件内容的工具叫做
ar
ar
的-r
选项,可以创建新的库,并将目标文件插入其中。如果库中不存在所命名的目标模块,会将它加入文档(必要情况下可能替换原来的目标文档)
1、编程模块hellofirst.c, helloseconf.c
// hellofirst.c
#include <stdio.h>
int first() {
printf("Hello, first!\n");
return 0;
}
// hellosecond.c
#include <stdio.h>
int second() {
printf("Hello, second!\n");
return 0;
}
2、将 hellofirst.c, hellosecond.c
编译成目标文件(-c选项明确指出编译程序要生成-o目标文件)
$ gcc -c hellofirst.c hellosecond.c
发现生成了hellofirst.o hellosecond.o
3、接下来创建一个叫做libhello.a
的静态库(包含上面的两个目标模块)
$ ar -r libhello.a hellofirst.o hellosecond.o
4、接下来我们就可以使用这个库了,编写一个twohellos.c
int first();
int second();
int main(){
first();
second();
return 0;
}
5、在命令行指定库,并编译twohellos.c
$ gcc twohellos.c libhello.a -o twohellos
$ ./twohellos
Hello, first!
Hello, second!
静态库一般以lib
开头,.a
后缀结束。
我们可以通过选项-l
,在命令行中使用库民的缩写方式。下面命令与前面命令的唯一区别在于期望gcc对库进行查找的位置不同
$ gcc twohellos.c -lhello -o twohellos
/usr/bin/ld: 找不到 -lhello
collect2: 错误:ld 返回 1
明确指出完全路径名会令编译程序在所指路径中查找库。库名既可以指明绝对路径,也可以是相对路径。选项-l不能指明路径,编译程序只会在系统库中进程查找
解决方法:
export LIBRARY_PATH=/usr/local/protobuf/lib
创建共享库
- 共享库是目标文件的集合,但是这些目标文件是由编译程序按照特殊方式生成的。对象模块的每个地址(变量引用和函数调用)都是相对地址,不是绝对地址。因此允许在运行程序的时候,可以动态加载和执行共享模块
1、将 hellofirst.c, hellosecond.c
编译成目标文件
(-c
选项明确指出编译程序要生成-o目标文件)
(-fpic
表示输出的对象模块是按照可重定位地址方式生成的)
(-pic
表示输出的对象模块是按照位置独立方式生成的)
$ gcc -c -fpic hellofirst.c hellosecond.c
发现生成了hellofirst.o hellosecond.o
2、使用模板文件构建共享库hello.so
(-o
为输出文件命名)
(后缀.so
告诉GCC该目标文件是要连接到共享库)
(-shared
:一般连接程序要使用mian
定位,并用它作为程序的入口,但是输出模块没有main函数,因此需要使用-shared
防止出错)
$ gcc -shared hellofirst.o hellosecond.o -o hello.so
ps: 我们可以将1、2命令合并为一个命令
$ gcc -fpic -shared hellofirst.c hellosecond.c -o hello.so
3、将程序编译并连接到共享库
$ gcc twohellos.c hello.so -o hellos
$ ./hellos
./hellos: error while loading shared libraries: hello.so: cannot open shared object file: No such file or directory
解决方法:
export LIBRARY_PATH=/usr/local/protobuf/lib