当前位置:   article > 正文

Scons环境搭建和编译原理概述及嵌入式开发常用模板

scons

Scons环境搭建和编译原理概述及嵌入式开发常用模板

        Scons是用python实现的一个类似makefile的软件构建工具。其官网是SCons: A software construction tool - SCons,其具有详细的文档来对其使用进行说明SCons Documentation

        Scons是一个软件构建工具,除了能对c/c++/asm进行构建外,也能实现对java等语言进行构建。因为其是用python来实现的,所以其具备跨平台的特性。

        本例程所有相关代码在GitHub上,请自行下载。https://github.com/bobwenstudy/scons_demo

为什么用Scons

        第一次接触Scons是在RTThread中,进一步了解它的特性,渐渐的就喜欢上了,平常自己写一些代码,用Scons可以方便不少。对于我个人来说,主要的好处有:

        实际项目中编译工程时,除了要对代码进行编译生成固件外,还需要整合一些其他资源(如编译耳机项目时,需要讲提示音等wav资源打包进代码中;多固件合并打包之类。)之前完成这些动作是用python写的,当然能用makefile调用,但是相比Scons本身就是python,同一套环境调试起来会方便不少。

        易读性,相比于makefile这么久远的构建语言,Scons是python写的,其语法和调试起来更方便,函数调用和可读性都比makefile好。

        文件依赖,使用makefile时,由于经常编译的时候只将c文件作为依赖,而没有将h文件作为依赖,或其他资源,导致部分h文件更新时,经常要考虑先make clean,再make all。而Scons可以自动将关联的文件作为依赖,并构建依赖树,不用考虑太多就可以自动将相关依赖关系给维护好,当文件更新再次编译时,只编译特定文件。同时可以通过Depends指定依赖关系。

        缺点也有:

        集成度太强:Scons内部做了太多事情,对于我这种掌控欲比较强的程序猿来说,有点脱离掌控了,虽然方便,但是当构建大型项目时,内部一些行为可能导致debug很长时间,需要我们对其原理进行深入分析。

        资料较少:毕竟是新语言,现在很多新语言很快的死在沙滩上了,对于新语言,大家或多或少保持观望态度,所以目前资料还是比较少的。遇到bug得自己看官方手册,还是有点麻烦的。

环境搭建

        从上面描述可知,Scons类似于makefile,但并不是替代了GCC,只是实现了对GCC的使用。按照makefile的逻辑,需要准备如下环境:

GCC环境:笔者是Windows环境,所以需要msys64+mingw工具链。

Scons环境:python环境安装后,再安装scons就行。

GCC环境

PC下的GCC环境安装
        参考这个文章安装即可。Win7下msys64安装mingw工具链 - Milton - 博客园

安装完以后,键入gcc -v,得到如下提示说明环境安装好了,目前笔者用的是mingw32的gcc。
image-20220912103125415

ARM下的GCC环境安装

        从各个芯片产商都可以获取到对应的交叉工具链,笔者的交叉工具链解压缩后,就有gcc环境,一般交叉工具链会有前缀。

        安装完以后,键入arm-none-eabi-gcc -v,出现如下信息就代表安装成功了。

image-20220912111316820

 

Scons环境

Python安装

        Scons是运行在python环境下的,目前新版本的都运行在Python3+的版本上,就不建议安装Python2的环境了(当然也可以用Python2就是了,不过最新的pip已经不支持Python2了,希望大家早点切换)。

        网上有很多教程了,Python安装教程-史上最全_壬杰的博客-CSDN博客_python安装教程可以参考这个,当然也可以直接到Welcome to Python.org下载。

        最终安装结束后,键入python -V,能看到python版本,代表环境安装好了。

image-20220912103922628

 

Scons安装

        使用python -m pip install scons即可。当然可以到官网看看SCons DownloadsSCons DownloadsSCons Downloads

        最终安装结束后,键入scons -v,能看到如下信息,代表环境安装好了。

image-20220912104526394

初识Scons

基本概述

        要讲清楚Scons,需要理解gcc是如何使用的,已经相比于make,scons的行为差异。首先对gcc、make和scons基本概念进行说明。

gcc
        实际编译c文件的动作都是由gcc来完成的,scons/make等构建语言只是完成了对多个编译文件和编译目标的调度管理,本身不完成编译文件的动作。

        c编译原理的概念很多大佬已经讲得比较多了,可以参考:C编译原理_daixiao3636的博客-CSDN博客_c编译原理。当然现在要编译文件也很简单了,一般我们只用2步,一个是通过gcc -c -o生成object文件,然后再将object文件gcc -o生成目标文件。

make
        使用的换需要安装make环境,一般安装好mingw的时候,就自动装好了make+gcc环境,需要注意的是,新版装好后没有make.exe,而是:mingw32-make.exe,可以复制一份,并修改文件名为make.exe,以方便后面使用。

 image-20220912110738208

make使用可以直接在终端上使用,键入make -v,看到如下信息,说明make环境安装成功了。 

image-20220912110902820

执行make,会去寻找文件:GNUmakefile、makefile 和 Makefile。详细可以见:认识Makefile文件_天糊土的博客-CSDN博客_makefile文件在哪

image-20220913100427048

Scons

        之前已经安装好了scons环境,要使用scons,和make类似,也需要一个脚本文件,配置要执行的操作。文件名为:SConstruct

image-20220913100518586

 

单文件构建

gcc编译

        单个文件编译,gcc直接命令行操作就行,两行命令就可以搞定(当然1条命令也可以,这里为了统一,都要求先生成object文件,再生成目标文件)。

 image-20220913101553879

main.c的源码如下: 

  1. #include <stdio.h>
  2. int main()
  3. {
  4. printf("hello, world\n");
  5. return 0;
  6. }

make编译

        如图所示,第一次编译的时候,编译目标all依赖main.o,由于没有main.o,先对main.c进行编译,生成main.o,最后生成最终目标。第二次编译时,由于main.c没改变,自然main.o不需要改变,所以只需要执行all所对应的指令,生成目标main。

        clean清除完环境后,再次make all,所有的操作都重新来过。

image-20220913102014649

Makefile的源码如下: 

  1. all: main.o
  2. gcc main.o -o main
  3. main.o: main.c
  4. gcc main.c -c -o main.o
  5. clean:
  6. rm main.o main.exe

Scons编译

        如下图所示是一个简易的scons编译行为,可以看到,脚本写的时候只需配置好源文件和目标文件source=main.c target=main,直接执行scons就可以,第二次编译的时候,由于什么都没变化scons不执行任何操作。

        相比于make,清空环境只需要执行scons -c就可以自动清除编译生成的文件,无需像make要指定所有目标。而后再次编译又会重新开始了。

image-20220913103139409

 scons源码如下:

  1. obj = Object('main.c')
  2. Program('main', obj)

总结

        gcc直接操作,每次编译都需要输入所有command,不能自动识别文件哪些有改动,只编译所需的文件,对于大型工程来说,编译时间还是很长的,只编译有修改的文件还是很方便的。

        make解决了gcc的缺点,每次编译只需要执行make all,删除执行make clean就可以,但是写makefile的人需要知晓所有的中间文件,并了解文件的依赖关系。

        scons保留了make的优点,每次编译只需要执行scons,删除执行scons -c就可以。同时写Sconstruct也更为轻松,不需要了解中间文件是什么,也不用专门写一个clean操作。所有的事情交给scons就行。

带.h文件的构建

gcc编译

        多个文件编译的时候,先将2个文件生成object文件,再将2个object文件编译成目标main.exe。

image-20220913105136107

main.c的源码如下: 

  1. #include <stdio.h>
  2. #include "test.h"
  3. int main()
  4. {
  5. printf("hello, world\n");
  6. test_work();
  7. return 0;
  8. }

test.c的源码如下:

  1. #include <stdio.h>
  2. #include "test.h"
  3. void test_work(void)
  4. {
  5. printf(TEST_PRINT_STRING);
  6. }

test.h的源码如下:

  1. #ifndef _TEST_H_
  2. #define _TEST_H_
  3. #define TEST_PRINT_STRING "Test_Origin_0"
  4. void test_work(void);
  5. #endif //_TEST_H_

make编译

        按照流程写好,这里需要注意的是,修改完test.h后,再次编译的时候make只再次生成了main.exe,并没有重新编译test.omain.o,并没有达到我们的目标。

        这是因为我们的makefile没写好,没把test.h依赖关系给写好。

