跳转至

001 编译

背景

以前对 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
2. 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";
}
3. main.cpp 内容如下
// main.cpp
// 调用 hello() 这个函数

#include "include/hello.h"

int main(int argc, char **argv)
{
    hello();
    return 0;
}
4. 单独编译 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" 就不会报错了
5. 单独编译 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

-- 同上
6. 连接 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