⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 移植(porting)与编译(compiling)程式.htm

📁 gcc的安装相关资料 详细介绍了gcc的安装步骤和方法
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0063)http://member.netease.com/~jnkey/linuxflr/howto/GCC-HOWTO4.html -->
<HTML><HEAD><TITLE>移植(Porting)与编译(Compiling)程式</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META content="MSHTML 6.00.2800.1106" name=GENERATOR></HEAD>
<BODY text=#000000 bgColor=#ffeedd><A 
href="http://member.netease.com/~jnkey/linuxflr/howto/GCC-HOWTO.html"><EM>The 
Linux GCC HOWTO中译版V0.1</EM></A> <B>:</B> 
<EM>移植(Porting)与编译(Compiling)程式</EM><BR><B>Previous:</B> <A 
href="http://member.netease.com/~jnkey/linuxflr/howto/GCC-HOWTO3.html"><EM>GCC的安装(installation)与启用(setup)</EM></A><BR><B>Next:</B> 
<A 
href="http://member.netease.com/~jnkey/linuxflr/howto/GCC-HOWTO5.html"><EM>Debugging 
and Profiling</EM></A> 
<HR noShade>

<H2><A name=18></A>4. 移植(Porting)与编译(Compiling)程式</H2>
<H3><A name=19></A>4.1. gcc自行定义的符号<A name=index.25></A> </H3>
<P>只要执行gcc时,附加<CODE> 
-v</CODE>这个参数(switch),就能找出你所用的这版gcc,自动帮你定义了什麽符号(symbols).例如,我的机器看起来会像这样:</P>
<P>
<BLOCKQUOTE><CODE><PRE>$ echo 'main(){printf("hello world\n");}' | gcc -E -v -
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
gcc version 2.7.2
 /usr/lib/gcc-lib/i486-box-linux/2.7.2/cpp -lang-c -v -undef
-D__GNUC__=2 -D__GNUC_MINOR__=7 -D__ELF__ -Dunix -Di386 -Dlinux
-D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386
-D__linux -Asystem(unix) -Asystem(posix) -Acpu(i386)
-Amachine(i386) -D__i486__ -
</PRE></CODE></BLOCKQUOTE>
<P></P>
<P>假若目前你正在写的程式码,会用到一些Linux独有的特性(Linux-specific 
features),那麽把那些无法移植的程式码(non-portable bits),以条件式编译(conditional 
compilation)的前置命令封括(enclose in)起来,可是个不错的主意呢!</P>
<P>
<BLOCKQUOTE><CODE><PRE>#ifdef __linux__
/* ... funky stuff ... */
#endif /* linux */
</PRE></CODE></BLOCKQUOTE>
<P></P>
<P>用<CODE>__linux__</CODE>即可达成目的;看仔细一点,<EM>不是</EM><CODE>linux</CODE>啊.仅管後者也有定义,毕竟,仍然不是POSIX的标准(not 
POSIX compliant).</P>
<H3><A name=20></A>4.2. 线上求助说明(invocation)</H3>
<P>gcc编译器参数(switches)的说明文件是gcc info page(在Emacs内,按下<CODE>C-h 
i</CODE>,然後选'gcc'的选项).要是弄不出来,不是卖你CD-ROM的人,没把这个东东压给你,不然就是你现在用的是旧版的.这种情况下,最好的方法是移动尊臀到archive<A 
href="ftp://prep.ai.mit.edu/pub/gnu">ftp://prep.ai.mit.edu/pub/gnu</A>或是它的mirrors站台上,把gcc的原始档案抓回家,重新烹饪一番.</P>
<P>gcc manual page (<CODE>gcc.1</CODE>) 
可以说是已经过时了.一旦你吃饱撑著没事干要去看看它的话,它就会告诉你这件事,叫你别无聊了.</P>
<H4><A name=21></A>4.2.1. 旗正飘飘~(flags)<A name=index.26></A> <A 
name=index.27></A></H4>
<P>在命令列(command 
line)上执行gcc时,只要在它的屁股後面加上<CODE>-O</CODE><EM>n</EM>的选项,就能让gcc乖乖的替你生出最佳化後的机器码(output 
code).这里的<EM>n</EM>是一个可有可无的小整数.不同的gcc版本,<EM>n</EM>的意义与其正确的(exact)功效都不一样;不过,典型的□围是从0(不要鸡婆,我不要最佳化)变化到2(最佳化要多一点),再到3(最佳化要再多一点,多一点).</P>
<P>gcc在其内部会将这些转译成一系列的<CODE>-f</CODE> 
与<CODE>-m</CODE>选项(options).执行gcc时带上旗号(flags)<CODE>-v</CODE>与<CODE>-Q</CODE>,你就能很清楚的看出每一种等级的<CODE>-O</CODE>是对应(maps)到那些选项(options).例如,就<CODE>-O2</CODE>来讲,我的gcc告诉我说:</P>
<P>
<BLOCKQUOTE><CODE><PRE>enabled: -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks
-fexpensive-optimizations
         -fthread-jumps -fpeephole -fforce-mem -ffunction-cse -finline
         -fcaller-saves -fpcc-struct-return -frerun-cse-after-loop
         -fcommon -fgnu-linker -m80387 -mhard-float -mno-soft-float
         -mno-386 -m486 -mieee-fp -mfp-ret-in-387
