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!
good article, learn a lot, thanks
LikeLike
thanks!
LikeLike
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
LikeLike
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.
LikeLike
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.
LikeLike