当前位置:首页 » 编程软件 » makefile条件编译

makefile条件编译

发布时间: 2022-04-26 06:15:29

c语言条件编译用常量表达书做条件,此常量表达式必须在编译时可求也就能不能让条件由scanf得到的

程序在编译时是不会执行scanf的 所以不能

② makefile中:all和:debug是什么意思

一般,在开发测试阶段用debug版本,而上线发布用release版本。 使用Makefile定制编译不同版本,避免修改程序和Makefile文件,将会十分方便。 读了一些资料,找到一个解决方法,Makefile预定义宏与条件判断,结合make预定义变量,进行条件编译。 ...

③ C语言学习路线

一,UNIX下C语言的学习路线。
工具篇
“公欲善其事,必先利其器”。编程是一门实践性很强的工作,在以后的学习或工作中,将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工具。
(一)操作系统
在UNIX或linux系统中学习C很方便,所以在开始的学习旅程前请先选择一个UNIX或Linux操作系统。
目前可供个人免费使用的UNIX或Linux系统有FreeBSD、RedHat Linux、SUSE Linux等,而且在安装包中还提供很多实用的工具,如:gcc, make等。
如果您一直使用Windows,身边又没有多余的机器安装UNIX,则可以使用VMware,通过VMware安装虚拟系统。
(二)编译工具
目前绝大多数Unix或Lnux系统都提供CC或GCC编译器,最简单的cc命令格式如下:
cc -o hello hello.c
在unix shell环境中敲入上面的代码会将hello.c程序编译成可执行文件hello。
make 工具如 GNU make、System V make 和 Berkeley make 是用来组织应用程序编译过程的基本工具,但是每个 make 工具之间又有所不同。
大部分UNIX和Linux程序都是通过运行make来编译的。make工具会读取一个包含指令的文件(这个文件的名字通常都是 makefile 或 Makefile,不过后文中统一称之为 “makefile”),并执行各种操作来编译程序。
(三)调试工具
最简单的调试工具:为程序添加打印语句
在对程序的运行机制有了一定的了解后,可以实用一些工具帮助进行调试,当然得学习一下这些工具得使用,如:dbx,gdb等。
还有一些内存工具可以帮查找内存泄漏或缓冲区溢出等一些问题,如:memwatch,yamd等
(四) 其他工具
1. vi或vim
Unix下文本编辑器。主要靠一堆命令来编辑文本文件,学Unix编程最好熟悉并熟练使用vi编辑器。
当然在实际工作中,可能需要一个集成编码环境或一个功能强大的图形化编辑工具。
2.netterm
最着名的网络终端软件之一,可以使用它方便的连接到主机系统中。
3.Secure shell
一个支持ssh协议得客户端工具,多数情况下用来连接linux系统。
书籍篇
“书是人类进步得阶梯”。学习一门新的知识,当然要选择几本适合自己得书籍,下面介绍一些我自己学习C语言使用过的书籍:
1.《C primer plus》
推荐理由:适合作为入门书和基本函数查询得参考资料。本书最新版为第五版,以ANSI C99为标准详细介绍了C语言。
2.《The C programming_Language》
推荐理由:C语言之父得作品权威性毋庸置疑。虽然书籍出版时间比较老,好像也没更新,不过仍不失为经典书籍,网上有这本书得英文电子版提供下载。
3.《C 专家编程》
推荐理由:本书可以帮助有一定经验的C程序员成为C编程方面的专家,最关键的是本书寓教于乐,充分享受编程的乐趣。
4.《C缺陷与陷阱》
推荐理由:书中所揭示的知识能帮助绕过C语言自身得陷阱和缺陷,减少代码中许多常见的Bug。
5.《unix环境高级编程》
推荐理由:既然是UNIX环境下C编程,就不得不说说UNIX编程书籍。Stevens先生的《unix环境高级编程》是竭力推荐的,也是案头必备(如果对网络编程有兴趣的,可以学习一下Stevens先生的《UNIX网络编程》两卷,如果觉得还不过瘾,可以再看看《TCP/IP详解》三卷)。
6.《计算机编程艺术》
推荐理由:算法大师得呕心沥血之作。计划出版五卷书,目前好像已出版3卷。对算法有兴趣得可以研究一下。
过程篇
1.学习C语法
语法的学习对于一个具有编程底子的来说,就很轻松了;即使以前没有学习过其他编程语言,我相信有2个星期,也能轻松搞定。
需要注意的是,不要太纠缠于语言的细节,比如:运算符优先级与结合性的问题等。
2.学习C标准库
ANSI C库把函数分为不同的组,每个组都具有与之相关的头文件。C语言标准库相对于其他语言,比如C++,Java来说是非常短小精悍的,但首先应着重对以下库进行学习:
ctype.h:字符处理
math.h:数学库
stdio.h:标准I/O库
stdlib.h:通用工具库
string.h:字符串处理
time.h:时间和日期
如果想了解完成的ANSI C库,可以购买相关的书籍,这些书籍一般会详细介绍每个函数的用户和一些注意点;
3.攻克C的难点
C语言声明:
C语言的声明确实觉得恐怖,比较晦涩难懂,而且声明的形式和使用的形式还类似。比如如下的声明恐怕就连很多熟悉C多年的程序员也不是一眼就能看出来的:
char * const * (*next)();
那么有没有一种好的记忆方法或规则来搞清楚呢,好像没有,如果有的话也不是这样折磨人了。不过可以看看《C专家编程》第三章的内容,或许会有所收获。
也只能多学多练了,所谓熟能生巧嘛,希望这个问题不要在你的心灵上留下阴影。
数组与指针:
数组与指针的关系,在标准中并没有作很详细的规定,而且好多C入门的书籍在这个问题上并没有给出很详细的说明,所以会给人造成很多误解。
对于这个问题,可以参考《C缺陷与陷阱》4.5节和《C专家编程》第4,9,10章,相信这里面的内容搞透彻,以后就不会再被这个问题搞迷惑。
指针与内存:
如果以后编写规模较大的程序,可能发现这个问题可能会是最大的烦恼,而且可能会是消耗最多调试时间的事项。
C版本的问题:
得特别小心该问题,最好不要的程序中混合使用不同版本C的特性,否则会带来很迷惑的问题。如果一定要用,最好清楚自己在做什么。
4. UNIX环境编程
学习了以上内容之后,就可以进行unix环境编程了。不过可能需要对操作系统理论有一点点的了解,这样学起来会比较轻松一些。
Unix环境编程,应该着重IO和进程两大块内容。《Unix环境高级编程》中对Unix环境编程有着非常详细且深入的论述,而且书中有大量实用性例子程序,不过可能得花上几个月得时间,好好啃一啃了。
在扎实掌握以上内容,不代表得C语言学习支路已经完成,相反,才刚刚开始。以后需要用学到得知识去解决大量不同实际问题,在不断得实践过程中,会近一步加深对C的理解。有了以上基础之后,会发现,在实践过程中需要的其他知识,会非常快速的掌握。
二,Windows程序员的学习路线
1.当然要熟悉下C语言了 入门可以选用潭浩强的 《C程序设计》(当然最好能读C Programming Language)特别要对其中的指针,结构体等东西一定要搞清楚了(要学好的很好至少要花费一个月时间) 为什么要从C开始呢:<1> C好学 <2> 大多数的操作系统核心部分是用C开发的 <3> C的效率高且语言成熟
2.在1的基础之上一定要认真学习一下数据结构 对C++程序员来说良好的数据结构可以让一个程序员很轻松的完成程序设计 糟糕的数据结构可以把一个程序员累死 推荐书籍:严蔚敏的《数据结构(C语言版)》或北京大学的一本中C++版的数据结构 书中说到的每个主体在程序设计中都会用到 认真学好会对的以后的C++程序设计有太多的好处 (3个月时间)
3.学好了2之后可以学习下《C++ PROGRAM DESIGN》这本书初步介绍了C++和如何使用C++写出Windows下的程序(要学好至少要花费3个月时间)
4.在3的基础之上可以读一本叫《Windows 95 程序设计》(它的最新版本是Programming Windows)这是一相Windows程序设计的领域的不朽之作(3个月时间) 通过2和3的学习已经成为了一个可以设计Windows程序的程序员了 要想更好的设计Windows程序设计 一定要借助框架结构不可 为什么:框架结构可以加快我们程序设计的速度 虽然使用框架使得我们的程序的效率低了那么一点 但随着当今计算机的运算能力的提升,不会感觉到这一点点的性能损失的反而会因为你使用的框架结构而使你的程序设计加快了速度 使用框架结构才算一个真正的VC++程序员
5.在4的基础之上可以看一些简单的MFC程序设计的书比如《Visual C++入门教程》之类的图书 这可以使你能写出一些带有通用控件的MFC程序 (1个月时间)
6.在5的基础之上已经可以很快开发一个软件了 但不了解MFC框架运行机制是很不好的 了解MFC的运行机制可以使以后的MFC程序设计工作做的更好 推荐书籍侯杰的《深入浅出MFC》 但这本书真的不适合初学者当你有了一定的开发经验以后这本书对来说确实很好 若很熟悉Windows下的SDK程序设计并打算或已经开始使用MFC进行软件开发 那这本书对来说再好不过了 (2个月时间)
7.在6的基础之上可以看下这本书《VC++技术内幕》由潘爱民译的 推荐看原着(3个月)
8.在以上基础之上为了更好的使用VC++这个工具 推荐看一下《VC++6.0宝典》(3个月) 从开发工具的角度讲这本书写的很好
9.为了更好的工作可以参考一下VC++程序设计百例
10.之后可以看一下《Windows核心编程》 这本书很好的讲解了Windows的编程 对你写系统程序很有好处的 推荐看原版
11.只了解其形不算真正的了解 之后还要认真的读一下Windows的内核源码 相信WRK 很容易找到的 可以配合《深入解析Windows操作系统》《Windows内核原理与实现》和《Windows内核情景分析》
12.其它一些东东《COM原理》(潘爱民) OpenGL D3D VC的数据库编程 图形图像 音视频处理和网络都要有所了解和会使用
13.要做到一个好的程序员一定要对驱动程序有所了解所以写一个文件驱动之类的东东是很有必要的
14.经过以上各步的学习完全成为一个优秀的Windows程序员了(前提是每一步要学好)
15.漏了一些重要的东东 编译原理 汇编及 组成原理 和设计模式等也是很重要的东东 只有学好了这些才能明白语言为什么要这样组织才能高效。

