[置顶] 修改GCC Specs大全

改变gcc默认的include目录和link目录  

About Specs file

specs文件是什么?

“GCC”是一种方便用户调用的程序前端驱动程序可执行文件将在后台调用其他程序,比如cc1作为其工作或ld根据给定的命令行参数。SPECS文件是纯文本用于控制“GCC”前端的默认行为。SPECS文件通常是内置的灵活性的目的,但它可以覆盖与外部版本。

基本SPECS文件修改

GCC通过以下命令将产生一个规范文件。

gcc -dumpspecs > specs

你可以使用你选择的文本编辑器来检查specs。

在编译时使用参数 -specs=<path_to_specs_file> 

或者 

将specs放入"gcc -print-libgcc-file-name"给出的路径,来默认使用这个specs文件 , 调用gcc -v来查看正在使用的specs配置




其实简单来说,gcc spec文件是用来控制gcc的默认行为的,一般被放在这个目录下可以找到这个文件:
# cd /x86toolchain/lib/gcc/i686-mot-linux-gnu/3.4.3
# ls specs
也可以通过这个命令来打印gcc spec:
# gcc -dumpspecs
如果希望使用自己的specs, 可以通过-specs参数来指定:
# g++ -O2 -specs=/tmp/specs  1.c
下面是用来修改gcc默认行为的几个例子:
使用 -O2 & -fomit-frame-pointer 进行编译
By default, 对于X86 GCC, 如果指定-O2, frame pointer并不会被omit掉,通过修改specs, 我们可以在-O2的情况下,同时omit frame pointer:
*cc1_options:
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{O2:-O2 -fomit-frame-pointer} %{O3:-O3 -fomit-frame-pointer}

*cc1plus_options:
%{O2:-O2 -fomit-frame-pointer} %{O3:-O3 -fomit-frame-pointer}

使gcc默认编译gdb调试debug程序

-g

By default, GCC不会在编译object的时候使用-g选项,可以通过修改specs来对所有的objects在编译的时候加上-g选项:
*cc1:
%(cc1_cpu) %{profile:-p} -g
*cc1plus:
-g

包括目录添加到搜索路径

* cpp:部分。默认情况下:

*cpp:
%{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT}
如果你需要将"z:\libx\include" 加入默认头文件搜索路径,那么操作如下
*cpp:
%{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT} -I z:/libx/include


添加lib搜索路径

*link_libgcc: 默认情况下:

*link_libgcc:
%D
如果你需要将"z:\libx\lib" 加入默认库文件搜索路径,那么操作如下
*link_libgcc:
%D -L z:/libx/lib

 
使Gcc默认-muclibc
修改specs文件为:
*link:
%{!static:--eh-frame-hdr} %{h*} %{version:-v}    %{b}    %{static:-Bstatic}    %{shared:-shared}    %{symbolic:-Bsymbolic}    %{rdynamic:-export-dynamic}    %{!dynamic-linker:-dynamic-linker %{muclibc:%{mglibc:%e-mglibc and -muclibc used together}/lib/ld-uClibc.so.0;:/lib/ld-uClibc.so.0}}    -X    %{mbig-endian:-EB} %{mlittle-endian:-EL} -m armelf_linux_eabi 
 
 
修改gcc默认的specs文件
specs文件修改了不会保存么?想让每次使用gcc都根据自己的意思来么?
办法1:
	在.bashrc脚本中添加alias arm-linux-gcc="arm-linux-gcc -specs=~/gcc_specs"