image-20220913105753757

        将makefile修改一下,这时候再次修改test.h文件,make就知道需要重新编译文件了(大型项目通常通过-MMD -MP来生成.h的依赖树)。

        注意,这个问题是我们写makefile经常遇到的问题,这个还存在更换之类的场景下,依赖关系没写好,导致再次编译的时候没将所有改动给编译进去,通常要先make clean再make all,完全丧失了make只编译改动的特点,导致编译效率大大降低。

 image-20220913111616496

Makefile的源码如下: 

  1. all: main.o test.o
  2. gcc main.o test.o -o main
  3. main.o: main.c test.h
  4. gcc main.c -c -o main.o
  5. test.o: test.c test.h
  6. gcc test.c -c -o test.o
  7. clean:
  8. rm main.o test.o main.exe

Scons编译

        scons的脚本依然很简单,配置好objects所需的源文件,在配置好目标,执行scons就可以了。需要注意的是,我们并没有显示的声明test.h的依赖关系,当修改test.h后再次编译,scons就能知道文件间的依赖关系,将整个工程正确的重新编译了,这对于写Sconstruct的人要求大大降低。

image-20220913112536319

 

SConstruct源码如下:

  1. objs = Object('main.c')
  2. objs += Object('test.c')
  3. Program('main', objs)

总结

        在包含.h文件等多种隐示依赖的情况下,scons无需开发人员了解编译的底层原理,只需要将所需编译的主文件配置好,并配置好目标,剩下scons都可以自动搞定,大大节约了工程人员的开发和维护成本。

Scons原理分析

        从上一章的分析可以看出,scons保留了make的所有优点,并简化了脚本编译,同时很好的维护了各个文件的隐示依赖关系,避免大家每次都要make clean,再make all了。

        这一章我们简单分析下Scons是如何工作的。

脚本如何运行

        没时间细看代码,自己也写过一些测试环境之类,大体猜测Scons的运行机制就是将Sconstruct文件用exec函数来执行,这样才能只写部分代码就可以完成编译工作。

        简单搜索了下源码Sconstruct,可以看到_SConstruct_exists函数会去用这个文件。

image-20220913125729673

 之后有用python的exec函数来执行这个文件。

image-20220913130153687

 

如何指导编译

        如果学习过make的语法,其核心语法就是目标和依赖,利用好其基本语法,再借助其强大的工具函数,就可以完成项目的编译管理工作。

        scons和make一样,本质并不会去做gcc的工作,更多是管理工程文件如何依次调用gcc进行编译

        要用scons实现大型项目的管理,也必须理解其底层运行机制,这样才能实现各种复杂的行为。直接学习其源码是可以的,但是太累了,直接看其文档也能看到一些,但是也不是特别清楚,所以这里笔者以自己浅显的理解来分析其行为。

        从上面的说明例子中,简单的c项目编译,只需要指定Object所需的source文件,然后再指定Program所需的objs和target对象,剩下都是scons来完成的。那么我们依次拆分其操作行为。

打印环境信息env.Dump()

        scons所有的配置参数和信息存储在Environment对象中,可以通过Dump方法可以打印当前scons的所有配置参数,而后用python的print方法就可以打印出来了。

        官方手册上也有说明:

