X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=scons%2Fcustom.py;h=2fad8f5b6d4398dfb0fe18c771579b8194f71192;hb=4a8085d67ca7b41690edf22c410e4dc0a28e3187;hp=df7ac93bb006492e401f8e66332b4a7b462e31c3;hpb=424b1210d951c206e7c2fb8f2778acbd384eb247;p=mesa.git diff --git a/scons/custom.py b/scons/custom.py index df7ac93bb00..2fad8f5b6d4 100644 --- a/scons/custom.py +++ b/scons/custom.py @@ -5,7 +5,7 @@ Custom builders and methods. """ # -# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# Copyright 2008 VMware, Inc. # All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a @@ -23,18 +23,17 @@ Custom builders and methods. # 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 NON-INFRINGEMENT. -# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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 os.path -import re import sys import subprocess +import modulefinder import SCons.Action import SCons.Builder @@ -42,6 +41,19 @@ import SCons.Scanner import fixes +import source_list + +# the get_implicit_deps() method changed between 2.4 and 2.5: now it expects +# a callable that takes a scanner as argument and returns a path, rather than +# a path directly. We want to support both, so we need to detect the SCons version, +# for which no API is provided by SCons 8-P + +# Scons version string has consistently been in this format: +# MajorVersion.MinorVersion.Patch[.alpha/beta.yyyymmdd] +# so this formula should cover all versions regardless of type +# stable, alpha or beta. +# For simplicity alpha and beta flags are removed. +scons_version = tuple(map(int, SCons.__version__.split('.')[:3])) def quietCommandLines(env): # Quiet command lines @@ -92,26 +104,25 @@ def createConvenienceLibBuilder(env): return convenience_lib -# TODO: handle import statements with multiple modules -# TODO: handle from import statements -import_re = re.compile(r'^import\s+(\S+)$', re.M) - def python_scan(node, env, path): # http://www.scons.org/doc/0.98.5/HTML/scons-user/c2781.html#AEN2789 + # https://docs.python.org/2/library/modulefinder.html contents = node.get_contents() - source_dir = node.get_dir() - imports = import_re.findall(contents) + + # Tell ModuleFinder to search dependencies in the script dir, and the glapi + # dirs + source_dir = node.get_dir().abspath + GLAPI = env.Dir('#src/mapi/glapi/gen').abspath + path = [source_dir, GLAPI] + sys.path + + finder = modulefinder.ModuleFinder(path=path) + finder.run_script(node.abspath) results = [] - for imp in imports: - for dir in path: - file = os.path.join(str(dir), imp.replace('.', os.sep) + '.py') - if os.path.exists(file): - results.append(env.File(file)) - break - file = os.path.join(str(dir), imp.replace('.', os.sep), '__init__.py') - if os.path.exists(file): - results.append(env.File(file)) - break + for name, mod in finder.modules.items(): + if mod.__file__ is None: + continue + assert os.path.exists(mod.__file__) + results.append(env.File(mod.__file__)) return results python_scanner = SCons.Scanner.Scanner(function = python_scan, skeys = ['.py']) @@ -136,7 +147,7 @@ def code_generate(env, script, target, source, command): # Explicitly mark that the generated code depends on the generator, # and on implicitly imported python modules - path = (script_src.get_dir(),) + path = (script_src.get_dir(),) if scons_version < (2, 5, 0) else lambda x: script_src deps = [script_src] deps += script_src.get_implicit_deps(env, python_scanner, path) env.Depends(code, deps) @@ -173,6 +184,9 @@ def _pkg_check_modules(env, name, modules): if subprocess.call(["pkg-config", "--exists", ' '.join(modules)]) != 0: return + # Strip version expressions from modules + modules = [module.split(' ', 1)[0] for module in modules] + # Other flags may affect the compilation of unrelated targets, so store # them with a prefix, (e.g., XXX_CFLAGS, XXX_LIBS, etc) try: @@ -180,7 +194,7 @@ def _pkg_check_modules(env, name, modules): except OSError: return prefix = name + '_' - for flag_name, flag_value in flags.iteritems(): + for flag_name, flag_value in flags.items(): assert '_' not in flag_name env[prefix + flag_name] = flag_value @@ -188,7 +202,7 @@ def _pkg_check_modules(env, name, modules): def pkg_check_modules(env, name, modules): - sys.stdout.write('Checking for %s...' % name) + sys.stdout.write('Checking for %s (%s)...' % (name, ' '.join(modules))) _pkg_check_modules(env, name, modules) result = env['HAVE_' + name] sys.stdout.write(' %s\n' % ['no', 'yes'][int(bool(result))]) @@ -207,15 +221,13 @@ def pkg_use_modules(env, names): prefix = name + '_' if not 'HAVE_' + name in env: - print 'Attempt to use unknown module %s' % name - env.Exit(1) + raise Exception('Attempt to use unknown module %s' % name) if not env['HAVE_' + name]: - print 'Attempt to use unavailable module %s' % name - env.Exit(1) + raise Exception('Attempt to use unavailable module %s' % name) flags = {} - for flag_name, flag_value in env.Dictionary().iteritems(): + for flag_name, flag_value in env.Dictionary().items(): if flag_name.startswith(prefix): flag_name = flag_name[len(prefix):] if '_' not in flag_name: @@ -229,6 +241,75 @@ def createPkgConfigMethods(env): env.AddMethod(pkg_use_modules, 'PkgUseModules') +def parse_source_list(env, filename, names=None): + # parse the source list file + parser = source_list.SourceListParser() + src = env.File(filename).srcnode() + + cur_srcdir = env.Dir('.').srcnode().abspath + top_srcdir = env.Dir('#').abspath + top_builddir = os.path.join(top_srcdir, env['build_dir']) + + # Normalize everything to / slashes + cur_srcdir = cur_srcdir.replace('\\', '/') + top_srcdir = top_srcdir.replace('\\', '/') + top_builddir = top_builddir.replace('\\', '/') + + # Populate the symbol table of the Makefile parser. + parser.add_symbol('top_srcdir', top_srcdir) + parser.add_symbol('top_builddir', top_builddir) + + sym_table = parser.parse(src.abspath) + + if names: + if sys.version_info[0] >= 3: + if isinstance(names, str): + names = [names] + else: + if isinstance(names, basestring): + names = [names] + + symbols = names + else: + symbols = list(sym_table.keys()) + + # convert the symbol table to source lists + src_lists = {} + for sym in symbols: + val = sym_table[sym] + srcs = [] + for f in val.split(): + if f: + # Process source paths + if f.startswith(top_builddir + '/src'): + # Automake puts build output on a `src` subdirectory, but + # SCons does not, so strip it here. + f = top_builddir + f[len(top_builddir + '/src'):] + if f.startswith(cur_srcdir + '/'): + # Prefer relative source paths, as absolute files tend to + # cause duplicate actions. + f = f[len(cur_srcdir + '/'):] + # do not include any headers + if f.endswith(tuple(['.h','.hpp','.inl'])): + continue + srcs.append(f) + + src_lists[sym] = srcs + + # if names are given, concatenate the lists + if names: + srcs = [] + for name in names: + srcs.extend(src_lists[name]) + + return srcs + else: + return src_lists + +def createParseSourceListMethod(env): + env.AddMethod(parse_source_list, 'ParseSourceList') + + def generate(env): """Common environment generation code""" @@ -240,6 +321,7 @@ def generate(env): createConvenienceLibBuilder(env) createCodeGenerateMethod(env) createPkgConfigMethods(env) + createParseSourceListMethod(env) # for debugging #print env.Dump()