2007-06-30 04:41:52 +02:00
|
|
|
# -*- python -*-
|
|
|
|
|
##
|
|
|
|
|
## Buildhelper.py - helpers, custom builders, for SConstruct
|
|
|
|
|
##
|
|
|
|
|
|
2008-03-10 09:28:58 +01:00
|
|
|
# Copyright (C) Lumiera.org
|
|
|
|
|
# 2008, Hermann Vosseler <Ichthyostega@web.de>
|
2007-06-30 04:41:52 +02:00
|
|
|
#
|
|
|
|
|
# This program is free software; you can redistribute it and/or
|
|
|
|
|
# modify it under the terms of the GNU General Public License as
|
2007-07-18 01:45:31 +02:00
|
|
|
# published by the Free Software Foundation; either version 2 of
|
2007-06-30 04:41:52 +02:00
|
|
|
# the License, or (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
2007-07-02 05:27:20 +02:00
|
|
|
import os
|
|
|
|
|
import sys
|
2007-08-13 09:55:32 +02:00
|
|
|
import glob
|
2007-07-02 05:27:20 +02:00
|
|
|
import fnmatch
|
2007-07-02 11:38:46 +02:00
|
|
|
|
2011-01-30 15:27:21 +01:00
|
|
|
from SCons import Util
|
2008-08-19 05:03:29 +02:00
|
|
|
|
2007-06-30 04:41:52 +02:00
|
|
|
|
2007-07-03 00:13:12 +02:00
|
|
|
|
2007-06-30 04:41:52 +02:00
|
|
|
#
|
|
|
|
|
# Common Helper Functions
|
|
|
|
|
#
|
|
|
|
|
def isCleanupOperation(env):
|
|
|
|
|
return env.GetOption('clean')
|
2007-07-02 05:27:20 +02:00
|
|
|
|
|
|
|
|
def isHelpRequest():
|
2007-07-18 01:45:31 +02:00
|
|
|
""" this is a hack: SCons does all configure tests even if only
|
2008-12-12 02:04:50 +01:00
|
|
|
the help message is requested. SCons doesn't export the
|
2007-07-02 05:27:20 +02:00
|
|
|
help option for retrieval by env.GetOption(),
|
|
|
|
|
so we scan the commandline directly.
|
2007-07-18 01:45:31 +02:00
|
|
|
"""
|
2007-07-02 05:27:20 +02:00
|
|
|
return '-h' in sys.argv or '--help' in sys.argv
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-03 05:46:36 +01:00
|
|
|
def srcSubtree(tree, **args):
|
|
|
|
|
""" convenience wrapper: scan the given subtree, which is relative
|
|
|
|
|
to the current SConscript, and find all source files.
|
2007-07-18 01:45:31 +02:00
|
|
|
"""
|
2011-12-03 05:46:36 +01:00
|
|
|
return list(scanSubtree(tree, **args))
|
2007-07-02 05:27:20 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-08-08 04:50:02 +02:00
|
|
|
SRCPATTERNS = ['*.c','*.cpp','*.cc']
|
2007-07-02 05:27:20 +02:00
|
|
|
|
2008-08-19 05:03:29 +02:00
|
|
|
def scanSubtree(roots, patterns=SRCPATTERNS):
|
2007-08-13 09:55:32 +02:00
|
|
|
""" first expand (possible) wildcards and filter out non-dirs.
|
2008-12-12 02:04:50 +01:00
|
|
|
Then scan the given subtree for source filenames
|
2007-07-02 05:27:20 +02:00
|
|
|
(python generator function)
|
2007-07-18 01:45:31 +02:00
|
|
|
"""
|
2007-08-13 09:55:32 +02:00
|
|
|
for root in globRootdirs(roots):
|
2012-01-10 05:52:00 +01:00
|
|
|
for (d,_,files) in os.walk(root):
|
|
|
|
|
if d.startswith('./'):
|
|
|
|
|
d = d[2:]
|
2008-08-19 05:03:29 +02:00
|
|
|
for p in patterns:
|
2007-08-13 09:55:32 +02:00
|
|
|
for f in fnmatch.filter(files, p):
|
2012-01-10 05:52:00 +01:00
|
|
|
yield os.path.join(d,f)
|
2007-08-13 09:55:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def globRootdirs(roots):
|
|
|
|
|
""" helper: expand shell wildcards and filter the resulting list,
|
|
|
|
|
so that it only contains existing directories
|
|
|
|
|
"""
|
2012-01-10 05:52:00 +01:00
|
|
|
isDirectory = lambda f: os.path.isdir(f) and os.path.exists(f)
|
2007-08-13 09:55:32 +02:00
|
|
|
roots = glob.glob(roots)
|
2012-01-10 05:52:00 +01:00
|
|
|
return (d for d in roots if isDirectory(d) )
|
2007-07-02 11:38:46 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-01-12 11:42:03 +01:00
|
|
|
def findSrcTrees(location, patterns=SRCPATTERNS):
|
|
|
|
|
""" find possible source tree roots, starting with the given location.
|
|
|
|
|
When delving down from the initial location(s), a source tree is defined
|
2012-01-10 05:52:00 +01:00
|
|
|
as a directory containidsource files and possibly further sub directories.
|
2009-01-12 11:42:03 +01:00
|
|
|
After having initially expanded the given location with #globRootdirs, each
|
|
|
|
|
directory is examined depth first, until encountering a directory containing
|
|
|
|
|
source files, which then yields a result. Especially, this can be used to traverse
|
2011-01-30 22:12:55 +01:00
|
|
|
an organisational directory structure and find out all possible source trees
|
2009-01-12 11:42:03 +01:00
|
|
|
to be built into packages, plugins, individual tool executables etc.
|
|
|
|
|
@return: the relative path names of all source root dirs found (generator function).
|
|
|
|
|
"""
|
2012-01-10 05:52:00 +01:00
|
|
|
for directory in globRootdirs(location):
|
|
|
|
|
if isSrcDir (directory,patterns):
|
|
|
|
|
yield directory
|
2009-01-12 11:42:03 +01:00
|
|
|
else:
|
2012-01-10 05:52:00 +01:00
|
|
|
for result in findSrcTrees (str(directory)+'/*'):
|
2009-01-12 11:42:03 +01:00
|
|
|
yield result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def isSrcDir(path, patterns=SRCPATTERNS):
|
|
|
|
|
""" helper: investigate the given (relative) path
|
|
|
|
|
@param patterns: list of wildcards defining what counts as "source file"
|
|
|
|
|
@return: True if it's a directory containing any source file
|
|
|
|
|
"""
|
|
|
|
|
if not os.path.isdir(path):
|
2012-01-10 05:52:00 +01:00
|
|
|
return False
|
2009-01-12 11:42:03 +01:00
|
|
|
else:
|
|
|
|
|
for p in patterns:
|
|
|
|
|
if glob.glob(path+'/'+p):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
2007-07-02 11:38:46 +02:00
|
|
|
|
2008-07-11 05:35:48 +02:00
|
|
|
def filterNodes(nlist, removeName=None):
|
|
|
|
|
""" filter out scons build nodes using the given criteria.
|
|
|
|
|
removeName: if set, remove all nodes with this srcname
|
|
|
|
|
"""
|
|
|
|
|
if removeName:
|
|
|
|
|
predicate = lambda n : not fnmatch.fnmatch(os.path.basename(str(n[0])), removeName)
|
|
|
|
|
else:
|
2012-01-10 05:52:00 +01:00
|
|
|
predicate = lambda n : True
|
2008-07-11 05:35:48 +02:00
|
|
|
|
|
|
|
|
return filter(predicate, nlist)
|
|
|
|
|
|
|
|
|
|
|
2008-08-19 05:03:29 +02:00
|
|
|
|
2012-01-10 05:52:00 +01:00
|
|
|
def getDirname (d, basePrefix=None):
|
2011-01-30 22:12:55 +01:00
|
|
|
""" extract directory name without leading path,
|
|
|
|
|
or without the explicitly given basePrefix
|
|
|
|
|
"""
|
2012-01-10 05:52:00 +01:00
|
|
|
d = os.path.realpath(d)
|
|
|
|
|
if not os.path.isdir(d):
|
|
|
|
|
d,_ = os.path.split(d)
|
2011-01-30 22:12:55 +01:00
|
|
|
if basePrefix:
|
|
|
|
|
basePrefix = os.path.realpath(basePrefix)
|
2012-01-10 08:06:09 +01:00
|
|
|
name = str(d)
|
2012-01-10 05:52:00 +01:00
|
|
|
if str(d).startswith(basePrefix):
|
2012-01-10 08:06:09 +01:00
|
|
|
name = name[len(basePrefix):]
|
2011-01-30 22:12:55 +01:00
|
|
|
else:
|
2012-01-10 05:52:00 +01:00
|
|
|
_, name = os.path.split(d)
|
2008-08-19 05:03:29 +02:00
|
|
|
return name
|
2008-12-19 20:17:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-01-10 05:52:00 +01:00
|
|
|
def createPlugins(env, directory, **kw):
|
2009-01-12 11:42:03 +01:00
|
|
|
""" investigate the given source directory to identify all contained source trees.
|
|
|
|
|
@return: a list of build nodes defining a plugin for each of these source trees.
|
|
|
|
|
"""
|
2011-01-30 18:56:51 +01:00
|
|
|
return [env.LumieraPlugin( getDirname(tree)
|
2011-12-03 05:46:36 +01:00
|
|
|
, srcSubtree(tree)
|
2011-01-30 18:56:51 +01:00
|
|
|
, **kw
|
2011-01-29 16:45:22 +01:00
|
|
|
)
|
2012-01-10 05:52:00 +01:00
|
|
|
for tree in findSrcTrees(directory)
|
2009-01-12 11:42:03 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-12-19 20:17:23 +01:00
|
|
|
def checkCommandOption(env, optID, val=None, cmdName=None):
|
|
|
|
|
""" evaluate and verify an option, which may point at a command.
|
|
|
|
|
besides specifying a path, the option may read True, yes or 1,
|
|
|
|
|
denoting that the system default for this command should be used.
|
|
|
|
|
@return: True, if the key has been expanded and validated,
|
|
|
|
|
False, if this failed and the key was removed
|
|
|
|
|
"""
|
|
|
|
|
if not val:
|
|
|
|
|
if not env.get(optID): return False
|
|
|
|
|
else:
|
|
|
|
|
val = env.get(optID)
|
2008-08-19 05:03:29 +02:00
|
|
|
|
2008-12-19 20:17:23 +01:00
|
|
|
if val=='True' or val=='true' or val=='yes' or val=='1' or val == 1 :
|
|
|
|
|
if not cmdName:
|
|
|
|
|
print "WARNING: no default for %s, please specify a full path." % optID
|
|
|
|
|
del env[optID]
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
val = env.WhereIs(cmdName)
|
|
|
|
|
if not val:
|
|
|
|
|
print "WARNING: %s not found, please specify a full path" % cmdName
|
|
|
|
|
del env[optID]
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
if not os.path.isfile(val):
|
|
|
|
|
val = env.WhereIs(val)
|
|
|
|
|
|
|
|
|
|
if val and os.path.isfile(val):
|
|
|
|
|
env[optID] = val
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
del env[optID]
|
|
|
|
|
return False
|
|
|
|
|
|
2008-08-19 05:03:29 +02:00
|
|
|
|
|
|
|
|
|
2011-01-30 15:27:21 +01:00
|
|
|
|
|
|
|
|
class Record(dict):
|
2011-02-13 23:11:16 +01:00
|
|
|
""" a set of properties with record style access.
|
2011-01-30 15:27:21 +01:00
|
|
|
Record is a dictionary, but the elements can be accessed
|
|
|
|
|
conveniently as if they where object fields
|
2008-08-19 05:03:29 +02:00
|
|
|
"""
|
2011-01-30 15:27:21 +01:00
|
|
|
def __init__(self, defaults=None, **props):
|
|
|
|
|
if defaults:
|
|
|
|
|
defaults.update(props)
|
|
|
|
|
props = defaults
|
|
|
|
|
dict.__init__(self,props)
|
2008-08-19 05:03:29 +02:00
|
|
|
|
2011-01-30 15:27:21 +01:00
|
|
|
def __getattr__(self,key):
|
|
|
|
|
if key=='__get__' or key=='__set__':
|
|
|
|
|
raise AttributeError
|
|
|
|
|
return self.setdefault(key)
|
2008-08-19 05:03:29 +02:00
|
|
|
|
2011-01-30 15:27:21 +01:00
|
|
|
def __setattr__(self,key,val):
|
|
|
|
|
self[key] = val
|
|
|
|
|
|
2008-08-19 05:03:29 +02:00
|
|
|
|
2011-01-30 15:27:21 +01:00
|
|
|
def extract_localPathDefs (localDefs):
|
|
|
|
|
""" extracts the directory configuration values.
|
|
|
|
|
For sake of simplicity, paths and directories are defined
|
|
|
|
|
immediately as global variables in the SConstruct. This helper
|
|
|
|
|
extracts from the given dict the variables matching some magical
|
|
|
|
|
pattern and returns them wrapped into a Record for convenient access
|
|
|
|
|
"""
|
|
|
|
|
def relevantPathDefs (mapping):
|
|
|
|
|
for (k,v) in mapping.items():
|
2011-01-30 19:20:02 +01:00
|
|
|
if (k.startswith('src') or k.startswith('build') or k.startswith('install')) and Util.is_String(v):
|
2011-01-30 15:27:21 +01:00
|
|
|
v = v.strip()
|
|
|
|
|
if not v.endswith('/'): v += '/'
|
|
|
|
|
yield (k,v)
|
|
|
|
|
|
|
|
|
|
return dict(relevantPathDefs(localDefs))
|