④ c代码编程问题,怎样初始化已定义的结构体

第一章:前言
对于c语言,有人认为它已经落伍了.对于这个问题,仁者见仕,智者见智.的确,c++比c有更强大的诸多优势.但c++是建立在c之上的.这也是herbert schildt所着的<>在全世界畅销不衰的原因.更何况,要深入学习linux就必需要有相当的c功底.(这也是我搜集整理本文的根由:-)
现结合个人在编程中的体会,为使新手少走弯路,为老手锦上添花,因此无论你是使用c或c++编程,也无论你是程序设计的初学者还是成熟的专业人员,均会发现,本文将会对你有所收益.当然,我尽力写得清晰易懂,又不古板.
我爱c.(正如世人爱上帝一样:-)..

你可以在forum.linuxaid.com.cn上获得此帖的文本.而其html版本正在赶制之中......

第二章:约定
专业的源程书写风格.
先看看世界级c大师的源程书写风格.如 steve maguire 就有许多不错的建议.

[]倡导使用易于理解的"匈牙利式"的命名约定.
所有的字符变量均以ch开始; 如: char ch_****;
所有的字节变量均冠以b; 如: byte b_****;
所有的长字变量均冠以l; 如: long l_****;
所有的指针变量均冠以p; 如: char *p_ch_****;
建议类型派生出的基本名字之后加上一个以大写字母开头的"标签".如:
分析 char **ppchmydata;
其让人一眼就能看出它****一个指向字符指针mydata的指针.
"匈牙利式"命名的最大不足是难念:-(( .但相对于不是总统演讲稿的c源程来说,这又算得了什么?想想看以下的数据命名:
char a,b,c;
long d,e,f;
[]倡导规范书写.
如果你思如泉涌,而不去也不及顾虑书写格式,那也没关系.在将其交出去之前,用cb命令格式化你的源程.虽然源程的格式不会影响到你编译结果的正确性,但切记,能让其他的程序员能轻松地阅读它.否则没人会理你的.
关于cb命令的更多用法,可以用man cb来参考其手册页.
当然除了cb之外,还有更多更好的.但cb是你在任何unix(linux)上都找得到的.更何况它并不差
第三章:开始任务
开始任务之前,先做个深呼吸!
[]其他文档你准备好了吗?
你是不是除了c源程之外一无所有了吗?兵马未动,粮草先行.你必须先清楚该程序所要完成的功能.在开始写程序之前,对程序的功能应有规范说明.书写规范书和确知程序功能的一个方法是先编写相应的操作手册.如果你是一人单干,劝你首先写需求书.切记切记,这对你意味着事半功倍的大好事.
一个实例:我计划为本行的信贷子功能模块打一个补丁.我用10周的时间用来写规划书,需求书,操作流程,使用说明等等文档.之后用2周的时间编写程序,在初步测试(1周)后递交给各信贷部门测试使用.然后根据反馈的信息再更改相应文档,并根据文档修改源程.6个月后发布正式版.
[]一定该遵循ansi标准吗?
如果你仅使用ansi的标准首标文件,恭喜你,你的程序有着全世界范围内的广泛支持和兼容.光明无限.但你必须在通用与专用之间做出取舍,对不起,我帮不了你.
我的原则是:核心用ansi,界面按需而取.这样在转换平台时仅需另编用户界面而已.实用至上嘛.
附:ansi 标准c头文件

是不是很寒酸?
[]再续前缘?
在得到新任务之后并在开始该新任务之前应马上回想有哪些是曾经拥有的.旧调重弹远比另起炉灶来的高效与环保.
[]是否该有自已的库?
我的答案是应该有自已的特色库,并与ansi兼容.与3.8不同的是,你仅需在源程序之后附上自已的专用库就可以了.其次在有了自已的库后,源码会很精炼的.不用去羡慕别人了吧.
[]要学会条件编译.注意你的平台特性.(高手的标志?)
除非你确定你要写的程序是在某特定的os特定的硬件平台而量身定做.否则应注意数据类型的长度,精度都是不同的,不要想当然.有时甚至是不同的编译器的差异都要考虑考虑.
....
....(欢迎您来充实此处空白)
....
好了,在任务中,又有哪些细节呢?
[]我是不是葛郎台?
不要那么吝啬.在源程序中加入详尽的注释以使自己和他人即使在许多年以后仍能读明白它是什么样的程序.
用注释行分离各个函数.
[]删除不需要的代码时要小心.
一个好建议是:使用#ifdef del,而不是简单地注释掉甚至是粗暴地直接dd.如果你是使用/* ... */,但一旦要删除的代码有很多行,或注释中以有注释时,这就可能不那么好使了.
[]如何给源程序文件命名?
表现特色且不与任何原有应用名相同.一个简单地方法就是试试看,系统有什么样地反应?
[]一次只修改一个地方.
[]一次只编写一个单一功能的函数。
[]编写通用程序.
只有当程序编写完,并且完成了所需要的性能要求之后,再反过头来优化该程序.
[]不要使用a.out作为结果.你大可以使用与源程相同的可执行文件名.
[]是否一定要用vi编辑?
linux下有许多专用编程编辑器.它们能使你有更高的效率和更低的低级输入错误,但我还是要劝你至少要熟练掌握vi.毕竟vi遍地开花.
[]协同作业.请相信,你不是在孤军作战.因此,你有必要熟练掌握一些其它的工具

第四章:使用lint
lint没有你想象中的那样糟糕.相反,一旦源程序形成了没有lint错误的形式,将很容易保持下去,并享受到如此而带来的好处.
[]在cc(gcc)之前就应使用lint.
lint是一语法检查程序,对于这个多嘴的婆婆来说,你应有足够的耐心.虽然你知道自已在干什么,但在cc之前使用lint总是一个好习惯.
[]lint有哪些特色?
在编译之前使用lint的重要原因是lint不但能发现ansi c中的语法错误,而且也能指出潜在的问题或是难于移植于另一机器的代码问题.除了能指出简单语法错误之外,linut还能基于以下原因指出另外的错误:
a.无法达到的语句.
b.没有进入循环.
c.没有被使用的变量.
d.函数参数从未使用.
e.没有赋值之前自动使用参数.
f.函数在有些地方有返回值,但在其他地方不返回.
g.函数调用在不同地方使得参数个数不同.
h.错误使用结构指针.
i.模糊使用操作符优先级.
呵呵呵,挺有用的吧!
[]如何控制lint的输出?
有时lint会有一大屏一大屏的警告信息.但似乎并未指出错误.为了找出潜在的错误则需费心费力地浏览这些大量的警告信息.
但如果你的程序会分出几个独立的模块,在初级启动lint时不要用可选项.当对这些模块进行更改或扩充时,可以忽略与代码无关的某些警告.为此可用以下选择项:
-h 对判别是否有错,类型是否正确不给出启发式测试.
-v 不管函数中没有定义的参数
-u 不管被使用的变量和函数没有定义或定义了但没有使用.
[]干脆,在程序中插入指令来影响lint运行.它看样子有些像注释.
/*notreached*/ 不可达到的代码不给信息说明.
/*varargsn*/ 函数的变量个数不作通常的检查,只检查开始n个参数的数据类型.
/*nostruct*/ 对下一个表达式不作严格类型检查.
/*argused*/ 下一函数中,不给出没被使用参数的警告信息.
/*lintlibrary*/ 置于文件的开头,它将不给出没被使用函数的警告信息.
关于lint的更多用法,请用man lint来获知

第五章:使用make
[]什么是make?
unix(linux)是一个天生的开发平台,我为此感到高兴.make是一个强力的工具.它能依赖的源代码块并组成一程序,使得很容易建立一可执行程序.make就是这种有依赖关系的部分和代码之间所作的规格说明.
[] 所有的程序都要使用make?
是的.尽管你只有几个简单的模块,但你需要有一种结构来支持它从简单走向复杂.除非你的程序已经盖棺定论.
[]makefile由哪些组成?
makefile由以下几个部分组成:
注释.
^^^^
使用#符号插入.make将忽略#之后的任何内容以及其后的return键.
变量.
^^^^
make允许定义与shell变量类似的有名变量.比如,你定义了sources=prog.c,那么该变量的值$(scoures)就包含了源文件名.
依赖关系.
^^^^^^^^
左边是目标模块,后接一冒号.再接与该模块有依赖关系的模块.
命令.
^^^^
以tab键开始(即使用相同数量的空格也不能代替它).
[]makefile示例
下面介绍一个简单的示例来说明make的用法.假设你的程序有两个源文件main.c和myc.c,一个位于子目录include下的头文件myhead.h,一个库由****源文件myrout1.c,myrout2.c,myrout3.c产生.
其makefile文件为:
#一个基本的makefile文件.
#其中包括个人的头文件和个人库.
headers=include/myhead.h
sources=main.c myc.c
proct=$(home)/bin/tool
lib=myrout.a
libsoures=myrout1.c myrout2.c myrout3.c
cc=cc
cflags=-g
all:$(proct)
$(proct):$(sources)
$(cc)$(cflags) -o $(proct)$(sources)
lint:$(proct)
lint $(sources)$(libsources)
哈哈,挺象shell编程的.如果你与我一样使用linux下的gcc,那么只要把上面的cc=cc改为cc=gcc即可.怎么样,想来一个更复杂点的吗?
[]一个更为复杂的makefile
你是否注意到,在上例中,只要启动make,就会重新编译所有源代码.
如果你能看懂以下的makefile,恭喜恭喜,你通关了.
#一个更为复杂的makefile
headers=include/myhead.h
soures=main.c myc.c
objects=main.c myc.c
proct=$(home)/bin/tool
lib=myrout.a
libsources=myrout1.c myrout2.c myrout3.c
libobjects=$(lib)(myrout1.o)$(lib)(myrout2.o)$(lib)(myrout3.o)
include=include
cc=cc
cflags=-g -xc
lint=lint
lintflags=-xc
all:$(proct)
$(proct):$(objects)$(lib)
$(cc)(cflags)-o$(proct)$(objects)$(lib)
.c.o: $(headers)
$(cc)$(cflags) -c i$(include)$<
$(lib):$(headers)$(libsources)
$(cc) $(cflags) -c $(?:.o=.c)
ar rv $(lib) $?
rm $?
.c.c:;
lint: $(proct)
$(lint)$(liniflags)$(sources)$libsources)

第六章:优质无错编程
亲爱的,检查一下,你是否注意到了以下的细节?也就是说,你是否是一个合格的,能编写优质无错代码的程序员?要永远记住,编写无错代码是程序员的责任,而不是测试员.(摘录于本人的"细节页",因此本节将永远不会保持完整,欢迎您来充实她)
[]所有程序员至少出现过的一个错误:
if(a=3){......}如果a等于3,那么......
你至少要养成这样的习惯:当判断一个变量与一个常量是否相等时,将常量写在前面.这样即使你一不小心写成这样:if(3=a){......}在cc 之前就可以很容易发现它.
[]老调重弹:逻辑操作符的优先权.
我不愿多嘴.总之,如果你一定要编写如下代码时:
if(a&0x1&&b&0x2){......}
你的手头最好有一本详尽的指南.或者你是这方面的专家.
[]尽量不使用int数据类型.
这仅是一个忠告.你大可使用char,short,long数据类型.若干年以后,当你成长为高手之时,你会发现此时我的良苦用心.
[]对于非整型函数一定要完整定义.
如 long float jisuan(char charr[],int chnum)
{ long float lmydata;
...
...
return(lmydata); }
[]对于非整型函数的输入要当心.
如 long float lfnum;
...
...
scanf("%lf",&lfnum);
[]float 型的有效数字为7位.当多于7位时,第8位及以后的位将不准确,可以将其定义为long float型.
[]文件的输入出尽量采用fread fwrite函数.只有当另有用途时才用fprintf fscanf 函数

⑤ vcs生成覆盖率时,条件编译的顶层会被当做不同的项目,合并覆盖率时会出错,怎么解决

 要生成覆盖率报告,要在编译和仿真的时候,加入一个选项。 -cm  line | fsm | tgl | cond , 指定生成针对什么条件的覆盖率报告。如下的makefile,就生成上述四个的覆盖率报告。注意,编译和仿真,都要加上-cm这个选项。执行 make vcs , make sim后,会生成simv.vdb文件夹,该文件夹下包含了覆盖率的内容,但是我们需要将内容生成报告,这样,才方便我们查看。生成报告,使用的是 urg命令,该命令也是属于vcs工具里面的-dir: 指定 .vdb文件夹的位置report: 指定生成报告的格式,报告格式有两种,一种网页格式,一种text格式。这里,both代表生成两种。执行 make urg后,就会生成both文件夹。  这文件夹下的文件,就是覆盖率报告了。打开dashboard.html。可以看到整体的一些信息。但是我们关心的是设计的,而不是testbench的。点击hierarchy,得到层次。点击u1,也就是设计的顶层。可以看到关于该顶层的信息。因为在顶层,都是调用各个子模块(这里是调用 band_generaterx_tx, uart_txd模块),所以没有line的覆盖率统计,但是有TOGGLE的覆盖率统计,也就是信号的翻转。从上面可以看出,对于rst_n信号,没有从1->0的翻转,而这个信号是testbench中传递的,因此看出,在testbench设计,对于rst_n信号产生,有bug。点击左下角的uart_txd_1,查看该模块的信息。  对于该设计,因为有具体的实现,所以可以看到有line的覆盖率,toggle的覆盖率,FSM的覆盖率。对于line覆盖率,从报告看出,总共有42行,覆盖到了41行。通过查看代码,可以知道是哪一行没有被执行到。对于toggle覆盖率。从报告看出,只有rst_n有问题,而这问题是testbench的的bug造成的。对于FSM的检查。从报告看出,每个状态都有被覆盖到。但是从有些状态跳转到另外的状态,没有被覆盖到。因此造成FSM的覆盖率不高。通过查看覆盖率报告,可以查找到设计的缺陷,从而进行修正。

⑥ 如何编译linux版本

编译安装内核
下载并解压内核
内核下载官网:https://www.kernel.org/
解压内核:tar xf linux-2.6.XX.tar.xz
定制内核:make menuconfig
参见makefile menuconfig过程讲解
编译内核和模块:make
生成内核模块和vmlinuz,initrd.img,Symtem.map文件
安装内核和模块:sudo make moles_install install
复制模块文件到/lib/moles目录下、复制config,vmlinuz,initrd.img,Symtem.map文件到/boot目录、更新grub
其他命令:
make mrprobe:命令的作用是在每次配置并重新编译内核前需要先执行“make mrproper”命令清理源代码树,包括过去曾经配置的内核配置文件“.config”都将被清除。即进行新的编译工作时将原来老的配置文件给删除到,以免影响新的内核编译。
make dep:生成内核功能间的依赖关系,为编译内核做好准备。

几个重要的Linux内核文件介绍
config
使用make menuconfig 生成的内核配置文件,决定将内核的各个功能系统编译进内核还是编译为模块还是不编译。
vmlinuz 和 vmlinux
vmlinuz是可引导的、压缩的内核,“vm”代表“Virtual Memory”。Linux 支持虚拟内存,不像老的操作系统比如DOS有640KB内存的限制,Linux能够使用硬盘空间作为虚拟内存,因此得名“vm”。vmlinuz是可执行的Linux内核,vmlinuz的建立有两种方式:一是编译内核时通过“make zImage”创建,zImage适用于小内核的情况,它的存在是为了向后的兼容性;二是内核编译时通过命令make bzImage创建,bzImage是压缩的内核映像,需要注意,bzImage不是用bzip2压缩的,bzImage中的bz容易引起误解,bz表示“big zImage”,bzImage中的b是“big”意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有gzip解压缩代码,所以你不能用gunzip 或 gzip –dc解包vmlinuz。 内核文件中包含一个微型的gzip用于解压缩内核并引导它。两者的不同之处在于,老的zImage解压缩内核到低端内存(第一个640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么可以采用zImage 或bzImage之一,两种方式引导的系统运行时是相同的。大的内核采用bzImage,不能采用zImage。 vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件。
initrd.img
initrd是“initial ramdisk”的简写。initrd一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态。比如initrd- 2.4.7-10.img主要是用于加载ext3等文件系统及scsi设备的驱动。如果你使用的是scsi硬盘,而内核vmlinuz中并没有这个 scsi硬件的驱动,那么在装入scsi模块之前,内核不能加载根文件系统,但scsi模块存储在根文件系统的/lib/moles下。为了解决这个问题,可以引导一个能够读实际内核的initrd内核并用initrd修正scsi引导问题,initrd-2.4.7-10.img是用gzip压缩的文件。initrd映象文件是使用mkinitrd创建的,mkinitrd实用程序能够创建initrd映象文件,这个命令是RedHat专有的,其它Linux发行版或许有相应的命令。这是个很方便的实用程序。具体情况请看帮助:man mkinitrd
System.map是一个特定内核的内核符号表,由“nm vmlinux”产生并且不相关的符号被滤出。
下面几行来自/usr/src/linux-2.4/Makefile:
nm vmlinux | grep -v '(compiled)|(.o$$)|( [aUw] )|(..ng$$)|(LASH[RL]DI)' | sort > System.map
在进行程序设计时,会命名一些变量名或函数名之类的符号。Linux内核是一个很复杂的代码块,有许许多多的全局符号, Linux内核不使用符号名,而是通过变量或函数的地址来识别变量或函数名,比如不是使用size_t BytesRead这样的符号,而是像c0343f20这样引用这个变量。 对于使用计算机的人来说,更喜欢使用那些像size_t BytesRead这样的名字,而不喜欢像c0343f20这样的名字。内核主要是用c写的,所以编译器/连接器允许我们编码时使用符号名,而内核运行时使用地址。 然而,在有的情况下,我们需要知道符号的地址,或者需要知道地址对应的符号,这由符号表来完成,符号表是所有符号连同它们的地址的列表。
Linux 符号表使用到2个文件: /proc/ksyms 、System.map 。/proc/ksyms是一个“proc file”,在内核引导时创建。实际上,它并不真正的是一个文件,它只不过是内核数据的表示,却给人们是一个磁盘文件的假象,这从它的文件大小是0可以看 出来。然而,System.map是存在于你的文件系统上的实际文件。当你编译一个新内核时,各个符号名的地址要发生变化,你的老的System.map 具有的是错误的符号信息,每次内核编译时产生一个新的System.map,你应当用新的System.map来取代老的System.map。
虽然内核本身并不真正使用System.map,但其它程序比如klogd, lsof和ps等软件需要一个正确的System.map。如果你使用错误的或没有System.map,klogd的输出将是不可靠的,这对于排除程序故障会带来困难。没有System.map,你可能会面临一些令人烦恼的提示信息。 另外少数驱动需要System.map来解析符号,没有为你当前运行的特定内核创建的System.map它们就不能正常工作。 Linux的内核日志守护进程klogd为了执行名称-地址解析,klogd需要使用System.map。System.map应当放在使用它的软件能够找到它的地方。执行:man klogd可知,如果没有将System.map作为一个变量的位置给klogd,那么它将按照下面的顺序,在三个地方查找System.map: /boot/System.map 、/System.map 、/usr/src/linux/System.map
System.map也有版本信息,klogd能够智能地查找正确的映象(map)文件。
makefile menuconfig过程讲解
当我们在执行make menuconfig这个命令时,系统到底帮我们做了哪些工作呢?这里面一共涉及到了一下几个文件我们来一一探讨
Linux内核根目录下的scripts文件夹
arch/$ARCH/Kconfig文件、各层目录下的Kconfig文件
Linux内核根目录下的makefile文件、各层目录下的makefile文件
Linux内核根目录下的的.config文件、arch/$ARCH/configs/下的文件
Linux内核根目录下的 include/generated/autoconf.h文件
1)scripts文件夹存放的是跟make menuconfig配置界面的图形绘制相关的文件,我们作为使用者无需关心这个文件夹的内容
2)当我们执行make menuconfig命令出现上述蓝色配置界面以前,系统帮我们做了以下工作:
首先系统会读取arch/$ARCH/目录下的Kconfig文件生成整个配置界面选项(Kconfig是整个linux配置机制的核心),那么ARCH环境变量的值等于多少呢?它是由linux内核根目录下的makefile文件决定的,在makefile下有此环境变量的定义:
SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ )
..........
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
或者通过 make ARCH=arm menuconfig命令来生成配置界面
比如教务处进行考试,考试科数可能有外语、语文、数学等科,这里我们选择了arm科可进行考试,系统就会读取arm/arm/kconfig文件生成配置选项(选择了arm科的卷子),系统还提供了x86科、milps科等10几门功课的考试题
3)假设教务处比较“仁慈”,为了怕某些同学做错试题,还给我们准备了一份参考答案(默认配置选项),存放在arch/$ARCH/configs/目录下,对于arm科来说就是arch/arm/configs文件夹:

