I am using scons script to compile my code by using VC10 and renesas compiler.
i am successfully building my source code in variant directory by using VC10, But if i used the same script for the renesas compiler it is not building the obj files in variant directory.
can anyone tell me how to do that.
I am using renesas rx600 family controller.
My example tree look like
src1
-main.c
sconscript
sconstruct
subdirA
fileA.c
sconscript
subdirB
fileB.c
sconscript
src1/sconstruct contains
import os
env = Environment()
tmp_obj_list = []
env = Environment(ENV = {'PATH' : os.environ['PATH']})
env['LINKFLAGS'] = "/nologo /subsystem:console /pdb:project.pdb"
env['CCFLAGS'] = "/nologo /wd4355 /GR- /EHs-c- /MT /c /W3 /WX /Zi /FD"
env['ENV']['TMP'] = os.environ['TMP']
env['ENV']['TEMP'] = os.environ['TEMP']
Export('env')
env.SConscript('d://src1//subdirA//SConscript',
variant_dir = 'd://build1//subdirA',
duplicate = 0, exports = 'env')
tmp_obj_list.append(Glob('d://build1//subdirA' + '/*.lib'))
env.SConscript('d://src1//subdirB//SConscript',
variant_dir = 'd://build1//subdirB',
duplicate = 0, exports = 'env')
tmp_obj_list.append(Glob('d://build1//subdirB' + '/*.lib'))
env.SConscript('d://src1//SConscript')
env.Append(LIBS = tmp_obj_list)
src1/sconscript contains
Import('env')
env.Program('program',Glob('*.c'))
env.Clean('program','d://build1')
src1/subdirA & src1/subdirB sconscript contains
Import('env')
l = env.Library(target='subdirB', source='fileB.c')
Return('l')
Related
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)])
Seems -u doesn't work on for me ( I am using scons-2.3.6).
To simplify the context, you can imagine my project structure like,
+root
+project
- bar.vcxproj (generated vs project)
-SConstruct
-bar.c
Inside SConstruct, I have put code like:
env_base = Environment()
...
env_base.StaticLibrary(target = 'bar', source = ['bar.c'])
...
If I execute command "scons" in root folder, everything works perfectly.
But If I execute command "scons -u" in project folder, scons can find my SConstruct up in root folder, but no file get compiled.
BTW : The reason for me to execute "scons -u" in project folder is because I want to put the generated vsproj in projet folder and use BuildCommandLine to compile the project.
I guess I didn't use "-u" correctly, what will be the elegant solution for my situation?
1st edit:
As bdbaddog asked, I have put the SConstruct here:
def BuildConfig(env, config):
env.Append(CCFLAGS = '/W 4')
env.Append(CCFLAGS = '/WX')
if config == "debug":
env.Append(CCFLAGS = '/DEBUG')
#env.Append(CCFLAGS = '-Zi /Fd${TARGET}.pdb')
env.Append(CCFLAGS = '/Z7')
elif config == "release":
pass
env_base = Environment()
lib = env_base.StaticLibrary(target = 'bar', source = ['bar.c'])
opts=Variables()
opts.Add('target', 'Compile Target (debug/release).', "debug")
# there is more in my project....
opts.Update(env_base) # update environment
# here I want to use my own command to build the project, so it can support different build option that is defined by me.
env_base['MSVSBUILDCOM'] = "scons -u target=$(Configuration)"
target = env_base["target"]
BuildConfig(env_base, env_base['target'])
env_base.MSVSProject(target = "project\\bar" + env_base['MSVSPROJECTSUFFIX'],
srcs = ["..\\bar.c"],
incs = [],
localincs = "",
resources = "",
misc = "",
buildtarget = lib,
variant = ['debug'],
auto_build_solution=0)
SCons only builds files under the current directory by default.
If you you wanted to only build files in a certain directory (for which there are rules that build the targets there), you can invoke SCons as follows:
scons the_target_directory_I_want_to_build
Though this may cause sources for targets in that directory to also be built.
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")
)
Im new to scons and am having problems with scons dependancies
in a hierarchichal build with a variant directory.
Im able to reproduce the problem in a reduced environment that consists of
2 subdirs under the SConscript directory (moduleA and moduleB) as follows:
.
|-- SConstruct
|-- file.conf
|-- moduleA
| |-- SConscript
| `-- conf2cc
`-- moduleB
|-- SConscript
`-- fileB.cc
Here is the flow of what needs to be done:
moduleA executes a shell script: conf2cc, input: $projRootDir/file.conf, output: moduleA/$variantDir/source.cc
moduleA compiles source.cc and creates moduleA/$variantDir/libmoduleA.a
moduleB needs to copy moduleA/$variantDir/source.cc to moduleB/source.cc
moduleB needs to compile moduleB/source.cc and moduleB/fileB.cc into its
library libmoduleB.a
Its entirely possible that Im doing several things wrong here. For example, I know
Im not using $TARGET/$SOURCE in moduleA Command(), but thats on purpose, since the
script needs the absolute path names, and scons doesnt remove the leading '#'
The problem I have is the Command() builder in moduleB (step 3 above) never executes.
Here are the SConstruct and SConscript files:
Sconstruct
import os
env = Environment()
env['variantDir'] = 'linux' # for this example, just make variantDir = linux
modules = ['moduleA', 'moduleB']
for dir in modules:
SConscript(
os.path.join(dir, 'SConscript'),
variant_dir = os.path.join(dir, env['variantDir']),
exports = ['env'],
duplicate = 0)
moduleA/Sconscript
import os
Import('env')
scriptInput = '#file.conf'
sourceFile = os.path.join('#moduleA', env['variantDir'], 'source.cc')
conf2ccScript = File('#moduleA/conf2cc').abspath
# The script needs abspaths for input and output, not the scons '#' prepended
# the script syntax is: script <inputFile> <outputFile>
cmd = '%s %s %s' % (conf2ccScript, File(scriptInput).abspath, File(sourceFile).abspath)
# Generate source.cc file based on file.conf
conf2ccNode = env.Command(target = sourceFile,
source = scriptInput,
action = cmd)
libNode = env.Library(target = 'moduleA', source = sourceFile)
env.Depends(libNode, conf2ccNode)
moduleB/Sconscript
import os
Import('env')
sourceFiles = ['fileB.cc', 'source.cc']
# Get the source.cc file
externalSourceFile = os.path.join('#moduleA', env['variantDir'], 'source.cc')
sourceTarget = os.path.join('#moduleB', 'source.cc')
cmdNode = env.Command(target = sourceTarget,
source = externalSourceFile,
action = Copy('$TARGET', '$SOURCE'))
libNode = env.Library(target = 'moduleB', source = sourceFiles)
env.Depends(libNode, cmdNode)
Here is the output when I execute scons:
Any help would be greatly appreciated!
Brady
notroot#ubuntu:~/projects/sconsTest/sconsTestHierDeps$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
/home/notroot/projects/sconsTest/sconsTestHierDeps/moduleA/conf2cc /home/notroot/projects/sconsTest/sconsTestHierDeps/file.conf /home/notroot/projects/sconsTest/sconsTestHierDeps/moduleA/linux/source.cc
g++ -o moduleA/linux/source.o -c moduleA/linux/source.cc
ar rc moduleA/linux/libmoduleA.a moduleA/linux/source.o
ranlib moduleA/linux/libmoduleA.a
g++ -o moduleB/linux/fileB.o -c moduleB/fileB.cc
scons: *** [moduleB/linux/source.o] Source `moduleB/source.cc' not found, needed by target `moduleB/linux/source.o'.
scons: building terminated because of errors.
I suggest problem in incorrect dependency what you use and filenames.
May be problem in variant_dir and source files for moduleB, you use Command to generate #/moduleB/source.cc, but in sourceFiles you have 'source.cc'.
So, one of ways to help you may be correct moduleB SConscript :
# Get the source.cc file
externalSourceFile = os.path.join('#moduleA', env['variantDir'], 'source.cc')
sourceTarget = os.path.join('#moduleB', 'source.cc')
sourceFiles = ['fileB.cc', sourceTarget]
cmdNode = env.Command(target = sourceTarget,
source = externalSourceFile,
action = Copy('$TARGET', '$SOURCE'))
libNode = env.Library(target = 'moduleB', source = sourceFiles)
And try to use Command like source file. instead filename. It's looks more correct.
moduleA :
conf2ccNode = env.Command(target = sourceFile,
source = scriptInput,
action = cmd)
libNode = env.Library(target = 'moduleA', source = conf2ccNode)
moduleB:
cmdNode = env.Command(target = sourceTarget,
source = externalSourceFile,
action = Copy('$TARGET', '$SOURCE'))
libNode = env.Library(target = 'moduleB', source = ['fileB.cc', cmdNode])
I found a solution to the problem, but I dont really understand why it works.
If I add a call to env.Default() with the targets I need built, then it works. So the SConscript files would then look like this:
moduleA/Sconscript
import os
Import('env')
scriptInput = '#file.conf'
sourceFile = os.path.join('#moduleA', env['variantDir'], 'source.cc')
conf2ccScript = File('#moduleA/conf2cc').abspath
# The script needs abspaths for input and output, not the scons '#' prepended
# the script syntax is: script <inputFile> <outputFile>
cmd = '%s %s %s' % (conf2ccScript, File(scriptInput).abspath, File(sourceFile).abspath)
# Generate source.cc file based on file.conf
conf2ccNode = env.Command(target = sourceFile,
source = scriptInput,
action = cmd)
libNode = env.Library(target = 'moduleA', source = sourceFile)
env.Depends(libNode, conf2ccNode)
env.Default([conf2ccNode, libNode])
moduleB/Sconscript
import os
Import('env')
sourceFiles = ['fileB.cc', 'source.cc']
# Get the source.cc file
externalSourceFile = os.path.join('#moduleA', env['variantDir'], 'source.cc')
sourceTarget = os.path.join('#moduleB', 'source.cc')
cmdNode = env.Command(target = sourceTarget,
source = externalSourceFile,
action = Copy('$TARGET', '$SOURCE'))
libNode = env.Library(target = 'moduleB', source = sourceFiles)
env.Depends(libNode, cmdNode)
env.Default(cmdNode, libNode)
So that leads to the question: If I dont specify Default() targets and there is more than one target, how does scons know which one to build?
Also, I still dont understand why scons doesnt resolve the dependancy in moduleB/SConscript that libNode has on the cmdNode.
My solution:
def CreateLibrary(env, name, sources, shared=True):
def GetObjectFile(sourceFileName):
def GetFileNameWithoutExtension(path):
return os.path.splitext(os.path.basename(path))[0]
def IsFileNameExist(newFileName):
return fileNames.count(newFileName) > 0
sourceAbsPath = os.path.abspath(sourceFileName)
fileNameWithoutExtension = GetFileNameWithoutExtension(sourceAbsPath)
destFileName = fileNameWithoutExtension
attemptNumber = 0
while IsFileNameExist(destFileName):
attemptNumber += 1
destFileName = fileNameWithoutExtension + str(attemptNumber)
fileNames.append(destFileName)
destFilePath = os.path.join(compilationDirRoot, destFileName)
if shared:
return env.SharedObject(destFilePath, sourceAbsPath)
else:
return env.StaticObject(destFilePath, sourceAbsPath)
objFiles = []
fileNames = []
compilationDirRoot = Dir('.').abspath
for src in sources:
if isinstance(src,str):
objFiles.append(GetObjectFile(src))
elif isinstance(src, SCons.Node.FS.File):
objFiles.append(GetObjectFile(SCons.Node.FS.File.rstr(src)))
else:
for f in src:
objFiles.append(GetObjectFile(str(f)))
if shared:
return env.SharedLibrary(name, objFiles, no_import_lib=True)
else:
return env.StaticLibrary(name, objFiles)
Example of use:
theora = CreateLibrary(env, 'theora', sources)
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.