1#!/usr/bin/env python 2 3""" 4setup.py file for SWIG libfdt 5Copyright (C) 2017 Google, Inc. 6Written by Simon Glass <sjg@chromium.org> 7 8Files to be built into the extension are provided in SOURCES 9C flags to use are provided in CPPFLAGS 10Object file directory is provided in OBJDIR 11Version is provided in VERSION 12 13If these variables are not given they are parsed from the Makefiles. This 14allows this script to be run stand-alone, e.g.: 15 16 ./pylibfdt/setup.py install [--prefix=...] 17""" 18 19from distutils.core import setup, Extension 20import os 21import re 22import sys 23 24# Decodes a Makefile assignment line into key and value (and plus for +=) 25RE_KEY_VALUE = re.compile('(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$') 26 27 28def ParseMakefile(fname): 29 """Parse a Makefile to obtain its variables. 30 31 This collects variable assigments of the form: 32 33 VAR = value 34 VAR += more 35 36 It does not pick out := assignments, as these are not needed here. It does 37 handle line continuation. 38 39 Returns a dict: 40 key: Variable name (e.g. 'VAR') 41 value: Variable value (e.g. 'value more') 42 """ 43 makevars = {} 44 with open(fname) as fd: 45 prev_text = '' # Continuation text from previous line(s) 46 for line in fd.read().splitlines(): 47 if line and line[-1] == '\\': # Deal with line continuation 48 prev_text += line[:-1] 49 continue 50 elif prev_text: 51 line = prev_text + line 52 prev_text = '' # Continuation is now used up 53 m = RE_KEY_VALUE.match(line) 54 if m: 55 value = m.group('value') or '' 56 key = m.group('key') 57 58 # Appending to a variable inserts a space beforehand 59 if 'plus' in m.groupdict() and key in makevars: 60 makevars[key] += ' ' + value 61 else: 62 makevars[key] = value 63 return makevars 64 65def GetEnvFromMakefiles(): 66 """Scan the Makefiles to obtain the settings we need. 67 68 This assumes that this script is being run from the top-level directory, 69 not the pylibfdt directory. 70 71 Returns: 72 Tuple with: 73 List of swig options 74 Version string 75 List of files to build 76 List of extra C preprocessor flags needed 77 Object directory to use (always '') 78 """ 79 basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) 80 swig_opts = ['-I%s' % basedir] 81 makevars = ParseMakefile(os.path.join(basedir, 'Makefile')) 82 version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'], 83 makevars['SUBLEVEL']) 84 makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt')) 85 files = makevars['LIBFDT_SRCS'].split() 86 files = [os.path.join(basedir, 'libfdt', fname) for fname in files] 87 files.append('pylibfdt/libfdt.i') 88 cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir] 89 objdir = '' 90 return swig_opts, version, files, cflags, objdir 91 92 93progname = sys.argv[0] 94files = os.environ.get('SOURCES', '').split() 95cflags = os.environ.get('CPPFLAGS', '').split() 96objdir = os.environ.get('OBJDIR') 97version = os.environ.get('VERSION') 98swig_opts = [] 99 100# If we were called directly rather than through our Makefile (which is often 101# the case with Python module installation), read the settings from the 102# Makefile. 103if not all((version, files, cflags, objdir)): 104 swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles() 105 106libfdt_module = Extension( 107 '_libfdt', 108 sources = files, 109 extra_compile_args = cflags, 110 swig_opts = swig_opts, 111) 112 113setup( 114 name='libfdt', 115 version= version, 116 author='Simon Glass <sjg@chromium.org>', 117 description='Python binding for libfdt', 118 ext_modules=[libfdt_module], 119 package_dir={'': objdir}, 120 py_modules=['pylibfdt/libfdt'], 121) 122