Using scons with Keil compiler/linker - scons

I'm trying to use the Keil C51 compiler with scons as a build system.
The final problem I have is how to get $SOURCES to be output comma-separated to the linker. The default uses space as separator.
The relevant parts of the SConstruct is
path = ['C:\Keil\C51\BIN']
env = Environment(ENV = {'PATH' : path})
#Compiler settings
env['CC'] = 'c51.exe'
env['CCCOM'] = '$CC $SOURCES $_CPPINCFLAGS $CFLAGS $_CCCOMCOM ' #-o $TARGET
env['INCPREFIX'] = 'INCDIR('
env['INCSUFFIX'] = ')'
# Linker settings
env.Replace(LINK='BL51.exe')
env['LINKCOM'] = '$LINK $SOURCES TO $TARGET $LINKFLAGS $__RPATH $_LIBDIRFLAGS $_LIBFLAGS'
With this I get:
BL51.exe driver.obj flash.obj initialization.obj power.obj TO Outfile.omf
What I want is:
BL51.exe driver.obj,flash.obj,initialization.obj,power.obj TO Outfile.omf
$SOURCES is a construction variable and I cant find how to change how it is printed to the command-line.
Anyone?

I solved this by using:
env['LINKCOM'] = '$LINK ",".join( $SOURCES ) TO $TARGET $LINKFLAGS $__RPATH $_LIBDIRFLAGS $_LIBFLAGS'

Related

Internal Error: no cycle found in Scons Build