</PRE></CODE></BLOCKQUOTE>
<P></P>
<P>要是你用的最佳化等级(optimization level)高於你的编译器所能支援的(e.g. 
<CODE>-O6</CODE>),那麽它的效果,就跟你用你的编译器<EM>所能</EM>提供的最高等级的,是一样的结果.说实在的,发行出去的gcc程式码,用在编译时竟是如此处理这等问题,实非什麽好的构想.日後若是有更进步的最佳化方法具体整合到新的版本里,而你(或你的users)还是试著这样做的话,可能就会发现,gcc会中断你的程式(break 
your code)了.</P>
<P><A name=index.28></A>从gcc 
2.7.0到2.7.2的users应该注意到,使用时<CODE>-O2</CODE>会有一个bug存在.更糟糕的是,强度折减(strength 
reduction)居然没有用(doesn't 
work)!要是你喜欢重新编译gcc的话,是有那麽一个修正的版本(patch)可以更正这项错误;不然的话,一定要确定每次编译时都会加上<CODE>-fno-strength-reduce</CODE>喔!</P>
<P>11/12/97译</P>
<H5><A name=22></A>4.2.1.1. 有个性的微处理器(Processor-specific)</H5>
<P>有一些<CODE>-m</CODE>的旗号无法藉由各种等级的<CODE>-O</CODE>来打开,然而却是十分有用的.这之中最主要的是<CODE>-m386</CODE>与<CODE>-m486</CODE>两种,用来告诉gcc该把正在编译的程式码视作专为386或是486机器所写的.不论是用哪一种来编译程式码,都可以在彼此的机器上执行,-m486编译出来的码会比较大,可是拿来在386的机器上跑也不会比较慢就是了.</P>
<P>目前尚无<CODE>-mpentium</CODE>或是<CODE>-m586</CODE>的旗号.Linus建议我们,可以用<CODE>-m486 
-malign-loops=2 -malign-jumps=2 -malign-functions=2</CODE>,来得到最佳化的486程式码(486 
code optimizations),而这样做正好就可以避免alignment(Pentium并不需要)有过大的gaps发生. Michael 
Meissner说:</P>
<P>
<BLOCKQUOTE>我的第六感(hunch)告诉我, 
  <CODE>-mno-strength-reduce</CODE>(嘿!我可不是在谈强度折减的bug啊,那已经是另外一个争论的战场了.)一样也可以在x86的机器上,产生较快的程式码,这是因为x86的机器对暂存器(register)有著不可磨灭的□渴在(and 
  GCC's method of grouping registers into spill registers vs. other registers 
  doesn't help either).传统上,强度折减的结果会使得编译器利用加法暂存器(additional 
  registers)以加法运算(addition)来取代乘法运算(multiplication).而且,我也在怀疑(suspect)<CODE>-fcaller-saves</CODE>,可能也只是个漏洞(loss)也说不定. 
