Who are you?

Linux编译器学习

这篇文档主要对gcc静态函数库(static library)以及动态函数库(shared library)的编译生成以及使用进行一个简短的学习。

GCC函数库

基础知识

  1. C编程中的相关文件后缀

    | 后缀 | 文件 |
    | :–: | ————- |
    | .a | 静态库 |
    | .c | C源代码(需要编译预处理) |
    | .h | C源代码头文件 |
    | .i | C源代码(不需编译预处理) |
    | .o | 对象文件 |
    | .s | 汇编语言代码 |
    | .so | 动态库 |

  2. 常用编译运行模式

    1
    2
    3
    4
    # 编译链接
    gcc -Wall helloubuntu.c -o helloubuntu
    # 运行
    ./helloubuntu

    注意:

    • 若用到math.h库等非gcc默认调用的标准库,请使用-lm参数

    • 常见编译器选项:

      • -c:只编译生成目标文件,默认的输出文件的文件名同源代码文件名一致

      • -Wall:生成所有警告信息

      • -w:不显示任何警告信息

      • -g:生成调试信息

      • -lLIBRARY: 连接时搜索指定的函数库LIBRARY。

      • -LDIRECTORY: 指定额外的函数库搜索路径DIRECTORY。

      • -IDIRECTORY :指定额外的头文件搜索路径DIRECTORY。

      • -o:指定生成的对象的文件名

      • -O[0-3]:数字越大,优化等级越高

      • -E:只进行编译预处理,若不指定输出对象,那么结果将在标准输出中列出,可以

        1
        $ gcc -E helloubuntu.c -o helloubuntu.i
      • -S:指示编译器生成汇编语言代码然後结束

        1
        $ gcc -S helloubuntu.c

静态库创建

静态库是编译器生成的普通的.o文件的集合。链接一个程序时用库中的对象文件还是目录中的对象文件都是一样的。静态库的另一个名字叫归档文件(archive),管理这种归档文件的工具叫ar

1
2
3
4
5
6
7
8
9
10
11
# 要构建一个库,首先要编译出库中需要的对象模块(也就是采取只编译不链接的命令)
gcc -c -Wall hellofirst.c hellosecond.c
# 程序 ar 配合参数 -r 可以创建一个新库并将对象文件插入。如果库不存在的话,参数 -r 将创建一个新的,并将对象模块添加(如有必要,通过替换)到归档文件中。
ar -r libhello.a hellofirst.o hellosecond.o
# 程序 twohellos 可以通过在命令行中指定库用一条命令来编译和链接
gcc -Wall twohellos.c libhello.a -o twohellos
# OR
# 静态库的命名惯例是名字以三个字母 lib 开头并以後缀 .a 结束。所有的系统库都采用这种命名惯例,并且它允许通过 -l(ell) 选项来简写命令行中的库名。
gcc -Wall twohellos.c -lhello -o twohellos

注意:

  • 上述两条命令效果相同,但是gcc找寻libhello.a的库的位置不同

    • 指定完整的路径名可使编译器在给定的目录中寻找库。库名可以指定为绝对路径(比如 /usr/worklibs/libhello.a)或者相对与当前目录的路径(比如 ./lib/libhello.a)
    • 选项-l 不具有指定路径的能力,但是它要求编译器在系统库目录下找寻该库。
  • 选项-L可以指定具体的目录,使编译器在搜寻系统库目录前先搜寻此目录

    1
    2
    # 假设libhello.a 在当前目录的lib文件夹下。
    gcc -Wall -L ./lib/ twohellos.c -lhello -o twohellos

共享库构建

