From 592c858e4c6be43b91a80264da4f2c87a26c07c6 Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Mon, 13 Aug 2012 17:29:58 +0100 Subject: [PATCH] Compile everything at once with --release --- SConscript | 26 +- site_scons/site_tools/mfprogram/__init__.py | 236 +++++++++++++++++++ site_scons/site_tools/mfprogram/__init__.pyc | Bin 0 -> 7254 bytes site_scons/site_tools/mfprogram/relpath.py | 73 ++++++ 4 files changed, 325 insertions(+), 10 deletions(-) create mode 100644 site_scons/site_tools/mfprogram/__init__.py create mode 100644 site_scons/site_tools/mfprogram/__init__.pyc create mode 100644 site_scons/site_tools/mfprogram/relpath.py diff --git a/SConscript b/SConscript index 56cb640ed..cb2f1b48f 100644 --- a/SConscript +++ b/SConscript @@ -52,9 +52,9 @@ if((not GetOption('lin')) and (not GetOption('win')) and (not GetOption('macosx' raise SystemExit(1) if(GetOption('win')): - env = Environment(tools = ['mingw', 'gch'], ENV = os.environ) + env = Environment(tools = ['mingw', 'gch', 'mfprogram'], ENV = os.environ) else: - env = Environment(tools = ['default', 'gch'], ENV = os.environ) + env = Environment(tools = ['default', 'gch', 'mfprogram'], ENV = os.environ) if GetOption("toolprefix"): env['CC'] = GetOption("toolprefix")+env['CC'] @@ -166,9 +166,6 @@ if(GetOption('save-version')): if(GetOption('minor-version')): env.Append(CPPDEFINES=['MINOR_VERSION=' + GetOption('minor-version')]) -if(GetOption('release')): - env.Append(CCFLAGS=['-O3', '-ftree-vectorize', '-funsafe-math-optimizations', '-ffast-math', '-fomit-frame-pointer', '-funsafe-loop-optimizations', '-Wunsafe-loop-optimizations']) - if(GetOption('x86')): env.Append(CPPDEFINES='X86') @@ -231,11 +228,20 @@ if(GetOption('macosx')): if(GetOption('win')): programName += ".exe" -env.Command(['generated/ElementClasses.cpp', 'generated/ElementClasses.h'], Glob('src/simulation/elements/*.cpp'), "python generator.py elements $TARGETS $SOURCES") -env.Command(['generated/ToolClasses.cpp', 'generated/ToolClasses.h'], Glob('src/simulation/tools/*.cpp'), "python generator.py tools $TARGETS $SOURCES") -env.Decider('MD5') -t=env.Program(target=programName, source=sources) -Default(t) +if(GetOption('release')): + env.Append(CCFLAGS=['-O3', '-ftree-vectorize', '-funsafe-math-optimizations', '-ffast-math', '-fomit-frame-pointer', '-funsafe-loop-optimizations', '-Wunsafe-loop-optimizations']) + #env.Command(programName, sources, "gcc -o $TARGETS $SOURCES") + env.Decider('MD5') + env.Command(['generated/ElementClasses.cpp', 'generated/ElementClasses.h'], Glob('src/simulation/elements/*.cpp'), "python generator.py elements $TARGETS $SOURCES") + env.Command(['generated/ToolClasses.cpp', 'generated/ToolClasses.h'], Glob('src/simulation/tools/*.cpp'), "python generator.py tools $TARGETS $SOURCES") + t=env.MFProgram(target=programName, source=sources) + Default(t) +else: + env.Command(['generated/ElementClasses.cpp', 'generated/ElementClasses.h'], Glob('src/simulation/elements/*.cpp'), "python generator.py elements $TARGETS $SOURCES") + env.Command(['generated/ToolClasses.cpp', 'generated/ToolClasses.h'], Glob('src/simulation/tools/*.cpp'), "python generator.py tools $TARGETS $SOURCES") + env.Decider('MD5') + t=env.Program(target=programName, source=sources) + Default(t) #if(GetOption('release')): # StripExecutable(t); diff --git a/site_scons/site_tools/mfprogram/__init__.py b/site_scons/site_tools/mfprogram/__init__.py new file mode 100644 index 000000000..2d94ac29c --- /dev/null +++ b/site_scons/site_tools/mfprogram/__init__.py @@ -0,0 +1,236 @@ +# +# Copyright (c) 2010 Western Digital Corporation +# Alan Somers asomers (at) gmail (dot) com +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +#### +import os +import new +import sys +## +import SCons + +if sys.version_info < (2,6,0): + from relpath import relpath +else: + from os.path import relpath + + +def sc_relpath(src, destdir): + """Like relpath but aware of SCons convention regarding '#' in pathnames""" + if src[0] == '#': + return relpath(src[1:], destdir) + else: + return relpath(os.path.join(destdir, src), destdir) + + + +class MF_Executor(SCons.Executor.Executor): + """Custom Executor that can scan each target file for its dependencies + individually, rather than giving every target the same deps. + Assumes that there is a one-to-one relationship between sources and targets + and the targets have the same basenames as their respective sources + ie. [[foo.o, bar.o], [foo.c, bar.c]]""" + def scan(self, scanner, node_list): + tgt_names = [os.path.splitext( + os.path.basename(str(i)))[0] for i in self.targets] + env = self.get_build_env() + + if scanner: + for node in node_list: + tgt = \ + self.targets[tgt_names.index( + os.path.splitext( + os.path.basename(str(node)))[0])] + node.disambiguate() + s = scanner.select(node) + if not s: + continue + path = self.get_build_scanner_path(s) + tgt.add_to_implicit(node.get_implicit_deps(env, s, path)) + else: + kw = self.get_kw() + for node in node_list: + tgt = \ + self.targets[tgt_names.index( + os.path.splitext( + os.path.basename(str(node)))[0])] + node.disambiguate() + scanner = node.get_env_scanner(env, kw) + if not scanner: + continue + scanner = scanner.select(node) + if not scanner: + continue + path = self.get_build_scanner_path(scanner) + tgt.add_to_implicit(node.get_implicit_deps(env, scanner, path)) + + +def MF_get_single_executor(self, env, tlist, slist, executor_kw): + if not self.action: + raise UserError, "Builder %s must have an action to build %s." % \ + (self.get_name(env or self.env), map(str,tlist)) + return MF_Executor(self.action, env, [], tlist, slist, executor_kw) + +def exists(env): + return env.WhereIs(env.subst['$CC']) or env.WhereIs(env.subst['$CXX']) + +def MFProgramEmitter(target, source, env): + """Ensures that target list is complete, and does validity checking. Sets precious""" + if len(target) == 1 and len(source) > 1: + #Looks like the user specified many sources and SCons created 1 target + #targets are implicit, but the builder doesn't know how to handle + #suffixes for multiple target files, so we'll do it here + objdir = env.get('OBJDIR', '') + #target = [os.path.join( + # objdir, + # os.path.splitext( + # os.path.basename(str(i)))[0] + '.o' ) for i in source] + elif len(source) == 1 and 'OBJDIR' in env: + target = os.path.join( + env['OBJDIR'], + os.path.splitext( + os.path.basename(str(source[0])))[0] + '.o' ) + else: + #targets are explicit, we need to check their validity + tgt_names = [os.path.splitext( + os.path.basename(str(i)))[0] for i in target] + src_names = [os.path.splitext( + os.path.basename(str(i)))[0] for i in source] + tgt_dirs = [os.path.dirname(str(i)) for i in target] + if sorted(tgt_names) != sorted(src_names): + raise ValueError, "target files do not have obvious one-one relationship to source files" + if len(set(src_names)) != len(src_names): + raise ValueError, "source files may not include identically named files in different directories" + if len(set(tgt_dirs)) != 1: + raise ValueError, "Target files must all be in same directory" + + for t in target: + env.Precious(t) + return target, source + +def MFProgramGenerator(source, target, env, for_signature): + #Rebuild everything if + # a) the number of dependencies has changed + # b) any target does not exist + # c) the build command has changed + #Else rebuild only those c files that have changed_since_last_build + #The signature of this builder should always be the same, because the + #multifile compile is always functionally equivalent to rebuilding + #everything + + if for_signature: + pared_sources = source + else: + #First a sanity check + assert len(set([os.path.splitext(str(i))[1] for i in source])) == 1, \ + "All source files must have the same extension." + pared_sources = [] + src_names = [os.path.splitext(os.path.basename(str(i)))[0] + for i in source] + tgt_names = [os.path.splitext(os.path.basename(str(t)))[0] + for t in target] + ni = target[0].get_binfo() + oi = target[0].get_stored_info().binfo + if ni.bactsig != oi.bactsig: + #Command line has changed + pared_sources = source + else: + for i in range(len(tgt_names)): + t = target[i] + tgt_name = tgt_names[i] + if not t.exists(): + #a target does not exist + pared_sources = source + break + bi = t.get_stored_info().binfo + then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs + children = t.children() + if len(children) != len(then): + #the number of dependencies has changed + pared_sources = source + break + for child, prev_ni in zip(children, then): + if child.changed_since_last_build(t, prev_ni) and \ + not t in pared_sources: + #If child is a source file, not an explicit or implicit + #dependency, then it is not truly a dependency of any target + #except that with the same basename. This is a limitation + #of SCons.node, which assumes that all sources of a Node + #are dependencies of all targets. So we check for that case + #here and only rebuild as necessary. + src_name = os.path.splitext(os.path.basename(str(child)))[0] + if src_name not in tgt_names or src_name == tgt_name: + s = source[src_names.index(tgt_name)] + pared_sources.append(s) + assert len(pared_sources) > 0 + destdir = str(target[0].dir) + #finding sconscript_dir is a bit of a hack. It assumes that the source + #files are always going to be in the same directory as the SConscript file + #which is not necessarily true. BUG BY Alan Somers + sconscript_dir = os.path.dirname(str(pared_sources[0])) + prefixed_sources = [relpath(str(i), destdir) for i in pared_sources] + prefixed_sources_str = ' '.join([str(i) for i in prefixed_sources]) + lang_ext = os.path.splitext(prefixed_sources[0])[1] + tgt_names2 = [os.path.splitext(os.path.basename(str(t)))[0] + for t in target] + + _CPPPATH = [] + if 'CPPPATH' in env: + for i in env['CPPPATH']: + #if i[0] == '#': + ##_CPPPATH.append(relpath(i[1:], destdir)) + _CPPPATH.append(i) + #else: + # _CPPPATH.append(relpath(os.path.join(sconscript_dir, i), + # destdir)) + _CPPINCFLAGS = ['-I' + i for i in _CPPPATH] + _CCOMCOM = '$CPPFLAGS $_CPPDEFFLAGS %s' % ' '.join(_CPPINCFLAGS) + + libstr = "" + for t in env['LIBS']: + libstr += ("-l"+t+" ") + + if lang_ext == '.c' : + _CCCOM = 'cd %s && $CC $CFLAGS $CCFLAGS %s %s $LINKFLAGS %s -o %s' % \ + (destdir, _CCOMCOM, prefixed_sources_str, libstr, tgt_names2[0]) + #XXX BUG BY Alan Somers. $CCCOMSTR gets substituted using the full list of target files, + #not prefixed_sources + cmd = SCons.Script.Action(env.subst(_CCCOM), "$CCCOMSTR") + elif lang_ext in ['.cc', '.cpp']: + _CXXCOM = 'cd %s && $CXX $CXXFLAGS $CCFLAGS %s %s $LINKFLAGS %s -o %s' % \ + (destdir, _CCOMCOM, prefixed_sources_str, libstr, tgt_names2[0]) + cmd = SCons.Script.Action(env.subst(_CXXCOM), "$CXXCOMSTR") + else: + assert False, "Unknown source file extension %s" % lang_ext + return cmd + +def generate(env): + """Adds the MFObject builder to your environment""" + MFProgramBld = env.Builder(generator = MFProgramGenerator, + emitter = MFProgramEmitter, + suffix = '.o', + source_scanner=SCons.Tool.SourceFileScanner) + MFProgramBld.get_single_executor = new.instancemethod(MF_get_single_executor, + MFProgramBld, MFProgramBld.__class__) + + env.Append(BUILDERS = {'MFProgram': MFProgramBld}) \ No newline at end of file diff --git a/site_scons/site_tools/mfprogram/__init__.pyc b/site_scons/site_tools/mfprogram/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..edc9a1b4b33abcb9dea44a6198591957ea1ebd26 GIT binary patch literal 7254 zcmcIpOK%*<5$>K{F1ZvbQldnPk}QoZT3*Exl?UQS>^Pw)%8@P6#8Nh8*~)l0GbCrZ zoLNrK@?q=(L6l<<I+Dbh@$-vhnHAQJap+E~(r$Rn*0vR*xOEjD}pR7WP|FXu^237JXqA91M`u0*brw zX5_U&a?>?;c|J{y8>Gojl;m-mVAQ&wg>ka(K7aXnH%?qKnD|?f5#F(& zQkP?viw&~d#G`UDpPHNv950nt8Yc~QA0nvc+3=v2>Ku@M&;6Ssuk5-mhG4Y z44v(1Uf19(NXN_yfjMKkI2_9WXGd;qT;ENT z=z5-B#}^OY=h>Q#xZ|!y`EC?}&$OEbnCB;9LESPW?^woiZ`=)k2QTHitG%;laC}_W9VRaH0T5c5NN;~C ztRCHk?fOaC1qosoB7`s41qL7P;#0K}Dj*Hbe9?j%VNWc*(4Z#!nmp-z2!-jiVaj{C zyp-x>5hBm>QH+4mc&pvG9ePo+gQEs&!esXH5!AvM>c1MVcl|udY1AfaL;3Q_C+5)x zlPL29ipY;2hF+d}@fH>j;ygc53@;lz+LO@Z;+wlUC$S0+fI330K}8i{!1McSC^WNNGT~3^rCel+)(!(*#DYPM*KZ@0U?1UD2=V z5vQg{oe^Evm-Vn7(>45$>C0$2Y&}`D+CD*kIYCc0=y?LVp0|~T-FAdmTD0edY2bNH z7xlw!Jsr?*Qnzm4G2CQrpr!+A4j=XixV(!B;Q@obN8<->@Kt8!F z=BUY^I9;{ud+A zKii;?MC)v)=*&AN$`-OL%|yJ^L26L*9EZ|~w){?$mLMAz58tHn+X38eE=tInks8%D zDx4iu`|u#Xe#c8j;9AMFf$xGMlnXx~J3I&lEvxAlbU=5@hsPzS^9@uA0pn2Qbf$r$ zovTl_I*P5!4a#ECu$-BnmqVYKfAGM@8pKun7E00ZXV zs2SR{(&Fa`5`1K{|G?I5JcrFd4;kUTA}ysy+pMw$T1HVI2!Un-#49S<)tq=R3=@CN z0T{ViV;!*=;z5MKXhHjQ@jg&?)QHZQj|h>Hv>(2N18RzE0HG!{HN5b^um(%=GbEt; zN2k*R|CU~tQ?+&8Ut#J$>GjH0FVK@0s}2djMINx`JjVRcJ0nNJZ za)hX{lSM(Cc8!GH0vK=KeDl_wCN@-DDMZm`QwjEu#GME@Q#VNq6iQcjNJT=!&&7oR zCL6v^B$+2;#Lth;|NGIgBNm#Es@K3j&-#qBtF_NNz+* z1}GYZ;+o#|+ug|GDruR>1|Um?WaZ3cj+I_9oguPCR@!yC+5+|FG}k+eLhu^*n!?8u z-stf$#)x0fpC-_ZW3_v?aaZE?XJHFLO_co?Z6apn%v4VgTmaS%;<;X_=$GN?Uk2`; z(Iff-9(+5a`h*TBM;8wFeWWbgyM_nJloN(d2~2k~2v8rohmAON`|Ai!r0 zkb}ry!g}*=L1Bs41GFA22Jje>03GF+n&Qj2n(B|rs1tG}I4;W_7m&kj5VWxLyCXFB zK34fj)kC0W!(^1nKq0*_VByS+A!xiHcTQGXM4>oYEI<0yq`L4I$bhbay_^fPS(JK_3U^q?_uFbR@ z=)_Nf-Z<;x940xfKT)3Ql=LB!gX2dB`%a1GRI$r*qB&;{Ri!t_SxH{*=u9>WVg8>7U`${!; zx=zw(6mP2MnWDl;PhrB;OBk~K=gLZNiuo#@-1#cq{SYxdkLdm{_(#6kFx+s*O+LjUy`hqh1Rbm5F zXG-Gi-Uay2Q-GpH@pWbv)j4>GCq2NP*4ZGCsC72zbZ{Mcg7kw2p#9*% z|4p54kP`~>E?(bBHj{L>O!L?z)Paz|kES~EXckD5GeNzbho ziKKYl*ms*Y!)PNJg4OcgE-m!C!3OSBj5xTXkK#^#MjA;r zAUcnDamT}SN~VlYniufWWEdkSD5+H05#yDd(FA6##e0X0<+Q`kHhKnG8q#e;wz%Hq z5?z(dnQu!Ut%^n`DI31rS+o{X^g>VZ5mB~dT+K46dSV}P7{OL38}Y1CKg~GmB=&L; zN4*gtZRA5`CjlU42VH8ort6hklKm*7sBt}^PdasH8rhOz$(~e^FPUOgg-l9SpVue# z$Y298)`ULCvU*-O@PC#u7)Fff6O~idXY>T>C-fxpEERpWatZDD)|Z?KdpqXg6E`F( z`w$g)+?M<%z}$sH-vyTikcX#%)Ntc#!JnuqGJTLI^P7lAB(=w=Lw+Lg;21yzzg^T6 z0G6J2P`&tAX$@ymTwJKtb73gyUH9JYw^x~rw@C}8rc-wxdg~&Y6=!L(1(Pc*zmS}q zTV&%=IabqMgIX0A6svop_+?&AbmHbackbR=Xf6w_gX36i2;vYeinK}-0#MD@S@41- zR&XCb1xQA3S?JzIzJ1xI>_nH6XjfK^6O;P@0^AKY(y+-~jjZN*0ieMkXElMQFUVcU zF6IO&1U0Q?ld}UxZ??mysiU;Fb*q}u4mFbirkpZUSBExAKIF5%Gck*4F&yDn@iWZ6 zv63VI_-TPYQ_$J|jzdwWW|oQ5ChKxI<&PYaauUG_RNG^a1NjI;4+S8#uRps)DZFMA ijIR?U#g~u3YDSz9$YR17uhi@3uhxH6uhgHdfA~LP{#0-P literal 0 HcmV?d00001 diff --git a/site_scons/site_tools/mfprogram/relpath.py b/site_scons/site_tools/mfprogram/relpath.py new file mode 100644 index 000000000..59e19710f --- /dev/null +++ b/site_scons/site_tools/mfprogram/relpath.py @@ -0,0 +1,73 @@ +#PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +#-------------------------------------------- +# +#1. This LICENSE AGREEMENT is between the Python Software Foundation +#("PSF"), and the Individual or Organization ("Licensee") accessing and +#otherwise using this software ("Python") in source or binary form and +#its associated documentation. +# +#2. Subject to the terms and conditions of this License Agreement, PSF hereby +#grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +#analyze, test, perform and/or display publicly, prepare derivative works, +#distribute, and otherwise use Python alone or in any derivative version, +#provided, however, that PSF's License Agreement and PSF's notice of copyright, +#i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +#Python Software Foundation; All Rights Reserved" are retained in Python alone or +#in any derivative version prepared by Licensee. +# +#3. In the event Licensee prepares a derivative work that is based on +#or incorporates Python or any part thereof, and wants to make +#the derivative work available to others as provided herein, then +#Licensee hereby agrees to include in any such work a brief summary of +#the changes made to Python. +# +#4. PSF is making Python available to Licensee on an "AS IS" +#basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +#IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +#DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +#FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +#INFRINGE ANY THIRD PARTY RIGHTS. +# +#5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +#FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +#A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +#OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. +# +#6. This License Agreement will automatically terminate upon a material +#breach of its terms and conditions. +# +#7. Nothing in this License Agreement shall be deemed to create any +#relationship of agency, partnership, or joint venture between PSF and +#Licensee. This License Agreement does not grant permission to use PSF +#trademarks or trade name in a trademark sense to endorse or promote +#products or services of Licensee, or any third party. +# +#8. By copying, installing or otherwise using Python, Licensee +#agrees to be bound by the terms and conditions of this License +#Agreement. + + + +# Changelog: +# 3-12-2010 Alan Somers Copied verbatim from posixpath.py in Python 2.6.4 + + + +from os.path import * + +def relpath(path, start=curdir): + """Return a relative version of a path""" + + if not path: + raise ValueError("no path specified") + + start_list = abspath(start).split(sep) + path_list = abspath(path).split(sep) + + # Work out how much of the filepath is shared by start and path. + i = len(commonprefix([start_list, path_list])) + + rel_list = [pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return curdir + return join(*rel_list) \ No newline at end of file