image-20220914115119261

  1. env = Environment()
  2. print(env.Dump())

 

        打印出来的信息如下所示,参数有很多,看不懂咋办。

        目前只需要完成嵌入式C开发需要,只要认下面几个关键字:

  • C编译:CCCCCOM

  • ASM编译:ASASCOM

  • 链接:LINKLINKCOM

  1. scons: Reading SConscript files ...
  2. { 'AR': 'ar',
  3. 'ARCOM': '$AR $ARFLAGS $TARGET $SOURCES',
  4. 'ARFLAGS': ['rc'],
  5. 'AS': 'as',
  6. 'ASCOM': '$AS $ASFLAGS -o $TARGET $SOURCES',
  7. 'ASFLAGS': [],
  8. 'ASPPCOM': '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o '
  9. '$TARGET $SOURCES',
  10. 'ASPPFLAGS': '$ASFLAGS',
  11. 'BUILDERS': { 'CopyAs': <SCons.Builder.BuilderBase object at 0x000001F3D9B0C7F0>,
  12. 'CopyTo': <SCons.Builder.BuilderBase object at 0x000001F3D9B0C7C0>,
  13. 'JarFile': <SCons.Builder.BuilderBase object at 0x000001F3D9B0C910>,
  14. 'JavaClassDir': <SCons.Builder.BuilderBase object at 0x000001F3D9B0CC10>,
  15. 'JavaClassFile': <SCons.Builder.BuilderBase object at 0x000001F3D9B0CB50>,
  16. 'JavaFile': <SCons.Builder.CompositeBuilder object at 0x000001F3D9B0CA60>,
  17. 'Library': <SCons.Builder.BuilderBase object at 0x000001F3D9ACAA10>,
  18. 'LoadableModule': <SCons.Builder.BuilderBase object at 0x000001F3D9ACA680>,
  19. 'M4': <SCons.Builder.BuilderBase object at 0x000001F3D9B0C4C0>,
  20. 'Object': <SCons.Builder.CompositeBuilder object at 0x000001F3D9AC9360>,
  21. 'Program': <SCons.Builder.BuilderBase object at 0x000001F3D9AC9900>,
  22. 'ProgramAllAtOnce': <SCons.Builder.BuilderBase object at 0x000001F3D9B0C6D0>,
  23. 'RES': <SCons.Builder.BuilderBase object at 0x000001F3D9A2ECB0>,
  24. 'RMIC': <SCons.Builder.BuilderBase object at 0x000001F3D9A89930>,
  25. 'SharedLibrary': <SCons.Builder.BuilderBase object at 0x000001F3D9ACA290>,
  26. 'SharedObject': <SCons.Builder.CompositeBuilder object at 0x000001F3D9AC95A0>,
  27. 'StaticLibrary': <SCons.Builder.BuilderBase object at 0x000001F3D9ACAA10>,
  28. 'StaticObject': <SCons.Builder.CompositeBuilder object at 0x000001F3D9AC9360>,
  29. 'Substfile': <SCons.Builder.BuilderBase object at 0x000001F3D9AC8FD0>,
  30. 'Tar': <SCons.Builder.BuilderBase object at 0x000001F3D9A8AB60>,
  31. 'Textfile': <SCons.Builder.BuilderBase object at 0x000001F3D9AC8F70>,
  32. 'Zip': <SCons.Builder.BuilderBase object at 0x000001F3D9A8AEC0>},
  33. 'CC': 'gcc',
  34. 'CCCOM': '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES',
  35. 'CCDEPFLAGS': '-MMD -MF ${TARGET}.d',
  36. 'CCFLAGS': [],
  37. 'CCVERSION': '12.1.0',
  38. 'CFILESUFFIX': '.c',
  39. 'CFLAGS': [],
  40. 'CONFIGUREDIR': '#/.sconf_temp',
  41. 'CONFIGURELOG': '#/config.log',
  42. 'COPYSTR': 'Copy file(s): "$SOURCES" to "$TARGETS"',
  43. 'CPPDEFPREFIX': '-D',
  44. 'CPPDEFSUFFIX': '',
  45. 'CPPSUFFIXES': [ '.c',
  46. '.C',
  47. '.cxx',
  48. '.cpp',
  49. '.c++',
  50. '.cc',
  51. '.h',
  52. '.H',
  53. '.hxx',
  54. '.hpp',
  55. '.hh',
  56. '.F',
  57. '.fpp',
  58. '.FPP',
  59. '.m',
  60. '.mm',
  61. '.S',
  62. '.spp',
  63. '.SPP',
  64. '.sx'],
  65. 'CXX': 'g++',
  66. 'CXXCOM': '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM $SOURCES',
  67. 'CXXFILESUFFIX': '.cc',
  68. 'CXXFLAGS': [],
  69. 'CXXVERSION': '12.1.0',
  70. 'DC': 'dmd',
  71. 'DCOM': '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of$TARGET '
  72. '$SOURCES',
  73. 'DDEBUG': [],
  74. 'DDEBUGPREFIX': '-debug=',
  75. 'DDEBUGSUFFIX': '',
  76. 'DFILESUFFIX': '.d',
  77. 'DFLAGPREFIX': '-',
  78. 'DFLAGS': [],
  79. 'DFLAGSUFFIX': '',
  80. 'DINCPREFIX': '-I',
  81. 'DINCSUFFIX': '',
  82. 'DLIB': 'lib',
  83. 'DLIBCOM': '$DLIB $_DLIBFLAGS -c $TARGET $SOURCES $_DLIBFLAGS',
  84. 'DLIBDIRPREFIX': '-L-L',
  85. 'DLIBDIRSUFFIX': '',
  86. 'DLIBFLAGPREFIX': '-',
  87. 'DLIBFLAGSUFFIX': '',
  88. 'DLIBLINKPREFIX': '',
  89. 'DLIBLINKSUFFIX': '.lib',
  90. 'DLINK': '$DC',
  91. 'DLINKCOM': '$DLINK -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS '
  92. '$_DLIBFLAGS',
  93. 'DLINKFLAGS': [],
  94. 'DPATH': ['#/'],
  95. 'DRPATHPREFIX': '-L-rpath=',
  96. 'DRPATHSUFFIX': '',
  97. 'DSUFFIXES': ['.d'],
  98. 'DVERPREFIX': '-version=',
  99. 'DVERSIONS': [],
  100. 'DVERSUFFIX': '',
  101. 'Dir': <SCons.Defaults.Variable_Method_Caller object at 0x000001F3D93C82E0>,
  102. 'Dirs': <SCons.Defaults.Variable_Method_Caller object at 0x000001F3D93C8370>,
  103. 'ENV': { 'COMSPEC': 'C:\\Windows\\system32\\cmd.exe',
  104. 'PATH': 'C:\\Windows\\System32;C:\\msys64\\mingw32\\bin',
  105. 'PATHEXT': '.COM;.EXE;.BAT;.CMD',
  106. 'SystemDrive': 'C:',
  107. 'SystemRoot': 'C:\\Windows',
  108. 'TEMP': 'C:\\Users\\wenbo\\AppData\\Local\\Temp',
  109. 'TMP': 'C:\\Users\\wenbo\\AppData\\Local\\Temp',
  110. 'USERPROFILE': 'C:\\Users\\wenbo'},
  111. 'ESCAPE': <function escape at 0x000001F3D9519B40>,
  112. 'F03': 'gfortran',
  113. 'F03COM': '$F03 -o $TARGET -c $FORTRANCOMMONFLAGS $F03FLAGS $_F03INCFLAGS '
  114. '$_FORTRANMODFLAG $SOURCES',
  115. 'F03FLAGS': [],
  116. 'F03PPCOM': '$F03 -o $TARGET -c $FORTRANCOMMONFLAGS $F03FLAGS $CPPFLAGS '
  117. '$_CPPDEFFLAGS $_F03INCFLAGS $_FORTRANMODFLAG $SOURCES',
  118. 'F08': 'gfortran',
  119. 'F08COM': '$F08 -o $TARGET -c $FORTRANCOMMONFLAGS $F08FLAGS $_F08INCFLAGS '
  120. '$_FORTRANMODFLAG $SOURCES',
  121. 'F08FLAGS': [],
  122. 'F08PPCOM': '$F08 -o $TARGET -c $FORTRANCOMMONFLAGS $F08FLAGS $CPPFLAGS '
  123. '$_CPPDEFFLAGS $_F08INCFLAGS $_FORTRANMODFLAG $SOURCES',
  124. 'F77': 'gfortran',
  125. 'F77COM': '$F77 -o $TARGET -c $FORTRANCOMMONFLAGS $F77FLAGS $_F77INCFLAGS '
  126. '$SOURCES',
  127. 'F77FLAGS': [],
  128. 'F77PPCOM': '$F77 -o $TARGET -c $FORTRANCOMMONFLAGS $F77FLAGS $CPPFLAGS '
  129. '$_CPPDEFFLAGS $_F77INCFLAGS $SOURCES',
  130. 'F90': 'gfortran',
  131. 'F90COM': '$F90 -o $TARGET -c $FORTRANCOMMONFLAGS $F90FLAGS $_F90INCFLAGS '
  132. '$_FORTRANMODFLAG $SOURCES',
  133. 'F90FLAGS': [],
  134. 'F90PPCOM': '$F90 -o $TARGET -c $FORTRANCOMMONFLAGS $F90FLAGS $CPPFLAGS '
  135. '$_CPPDEFFLAGS $_F90INCFLAGS $_FORTRANMODFLAG $SOURCES',
  136. 'F95': 'gfortran',
  137. 'F95COM': '$F95 -o $TARGET -c $FORTRANCOMMONFLAGS $F95FLAGS $_F95INCFLAGS '
  138. '$_FORTRANMODFLAG $SOURCES',
  139. 'F95FLAGS': [],
  140. 'F95PPCOM': '$F95 -o $TARGET -c $FORTRANCOMMONFLAGS $F95FLAGS $CPPFLAGS '
  141. '$_CPPDEFFLAGS $_F95INCFLAGS $_FORTRANMODFLAG $SOURCES',
  142. 'FORTRAN': 'gfortran',
  143. 'FORTRANCOM': '$FORTRAN -o $TARGET -c $FORTRANCOMMONFLAGS $FORTRANFLAGS '
  144. '$_FORTRANINCFLAGS $_FORTRANMODFLAG $SOURCES',
  145. 'FORTRANFLAGS': [],
  146. 'FORTRANMODDIR': '',
  147. 'FORTRANMODDIRPREFIX': '-J',
  148. 'FORTRANMODDIRSUFFIX': '',
  149. 'FORTRANMODPREFIX': '',
  150. 'FORTRANMODSUFFIX': '.mod',
  151. 'FORTRANPPCOM': '$FORTRAN -o $TARGET -c $FORTRANCOMMONFLAGS $FORTRANFLAGS '
  152. '$CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS $_FORTRANMODFLAG '
  153. '$SOURCES',
  154. 'FORTRANSUFFIXES': [ '.f',
  155. '.for',
  156. '.ftn',
  157. '.F',
  158. '.FOR',
  159. '.FTN',
  160. '.fpp',
  161. '.FPP',
  162. '.f77',
  163. '.F77',
  164. '.f90',
  165. '.F90',
  166. '.f95',
  167. '.F95',
  168. '.f03',
  169. '.F03',
  170. '.f08',
  171. '.F08'],
  172. 'FRAMEWORKPATH': [],
  173. 'FRAMEWORKS': [],
  174. 'File': <SCons.Defaults.Variable_Method_Caller object at 0x000001F3D93C83A0>,
  175. 'HOST_ARCH': 'x86_64',
  176. 'HOST_OS': 'win32',
  177. 'IDLSUFFIXES': ['.idl', '.IDL'],
  178. 'IMPLIBNOVERSIONSYMLINKS': True,
  179. 'INCF03PREFIX': '-I',
  180. 'INCF03SUFFIX': '',
  181. 'INCF08PREFIX': '-I',
  182. 'INCF08SUFFIX': '',
  183. 'INCF77PREFIX': '-I',
  184. 'INCF77SUFFIX': '',
  185. 'INCF90PREFIX': '-I',
  186. 'INCF90SUFFIX': '',
  187. 'INCF95PREFIX': '-I',
  188. 'INCF95SUFFIX': '',
  189. 'INCFORTRANPREFIX': '-I',
  190. 'INCFORTRANSUFFIX': '',
  191. 'INCPREFIX': '-I',
  192. 'INCSUFFIX': '',
  193. 'JAR': 'jar',
  194. 'JARCOM': "${TEMPFILE('$_JARCOM','$JARCOMSTR')}",
  195. 'JARFLAGS': ['cf'],
  196. 'JARSUFFIX': '.jar',
  197. 'JAVABOOTCLASSPATH': [],
  198. 'JAVAC': 'javac',
  199. 'JAVACCOM': "${TEMPFILE('$_JAVACCOM','$JAVACCOMSTR')}",
  200. 'JAVACFLAGS': [],
  201. 'JAVACLASSPATH': [],
  202. 'JAVACLASSSUFFIX': '.class',
  203. 'JAVAINCLUDES': [],
  204. 'JAVASOURCEPATH': [],
  205. 'JAVASUFFIX': '.java',
  206. 'LDMODULE': '$SHLINK',
  207. 'LDMODULECOM': <SCons.Action.CommandGeneratorAction object at 0x000001F3D9A2E800>,
  208. 'LDMODULEEMITTER': [ <function lib_emitter at 0x000001F3D93B4AF0>,
  209. <function ldmod_symlink_emitter at 0x000001F3D9AE8940>,
  210. <function shlib_emitter at 0x000001F3D9A5A290>],
  211. 'LDMODULEFLAGS': '$SHLINKFLAGS',
  212. 'LDMODULENAME': '${LDMODULEPREFIX}$_get_ldmodule_stem${_LDMODULESUFFIX}',
  213. 'LDMODULENOVERSIONSYMLINKS': True,
  214. 'LDMODULEPREFIX': '$SHLIBPREFIX',
  215. 'LDMODULESUFFIX': '$SHLIBSUFFIX',
  216. 'LDMODULEVERSION': '$SHLIBVERSION',
  217. 'LDMODULE_NOVERSION_SYMLINK': '$_get_shlib_dir${LDMODULEPREFIX}$_get_ldmodule_stem${LDMODULESUFFIX}',
  218. 'LDMODULE_SONAME_SYMLINK': '$_get_shlib_dir$_LDMODULESONAME',
  219. 'LIBDIRPREFIX': '-L',
  220. 'LIBDIRSUFFIX': '',
  221. 'LIBLINKPREFIX': '-l',
  222. 'LIBLINKSUFFIX': '',
  223. 'LIBPREFIX': 'lib',
  224. 'LIBPREFIXES': ['$LIBPREFIX'],
  225. 'LIBSUFFIX': '.a',
  226. 'LIBSUFFIXES': ['$LIBSUFFIX'],
  227. 'LINESEPARATOR': '\n',
  228. 'LINK': '$SMARTLINK',
  229. 'LINKCOM': '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS '
  230. '$_LIBFLAGS',
  231. 'LINKFLAGS': [],
  232. 'M4': 'm4',
  233. 'M4COM': 'cd ${SOURCE.rsrcdir} && $M4 $M4FLAGS < ${SOURCE.file} > '
  234. '${TARGET.abspath}',
  235. 'M4FLAGS': ['-E'],
  236. 'MAXLINELENGTH': 2048,
  237. 'NINJA_DEPFILE_PARSE_FORMAT': 'gcc',
  238. 'OBJPREFIX': '',
  239. 'OBJSUFFIX': '.o',
  240. 'PLATFORM': 'win32',
  241. 'PROGPREFIX': '',
  242. 'PROGSUFFIX': '.exe',
  243. 'PSPAWN': <function piped_spawn at 0x000001F3D9519990>,
  244. 'RANLIB': 'ranlib',
  245. 'RANLIBCOM': '$RANLIB $RANLIBFLAGS $TARGET',
  246. 'RANLIBFLAGS': [],
  247. 'RC': 'windres',
  248. 'RCCOM': '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} '
  249. '$RCFLAGS -i $SOURCE -o $TARGET',
  250. 'RCFLAGS': [],
  251. 'RCINCFLAGS': '${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, '
  252. 'TARGET, SOURCE, affect_signature=False)}',
  253. 'RCINCPREFIX': '--include-dir ',
  254. 'RCINCSUFFIX': '',
  255. 'RDirs': <SCons.Defaults.Variable_Method_Caller object at 0x000001F3D93C8430>,
  256. 'RMIC': 'rmic',
  257. 'RMICCOM': '$RMIC $RMICFLAGS -d ${TARGET.attributes.java_lookupdir} '
  258. '-classpath ${SOURCE.attributes.java_classdir} '
  259. '${SOURCES.attributes.java_classname}',
  260. 'RMICFLAGS': [],
  261. 'RPATHPREFIX': '-Wl,-rpath=',
  262. 'RPATHSUFFIX': '',
  263. 'SCANNERS': [<SCons.Scanner.ScannerBase object at 0x000001F3D9393C10>],
  264. 'SHCC': '$CC',
  265. 'SHCCCOM': '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES',
  266. 'SHCCFLAGS': ['$CCFLAGS'],
  267. 'SHCFLAGS': ['$CFLAGS'],
  268. 'SHCXX': '$CXX',
  269. 'SHCXXCOM': '$SHCXX -o $TARGET -c $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES',
  270. 'SHCXXFLAGS': ['$CXXFLAGS'],
  271. 'SHDC': '$DC',
  272. 'SHDCOM': '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -fPIC '
  273. '-of$TARGET $SOURCES',
  274. 'SHDLINK': '$DC',
  275. 'SHDLINKCOM': '$DLINK -of$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS '
  276. '$__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS',
  277. 'SHDLINKFLAGS': ['$DLINKFLAGS', '-shared', '-defaultlib=libphobos2.so'],
  278. 'SHELL': 'C:\\Windows\\System32\\cmd.exe',
  279. 'SHF03': '$F03',
  280. 'SHF03COM': '$SHF03 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF03FLAGS '
  281. '$_F03INCFLAGS $_FORTRANMODFLAG $SOURCES',
  282. 'SHF03FLAGS': ['$F03FLAGS'],
  283. 'SHF03PPCOM': '$SHF03 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF03FLAGS '
  284. '$CPPFLAGS $_CPPDEFFLAGS $_F03INCFLAGS $_FORTRANMODFLAG '
  285. '$SOURCES',
  286. 'SHF08': '$F08',
  287. 'SHF08COM': '$SHF08 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF08FLAGS '
  288. '$_F08INCFLAGS $_FORTRANMODFLAG $SOURCES',
  289. 'SHF08FLAGS': ['$F08FLAGS'],
  290. 'SHF08PPCOM': '$SHF08 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF08FLAGS '
  291. '$CPPFLAGS $_CPPDEFFLAGS $_F08INCFLAGS $_FORTRANMODFLAG '
  292. '$SOURCES',
  293. 'SHF77': '$F77',
  294. 'SHF77COM': '$SHF77 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF77FLAGS '
  295. '$_F77INCFLAGS $SOURCES',
  296. 'SHF77FLAGS': ['$F77FLAGS'],
  297. 'SHF77PPCOM': '$SHF77 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF77FLAGS '
  298. '$CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS $SOURCES',
  299. 'SHF90': '$F90',
  300. 'SHF90COM': '$SHF90 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF90FLAGS '
  301. '$_F90INCFLAGS $_FORTRANMODFLAG $SOURCES',
  302. 'SHF90FLAGS': ['$F90FLAGS'],
  303. 'SHF90PPCOM': '$SHF90 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF90FLAGS '
  304. '$CPPFLAGS $_CPPDEFFLAGS $_F90INCFLAGS $_FORTRANMODFLAG '
  305. '$SOURCES',
  306. 'SHF95': '$F95',
  307. 'SHF95COM': '$SHF95 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF95FLAGS '
  308. '$_F95INCFLAGS $_FORTRANMODFLAG $SOURCES',
  309. 'SHF95FLAGS': ['$F95FLAGS'],
  310. 'SHF95PPCOM': '$SHF95 -o $TARGET -c $FORTRANCOMMONFLAGS $SHF95FLAGS '
  311. '$CPPFLAGS $_CPPDEFFLAGS $_F95INCFLAGS $_FORTRANMODFLAG '
  312. '$SOURCES',
  313. 'SHFORTRAN': '$FORTRAN',
  314. 'SHFORTRANCOM': '$SHFORTRAN -o $TARGET -c $FORTRANCOMMONFLAGS '
  315. '$SHFORTRANFLAGS $_FORTRANINCFLAGS $_FORTRANMODFLAG $SOURCES',
  316. 'SHFORTRANFLAGS': ['$FORTRANFLAGS'],
  317. 'SHFORTRANPPCOM': '$SHFORTRAN -o $TARGET -c $FORTRANCOMMONFLAGS '
  318. '$SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS '
  319. '$_FORTRANMODFLAG $SOURCES',
  320. 'SHLIBEMITTER': [ <function lib_emitter at 0x000001F3D93B4AF0>,
  321. <function shlib_symlink_emitter at 0x000001F3D9AE8B80>,
  322. <function shlib_emitter at 0x000001F3D9A5A290>],
  323. 'SHLIBNAME': '${_get_shlib_dir}${SHLIBPREFIX}$_get_shlib_stem${_SHLIBSUFFIX}',
  324. 'SHLIBNOVERSIONSYMLINKS': True,
  325. 'SHLIBPREFIX': '',
  326. 'SHLIBSONAMEFLAGS': '-Wl,-soname=$_SHLIBSONAME',
  327. 'SHLIBSUFFIX': '.dll',
  328. 'SHLIB_NOVERSION_SYMLINK': '${_get_shlib_dir}${SHLIBPREFIX}$_get_shlib_stem${SHLIBSUFFIX}',
  329. 'SHLIB_SONAME_SYMLINK': '${_get_shlib_dir}$_SHLIBSONAME',
  330. 'SHLINK': '$LINK',
  331. 'SHLINKCOM': <SCons.Action.CommandGeneratorAction object at 0x000001F3D9A2E7A0>,
  332. 'SHLINKCOMSTR': <function shlib_generator at 0x000001F3D9A59630>,
  333. 'SHLINKFLAGS': ['$LINKFLAGS', '-shared'],
  334. 'SHOBJPREFIX': '$OBJPREFIX',
  335. 'SHOBJSUFFIX': '.o',
  336. 'SMARTLINK': <function smart_link at 0x000001F3D93B4A60>,
  337. 'SPAWN': <function spawn at 0x000001F3D9519AB0>,
  338. 'STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME': 1,
  339. 'SUBSTFILEPREFIX': '',
  340. 'SUBSTFILESUFFIX': '',
  341. 'TAR': 'tar',
  342. 'TARCOM': '$TAR $TARFLAGS -f $TARGET $SOURCES',
  343. 'TARFLAGS': ['-c'],
  344. 'TARGET_ARCH': None,
  345. 'TARGET_OS': None,
  346. 'TARSUFFIX': '.tar',
  347. 'TEMPFILE': <class 'SCons.Platform.TempFileMunge'>,
  348. 'TEMPFILEARGESCFUNC': <function quote_spaces at 0x000001F3D9252DD0>,
  349. 'TEMPFILEARGJOIN': ' ',
  350. 'TEMPFILEPREFIX': '@',
  351. 'TEXTFILEPREFIX': '',
  352. 'TEXTFILESUFFIX': '.txt',
  353. 'TOOLS': [ 'default',
  354. 'mingw',
  355. 'gcc',
  356. 'g++',
  357. 'gnulink',
  358. 'ar',
  359. 'gas',
  360. 'gfortran',
  361. 'm4',
  362. 'dmd',
  363. 'filesystem',
  364. 'jar',
  365. 'javac',
  366. 'rmic',
  367. 'tar',
  368. 'zip',
  369. 'textfile'],
  370. 'WINDOWSDEFPREFIX': '',
  371. 'WINDOWSDEFSUFFIX': '.def',
  372. 'WIXCANDLE': 'candle.exe',
  373. 'WIXLIGHT': 'light.exe',
  374. 'ZIP': 'zip',
  375. 'ZIPCOM': <SCons.Action.FunctionAction object at 0x000001F3D9A8ACB0>,
  376. 'ZIPCOMPRESSION': 8,
  377. 'ZIPFLAGS': [],
  378. 'ZIPROOT': [],
  379. 'ZIPSUFFIX': '.zip',
  380. '_CCCOMCOM': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS',
  381. '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__, '
  382. 'TARGET, SOURCE)}',
  383. '_CPPINCFLAGS': '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, '
  384. 'TARGET, SOURCE, affect_signature=False)}',
  385. '_DDEBUGFLAGS': '${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)}',
  386. '_DFLAGS': '${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)}',
  387. '_DINCFLAGS': '${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, '
  388. 'TARGET, SOURCE)}',
  389. '_DLIBDIRFLAGS': '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, '
  390. 'RDirs, TARGET, SOURCE)}',
  391. '_DLIBFLAGS': '${_stripixes(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, '
  392. 'LIBPREFIXES, LIBSUFFIXES, __env__)}',
  393. '_DRPATH': '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}',
  394. '_DVERFLAGS': '${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)}',
  395. '_F03INCFLAGS': '${_concat(INCF03PREFIX, F03PATH, INCF03SUFFIX, __env__, '
  396. 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  397. '_F08INCFLAGS': '${_concat(INCF08PREFIX, F08PATH, INCF08SUFFIX, __env__, '
  398. 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  399. '_F77INCFLAGS': '${_concat(INCF77PREFIX, F77PATH, INCF77SUFFIX, __env__, '
  400. 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  401. '_F90INCFLAGS': '${_concat(INCF90PREFIX, F90PATH, INCF90SUFFIX, __env__, '
  402. 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  403. '_F95INCFLAGS': '${_concat(INCF95PREFIX, F95PATH, INCF95SUFFIX, __env__, '
  404. 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  405. '_FORTRANINCFLAGS': '${_concat(INCFORTRANPREFIX, FORTRANPATH, '
  406. 'INCFORTRANSUFFIX, __env__, RDirs, TARGET, SOURCE, '
  407. 'affect_signature=False)}',
  408. '_FORTRANMODFLAG': '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, '
  409. 'FORTRANMODDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
  410. '_JARCOM': '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES',
  411. '_JARFLAGS': <function jarFlags at 0x000001F3D9AB6EF0>,
  412. '_JARMANIFEST': <function jarManifest at 0x000001F3D9AB6E60>,
  413. '_JARSOURCES': <function jarSources at 0x000001F3D9AB5990>,
  414. '_JAVABOOTCLASSPATH': '${_javapathopt("-bootclasspath", '
  415. '"JAVABOOTCLASSPATH")} ',
  416. '_JAVACCOM': '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVACLASSPATH -d '
  417. '${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES',
  418. '_JAVACLASSPATH': '${_javapathopt("-classpath", "JAVACLASSPATH")} ',
  419. '_JAVASOURCEPATH': '${_javapathopt("-sourcepath", "JAVASOURCEPATH", '
  420. '"_JAVASOURCEPATHDEFAULT")} ',
  421. '_JAVASOURCEPATHDEFAULT': '${TARGET.attributes.java_sourcedir}',
  422. '_LDMODULESONAME': <function _ldmodule_soname at 0x000001F3D9AE9000>,
  423. '_LDMODULESOVERSION': <function _ldmodule_soversion at 0x000001F3D9AE8F70>,
  424. '_LDMODULESUFFIX': '${LDMODULESUFFIX}${_LDMODULEVERSION}',
  425. '_LDMODULEVERSION': <function _LDMODULEVERSION at 0x000001F3D9AE9090>,
  426. '_LDMODULEVERSIONFLAGS': '$LDMODULEVERSIONFLAGS -Wl,-soname=$_LDMODULESONAME',
  427. '_LIBDIRFLAGS': '${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, '
  428. 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  429. '_LIBFLAGS': '${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, '
  430. 'LIBSUFFIXES, __env__)}',
  431. '_RPATH': '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}',
  432. '_SHDLIBVERSIONFLAGS': '$SHDLIBVERSIONFLAGS -L-soname=$_SHLIBSONAME',
  433. '_SHLIBSONAME': <function _soname at 0x000001F3D9AE8CA0>,
  434. '_SHLIBSOVERSION': <function _soversion at 0x000001F3D9AE8C10>,
  435. '_SHLIBSUFFIX': '$SHLIBSUFFIX',
  436. '_SHLIBVERSION': "${SHLIBVERSION and '.'+SHLIBVERSION or ''}",
  437. '_SHLIBVERSIONFLAGS': '$SHLIBVERSIONFLAGS -Wl,-soname=$_SHLIBSONAME',
  438. '__DSHLIBVERSIONFLAGS': '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
  439. '__LDMODULEVERSIONFLAGS': '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
  440. '__SHLIBVERSIONFLAGS': '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
  441. '__lib_either_version_flag': <function __lib_either_version_flag at 0x000001F3D93B7250>,
  442. '__libversionflags': <function __libversionflags at 0x000001F3D93B6F80>,
  443. '_concat': <function _concat at 0x000001F3D93B6CB0>,
  444. '_defines': <function _defines at 0x000001F3D93B6EF0>,
  445. '_get_ldmodule_stem': <function _get_ldmodule_stem at 0x000001F3D9AE8EE0>,
  446. '_get_shlib_dir': <function _get_shlib_dir at 0x000001F3D9AE8DC0>,
  447. '_get_shlib_stem': <function _get_shlib_stem at 0x000001F3D9AE8D30>,
  448. '_javapathopt': <class 'SCons.Tool.javac.pathopt'>,
  449. '_stripixes': <function _stripixes at 0x000001F3D93B6DD0>}
  450. scons: done reading SConscript files.
  451. scons: Building targets ...
  452. scons: `.' is up to date.
  453. scons: done building targets.

C文件编译行为分析

        首先我们调整下编译行为,注释Program,只执行Object,可以看到其最终执行了gcc -o main.o -c main.c,那为什么其知道要使用这个命令呢?如果我需要加一些编译参数,应该如何配置呢?如果要进行嵌入式开发,需要替换gcc为aram-xx-gcc如何处理?

image-20220913212755986

         从上文可知,scons是通过CCCOM来指导c文件编译的。从官网上也可以看出是通过这个来完成对c的源文件编译,生成object文件。

image-20220914132041877

         通过dump可知,默认配置下,各个参数如下:

  • TARGET:就是目标文件
  • SOURCES:就是源文件列表
  • CFLAGS:通用C配置参数
  • CCFLAGS:通用C和C++公用的配置参数,因为scons支持多个语言,配置了这个参数,其同时会在C++编译时使用。详细可以参考:CXXCOM
  • _CCCOMCOM: 更多参数配置,如-D或者-I等配置。
    • CPPFLAGS:用于预处理相关的配置,既可以用于C编译,同时也被用于ASM编译。
    • _CPPDEFFLAGS:用于-D的预编译配置。
    • _CPPINCFLAGS:用于-I的include路径配置。
       
  1. {
  2. 'CC': 'gcc',
  3. 'CCCOM': '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES',
  4. 'CCFLAGS': [],
  5. 'CFLAGS': [],
  6. '_CCCOMCOM': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS',
  7. 'CPPDEFPREFIX': '-D',
  8. 'CPPDEFSUFFIX': '',
  9. '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__, '
  10. 'TARGET, SOURCE)}',
  11. 'INCPREFIX': '-I',
  12. 'INCSUFFIX': '',
  13. '_CPPINCFLAGS': '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, '
  14. 'TARGET, SOURCE, affect_signature=False)}',
  15. }

        其实熟悉GCC的基本已经看明白了,其实把gcc编译object的参数全部配置好了,需要的话直接改env对应的参数即可。

        在示例中,obj = Object('main.c')中SOURCES = [main.c],TARGET = main.o,其他参数由于都没开启,所以没显示。最终就是我们看到的gcc操作。

gcc -o main.o -c main.c
obj = Object('main.c')

        假设调整CCFLAGS,加入-g参数,编译结果如下图所示,可以看出确实是跟着变的,之后我们只要对应改相关的参数,就可以做到修改gcc的目的。

image-20220914134548062

 

ASM文件编译行为分析

        在PC环境下,基本很少写ASM相关的程序,而在嵌入式环境下,不管是startup文件还是一些特殊用途的行为,都需要使用ASM语句进行操作。

        类似于C文件的编译过程,由于PC环境所需的汇编指令各不相同,在嵌入式系统下针对对应的芯片,也有不同汇编指令,本节只对相关配置进行说明。

        从上文可知,scons是通过ASCOM来指导asm文件编译的。从官网上也可以看出是通过这个来完成对c的源文件编译,生成object文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gKSS5iUs-1663252258508)(C:/Users/wenbo/AppData/Roaming/Typora/typora-user-images/image-20220915091107811.png)]

通过dump可知,默认配置下,各个参数如下:

  • TARGET:就是目标文件
  • SOURCES:就是源文件列表
  • ASFLAGS:通用ASM配置参数
  1. {
  2. 'AS': 'as',
  3. 'ASCOM': '$AS $ASFLAGS -o $TARGET $SOURCES',
  4. 'ASFLAGS': [],
  5. }

        和gcc类似,实际是使用as来对ASM程序进行编译,生成object文件。

Link编译行为分析

        在完成Object的文件编译后,生成了一个或多个的Object文件。编译的最后一步是将这些Object文件Link为Program程序。

        我们保留生成的Object,只执行Program,

        首先我们调整下编译行为,注释Program,只执行Object,可以看到其最终执行了gcc -o main.exe main.o,那为什么其知道要使用这个命令呢?如果我需要加一些编译参数,应该如何配置呢?如果要进行嵌入式开发,需要替换gcc为aram-xx-ld如何处理?

image-20220915092157352

         从上文可知,scons是通过LINKCOM来指导LINK的。从官网上也可以看出是通过这个来完成对Object文件Link流程的。

image-20220915092318063

 

通过dump可知,默认配置下,各个参数如下,由于LINK实际环境使用的程序各不一样,所以实际是一个python对象:

  • TARGET:就是目标文件
  • SOURCES:就是源文件列表
  • LINKFLAGS:通用ld配置参数
  • _LIBDIRFLAGS:用于-L的lib路径配置,LIBPATH为具体路径
  • _LIBFLAGS: 用于-l的lib文件配置,LIBS为具体lib名称。
     
  1. {
  2. 'LINK': '$SMARTLINK',
  3. 'LINKCOM': '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS '
  4. '$_LIBFLAGS',
  5. 'LINKFLAGS': [],
  6. 'LIBDIRPREFIX': '-L',
  7. 'LIBDIRSUFFIX': '',
  8. '_LIBDIRFLAGS': '${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, '
  9. 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  10. 'LIBLINKPREFIX': '-l',
  11. 'LIBLINKSUFFIX': '',
  12. '_LIBFLAGS': '${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, '
  13. 'LIBSUFFIXES, __env__)}',
  14. }

        和GCC一样,Program最终调用的就是这个配置。

        假设调整LINKFLAGS,加入-g参数,编译结果如下图所示,可以看出确实是跟着变的,之后我们只要对应改相关的参数,就可以做到修改link的目的。

image-20220915093322494

嵌入式开发和Scons模板

        默认情况下,c编译是根据具体编译环境来的,scons会自己选定gcc程序、asm程序和Link程序,但是在嵌入式开发时,需要指定交叉编译器,按照之前的所描述的,其实大家已经清楚了,只需要调整相应的配置参数即可。

        此外嵌入式开发也有一些特殊的配置,这都需要我们理解并调整配置参数才行。

        如下所示,每行都有注释,下面对一些关键参数/函数进行说明:

  • get_path_files:工具函数,获取路径下所有特定后缀的文件,当然可以用其他方式实现(实现这个函数主要为了写path的时候方便)
  • GCC_ARM_PATH:交叉工具链路径,scons直接改工作路径不怎么会,直接指定路径
  • PLF:编译平台,默认使用PC编译,当然嵌入式开发可以选'arm',之后会自动去配置相关参数
  • PREFIX:嵌入式开发需要,交叉工具链前缀
  • SPEC_LD_FLAGS:arm交叉工具链开发的时候,LD使用有一些特殊的要求,scons原生的参数不怎么好用,需要在_LIBFLAGS参数尾巴拼接上Map信息,其他工具链有特殊要求也可以根据需要调整
     

 

  1. import os
  2. def get_path_files(dirs, file_ext):
  3. path_files = []
  4. # print('dir: ' + str(dirs))
  5. for dir in dirs:
  6. # print('dir: ' + dir)
  7. path_files.append(Glob(dir + '/' + file_ext))
  8. return path_files
  9. GCC_ARM_PATH = 'D:/env/gcc-arm-none-eabi-4_8-2014q3-20140805-win32'
  10. #PLF = 'arm'
  11. PLF = ''
  12. # toolchains
  13. if PLF == 'arm':
  14. PREFIX = GCC_ARM_PATH + '/bin/arm-none-eabi-'
  15. else:
  16. PREFIX = ''
  17. CC = PREFIX + 'gcc'
  18. AS = PREFIX + 'as'
  19. AR = PREFIX + 'ar'
  20. CXX = PREFIX + 'g++'
  21. LINK = PREFIX + 'ld'
  22. SIZE = PREFIX + 'size'
  23. OBJDUMP = PREFIX + 'objdump'
  24. OBJCPY = PREFIX + 'objcopy'
  25. TARGET_PATH = 'build/'
  26. TARGET_NAME = 'main'
  27. TARGET_WITHOUT_SUFFIX = TARGET_PATH + TARGET_NAME
  28. ###################################################################################
  29. # C source dirs config
  30. C_DIRS = []
  31. #C_DIRS.append('src')
  32. # C source files config
  33. C_FILES = []
  34. #C_FILES.append('main.c')
  35. # Create c sources list
  36. C_SRC_LIST = get_path_files(C_DIRS, '*.c') + C_FILES
  37. ###################################################################################
  38. # ASM source dirs config
  39. AS_DIRS = []
  40. #AS_DIRS.append('src')
  41. # ASM source files config
  42. AS_FILES = []
  43. #AS_FILES.append('startup.s')
  44. AS_SRC_LIST = get_path_files(AS_DIRS, '*.s') + AS_FILES
  45. ###################################################################################
  46. # -I, Include path config
  47. CPP_PATH = []
  48. #CPP_PATH.append('inc')
  49. # -D, Preprocess Define
  50. CPP_DEFINES = []
  51. #CPP_DEFINES.append('CFG_TEST')
  52. # C generate define
  53. C_FLAGS = []
  54. C_FLAGS.append('-O1')
  55. C_FLAGS.append('-g')
  56. C_FLAGS.append('-std=c99')
  57. # C and C++ generate define
  58. CC_FLAGS = []
  59. CC_FLAGS.append('-Wall')
  60. # ASM generate define
  61. AS_FLAGS = []
  62. AS_FLAGS.append('-g')
  63. # Link Config
  64. LINK_FLAGS = []
  65. #LINK_FLAGS.append('-Wl,–gc-sections')
  66. # lib path.
  67. LIB_PATH = []
  68. #LIB_PATH.append('lib')
  69. # .lib, .a file
  70. LIBS_FILES = []
  71. #LIBS_FILES.append('test')
  72. # spec ld flag. Arm spec.
  73. SPEC_LD_FLAGS = []
  74. if PLF == 'arm':
  75. SPEC_LD_FLAGS.append('-Map')
  76. SPEC_LD_FLAGS.append(TARGET_WITHOUT_SUFFIX + '.map')
  77. SPEC_LD_FLAGS.append('-T' + 'src/map_ram.txt')
  78. env = Environment()
  79. ###################################################################################
  80. # Step0: toolchains setting.
  81. if PLF == 'arm':
  82. env['CC'] = CC
  83. env['AS'] = AS
  84. env['AR'] = AR
  85. env['CXX'] = CXX
  86. env['LINK'] = LINK
  87. env['OBJSUFFIX'] = '.o'
  88. env['LIBPREFIX'] = 'lib'
  89. env['LIBSUFFIX'] = '.a'
  90. env['PROGSUFFIX'] = '.elf'
  91. ###################################################################################
  92. # Step1: C compile setting. use <print(env.Dump())> for details.
  93. # 'CCCOM': '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
  94. # Step1.0: General options, like: optim/debug setting. $CFLAGS.
  95. env.Append(CFLAGS=C_FLAGS)
  96. # Step1.1: General options, other setting. $CCFLAGS.
  97. env.Append(CCFLAGS=CC_FLAGS)
  98. # Step1.2: -D, -I, setting. $_CCCOMCOM
  99. # '_CCCOMCOM': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS'
  100. # StepX.2.0: CPPFLAGS setting. --- do nothing.
  101. # StepX.2.1: -D setting.
  102. # 'CPPDEFPREFIX': '-D'
  103. # '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__, '
  104. # 'TARGET, SOURCE)}',
  105. env.Append(CPPDEFINES=CPP_DEFINES)
  106. # Step1.2.2: -I setting.
  107. # 'INCPREFIX': '-I'
  108. # '_CPPINCFLAGS': '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, '
  109. # 'TARGET, SOURCE, affect_signature=False)}',
  110. env.Append(CPPPATH=CPP_PATH)
  111. ###################################################################################
  112. # Step2: ASM compile setting. use <print(env.Dump())> for details.
  113. # 'ASCOM': '$AS $ASFLAGS -o $TARGET $SOURCES'
  114. # Step2.0: General options. $ASFLAGS.
  115. env.Append(ASFLAGS=AS_FLAGS)
  116. ###################################################################################
  117. # Step3: LINK setting. use <print(env.Dump())> for details.
  118. # 'LINKCOM': '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS '
  119. # '$_LIBFLAGS',
  120. # Step3.0: General options. $LINKFLAGS.
  121. env.Append(LINKFLAGS=LINK_FLAGS)
  122. # Step3.1: Link path setting. $_LIBDIRFLAGS.
  123. # '_LIBDIRFLAGS': '${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, '
  124. # 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  125. env.Append(LIBPATH=LIB_PATH)
  126. # Step3.2: libs setting, like *.a, *.lib. $_LIBFLAGS.
  127. # '_LIBFLAGS': '${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, '
  128. # 'LIBSUFFIXES, __env__)}',
  129. env.Append(LIBS=LIBS_FILES)
  130. # Step3.3: Add some spec params. must append at end.
  131. env.Append(_LIBFLAGS=SPEC_LD_FLAGS)
  132. ###################################################################################
  133. # Step4: Compile Object files, use:
  134. # 1. <$CCCOM>: For c code compile
  135. # 2. <$ASCOM>: For asm code compile
  136. c_objs = env.Object(C_SRC_LIST)
  137. as_objs = env.Object(AS_SRC_LIST)
  138. ###################################################################################
  139. # Step5: Compile target <.elf>, use <$LINKCOM>.
  140. target = env.Program(target = TARGET_WITHOUT_SUFFIX, source=[c_objs, as_objs])
  141. # Other compile target.
  142. env.Command(TARGET_WITHOUT_SUFFIX + '.bin', target, OBJCPY + ' -v -O binary $SOURCE $TARGET')
  143. env.Command(TARGET_WITHOUT_SUFFIX + '.lst', target, OBJDUMP + ' --source --all-headers --demangle --line-numbers --wide $SOURCE > $TARGET')
  144. env.Command(TARGET_WITHOUT_SUFFIX + '.size', target, SIZE + ' --format=berkeley $SOURCE')
  145. # Dump() env params, if need.
  146. #print(env.Dump())

模板使用示例

        下面举一个例子,还是以PC举例,嵌入式开发自己根据需要配置即可。

        有如下的一个多文件结构的C代码,目前要用scons来编译,在根目录下写SConstruct配置文件。

image-20220915220449757

         最终的SConstruct配置如下:

  1. import os
  2. def get_path_files(dirs, file_ext):
  3. path_files = []
  4. # print('dir: ' + str(dirs))
  5. for dir in dirs:
  6. # print('dir: ' + dir)
  7. path_files.append(Glob(dir + '/' + file_ext))
  8. return path_files
  9. GCC_ARM_PATH = 'D:/env/gcc-arm-none-eabi-4_8-2014q3-20140805-win32'
  10. #PLF = 'arm'
  11. PLF = ''
  12. # toolchains
  13. if PLF == 'arm':
  14. PREFIX = GCC_ARM_PATH + '/bin/arm-none-eabi-'
  15. else:
  16. PREFIX = ''
  17. CC = PREFIX + 'gcc'
  18. AS = PREFIX + 'as'
  19. AR = PREFIX + 'ar'
  20. CXX = PREFIX + 'g++'
  21. LINK = PREFIX + 'ld'
  22. SIZE = PREFIX + 'size'
  23. OBJDUMP = PREFIX + 'objdump'
  24. OBJCPY = PREFIX + 'objcopy'
  25. TARGET_PATH = 'build/'
  26. TARGET_NAME = 'main'
  27. TARGET_WITHOUT_SUFFIX = TARGET_PATH + TARGET_NAME
  28. ###################################################################################
  29. # C source dirs config
  30. C_DIRS = []
  31. C_DIRS.append('app\driver\src')
  32. C_DIRS.append('module1\src')
  33. C_DIRS.append('module2\src')
  34. # C source files config
  35. C_FILES = []
  36. C_FILES.append('app\main.c')
  37. # Create c sources list
  38. C_SRC_LIST = get_path_files(C_DIRS, '*.c') + C_FILES
  39. ###################################################################################
  40. # ASM source dirs config
  41. AS_DIRS = []
  42. #AS_DIRS.append('src')
  43. # ASM source files config
  44. AS_FILES = []
  45. #AS_FILES.append('startup.s')
  46. AS_SRC_LIST = get_path_files(AS_DIRS, '*.s') + AS_FILES
  47. ###################################################################################
  48. # -I, Include path config
  49. CPP_PATH = []
  50. CPP_PATH.append('app\driver\inc')
  51. CPP_PATH.append('module1\inc')
  52. CPP_PATH.append('module2\inc')
  53. # -D, Preprocess Define
  54. CPP_DEFINES = []
  55. #CPP_DEFINES.append('CFG_TEST')
  56. # C generate define
  57. C_FLAGS = []
  58. C_FLAGS.append('-O1')
  59. C_FLAGS.append('-g')
  60. C_FLAGS.append('-std=c99')
  61. # C and C++ generate define
  62. CC_FLAGS = []
  63. CC_FLAGS.append('-Wall')
  64. # ASM generate define
  65. AS_FLAGS = []
  66. AS_FLAGS.append('-g')
  67. # Link Config
  68. LINK_FLAGS = []
  69. #LINK_FLAGS.append('-Wl,–gc-sections')
  70. # lib path.
  71. LIB_PATH = []
  72. #LIB_PATH.append('lib')
  73. # .lib, .a file
  74. LIBS_FILES = []
  75. #LIBS_FILES.append('test')
  76. # spec ld flag. Arm spec.
  77. SPEC_LD_FLAGS = []
  78. if PLF == 'arm':
  79. SPEC_LD_FLAGS.append('-Map')
  80. SPEC_LD_FLAGS.append(TARGET_WITHOUT_SUFFIX + '.map')
  81. SPEC_LD_FLAGS.append('-T' + 'src/map_ram.txt')
  82. env = Environment()
  83. ###################################################################################
  84. # Step0: toolchains setting.
  85. if PLF == 'arm':
  86. env['CC'] = CC
  87. env['AS'] = AS
  88. env['AR'] = AR
  89. env['CXX'] = CXX
  90. env['LINK'] = LINK
  91. env['OBJSUFFIX'] = '.o'
  92. env['LIBPREFIX'] = 'lib'
  93. env['LIBSUFFIX'] = '.a'
  94. env['PROGSUFFIX'] = '.elf'
  95. ###################################################################################
  96. # Step1: C compile setting. use <print(env.Dump())> for details.
  97. # 'CCCOM': '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
  98. # Step1.0: General options, like: optim/debug setting. $CFLAGS.
  99. env.Append(CFLAGS=C_FLAGS)
  100. # Step1.1: General options, other setting. $CCFLAGS.
  101. env.Append(CCFLAGS=CC_FLAGS)
  102. # Step1.2: -D, -I, setting. $_CCCOMCOM
  103. # '_CCCOMCOM': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS'
  104. # StepX.2.0: CPPFLAGS setting. --- do nothing.
  105. # StepX.2.1: -D setting.
  106. # 'CPPDEFPREFIX': '-D'
  107. # '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__, '
  108. # 'TARGET, SOURCE)}',
  109. env.Append(CPPDEFINES=CPP_DEFINES)
  110. # Step1.2.2: -I setting.
  111. # 'INCPREFIX': '-I'
  112. # '_CPPINCFLAGS': '${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, '
  113. # 'TARGET, SOURCE, affect_signature=False)}',
  114. env.Append(CPPPATH=CPP_PATH)
  115. ###################################################################################
  116. # Step2: ASM compile setting. use <print(env.Dump())> for details.
  117. # 'ASCOM': '$AS $ASFLAGS -o $TARGET $SOURCES'
  118. # Step2.0: General options. $ASFLAGS.
  119. env.Append(ASFLAGS=AS_FLAGS)
  120. ###################################################################################
  121. # Step3: LINK setting. use <print(env.Dump())> for details.
  122. # 'LINKCOM': '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS '
  123. # '$_LIBFLAGS',
  124. # Step3.0: General options. $LINKFLAGS.
  125. env.Append(LINKFLAGS=LINK_FLAGS)
  126. # Step3.1: Link path setting. $_LIBDIRFLAGS.
  127. # '_LIBDIRFLAGS': '${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, '
  128. # 'RDirs, TARGET, SOURCE, affect_signature=False)}',
  129. env.Append(LIBPATH=LIB_PATH)
  130. # Step3.2: libs setting, like *.a, *.lib. $_LIBFLAGS.
  131. # '_LIBFLAGS': '${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, '
  132. # 'LIBSUFFIXES, __env__)}',
  133. env.Append(LIBS=LIBS_FILES)
  134. # Step3.3: Add some spec params. must append at end.
  135. env.Append(_LIBFLAGS=SPEC_LD_FLAGS)
  136. ###################################################################################
  137. # Step4: Compile Object files, use:
  138. # 1. <$CCCOM>: For c code compile
  139. # 2. <$ASCOM>: For asm code compile
  140. c_objs = env.Object(C_SRC_LIST)
  141. as_objs = env.Object(AS_SRC_LIST)
  142. ###################################################################################
  143. # Step5: Compile target <.elf>, use <$LINKCOM>.
  144. target = env.Program(target = TARGET_WITHOUT_SUFFIX, source=[c_objs, as_objs])
  145. # Other compile target.
  146. env.Command(TARGET_WITHOUT_SUFFIX + '.bin', target, OBJCPY + ' -v -O binary $SOURCE $TARGET')
  147. env.Command(TARGET_WITHOUT_SUFFIX + '.lst', target, OBJDUMP + ' --source --all-headers --demangle --line-numbers --wide $SOURCE > $TARGET')
  148. env.Command(TARGET_WITHOUT_SUFFIX + '.size', target, SIZE + ' --format=berkeley $SOURCE')
  149. # Dump() env params, if need.
  150. #print(env.Dump())

执行scons操作,可以看到相关参数的编译过程,最后也会生成bin、lst以及code size信息。

  1. D:\test\sample_4>scons
  2. scons: Reading SConscript files ...
  3. scons: done reading SConscript files.
  4. scons: Building targets ...
  5. gcc -o app\driver\src\driver1.1.o -c -O1 -g -std=c99 -Wall -Iapp\driver\inc -Imodule1\inc -Imodule2\inc app\driver\src\driver1.1.c
  6. gcc -o app\driver\src\driver2.2.o -c -O1 -g -std=c99 -Wall -Iapp\driver\inc -Imodule1\inc -Imodule2\inc app\driver\src\driver2.2.c
  7. gcc -o app\main.o -c -O1 -g -std=c99 -Wall -Iapp\driver\inc -Imodule1\inc -Imodule2\inc app\main.c
  8. gcc -o module1\src\module1.1.o -c -O1 -g -std=c99 -Wall -Iapp\driver\inc -Imodule1\inc -Imodule2\inc module1\src\module1.1.c
  9. gcc -o module1\src\module1.2.o -c -O1 -g -std=c99 -Wall -Iapp\driver\inc -Imodule1\inc -Imodule2\inc module1\src\module1.2.c
  10. gcc -o module2\src\module2.1.o -c -O1 -g -std=c99 -Wall -Iapp\driver\inc -Imodule1\inc -Imodule2\inc module2\src\module2.1.c
  11. gcc -o module2\src\module2.2.o -c -O1 -g -std=c99 -Wall -Iapp\driver\inc -Imodule1\inc -Imodule2\inc module2\src\module2.2.c
  12. gcc -o build\main.exe app\driver\src\driver1.1.o app\driver\src\driver2.2.o module1\src\module1.1.o module1\src\module1.2.o module2\src\module2.1.o module2\src\module2.2.o app\main.o
  13. objcopy -v -O binary build\main.exe build\main.bin
  14. copy from `build\main.exe' [pei-i386] to `build\main.bin' [binary]
  15. objdump --source --all-headers --demangle --line-numbers --wide build\main.exe > build\main.lst
  16. size --format=berkeley build\main.exe
  17. text data bss dec hex filename
  18. 39620 2944 2676 45240 b0b8 build\main.exe
  19. scons: done building targets.
  20. D:\test\sample_4>scons -c
  21. scons: Reading SConscript files ...
  22. scons: done reading SConscript files.
  23. scons: Cleaning targets ...
  24. Removed app\driver\src\driver1.1.o
  25. Removed app\driver\src\driver2.2.o
  26. Removed app\main.o
  27. Removed module1\src\module1.1.o
  28. Removed module1\src\module1.2.o
  29. Removed module2\src\module2.1.o
  30. Removed module2\src\module2.2.o
  31. Removed build\main.exe
  32. Removed build\main.bin
  33. Removed build\main.lst
  34. scons: done cleaning targets.

转自:Scons环境搭建和编译原理概述及嵌入式开发常用模板_CoderBob的博客-CSDN博客_scons源码解析

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/168831
推荐阅读
  

闽ICP备14008679号