最近在基于目前已有的rt-thread构建框架,改造设计一套新的软件架构及构建,基于RA系列的BSP,使用scons的构建方式在windows的env环境下推进。
在这期间,参考了社区帖子 scons如何指定输出目录 , 基本能够实现将编译输出的obj文件导到编译输出目录,而不是在原来的源码目录。
但是,我发现了一个个例,以 bsp\renesas\ra2l1-cpk 为例,在它的原生的rt-thread env构建流程中也是存在这样的问题。
见下面执行scons的编译出:
CC build\kernel\src\kservice.o
CC build\kernel\src\mem.o
CC build\kernel\src\mempool.o
CC build\kernel\src\object.o
CC build\kernel\src\scheduler.o
CC build\kernel\src\thread.o
CC build\kernel\src\timer.o
CC build\ra_gen\common_data.o
CC build\ra_gen\hal_data.o
CC build\ra_gen\main.o
CC build\ra_gen\pin_data.o
CC build\ra_gen\vector_data.o
CC build\src\hal_entry.o
CC ra\fsp\src\bsp\cmsis\Device\RENESAS\Source\startup.o
CC ra\fsp\src\bsp\cmsis\Device\RENESAS\Source\system.o
CC ra\fsp\src\bsp\mcu\all\bsp_clocks.o
CC ra\fsp\src\bsp\mcu\all\bsp_common.o
CC ra\fsp\src\bsp\mcu\all\bsp_delay.o
CC ra\fsp\src\bsp\mcu\all\bsp_group_irq.o
CC ra\fsp\src\bsp\mcu\all\bsp_guard.o
CC ra\fsp\src\bsp\mcu\all\bsp_io.o
CC ra\fsp\src\bsp\mcu\all\bsp_irq.o
CC ra\fsp\src\bsp\mcu\all\bsp_register_protection.o
CC ra\fsp\src\bsp\mcu\all\bsp_rom_registers.o
CC ra\fsp\src\bsp\mcu\all\bsp_sbrk.o
CC ra\fsp\src\bsp\mcu\all\bsp_security.o
CC ra\fsp\src\r_icu\r_icu.o
CC ra\fsp\src\r_ioport\r_ioport.o
CC ra\fsp\src\r_sci_uart\r_sci_uart.o
CC D:\llc\git_repos\rt-thread-share\rt-thread-share\rtt-5.0\rt-thread\bsp\renesas\libraries\HAL_Drivers\drv_common.o
CC D:\llc\git_repos\rt-thread-share\rt-thread-share\rtt-5.0\rt-thread\bsp\renesas\libraries\HAL_Drivers\drv_gpio.o
CC D:\llc\git_repos\rt-thread-share\rt-thread-share\rtt-5.0\rt-thread\bsp\renesas\libraries\HAL_Drivers\drv_usart_v2.o
D:\llc\git_repos\rt-thread-share\rt-thread-share\rtt-5.0\rt-thread\bsp\renesas\libraries\HAL_Drivers\drv_usart_v2.c: In function 'ra_uart_transmit':
D:\llc\git_repos\rt-thread-share\rt-thread-share\rtt-5.0\rt-thread\bsp\renesas\libraries\HAL_Drivers\drv_usart_v2.c:260:21: warning: variable 'uart' set but not used [-Wunused-but-set-variable]
260 | struct ra_uart *uart;
| ^~~~
LINK rtthread.elf
arm-none-eabi-objcopy -O ihex rtthread.elf rtthread.hex
arm-none-eabi-size rtthread.elf
text data bss dec hex filename
87364 1592 4728 93684 16df4 rtthread.elf
scons: done building targets.
注意看 ra目录下的几个obj文件,比如 (CC ra\fsp\src\bsp\mcu\all\bsp_clocks.o),输出都是在源码目录,而其他的与ra同级的目录,比如ra_gen都是在build目录往下存放(rt-thread的build tool默认将obj文件放在build目录)。
起初,我以为是ra目录下的SConscript文件和ra_gen目录下的SConscript文件有些区别,但我看了内容了,实在没想明白,为啥ra目录下的源码编译输出的obj文件就在源码目录,而ra_gen目录的源码却不会这样。
bsp顶级目录的SConscript文件内容:
# for module compiling
import os
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = []
CPPPATH = []
list = os.listdir(cwd)
if rtconfig.PLATFORM in ['iccarm']:
print("\nThe current project does not support IAR build\n")
Return('group')
elif rtconfig.PLATFORM in ['gcc', 'armclang']:
if GetOption('target') != 'mdk5':
CPPPATH = [cwd + './src']
src = Glob('./src/*.c')
group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
group = group + SConscript(os.path.join(d, 'SConscript'))
Return('group')
ra目录下的SConscript文件内容:
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = []
group = []
CPPPATH = []
if rtconfig.PLATFORM in ['iccarm']:
print("\nThe current project does not support IAR build\n")
Return('group')
elif rtconfig.PLATFORM in ['gcc', 'armclang']:
if GetOption('target') != 'mdk5':
src += Glob(cwd + '/fsp/src/bsp/mcu/all/*.c')
src += [cwd + '/fsp/src/bsp/cmsis/Device/RENESAS/Source/system.c']
src += [cwd + '/fsp/src/bsp/cmsis/Device/RENESAS/Source/startup.c']
src += Glob(cwd + '/fsp/src/r_*/*.c')
CPPPATH = [ cwd + '/arm/CMSIS_5/CMSIS/Core/Include',
cwd + '/fsp/inc',
cwd + '/fsp/inc/api',
cwd + '/fsp/inc/instances',]
group = DefineGroup('ra', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
ra_gen目录下的SConscript文件内容:
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = []
group = []
CPPPATH = []
if rtconfig.PLATFORM in ['iccarm']:
print("\nThe current project does not support IAR build\n")
Return('group')
elif rtconfig.PLATFORM in ['gcc', 'armclang']:
if GetOption('target') != 'mdk5':
src = Glob('*.c')
CPPPATH = [cwd, ]
group = DefineGroup('ra_gen', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
ra目录的编译输出存放在源码目录:

ra_gen目录的编译输出存放在build目录下:

bsp的目录结构大致长这样:

对此,我有几个疑问:
- 为啥ra目录和ra_gen目录的会有这个差别?而且我发现,瑞萨这几款bsp都有类似的问题
- 到底是顶级的SConscript文件决定了上面的现象还是ra目录下的SConscript文件导致的?
- 要想把ra目录下的生成文件也像ra_gen目录下的编译一样,存放在build目录下,要怎么修改?
以上问题,如果有大佬了解的,还请指导指导,多谢多谢。
这个我试过,大多国产mcu的bsp确实可以这么设置,但是题主的那个bsp目录情况不一样。找不到发生这种现象的原因
从编译上来看,确实不影响正常编译,但是从编译构建的管理上,把obj文件输出到yuanm目录,的确不是一个明智选择;obj文件是中间文件,就应该放在独立的输出目录,这样当需要执行清除中间文件的时候,操作将会变成很容易。就拿典型的KEIL编译环境来说,都会设置输出在Objects目录下,这个是符合预期的。我上面纠结的是,我调试的bsp下,同级目录的ra好ra_gen目录类似,但他们的输出表现却不太一样,一个符合预期(ra_gen),而另一个却不符合预期(ra)。不过大佬们的回复讨论,让我有点思路了,大概是ra目录下的SConscript中定义src文件使用了 绝对路径 , 而不是 相对路径 , 这个很有可能就是问题的关键。待我去验证一下,回头再来补充答案。@JonasWen @a10
非常高兴,经上面大佬们的点拨,基本确认了,果然就是ra目录下SConscript文件定义src使用了 绝对路径, 而不是 相对路径,从而引发问题的。
再次感谢大佬们的点拨,真的是一语惊醒梦中人。社区力量就是强大,总有意向不大的收获!
目前问题已经得到解决,参考下面的记录。
修改的地方正是 ra目录下的SConscript文件:
修改后的编译输出:
obj文件生成的验证:
完美手工。
@recan
@recan
但是 linux 等项目就是把 obj 和源代码直接放同一目录的, 所以也还算ok吧 :)
这个直接
scons -c
就可以了; 如果用了 git, 也可以直接git checkout . && git clean -xdf
:)保存编译结果到独立输出目录的做法大概是 IDE 出现后才有的,大概是因为IDE 往往会同时配置多种编译配置, 需要分别保存到不同的输出路径,否则会出问题, 例如
build/debug
,build/release
.@recan
但是ra_gen目录却不需要专门定义相对路径,其实这一点我是还没有完全搞明白的
ra_gen里面的定义:
它用的是Glob函数,这种写法本质也是从当前目录开始扫码 .c文件,等同于 src = Glob(‘./*.c’)
只不过是把 ./ 省略了而已。
@JonasWen
可能我见得比较少obj文件输出到源码目录的情况,这种会造成obj文件满天飞的情况;同时还有一个情况,比如有些模块是复用了,我编译多个应用时,如果大家的obj文件都放在源码目录,那么他们可能就冲突了, 是可能会出问题的;而我现在在做的多应用构建编译,就会遇到这个问题,所以我需要把obj文件按需存放。
当然,也或者是我对这个玩意有洁癖,从使用上并无差异,个人喜好,仅供大家参考,哈哈哈。@a1012112796
@recan
豁然开朗,受教了
互相学习,我最近也是在研究scons,以前都是makefile的忠实粉丝,也是为了考虑windows下的构建,才考虑学习一下scons构建。一路踩坑,一路成长。@JonasWen