# -*- org -*- #+TITLE: gcc fixincludes简介 #+SETUPFILE: ../templates/level-1.org * 为什么要修改头文件 引自 =fixincludes/README-fixinc= #+BEGIN_quote Many of the files in this directory were automatically edited from the standard system header files by the fixincludes process. They are system-specific, and will not work on any other kind of system. They are also not part of GCC. The reason we have to do this is because GCC requires ANSI C headers and many vendors supply ANSI-incompatible headers. #+END_quote 但是,有时候它也会犯错误, #+BEGIN_quote Because this is an automated process, sometimes headers get "fixed" that do not, strictly speaking, need a fix. As long as nothing is broken by the process, it is just an unfortunate collateral inconvenience. We would like to rectify it, if it is not "too inconvenient". #+END_quote 这时候,就需要理解fixincludes是如何工作的。 * 如何修改头文件 修改头文件是在编译gcc的过程中发生的。 修改头文件的工作由 =fixincludes/fixinc.sh= 这个脚本发起的,它把相关的环 境变量和头文件传给 =fixincl= 这个程序,由后者完成具体修改的任务。 #+BEGIN_src ditaa :file online.png :cmdline -S -E +-----------+ +---------------+ +-----------+ +---------------+ | cBLU | | c897 | | cBLU | | c897 | | fixinc.sh +-->+ env vars +--->+ fixincl +--->+ fixed headers | | | +---------------+ | | | {d} | +-----------+ | header files | +-----------+ +---------------+ | c897 {d} | +---------------+ #+END_src =fixincl= 是在编译gcc的过程中编译出来的。根据host平台的不同,它会选择 不同的工作方式,理想的情况下使用pipe,否则使用临时文件。所以通常情况下, 我们只需要关心宏 =SEPARATE_FIX_PROC= 没有定义情况下的源代码。 =fixincl= 的工作分两步:确定一个头文件是否需要修改,如果需要,则读入文 件、创建pipe,然后调用外部命令完成修改。修改头文件的方式有四种: 1. 使用 =sed= 命令; 2. 使用 =shell= 脚本; 3. 完全替换; 4. 调用C函数; 为了简化操作, =fixincl= 并不会直接调用内部的C函数完成修改动作,而是 =fork= 出一个子进程进行修改。父进程在对一个头文件的所有修改完成后,通 过pipe读回修改后的内容,并与初始内容做比较,如果有不同,则将其保存在 =include-fixed= 目录。 #+BEGIN_src ditaa :file child_process.png :cmdline -S -E +--------------------------+ +--------------------------+ | | | | | Parent fixincl process | | Parent fixincl process | | | | | +-----------+--------------+ +-----------+--------------+ ^ ^ | | +---+----+ +---+----+ | {s} | or | {s} | | pipe | | pipe | +---+----+ +---+----+ ^ ^ | | +-----------+--------------+ +-----------+--------------+ | | | | | Child fixincl process | | Child sed process | | | | | +--------------------------+ +--------------------------+ #+END_src 如果对一个头文件需要多次修改,则会有多个子进程被创建出来。 #+BEGIN_src ditaa :file multi_child_processes.png :cmdline -S -E +--------------------------+ | | | Parent fixincl process | | | +-----------+--------------+ ^ | +---+----+ | {s} | | pipe | +---+----+ ^ | +-----------+--------------+ | | | Child fixincl process 2 | | | +-----------+--------------+ ^ | +---+----+ | {s} | | pipe | +---+----+ ^ | +-----------+--------------+ | | | Child sed process 1 | | | +--------------------------+ #+END_src 其中进程1先于进程2被创建出来。 * 如何描述修改 哪些平台上的哪些头文件需要怎样修改,这些信息如何描述呢? 答案:参见 =fixincludes/inclhack.def= 和 =fixincludes/README= 。 说到这里,不得不提 [[http://www.gnu.org/s/autogen/][autogen]] 。它是个模板系统,类似Perl的 Template-Toolkit。autogen有两个输入文件——模板文件( =fixincl.tpl= )和 数据文件( =inclhack.def= ),它的核心任务就是把数据填到模板内的相应位 置。 =fixincludes/fixincl.x= 就是一个典型的autogen生成的文件,它是一段 C代码,include在 =fixincludes/fixincl.c= 文件里,一同编译生成 =fixincl= 程序。 #+BEGIN_src ditaa :file autogen.png :cmdline -S -E +-------------+ | c897 | | fixincl.tpl +------+ +-----------+ +------------+ | {d} | | | cBLU | | c897 | +-------------+ | | autogen | | fixincl.x | +--->| +--->| | +-------------+ | | | | {d} | | c897 | | +-----------+ +------------+ | inclhack.def+------+ | {d} | +-------------+ #+END_src =fixincl.x= 文件并非每次在编译时生成,而是已经生成好了放在哪里。如果修 改了 =fixincl.tpl= 或者 =inclhack.def= ,则需要调用 =fixincludes/genfixes= 脚本重新生成 =fixincl.x= ,还要进行测试,确保没 有破坏任何已有的fix。具体方法参见 =fixincludes/README= 文件。