Compile everything at once with --release

This commit is contained in:
Simon Robertshaw 2012-08-13 17:29:58 +01:00
parent 074dcd0b42
commit 592c858e4c
4 changed files with 325 additions and 10 deletions

View File

@ -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);

View File

@ -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})

Binary file not shown.

View File

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