Sailor's Technical Column

linux c/c++ 程序入门

2019-05-19
Sailor

本文主要是对makefile,gcc 以及gdb的学习

1. gcc/g++

  • c++ 程序的编译过程如下图:
  • gcc/g++ 的常用命令
  • 静态库的生成
  • 动态库的生成

2. makefile

2.1 概念

  • makefile 是一条或多条规则组成
  • 命名 makefile and Makefile
  • 编写规则

目标1:目标依赖  然后回车+tab键
 命令

目标2:目标依赖  然后回车+tab键
 命令
...

目标n:目标依赖  然后回车+tab键
 命令

注意:命令必须是tab键开头的

2.2 规则

  • 主要由三部分组成:目标,依赖和命令
  • 一般形式是:“目标:依赖 命令
    • command太长, 可以用 “" 作为换行符 -比如
      gcc a.c b.c c.c -O app 可以改写成:
      app:a.c b.c c.c
           gcc a.c b.c c.c -o app
    
    
  • 规则中的通配符
    • * : 表示任意一个或多个字符,%标记和系统通配符的区别在于,是应用在系统中的,%是应用在这个Makefile文件中的。

    • ? : 表示任意一个字符
    • […] : ex. [abcd] 表示a,b,c,d中任意一个字符, [^abcd]表示除a,b,c,d以外的字符, [0-9]表示 0~9中任意一个数字
    • ~ 表示用户的home目录
  • 路径搜索
    • 当一个Makefile中涉及到大量源文件时(这些源文件和Makefile极有可能不在同一个目录中),这时, 最好将源文件的路径明确在Makefile中, 便于编译时查找. Makefile中有个特殊的变量 VPATH 就是完成这个功能的
    • 如果当前目录中没有找到相应文件或依赖的文件, Makefile 回到 VPATH 指定的路径中再去查找
    • VPATH src:../parent-dir 当前目录中找不到文件时, 按顺序从 src目录 ../parent-dir目录中查找文件
    • VPATH %.h ./header 示例2 - .h结尾的文件都从 ./header 目录中查找
    • VPATH 清除所有已经设置好的文件路径
    • vpath 清除符合格式的文件搜索路径;VPATH %.h 清除示例2中设置的规则

2.3 变量

2.4 引用其他的makefile文件

  • 语法: include (filename 可以包含通配符和路径)
  • include ./other/Makefile
  • export

    2.5 查看c文件的依赖关系

    比如, 下面命令显示内核源码中 virt/kvm/kvm_main.c 中的依赖关系

    $ cd virt/kvm/    
    $ gcc -MM kvm_main.c 
    

    kvm_main.o: kvm_main.c iodev.h coalesced_mmio.h async_pf.h <– 这句就可以加到 Makefile 中作为编译 kvm_main.o 的依赖关系

2.6 定义命令包或函数

定义这种命令序列的语法以“define”开始,以“endef”结束,如:

all:                    
    @$(cmd)

define cmd
    echo "test define 1"
    echo "test define 2"
    echo "test define 3"
endef

“cmd”是这个命令包的名字,其不要和Makefile中的变量重名。在“define”和“endef”中的两行就是命令序列。在define 和 endef 间的部分即是命令主体。

2.7 条件判断

  • 格式:

conditional directive   
   text-if-true   
endif   

或者   
conditional-directive   
   text-if-true   
else   
   text-if-false     
endif      

  • 实例
# Makefile 内容
all:
ifeq ("aa", "bb")
    @echo "equal"
else
    @echo "not equal"
endif

# bash 中执行 make
$ make
not equal       

2.8 Makefile 中的函数

  • 语法如下:
$(<function> <arguments>)
或是
${<function> <arguments>}       

make支持的函数不多。* arguments*是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔

  • 常用函数如下:

2.9 编写规则分析-实例

2.9.1 案例1

  • makefile 文件
app:add.c sub.c mul.c
    gcc add.c sub.c mul.c -o app

  • 缺点是:效率低,修改一个文件,所有文件会被全部重新编译

2.9.2 案列 2

  • makefile 是:
app : main.o add.o sub.o mul.o
       gcc main.o add.o sub.o mul.o -o app
main.o:main.c
       gcc main.c -c  
add.o:add.c
       gcc add.c -c   
sub.o:sub.c
       gcc mul.c -c 
