您的位置:首页 > 运维架构 > Linux

学习笔记:GNU Linux编程指南(第二版):一

2011-09-04 17:30 483 查看
目录:

第一章 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_MASK(int priority) :创建仅由一个优先级组成的掩码
LOG_UPTO(int priority) :创建一个由一系列降序优先级组成的掩码


如LOG_UPTO(LOG_NOTICE)创建的掩码包括了从LOG_EMERG到LOG_NOTICE之间的任何级别的消息。

而LOG_INFO和LOG_DEBUG级别的消息则不能通过

待续...

作者:Jarvis Chu

首发:CSDN Blog

转载请注明出处:/article/1621497.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: