GCC

GCC

编译过程:

a.c ->预处理-> a.i ->汇编-> a.s ->编译-> a.o ->链接-> a.out
gcc -E -o a.i a.c (预处理)
gcc -S -o a.s a.i (编译)
gcc -c -o a.o a.s (汇编)
gcc -o a.out a.o  (链接)

后辍文件详解:
< .c > C语言源码文件
< .a > 目标文件构成的库文件
< .C / .cc /.cxx > C++ 源码文件
< .h > 头文件
< .o > 编译后的目标文件
< .s > 是汇编语言源代码文件

编译选项:
< -o file_name >  指定输出文件
< -O >  对程序进行优化编译,链接
< -O2 > 对程序进行更好的优化编译,链接
< -O3 > 最佳优化
< -g >  对程序加入调试 (gdb 调试)
< -I dir_name >  将所指出的目录作为编译器寻找头文件的路径
< -Wall > 生成所有警告信息
< -w >    不生成任何警告信息

<  -D/-DMACRO > 定义MACRO宏,等效于在程序中使用#define MACRO
(应用场景:可以控制debug的输出)
-----------------------------------------------------------
        GDB
layout asm ---汇编界面
b *addr
        查看内存命
可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:
x/<n/f/u> <addr>
n、f、u是可选的参数。
n是一个正整数,表示需要显示的内存单元的个数,也就是说从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义。
f 表示显示的格式,参见下面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。
当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
<addr>表示一个内存地址。
注意:严格区分n和u的关系,n表示单元个数,u表示每个单元的大小。
n/f/u三个参数可以一起使用。例如:
命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示输出三个单位,u表示按十六进制显示。
输出格式
一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。
例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量的中的位的情况。
要做到这样,你可以使用GDB的数据显示格式:

x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
------------------------------------------------------------
        静态库
  1.命名规则:
    lib+库名+.a
  2.制作静态库:
     生成对应的.o文件  .c---> .o     (gcc -c a.c b.c c.c ....)
      将生成的.a文件打包 ar rcs 生成静态库名 lib1.o lib2.o ..... (ar src liblogan.a ./*.o)
  3.发布和使用静态库:
    1发布静态库: 把头文件移动到include里,把.a文件移动到lib里
    2头文件
  4.使用接口:
    1源文件里导入头文件,gcc main.c -I ./include lib/lib.a (后面导入lib文件)  (把main.c 放第一位)
      2正式用法: gcc main.c -Iinclude -L lib -l logan -o run  (logan 去头去尾: liblogan.a)
    -I 指定头文件路径    (可以无空格)
    -L 指定lib目录
    -l 指定lib目录下的lib文件
  5.查看静态库文件:
    nm lib.a  (nm 还可以查看.out .o)
    nm 里
    T 代表代码区
    B b D W t r
  6.缺点:
    1若使用静态库里的某一个函数,则编译时会将整个.o文件连接到可执行文件中,占用空间(以.o文件为单位)
    2库文件发生改变,需重新编译
  7.优点:
    1发布程序的时候,不需要提供对应的库
    2Load程序的时候,速度快
-------------------------------------------------------------
        共享库
 
  1.命名规则:
    lib+库名+.so
  2.制作共享库:
    1生成与位置无关的.o  (gcc -fPIC -c *.c)
    2将.o打包成共享库(动态库) (gcc -shared -o liblogan.so ./*.o)
  3.发布和使用共享库:
    1发布共享库: 把.so文件移动到lib里
    2使用共享库:
       在编译目标代码时只需导入动态链接库就可以使用(单个)
       一*  gcc main.c  lib/libprint.so -o run
       
       二*
       使用:(gcc main.c -L lib -l print -o run)会导致在运行时无法链接
       需使用以下方法进行链接:

       1*使用环境变量来导入lib.so
       echo $LD_LIBRARY_PATH
       export LD_LIBRARY_PATH=./lib (临时测试用)

       2*修改配置文件来实现永久修改:(永久)(不常用)
       vim ~/.bashrc
       找到 LD_LIBRARY_PATH=...然后进行修改
    
           3*修改动态链接器的配置文件实现链接lib(永久)
         1->找到动态链接器的配置文件
        sudo vim /etc/ld.so.conf
         2->动态路径些到ld.so.conf里
         3->更新  sudo ldconfig -v
    3查看可执行程序的链接库: ldd file  (print share object dependencis)
    4动态库的优缺点:
        优点:
        体积小
        更新不需重新编译程序,实现了模块化(函数接口不变的情况下)
        缺点:
        需要把动态库提供给用户
        加载速度相对较慢
    
-------------------------------------------------------------------------
        gdb调试:
    命令:
    l ----list 查看源码
      l 10 查看10行
      查看其他文件:
      l a.c:20 表示查看 a.c文件里的20的行内容
      l a.c:function_name 查看 a.c文件里fun函数
    
    b ----breakpoint 下断点
    break---------->
    条件断点:
    b 15 if i==15 表示在15行变量i=15时停下
    查看断点信息:
    i b-------information of break
    info break---->
    d----删除断点
    info break

    

    p ----print 打印
    print------>

    ptype----查看变量类型

    diplay----display----追踪变量(循环里可运用)
    undisplay----去掉追踪变量的值
    用之前需获取变量ID
    使用 info display 获取
    然后 undisplay var_ID

    r ----run运行
    start------>
    vmmap ----查看内存分布
    n----单布调试(绕过函数体)
    c----继续执行(遇到断点停下)
    s----(单步)(可进入函数体)
    u----跳出单次循环
    finish----跳出当前进入的函数
    
-----------------------------------------------------------------------------------------------
        Makefile
    Makefile规则

    TARGET....: DEPENDEDS...
    COMMAND
    ...
    ...
    在执行动作命令之前会判断所DEPENDEDS条件是满足,若不满足,则执行依赖项
    clean规则会执行 -$(RM)$(TARGET)$(OBJS)命令
    clean用于清除中间生成文件
    
    注意:COMMAND之前必须有TAB键,不能使用空格来代替
    
    make命令执行的时候会根据文件的时间搓来判断是否执行相关的命令

    匹配模式:
        例:
            main.o:main.c add/add.h sub/sub.h
                gcc -c -o main.o main.c -Iadd -Isub
        简便方法实现相同功能:
            main.o:%o:%c
                gcc -c$< -o $@
    
        %o:%c表示将TARGET域的.o拓展名替换为.c,即main.o 替换为main.c.
        $<表示依赖项的结果,即main.c
        $@表示TARGET域的名称,即 main.o

    
    函数:
        $(wildcard ./*.c)  ---获取./下的所有.c文件
        $(patsubst %.o,%.c,a.o) ---将.o替换为.c
    
    !在命令前加'-',若命令执行失败,则忽略该命令,继续往下执行.

    若在当前目录下存在一个'clean'文件,则就无法使用make clean来实现清除的目的
    需要在Makefile中声明伪目标.
    具体实现:
        .PHONY:clean
        clean:
    

posted @ 2019-12-18 21:00  i0gan  阅读(449)  评论(0)    收藏  举报