文章目录
- 1 问题来源
- 2 初步分析
- 2.1 内事不决问百度,外事不决问谷歌
- 2.2 开发不懂问‘男人’
- 2.3 gcc默认的specs参数
- 2.4 specs文件都放在哪里?
- 2.5 愉快地结束
- 3 更多分享
1 问题来源
近来关注rt-thread的论坛稍微少了一些,今天突然在论坛里面看到这么一个问题:
为何会对这个问题感兴趣呢?
主要有以下两个原因:
- 最近都在研究一些gcc编译链接相关的知识,做了一些笔记,方便自己加深理解和记忆;
- 这个specs选项,隐约记得在哪里见过,但是又记不清楚来龙去脉,看来还是记忆不够深刻。
于是乎,我决定趁着这个机会,好好扒一扒这个specs选项。
2 初步分析
2.1 内事不决问百度,外事不决问谷歌
二话不说,先baidu之,如下:
没找到合适的,那google一下?无奈,没有梯子,那就bing一下吧:
问题答案没找到,倒是把问题自己给找到了。
2.2 开发不懂问‘男人’
都说男人靠得住,母猪都上树
,但是作为一个长期混迹在Linux开发环境下的程序猿,我可以很负责任地告诉,男人是最不会骗人的
,不信你man
一下:
recan@ubuntu:~$ man gcc | grep "specs"
-specs=file -wrapper @file -ffile-prefix-map=old=new -fplugin=file -fplugin-arg-name=arg -fdump-ada-spec[-slim]
-fconstexpr-loop-limit=n -fconstexpr-ops-limit=n -fno-elide-constructors -fno-enforce-eh-specs -fno-gnu-keywords
-dletters -dumpspecs -dumpmachine -dumpversion -dumpfullversion -fchecking -fchecking=n -fdbg-cnt-list
-mshort-calls -nodevicelib -nodevicespecs -Waddr-space-convert -Wmisspelled-isr
declaration). Such files are also called specs.
-specs=file
Process file after the compiler reads in the standard specs file, in order to override the defaults which the gcc
driver program uses when determining what switches to pass to cc1, cc1plus, as, ld, etc. More than one -specs=file
For C and C++ source and include files, generate corresponding Ada specs.
In conjunction with -fdump-ada-spec[-slim] above, generate Ada specs as child units of parent unit.
-fno-enforce-eh-specs
used in filesystem paths and specs. Depending on how the compiler has been configured it can be just a single number
-dumpspecs
Print the compiler's built-in specs---and don't do anything else. (This is used when GCC itself is being built.)
troff: <standard input>:17361: warning [p 110, 20.7i]: can't break line
-nodevicespecs
Don't add -specs=device-specs/specs-<mcu> to the compiler driver's command line. The user takes responsibility for
(/usr/lpp/ppe.poe/), or the specs file must be overridden with the -specs= option to specify the appropriate
这句命令行的意思就是在man gcc
的结果里面搜索specs
关键字,注意仔细看,我们发现了有-specs=file
这个关键信息,不用猜,就是它了。
为了更好地说明,我把这段描述完整地拎出来:
-specs=file
Process file after the compiler reads in the standard specs file, in order to override the defaults which the gcc
driver program uses when determining what switches to pass to cc1, cc1plus, as, ld, etc. More than one -specs=file
can be specified on the command line, and they are processed in order, from left to right.
需要点英文理解能力,但是语意并不难,实在不行,用翻译软件也可以搞定:
-specs=文件
编译器读入标准规范文件后处理文件,以覆盖gcc使用的默认值
驱动程序用于确定要传递给cc1、cc1plus、as、ld等的开关。多个-specs=文件
可以在命令行上指定,并按从左到右的顺序处理。
OK,意思已经很明确了,就是用于覆盖gcc默认的传递参数,这些新的参数是在一个新的文件里面里面指定,比如问题中的就是kernel.specs
。
2.3 gcc默认的specs参数
如果你好好读man gcc
的返回,你会发现有这么一个-dumpspec
选项,它就是记录了gcc默认的specs参数,为了说明下specs文件长啥样,我把它导出来看看:(说明下,我这个是x64环境下的gcc,如果是交叉编译的gcc,替换对应的gcc即可,方法都是一样的。)
recan@ubuntu:~$ gcc -dumpspecs > default.specs
recan@ubuntu:~$
recan@ubuntu:~$ cat default.specs
*asm:
%{m16|m32:--32} %{m16|m32|mx32:;:--64} %{mx32:--x32} %{msse2avx:%{!mavx:-msse2avx}}
*asm_debug:
%{%:debug-level-gt(0):%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}} %{fdebug-prefix-map=*:--debug-prefix-map %*}
*asm_final:
%{gsplit-dwarf:
objcopy --extract-dwo %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo}
objcopy --strip-dwo %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} }
*asm_options:
%{-target-help:%:print-asm-header()} %{v} %{w:-W} %{I*} %{gz|gz=zlib:--compress-debug-sections=zlib} %{gz=none:--compress-debug-sections=none} %{gz=zlib-gnu:--compress-debug-sections=zlib-gnu} %a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}
*invoke_as:
%{!fwpa*: %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()} %{!S:-o %|.s |
as %(asm_options) %m.s %A } }
*cpp:
%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}
*cpp_options:
%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w} %{f*} %{g*:%{%:debug-level-gt(0):%{g*} %{!fno-working-directory:-fworking-directory}}} %{O*} %{undef} %{save-temps*:-fpch-preprocess} %(distro_defaults)
*cpp_debug_options:
%{d*}
*cpp_unique_options:
%{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %@{I*&F*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}} %{remap} %{g3|ggdb3|gstabs3|gxcoff3|gvms3:-dD} %{!iplugindir*:%{fplugin*:%:find-plugindir()}} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{E|M|MM:%W{o*}}
*trad_capable_cpp:
cc1 -E %{traditional|traditional-cpp:-traditional-cpp}
*cc1:
%{!mandroid|tno-android-cc:%(cc1_cpu) %{profile:-p};:%(cc1_cpu) %{profile:-p} %{!mglibc:%{!muclibc:%{!mbionic: -mbionic}}} %{!fno-pic:%{!fno-PIC:%{!fpic:%{!fPIC: -fPIC}}}}}
*cc1_options:
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %{!iplugindir*:%{fplugin*:%:find-plugindir()}} %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*} %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{Qy:} %{-help:--help} %{-target-help:--target-help} %{-version:--version} %{-help=*:--help=%*} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{coverage:-fprofile-arcs -ftest-coverage} %{fprofile-arcs|fprofile-generate*|coverage: %{!fprofile-update=single: %{pthread:-fprofile-update=prefer-atomic}}}
*cc1plus:
*link_gcc_c_sequence:
%{static|static-pie:--start-group} %G %{!nolibc:%L} %{static|static-pie:--end-group}%{!static:%{!static-pie:%G}}
*distro_defaults:
%{!fno-asynchronous-unwind-tables:-fasynchronous-unwind-tables} %{!fno-stack-protector:%{!fstack-protector-all:%{!ffreestanding:%{!nostdlib:%{!fstack-protector:-fstack-protector-strong}}}}} %{!Wformat:%{!Wformat=2:%{!Wformat=0:%{!Wall:-Wformat} %{!Wno-format-security:-Wformat-security}}}} %{!fno-stack-clash-protection:-fstack-clash-protection} %{!fcf-protection*:%{!fno-cf-protection:-fcf-protection}}
*link_ssp:
%{fstack-protector|fstack-protector-all|fstack-protector-strong|fstack-protector-explicit:}
*endfile:
%{!mandroid|tno-android-ld:%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} %{mpc32:crtprec32.o%s} %{mpc64:crtprec64.o%s} %{mpc80:crtprec80.o%s} %{fvtable-verify=none:%s; fvtable-verify=preinit:vtv_end_preinit.o%s; fvtable-verify=std:vtv_end.o%s} %{static:crtend.o%s; shared|static-pie|!no-pie:crtendS.o%s; :crtend.o%s} crtn.o%s %{fopenacc|fopenmp:crtoffloadend%O%s};:%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} %{mpc32:crtprec32.o%s} %{mpc64:crtprec64.o%s} %{mpc80:crtprec80.o%s} %{shared: crtend_so%O%s;: crtend_android%O%s}}
*link:
%{!r:--build-id} %{!static|static-pie:--eh-frame-hdr} %{!mandroid|tno-android-ld:%{m16|m32|mx32:;:-m elf_x86_64} %{m16|m32:-m elf_i386} %{mx32:-m elf32_x86_64} --hash-style=gnu --as-needed %{shared:-shared} %{!shared: %{!static: %{!static-pie: %{rdynamic:-export-dynamic} %{m16|m32:-dynamic-linker %{muclibc:/lib/ld-uClibc.so.0;:%{mbionic:/system/bin/linker;:%{mmusl:/lib/ld-musl-i386.so.1;:/lib/ld-linux.so.2}}}} %{m16|m32|mx32:;:-dynamic-linker %{muclibc:/lib/ld64-uClibc.so.0;:%{mbionic:/system/bin/linker64;:%{mmusl:/lib/ld-musl-x86_64.so.1;:/lib64/ld-linux-x86-64.so.2}}}} %{mx32:-dynamic-linker %{muclibc:/lib/ldx32-uClibc.so.0;:%{mbionic:/system/bin/linkerx32;:%{mmusl:/lib/ld-musl-x32.so.1;:/libx32/ld-linux-x32.so.2}}}}}} %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z text}};:%{m16|m32|mx32:;:-m elf_x86_64} %{m16|m32:-m elf_i386} %{mx32:-m elf32_x86_64} --hash-style=gnu --as-needed %{shared:-shared} %{!shared: %{!static: %{!static-pie: %{rdynamic:-export-dynamic} %{m16|m32:-dynamic-linker %{muclibc:/lib/ld-uClibc.so.0;:%{mbionic:/system/bin/linker;:%{mmusl:/lib/ld-musl-i386.so.1;:/lib/ld-linux.so.2}}}} %{m16|m32|mx32:;:-dynamic-linker %{muclibc:/lib/ld64-uClibc.so.0;:%{mbionic:/system/bin/linker64;:%{mmusl:/lib/ld-musl-x86_64.so.1;:/lib64/ld-linux-x86-64.so.2}}}} %{mx32:-dynamic-linker %{muclibc:/lib/ldx32-uClibc.so.0;:%{mbionic:/system/bin/linkerx32;:%{mmusl:/lib/ld-musl-x32.so.1;:/libx32/ld-linux-x32.so.2}}}}}} %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z text}} %{shared: -Bsymbolic}}
*lib:
%{!mandroid|tno-android-ld:%{pthread:-lpthread} %{shared:-lc} %{!shared:%{profile:-lc_p}%{!profile:-lc}};:%{shared:-lc} %{!shared:%{profile:-lc_p}%{!profile:-lc}} %{!static: -ldl}}
*link_gomp:
*libgcc:
%{static|static-libgcc|static-pie:-lgcc -lgcc_eh}%{!static:%{!static-libgcc:%{!static-pie:%{!shared-libgcc:-lgcc --push-state --as-needed -lgcc_s --pop-state}%{shared-libgcc:-lgcc_s%{!shared: -lgcc}}}}}
*startfile:
%{!mandroid|tno-android-ld:%{shared:; pg|p|profile:%{static-pie:grcrt1.o%s;:gcrt1.o%s}; static:crt1.o%s; static-pie:rcrt1.o%s; !no-pie:Scrt1.o%s; :crt1.o%s} crti.o%s %{static:crtbeginT.o%s; shared|static-pie|!no-pie:crtbeginS.o%s; :crtbegin.o%s} %{fvtable-verify=none:%s; fvtable-verify=preinit:vtv_start_preinit.o%s; fvtable-verify=std:vtv_start.o%s} %{fopenacc|fopenmp:crtoffloadbegin%O%s};:%{shared: crtbegin_so%O%s;: %{static: crtbegin_static%O%s;: crtbegin_dynamic%O%s}}}
*cross_compile:
0
*version:
9.3.0
*multilib:
. !m32 !m64 !mx32;32:../lib32:i386-linux-gnu m32 !m64 !mx32;64:../lib:x86_64-linux-gnu !m32 m64 !mx32;x32:../libx32:x86_64-linux-gnux32 !m32 !m64 mx32;
*multilib_defaults:
m64
*multilib_extra:
*multilib_matches:
m32 m32;m64 m64;mx32 mx32;
*multilib_exclusions:
*multilib_options:
m32/m64/mx32
*multilib_reuse:
*linker:
collect2
*linker_plugin_file:
*lto_wrapper:
*lto_gcc:
*post_link:
*link_libgcc:
%D
*md_exec_prefix:
*md_startfile_prefix:
*md_startfile_prefix_1:
*startfile_prefix_spec:
*sysroot_spec:
--sysroot=%R
*sysroot_suffix_spec:
*sysroot_hdrs_suffix_spec:
*self_spec:
*cc1_cpu:
%{march=native:%>march=native %:local_cpu_detect(arch) %{!mtune=*:%>mtune=native %:local_cpu_detect(tune)}} %{mtune=native:%>mtune=native %:local_cpu_detect(tune)}
*link_command:
%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S: %(linker) %{!fno-use-linker-plugin:%{!fno-lto: -plugin %(linker_plugin_file) -plugin-opt=%(lto_wrapper) -plugin-opt=-fresolution=%u.res %{flinker-output=*:-plugin-opt=-linker-output-known} %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} }}%{flto|flto=*:%<fcompare-debug*} %{flto} %{fno-lto} %{flto=*} %l %{static|shared|r:;!no-pie:-pie -z now} %{fuse-ld=*:-fuse-ld=%*} %{gz|gz=zlib:--compress-debug-sections=zlib} %{gz=none:--compress-debug-sections=none} %{gz=zlib-gnu:--compress-debug-sections=zlib-gnu} -z relro %X %{o*} %{e*} %{N} %{n} %{r} %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!r:%{!nostartfiles:%S}}} %{static|no-pie|static-pie:} %@{L*} %(mfwrap) %(link_libgcc) %{fvtable-verify=none:} %{fvtable-verify=std: %e-fvtable-verify=std is not supported in this configuration} %{fvtable-verify=preinit: %e-fvtable-verify=preinit is not supported in this configuration} %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):%{!shared:libasan_preinit%O%s} %{static-libasan:%{!shared:-Bstatic --whole-archive -lasan --no-whole-archive -Bdynamic}}%{!static-libasan:%{!fuse-ld=gold:--push-state} --no-as-needed -lasan %{fuse-ld=gold:--as-needed;:--pop-state}}} %{%:sanitize(thread):%{!shared:libtsan_preinit%O%s} %{static-libtsan:%{!shared:-Bstatic --whole-archive -ltsan --no-whole-archive -Bdynamic}}%{!static-libtsan:%{!fuse-ld=gold:--push-state} --no-as-needed -ltsan %{fuse-ld=gold:--as-needed;:--pop-state}}} %{%:sanitize(leak):%{!shared:liblsan_preinit%O%s} %{static-liblsan:%{!shared:-Bstatic --whole-archive -llsan --no-whole-archive -Bdynamic}}%{!static-liblsan:%{!fuse-ld=gold:--push-state} --no-as-needed -llsan %{fuse-ld=gold:--as-needed;:--pop-state}}}}}} %o %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1): %:include(libgomp.spec)%(link_gomp)} %{fgnu-tm:%:include(libitm.spec)%(link_itm)} %(mflib) %{fsplit-stack: --wrap=pthread_create} %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address): %{static-libasan|static:%:include(libsanitizer.spec)%(link_libasan)} %{static:%ecannot specify -static with -fsanitize=address}} %{%:sanitize(thread): %{static-libtsan|static:%:include(libsanitizer.spec)%(link_libtsan)} %{static:%ecannot specify -static with -fsanitize=thread}} %{%:sanitize(undefined):%{static-libubsan:-Bstatic} %{!static-libubsan:--push-state --no-as-needed} -lubsan %{static-libubsan:-Bdynamic} %{!static-libubsan:--pop-state} %{static-libubsan|static:%:include(libsanitizer.spec)%(link_libubsan)}} %{%:sanitize(leak): %{static-liblsan|static:%:include(libsanitizer.spec)%(link_liblsan)}}}}} %{!nostdlib:%{!r:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}} %{!nostdlib:%{!r:%{!nostartfiles:%E}}} %{T*}
%(post_link) }}}}}}
由于specs文件这块知识在我这,确实是个盲区,我还得记住巨人的肩膀,我找到了一篇参考价值比较大的文章。
具体我不再细说里面的内容了,大家可以对照着来学习,简单捋一遍就会印象更深刻。
2.4 specs文件都放在哪里?
起初,当我们知道-specs=kernel.specs
中的kernel.specs
是一个文件的时候,我第一感觉就是:“嗯,应该在源码的bsp目录里面”,结果我拉去rt-smart的源码搜了一遍也没搜到:
takeout@newnew MINGW64 /c/llc/git_repos/rt-thread-share/rt-thread (rt-smart)
$ find . -name "kernel.specs"
takeout@newnew MINGW64 /c/llc/git_repos/rt-thread-share/rt-thread (rt-smart)
$ find . -name "*.specs"
这类名称的specs文件一个没搜到,倒是搜关键字的时候,有的bsp提到了nano.specs
:
既然有些bsp的链接选项,明目张胆地引入nano.specs
文件,而且编译不会报错,自然肯定有地方能找到它。
既然不在源码目录,那么还有一个可能就是在交叉编译工具链的目录里面,我们来找一找。
以我手上的gcc-arm-none-eabi-5_4-2016q3
为例子:
这么一说,我想起了为何之前对specs
有些印象,就是这两个nano.specs
和nosys.specs
;baidu之,这下资料就很多了,这里给几个有效的参考链接:
- RISC-V GCC:-specs=nano.specs 的作用
- stm32 基于ARM GCC Compliler(EmBitz IDE) print重定向到串口打印输出 com serial
看了第二个nosys.specs
,再次勾起回忆,之前RRT论坛就有一个问题跟这个有关的,需要通过加入nosys.specs
来解决的,当然我还看到它的解决思路,还真的是有点印象,仅此而已。
找到当时我回答的那个问题,大家也可以顺带看看当时我的思路。
另外,相关的问题我给出链接,大家有空都可以去看看,说不定能解决你的一些疑问。
- https://club.rt-thread.org/ask/search.html?module=question&type=new&keyword=_sbrk
- sbrk话题
2.5 愉快地结束
看到这里,楼主的疑问已经解答了,我自己对这个知识点也加深了理解,看来还是要多记笔记,真正进入到自己脑海里的东西才是自己的,否则永远只存在于搜索引擎中。
3 更多分享
欢饮大家关注我的github仓库01workstation,欢迎指正问题。
同时也非常欢迎关注我的CSDN主页和专栏:
【http://yyds.recan-li.cn】
【C/C++语言编程专栏】
【GCC专栏】
【信息安全专栏】
有问题的话,可以跟我讨论,知无不答,谢谢大家。