此文件夹中有许多选项,系统会读取哪个呢?内核默认会读取linux内核根目录下.config文件作为内核的默认选项(试题的参考答案),我们一般会根据开发板的类型从中选取一个与我们开发板最接近的系列到Linux内核根目录下(选择一个最接近的参考答案)
4).config
假设教务处留了一个心眼,他提供的参考答案并不完全正确(.config文件与我们的板子并不是完全匹配),这时我们可以选择直接修改.config文件然后执行make menuconfig命令读取新的选项。但是一般我们不采取这个方案,我们选择在配置界面中通过空格、esc、回车选择某些选项选中或者不选中,最后保存退出的时候,Linux内核会把新的选项(正确的参考答案)更新到.config中,此时我们可以把.config重命名为其它文件保存起来(当你执行make distclean时系统会把.config文件删除),以后我们再配置内核时就不需要再去arch/arm/configs下考取相应的文件了,省去了重新配置的麻烦,直接将保存的.config文件复制为.config即可.
5)经过以上两步,我们可以正确的读取、配置我们需要的界面了,那么他们如何跟makefile文件建立编译关系呢?当你保存make menuconfig选项时,系统会除了会自动更新.config外,还会将所有的选项以宏的形式保存在Linux内核根目录下的 include/generated/autoconf.h文件下

