zoukankan      html  css  js  c++  java
  • gcc使用及动静态库制作

    一. GCC的使用

    1. GCC的编译过程

    (1)预处理(cpp)gcc -E(输出问价通常以 .i 结尾),将头文件展开,宏替换等操作;

    (2)编译器(gcc)gcc -S(输出问价以 .s 结尾)生成汇编代码;

    (3)汇编器(as)gcc -c(输出文件以 .o 结尾)将汇编编译成二进制文件;

    (4)连接器(ld)gcc,链接 lib 库生成可执行文件。

    执行过程如下(hello.c):

    #include<stdio.h>
    
    int main()
    {
        printf("hello world
    ");
        return 0;
    }

    Linux执行过程:

    [root@centos1 src]# gcc -E hello.c >> hello.i
    [root@centos1 src]# gcc -S hello.i
    [root@centos1 src]# gcc -c hello.s
    [root@centos1 src]# gcc -o hello.out hello.o
    [root@centos1 src]# ./hello.out
    hello world

    注:第4步如果使用 ld 会报如下错误

    [root@centos1 src]# ld hello.o
    ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
    hello.o: In function `main':
    hello.c:(.text+0xa): undefined reference to `puts'

    没有 __start 是因为C程序以main为主函数,汇编以start为主函数入口,改用gcc连接就可以,如果非用ld,需要自己链接libc.so库。

    2. GCC编译参数

    • -I 包含头文件路径(可以使绝对路径,也可以是相对路径)
    • -O 优化选项,1-3越高优先级越高
    • -L 包含的库路径
    • -l(L的小写)指定库名(通常libxxx.so或者libxxx.a,-lxxx)
    • -o 目标文件
    • -c 编译成.o文件
    • -g 用于gdb调试不加此选项不能gdb调试
    • -Wall 显示更多的警告
    • -D 指定宏编译
    • -lstdc++ 编译c++代码

    二. 动静库

    1. 制作库文件作用

        作用:将实现某部分功能的代码封装成库文件,以方便调用,或者是对代码进行保护加密。

        应用场景:有时想将某代码提供给别人用,但是又不想公开源代码,这时可以将代码封装成库文件。在开发中调用其他人员编写的库。

    2. 静态库

    (1)制作步骤

        1)编译.o文件

        2)将.o文件打包:ar rcs libname.a file1.o file2.o file3.o ...

        3)将头文件与库一起发布

    文件内容及路径分布如下:

    [root@centos1 calc]# tree
    .
    ├── include
    │   └── head.h
    ├── lib
    ├── main.c
    └── src
        ├── add.c
        └── sub.c
    1 #include<stdio.h>
    2 
    3 int add(int a, int b);
    4 int sub(int a, int b);
    head.h
     1 #include "head.h"
     2 
     3 int main(void)
     4 {
     5     int a = 10, b = 10;
     6 
     7     printf("%d + %d is %d
    ", a, b, add(a, b));
     8     printf("%d - %d is %d
    ", a, b, sub(a, b));
     9 
    10     return 0;
    11 }
    main.c
    1 #include "head.h"
    2 
    3 int add(int a, int b)
    4 {
    5     return a + b;
    6 }
    add.c
    1 #include "head.h"
    2 
    3 int sub(int a, int b)
    4 {
    5     return a - b;
    6 }
    sub.c
    • 编译为.o文件

          进入到 src 目录下执行:

    [root@centos1 src]# gcc -c *.c -I ../include/
    [root@centos1 src]# ll
    总用量 16
    -rw-r--r--. 1 root root   63 4月  20 14:53 add.c
    -rw-r--r--. 1 root root 1240 4月  20 15:10 add.o
    -rw-r--r--. 1 root root   63 4月  20 14:24 sub.c
    -rw-r--r--. 1 root root 1240 4月  20 15:10 sub.o
    • 将.o文件打包,制作成libCalc.a静态库
    [root@centos1 src]# ar rcs libCalc.a *.o
    [root@centos1 src]# ll
    总用量 20
    -rw-r--r--. 1 root root   63 4月  20 14:53 add.c
    -rw-r--r--. 1 root root 1240 4月  20 15:10 add.o
    -rw-r--r--. 1 root root 2688 4月  20 15:12 libCalc.a
    -rw-r--r--. 1 root root   63 4月  20 14:24 sub.c
    -rw-r--r--. 1 root root 1240 4月  20 15:10 sub.o

    (2)使用

        编译时需要加静态库名(记得路径),-I 包含头文件

    • 使用静态库编译main.c并执行main

          我们将libCalc.a移动到上层的lib中并退回到calc目录,编译main.c并执行:

    [root@centos1 calc]# gcc main.c -o main -I include/ -L ./lib -lCalc
    [root@centos1 calc]# ll
    总用量 24
    drwxr-xr-x. 2 root root 4096 4月  20 15:07 include
    drwxr-xr-x. 2 root root 4096 4月  20 15:14 lib
    -rwxr-xr-x. 1 root root 6838 4月  20 15:14 main
    -rw-r--r--. 1 root root  179 4月  20 14:57 main.c
    drwxr-xr-x. 2 root root 4096 4月  20 15:14 src
    [root@centos1 calc]# ./main
    10 + 10 is 20
    10 - 10 is 0

    可以用 nm 命令查看文件内容:

    [root@centos1 calc]# nm lib/libCalc.a
    
    add.o:
    0000000000000000 T add
    
    sub.o:
    0000000000000000 T sub

    (3)静态库优缺点

       优点:

       1)执行快

       2)发布应用时不需要发布库

       缺点:

       1)执行程序体积会比较大

       2)库变更时需要重新编译程序

    三. 动态库

    1. 制作步骤

    (1)编译与位置无关的代码(下图共享库),生成.o目标文件,关键参数 -fPIC

    进程虚拟地址空间

    (2)将.o文件打包,关键参数 -shared

    (3)将库与头文件一起发布

    • 生成.o目标文件

    文件路径和内容同上,进入到src目录,生成.o目标文件:

    [root@centos1 src]# gcc -fPIC -c *.c -I ../include/
    [root@centos1 src]# ll
    总用量 16
    -rw-r--r--. 1 root root   63 4月  20 14:53 add.c
    -rw-r--r--. 1 root root 1240 4月  20 15:20 add.o
    -rw-r--r--. 1 root root   63 4月  20 14:24 sub.c
    -rw-r--r--. 1 root root 1240 4月  20 15:20 sub.o
    • 将.o文件打包生成动态库
    [root@centos1 src]# gcc -shared -o libCalc.so *.o
    [root@centos1 src]# ll
    总用量 24
    -rw-r--r--. 1 root root   63 4月  20 14:53 add.c
    -rw-r--r--. 1 root root 1240 4月  20 15:20 add.o
    -rwxr-xr-x. 1 root root 5817 4月  20 15:21 libCalc.so
    -rw-r--r--. 1 root root   63 4月  20 14:24 sub.c
    -rw-r--r--. 1 root root 1240 4月  20 15:20 sub.o

    2. 使用

    • 使用生成的动态库,-L 指定动态库路径 -l 指定库名(gcc main.c -o main -I include/ -L ./lib -lCalc) 

    退出到calc目录下,将动态库拷贝到lib目录下并编译mian.c并执行main:

    [root@centos1 calc]# gcc main.c -o main -I include/ -L ./lib -lCalc
    [root@centos1 calc]# ll
    总用量 24
    drwxr-xr-x. 2 root root 4096 4月  20 15:07 include
    drwxr-xr-x. 2 root root 4096 4月  20 15:29 lib
    -rwxr-xr-x. 1 root root 7066 4月  20 15:30 main
    -rw-r--r--. 1 root root  179 4月  20 14:57 main.c
    drwxr-xr-x. 2 root root 4096 4月  20 15:29 src
    [root@centos1 calc]# ./main
    ./main: error while loading shared libraries: libCalc.so: cannot open shared object file: No such file or directory

    无法找到动态库目标文件,解决方法有三个:

       (1)拷贝到/lib下(不允许,容易与别人库命名重合)

       (2)将库路径增加到环境变量LD_LIBRARY_PATH中(不是特别推荐)

    [root@centos1 calc]# export LD_LIBRARY_PATH=/home/xuejiale/src/calc/lib/:$LD_LIBRARY_PATH
    [root@centos1 calc]# ./main
    10 + 10 is 20
    10 - 10 is 0

       (3)配置/etc/ld.so.conf文件,增加 /home/xuejiale/src/calc/lib/ 路径,执行 ldconfig -v,并执行main

    /home/xuejiale/src/calc/lib/
    [root@centos1 calc]# ./main
    10 + 10 is 20
    10 - 10 is 0

    3. 优缺点总结

       缺点:

    • 执行时需要加载动态库,相对而言,比静态库慢
    • 发布应用时需要同步发布动态库

       优点:

    • 执行程序体积小
    • 库变更时,一般不需要重新编译应用

    动静态库总结:

         静态库特点:

    • 库的代码会编译进程序里面,所以静态库编译的程序比较大。
    • 由静态库编译的程序不用依赖于系统的环境变量,所以环境变量有没有这个库文件,也可以运行。

        动态库特点:

    • 库的代码不会编译进程序里面,所以动态库编译的程序比较小。
    • 由动态库编译的程序依赖于系统的环境变量有没有这个库文件,没有则运行不了。
  • 相关阅读:
    访客登录方案设计与应用
    VS Code下载
    dockerfile COPY命令失效
    mysql排序字段值相等时,分页数据重复
    go使用json包Marshal方法得到异常结果[123 125]
    Mysql知识点概览
    dockercompose安装
    docker安装
    Shell脚本执行报错:Syntax error: "(" unexpected
    二进制数的位运算,角色权限,多种账号来源
  • 原文地址:https://www.cnblogs.com/xuejiale/p/10741311.html
Copyright © 2011-2022 走看看