</BLOCKQUOTE>
<BLOCKQUOTE>而我的第七感则再度的告诉我, 
  <CODE>-fomit-frame-pointer</CODE>可能会,也可能不会有任何的赚头.从这点来看,即意谓著有另一个暂存器可用来处理记忆体分配(allocation)的问题.另方面,若纯粹从x86的机器在转换(encodes)它的指令集(instruction 
  set)成为机器码的方法上来看,便意谓著堆叠(stack)所用到的记忆体空间要比frame所用到的还要来的多;换句话说,Icache对程式码而言并没有实质上的益处.若是阁下用了<CODE>-fomit-frame-pointer</CODE>的话,同时,也就是告诉编译器在每次呼叫函数(calls)之後,就必须修正堆叠的指标(stack 
  pointer);然而,就frame来讲,若呼叫的次数不多的话,则允许堆叠暂时堆积(accumulate)起来. </BLOCKQUOTE>
<P></P>
<P>有关这方面主题的最後一段话仍是来自於Linus:</P>
<P>
<BLOCKQUOTE>要注意的是,如果你想要得到最佳状况的执行成果(optimal 
  performance),可千万别相信我的话.无论如何,一定要进行测试.gcc编译器还有许多的参数(switches)可用,其中可能就有一种最特别的组合(set),可以给你最佳化的结果喔. 