内核中的源代码就都会包含以上.h文件,跟宏的定义情况进行条件编译。
当我们需要对一个文件整体选择如是否编译时,还需要修改对应的makefile文件,例如:

我们选择是否要编译s3c2410_ts.c这个文件时,makefile会根据CONFIG_TOUCHSCREEN_S3C2410来决定是编译此文件,此宏是在Kconfig文件中定义,当我们配置完成后,会出现在.config及autconf中,至此,我们就完成了整个linux内核的编译过程。
最后我们会发现,整个linux内核配置过程中,留给用户的接口其实只有各层Kconfig、makefile文件以及对应的源文件。
比如我们如果想要给内核增加一个功能,并且通过make menuconfig控制其声称过程
首先需要做的工作是:修改对应目录下的Kconfig文件,按照Kconfig语法增加对应的选项;
其次执行make menuconfig选择编译进内核或者不编译进内核,或者编译为模块,.config文件和autoconf.h文件会自动生成;
最后修改对应目录下的makefile文件完成编译选项的添加;
最后的最后执行make命令进行编译。
Kconfig和Makefile
Linux内核源码树的每个目录下都有两个文档Kconfig和Makefile。分布到各目录的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文档相关的内核配置菜单。在执行内核配置make menuconfig时,从Kconfig中读出菜单,用户选择后保存到.config的内核配置文档中。在内核编译时,主Makefile调用这 个.config,就知道了用户的选择。这个内容说明了,Kconfig就是对应着内核的每级配置菜单。
假如要想添加新的驱动到内核的源码中,要修改Kconfig,这样就能够选择这个驱动,假如想使这个驱动被编译,则要修改Makefile。添加新 的驱动时需要修改的文档有两种(如果添加的只是文件,则只需修改当前层Kconfig和Makefile文件;如果添加的是目录,则需修改当前层和目录下 的共一对Kconfig和Makefile)Kconfig和Makefile。要想知道怎么修改这两种文档,就要知道两种文档的语法结构,Kconfig的语法参见参考文献《【linux-2.6.31】kbuild》。
Makefile 文件包含 5 部分:
Makefile 顶层的 Makefile
.config 内核配置文件
arch/$(ARCH)/Makefile 体系结构 Makefile
scripts/Makefile.* 适用于所有 kbuild Makefile 的通用规则等
kbuild Makefiles 大约有 500 个这样的文件
顶层 Makefile 读取内核配置操作产生的.config 文件,顶层 Makefile 构建两个主要的目标:vmlinux(内核映像)和 moles(所有模块文件)。它通过递归访问内核源码树下的子目录来构建这些目标。访问哪些子目录取决于内核配置。顶层 Makefile 包含一个体系结构 Makefile,由 arch/$(ARCH)/Makefile 指定。体系结构 Makefile 文件为顶层 Makefile 提供了特定体系结构的信息。每个子目录各有一个 kbuild文件和Makefile 文件来执行从上层传递下来的命令。kbuild和Makefile文件利用.config 文件中的信息来构造由 kbuild 构建内建或者模块对象使用的各种文件列表。scripts/Makefile.*包含所有的定义/规则,等等。这些信息用于使用 kbuild和 Makefile 文件来构建内核。Makefile的语法参见参考文献《【linux-2.6.31】kbuild》。

