嵌入式Linux应用开发——Linux下的C编程基础

一、markdown简单操作

1.标题

  • 在文字开头加上 “#”,通过“#”数量表示几级标题。
  • 通过在文字下方添加“=”和“-”,他们分别表示一级标题和二级标题。

    2.块注释

  • 通过在文字开头添加“>”表示块注释。
  • (当>和文字之间添加五个blank时,块注释的文字会有变化)

    3.斜体

  • 将需要设置为斜体的文字两端使用1个 “*” 或者 “_” 夹起来

    4.粗体

  • 将需要设置为斜体的文字两端使用2个 “*” 或者 “_” 夹起来

    5.无序列表

  • 在文字开头添加(*, +, and -)
  • 注意在(*, +, and -)和文字之间需要添加空格。(建议:一个文档中只用一种无序列表的表示方式)

    6.有序列表

  • 使用数字后面跟上句号。(还要有空格)

    7.链接

  • 内联方式
  • 引用方式

  • 内联方式:

  • 引用方式:[alt text][id]
    [id]: /path/to/img.jpg "Title"

    9.代码(HTML中所谓的Code)

  • 简单文字出现一个代码框:使用<blockquote>。(不是单引号而是左上角的ESC下面~中的
  • 大片文字需要实现代码框:使用Tab和四个空格。

    10.下划线

  • 在空白行下方添加三条“-”横线。

二、vim基本操作

1.六种基本模式:

(1)普通模式(Normal mode)

  • 在普通模式中,用的编辑器命令,比如移动光标,删除文本等等。这也是Vim启动后的默认模式。这正好和许多新用户期待的操作方式相反(大多数编辑器默认模式为插入模式)。
  • 在普通模式中,有很多方法可以进入插入模式。比较普通的方式是按a(append/追加)键或者i(insert/插入)键。

    (2)插入模式(Insert mode)

  • 在这个模式中,大多数按键都会向文本缓冲中插入文本。大多数新用户希望文本编辑器编辑过程中一直保持这个模式。
  • 在插入模式中,可以按ESC键回到普通模式。

    (3)可视模式(Visual mode)

  • 这个模式与普通模式比较相似。但是移动命令会扩大高亮的文本区域。高亮区域可以是字符、行或者是一块文本。当执行一个非移动命令时,命令会被执行到这块高亮的区域上。Vim的"文本对象"也能和移动命令一样用在这个模式中。

    (4)选择模式(Select mode)

  • 这个模式和无模式编辑器的行为比较相似(Windows标准文本控件的方式)。这个模式中,可以用鼠标或者光标键高亮选择文本,不过输入任何字符的话,Vim会用这个字符替换选择的高亮文本块,并且自动进入插入模式。

    (5)命令行模式(Command line mode)

  • 在命令行模式中可以输入会被解释成并执行的文本。例如执行命令(:键),搜索(/和?键)或者过滤命令(!键)。在命令执行之后,Vim返回到命令行模式之前的模式,通常是普通模式。

    (6)Ex模式(Ex mode)

  • 这和命令行模式比较相似,在使用:visual命令离开Ex模式前,可以一次执行多条命令。

    2.常用命令总结

    (1)插入

    i	在当前光标处进行编辑
    I	在行首插入
    A	在行末插入
    a	在光标后插入编辑
    o	在当前行后插入一个新行
    O	在当前行前插入一个新行
    cw	替换从光标所在位置后到一个单词结尾的字符

    (2)退出

    :q!		强制退出,不保存
    :q		退出
    :wq!	强制保存并退出
    :w <文件路径>		另存为
    :saveas 文件路径	另存为
    :x		保存并退出
    :wq		保存并退出

    (3)删除

    x		删除游标所在的字符
    X		删除游标所在前一个字符
    Delete	同x
    dd		删除整行
    dw		删除一个单词(不适用中文)
    d$或D	删除至行尾
    d^		删除至行首
    dG		删除到文档结尾处
    d1G		删至文档首部

    (4)行间跳转

    nG(n Shift+g)	游标移动到第 n 行
    (如果默认没有显示行号,请先进入命令模式,输入:set nu以显示行号)
    gg				游标移动到到第一行
    G(Shift+g)		到最后一行

    (5)行内跳转

    w		到下一个单词的开头
    e		到下一个单词的结尾
    b		到前一个单词的开头
    ge		到前一个单词的结尾
    0或^		到行头
    $		到行尾
    f<字母>	向后搜索<字母>并跳转到第一个匹配的位置(非常实用)
    F<字母>	向前搜索<字母>并跳转到第一个匹配的位置
    t<字母>	向后搜索<字母>并跳转到第一个匹配位置之前的一个字母(不常用)
    T<字母>	向前搜索<字母>并跳转到第一个匹配位置之后的一个字母(不常用)

    (6)复制与粘贴

  • 普通模式中使用y复制

     yy		复制游标所在的整行(3yy表示复制3行)
     y^ 	复制至行首,或y0。不含光标所在处字符。
     y$ 	复制至行尾。含光所在处字符。
     yw 	复制一个单词。
     y2w	复制两个单词。
     yG 	复制至文本末。
     y1G	复制至文本开头。
  • 普通模式中使用p粘贴

     p(小写)		代表粘贴至光标后(下)
     P(大写)		代表粘贴至光标前(上)

    (7)替换和撤销

    r+<待替换字母>	将游标所在字母替换为指定字母
    R			连续替换,直到按下Esc
    cc			替换整行,即删除游标所在行,并进入插入模式
    cw			替换一个单词,即删除一个单词,并进入插入模式
    C(大写)		替换游标以后至行末
    ~			反转游标所在字母大小写
    u{n}		撤销一次或n次操作
    U(大写)		撤销当前行的所有修改
    Ctrl+r		redo,即撤销undo的操作

    (8)快速缩进与文本位置

    >> 整行将向右缩进
    << 整行向左回退
    :set shiftwidth? 	获取目前的设定值
    :set shiftwidth=10 	设置缩进为10个字符
    :ce 		本行内容居中
    :ri(right) 	本行文本靠右
    :le(left) 	本行内容靠左

    (9)查找

    /icmp 	查找字符串icmp
     n 		查找下一个icmp
    ?tcp 	向上查找字符串tcp
    N  		查找上一个出现的tcp
    *		寻找游标所在处的单词
    #		同上,但* 是向前(上)找,#则是向后(下)找
    g*		同* ,但部分符合该单词即可
    g#		同# ,但部分符合该单词即可

    (10)多文件编辑

vim 1.txt 2.txt

:n	编辑2.txt文件,可以加!即:n!强制切换
:N	编辑1.txt文件,可以加!即:N!强制切换,
注:之前文件内的输入没有保存,仅仅是切换到另一个文件

进入vim后打开新文件

:e 3.txt 			打开新文件3.txt
:e# 				回到前一个文件
:ls					可以列出以前编辑过的文档
:b 2.txt(或编号)	可以直接进入文件2.txt编辑
:bd 2.txt(或编号)	可以删除以前编辑过的列表中的文件项目
:e! 4.txt			新打开文件4.txt,放弃正在编辑的文件
:f 					显示正在编辑的文件名
:f new.txt			改变正在编辑的文件名字为new.txt

(11)视窗操作

:sp 1.txt	打开新的横向视窗来编辑1.txt
:vsp 2.txt	打开新的纵向视窗来编辑1.txt
Ctrl-w s 	将当前窗口分割成两个水平的窗口
Ctrl-w v 	将当前窗口分割成两个垂直的窗口
Ctrl-w q 	即 :q 结束分割出来的视窗。如果在新视窗中有输入需要使用强制符!即:q!
Ctrl-w o 	打开一个视窗并且隐藏之前的所有视窗
Ctrl-w j 	移至下面视窗
Ctrl-w k 	移至上面视窗
Ctrl-w h 	移至左边视窗
Ctrl-w l 	移至右边视窗
Ctrl-w J 	将当前视窗移至下面
Ctrl-w K 	将当前视窗移至上面
Ctrl-w H 	将当前视窗移至左边
Ctrl-w L 	将当前视窗移至右边
Ctrl-w 		减小视窗的高度
Ctrl-w + 	增加视窗的高度

(12)功能设定

:set或者:se			显示所有修改过的配置
:set all 				显示所有的设定值
:set option? 			显示option的设定值
:set nooption 			取消当期设定值
:set autoindent(ai)	 	设置自动缩进
:set autowrite(aw) 		设置自动存档,默认未打开
:set background=dark或light	设置背景风格
:set backup(bk) 			设置自动备份,默认未打开
: set cindent(cin) 	设置C语言风格缩进

(13)创建加密文档

$ vim -x file1

3.vimtutor练习教程实践

(1)文本简单操作

  • 光标在屏幕文本中的移动既可以用箭头键,也可以使用 hjkl 字母键。
    h (左移) j (下行) k (上行) l (右移)
  • 欲进入vim编辑器(从命令行提示符),请输入∶vim 文件名 <回车>
  • 欲退出vim编辑器输入以下命令放弃所有修改∶:q!<回车>
  • 输入以下命令保存所有修改∶ :wq <回车>
  • 在正常模式下删除光标所在位置的字符,请按∶ x
  • 在光标所在位置开始插入文本,请按∶i 输入必要文本

    (2)删除与撤销

  • 欲从当前光标删除至单字/单词末尾,请输入∶dw
  • 欲从当前光标删除至当前行末尾,请输入∶d$
  • 欲删除整行,请输入∶dd
  • 在正常模式下一个命令的格式是∶[number] command object 或 command [number] object
    number - 代表的是命令执行的次数
    command - 代表要做的事情,比如 d 代表删除
    object - 代表要操作的对象,比如 w 代表单字/单词,$ 代表到行末等等。
  • 欲撤消以前的操作,请输入∶u (小写的u)
  • 欲撤消在一行中所做的改动,请输入∶U (大写的U)
  • 欲撤消以前的撤消命令,恢复以前的操作结果,请输入∶CTRL-R

    (3)置入、替换和更改

  • 要重新置入已经删除的文本内容,请输入小写字母 p。该操作可以将已删除的文本内容置于光标之后。如果最后一次删除的是一个整行,那么该行将置于当前光标所在行的下一行。
  • 要替换光标所在位置的字符,请输入小写的 r 和要替换掉原位置字符的新字符即可。
  • 更改类命令允许您改变指定的对象,从当前光标所在位置直到对象的末尾。比如输入 cw 可以替换当前光标到单词的末尾的内容;输入 c$ 可以替换当前光标到行末的内容。
  • 更改类命令的格式是∶
    [number] c object 或者 c [number] object

    (4)定位与搜索

  • Ctrl-g 用于显示当前光标所在位置和文件状态信息。Shift-G 用于将光标跳转至文件最后一行。先敲入一个行号然后按 Shift-G 则是将光标移动至该行号代表的行。
  • 输入 / 然后紧随一个字符串是则是在当前所编辑的文档中向后查找该字符串。
  • 输入问号 ? 然后紧随一个字符串是则是在当前所编辑的文档中向前查找该字符串。完成一次查找之后按 n 键则是重复上一次的命令,可在同一方向上查找下一个字符串所在;或者按 Shift-N 向相反方向查找下该字符串所在。
  • 如果光标当前位置是括号(、)、[、]、{、},按 % 可以将光标移动到配对的
    括号上。
  • 在一行内替换头一个字符串 old 为新的字符串 new,请输入 :s/old/new
  • 在一行内替换所有的字符串 old 为新的字符串 new,请输入 :s/old/new/g
  • 在两行内替换所有的字符串 old 为新的字符串 new,请输入 :#,#s/old/new/g
  • 在文件内替换所有的字符串 old 为新的字符串 new,请输入 :%s/old/new/g
  • 进行全文替换时询问用户确认每个替换需添加 c 选项,请输入 :%s/old/new/gc

    (5)外部命令与文件

  • :!command 用于执行一个外部命令 command。

例子∶
:!dir - 用于显示当前目录的内容。

:!rm FILENAME - 用于删除名为 FILENAME 的文件

  • :w FILENAME 可将当前 VIM 中正在编辑的文件保存到名为FILENAME 的文件中。
  • :#,#w FILENAME 可将当前编辑文件第 # 行至第 # 行的内容保存到文件FILENAME 中。
  • :r FILENAME 可提取磁盘文件 FILENAME 并将其插入到当前文件的光标位置后面。

    (6)插入

  • 输入小写的 o 可以在光标下方打开新的一行并将光标置于新开的行首,进入插入模式。
  • 输入大写的 O 可以在光标上方打开新的一行并将光标置于新开的行首,进入插入模式。
  • 输入小写的 a 可以在光标所在位置之后插入文本。
  • 输入大写的 A 可以在光标所在行的行末之后插入文本。
  • 输入大写的 R 将进入替换模式,直至按 键退出替换模式而进入正常模式。
  • 输入 :set xxx 可以设置 xxx 选项。

    (7)在线帮助

  • 按下 键 (如果键盘上有的话)
  • 按下 键 (如果键盘上有的话)
  • 输入 :help <回车>
  • 提供一个正确的参数给":help"命令,您可以找到关于该主题的帮助。

    (8)vim功能

  • 开始编辑vimrc文件,这取决于您所使用的操作系统∶
  • :edit ~/.vimrc 这是Unix系统所使用的命令
  • :edit $VIM/_vimrc 这是Windows系统所使用的命令
  • 接着导入vimrc范例文件∶:read $VIMRUNTIME/vimrc_example.vim
  • 保存文件,命令为∶:write

    (9)宏录制

  • qa 操作序列 q, @a, @@
  • qa 把你的操作记录在寄存器 a。于是 @a 会replay被录制的宏。
    @@ 是一个快捷键用来replay最新录制的宏。

    (10)分屏

  • :split → 创建分屏 (:vsplit创建垂直分屏)
  • dir:dir就是方向,可以是 hjkl 或是 ←↓↑→ 中的一个,其用来切换分屏。
  • _ (或 |) : 最大化尺寸 (| 垂直分屏)
  • + (或 -) : 增加尺寸

三、GCC编译器

1.gcc支持编译的一些源文件后缀名

.c				C语言源文件
.C .cc .cxx		C++源文件
.m				Object-C源文件
.i				经过预处理后的C源文件
.ii				经过预处理后的C++源文件
.s .S			汇编语言源文件
.h				预处理文件(头文件)
.o				目标文件
.a				存档文件

2.gcc编译流程

原文件->预处理->编译->汇编->连接->可执行文件
  • 预处理:gcc –E hello.c –o hello.i
  • gcc –E调用cpp 生成中间文件,可以让gcc在预处理结束后停止编译过程。
  • 编 译:gcc –S hello.i –o hello.s
  • gcc –S调用ccl翻译成汇编文件.
  • 汇 编:gcc –c hello.s –o hello.o
  • gcc -c 调用as 翻译成可重定位目标文件
  • 链 接:gcc hello.o –o hello
  • gcc -o 调用ld** 创建可执行目标文件
  • ./name.out
  • 运行这个可执行目标文件需要输入它的名字

注:请记住,gcc预处理源文件的时候(第一步),不会进行语法错误的检查。
语法检查会在第二步进行,比如花括号不匹配、行末尾没有分号、关键字错误等。

五、静态链接库与动态链接库

1.概念

通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。

静态链接库

  • 程序在运行时,与函数库无关,因为所有需要的函数已拷贝到自己门下,所以这些函数库被成为静态库(static libaray)
  • 通常文件名为“libxxx.a”的形式。

    动态链接库

  • 把对一些库函数的链接载入推迟到程序运行时期(runtime),这就是动态链接库(dynamic link library)技术
  • 动态链接库的名字形式为 “libxxx.so” 后缀名为 “.so”

    2.创建与主程序运行

    静态链接库

  • 使用归档工具ar将目标文件集成在一起:

    gcc –c file1.c file2.c
    ar rcsv libxxx.a file1.o file2.o
  • 编译主程序main.c,链接到生成的静态库libxxx.a 并运行

    gcc -o main main.c -L. -lxxx
    ./main

    动态链接库

  • 使用-fPIC选项为动态库构造一个目标文件

    gcc -fPIC -Wall -c file1.c
    gcc -fPIC -c file2.c
  • 使用-shared和和已创建的位置无关目标代码,生成一个动态库libxxx.so

    gcc -shared -o libxxx.so file1.o file2.o
  • 编译主程序main.c,链接到生成的动态库libxxx.a

    gcc -o main main.c -L. -lxxx
  • 注意:在运行可执行程序前需要注册动态库的路径名。例:将库文件直接复制到/lib目录下,然后运行

    cp libxxx.so /lib
    ./main

3.编译参数

-c	只编译,不连接成为可执行文件。即把.c文件编译成.o文件
-o 		命名生成文件

ar -r	在库中插入模块(替换)
   -c	创建一个库
   -s	写入一个目录文件索引到库中,即把两个.o文件归档成静态库存档文件.a并且写入目录文件索引到库中。

-static 告诉编译器驱动程序,链接器应该构建一个完全链接的可执行目标文件,进行静态编译,即链接静态库,禁止使用动态库
-shared	可以生成动态库文件,进行动态编译,尽可能的链接动态库,没有动态库时才会链接同名静态库

-Lpath	表示在path目录中搜索库文件,,如-L.则表示在当前目录。
-L dir	在库文件的搜索路径列表中添加dir目录
-lname	链接称为libname.a或者libname.so的库文件。如果两个库文件都存在,根据编译方式是static还是shared进行链接。

-fPIC	生成使用相对地址的位置无关的目标代码,然后通常使用gcc的-static选项从该pic目标文件生成动态库文件。不用此选项的话编译后的代码是位置相关的。
-Ipaht	表示在path目录中搜索头文件。
-ltest	编译器查找动态连接库时有隐含命名规则,名字前加lib后加.so确定库的名称。
-Wall	允许发出gcc提供的所有有用的报警信息。

四、GDB调试技术

1.gdb主要功能

  • (1)启动程序,可以按照用户自定义的要求随心所欲的运行程序。
  • (2)可让被调试的程序在用户所指定的调试的断点处停住 (断点可以是条件表达式)。
  • (3)当程序停住时,可以检查此时程序中所发生的事。
  • (4)动态地改变程序的执行环境。

    2.基本命令

    (1)进入GDB

    gcc -g test.c -o test
    gdb test
  • test是要调试的程序,进入后提示符变为(gdb) 。

    (2)查看源码  

    (gdb) l
  • 源码会进行行号提示。
  • 如果需要查看在其他文件中定义的函数,在l后加上函数名即可定位到这个函数的定义及查看附近的其他源码。或者:使用断点或单步运行,到某个函数处使用s进入这个函数。

    (3)设置断点  

    (gdb) b 6
  • 这样会在运行到源码第6行时停止,可以查看变量的值、堆栈情况等;这个行号是gdb的行号。

    (4)查看断点处情况  

    (gdb) info b
  • 可以键入"info b"来查看断点处情况,可以设置多个断点;

    (5)运行代码  

    (gdb) r

    (6)显示变量值  

    (gdb) p n
  • 在程序暂停时,键入"p 变量名"(print)即可;
  • GDB在显示变量值时都会在对应值之前加上"$N"标记,它是当前变量值的引用标记,以后若想再次引用此变量,就可以直接写作"$N",而无需写冗长的变量名;

    (7)观察变量  

    (gdb) watch n
  • 在某一循环处,往往希望能够观察一个变量的变化情况,这时就可以键入命令"watch"来观察变量的变化情况,GDB在"n"设置了观察点;

    (8)单步运行  

    (gdb) n

    (9)程序继续运行  

    (gdb) c
  • 使程序继续往下运行,直到再次遇到断点或程序结束;

    (10)退出GDB  

    (gdb) q

    3.四种断点

    (1)函数断点

    b	函数名	条件表达式

    (2)行断点

    b	行数或函数名	条件表达式

    (3)条件断点

    b	行数或函数名	if表达式

    (4)临时断点

    tbreak	行数或函数名	条件表达式

五、make与makefile

1.Makefile 介绍

make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。

  • 首先,我们用一个示例来说明Makefile的书写规则(这个示例来源于GNU的make使用手册):我们的工程有若干个.C文件和.h文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:

    1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
    2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
    3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
  • makefile带来的好处就是——“自动化编译”。只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。只需要一个make命令,整个工程完全编译,极大的提高了软件的开发效率。

    2.Makefile的规则

    target ... : prerequisites ...
    command
    ...
    ...
  • target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label)。
  • prerequisites就是,要生成那个target所需要的文件或是目标。
  • command也就是make需要执行的命令。(任意的Shell命令)

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则,也是Makefile中最核心的内容。