</BLOCKQUOTE>
<P></P>
<P>11/14/97译</P>
<H4><A name=23></A>4.2.2. <CODE>Internal compiler error: cc1 got fatal signal 
11</CODE><A name=index.29></A> <A name=index.30></A><A name=index.31></A><A 
name=index.32></A><A name=index.33></A></H4>
<P>Signal 11是指 SIGSEGV, 或者 `segmentation 
violation'.通常这是指说gcc对自己所用的指标感到困惑起来,而且还尝试著写入不属於它的记忆体.所以,这可能是一个gcc的bug.</P>
<P>然而,大部份而言,gcc是一件经过严密测试且可靠度佳的软体佳作.它也用了大量复杂的资料结构与惊人的指标数量.简言之,若是要评选本世纪最挑惕与最一丝不□的RAM测试程式(RAM 
tester)的话,gcc绝对可以一摘后冠的.假如你<EM>无法重新复制这只bug</EM>---当你重新开始编译时,错误的讯息并没有一直出现在同一个地方---那几乎可以确定,是你的硬体本身有问题(CPU,记忆体,主机板或是快取记忆体).<B>千万不要</B>因为你的电脑可以通过开机程序的测试(power-on 
checks),或者Windows可以跑得很顺,或者其它什麽的,就回过头来大肆宣传说这是gcc的一个bug;你所做的这些测试动作,通常没有什麽实际上的价值,而且没有价值也是很合理的结论.另外,也不要因为编译核心时,总是停留在`<CODE>make 
zImage</CODE>'的阶段,就要大骂这是gcc的bug---当然它会停在那儿啊!做`<CODE>make 
zImage</CODE>'时,需要编译的档案可能超过200档案;我们正在研拟一个<EM>比较小的</EM>地方来取代.</P>
<P>如果你可以重覆产生这个bug,而且(最好是这样啦)可以写一个短小的程式来展示这只bug的话,你就可以把它做成bug报表(bug 
report),然後email给FSF,或者是linux-gcc邮件表列(linux-gcc mailing 
list).你可以去参考gcc的说明文件,看看有什麽详细的资讯,是他们所需要的.</P>
<H3><A name=24></A>4.3. 移植能力(Portability)</H3>
<P>据报,近日来许多正面消息指出,若有某件东东到现在都还没移植到Linux上去,那麽可以肯定的是,它一定一点价值也没有.:-)</P>
<P>嗯!正经一点.一般而言,原始码只需要做一些局部的修改(minor changes),就可以克服(get over)Linux 
100%与POSIX相容的特质(compliance).如果你做了任何的修改,而将此部份传回(passing 
back)给原作者,会是很有建设性的举动(worthwhile).这样日後就只需要用到'make',就能得到一个可执行的档案了.</P>
<H4><A name=25></A>4.3.1. BSD教派(BSDisms) (有 <CODE>bsd_ioctl</CODE>, 
<CODE>daemon</CODE> 与 <CODE>&lt;sgtty.h&gt;</CODE>)</H4>
<P>编译程式时,可以配合<CODE>-I/usr/include/bsd</CODE>与连结<CODE>-lbsd</CODE>的程式库.(例如:在你的Makefile档内,把<CODE>-I/usr/include/bsd</CODE>加到<CODE>CFLAGS</CODE>那一行;把<CODE>-lbsd</CODE>加到<CODE>LDFLAGS</CODE>那一行).如果你真的那麽想要BSD型态的信号行为(BSD 
type signal 
behavior),也<EM>不</EM>再需要加上<CODE>-D__USE_BSD_SIGNAL</CODE>了.那是因为当你用了<CODE>-I/usr/include/bsd</CODE>与含括了标头档<CODE>&lt;signal.h&gt;</CODE>之後,make就自动会把它加入了.</P>
<H4><A name=26></A>4.3.2. 失落的封印(`Missing' signals)(<CODE>SIGBUS</CODE>, 
<CODE>SIGEMT</CODE>, <CODE>SIGIOT</CODE>, <CODE>SIGTRAP</CODE>, 
<CODE>SIGSYS</CODE> etc) <A name=index.34></A><A name=index.35></A><A 
name=index.36></A><A name=index.37></A><A name=index.38></A></H4>
<P>Linux与POSIX是完全相容的.不过,有些信号并不是POSIX定义的---ISO/IEC 9945-1:1990 (IEEE Std 
1003.1-1990), paragraph B.3.3.1.1 sez:</P>
<P>
<BLOCKQUOTE>"在POSIX.1中省略了SIGBUS, SIGEMT, SIGIOT, SIGTRAP, 
  与SIGSYS信号,那是因为它们的行为(behavior)与实作方式是息息相关的(implementations 
  dependent),而且也无法进行适当的分门别类(adequately categorized).确认实作方式後(conforming 
  implementations),便可以生产出(deliver)这些信号,可以必须以文件说明(document)它们是在什麽样的环境(circumstances)下生产出来的,以及指出与它们的发展相关的任何限制(any 
  restrictions concerning their delivery)". </BLOCKQUOTE>
<P></P>
<P>如欲修正此点,最简单,也是最笨的(cheesy)方法就是以<CODE>SIGUNUSED</CODE>重新定义这些信号.而<EM>正确的</EM>方法应是以条件式的编译<CODE>#ifdef</CODE>来处理这些问题才对:</P>
<P>
<BLOCKQUOTE><CODE><PRE>#ifdef SIGSYS
/* ... non-posix SIGSYS code here .... */
#endif
</PRE></CODE></BLOCKQUOTE>
<P></P>
<P>11/15/97译</P>
<H4><A name=27></A>4.3.3. K &amp; R <A name=index.39></A></H4>
<P>gcc是个与ANSI相容的编译器;奇怪的是,目前大多数的程式码都不符合ANSI所定的标准.如果你热爱ANSI,喜欢用ANSI提供的标准来撰写C程式,似乎除了在编译器的旗号上加上<CODE>-traditional</CODE>之外,就没有什麽其它的可以多谈的了.There 
is a certain amount of finer-grained control over which varieties of brain 
damage to emulate;请自行查阅gcc info page.</P>
<P>要注意的是,尽管你用了<CODE>-traditional</CODE>来改变语言,它的效果也仅局限在gcc所能够接受的□围.例如, 
<CODE>-traditional</CODE>会打开(turn 
on)<CODE>-fwritable-strings</CODE>,使得字串常数(string constants)移至资料记忆体空间(data 
space)内(从程式码记忆体空间(text space),这地方是不能任意写入的).这样做会让程式码的记忆体空间无形中增加的.</P>
<H4><A name=28></A>4.3.4. 前置处理器(Preprocessor)的符号卯上函数原型宣告(prototypes)<A 
name=index.40></A> <A name=index.41></A></H4>
<P>最常见的问题是,如众所皆知,Linux中有许多常用的函数都定义成巨集(macros)存放在标头档(header 
files)内,此时若有相似的函数原型宣告出现在程式码内,前置处理器会拒绝进行语法分析(parse)的前置作业.常见的有<CODE>atoi()</CODE>与<CODE>atol()</CODE>.</P>
<H4><A name=29></A>4.3.5. <CODE>sprintf()</CODE><A name=index.42></A> </H4>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -