荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: zzt (我命由我不由天), 信区: Linux
标  题: GNU make指南[转](二)
发信站: BBS 荔园晨风站 (Wed Jun  7 08:23:22 2000), 转信

【 以下文字转载自 zzt 的信箱 】
【 原文由 zzt.bbs@flanker.uestc.edu.cn 所发表 】
发信人: bclz (依然是不见不散), 信区: Linux
标  题: GNU make指南[转](二)
发信站: 一网深情 (Wed May 26 10:20:57 1999), 转信

       1.3 怎样分解项目
       先说明,这完全是我个人的意见,你可以(也许你真的会?)用别的
       方式来做。这会触动到有关编码风格的问题,而大家从来就没有停止
       过在这个问题上的争论。在这里我只是给出我自己喜欢的做法(同时
       也给出这么做的砸颍?

   i) 不要用一个 header 文件指向多个源码文件(例外:程序包 的 header
       文件)。用一个 header定义一个源码文件的方式
       会更有效,也更容易查寻。否则改变一个源文件的结构(并且 它的 header
       文件)就必须重新编译好几个文件。
       ii) 如果可以的话,完全可以用超过一个的 header 文件来指向同
       一个源码文件。有时将不可公开调用的函数孕停嘈投ㄒ?
       等等,从它们的C源码文件中分离出来是非常有用的。使用一 个 header
       文件装公开符号,用另一个装私人符号意味着如果
       你改变了这个源码文件的内部结构,你可以只是重新编译它而
       不需要重新编译那些使用它的公开 header 文件的其它的源文 件。
       iii) 不要在多个 header 文件中重复定义信息。 如果需要, 在其中一个
       header 文件里 #include 另一个,但 是不要重复输入相同的 header
       信息两次。砸蚴侨绻阋院蟾?
       变了这个信息,你只需要把它改变一次,不用搜索并改变另外一
       个重复的信息。
       iv) 在每一个源码文件里, #include 那些声明了源码文件中的符
       号的所有 header 文件。这样一来,你在源码文件和 header
       文件对某些函数做出的矛盾声明可以比较容易的被编译器发现。

   1.4 对于常见错误的注释
   a) 定义符 (Identifier) 在源码文件中的矛盾:在C里,变量和函数的缺
       省状态是公用的。因此,任何C源码档案都可以引用存在于其它源
       码档中的通用 (global) 函数和通用变量,既使这个档案没有那个变
       量或函数的声明或类型,因此你必须保证在不同的两个档案里不能
       用同一个符号名称,否则会有连接错误或者在编译时会有警告。
       一种避免这种错误的方法是在公用的符号前加上跟其所在源文件有
       关的前缀。比如:所有在 gfx.c 里的函数都加上前缀“gfx_”。如果
       你很小心的分解你的程序,使用有意义的函数名称,并且不是过分
       使用通用变量,当然这根本就不是问题。
       要防止一个符号在它被定义的源文件以外被看到,可在它的定义前
       加上关键字“static”。这对只在一个档案内部使用,其它档案都
       都不会用到的简单函数是很有用的。
       b) 多次定义的符号: header 档会被逐字的替换到你源文件里 #include
       的位置的。因此,如果 header 档被 #include 到一个以上的源文件
       里,这个 header 档中所有的定义就会出现在每一个有关的源码文件
       里。这会使它们里的符号被定义一次以上,从而出现连接错误(见 上)。
       解决方法: 不要在 header 档里定义变量。你只需要在 header
       档里声明它们然后在适当的C源码文件(应该 #include 那个 header
       档的那个)里定义它们(一次)。对于初学者来说,定义和声明是
       很容易混淆的。声明的作用是告诉编译器其所声明的符号应该存在,
       并且要有所指定的类型。但是,它并不会使编译器分配贮存空间。
       而定义的做用是要求编译器分配贮存空间。当做一个声明而不是做
       定义的时候,在声明前放一个关键字“extern”。
       例如,我们有一个叫“counter”的变量,如果想让它成为公用的,
       我们在一个源码程序(只在一个里面)的开始定义它:“int
       counter;”,再在相关的 header 档里声明它:“extern int
       counter;”。
       函数孕屠镆? extern 的意思,所以不需顾虑这个问题。
       c) 重复定义,重复声明,矛盾类型:
       请考虑如果在一个C源码文件中 #include 两个档 a.h 和 b.h, 而 a.h
       又 #include 了 b.h 档(砸蚴? b.h 档定义了一些 a.h
       需要的类型),会发生什么事呢?这时该C源码文件 #include 了 b.h
       两次。因此每一个在 b.h 中的 #define 都发生了两次,每一
       个声明发生了两次,等等。理论上,因为它们是完全一样的拷贝,
       所以应该不会有什么问题,但在实际应用上,这是不符合C的语法
       的,可能在编译时出现错误,或至少是警告。
       解决的方法是要确定每一个 header 档在任一个源码文件中只被包
       含了一次。我们一般是用预处理器来达到这个目的的。当我们进入 每一个
       header 档时,我们为这个 header 档 #define 一个巨集
       指令。只有在这个巨集指令没有被定义的前提下,我们才真正使用 该
       header 档的主体。在实际应用上,我们只要简单的把下面一段
       码放在每一个 header 档的开始部分:
       #ifndef FILENAME_H
       #define FILENAME_H
       然后把下面一行码放在最后:
       #endif
       用 header 档的档名(大写的)代替上面的 FILENAME_H,用底线
       代替档名中的点。有些人喜欢在 #endif 加上注释来提醒他们这个 #endif
       指的是什么。例如:
       #endif /* #ifndef FILENAME_H */
       我个人没有这个习惯,因为这其实是很明显的。当然这只是各人的
       风格不同,无伤大雅。
       你只需要在那些有编译错误的 header 档中加入这个技巧,但在所 有的
       header 档中都加入也没什么损失,到底这是个好习惯。

   1.5 重新编译一个多文件项目
   清楚的区别编译和连接是很重要的。编译器使用源码文件来产生某种
   形式的目标文件(object files)。在这个过程中,外部的符号参考并
   没有被解释或替换。然后我们使用连接器来连接这些目标文件和一些
   标准的程序包再加你指定的程序包,最后连接生成一个可执行程序。
   在这个阶段,一个目标文件中对别的文件中的符号的参考被解释,并
   报告不能被解释的参考,一般是以错误信息的形式报告出来。
   基本的步骤就应该是,把你的源码文件一个一个的编译成目标文件的格
   式,最后把所有的目标文件加上需要的程序包连接成一个可执行文件。
   具体怎么做是由你的编译器决定的。这里我只给出 gcc (GNU C 编译
   器)的有关命令,这些有可能对你的非 gcc 编译器也适用。
   gcc 是一个多目标的工具。它在需要的时候呼叫其它的元件(预处理
   程序,编译器,组合程序,连接器)。具体的哪些元件被呼叫取决于
   输入文件的类型和你传递给它的开关。
   一般来说,如果你只给它C源码文件,它将预处理,编译,组合所有
   的文件,然后把所得的目标文件连接成一个可执行文件(一般生成的
   文件被命名为 a.out )。你当然可以这么做,但这会破坏很多我们
   把一个项目分解成多个文件所得到的好处。
   如果你给它一个 -c 开关,gcc 只把给它的文件编译成目标文件,
   用源码文件的文件名命名但把其后缀由“.c”或“.cc”变成“.o”。
   如果你给它的是一列目标文件, gcc 会把它们连接成可执行文件,
   缺省文件名是 a.out 。你可以改变缺省名,用开关 -o 后跟你指定 的文件名。
   因此,当你改变了一个源码文件后,你需要重新编译它: 'gcc -c filename.c'
   然后重新连接你的项目: 'gcc -o exec_filename *.o'。 如果你改变了一个
   header 档,你需要重新编译所有 #include 过 这个档的源码文件,你可以用
   'gcc -c file1.c file2.c file3.c' 然后象上边一样连接。
   当然这么做是很繁琐的,幸亏我们有些工具使这个步骤变得简单。
   本文的第二部分就是介绍其中的一件工具:GNU Make 工具。
   (好家伙,现在才开始见真章。您学到点儿东西没?)

--

           执子之手,与子谐老。

※ 来源:.一网深情 bbs.uestc.edu.cn.[FROM: 202.115.16.2]
--
※ 转寄:.一网深情 bbs.uestc.edu.cn.[FROM: 210.39.3.50]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.1.11]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店