mul.o:mul.c
       gcc mul.c -c 

  • 工作原理:
    • 检测依赖是否存在,向下搜索下边的规则,如果有规则是用来生成查找的依赖的,执行规则中的命令。
    • 依赖存在,判断是否需要更新,如果目标时间大于依赖时间则不需要,否则需要更新
  • 缺点:太冗余

2.9.3 案例3

obj = main.o add.o sub.o mul.o
target = app
$(target):$(obj)
          gcc $(obj) -o $(target)
%.o:%.c
   gcc -c $< -o $@
    
  • 案列解析
    • 自定义变量 obj=main.o add.o
    • 变量取值:aa = $(obj)
    • makefile 自带的变量是大写的如 CPPFLAGS ,CC
    • 自动变量
      • $@:规则中的目标
      • $<:规则中的第一个依赖
      • $^:规则中所有依赖
      • 只能在规则的命令中使用
    • 模式匹配
      • %.o:%.o
      • 第一次 mian.o 没有,则main.o:main.c gcc -c main.C -o main.O 以次类推
  • 可移植性比较差

2.9.4 案例4

  • makefile文件
src =$(wildcard ./*.c)
obj = $(patsubst %.c ,%.o,$(src))

target = app
$(target):$(obj)
          gcc $(obj) -o $(target)
%.o:%.c
   gcc -c $< -o $@

  • 案列解析
    • makefile 所有的函数都有返回值
    • 查找指定目录下指定类型的文件:src=$(wildcard ./*.c)首先使用“wildcard”函数获取工作目录下的.c文件列表
    • obj=$(patsubst %.c,%.o,s(src)),将列表中所有文件名的后缀.c替换为.o,这样我们就可以得到在当前目录可生成的.o文件列表
    • wildcard : 扩展通配符
    • notdir : 去除路径:dir=$(notdir $(src))
    • patsubst :替换通配符
  • 缺点不能清理项目

2.9.5 案例5

  • makefile文件
src =$(wildcard ./*.c)
obj = $(patsubst %.c ,%.o,$(src))

target = app
$(target):$(obj)
          gcc $(obj) -o $(target)
%.o:%.c
   gcc -c $< -o $@

hello:
    echo "Hello makefile"

.PHONY:clean
clean:
    -mkdir /abc
    -rm $(obj) $(target) -f     
  • 命令前加 -:忽略执行失败的命令,继续向下执行其余的命令
  • -f :强制执行
  • .PHONY后面的target表示的也是一个伪造的target, 而不是真实存在的文件target..
  • PHONY: clean
    • means the word “clean” doesn’t represent a file name in this Makefile;
    • means the Makefile has nothing to do with a file called “clean” in the same directory.

2.10 make 的工作方式

3. gdb调试

  • 保留调试信息
    >>> gcc test.c -o app    
    >>> gcc test.c -o app -g
    

-g 会保留函数名和变量名

  • 启动gdb

格式:gdb 可执行程序的名字
如:gdb app
给程序传参:set args xx

  • 查看代码 –list -l
    • 当前文件
      • l
      • l 行号
      • l 函数名
    • 非当前文件
      • l 文件名:行号
      • l 文件名:函数名
  • 断点操作 -break/b
    • 设置断点
      • b 行号
      • b 函数名
      • b 文件名:行号
      • b 文件名:函数名
    • 查看断点
      • info(i) b
    • 删除断点
      • d num(断点的编号)
      • 删除多个:d num1 num2
    • 设置断点无效
      • dis num
    • 断点生效
      • ena num
    • 设置条件断点
      • b 行号 if 变量== var
  • 调试相关命令
    • 让gdb跑起来
      • start 运行一行,停止
      • run -r 停在第一个断点的位置
    • 打印变量的值
      • p 变量名
    • 打印变量的类型
      • ptype 变量名
    • 向下单步调试
      • next - n 不会进入函数体
      • step -s 会进入函数体
        • 跳出函数体:finish,如果出不去,看一下函数体重的循环中是否有断点,如果有则删掉,或者设置无效
    • 继续运行gdb,停在下一个断点的位置
      • continue -c
    • 退出gdb
      • quit -q
    • 变量的自动显示
      • display 变量名
      • 取消: undisplay 编号
      • i display
    • 从循环体直接跳出
      • until 不能有断点
    • 直接设置变量等于某一个值
      • set var 变量名=value

Similar Posts

Comments