When I build my Sconstruct file, I am getting the below error.
scons: *** Found dependency cycle(s):
build/sselser/sselConfigArgs.h -> build/sselser/sselConfigArgs.h
Internal Error: no cycle found for node build/sselser/sselMain (<SCons.Node.FS.File instance at 0x9f61e8>) in state pending
Internal Error: no cycle found for node build/sselser/sselMain.o (<SCons.Node.FS.File instance at 0x9f2e68>) in state pending
File "/nfs/scons/scons-1.3.0/lib/scons-1.3.0/SCons/Taskmaster.py", line 1026, in cleanup
I guess this is due to dependency of sselMain in sselTransorm as the error occurs during the build of sselTransform directory.
Makefile in sselTransform:
UNIT_SUPPORT_FILES += ../sselser/sselMain intest ../../../make/Makenv
MDE_SUPPORT_FILES += ../sselser/sselMain intest ../../../make/Makenv
I need to add the same in Sconscript of sselTransform directory to resolve this issue.
How to resolve this issue?
Sconscript:
#Set CPPPATH, RPATH, DEFINES and CCFLAGS
env = Environment(CPPPATH =['.','../sselTransform','../sselSm','../sselSRC'],
RPATH = ['/l-n/app/colr/lib/infra/SunOS5.10/WS12.0'],CPPDEFINES = ['THREADSAFE','_RWSTD_SOLARIS_THREADS','_SVID_GETTO
D','DEBUG','sun5'],CCFLAGS = ['library=rwtools7_std','features=no%tmplife','-pta','-mt','-xdebugformat=stabs','-g0','-xildoff'])
env['CXX']=CXX
Src = Split('sselManager.C PromoNotifyMgr.C ')
env.StaticLibrary('libSselser-g0.a',Src)
Src1 = Split('sselMain.C sselManager.o PromoNotifyMgr.o ')
env.Program('sselMain',Src1)
configfile = 'sselConfigArgs.h'
CONFIG_PATH = '../../build/include/'
CONFIG=CONFIG_PATH+configfile
env.Command(CONFIG,configfile,
[Copy('$TARGET', '$SOURCE'),
Chmod('$TARGET', 0444)])
Sconstruct:
SConscript('src/ssel/sselser/SConscript',variant_dir='build/sselser',duplicate=0,exports='env')
Try this?
Notes:
I'm saving the build objects for your two source files and using those in both the program and static library.
I've added the target dir you're copying the header file to earlier in the CPPPATH.
You could have skipped the variables configfile, CONFIG_PATH, CONFIG and just used the strings in your Command.
You are using a VERY old version of SCons. If you're limited to python 2.7 please try using SCons 3.0.1? If you're not and can use Python 3.6, then try using SCons 4.3.0.
#Set CPPPATH, RPATH, DEFINES and CCFLAGS
env = Environment(
CPPPATH =['.','../include','../sselTransform','../sselSm','../sselSRC'],
RPATH = ['/l-n/app/colr/lib/infra/SunOS5.10/WS12.0'],
CPPDEFINES = ['THREADSAFE','_RWSTD_SOLARIS_THREADS','_SVID_GETTOD','DEBUG','sun5'],
CCFLAGS = ['library=rwtools7_std','features=no%tmplife','-pta','-mt','-xdebugformat=stabs','-g0','-xildoff'])
env['CXX']=CXX
Src = ['sselManager.C','PromoNotifyMgr.C']
objects = []
for s in Src:
objects.extend(env.StaticObject(s))
env.StaticLibrary('Sselser-g0',objects)
Src1 = ['sselMain.C'] + objects
env.Program('sselMain', Src1)
configfile = 'sselConfigArgs.h'
CONFIG_PATH = '../include/'
CONFIG=CONFIG_PATH+configfile
env.Command(CONFIG, configfile,
[Copy('$TARGET', '$SOURCE'),
Chmod('$TARGET', 0444)])

SCons generates an incomplete dependency tree if I use a custom decider

I'm trying to build a flex-bison parser with SCons, using a custom decider. (You can learn more about the decider in this question, although, the details probably aren't too relevant to the current problem.)
Files:
My SConstruct:
env = DefaultEnvironment()
deciderEnv = env.Clone()
def source_and_target_decider(dependency, target, prev_ni, repo_node=None):
src_old_csig = prev_ni.csig if hasattr(prev_ni, 'csig') else None
src_new_csig = dependency.get_csig()
tgt_stored_info = target.get_stored_info()
tgt_old_csig = tgt_stored_info.ninfo.csig if hasattr(tgt_stored_info.ninfo, 'csig') else None
tgt_new_csig = target.get_csig()
return src_new_csig != src_old_csig or tgt_new_csig != tgt_old_csig
deciderEnv.Decider(source_and_target_decider)
deciderEnv['YACCFLAGS'] = ['-d']
deciderEnv['YACCHXXFILESUFFIX'] = '.hh'
bison_source = deciderEnv.CXXFile('src/test.yy.cc', 'src/test.yy')[0]
deciderEnv['LEXFLAGS'] = [f'--header-file=${{SOURCE}}.hh']
flex_source = deciderEnv.CXXFile('src/test.ll.cc', 'src/test.ll')[0]
Program('test', [bison_source, flex_source])
src/test.yy:
%language "c++"
%code {
int yylex(int*);
}
%token X
%%
everything: X {}
and src/test.ll:
%{
#include "./test.yy.hh"
%}
%option c++
%%
. { return yy::parser::token::X; }
Result:
I run a command scons ./src/test.ll.o.
The first time you run it, it works correctly.
flex --header-file=src/test.ll.hh -t src/test.ll > src/test.ll.cc
bison -d -o src/test.yy.cc src/test.yy
g++ -o src/test.ll.o -c src/test.ll.cc
SCons seems to understand that it needs to generate src/test.yy.hh using bison before it compiles the src/test.ll.o because src/test.ll.cc #includes that header.
However, if I then remove .sconsign.dblite (leaving the rest of the files intact), SCons seems to lose that understanding for the duration of the next build.
Running scons ./src/test.ll.o yields:
flex --header-file=src/test.ll.hh -t src/test.ll > src/test.ll.cc
g++ -o src/test.ll.o -c src/test.ll.cc
and only after calling it a second time it decides to build the src/test.yy.hh:
bison -d -o src/test.yy.cc src/test.yy
g++ -o src/test.ll.o -c src/test.ll.cc
Dependency tree:
Normally the dependency tree (scons --tree=all src/test.ll.o) looks like this:
+-src/test.ll.o
+-src/test.ll.cc
| +-src/test.ll
| +-/bin/flex
+-src/test.yy.hh
| +-src/test.yy
| +-/bin/bison
+-/bin/g++
However, right after deleting the .sconsign.dblite it is incomplete:
+-src/test.ll.o
+-src/test.ll.cc
| +-src/test.ll
| +-/bin/flex
+-/bin/g++
Further observations:
The last line of the custom decider seems to be the culprit.
Specifically, the part or tgt_new_csig != tgt_old_csig. If you remove this part, the problem no longer occurs.
However, I have no clue why this particular piece of code breaks the build.
Any idea how to fix this?
The sconsign is where SCons stores info about previous builds.
If you remove it, then SCons will not have that info and will rebuild everything.
Because in your decider you are setting:
tgt_old_csig = tgt_stored_info.ninfo.csig if hasattr(tgt_stored_info.ninfo, 'csig') else None
and then comparing None to the current csig, which will not be equal and require a rebuild.
You'd likely need to change as follows to work when you're explicitly removing the source of the tgt_stored_info (the sconsign file).
def source_and_target_decider(dependency, target, prev_ni, repo_node=None):
src_old_csig = prev_ni.csig if hasattr(prev_ni, 'csig') else None
src_new_csig = dependency.get_csig()
tgt_stored_info = target.get_stored_info()
tgt_old_csig = tgt_stored_info.ninfo.csig if hasattr(tgt_stored_info.ninfo, 'csig') else None
tgt_new_csig = target.get_csig()
if tgt_old_csig:
return src_new_csig != src_old_csig or tgt_new_csig != tgt_old_csig
else:
return src_new_csig != src_old_csig
Why are you removing .sconsign.dblite?

How to add global CXX compiler flag to yocto build

It seems something obvious to me, but I couldn't find any solution. Suppose I want to add or change a compiler flag/option which applies to all yocto recipes. It is possible to add a global flag somewhere, without changing the recipes ?
You can add it to the machine configuration file.
The machine configuration file is in the board support layer, under conf/machine. It is named $MACHINE.conf, where MACHINE is defined in your local.conf.
Here are the ones in poky 1.4. Yours might be in a layer outside of poky.
> ls -1 meta-yocto-bsp/conf/machine/
atom-pc.conf
beagleboard.conf
mpc8315e-rdb.conf
routerstationpro.conf
> ls -1 meta/conf/machine/
include
qemuarm.conf
qemumips.conf
qemuppc.conf
qemux86-64.conf
qemux86.conf
Once you identify your board configuration file, add a line to the end to add to your C Flags:
TARGET_CFLAGS += " <my flags> "
You can add global compiler options for Yocto builds in poky/meta/conf/bitbake.conf. After adding options, check the bitbake environment using the command bitbake -e
cat poky/meta/conf/bitbake.conf
...
...
##################################################################
# Build flags and options.
##################################################################
export BUILD_CPPFLAGS = "-isystem${STAGING_INCDIR_NATIVE}"
BUILDSDK_CPPFLAGS = "-isystem${STAGING_INCDIR}"
export CPPFLAGS = "${TARGET_CPPFLAGS}"
export BUILD_CFLAGS = "${BUILD_CPPFLAGS} ${BUILD_OPTIMIZATION}"
BUILDSDK_CFLAGS = "${BUILDSDK_CPPFLAGS} ${BUILD_OPTIMIZATION}"
export CFLAGS = "${TARGET_CFLAGS}"
export TARGET_CFLAGS = "${TARGET_CPPFLAGS} ${SELECTED_OPTIMIZATION}"
export BUILD_CXXFLAGS = "${BUILD_CFLAGS}"
export CXXFLAGS = "${TARGET_CXXFLAGS}"
export TARGET_CXXFLAGS = "${TARGET_CFLAGS}"

Scons compiler path contains spaces

I have a toolchain, not on the path, installed at a location containing spaces (C:\Program Files\Some Compiler\). I've tried:
env = Environment(
MY_TOOLCHAIN_ROOT = R'C:\Program Files\Some Compiler\',
MY_TOOLCHAIN_BIN = R'$MY_TOOLCHAIN_ROOT\bin',
)
env.Replace(
CC = "$MY_TOOLCHAIN_BIN/gcc",
CXX = "$MY_TOOLCHAIN_BIN/g++",
OBJCOPY = "$MY_TOOLCHAIN_BIN/objcopy"
)
env.Program('main.cpp')
But I get the error
'C:\Program' is not recognized as an internal or external command, operable program or batch file.
How can I get scons to quote the spaces?
Seems I need to mark them as Files:
env.Replace(
CC = env.File("$MY_TOOLCHAIN_BIN/gcc"),
CXX = env.File("$MY_TOOLCHAIN_BIN/g++"),
OBJCOPY = env.File("$MY_TOOLCHAIN_BIN/objcopy")
)
I think the problem is with the os style variables you are using with the $. Instead of specifying them with the env.File() (Im surprised it handled the variables), you could consider some simple python code as follows:
import os
env = Environment(
MY_TOOLCHAIN_ROOT = R'C:\Program Files\Some Compiler\',
MY_TOOLCHAIN_BIN = R'$MY_TOOLCHAIN_ROOT\bin',
)
env.Replace(
CC = os.path.join(os.environ["MY_TOOLCHAIN_BIN"], "gcc"),
CXX = os.path.join(os.environ["MY_TOOLCHAIN_BIN"], "g++"),
OBJCOPY = os.path.join(os.environ["MY_TOOLCHAIN_BIN"], "objcopy")
)

scons: overriding build options for one file

Easy question but I don't know the answer.
Let's say I have a scons build where my CCFLAGS includes -O1. I have one file needsOptimization.cpp where I would like to override the -O1 with -O2 instead. How could I do this in scons?
update: this is what I ended up doing based on bialix's answer:
in my SConscript file:
Import('env');
env2 = env.Clone();
env2.Append(CCFLAGS=Split('-O2 --asm_listing'));
sourceFiles = ['main.cpp','pwm3phase.cpp'];
sourceFiles2 = ['serialencoder.cpp','uartTestObject.cpp'];
objectFiles = [];
objectFiles.append(env.Object(sourceFiles));
objectFiles.append(env2.Object(sourceFiles2));
...
previously this file was:
Import('env');
sourceFiles = ['main.cpp','pwm3phase.cpp','serialencoder.cpp','uartTestObject.cpp'];
objectFiles = env.Object(sourceFiles);
...
Use Object() builder for fine-grained control over compilation, and then pass these objects to Program() builder.
E.g. instead of:
env = Environment()
env.Program(target='foo', source=['foo.cpp', 'bar.cpp', 'needsOptimisation.cpp'])
You need to use following:
env = Environment()
env_o1 = env.Clone()
env_o1.Append(CCFLAGS = '-O1')
env_o2 = env.Clone()
env_o2.Append(CCFLAGS = '-O2')
# extend these lists if needed
SRC_O1 = ['foo.cpp', 'bar.cpp']
SRC_O2 = ['needsOptimisation.cpp']
obj_o1 = [env_o1.Object(i) for i in SRC_O1]
obj_o2 = [env_o2.Object(i) for i in SRC_O2]
env.Program(target='foo', source=obj_o1+obj_o2)
You can avoid creation of separate clone of env variable if you provide CCFLAGS='-O2' right in the Object() call:
obj_o2 = [env.Object(i, CCFLAGS=env['CCFLAGS'] + ['-O2']) for i in SRC_O2]
Avoiding creating of a separate env variable requires (ref: bialix's answer) needs something like this.
obj_o2 = env.Object(SRC_O2, CCFLAGS=env['CCFLAGS'] + ['-O2']);
If you just do this (or in the for loop like bialix does)
obj_o2 = env.Object(SRC_O2, CCFLAGS='-O2');
then you lose all the builtin flags.

Resources