3.make工作方式

  • 在默认的方式下,也就是我们只输入make命令。那么,

    • make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
    • 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,它会找到“edit”这个文件,并把这个文件作为最终的目标文件。
    • 如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
    • 如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
    • 当然,你的C文件和H文件是存在的,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是执行文件edit了。

这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即如果在找了依赖关系之后,冒号后面的文件还是不在,那么就停止工作。

  • 执行步骤:

    (1)读入所有的Makefile。
    (2)读入被include的其它Makefile。
    (3)初始化文件中的变量。
    (4)推导隐晦规则,并分析所有规则。
    (5)为所有的目标文件创建依赖关系链。
    (6)根据依赖关系,决定哪些目标要重新生成。
    (7)执行生成命令。

    4.带宏的 Makefile

  • Makefile中的宏,也称作变量。变量是在makefile中定义的名字,用来代替一个文本字符串,该文本字符串称为该变量的值。
  • 定义变量的两种方式:

(1)递归展开方式

	VAR=var

(2)简单方式

	VAR:=var

使用变量的格式为:

	$(VAR)
  • 变量的分类:
  • 用户自定义变量
  • 预定义变量
  • 自动变量
  • 环境变量

    5.自动变量

  • 这些变量在规则每次执行时都基于目标和依赖产生新值。例如: 可以使用变量‘$@’代替目标文件名,变量‘$<’代替依赖文件名。
  • 自动变量列表

    $@	规则的目标文件名。如果目标是一个档案成员,则变量‘$@’ 档案文件的文件名。对于有多个目标的格式规则(参阅格式规则简介),变量‘$@’是那个导致规则命令运行的目标文件名
    $%	当目标是档案成员时,该变量是目标成员名,参阅使用make更新档案文件。例如,如果目标是‘foo.a(bar.o)',则‘$%'的值是‘bar.o',‘$@'的值是‘foo.a'。如果目标不是档案成员,则‘$%'是空值。
    $<	第一个依赖的文件名。如果目标更新命令来源于隐含规则,该变量的值是隐含规则添加的第一个依赖。参阅使用隐含规则。
    $?	所有比目标‘新’的依赖名,名字之间用空格隔开。对于为档案成员的依赖,只能使用已命名的成员。参阅使用make更新档案文件。
    $^	所有依赖的名字,名字之间用空格隔开。对于为档案成员的依赖,只能使用已命名的成员。参阅使用make更新档案文件。对同一个目标来说,一个文件只能作为一个依赖,不管该文件的文件名在依赖列表中出现多少次。所以,如果在依赖列表中,同一个文件名出现多次,变量‘$^’的值仍然仅包含该文件名一次。
    $+	该变量象‘$^',但是,超过一次列出的依赖将按照它们在makefile文件中出现的次序复制。这主要的用途是对于在按照特定顺序重复库文件名很有意义的地方使用连接命令。
    $*	和隐含规则匹配的stem(径),参阅格式匹配。如果一个目标为‘dir/a.foo.b',目标格式规则为:‘a.%.b' ,则stem为‘dir/foo'。在构建相关文件名时stem 十分有用。在静态格式规则中,stem是匹配目标格式中字符‘%’的文件名中那一部分。在一个没有stem具体规则中;变量‘$*' 不能以该方法设置。如果目标名以一种推荐的后缀结尾,变量‘$*'设置为目标去掉该后缀后的部分。例如,如果目标名是‘foo.c',则变量‘$*' 设置为‘foo', 因为‘.c' 是一个后缀。在隐含规则和静态格式规则以外,应该尽量避免使用变量‘$*'。在具体规则中如果目标名不以推荐的后缀结尾,则变量‘$*’在该规则中设置为空值。