共享库是编译器以一种特殊的方式生成的对象文件的集合。对象文件模块中所有地址(变量引用或函数调用)都是相对而不是绝对的,这使得共享模块可以在程序的运行过程中被动态地调用和执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 要构建一个共享库,首先要编译出库中需要的对象模块
# -c:只生成 .o 的对象文件
# -fpic:使生成的对象模块采用浮动的(可重定位的)地址,缩微词pic代表“位置无关代码”(position independent code)
gcc -c -Wall -fpic shellofirst.c shellosecond.c
# 下面的 gcc 命令将对象文件构建成一个名为 hello.so 的共享库
# -o:用来为输出文件命名
# -shared:抑制错误选项
# .so :通知编译器将对象文件链接成一个共享库
gcc -Wall -shared shellofirst.o shellosecond.o -o hello.so
## OR 以上两条命令合成一条
gcc -Wall -fpic -shared shellofirst.c shellosecond.c -o hello.so
# 程序可以用下面的命令编译并链接共享库
gcc -Wall stwohellos.c hello.so -o stwohellos
# 程序 stwohello 已经完成,但要运行它必须让其能定位到共享库 hello.so,因为库中的函数要在程序运行时被加载。 需要注意的是,当前工作目录可能不在共享库的查找路径中,因此需要使用如下的命令行设定环境变量LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./

G++函数库

基础知识

  1. Cpp编程中的相关文件后缀

    | 后缀 | 文件 |
    | :————————–: | ————— |
    | .C .c .cc .cp .cpp .cxx .c++ | C++源代码(需要编译预处理) |
    | .h | C或者C++源代码头文件 |
    | .ii | C++源代码(不需编译预处理) |
    | .o | 对象文件 |
    | .s | 汇编语言代码 |
    | .a | 静态库 (archive) |
    | .so | 动态库 |
    | \ | 标准C++系统头文件 |

  1. 常用编译运行模式

    1
    2
    3
    4
    # 编译链接
    g++ helloworld.cpp -o helloworld
    # 运行
    ./helloworld

    注意:

    • 程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。通过遵循源码的命名规范并指定对应库的名字,用 gcc 来编译链接 C++ 程序是可行的,如下例所示

      1
      2
      gcc helloworld.cpp -lstdc++ -o helloworld
      # 选项 -l (ell) 通过添加前缀 lib 和后缀 .a 将跟随它的名字变换为库的名字 libstdc++.a。而后它在标准库路径中查找该库。gcc 的编译过程和输出文件与 g++ 是完全相同的。
    • 编译器选项与GCC完全相同

静态库创建

同GCC

动态库创建

同GCC

Gfortran函数库

基础知识

  1. Gfortran编程中的相关文件后缀

    | 后缀 | 文件 |
    | —————————————- | ————————- |
    | .f .for .FOR .ftn* .f90* .f95* .f03 | Fortran源代码(不需编译预处理) |
    | .F .fpp .FPP .FTN .F90* .F95* .F03* | Fortran源代码(需要编译预处理) |
    | .r | Fortran源代码(需要RatFor编译预处理) |
    | .o | 对象文件 |
    | .s | 汇编语言代码 |
    | .a | 静态库 (archive) |
    | .so | 动态库 |

    注意:其中,标 * 的后缀名是gfortran的文件后缀,g77不能识别。

  1. 常用编译运行模式

    1
    2
    3
    4
    # 编译链接
    gfortran helloworldff.f90 -o helloworldff
    # 运行
    ./helloworldff

    注意:

    • 编译选项同GCC相同

    • 类似g++ ,gfortran 也只是设置过 Fortran 程序所需基本环境的 gcc 的一个前端。当我们运行 gfortran 时,实际上运行并不是这个编译器,而是编译器驱动器。该驱动器解析命令行中所给出的选项,然后才调用真正的编译器,汇编器和链接器。默认情况下,编译器驱动器根据命令行中给定的文件的后缀决定它自己下一步的动作:一个名为 foo.c 将传递给 C 编译器,而名为 foo.f95 的文件将传递给 Fortran 95 的编译器,等等。

      1
      2
      # 类似于 g++
      gcc helloworld.f -o helloworld -lgfortran -lgfortranbegin

静态库创建

同GCC

动态库创建

同GCC

参考: