目录:
第一章 Linux及Linux编程综述
第二章 设置开发系统
第三章 使用GNU CC
第四章 使用GNU make 管理项目
第五章 创建可移植的自配置软件 GNU autoconf
第六章 比较和合并源代码文件
第七章 使用RCS和CVS控制版本
第八章 调试
第九章 出错处理
注:原书639页,内容繁多,不易快速定位要点。在第一次阅读过程中,我摘抄要点、记录心得,形成该笔记,供日后查阅和再学习用。
说明:$ 表示 终端输入命令
第一章 Linux及Linux编程综述
1. Linux不是Unix,Unix是一个注册商标,需要满足一大串条款并且支付可观的费用才能被许可使用
Linux在运行特性上与Unix相似,所有内核代码都是由Linus和几位核心黑客手工编写的。
许多Linux上运行的程序,也是手动编写的,当然也有移植的
Linux之所以和Unix相像,是因为它遵循POSIX标准
-------------------------------------------------------------------
第二章 设置开发系统
第三章 使用GNU CC
1. GCC能编译ANSI C和传统C等C语言变体GCC能编译C、C++、Objective C
GNU Compiler Collection
2. 增加搜索路径 -I <针对头文件>
gcc hello.c -I /home/fred/include -o hello
3. 增加搜索路径 -L <针对库文件>
gcc hello.c -L/home/fred/lib -lnew -o hello
gcc首先在/home/fred/lib 下查找库文件,然后到默认路径下搜索
-l 选项使得链接程序使用指定的函数库中的目标代码
4. 通常用法
gcc hello.c -L/home/fred/lib -I /home/fred/include -lnew -o hello
告诉GCC链接libnew.so, 在/home/fred/lib 中查找libnew.so, 以及在/home/fred/include中查找任何非标准的头文件
5. 启用任何一种调试的选项都会让二进制文件的大小急剧增长
6. gcc -c filename 得到目标文件
第四章 使用GNU make 管理项目
1. make是一种控制编译或者重复编译软件的工具make可以自动管理软件编译的内容、方式和时机,从而使程序员能够把精力集中在编写代码上
2. 为何使用make
(1). 包含多个源文件的项目在编译时都有长而且复杂的命令行
(2). 减少重复编译所需要的时间。(编译修改过的部分)
(3). 构建依赖信息数据库,检测是否能找到所需的文件
(4). 能够建立一个稳定的编译环境
(5). 让编译过程自动执行
3. makefile
(1). 文本形式的数据库文件,包含一些规则告诉make编译哪些文件、如何编译以及在什么条件下编译
(2). 规则--三个部分组成
<1>. target : 目标体,即make最终需要创建的东西。
<2>. denpendency: 包含一或多个dependency列表,通常是编译目标体需要的其它文件。
<3>. command : 为了从指定依赖创建出目标体所需要执行的命令列表。
target通常是程序,但可以是文本文件、手册等任何东西。
command可以是编译器的命令或者shell命令,也可以是任何命令行能完成的命令
(3). 通用形式
target : dependency [denpendency [...]]
command
command
[...]
注意:,每个command的第一个字符必须是 制表符
4. 一个makefile文件
sayHelloApp: main.o simple_fun.o simple_fun.h
gcc main.o simple_fun.o -o sayHelloApp
simple_fun.o: simple_fun.c simple_fun.h
gcc -c simple_fun.c
main.o: main.c
gcc -c main.c
.PHONY : clean
clean:
rm main.o simple_fun.o
5. 伪目标
上面的makefile文件中的clean并不是对应实际的文件,是伪目标
伪目标规定了make应该执行的命令
clean没有依赖体,所以它的命令不会被自动执行,使用make clean
如果不使用.PHONY,如果存在clean的文件,make就会发现它,
但是使用了.PHONY后,make不检查是否存在有文件名和依赖体中的一个名字相匹配的文件,直接执行命令
6. 变量
定义: VARNAME=some_text
使用: $(VARNAME)
除用户自定义变量外,make运行使用环境变量、自动变量和预定义变量
(1)环境变量: 如果makefile中有同名的,以makefile中的为准
(2)自动变量: make自动用特定的、熟知的值替换。$(@F) : 目标文件的文件名部分;。。。
(3)预定义变量:用于定义程序名或者给这些程序传递标志和参数。CC : C编译程序;RM :文件删除程序;。。。
7. 模式规则
扩展make的隐式规则的一种方法。
类似普通规则,但是它的目标必定有符号“%”,可以任何非空字符串匹配。
依赖文件也必须使用%
8. 注释
#
9. 命令行
-f file : 指定makefile的文件名
-n : 打印将需要执行的命令,但实际上并不执行这些命令
-s : 在执行时不打印命令名
-w : 如果make在执行时改变目录,打印当前目录名
-d : 打印调试信息
第五章 创建可移植的自配置软件 GNU autoconf
1. autoconf它生成一个能自动配置源代码包的shell脚本,以使程序能够在许多不通品牌的UNIX和类UNIX系统上编译和运行。
这些脚本通常名为configure,它们检查在当前系统中是否提供程序所需要的某些功能,在此基础上生成makefile。
./configure
2. configure.in
为了生成configure脚本,需要在源文件树的根目录下创建名为configure.in 的文件。
它调用一系列autoconf宏来测试程序需要的或用到的特性是否存在,以及这些特性的功能。
3. configure.in 文件的常用格式
AC_INIT #AC_INIT(unique_file_in_source_dir),用来测试当前目录是否正确
测试程序 #每个宏一行
测试函数库 #如果超过一行,需要使用[]和\,[]扩住所有的参数
测试头文件 # AC_CHECK_HEADERS([head1.h header2.h \
测试类型定义 # header3.h])
测试结构
测试编译器行为
测试库函数
测试系统调用
AC_OUTPUT #AC_OUTPUT(file) file是空格分割的输出文件列表
#用于创建名为makefile或者其它名字的输出文件
4. 运行autoscan
autoscan 包含在autoconf软件包中 (sudo apt-get install autoconf),
是Perl脚本
从源文件中抽取与函数调用和头文件有关的信息,并将其输出到configure.scan 文件中。
5. config.h.in文件
包含程序需要的所有#define指令
运行autoconf 自带的名为autoheader的shell脚本
autoheader通过读入configure.in、作为autoconf软件一部分的acconfig.h、
位于源代码根路径下用于保存预处理符号的acconfig.h(即./acconfig.h) 生成 config.h.in文件
6. ./acconfig.h
只需要包含可以被autoconf和autoheader读取和使用的合法定义的C风格预处理符号
让宏其作用,则设置其值为1
7. 流程
(1). 编写源文件 和 Makefile.in文件 和 acconfig.h文件
(2). 运行autoscan 得到configure.scan
(3). 重命名 由configure.scan得到configure.in
(4). 运行autoheader 由acconfig.h 和
configure.in 得到 config.h.in
(5). 运行autoconf 由configure.in 得到 configure
(6). ./configure 由config.h.in 得到 Config.h
由Makefile.in 得到 Makefile
(7). 运行make 由makefile 得到 应用程序app
第六章 比较和合并源代码文件
1. diff 和 patch 区别如果认为 diff 是通过从一个文件中减去另一个文件来生成者两个文件的差别文件
那么可以认为 patch 是使用这个差别文件和其中的源文件来生成另一个源文件
2. diff 并排输出两个文件
diff -y -W 80 a.vim b.vim
3. diff3
当两个人同时修改一个共用文件时,diff3 就会发挥作用。
它比较两个人做出的两套修改内容,创建第3个文件保存合并后的输出结果,并且指出双方修改的冲突之处。
第七章 使用RCS和CVS控制版本
第八章 调试
1. GDB GNU DeBugger自由软件联盟(Free Software Foundation,FSF)的主要软件工具之一
2. make progname
编写源文件main.c
使用make main.c,则输出cc main.c -o main,并得到main可执行文件
3. gdb 的使用步骤
(1). 使用gcc -g test.c -o test
使用-g 选项,编译出的可执行代码才包含调试信息,否则gdb无法载入改执行文件
(2). gdb test [core]
core 为可选的文件,内存转存文件,增强gdb调试能力
至此进入gdb命令交互界面
4. gdb 常用调试命令
(1). l 查看所载入的文件
注:gdb 中都可以使用缩略形式:
如 l 代表 list;
b 代表 brekpoint;
p 代表 print
r 代表 run
n 代表 next
c 代表 continue
(2). b 设置断点
b 6 在第6行设置断点
tbreak 6 设置临时断点,运行到后就自动移除
ignore 6 忽略断点6
enable 6 激活断点6
disable 6 使断点6失效
(3). info b 查看断点
(4). delete 移除断点
delete 1 移除断点号为1的断点
(5). run 运行代码
默认从代码首行运行
run 6 从第六行运行
(6). p 查看变量值
p i : 查看变量i 的值
结果显示:$1 = 2
'$1' 是变量i的标志
(7). n\s 单步运行
当有函数调用时,s 会进入函数,n 不会进入函数
(8). c 继续
c : 运行,直到函数结束或者下一个断点
finish: 运行,直到函数结束
5. gdb 其它常用命令
(1). help
$ help
$ help running
第九章 出错处理
1. assert #include <assert.h>
void assert(int expression);
如果expression值为假(0),则向stderr打印一条出错信息,然后通过函数abort来终止程序运行
2. 如果在
include <assert.h> 之前加上下面的语句
#define NDEBUG
则不会调用assert宏
3. 使用系统日志
Linux 用两个守护进程 klogd 和 syslogd 提供了集中的系统日志功能
syslogd 控制着来自用户空间程序的消息的产生。
klogd 供内核和运行在内核空间的程序,特别是设备驱动程序所使用。
大多数Linux系统,系统日志位于/var/log 目录下,包括如:messages,debug,mail,news等等
还可能有其它的日志,取决于/etc/syslog.conf中定义的日志功能配置(注:Ubuntu没有文件)
标准的控制台日志守护进程是syslogd,由它来维护这些日志文件。
写入系统日志的消息由它的级别(level)和功能(facility)来控制,
级别指出了消息的严重性或重要性,而功能告诉维护系统日志的syslogd守护进程是哪个程序发送的这条消息
一条日志消息的级别和功能合起来被称为它的优先级(priority)。
4. syslog的日志级别
级别 严重性
LOG_EMERG 系统不可用
LOG_ALERT 要求立即处理
LOG_CRIT 重大错误,比如硬盘故障
LOG_ERR 错误条件
LOG_WARNING 警告条件
LOG_NOTICE 正常但重要的消息
LOG_INFO 纯粹的通报消息
LOG_DEBUG 调试或跟踪输出
5. syslog的功能值
功能 消息源
LOG_AUTHPRIV 私有的安全和授权消息
LOG_CRON 时钟守护进程(crond 和 atd)
LOG_DAEMON 其它系统守护进程
LOG_KERN 内核消息
LOG_LOCAL[0-7] 为本地/站点使用而保留
LOG_LPR 打印子系统
LOG_MAIL 邮件子系统
LOG_NEWS 新闻子系统
LOG_SYSLOGsyslog 产生的内部消息
LOG_USER (默认值)一般用户级消息
LOG_UUCP uucp子系统
注:当出现错误时,对于用户级程序来说LOG_WARN已经足够了
LOG_INFO 对于日常烦人的日志消息最合适
LOG_ERR 出现了可能致命的系统错误
6. 系统日志函数
头文件 <syslog.h> 定义了syslogd的接口。
创建一个日志消息,使用syslog函数,原型为:
#include <syslog.h>
void syslog(int priority, char* format,...);
priority 是级别和功能的位逻辑“或”值
format指定写入日志的消息和任何类似printf的格式说明字符串
%m 由strerror为errno分配的错误消息 替换
7. 简单的例子
/***********************************************************
程序代码
/***********************************************************/
#include <stdio.h>
#include <syslog.h>
int main(int argc,int** argv)
{
//LOG_WARNING 结果写入 /var/log/syslog 文件中
syslog(LOG_WARNING | LOG_USER,\
"This is a warning from %s,%s %s,%m\n",\
__FILE__,__DATE__,__TIME__);
//ubuntu下,LOG_INFO 结果也是写入 /var/log/syslog 文件中
//LOG_USER是默认的功能级
syslog(LOG_INFO,"This is a normal message from %s\n",__FILE__);
return 1;
}
/***********************************************************
运行结果
/***********************************************************/
/*
在/var/log/下的syslog文件中,有如下两条记录条记录:
Sep 3 16:39:52 jarvischu-Studio-1435 using_syslog: This is a warning from using_syslog.c,Sep 3 2011 16:39:47,Success
Sep 3 16:39:52 jarvischu-Studio-1435 using_syslog: This is a normal message from using_syslog.c */
8. openlog 定制日志操作,主要是加上前缀
#include <syslog.h>
void openlog(const char *ident, int option, int facility);
ident:
指定加到日志消息前的字符串
option: 多个选项的位逻辑“或”值
LOG_PID 在每条消息中包含PID
LOG_CONS 如果消息不能写入日志文件,则发送到控制台
LOG_NDELAY 立即打开链接(默认是在syslog第一次被调用时才打开链接)
LOG_PERROR 把消息写入日志文件的同时也输出到stderr
facility:即 5. 中的某个值
例:
openlog("JarvisChu",LOG_PID,LOG_USER);
syslog(LOG_INFO|LOG_USER,"This is a message\n");
则在/var/log/syslog 文件中,有如下记录:
JarvisChu[1231]:This is a message
9. 其它函数
(1). closelog()
如同openlog,可选的,关闭openlog打开的文件描述符。
(2). int setlogmask(int priority);
设置所有日志消息的默认级别,(即哪些级别的消息能写入syslog,哪些不能写入)
函数返回原来的优先级
syslog拒绝任何没有在掩码中设置的优先级消息
同 宏:
如LOG_UPTO(LOG_NOTICE)创建的掩码包括了从LOG_EMERG到LOG_NOTICE之间的任何级别的消息。LOG_MASK(int priority) :创建仅由一个优先级组成的掩码 LOG_UPTO(int priority) :创建一个由一系列降序优先级组成的掩码
而LOG_INFO和LOG_DEBUG级别的消息则不能通过
待续...
作者:Jarvis Chu
首发:CSDN Blog
转载请注明出处:http://blog.csdn.net/jarvischu/article/details/6747420