#遇到的问题及解决(作业)

1.gcc、静态库和动态库创建

  • 编写代码:

  • 各种出错:

  • 原因:

(1)mul.c文件中写的返回值类型是double,但是main.c里面错写成int型“%d”。

(2)老师在要求中粘贴的main.c没有包含“head.h”和“stdio.h”两个文件头,是需要自己加上的。

  • 在掉了n多次网之后终于完成了敲对了代码,完成静态库创建:

  • 动态库创建

(1)显示libmath.so没有那个文件或目录。原因:命令写错了,没有加-o

(2)执行可执行文件,提示没有libmath.so的文件,需要注册动态库的路径名。我本来想用书上的方法——可以直接复制到/lib文件下,但是cp了之后它提示权限不够。我用su想获取权限,账号密码不都是shiyanlou吗?! 试了好几次都说认证失败。果断改用目录的形式:

2.makefile

  • 创建makefile文件

也不知道当时我怎么想的居然创建了一个math1文件....
再进去用:w 改名!

原因:

(1)写静态库makefile的时候写错了,把“math1”写成了“math.1”:

(2)恰好创建的时候改名前文件是math1,所以显示的是权限不够,我开始还以为是之前创建的math1有问题,所以删除了math1,之后又显示成了没有文件或目录。改成这样就好了:

  • 吸取经验教训,小心谨慎地创建动态库

原文地址:https://www.cnblogs.com/20135207oneking/p/4842497.html