Scons compiler path contains spaces - scons

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")
)

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)])

vim youcompleteme can't find cstdint

I've encountered a problem trying to set up a C++ project on my Mac (Yosemite with Xcode 6) using CMake with Unix style Makefiles and vim with the youcompleteme plugin (I'm a Linux veteran and Mac newbie so I prefer this setup to Xcode). The code builds and runs but youcompleteme throws some bogus errors which I think boil down to it not being able to find the <cstdint> header.
I've just tried it on Linux too, and had the same problem.
I've configured .ycm_extra_conf.py to use a compile_commands.json generated by cake. The "command" lines in compile_commands.json use these flags:
"command": "/usr/bin/c++ -std=c++11 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks -I/usr/local/include -I/Users/tony/Dev/cow/jni -I/Users/tony/Library/Frameworks/SDL2.framework/Headers -Wall -Wextra -Wunused -F/Users/tony/Library/Frameworks -o ...
There doesn't seem to be an explicit reference there to any directory containing stdint as a direct parent.
Is there a way I can get youcompleteme to do its stuff with libclang in such a way that it can find the directory implicitly, which seems to work when running c++ on the command line? Or what's the best way to get cmake to add an appropriate system header path without hardwiring it? I want my CMakeLists.txt to be portable and to be able to cope with toolchain upgrades.
My .ycm_extra_conf.py was pretty much a copy of the supplied example modified slightly to find compile_commands.json where I put it.
As #ladislas said, YCM needs to be explicitly pointed to all relevant include directories as libclang won't use the same implicit location a normal compiler driver invocation (i.e. clang++ from the command line) would use.
What I usually do, on OSX, is to let YCM know about Xcode's libc++ headers with something like (in .ycm_extra_conf.py):
import os
import ycm_core
import subprocess
xcode_cpp11headers = subprocess.Popen("xcode-select -p", stdout = subprocess.PIPE, shell=True).communicate()[0].rstrip('\n') + '/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1'
.
.
flags = [
.
.
'-isystem',
xcode_cpp11headers,
.
.
]
The "xcode_cpp11headers" variable is populated with the proper path depending on the location of your current Xcode's installation, and you can change it accordingly if you want to use say the commandline-tools version of libc++ (i.e. the includes are in /Library/Developer/CommandLineTools/usr/include/c++/v1) or a source distribution of libc++ if you have compiled your own.
Of course this is platform dependant and either you provide a platform specific .ycm_extra_conf.py alongside your project, or you can populate that variable differently with some extra python code accordingly to the current platform.
You must add all the paths where YCM needs to look for your sources, libraries, and so on.
It does not work recursively, so it's a little bit cumbersome at first but is should not change once set for your project.
As an example, here is mine for an Arduino project :
https://github.com/ladislas/Bare-Arduino-Project/blob/master/.ycm_extra_conf.py#L21
Hope this helps!
EDIT - 2015/01/08
The solution of #abigagli is very elegant! I too use something like this to parse my lib directory and look for .h files to add their path to flags.
Here it is if it can be useful :) http://git.io/IiR1JA
As I found out from the above answers, YCM needs to be told the compiler's system include paths which are usually implicit in other ways of using the compiler. I added a function GetSystemIncludePaths() to .ycm_extra_conf.py to discover and cache these paths portably. Here's the full file with comments and irrelevant content of flags list snipped. The original is Copyright (C) 2014 Google Inc with a GPL2+ licence:
import subprocess, os
import ycm_core
flags = []
def DirectoryOfThisScript():
return os.path.dirname( os.path.abspath( __file__ ) )
compilation_database_folder = os.path.abspath(
os.path.join(DirectoryOfThisScript(), 'build-make'))
if os.path.exists( compilation_database_folder ):
database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
database = None
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
if not working_directory:
return list( flags )
new_flags = []
make_next_absolute = False
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
for flag in flags:
new_flag = flag
if make_next_absolute:
make_next_absolute = False
if not flag.startswith( '/' ):
new_flag = os.path.join( working_directory, flag )
for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break
if flag.startswith( path_flag ):
path = flag[ len( path_flag ): ]
new_flag = path_flag + os.path.join( working_directory, path )
break
if new_flag:
new_flags.append( new_flag )
return new_flags
def IsHeaderFile( filename ):
extension = os.path.splitext( filename )[ 1 ]
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
def GetCompilationInfoForFile( filename ):
if IsHeaderFile( filename ):
basename = os.path.splitext( filename )[ 0 ]
for extension in SOURCE_EXTENSIONS:
replacement_file = basename + extension
if os.path.exists( replacement_file ):
compilation_info = database.GetCompilationInfoForFile(
replacement_file )
if compilation_info.compiler_flags_:
return compilation_info
return None
return database.GetCompilationInfoForFile( filename )
def GetSystemIncludePaths():
cache = os.path.join(DirectoryOfThisScript(), ".ycm_sys_incs")
if os.path.exists(cache):
fp = open(cache, 'r')
flags = fp.readlines()
fp.close()
flags = [s.strip() for s in flags]
else:
devnull = open(os.devnull, 'r')
child = subprocess.Popen(["/usr/bin/cpp", "-xc++", "-v"],
stdin = devnull, stderr = subprocess.PIPE)
output = child.communicate()[1].split('\n')
devnull.close()
flags = []
status = 0
for l in output:
l = l.strip()
if l == '#include "..." search starts here:':
status = 1
elif l == '#include <...> search starts here:':
status = 2
elif status:
if l == 'End of search list.':
break
elif l.endswith('(framework directory)'):
continue
elif status == 1:
flags.append('-I')
elif status == 2:
flags.append('-isystem')
flags.append(os.path.normpath(l))
fp = open(cache, 'w')
fp.write('\n'.join(flags))
fp.close()
return flags
def FlagsForFile( filename, **kwargs ):
if database:
compilation_info = GetCompilationInfoForFile( filename )
if not compilation_info:
return None
final_flags = MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_ )
sys_incs = GetSystemIncludePaths()
if sys_incs:
final_flags += sys_incs
else:
relative_to = DirectoryOfThisScript()
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
return {
'flags': final_flags,
'do_cache': True
}

How to change build directory in scons by using renesas compiler

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')

Using scons with Keil compiler/linker

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'

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