那么以后每次调用gcc的时候都会根据自定义的specs编译了
 
  
方法2:
step1:调用命令:arm-linux-gcc -v
Using built-in specs. Target: arm-none-linux-gnueabi Configured with: ../../gcc-4.2.1/configure --prefix=/usr/local/arm_linux_4.2 --target=arm-none-linux-gnueabi --enable-languages=c,c++ --with-gnu-ld --with-gnu-as --disable-nls --with-float=soft --without-newlib --disable-libmudflap --disable-libssp --disable-libgomp Thread model: posix gcc version 4.2.1
发现当前是使用	Using built-in specs. gcc内建的specs
step2:调用命令:arm-linux-gcc -print-libgcc-file-name查看当前今天libc库连接的路径,将specs文件放入这个目录(注:名称只能是specs)
step3:再次arm-linux-gcc -v,发现现在使用的已经是自己的specs了
Reading specs from /mnt/exfs/dragon/usr/arm/arm_linux_4.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.2.1/specs
Target: arm-none-linux-gnueabi
Configured with: ../../gcc-4.2.1/configure --prefix=/usr/local/arm_linux_4.2 --target=arm-none-linux-gnueabi --enable-languages=c,c++ --with-gnu-ld --with-gnu-as --disable-nls --with-float=soft --without-newlib --disable-libmudflap --disable-libssp --disable-libgomp
Thread model: posix
gcc version 4.2.1

 
 
 
 

gcc 是一个驱动式的程序. 它调用其它程序来依次进行编译, 汇编和链接. GCC 分析命令行参数, 然后决定该调用哪一个子程序, 哪些参数应该传递给子程序. 所有这些行为都是由 SPEC 字符串(spec strings)来控制的. 通常情况下, 每一个 GCC 可以调用的子程序都对应着一个 SPEC 字符串, 不过有少数的子程序需要多个 SPEC 字符串来控制他们的行为. 编译到 GCC 中的 SPEC 字符串可以被覆盖, 方法是使用 -specs= 命令行参数来指定一个 SPEC 文件(spec file).

Spec 文件(Spec files) 就是用来配置 SPEC 字符串的. 它包含了一系列用空行分隔的指令. 指令的类型由一行的第一个非空格字符决定, 它们可能是:

%command
定义 SPEC 文件的预处理命令, 预处理命令包括以下的命令:
%include <file>
搜索文件, 并将其内容插入到 SPEC 文件的当前位置.
%include_noerr <file>
和 '%include' 一样, 但是在没有找到文件的情况下不会产生错误消息.
%renameold_name new_name
将 SPEC 字符串 old_name 改名为 new_name.
*[spec_name]:
这条命令让编译器创建,覆盖或删除指定名字的 SEPC 字符串. 所有在这条指令之后到下一条指令或空行之前的文本都被认为是这个 SPEC 字符串的内容. 如果它的内容为空, 则这个名字将被删除(如果该名字不存在, 则什么都不会发生). 内容不为空时, 如果该名字不存在, 则会创建一个新的 SPEC 字符串, 如果已经存在了, 他们的内容将会被替换. 如果内容的第一个字符为 '+', 则这些内容会被追加到原来定义的内容后面, 而不是覆盖了.
[suffix]:
创建一个新的 '[suffix] spec'(后缀处理) 组合. 这个指令之后到下一个指令或空行之前的行组成了这个后缀的 SPEC 字符串. 当编译器遇到指这种后缀的输入文件时, 它会依次执行 SPEC 字符串中的指令, 这些指令指明了如何编译那个文件. 例如:
          .ZZ:
          z-compile -input %i
     

它的意思是: 任何以 '.ZZ' 结尾的输入文件都将使用 'z-compile' 程序进行处理, 调用的时候将会使用 -input 开关以及 '%i' 替换后的结果(详见下文) 作为命令行参数.

作为 SPEC 字符串的内容, suffix 指令后的文本还可以是下面的某一个:

@language
它表明这个后缀是某种已知语言的别名. 它和 GCC 命令行中用于指定语言的 -x 选项类似. 比如:
               .ZZ:
               @c++
          

这说明 .ZZ 文件实际上是 C++ 的源代码文件.


#name
这会产生一条错误消息:
               当前系统没有安装 name 编译器.
          

GCC 已经内建了一份巨大的后缀列表. 这条指令将后缀添加到列表的结尾处, 由于这个列表使用的时候是从结尾向后搜索的, 实际上可以使用这种技术来覆盖之前的条目.

