I am trying to build a simple c++ hello world program using g++ with SCons. How can I specify that I want SCons to use g++ without any dependencies on external environment variables, such as PATH?
This is what I've tried:
env = Environment(CXX = 'C:/cygwin/bin/g++')
env.Program('helloworld.c++')
This is my result:
scons: warning: No version of Visual Studio compiler found - C/C++
compilers most likely not set correctly
File "C:\Python27\Scripts\scons.py", line 201, in <module>
C:/cygwin/bin/g++ /Fohelloworld.obj /c helloworld.c++ /TP /nologo
g++: error: /Fohelloworld.obj: No such file or directory
g++: error: /c: No such file or directory
g++: error: /TP: No such file or directory
g++: error: /nologo: No such file or directory
scons: *** [helloworld.obj] Error 1
scons: building terminated because of errors.
Turns out the answer was staring me straight in the face. My first problem was that the first part of this answer:
import os
env = Environment(ENV = {'PATH' : os.environ['PATH']})
utilizes the OS PATH, which I explicitly wanted to avoid. My second problem was that I completely overlooked the answer below, which was the precise answer to my question:
The way to guarantee that the build is repeatable is to explicitly
initialize the PATH
path= ['/bin', '/usr/bin', '/path/to/other/compiler/bin']
env = Environment(ENV = {'PATH' : path})
The reason I didn't realize this was the solution is because I simply misunderstood that env['ENV']['PATH'] and os.environ['PATH'] are completely separate and distinct. Whereas os.environ['PATH'] is obviously the external OS PATH, env['ENV']['PATH'] seems to be SCons' internal equivalent. You can set is to be whatever you please.
In the end, the precise solution I chose, and the one most readable to me was:
PATH = {'PATH' : ['C:/cygwin/bin']}
env = Environment(ENV = PATH)
env['ENV'] = PATH
env['CXX'] = 'g++'
env.Program('helloworld.c++')
A slightly cleaner way
env = Environment(tools=['g++','gnulink'])
env['ENV']['PATH'] = ['C:/cygwin/bin']
env['CXX'] = 'g++'
env.Program('helloworld.c++')
Another way:
env = Environment(tools=['g++','gnulink'])
env.PrependENVPath('PATH','C:/cygwin/bin')
env.Program('helloworld.c++')
Try this:
env = Environment(tools=['ar', 'cc', 'clang', 'clangxx', 'gcc', 'g++', 'gnulink', 'link'], ENV=os.environ, toolpath=['custom_path']).
The command above will:
Create a variable env of type Environment.
Tells scons to set up requires tools.
Find these tools in system variable.
Else find in custom path(you can omit the last parameter: toolpath=['custom_path'] if you don't need it).
Where:
ar: Sets construction variables for the ar library archiver.
Sets: $AR, $ARCOM, $ARFLAGS, $LIBPREFIX, $LIBSUFFIX, $RANLIB, $RANLIBCOM, $RANLIBFLAGS.
cc: Sets construction variables for generic POSIX C compilers.
Sets: $CC, $CCCOM, $CCFLAGS, $CFILESUFFIX, $CFLAGS, $CPPDEFPREFIX, $CPPDEFSUFFIX,$FRAMEWORKPATH, $FRAMEWORKS, $INCPREFIX, $INCSUFFIX, $SHCC, $SHCCCOM, $SHCCFLAGS,$SHCFLAGS, $SHOBJSUFFIX.
clang: Set construction variables for the Clang C compiler.
Sets: $CC, $CCVERSION, $SHCCFLAGS.
clangxx: Set construction variables for the Clang C++ compiler.
Sets: $CXX, $CXXVERSION, $SHCXXFLAGS, $SHOBJSUFFIX,$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME.
g++: Set construction variables for the gXX C++ compiler.
Sets: $CXX, $CXXVERSION, $SHCXXFLAGS, $SHOBJSUFFIX.
gcc: Set construction variables for the gcc C compiler.
Sets: $CC, $CCVERSION, $SHCCFLAGS.
gnulink: Set construction variables for GNU linker/loader
Sets: $LDMODULEVERSIONFLAGS, $RPATHPREFIX, $RPATHSUFFIX, $SHLIBVERSIONFLAGS,$SHLINKFLAGS, $_LDMODULESONAME, $_SHLIBSONAME.
link: Sets construction variables for generic POSIX linkers. This is a "smart" linker tool which selects a compiler tocomplete the linking based on the types of source files.
Sets: $LDMODULE, $LDMODULECOM, $LDMODULEFLAGS, $LDMODULENOVERSIONSYMLINKS,$LDMODULEPREFIX, $LDMODULESUFFIX, $LDMODULEVERSION, $LDMODULEVERSIONFLAGS,$LIBDIRPREFIX, $LIBDIRSUFFIX, $LIBLINKPREFIX, $LIBLINKSUFFIX, $LINK,$LINKCOM, $LINKFLAGS, $SHLIBSUFFIX, $SHLINK, $SHLINKCOM, $SHLINKFLAGS,$__LDMODULEVERSIONFLAGS, $__SHLIBVERSIONFLAGS.Uses: $LDMODULECOMSTR, $LINKCOMSTR, $SHLINKCOMSTR
Or you can use default config tools for your system by:
env = Environment(tools=['default'], ENV=os.environ)
To quote from scons man 4.1.0
default
Sets construction variables for a default list of Tool modules. Use
default in the tools list to retain the original defaults, since the
tools parameter is treated as a literal statement of the
tools to be made available in that construction environment, not
an addition.
The list of tools selected by default is not static, but
is dependent both on the platform and on the software installed on the
platform. Some tools will not initialize if an underlying command is
not found, and some tools are selected from a list of choices on
a first-found basis. The finished tool list can be examined
by inspecting the TOOLS construction variable in the construction
environment.
On all platforms, all tools from the following list are
selected whose respective conditions are met: filesystem,wix, lex,
yacc, rpcgen, swig, jar, javac, javah, rmic, dvipdf, dvips, gs, tex,
latex, pdflatex, pdftex, tar, zip, textfile.
On Linux systems, the
default tools list selects (first-found): a C compiler from gcc,
intelc, icc, cc; a C++ compilerfrom g++, intelc, icc, cxx; an
assembler from gas, nasm, masm; a linker from gnulink, ilink; a
Fortran compilerfrom gfortran, g77, ifort, ifl, f95, f90, f77; and a
static archiver 'ar'. It also selects all found from the list m4,
rpm.
On Windows systems, the default tools list selects
(first-found): a C compiler from msvc, mingw, gcc, intelc,icl,
icc, cc, bcc32; a C++ compiler from msvc, intelc, icc, g++, cxx,
bcc32; an assembler from masm, nasm, gas,386asm; a linker from mslink,
gnulink, ilink, linkloc, ilink32; a Fortran compiler from gfortran,
g77, ifl, cvf, f95,f90, fortran; and a static archiver from mslib, ar,
tlib; It also selects all found from the list msvs, midl.
On MacOS
systems, the default tools list selects (first-found): a C compiler
from gcc, cc; a C++ compiler from g++, cxx; an assembler 'as'; a
linker from applelink, gnulink; a Fortran compiler from gfortran, f95,
f90, g77; anda static archiver ar. It also selects all found from the
list m4, rpm.
Default lists for other platforms can be found by
examining the scons source code (see SCons/Tool/init.py).
This question is subsequent to my previous one: How to integrate such kind of source generator into CMake build chain?
Currently, the C source file is generated from XS in this way:
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${file_src_by_xs} PROPERTIES GENERATED 1)
add_custom_target(${file_src_by_xs}
COMMAND ${XSUBPP_EXECUTABLE} ${XSUBPP_EXTRA_OPTIONS} ${lang_args} ${typemap_args} ${file_xs} >${CMAKE_CURRENT_BINARY_DIR}/${file_src_by_xs}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${file_xs} ${files_xsh} ${_XSUBPP_TYPEMAP_FILES}
COMMENT "generating source from XS file ${file_xs}"
)
The GENERATED property let cmake don't check the existence of this source file at configure time, and add_custom_target let the xsubpp always re-run at each compile. The reason for always rerun is because xsubpp will generate an incomplete source file even if it fails, so there are possibility that the whole compiling continues with an incomplete source file.
I found it is time consuming to always re-run source generator and recompile it. So I want to have it re-run only when dependent XS files are modified. However, if I do so, the incomplete generated source file must be deleted.
So my question is: is there any way to remove the generated file, only when the program exit abnormally at compile time?
Or more generic: is there any way to run a command depending on another command's exit status at compile time?
You can always write a wrapper script in your favorite language, e.g. Perl or Ruby, that runs xsubpp and deletes the output file if the command failed. That way you can be sure that if it exists, it is correct.
In addition, I would suggest that you use the OUTPUT keyword of add_custom_command to tell CMake that the file is a result of executing the command. (And, if you do that, you don't have to set the GENERATED property manually.)
Inspired by #Lindydancer's answer, I achieved the purpose by multiple COMMANDs in one target, and it don't need to write an external wrapper script.
set(source_file_ok ${source_file}.ok)
add_custom_command(
OUTPUT ${source_file} ${source_file_ok}
DEPENDS ${xs_file} ${xsh_files}
COMMAND rm -f ${source_file_ok}
COMMAND xsubpp ...... >${source_file}
COMMAND touch ${source_file_ok}
)
add_library(${xs_lib} ${source_file})
add_dependencies(${xs_lib} ${source_file} ${source_file_ok})
The custom target has 3 commands. The OK file only exists when xsubpp is success, and this file is added as a dependency of the library. When xsubpp is not success, the dependency on the OK file will force the custom command to be run again.
The only flaw is cross-platform: not all OS have touch and rm, so the name of these two commands should be decided according to OS type.
I hope the title clarifies what I want to ask because it is a bit tricky.
I have a SCONS SConscript for every subdir as follows (doing it in linux, if it matters):
src_dir
compiler
SConscript
yacc srcs
scripts
legacy_script
data
SConscript
data files for the yacc
I use a variant_dir without copy, for example:
SConscript('src_dir/compiler/SConscript', variant_dir = 'obj_dir', duplicate = 0)
The resulting obj_dir after building the yacc is:
obj_dir
compiler
compiler_compiler.exe
Now here is the deal.
I have another SConscript in the data dir that needs to do 2 things:
1. compile the data with the yacc compiled compiler
2. Take the output of the compiler and run it with the legacy_script I can't change
(the legacy_script, takes the output of the compiled data and build some h files for another software to depend on)
number 1 is acheived easily:
linux_env.Command('[output1, output2]', 'data/data_files','compiler_compiler.exe data_files output1 output2')
my problem is number 2: How do I make the script runner depend on outputs of another target
And just to clarify it, I need to make SCONS run (and only if compiler_output changes):
src_dir/script/legacy_script obj_dir/data/compiler_output obj_dir/some_dir/script_output
(the script is usage is: legacy_script input_file output_file)
I hope I made myself clear, feel free to ask some more questions...
I've had a similar problem recently when I needed to compile Cheetah Templates first, which were then used from another Builder to generate HTML files from different sources.
If you define the build output of the first builder as source for the second builder, SCons will run them in the correct order and only if intermediate files have changed.
Wolfgang
Does the objective-c compiler in Xcode know better, or is it faster if I use bit shift for multiplications and divisions by powers of 2?
NSInteger parentIndex = index >> 1; // integer division by 2
Isn't this a bit 1980's? Don't processors run these instructions in the same time these days? I remember back in my 68000 days when a div was 100+ cycles and a shift only 3 or 4... not sure this is the case any more as processors have moved on.
Why don't you get the compiler to generate the assembler file and have a look what it's generating and run some benchmarks.
I found this on the web which may help you... although it's for 'C' I think most of the options will be the same.
Q: How can I peek at the assembly code generated by GCC?
Q: How can I create a file where I can see the C code and its assembly
translation together?
A: Use the -S (note: capital S) switch to GCC, and it will emit the assembly code to a file with a .s extension. For example, the following command:
gcc -O2 -S -c foo.c
will leave the generated assembly code on the file foo.s.
If you want to see the C code together with the assembly it was converted to, use a command line like this:
gcc -c -g -Wa,-a,-ad [other GCC options] foo.c > foo.lst
which will output the combined C/assembly listing to the file foo.lst.
If you need to both get the assembly code and to compile/link the program, you can either give the -save-temps option to GCC (which will leave all the temporary files including the .s file in the current directory), or use the -Wa,aln=foo.s option which instructs the assembler to output the assembly translation of the C code (together with the hex machine code and some additional info) to the file named after the =.
I have a plist that is processed with a precompiled header file and in it there is the "variable" VERSION_STRING used a few times in such fields as CFBundleGetInfoString, ie the value for the key CFBundleGetInfoString is: MyProduct VERSION_STRING Copyright © 2009 MyCorp
In MyHeader.h (which is the set as the Info.plist prefix header I would like to be able to build VERSION_STRING into the form MAJOR.MINOR.PATCH.BUILD where I have
#define MAJOR 1
#define MINOR 0
#define PATCH 0
#define BUILD 23
For some reason I seem to be incapable of doing this. I might just be having one of those moments
Turns out there is actually an Apple Tech Note on this and a solution to the very problem I was having. So, for anyone that may come across this and is having the same problems I was check out Technical Note TN2175: Preprocessing Info.plist files in Xcode Using the C Preprocessor
Take your plist file and rename it with an extra extension (perhaps a P?). Add #include "MyHeader.h" to the beginning of the file, and preprocess it in your build with the C preprocessor (usually cpp). You may need to filter out extra # lines, but I don't see why it wouldn't work.
By default, cpp should output to stdout, so adding a command like this might work fine:
cpp myplist.plist.P | grep -v '^#' > myplist.plist