参考文献
【linux-2.6.31】内核编译指南.pdf
【linux-2.6.31】kbuild.pdf
Linker script in Linux.pdf
linux内核的配置机制及其编译过程
Linux内核编译过程详解
Linux Kconfig及Makefile学习

⑦ 嵌入式Linux上的C语言编程实践的目录

第一部分 基础知识
第1章 Linux环境下C语言的开发 2
1.1 Linux下的C语言开发环境 2
1.2 在Linux中使用C语言开发 3
1.2.1 开发流程和开发工具 3
1.2.2 Linux中程序的运行原理 4
第2章 嵌入式环境中的C语言开发 7
2.1 嵌入式C语言的开发环境 7
2.2 嵌入式开发中C语言编程要点 9
第二部分 Linux环境中
C语言的开发环境和工具
第3章 Linux的文本编辑工具VI 12
3.1 VI编辑器概述 12
3.1.1 VI简介 12
3.1.2 VI的工作模式和使用
3.1.2 之前的准备 12
3.1.3 进入和退出VI 13
3.2 VI的增强版VIM 16
3.3 VI编辑器的基本使用方法 17
3.3.1 在屏幕上移动光标 17
3.3.2 插入文本 20
3.3.3 删除文本 22
3.3.4 修改文本内容 25
3.3.5 替换文本内容 27
3.3.6 合并文本内容 30
3.3.7 移动文本内容 30
3.4 VI编辑器的命令和高级操作 32
3.4.1 VI常用命令的列表 32
3.4.2 VI的一些高级的操作和
3.1.2 使用技巧 35
第4章 GCC程序开发工具 39
4.1 GNU工具综述 39
4.2 GCC的编译和连接 43
4.2.1 工程示例 43
4.2.2 编译、汇编和连接 46
4.2.3 动态库 48
4.3 GCC的二进制工具 49
4.3.1 ar(归档工具) 49
4.3.2 readelf(读取ELF格式
3.1.2 文件信息) 51
4.3.3 strings(查看字符串) 54
4.3.4 nm(显示符号信息) 55
4.3.5 strip(删除符号) 57
4.3.6 objmp(显示目标
3.1.2 文件信息) 58
4.3.7 obj(复制目标文件) 63
第5章 make工程管理工具 67
5.1 make和Makefile 67
5.1.1 make机制概述 67
5.1.2 make和Makefile的使用 68
5.2 Makefile使用示例 69
5.2.1 简单的Makefile 69
5.2.2 Makefile中的依赖关系 71
5.2.3 Makefile中使用隐含规则
3.1.2 来编译程序 73
5.2.4 Makefile中指定依赖关系的
3.1.2 编译 76
5.3 自动生成Makefile 78
5.3.1 自动生成Makefile的意义和
3.1.2 相关工具 78
5.3.2 自动生成Makefile的流程 79
第6章 GDB调试工具 85
6.1 GDB简介 85
6.2 使用GDB调试程序 86
6.2.1 基本操作 88
6.2.2 查看命令 90
6.2.3 高级命令 92
6.2.4 attach命令的使用 94
6.3 远程GDB调试 95
6.3.1 本地GDB调试和远程GDB
3.1.2 调试的比较 95
6.3.2 远程GDB调试流程 97
6.3.3 远程GDB调试示例 98
第三部分 库函数
第7章 C语言标准库函数 106
7.1 ISO的C语言标准库函数
7.1 分类 106
7.2 标准格式化输入/输出类函数 107
7.2.1 scanf函数:格式化输入
3.1.2 字符串 107
7.2.2 printf函数:格式化输出
3.1.2 字符串 109
7.2.3 putchar函数:输出字符到
3.1.2 标准输出 111
7.2.4 getchar函数:从标准输入
3.1.2 获取字符 111
7.2.5 putc函数:向文件输出字符 112
7.2.6 getc函数:从文件输入字符 112
7.2.7 gets函数:获得字符串 112
7.2.8 puts函数:输出指定字符串 113
7.2.9 ungetc函数:把字符
3.1.2 写回流中 113
7.3 字符处理类函数 114
7.4 字符串处理及转换函数 116
7.4.1 sprintf函数:格式化输出
3.1.2 字符串到一个缓冲区 116
7.4.2 strcat和strncat函数:
3.1.2 字符串连接 119
7.4.3 strcpy和strncpy函数:
3.1.2 字符串复制 120
7.4.4 strcmp和strncmp函数:
3.1.2 字符串比较 121
7.4.5 strlen函数:获取字符串
3.1.2 长度 122
7.4.6 strchr和strrchr函数:字符/
3.1.2 字符串定位 122
7.4.7 strstr函数:字符串查找 123
7.4.8 strrev函数:字符串逆序 124
7.4.9 strupr和strlwr函数:字母
3.1.2 形式转换 125
7.4.10 strp和strnp函数:
3.1.2 字符串复制 125
7.4.11 memset函数:内存设置 126
7.4.12 memmove函数:内存移动 126
7.4.13 memcmp函数:内存比较 127
7.4.14 memcpy函数:内存复制 128
7.5 数学计算类函数 128
7.6 数据结构和算法类函数 133
7.6.1 bsearch函数:二元搜索 133
7.6.2 lfind函数:线性搜索 134
7.6.3 lsearch函数:线性搜索 135
7.6.4 qsort函数:利用快速排序法
3.1.2 排列数组 136
7.6.5 rand函数:产生随机数 136
7.6.6 srand函数:设置随机
3.1.2 数种子 137
7.7 文件I/O操作类相关函数 137
7.7.1 fopen函数:打开文件 138
7.7.2 fclose函数:关闭文件 139
7.7.3 fgetc函数:从文件中读取
3.1.2 一个字符 139
7.7.4 fputc函数:将一指定字符
3.1.2 写入文件流中 139
7.7.5 fgets函数:从文件中读取
3.1.2 一字符串 140
7.7.6 fputs函数:将一指定的
3.1.2 字符串写入文件内 140
7.7.7 rewind函数:重设文件流的
3.1.2 读写位置为文件开头 141
7.7.8 ftell函数:取得文件流的
3.1.2 读取位置 141
7.7.9 fseek函数:移动文件流的
3.1.2 读写位置 141
7.7.10 fwrite函数:将数据写至
7.7.10 文件流 142
7.7.11 fread函数:从文件流读取
7.7.10 数据 142
7.7.12 remove函数:删除文件 143
7.7.13 rename函数:更改文件
7.7.10 名称或位置 143
7.7.14 freopen函数:重新打开
7.7.10 文件 144
7.7.15 fflush函数:同步缓冲区 144
7.7.16 fgetpos函数:获得文件
7.7.10 位置 145
7.7.17 fsetpos函数:设置文件
7.7.10 位置 145
7.7.18 mktemp函数:建立临时
7.7.10 文件 146
7.7.19 tmpfile函数:临时文件 146
7.7.20 tmpnam:得到临时文件名 147
7.8 日期时间类函数 147
7.8.1 clock函数:获得CPU时间 148
7.8.2 time函数:获得当前日历
7.8.2 时间 148
7.8.3 difftime函数:获得时间
7.8.2 差值 148
7.8.4 gmtime函数:将日历时间
7.8.2 转换成UTC时间 149
7.8.5 mktime函数:将UTC时间
7.8.2 转换成日历时间 149
7.8.6 asctime函数:将UTC时间
7.8.2 转换成字符串 149
7.8.7 ctime函数:将日历时间转换
7.8.2 成当地时间的字符串 150
7.8.8 localtime函数:将日历时间
7.8.2 转换成本地时间 150
7.8.9 strftime函数:转换日期和
7.8.2 时间格式 151
7.9 国际化和本地化函数 152
7.9.1 setlocale函数:本地化控制
7.8.2 函数 153
7.9.2 localeconv函数:本地化
7.8.2 转换 154
7.10 错误处理类函数 155
7.10.1 clearerr函数:清除流中的
7.10.1 结束指示符和错误指示符 155
7.10.2 feof函数:指示文件结束 155
7.10.3 ferror函数:指示文件出错 156
7.10.4 perror函数:输出出错信息 156
7.10.5 errno函数:错误编号记录 156
7.11 其他一些工具函数 157
7.11.1 assert函数:程序诊断 157
7.11.2 长跳转函数 157
7.11.3 可变长的参数控制函数 160
7.11.4 获取结构体成员函数
7.10.1 (宏) 161
7.12 一些标准库中有用的宏 161
第8章 Linux中C语言的扩展库
函数 163
8.1 文件I/O操作函数 163
8.1.1 open函数:打开文件 163
8.1.2 close函数:关闭文件 164
8.1.3 read函数:读文件 165
8.1.4 write函数:写文件 165
8.1.5 lseek函数:文件定位 167
8.1.6 ioctl函数:文件控制 167
8.1.7 flock函数:锁定文件 167
8.1.8 mmap函数和munmap函数:
8.1.8 内存映射 168
8.1.9 create函数:创建新文件 170
8.1.10 p函数和p2函数:
8.1.10 复制文件描述符 171
8.1.11 fcntl函数:改变已打开的
8.1.10 文件的属性 171
8.2 文件权限相关的操作函数 172
8.2.1 access函数:判断是否
8.2.1 具有存取文件的权限 172
8.2.2 chown函数和fchown函数:
8.2.1 改变文件的所有者 173
8.2.3 chmod函数和fchmod函数:
8.2.1 改变权限 173
8.2.4 unlink函数:删除文件 173
8.2.5 utime函数和utimes函数:
8.2.1 改变文件时间 174
8.2.6 umask函数:设置建立
8.2.1 新文件时的权限掩码 175
8.2.7 link函数:建立文件连接 175
8.2.8 stat函数、fstat函数和lstat
8.2.1 函数:获取文件信息 175
8.3 用户组操作函数 176
8.3.1 getgid函数和setgid函数:
8.2.1 获得/设置组识别码 176
8.3.2 getegid函数和setegid函数:
8.2.1 获得/设置有效的组识别码 177
8.3.3 getuid函数和setuid函数:
8.2.1 获得/设置真实的用户识别码 177
8.3.4 geteuid函数和seteuid函数:
8.2.1 获得/设置有效的用户识别码 178
8.3.5 getgroups函数和setgroups
8.2.1 函数:获得/设置组代码 178
8.4 信号类函数 179
8.4.1 kill函数:传送信号给指定的
8.2.1 进程 181
8.4.2 raise函数:信号发送函数 181
8.4.3 alarm函数:设置超时函数 182
8.4.4 signal函数:信号安装函数 182
8.5 进程处理函数 183
8.5.1 getpid函数和getppid函数:
8.2.1 获得进程ID和父进程ID 183
8.5.2 fork函数:建立子进程 183
8.5.3 sleep函数和usleep函数:
8.2.1 让进程暂停执行一段时间 185
8.5.4 exec函数族:找到可执行
8.2.1 文件 185
8.5.5 _ exit函数和_Exit函数:
8.2.1 结束进程执行 188
第四部分 C语言高级编程
第9章 动态内存的堆与栈 190
9.1 程序内存区域的使用 190
9.1.1 静态内存与动态内存 190
9.1.2 C语言中的动态内存 191
9.2 C程序中栈空间的使用 196
9.2.1 参数使用栈空间 196
9.2.2 自动变量使用栈空间 199
9.2.3 程序中较大的栈 201
9.2.4 栈空间的特性 202
9.3 C程序中的堆空间使用 203
9.3.1 分配和释放堆内存的库函数 203
9.3.2 库函数使用 204
9.3.3 堆内存的特性 218
9.4 堆内存和栈内存使用的比较 222
9.4.1 利用返回值传递信息 222
9.4.2 利用参数传递信息 226
9.4.3 堆与栈内存管理的区别 231
第10章 函数指针的使用 232
10.1 函数指针的概念 232
10.1.1 C语言函数的本质 232
10.1.2 函数指针在C语言中的
10.1.2 意义 234
10.2 函数指针的使用 237
10.2.1 函数指针使用初步 237
10.2.2 函数指针的类型定义 240
10.2.3 函数指针作为结构体成员 242
10.2.4 函数指针作为函数的参数 243
10.2.5 函数指针作为函数的
10.2.5 返回值 244
10.2.6 函数指针数组 246
10.3 函数指针使用示例 248
第11章 回调函数的使用 252
11.1 回调函数的概念与作用 252
11.1.1 程序调用的方式 252
11.1.2 回调函数的作用 254
11.2 回调函数的语法 254
11.2.1 简单的回调函数 254
11.2.2 完全角式的回调函数 256
11.3 回调函数的使用 259
11.3.1 qsort中的回调函数 259
11.3.2 atexit和on_exit函数的
10.2.5 注册退出函数 263
第12章 C语言实现对象编程 268
12.1 C语言实现基于对象编程的
12.1 概念与作用 268
12.2 C语言基于对象编程实现
12.1 封装 269
12.2.1 简单的程序示例 269
12.2.2 C语言基于对象编程的
10.2.5 详解 272
12.2.3 C语言基于对象编程与
10.2.5 C++面向对象编程的对比 275
12.3 C语言基于对象编程实现
12.3 部分继承功能 278
12.3.1 利用数据结构的包含实现
10.2.5 继承功能 279
12.3.2 利用私有指针实现继承
10.2.5 功能 282
12.3.3 C语言实现继承的总结 287
12.4 C语言基于对象编程实现
12.4 部分多态功能 288
12.4.1 利用操作指针组的包含
10.2.5 实现多态功能 288
12.4.2 C语言实现多态功能的总结 292
12.5 对C语言实现基于对象
12.5 编程的思考 292
12.5.1 C语言基于对象编程的
10.2.5 特性 292
12.5.2 C语言基于对象编程中接口、
10.2.5 实现和调用者的关系 293
第五部分 在嵌入式
环境下的C语言编程
第13章 C语言程序的内存布局 295
13.1 C语言程序的存储区域 295
13.2 C语言程序的段 297
13.2.1 段的分类 297
13.2.2 程序中段的使用 298
13.3 可执行程序的连接 301
13.3.1 可执行程序的组成 301
13.3.2 各个目标文件的关系 303
13.3.3 连接错误示例 304
13.4 C语言程序的运行 309
13.4.1 RAM调试运行 311
13.4.2 固化程序的XIP运行 312
13.4.3 固化程序的加载运行 313
13.4.4 C语言程序的运行总结 315
第14章 嵌入式C语言常用语法 317
14.1 内存指针操作 317
14.1.1 内存操作的意义 317
14.1.2 使用指针操作内存 319
14.1.3 volatile的使用 324
14.1.4 嵌入式系统指针的实际
10.2.5 应用 325
14.2 位操作 327
14.2.1 位操作的意义 327
14.2.2 位操作的语法 328
14.3 大小端与对齐问题 330
14.3.1 大小端问题 331
14.3.2 内存对齐问题 335
14.3.3 结构体成员的对齐问题 338
14.4 程序的跳转 344
14.4.1 嵌入式系统程序跳转的
10.2.5 类型 344
14.4.2 C语言中实现程序的跳转 345
第15章 嵌入式C语言编程的技巧 348
15.1 程序的优化技巧 348
15.1.1 循环缓冲区 348
15.1.2 查表法 350
15.1.3 针对循环执行效率的
10.2.5 优化 353
15.2 关于小数运算 355
15.3 函数参数和返回值的传递 357
15.4 变量的初始化技巧 360
15.4.1 数组的初始化 360
15.4.2 结构体的初始化 362
15.4.3 变量的初始化总结 362
15.5 程序的调试和宏使用的技巧 363
15.5.1 打印文件、函数和程序行 363
15.5.2 #:字符串化操作符 364
15.5.3 ##:连接操作符 366
15.5.4 调试宏的第一种定义方式 367
15.5.5 调试宏的第二种定义方式 368
15.5.6 对调试语句进行分级审查 369
15.5.7 条件编译调试语句 370
15.5.8 使用do…while的宏定义 372
15.6 代码剖析 373
参考文献 378