GCC 已经内置了如下的 SPEC 字符串. SPEC 文件可以覆盖他们或者创建新的. 注意, 某些 GCC 的实现也可能添加它们自己的 SEPC 字符串到这个列表里面.

     asm          传递给汇编器的选项
     asm_final    传递给汇编后处理器的选项
     cpp          传递给 C 预处理器的选项
     cc1          传递给 C 编译器的选项
     cc1plus      传递给 C++ 编译器的选项
     endfile      链接的最后需要包含的目标文件
     link         传递给链接器的选项
     lib          命令行传递给链接器的要包含的库
     libgcc       决定给链接器传递哪个 GCC 支持库
     linker       设置链接器的名字
     predefines   传递给 C 预处理器的宏定义
     signed_char  传递给 CPP 的用于说明 char 默认是否是有符号类型的宏
     startfile    一开始就需要传递给链接器的目标文件

下面是一个简单的 SPEC 文件的例子:

     %rename lib                 old_lib
     
     *lib:
     --start-group -lgcc -lc -leval1 --end-group %(old_lib)

这个例子把 'lib' 改名为 'old_lib' 然后用一个新的定义覆盖了之前的 'lib' 定义. 新定义在包含旧的定义文本之前添加了一些额外的命令行选项.

SEPC 字符串是传递给相应程序的命令行选项的列表. 另外, SEPC 字符串可以包含 '%' 作为前缀的字符串来表示变量. 变量可以用来代替一串文本, 或者作为向命令行插入文本的条件. 使用这些概念可以产生非常复杂的命令行.

下面是所有的用于 SPEC 字符串的预定义变量. 注意,这些变量在表示文本时不会自动在结果两边产生空格. 你可以在链接这些变量时使用常量字符串来一起链接.

%%
在程序名字或参数中用于表示一个 '%'.
%i
用来表示当前正在处理的输入文件名
%b
表示输入文件的基本名字. 它不包含最后一个点号以及之后的内容, 也不包含路径名.
%B
和 '%b' 相同, 但是它包含了后缀名(最后一个点号后的内容).
%d
用包含或附加 '%d' 来标记一个临时文件名, GCC 正常退出后会自动删除带有这种标记的文件. 和 '%g' 不同, 这个变量不会在参数中产生文本内容.
%gsuffix
产生指定后缀 suffix 的文件名, 每次编译产生一个. 和 '%d' 一样, 它也会被标记为临时文件. 为了减少拒绝服务攻击的可能性, 即使上一次产生的文件名已经知道了, 下一次产生的文件名也是无法预料的. 例如, '%g.s ... %g.o ... %g.s' 可能被转换成 'ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'. 后缀名需要可以和 '[.A-Za-z]*' 这样的正则表达式匹配或者使用特定的 '%O'. '%O' 使用的时候假设它已经被处理过了. 以前, '%g' 只是简单的每次出现都被替换成一个文件名, 没有后缀的情况下使得攻击很容易成功.
%usuffix
和 '%g' 一样, 但是每次出现就会产生一个新的临时文件名, 而不是每次编译的时候一个.
%Usuffix
生成上一次使用 '%usuffix' 时产生的文件名, 如果之前没有过, 就生成一个新的. 在没有使用过 '%usuffix' 的情况下, 它和 '%gsuffix' 一样, 只是他们不会共享后缀名字空间. 因此, '%g.s ... %U.s ... %g.s ... %U.s' 会生成两个不同的文件名, 一个是 '%g.s' 产生的, 另一个是 '%U.s'. 以前, '%U' 只是替换成上一个的 '%u' 产生的文件名, 不会带任何的后缀.
%jsuffix
如果存在 HOST_BIT_BUCKET, 并且它可写, 也没有使用 -save-temps, 这会被替换成 HOST_BIT_BUCKET 的名字. 否则, 产生一个临时文件名, 和 '%u' 效果相同. 这个临时文件并不用来在两个进程间通信, 只是作为垃圾进行处理.

