gcc-编译那些事
背景
以前对 gcc 编译这一块比较务实,一直是拿来就用的状态,最近上好有时间把这一块整理下。
编译是分阶段的
以前写 hello world 的时候都是直接一行命令就把整个编译过程搞完了,以至于感觉不到有“链接”这个环节。
// main.cpp
#include <iostream>
void hello()
{
std::cout << "this is in hello function. \n";
}
int main(int argc, char **argv)
{
hello();
return 0;
}
编译+连接+运行
g++ -o main main.cpp && ./main
this is in hello function.
如果所有的 C/C++ 程序只有一个源文件的话,那么事情到这里就结束了。但是通常我们是把一个程序拆分成多个文件。
gcc 支持单独编译一个文件的,下面我们也把刚才的 hello world 强行拆一下。
从多文件项目讲起
可以通过一个多文件项目来体验编译器的“链接”环节。 1. 头文件 include/hello.h 内容如下。
// include/hello.h
// 声明 void hello() 这个函数
#ifndef _N_HELLO_
#define _N_HELLO_ 1
void hello();
#endif
- src/hello.cpp 内容如下
// src/hello.cpp
// 实现 void hello() 这个函数
#include <iostream>
#include "include/hello.h"
void hello()
{
using std::cout;
cout << "this is in hello function \n";
}
- main.cpp 内容如下
// main.cpp
// 调用 hello() 这个函数
#include "include/hello.h"
int main(int argc, char **argv)
{
hello();
return 0;
}
- 单独编译 hello.cpp 生成目标文件
g++ -c src/hello.cpp -I.
ll | grep hello
-rw-r--r-- 1 root root 2488 May 11 16:19 hello.o
-- -c 选择告诉g++只执行完编译就退出 .o 结尾的文件就是编译生成的目标文件
-- 这里的 -I 是认 g++ 在当前目录下找头文件,而当前目录下刚好存在 "include/hello.h" 这样的话,main.cpp 里面的 include "include/hello.h" 就不会报错了
- 单独编译 main.cpp 生成目标文件
gcc -c main.cpp && ll | grep main
-rw-r--r-- 1 root root 134 May 11 16:17 main.cpp
-rw-r--r-- 1 root root 1384 May 11 16:24 main.o
-- 同上
- 连接 main.o 和 hello.o 生成可执行文件
g++ -o main main.o hello.o && ./main
this is in hello function
静态库
正常情况下我们也不怎么接触目标文件,大多数情况用的还是“静态库”,和“共享库”。下面我们看一下怎么把目标文件整成静态库并让程序运行起来。
-- 打包目标文件成静态库
mkdir lib
ar crv libhello.a hello.o
-- 移动静态库到 lib 目录下
-- 命令是要求的 1. lib 开头 2. 库名 3. .a 结尾,名字不对会识别不了!!!
mv libhello.a lib
ranlib lib/libhello.a
-- 链接目标文件与静态库,生成可执行文件
g++ -o main main.o -Llib -lhello && ./main
this is in hello function
动态库
动态库相比静态库来说会更加的节约空间一些,下面给一个用共享库明生成可执行文件的例子。
-- 生成位置无关文件, 得到 .o 文件
g++ -fPIC -c src/hello.cpp -I./
-- 检查
ll -h | grep hello
-rw-r--r-- 1 root root 2.6K May 12 20:15 hello.o
-- 生成共享库文件
g++ -shared -o libhello.so hello.o -I./
mv libhello.so lib/
-- 生成可执行文件
g++ -o main main.cpp lib/libhello.so
./main
this is in hello function