⑧ linux下一个版本,有Makefile,请问,如果分别编译成debug和release版本,是输入make -release么

一般,在开发测试阶段用debug版本,而上线发布用release版本。
使用Makefile定制编译不同版本,避免修改程序和Makefile文件,将会十分方便。
读了一些资料,找到一个解决方法,Makefile预定义宏与条件判断,结合make预定义变量,进行条件编译。

比如,有一个test.cpp,包含这段代码
#ifdef debug
//your code#endif
你希望在debug版本要执行它,在release版本不执行。
我们可以写这样的一个Makefile:
1 ver = debug
2
3 ifeq ($(ver), debug)
4 ALL: test_d
5 CXXFLAGS = -c -g -Ddebug
6 else 7 ALL: test_r
8 CXXFLAGS = -c -O3
9 endif
10
11 test_d: test.do12 g++ -o $@ $^
13
14 test_r: test.ro
15 g++ -o $@ $^
16
17 %.do: %.cpp
18 g++ $(CXXFLAGS) $< -o $@
19
20 %.ro: %.cpp
21 g++ $(CXXFLAGS) $< -o $@
简单说一下,Makefile根据ver的不同定义了不同的编译选项CXXFLAGS与输出程序ALL,
debug版本输出程序是test_d,release版本输出程序是test_r
debug版本编译选项是"-c -g -Ddebug",release版本编译选项是"-c -O3"
debug版本object文件后缀是".do",release版本object文件后缀是".ro"
debug版本编译选项使用"-D"定义宏debug,使得your code能够执行。
不同版本的编译选项、object文件、输出程序均不同,所以可以同时编译两个版本的程序,互不影响。

