G++/GCC基础

编译过程有四步

  1. 预处理

    1
    2
    3
    g++ -E test.cpp -o test.i
    #预处理为.i文件
    #头文件啥的的预定义啥的
  1. 编译

    1
    2
    g++ -S test.i -o test.s
    #编译为汇编语言输出为.s文件
  1. 汇编

    1
    2
    g++ -c test.s -o test.o
    #编译为机器语言输出为.o
  1. 链接

    1
    2
    g++ test.o test
    #生成为可执行文件test,二进制的文件

GCC/G++的优化选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#基本优化
-O
#等效O1
-O0
#不做优化
-O1
#为默认优化
-O2
#默认优化+额外的调整
-O3
#默认优化+额外的调整+循环展开等处理特性的优化

g++ test.cpp -O2 -o test
#优化等级2生成可执行文件test

所谓优化就是提升效率,编译时间换取执行效率

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include <iostream>
using namespace std;

int main ()
{

unsigned long int counter;
unsigned long int result;
unsigned long int temp;
unsigned int five;
int i;

//有很多计算步骤都都在循环条件里
for(counter=0;counter<2000*2000*100/4+2010;counter+=(10-6)/4)
{

temp+=counter/1979;
for(i=0;i<20;i++)
{
five=200*200/8000;
result=counter;
}
}
cout<<"result="<<result<<endl;
return 0;
}


测试优化O2与不优化O0

1
g++ test.cpp -O2 -o Youhua
1
g++ test.cpp -O0 -o NotYouhua

再依次执行

1
2
time ./Youhua
time ./NotYouhua

可以看见优化后的执行效率相当高

指定库文件与头文件

库的指定:

1
2
3
4
5
g++ -lglog test.cpp
#链接golg 库

g++ -L/home/icrad/mylibfolder -lmylib test.cpp
#链接自己的指定的库文件夹下的库文件,需要大写

头文件的指定

1
2
3
#一般来说,是不需要指定的,GCC默认去找include文件夹,当不存在时,就需要自己指定了头文件目录了

g++ -I/myinclude test.cpp

基本常用的其他项

  • -Wall

    打印警告信息

    1
    g++ -Wall test.cpp
  • -w

    关闭警告信息

    1
    g++ -W test.cpp
  • -std=c++11

    指定C++ 特性

    1
    g++ -std=c++11 test.cpp
  • -o

    编译输出可执行文件

    1
    g++ test.cpp -o test
  • -D

    定义宏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //使用场景,可以在编译的时候选择是否 执行宏定义
    #include <iostream>
    using namespace std;
    int main ()
    {
    #ifdef DEBUG
    cout<<"DEBUG_LOG"<<endl;
    #endif
    cout<<"Ubuntu,yes!";
    return 0;
    }

    编译这个文件时可以

    1
    g++ -DDEBUG test.cpp -o test

    生成的执行文件会将宏定义中的代码输出

    如果没有定义宏,只会输出

    1
    Ubuntu,yes!

GDB调试参数

调试需要在编译时加入可调试信息才可使用GDB工具进行调试

1
2
g++ -g test.cpp -o test
#生成可调试的执行文件

编译示例

多文件夹的目录结构

1
2
3
4
5
├── include
│   └── swap.h
├── math.cpp
└── src
└── swap.cpp
  • 直接编译

    1
    2
    g++ math.cpp -std=c++11 src/swap.cpp -Iinclude
    #记得引入头文件

    即可生成可执行文件a.out

  • 链接生成静态库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #将src的文件夹下的swap.cpp生成为.o文件(汇编语言)
    cd src/
    g++ swap.cpp -c -I../include

    #进行归档操作
    ar rs libswap.a swap.o
    #作用是将swap.o归档为一个静态库文件

    cd ..#回到上级目录
    g++ math.cpp -lswap -Lsrc -I\include -o static_swap
    #链接指定的静态库进行编译
    #最终得到可执行文件static_swap

  • 链接生成动态库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    cd src/

    g++ swap.cpp -I../include -fPIC -shared -o libswap.so
    #等价于
    gcc swap.cpp -I../include -c -fPIC
    #生成.o文件
    gcc -shared -o libswap.so swap.o
    #生成静态库文件libswap.so

    回到上级目录
    cd ..
    g++ math .cpp -Iinclude -lswap -Lsrc -o dyna_swap
    #生成了可执行的文件dyna_swap

    动态库的可执行文件需要指定搜索路径

    为什不直接设定系统的环境变量?避免与系统重复

    第一种方法(临时测试用 ——推荐)

    1
    2
    LD_LIBRARY_PATH=src ./dyna_swap
    #指定了动态库的搜索路径运行该可执行文件

    第二种方法:可以配置用户终端的环境变量(不推荐)

    1
    2
    3
    修改当前目录的bashrc文件
    再最后行加入动态库的路径
    LD_LIBRARY_PATH=
  • 第三种的方法(推荐)

    • 找到动态库连接器的配置文件

      1
      2
      cd /etc
      sudo vi ld.so.conf
    • 将动态库的路径写到配置文件中,绝对路径

      1
      动态库的路径
    • 更新

      1
      sudo ldconfig -v

      更新后就可以使用该链接动态库的程序的执行

      1
      2
      ldd 
      #查看执行文件的动态库连接

静态库与静态库的区别:大小,前者更大,直接包含在执行文件中了,而动态库在调用相应函数时才会加载,所以在运行时,静态库不需要指定路径直接运行,而动态库需要。