[Scons-users] Building object files in multiple environments

Dan Čermák dan.cermak at cgc-instruments.com
Wed Nov 8 06:38:02 EST 2017


Thanks a lot for your extensive answer!

Do I understand it correctly that for each "device"/"project" you infer
all modules from the config file and then build them for that specific
project?

I actually wanted it kind of the other way around: all modules are build
once and then linked for each project, but the project specific stuff
should be build with an additional include path.

I must admit that I like your approach very much and I think I could use
something like that, too. Could you give me maybe a hint how your
configuration system roughly works (only if you can do that without
getting into trouble with your employer)?


Cheers,

Dan


Hua Yanghao <huayanghao at gmail.com> writes:

> I think it is much easier to introduce something called "configuration".
> Take a look at the Linux kernel or u-boot Kconfig system, where
> everything is considered equally as source code and then the
> configuration file selects which pieces you want to compile and link
> together.
>
> My current project folder structure is something like this:
> hua at grass:~/git/usw $ tree -L 1
> .
> ├── arch
> ├── boards
> ├── build_list.txt
> ├── common
> ├── configs
> ├── doc
> ├── drivers
> ├── external
> ├── include
> ├── lib
> ├── Makefile
> ├── output
> ├── README.md
> ├── SConstruct
> ├── site_scons
> ├── soc
> ├── test
> ├── TODO.md
> └── tools
>
> 14 directories, 5 files
> hua at grass:~/git/usw $
>
> where in configs/ you have all the configuration file written in
> python, for example configs/qemu_arm_vexpress_bios.py: 1
> #!/usr/bin/env python
>   2 '''
>   3 To execute:
>   4 export QEMU_AUDIO_DRV="none"
>   5 qemu-system-arm -M vexpress-a9 -nographic -kernel
> output/armv7_gcc_full/usw.elf
>   6 '''
>   7 from common import ConfigMeta
>   8 from compiler import gcc_arm_none_eabi
>   9
>  10 class Config(object):
>  11     __metaclass__ = ConfigMeta
>  12     COMPILER = gcc_arm_none_eabi.Compiler()
>  13
>  14     CONFIG_ARCH = "armv7"
>  15     CONFIG_NO_STACK = 1
>  16     CONFIG_BIOS_START = 1
>  17     CONFIG_BOOT_ENTRY = 0x60000200
>  18     CONFIG_LINK_SCRIPT = "arch/armv7/link.ld"
>  19     CONFIG_TEXT_START = 0x00000000
>  20     CONFIG_HEAP_SIZE = 0x100000
>  21     CONFIG_ARM_BASE = 0x1e000000
>  22     CONFIG_UART_BASE = 0x10009000
>  23     CONFIG_PRINT_COLOR = 1
>  24
>  25     CONFIG_IBI_HEADER = 1
>  26     CONFIG_IBI_SIZELIMIT = 0x64000
>  27     # SMP
>  28     CONFIG_CPU_NUM = 4
>  29     CONFIG_IRQ_STACK_SIZE = 0x10000
>  30     CONFIG_FIQ_STACK_SIZE = 0x10000
>  31
>  32     # Module List
>  33     MODULE_LIST = [
>  34         "arch",
>  35         "arch/armv7",
>  36     ]
>
> This is one of my simplest config file, where it selects which module
> (e.g. each folder that have a SConscript is considered a module) is
> specified in the MODULE_LIST and then in SConstruct the SConscript
> file is automatically imported.
> All build that is corresponding to a particular config file has a
> dedicated output folder:
> hua at grass:~/git/usw $ ll output/
> total 28
> drwxr-xr-x  9 hua hua 4096 Nov  8 10:30 linux64_full
> drwxr-xr-x 10 hua hua 4096 Nov  8 10:29 qemu_arm_vexpress
> drwxr-xr-x  4 hua hua 4096 Nov  8 10:30 qemu_arm_vexpress_bios
> drwxr-xr-x 11 hua hua 4096 Nov  8 10:30 xmm7xx0
> drwxr-xr-x 11 hua hua 4096 Nov  8 10:30 xmm7xx0_xxx
> drwxr-xr-x  4 hua hua 4096 Nov  8 10:30 xmm7xx0_xxx_lmu
> drwxr-xr-x  8 hua hua 4096 Nov  8 10:30 xmm7xx0_xxx_yyy
> hua at grass:~/git/usw $
>
> So even for a single device, you could have have different
> configuration, e.g. one for boot loader/bios, one for verification SW,
> one for production SW etc.
>
> The best part I love SCons is that in the output folder there is a
> copy of the file that is actually being selected/used from the
> configuration system so you know exactly what is compiled.
>
> For each individual module the SConscript is extremely simple and
> straightforward:
>
> hua at grass:~/git/usw $ cat boards/vexpress/SConscript
> name = "usw_lib"
>
> Import('cs')
> Import('usw_files')
>
> obj_files = [
>     "board.c",
>     "pl011_device.c",
>     "test_device.c",
>     "pipe_device.c",
> ]
>
> lib_files = [
> ]
>
> if hasattr(cs, "CONFIG_LOAD_BINARY"):
>     obj_files.append(("binary.c", ["cmd.txt", "page_table.bin"]))
>
> ret = usw_files(name, lib_files, obj_files)
>
> Return('ret')
> hua at grass:~/git/usw $
>
> There you just provide a obj_files / lib_files and you can even
> specify dependency files (where you don't really want a Scons parser),
> and even specify customized compilation flags for individual files
> (Kconfig/Kbuild can also do this, but not the explicit dependency
> specification).
>
> I am trying to make this framework (basically Kconfig/Kbuild reduced
> feature set implemented using SCons) open source but company process
> is lengthy ...
> Or maybe it even makes sense to make this kind of feature as part of
> SCons itself?
>
> I hope this helps a little bit.
>
> Best Regards,
> Hua Yanghao
>
> On Wed, Nov 8, 2017 at 10:48 AM, Dan Čermák
> <dan.cermak at cgc-instruments.com> wrote:
>> Hi Folks,
>>
>> I am currently using SCons for a big mono-repo C++ Firmware, where I
>> have lots of common source files and then a directory where the actual
>> firmware for each device is (this is just a .cpp file with device
>> specific configurations and the appropriate high-level logic).
>>
>> For illustration purposes, the directory structure looks something like
>> this:
>> .
>> ├── devices
>> │   ├── Device_A
>> │   │   ├── main.cpp
>> │   │   ├── SConscript
>> │   │   ├── uart.cpp
>> │   │   └── uart.hpp
>> │   ├── Device_B
>> │   │   ├── main.cpp
>> │   │   └── SConscript
>> │   └── SConscript
>> ├── spi
>> │   └── config.cpp
>> ├── uart
>> │   └── uart.cpp
>> ├── util
>> │   └── endian.c
>> └── SConstruct
>>
>> The idea behind this is that everything outside of 'devices' is
>> considered as common files and build into object files. Every
>> subdirectory of devices should have a SConscript that creates a single
>> binary file (this is the firmware for the specific device) that is
>> linked with the common object files.
>>
>> I have achieved this by creating object files for every cpp file not in
>> devices/ and passing them to the SConscript in devices/. However, there
>> is a catch: I would like to build everything under devices with an
>> additional include path (the top level directory of the project) which
>> should not be propagated to the common object files. I therefore tried
>> creating a clone of the environment for each device in
>> devices/SConscript and then doing the following in
>> devices/Device_A/SConscript:
>>
>> Import('env_clone', 'obj')
>>
>> local_obj = env_clone.Object(Glob('*.cpp'))
>> prog = env_clone.Program('Device_A_bin', local_obj + obj)
>>
>> Return('prog')
>>
>> where env_clone is the cloned environment with the additional include
>> path and obj the list of object files that are common to all
>> devices (which have been created in the environment env from which
>> env_clone was cloned). This however causes SCons to complain, that there
>> are object files in multiple environments with the same build command.
>>
>>
>> My guess is, that my solution of cloning environments is not the correct
>> way. Does someone have an idea how to achieve this with SCons?
>>
>>
>> Thanks in advance,
>>
>> Dan
>> _______________________________________________
>> Scons-users mailing list
>> Scons-users at scons.org
>> https://pairlist4.pair.net/mailman/listinfo/scons-users
> _______________________________________________
> Scons-users mailing list
> Scons-users at scons.org
> https://pairlist4.pair.net/mailman/listinfo/scons-users


More information about the Scons-users mailing list