最近发现scons真的很好用,python语法比makefile友好很多。准备用scons 替换掉项目中的makefile,重新搭建build system。
本文是之前自己刚开始学习scons的一个小demo,用来编译一个嵌入式arm的项目。
项目目录
-scons_demo
- boot.s
- cm4.ld
- compiler.py
- main.c
- SConstruct
- driver
- SConscript
- qemu_print.c
- sub_driver
- Sconscript
- sub_driver.c
- 一共有三个目录,根目录scons_demo, driver, sub_driver.
- 四个源文件 boot.s, main.c, driver/qemu_print.c, driver/sub_driver/test.c
- 一个链接文件cm4.ld。
编译目标
- 将四个源文件编译成*.o
- 然后根据cm4.ld 将obj文件输出elf
- 根据elf输出binary文件,同时导出反汇编文件。
compiler.py:定义编译器、编译参数和链接参数
COMPILER_PREFIX = 'arm-none-eabi-'
DEF_LINK = COMPILER_PREFIX + 'ld'
DEF_AS = COMPILER_PREFIX + 'as'
DEF_GCC = COMPILER_PREFIX + 'gcc'
DEF_OBJCOPY = COMPILER_PREFIX + 'objcopy'
DEF_LINKFLAGS = '-T cm4.ld'
DEF_CFLAGS = [
'-std=c11',
'-g',
'-mcpu=cortex-m3',
'-mthumb',
'-nostartfiles',
'--specs=nosys.specs'
]
scons_demo/SConsturct
import os
# 导入编译参数
from compiler import *
# 创建编译环境,使用complier.py中的编译器以及编译参数、链接参数
env = Environment()
env['LINK'] = DEF_LINK
env['AS'] = DEF_AS
env['CC'] = DEF_GCC
env['OBJCOPY'] = DEF_OBJCOPY
env['LINKFLAGS'] = DEF_LINKFLAGS
env.Append(CCFLAGS = DEF_CFLAGS)
#指定子目录,这里只有一个子目录driver
sub_dirs = [
'driver'
]
#编译当前目录下所有c文件到o文件
env.Object(Glob('*.c'))
#编译当前目录下boot.s到o文件
env.Object('boot.s')
src_obj = Glob('*.o')
#遍历添加子目录中的.o文件
for d in sub_dirs:
src_obj += SConscript(d + '/SConscript')
#将所有的.o根据cm4_ld链接成main.elf
env.Program('main.elf', src_obj)
#根据elf生成binary
env.Command('main.bin', 'main.elf', env['OBJCOPY'] + ' -O binary -S -R .note -R .comment main.elf main.bin')
#根据elf生成反汇编
env.Command('main.dis', 'main.elf', 'arm-none-eabi-objdump -S main.elf > main.dis')
scons_demo/driver/SConscript
# 导入编译参数
from compiler import *
#指定子目录,这里只有一个子目录sub_driver
sub_dirs = [
'sub_driver'
]
env = Environment()
env['LINK'] = DEF_LINK
env['AS'] = DEF_AS
env['CC'] = DEF_GCC
env['OBJCOPY'] = DEF_OBJCOPY
env['LINKFLAGS'] = DEF_LINKFLAGS
env.Append(CCFLAGS = DEF_CFLAGS)
#编译所有c文件到o文件
src = Glob('*.c')
obj = env.Object(src)
src_obj = Glob('*.o')
#遍历添加子目录中的.o文件
for d in sub_dirs:
obj = obj + SConscript(d + '/SConscript')
#返回obj文件给上级目录scons_demo/SConstruct
Return('obj')
scons_demo/driver/sub_driver/SConscript
# 导入编译参数
from compiler import *
env = Environment()
env['LINK'] = DEF_LINK
env['AS'] = DEF_AS
env['CC'] = DEF_GCC
env['OBJCOPY'] = DEF_OBJCOPY
env['LINKFLAGS'] = DEF_LINKFLAGS
env.Append(CCFLAGS = DEF_CFLAGS)
#编译所有c文件到o文件
src = Glob('*.c')
obj = env.Object(src)
#返回obj文件给上级目录scons_demo/driver/SConsript
Return('obj')
编译log
~/Misc_demo/scons_demo$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
arm-none-eabi-as -o boot.o boot.s
arm-none-eabi-gcc -o driver/qemu_print.o -c -std=c11 -g -mcpu=cortex-m3 -mthumb -nostartfiles --specs=nosys.specs driver/qemu_print.c
arm-none-eabi-gcc -o driver/sub_driver/sub_driver.o -c -std=c11 -g -mcpu=cortex-m3 -mthumb -nostartfiles --specs=nosys.specs driver/sub_driver/sub_driver.c
arm-none-eabi-gcc -o main.o -c -std=c11 -g -mcpu=cortex-m3 -mthumb -nostartfiles --specs=nosys.specs main.c
arm-none-eabi-ld -o main.elf -T cm4.ld boot.o main.o driver/qemu_print.o driver/sub_driver/sub_driver.o
arm-none-eabi-objcopy -O binary -S -R .note -R .comment main.elf main.bin
arm-none-eabi-objdump -S main.elf > main.dis
scons: done building targets.