• 《GCC编译器的使用以及静态库和动态库的制作与使用》


    1.源码

    main.c
    #include <stdio.h>
    #include "sub.h"
    int main(int argc, char *argv[])
    {
           int i;
           printf("Main fun!
    ");
           sub_fun();
           return 0;
    }
    
    
    sub.c
    void sub_fun(void)
    {
           printf("Sub fun!
    ");
    }
    
    
    sub.h
    void sub_fun(void);

      注意:头文件stdio.h,如果用gcc去编译程序,一般stdio.h在/usr/include中。如果是arm-linux-gcc,那么stdio.h就位于这个编译器目录里面的usr/include。也可以通过-I去指定一个路径里面的头文件,或者使用"stdio.h",表示在当前目录中的stdio头文件。

      最终的可执行程序需要通过main.c和sub.c一起编译才可以。

    gcc -o test main.c sub.c

      最后会生成一个名为test的可执行文件。

    警告:

      这边提示的是隐式函数声明,只需要在sub.c中定义一下#include <stdio.h>。关于隐式函数更加详细说明点击这里。

    2.编译

      在日常交流中通常使用“编译”统称这4个步骤,实际上分为四个步骤:一个C/C++文件要经过预处理(preprocessing)编译(compilation)汇编(assembly)链接(linking)等4步才能变成可执行文件。

      预处理(preprocessing):C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令“#define”、条件编译命令“#if”、“#ifdef”等。预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到一个“.i”文件中等待进一步处理

      编译(compilation):编译就是把C/C++代码(比如上述的“.i”文件)“翻译”成汇编代码,所用到的工具为cc1(它的名字就是cc1,x86有自己的cc1命令,ARM板也有自己的cc1命令),生成.s文件

      汇编(assembly):汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现为ELF目标文件(OBJ文件),用到的工具为as。x86有自己的as命令,ARM版也有自己的as命令,也可能是xxxx-as(比如arm-linux-as),最后生成.o文件

      反汇编:是指将机器代码转换为汇编代码,这在调试程序时常常用到。

      链接(linking):链接就是将上步生成的OBJ文件和系统库的OBJ文件、库文件链接起来,最终生成了可以在特定平台运行的可执行文件,用到的工具为ld或collect2,最后生成可执行程。

       注意:指定头文件目录的是-I(大写的i),而指定库文件的是-l(是小写的L)。

    3.怎么编译多个文件

    3.1 一起编译、链接:

    gcc  -o test  main.c  sub.c(建议源文件少的情况下使用)

    3.2 分开编译,统一链接:

    gcc -c -o main.o  main.c  (建议源文件多的情况下使用)
    gcc -c -o sub.o   sub.c
    gcc -o test main.o sub.o

    注意:用3.1的方法,修改一个.c文件,那么全部的.c文件都将会被重新编译。对于源文件少的没有影响,但是如果源文件多,效率很低。

       3.2的方法,修改一个.c文件,只编译修改的那个。

    4.制作、使用动态库

    4.1制作、编译

    gcc -c -o main.o  main.c
    gcc -c -o sub.o   sub.c
    gcc -shared  -o libsub.so  sub.o  sub2.o  sub3.o(可以使用多个.o生成动态库)
    gcc -o test main.o  -lsub  -L /libsub.so/所在目录/

      其中lsub就是libsub.so通过-l指定具体的库,通过-L指定库所在的目录。如果不指定库所在的目录,编译器默认去lib下面查找。

    4.2在开发板运行

      1.因为使用的是动态库,必须将动态库放在开发板的/lib或者/usr/lib下,因为在执行应用程序的时候,默认去这两个目录中查找。

      2.如果不想把libusb.so放到/lib,也可以放在某个目录比如/a,然后如下执行:

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a  
    ./test

      3.添加/etc/ld.so.conf.d/*.conf文件,执行ldconfig刷新。

    5.制作、使用静态库

    gcc -c -o main.o  main.c
    gcc -c -o sub.o   sub.c
    ar  crs  libsub.a  sub.o  sub2.o  sub3.o(可以使用多个.o生成静态库)
    gcc  -o  test  main.o  libsub.a  (如果.a不在当前目录下,需要指定它的绝对或相对路径)

    运行:

      不需要把静态库libsub.a放到板子上。但是可执行程序的大小会大很多。

     

    6.静态库和动态库的优缺点

    6.1静态库  

      编译(链接)时把静态库中相关代码复制到可执行文件中(占用更多磁盘和内存空间)。

      程序中已包含代码,运行时不再需要静态库(运行时无需加载库,运行速度更快)。

      静态库升级后,程序需要重新编译链接(不利于后期的升级维护)。

    6.2动态库

      编译(链接)时仅记录用到哪个共享库中的哪个符号,不复制共享库中相关代码(尺寸小)。

      多个程序可共享同一个库。

      程序运行时需要加载库(运行速度受影响)。

      库升级方便,无需重新编译程序。

    7.gcc中一些比较好用的选项

    gcc -E main.c   // 查看预处理结果,比如头文件是是去哪里查找的
    gcc -E -dM main.c  > 1.txt  // 把所有的宏展开,存在1.txt里,可以清楚的看到宏最后定义了什么
    gcc -Wp,-MD,abc.dep -c -o main.o main.c  // 生成依赖文件abc.dep,后面Makefile会用

      

  • 相关阅读:
    不能在此路径中使用此配置节。如果在父级别上锁定了该节,便会出现这种情况
    C# 实现CRC16校验
    C#实现AES加密解密
    C# 简单的定时器使用
    使用密码远程QQ时窗口闪退
    C#桌面程序启动时传入参数
    解决Hangfire 导致服务器内存飙涨
    Mantis 1.2.19 on Windows Server 2012 r2 datacenter 安装及配置随笔
    web api 记录部署IIS获取服务器地址的类型
    学习asp.net Identity 心得体会(连接oracle)
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/11757674.html
Copyright © 2020-2023  润新知