[adie: HOST_BIT_BUCKET 是 GCC 中配置宿主系统环境时用到一个参数. 它是由宿主系统定义的一个路径名, 可以被当作一个文件来进行写入, 但是所有写入的内容都会被丢弃. 这通常被称为 bit bucket(比特流垃圾桶) 或 null device(空设备), 在 UNIX 中它通常就是 /dev/null.


%|suffix
%msuffix
和 '%g' 类似, 只是可以使用 -pipe (管道). 使用管道时, '%|' 被替换成一个破折号, '%m' 被替换成空. 这是让程序从标准输入读取数据和往标准输出写数据的常用方式. 如果你需要处理更复杂的情况, 你还可以使用 '%{pipe:X}': 参考 f/lang-specs.h 中的例子.
%.SUFFIX
对于匹配后缀的参数进行替换. 后缀到空格或下一个 % 结束.
%w
对包含或跟随有 '%w' 的参数标记为此次编译的输出文件. 这会将这个参数放到 '%o' 的参数序列里面.
%o
替换所有输出文件的名字, 并自动在他们周围放置空格. 你仍然应该在 '%o' 的周围书写空格, 否则结果将是未定义的. '%o' 用于运行链接器. 没有可识别后缀的输入文件将不会被编译, 但是他们被包含在输出文件里, 因此, 他们可以被链接. 
%O
为目标文件替换后缀. 注意, 当它紧接在 '%g, %u, 和 %U' 后面时会被特别处理, 因为它们需要完整的文件名. 处理的方法是假设 '%O' 已经被处理过了, 除非 '%g, %u, 和 %U' 当前不支持使用特殊的 '%O' 后缀, 例如, '.o'.
%p
替换标准的预定义宏为当前的目标类型. 运行 cpp 程序时使用.
%P
和 '%p' 类似, 只是会在每个预定义宏的名字前后加上 '__', 除非宏的名字是以 '__' 或 '_L' 开头的. 其中 L 是一个大写字母. 这是 ISO C 所要求的.
%I
贴换所有的 -iprefix(来自 GCC_EXEC_PREFIX), -isysroot(来自 TARGET_SYSTEM_ROOT), -isystem(来自 COMPILER_PATH 和 -B 选项) 以及所需的 -imultilib.
%s
当前参数是某个库或可执行文件的名字. 搜索标准的目录列表来查找这个文件名, 如果找到了, 就用全名来进行替换. 当前目录被包含在扫描的目录列表的第一位.
%T
当前参数是一个连接脚本. 在库文件的目录列表里面搜索那个文件. 如果文件找到了, 插入一个 --script 选项和文件的全路径名到命令行中. 如果文件没找到将会产生一条错误信息. 注意, 当前目录不会被搜索.
%estr
把 str 作为错误消息打印出来. str 使用换行作为结束. 检测到不一致的选项时可以使用它.
%(name)
贴换名字为 name 的 SPEC 字符串内容到当前位置.
%x{option}
为 '%X' 添加一个选项.
%X
输出用 -W1 或 '%x' 添加的所有链接器选项.
%Y
输出用 -Wa 添加的所有汇编器选项.
%Z
输出用 -Wp 添加的所有汇编器选项.
%a
处理 asm spec. 用于计算传递给汇编器的开关.
%A
处理 asm_final spec. 如果需要汇编后处理器的话, 用于计算传递给汇编后处理器的选项.
%l
处理 link spec. 用于计算传递给链接器的命令行参数. 它一般是使用的 `%L %G %S %D 和 %E' 序列.
%D
为所有 GCC 认为可能包含可执行文件的目录导出一个 -L 选项. 如果目标支持多库, 那么每个目录都会考虑多库目录.
%L
处理 lib spec. 这个 SPEC 字符串决定了连接器的命令行需要包含的库文件.
%G
处理 libgcc spec. 这个 SEPC 字符串决定了传递给连接器命令行参数中使用的 GCC 支持库.
%S
处理 startfile spec. 这个 SEPC 字符串表示传递给链接器的第一个目标文件. 通常这个文件名是 crt0.o.
%E
处理 endfile spec. 表示传递给链接器的最后一个目标文件.
%C
处理 cpp spec. 用于构造传递给 C 预处理器的参数.
%1
处理 cc1 spec. 用于构造传递给当前的 C 编译器('cc1') 的选项.
%2
处理 cc1plus spec. 用于构造传递给当前的 C++ 编译器('cc1plus') 的选项.
%*
替换匹配选项的可变部分. 详见下文. 注意, 替换字符串中的逗号会被空格取代.
%<S
删除命令行中所有的 -S 选项. 注意这个命令是位置相关的. 在 SPEC 字符串中这个命令之前的 -S 会被删除, 之后的不会.
%:function(args)
调用指定名字的函数, 并传递参数. 参数首先被当作嵌套的 SPEC 字符串处理, 然后分割成一个参数数组. 函数返回一个字符串, 插入到当前命令所在的位置.

下面是内建支持的 SPEC 函数:

getenv
getenv spec 函数带两个参数: 一个环境变量名称和一个字符串. 如果环境变量没有定义, 则会产生一个严重错误. 返回值是环境变量的值和字符串连接在一起的. 例如, 如果 TOPDIR 被定义为 /path/to/top, 那么:
               %:getenv(TOPDIR /include)

将会展开成 /path/to/top/include.


if-exists
if-exists 函数带一个参数, 一个文件的绝对路径名. 如果文件存在, if-exists 返回路径名. 下面是一个用法的简单例子:
               *startfile:
               crt0%O%s %:if-exists(crti%O%s) crtbegin%O%s

if-exists-else
if-exists-else 函数和 if-exists 函数类似, 不同的是它带有两个参数. 第一个参数是文件的路径名. 如果文件存在, if-exists-else 函数返回路径名. 如果不存在, 返回第二个参数. 这样, if-exists-else 函数可以根据文件是否存在来选择这个文件或其它 . 下面是一个使用的例子:
               *startfile:
               crt0%O%s %:if-exists(crti%O%s) \
               %:if-exists-else(crtbeginT%O%s crtbegin%O%s)

replace-outfile
replace-outfile 函数带有两个参数. 它在输出文件数组中查找第一个参数, 并用第二个参数来替换.下面是示例:
               %{fgnu-runtime:%:replace-outfile(-lobjc -lobjc-gnu)}

remove-outfile
remove-outfile 函数带一个参数. 它在输出文件数组中查找这个参数并将其删除. 示例:
               %:remove-outfile(-lm)

pass-through-libs
pass-through-libs 可以带任意数量的参数. 它查找 -l 选项和以 .a 结尾的非选项内容(确保是输入链接器的库文件), 将找到的所有参数加上 -plugin-opt=-pass-through= 前缀, 并添加空格分隔后返回. 这个列表用于传递给 LTO 链接器插件.
               %:pass-through-libs(%G %L %G)

print-asm-header
print-asm-header 函数不带参数, 它只是简单的打印如下的标语:
               Assembler options
               =================
               
               Use "-Wa,OPTION" to pass "OPTION" to the assembler.

它用于在使用 --target-help 的输出中分隔编译器选项和汇编器选项.


%{S}
如果给 GCC 传递了 -S 选项, 替换这个选项. 如果么有, 它什么也不做. 注意这个选项的前导破折号, 替换的时候会被自动加上. 因此, SPEC 字符串 '%{foo}' 匹配命令行中的 -foo 选项, 并且输出一个 -foo.
%W{S}
和 %{S} 类似, 只是会标记最后提供的那个参数为文件, 并且在失败的时候删除这个文件.
%{S*}
贴换传递给 GCC 的所有以 -S 开头的选项, 通常它们都还带有一个参数. 这主要用于对 -o, -D, -I 等选项使用. GCC 认为 -o foo 是一个选项, 它的名字以 'o' 开头. '%{o*}' 替换这个, 包括空格. 因此, 将会产生两个参数.
%{S*&T*}
和 %{S*} 类似, 只是保持 S 和 T 选项的顺序(在 SEPC 中 S 和 T 的顺序并不重要). 可以使用任意数量的 & 分隔的变量, 其中的每个字段都是可选的. 对 CPP 比较有用的例子如: '%{D*&U*&A*}'. 
%{S:X}
如果 GCC 中使用了 -S 选项, 用 X 来代替.
%{!S:X}
如果没有在 GCC 中使用 -S 选项, 替换成 X.
%{S*:X}
如果有一个或多个以 -S 开头的选项, 则替换成 X. 通常, 不管选项出现了多少次, 都只替换成一个 X. 但是, 如果 X 中包含了 '%*', 那么每一个选项都会替换成一个 X, 其中的 '%*' 被选项中匹配 '*' 的部分替代.
%{.S:X}
如果处理的文件以 S 开头, 则替换成 X
%{!.S:X}
如果没有处理以 S 开头的文件, 则替换成 X
%{,S:X}
如果处理的文件是 S 语言的, 则替换成 X
%{!,S:X}
如果没有处理 S 语言的文件, 则替换成 X
%{S|P:X}
如果提供了 -S 或 -P 选项, 则替换成 X. 它也可以和 '!', '.', ',' 以及 * 进行组合, 虽然他们比 '|' 有更强的约束. 如果 X 中出现了 '%*', 所有的替换项都需要使用 '*', 并且只有第一个匹配的替换项被使用.

例如, 像下面这样的 SEPC 字符串:

          %{.c:-foo} %{!.c:-bar} %{.c|d:-baz} %{!.c|d:-boggle}

则输入的命令行和对应的输出如下:

          fred.c        -foo -baz
          jim.d         -bar -boggle
          -d fred.c     -foo -baz -boggle
          -d jim.d      -bar -baz -boggle

%{S:X; T:Y; :D}
如果 GCC 包含了 -S 选项, 替换成 X, 否则, 如果包含了 -T, 替换成 Y, 否则, 替换成 D. 你可以添加任意数量的子句. 它还可以和 '.', ',', '!', '|' 以及 '*' 进行组合.

在条件语句 %{S:X} 以及类似的结构中的 X 可以包含嵌套的 '%' 结构, 空格, 甚至是换行. 向以上描述的那样, 它们照常工作. 在 X 结尾处的空格会被忽略. 空格也可以出现在冒号的左边, 但不能出现在 '.' 或 '*' 与匹配单词之间.

在这些结构中, -O, -f, -m, 以及 -W 选项会被特殊处理. 如果有其他的 -O 选项或者有与 -f, -m, -W 起作用相反的选项, 之前的值将会被忽略, 除非 {S*} 中的 S 只有一个字母. 只有一个字母时所有的匹配项都可以通过.

'|' 字符出现在谓词的开头表示接下来的命令应该使用管道, 不过只有使用了 -pipe 时才能生效.

哪些选项需要使用参数是内置到 GCC 里面的. (你或许在想, 通过使用不同的编译器 sepc 来定义哪些选项需要参数是很有用的. 但是, 这在目前是无法实现的. 如果不知道哪些选项需要参数的话, GCC 无法决定哪个是需要编译的输入文件. GCC 必须要知道输入文件才能决定使用哪个编译器).

GCC 也知道, 以 -l 开头的参数会被作为编译输出文件处理, 并按照它在其他输出文件中的位置传递给链接器.

sysroot 与 specs


Open source 常見的 toolchain,就非 gcc 和 binutils 系列莫屬。然而,商業公司提供的 toolchain,往往必需安裝在特定目錄,這總是惹惱有潔癖者,如我。然而,若將 toolchain 任意搬動位置,則會曝露 gcc 的一個缺陷,gcc 找不到其它幅程式或 library 。這是因為 gcc 假設 library 和 toolchain 會安裝在固定位置,於是在 build toolchain 時,就將這些路徑設定死。於是,對於不想重新 build toolchain,或只拿到 binary 的 user 而言,就必需使用 -nostdlib 這個參數,然後加上一堆 -I 和 -L 參數,使 gcc 能正確的找到 library 。

另外,一些 toolchain ,因為平台的因素,無法使用 gcc 預設好的參數內容。於是要強迫使用者必需下一堆固定的參數,例如: Android 就在其 build system 裡,為 gcc 設定一堆和平台相關的參數,像是 -mthumb。於是,若使用該 toolchain 自行開發軟體,就誓必要找出這些參數,並正確的設定為 gcc 的參數。這完全是一堆苦工。其實,只要作 toolchain 的人多用點心,使用 toolchain 其實可以不用這麼累。

sysroot

一般而言,gcc 會到 /usr/lib 和 /usr/include 下找 library 、 header files 和其它一些 start files 、 end files。當我們在 build gcc 設定 --prefix=/path/to/xxx ,則 gcc 安裝到 /path/to/xxx ,也在該目錄下的 lib/ 和 include/ 找 library 和 header 。旦,若裝 gcc 移到其它目錄時, gcc 會找不到這些 library 。這時,我們可以在呼叫 gcc 時,給予 --sysrooot=/new/path/to/xxx 參數。如此,gcc 就會改以 /new/path/to/xxx 為參考目錄,去搜尋所需的幅程式和 library 等。

然而,要注意的是, ld 必需要能 support --sysroot。這必需在 configure binutils 時,給予 --sysroot=xxx 參數。xxx 可以是任意目錄,不一定是實際安裝的位置。這個參數的主要目的是使 ld 啟動 --sysroot 的功能。

Spec File

--sysroot 解決了一部分問題,但有更大部分的問題是 toolchain 往往要你設定一些固定參數。例如,你會需要設定一些 header file 的目錄,並且設定一些平台有關的參數。這些設定往往又臭又長,很容易出錯。其實,這些參數可以寫在 spec file 裡,使用者就不用一再的重復指定這些參數。例如,以下是我為 Android 設定的 spec file 的內容

%rename cc1_android old_cc1_android
%rename cc1plus_android old_cc1plus_android

*android_root:
%R/../../../../../

*android_product:
generic

*ccflags:
%{!march=:-march=armv5te} %{!mtune=:-mtune=xscale} -mthumb \
-fno-strict-aliasing -finline-limit=64 -mthumb-interwork \
-fno-short-enums \
-D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__ \
-isystem %(android_root)bionic/libc/arch-arm/include/ \
-isystem %(android_root)bionic/libc/include \
-isystem %(android_root)bionic/libstdc++/include \
-isystem %(android_root)bionic/libc/kernel/common \
-isystem %(android_root)bionic/libc/kernel/arch-arm \
-isystem %(android_root)bionic/libm/include \
-isystem %(android_root)bionic/libm/include/arch/arm \
-isystem %(android_root)bionic/libthread_db/include \
-include %(android_root)system/core/include/arch/linux-arm/AndroidConfig.h \
-isystem %(android_root)system/core/include/arch/linux-arm/

*cc1_android:
%(old_cc1_android) %(ccflags)

*cc1plus_android:
%(old_cc1plus_android) %(ccflags)

像 Android 的 header files 就散置在一堆目錄,於是 build system 就指定了一堆參數。如果你自己寫個小程式,又不使用 Android 的 build system 時,就必需自己指定這些參數。於是,有人寫了一個 perl 的小程式,作為 gcc 的 wrapper ,幫你指定一些參數。其實不用這麼麻煩,只需像上例一樣,設定一個 spec file ,在執行 gcc 時加上一個參數就能自動套用這些參數

  • gcc -specs myandroid.specs

spec file 設計的很有彈性,可以對參數列的內容進行修改,也可以加入條件性的參數。像上例 {!march=:...} 就是指定,當參數列沒有指定 -march= 的參數時,就在 cc1 的參數例加入 -march=armv5te。另外我還指定了一些巨集和 -system 指定一些 header file 的路徑。而這些路徑是相對於 %R ,也就是 --sysroot 所指定的路。例如 --sysroot=/my/path/to/the/kkk/ ,則 %(android_root)bionic/libm/include/arch/arm 就會對應到 /my/path/to/th/kkk/../../../../../bionic/libm/include/arch/arm 。

更進一步

--sysroot 的預設內容,其實是可以設定成相對於 gcc 本身的位置。在 configure 時,若

configure --with-sysroot='${exec_prefix}/xxx'

則編譯出來的 gcc ,其 sysroot 就會相對於其執行路徑。如此 user 甚至不必再手動指定 --sysroot 。

結論

有了 spec files ,我們只需設定 -specs 和 --sysroot 兩個參數就能解決所有的問題。其實在建 toolchain 時,應該再多花一點時間,幫 user 作好 spec files 。這樣的 toolchain 才方便使用。 關於 spec file 更詳細的內容,請參考 Spec Files


 
 

你可能感兴趣的:([置顶] 修改GCC Specs大全)