Makefile执行时,首先判断ver变量,如果ver的值是debug,编译debug版,否则编译release版。当然,默认情况下是编译debug版的。
如果想编译release版,要怎么做?
只要在执行make时,对ver变量赋值,使得ver的值不为debug,比如# make ver=release

⑨ 如何在makefile中定义宏进行条件编译

你可以借助BASHSHELL强大的字符串处理能力来实现啊!
比如你可以将你想定义的“宏”放在makefile.include中,然后将其赋值,而在makefile中加入include makefile.include一行,在其后需要进行条件预编译时进行字符串比较来实现啊!

热点内容
scratch少儿编程课程 发布:2025-04-16 17:11:44 浏览:624
荣耀x10从哪里设置密码 发布:2025-04-16 17:11:43 浏览:353
java从入门到精通视频 发布:2025-04-16 17:11:43 浏览:68
php微信接口教程 发布:2025-04-16 17:07:30 浏览:293
android实现阴影 发布:2025-04-16 16:50:08 浏览:786
粉笔直播课缓存 发布:2025-04-16 16:31:21 浏览:336
机顶盒都有什么配置 发布:2025-04-16 16:24:37 浏览:201
编写手游反编译都需要学习什么 发布:2025-04-16 16:19:36 浏览:795
proteus编译文件位置 发布:2025-04-16 16:18:44 浏览:353
土压缩的本质 发布:2025-04-16 16:13:21 浏览:581