Using SCons with GNU toolchain for ARM on Windows – part 3 : the SCons script

[part 1 part 2 part 3]

So we have prepared the code that we want to compile using SCons.

1. Command prompt

Since SCons will be invoked from the command line, it’s nice to have a batch file that will open the prompt with the necessary settings; so let’s create the following file in the project folder and call it shell.bat:

REM Add Python and tool-chain locations to system path
set PYTHON_PATH=C:\Python27
set GNUARM_PATH=D:\APPLICATIONS\_DEVELOPMENT\_LANG\GNUARM\GNU Tools ARM Embedded\4.9 2014q4\bin
set OPENOCD_PATH=D:\APPLICATIONS\_DEVELOPMENT\_LANG\GNUARM\OpenOCD\openocd-0.8.0\bin-x64

set PATH=%PYTHON_PATH%;%GNUARM_PATH%;%OPENOCD_PATH%;%PATH%

start cmd.exe

Of course the specified paths must be substituted with correct ones. Now, if we double-click on the shell.bat file, a new command prompt will be opened.

2. The SCons script

Let’s then create a file in the project folder and call it SConstruct with the following contents:

# gnu arm toolchain must be already in system path

import os
env = Environment(ENV = os.environ)

env['AR'] = 'arm-none-eabi-ar'
env['AS'] = 'arm-none-eabi-as'
env['CC'] = 'arm-none-eabi-gcc'
env['CXX'] = 'arm-none-eabi-g++'
env['LINK'] = 'arm-none-eabi-g++'                # predefined is 'arm-none-eabi-gcc'
env['RANLIB'] = 'arm-none-eabi-ranlib'
env['OBJCOPY'] = 'arm-none-eabi-objcopy'
env['PROGSUFFIX'] = '.elf'

# include locations
env['CPPPATH'] = [
    '#Inc',
    '#Drivers/CMSIS/Include',
    '#Drivers/CMSIS/Device/ST/STM32F4xx/Include',
    '#Drivers/STM32F4xx_HAL_Driver/Inc',
    '#Drivers/STM32F4xx_HAL_Driver/Inc/Legacy',
    ]

# compiler flags
env.Append(CCFLAGS = [
    '-mcpu=cortex-m4',
    '-mthumb',
    '-O2',
    '-fsigned-char',
    '-ffunction-sections',
    '-fdata-sections',
    '-std=gnu11',
    '-fmessage-length=0',
    '-mthumb-interwork',
    ])

# linker flags
env.Append(LINKFLAGS = [
    '-ffunction-sections',
    '-fdata-sections',
    '-TTrueSTUDIO/Discovery001 Configuration/STM32F407VG_FLASH.ld',
    '-Xlinker',
    '--gc-sections',
    '--specs=nano.specs',
    ]) 

# defines
env.Append(CPPDEFINES = [
    'STM32F407xx',
])

# build everything
prg = env.Program(
    target = 'main',
    source = [
        'Src/main.c',
        'Src/stm32f4xx_hal_msp.c',
        'Src/stm32f4xx_it.c',
        'Src/sys/startup_stm32f4xx_fromCoocox.c',
        'Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c',
        'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c',
    ]
)

# binary file builder
def arm_generator(source, target, env, for_signature):
    return '$OBJCOPY -O binary %s %s'%(source[0], target[0])
env.Append(BUILDERS = {
    'Objcopy': Builder(
        generator=arm_generator,
        suffix='.bin',
        src_suffix='.elf'
    )
})

env.Objcopy(prg)

This is our SCons configuration file. SCons experts will deservedly turn their nose up, because it’s super-simplified. SCons can do a lot more and better, but this script works and proves how it can be used to cross-compile for our target.

What the script does is very simple:

  • In the first section it set the parameters that inform SCons about the toolchain we are using.
  • Then the include libraries are added, together with compiler and linker flags.
  • Finally all the sources are compiled and the final program is built. Afterwards the produced .elf file is converted in the binary form suitable for uploading to flash.

3. Building and uploading the project

In order to build the project, open a new command prompt by double cliccking on the previously created shell.bat file and type scons.

If everything works, at the end you should read something like “scons: done building targets.” and a couple of files should now be present in the project folder: main.elf and main.bin.

The second one can be uploaded to the MCU flash using the command:

openocd -f board/stm32f4discovery.cfg -c "init; reset halt; flash write_image erase main.bin 0x08000000; reset run; shutdown"

After some seconds, the board should start blinking, and if you connect to the USART2 port some chars are received.

Happy coding!

7 thoughts on “Using SCons with GNU toolchain for ARM on Windows – part 3 : the SCons script”

  1. very usefull article, thank you very much!

    Could you tell me where you’ve found the compiler settings for your device? I am currently on the same setup for a different Cortex (M4F), and I’m having trouble finding the proper compiler flags (other than optimisation, debugging etc.)

    Kind regards,

    Diederik

    Like

  2. This series, particularly the third post, was extremely useful for me. Since you mention that the scons-elite would turn their nose up: I’m curious, what would you do to improve your SConstruct file?

    Also, I had to use “-Wl,” before linker options to get g++ to pass them along.

    Like

  3. Hi when i am trying to build i am getting error.
    Here is my output..

    scons: Reading SConscript files …
    scons: done reading SConscript files.
    scons: Building targets …
    arm-none-eabi-gcc /Foinc\sgk_assert.obj /c inc\sgk_assert.c /nologo -mcpu=cortex-m0 -mthumb
    arm-none-eabi-gcc: error: /Foinc\sgk_assert.obj: No such file or directory
    arm-none-eabi-gcc: error: /c: No such file or directory
    arm-none-eabi-gcc: error: /nologo: No such file or directory
    scons: *** [inc\sgk_assert.obj] Error 1
    scons: building terminated because of errors.

    Sconstruct file
    import os
    env = Environment(ENV = os.environ)

    env[‘AR’] = ‘arm-none-eabi-ar’
    env[‘AS’] = ‘arm-none-eabi-as’
    env[‘CC’] = ‘arm-none-eabi-gcc’
    env[‘CXX’] = ‘arm-none-eabi-g++’
    env[‘LINK’] = ‘arm-none-eabi-g++’ # predefined is ‘arm-none-eabi-gcc’
    env[‘RANLIB’] = ‘arm-none-eabi-ranlib’
    env[‘OBJCOPY’] = ‘arm-none-eabi-objcopy’
    env[‘PROGSUFFIX’] = ‘.elf’

    # compiler flags
    env.Append(CCFLAGS = [
    ‘-mcpu=cortex-m0’,
    ‘-mthumb’
    ])
    env.Append(ENV = {‘PATH’ : os.environ[‘PATH’]})
    Export(‘env’)
    env.SConscript(“src/SConscript”)
    env.SConscript(“inc/SConscript”)

    Please help. I want to compile scons with arm-eabi in windows.

    Like

Leave a reply to cedar Cancel reply