1#!/usr/bin/env python3 2# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 3 4""" 5setup.py file for SWIG libfdt 6Copyright (C) 2017 Google, Inc. 7Written by Simon Glass <sjg@chromium.org> 8 9This script is modified from the upstream version, to fit in with the U-Boot 10build system. 11 12Files to be built into the extension are provided in SOURCES 13C flags to use are provided in CPPFLAGS 14Object file directory is provided in OBJDIR 15Version is provided in VERSION 16 17If these variables are not given they are parsed from the Makefiles. This 18allows this script to be run stand-alone, e.g.: 19 20 ./pylibfdt/setup.py install [--prefix=...] 21""" 22 23from setuptools import setup, Extension 24from setuptools.command.build_py import build_py as _build_py 25import os 26import re 27import sys 28 29try: 30 from setuptools import sic 31except ImportError: 32 pass 33 34srcdir = os.path.dirname(__file__) 35 36with open(os.path.join(srcdir, "../README"), "r") as fh: 37 long_description = fh.read() 38 39# Decodes a Makefile assignment line into key and value (and plus for +=) 40RE_KEY_VALUE = re.compile(r'(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$') 41 42def get_top_builddir(): 43 if '--top-builddir' in sys.argv: 44 index = sys.argv.index('--top-builddir') 45 sys.argv.pop(index) 46 return sys.argv.pop(index) 47 else: 48 return os.path.join(srcdir, '..') 49 50top_builddir = get_top_builddir() 51 52def ParseMakefile(fname): 53 """Parse a Makefile to obtain its variables. 54 55 This collects variable assigments of the form: 56 57 VAR = value 58 VAR += more 59 60 It does not pick out := assignments, as these are not needed here. It does 61 handle line continuation. 62 63 Returns a dict: 64 key: Variable name (e.g. 'VAR') 65 value: Variable value (e.g. 'value more') 66 """ 67 makevars = {} 68 with open(fname) as fd: 69 prev_text = '' # Continuation text from previous line(s) 70 for line in fd.read().splitlines(): 71 if line and line[-1] == '\\': # Deal with line continuation 72 prev_text += line[:-1] 73 continue 74 elif prev_text: 75 line = prev_text + line 76 prev_text = '' # Continuation is now used up 77 m = RE_KEY_VALUE.match(line) 78 if m: 79 value = m.group('value') or '' 80 key = m.group('key') 81 82 # Appending to a variable inserts a space beforehand 83 if 'plus' in m.groupdict() and key in makevars: 84 makevars[key] += ' ' + value 85 else: 86 makevars[key] = value 87 return makevars 88 89def GetEnvFromMakefiles(): 90 """Scan the Makefiles to obtain the settings we need. 91 92 This assumes that this script is being run from the top-level directory, 93 not the pylibfdt directory. 94 95 Returns: 96 Tuple with: 97 List of swig options 98 Version string 99 List of files to build 100 List of extra C preprocessor flags needed 101 Object directory to use (always '') 102 """ 103 basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) 104 swig_opts = ['-I%s' % basedir] 105 makevars = ParseMakefile(os.path.join(basedir, 'Makefile')) 106 version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'], 107 makevars['SUBLEVEL']) 108 makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt')) 109 files = makevars['LIBFDT_SRCS'].split() 110 files = [os.path.join(basedir, 'libfdt', fname) for fname in files] 111 files.append('libfdt.i') 112 cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir] 113 objdir = '' 114 return swig_opts, version, files, cflags, objdir 115 116 117progname = sys.argv[0] 118files = os.environ.get('SOURCES', '').split() 119cflags = os.environ.get('CPPFLAGS', '').split() 120objdir = os.environ.get('OBJDIR') 121try: 122 version = sic(os.environ.get('VERSION')) 123except: 124 version = os.environ.get('VERSION') 125swig_opts = os.environ.get('SWIG_OPTS', '').split() 126 127# If we were called directly rather than through our Makefile (which is often 128# the case with Python module installation), read the settings from the 129# Makefile. 130if not all((swig_opts, version, files, cflags, objdir)): 131 swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles() 132 133libfdt_module = Extension( 134 '_libfdt', 135 sources=files, 136 include_dirs=[os.path.join(srcdir, 'libfdt')], 137 library_dirs=[os.path.join(top_builddir, 'libfdt')], 138 swig_opts=swig_opts, 139) 140 141class build_py(_build_py): 142 def run(self): 143 self.run_command("build_ext") 144 return super().run() 145 146setup( 147 name='libfdt', 148 version=version, 149 cmdclass = {'build_py' : build_py}, 150 author='Simon Glass', 151 author_email='sjg@chromium.org', 152 description='Python binding for libfdt', 153 ext_modules=[libfdt_module], 154 package_dir={'': objdir}, 155 py_modules=['libfdt'], 156 157 long_description=long_description, 158 long_description_content_type="text/plain", 159 url="https://git.kernel.org/pub/scm/utils/dtc/dtc.git", 160 license="BSD", 161 license_files=["GPL", "BSD-2-Clause"], 162 163 classifiers=[ 164 "Programming Language :: Python :: 3", 165 "License :: OSI Approved :: BSD License", 166 "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", 167 "Operating System :: OS Independent", 168 ], 169 170) 171