Browse Source

pylibfdt: Allow setup.py to operate stand-alone

At present we require that setup.py is executed from the Makefile, which
sets up various important things like the list of files to build and the
version number.

However many installation systems expect to be able to change to the
directory containing setup.py and run it. This allows them to support (for
example) building/installing for multiple Python versions, varying
installation paths, particular C flags, etc.

The problem in implementing this is that we don't want to duplicate the
information in the Makefile. A common solution (so I am told) is to parse
the Makefile to obtain the required information.

Update the setup.py script to read a few Makefiles when it does not see
the required information in its environment. This allows installation
using:

   ./pylibfdt/setup.py install

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
main
Simon Glass 8 years ago committed by David Gibson
parent
commit
90db6d9989
  1. 1
      Makefile
  2. 14
      README
  3. 9
      pylibfdt/Makefile.pylibfdt
  4. 98
      pylibfdt/setup.py
  5. 6
      tests/Makefile.tests

1
Makefile

@ -267,6 +267,7 @@ TESTS_BIN += convert-dtsv0 @@ -267,6 +267,7 @@ TESTS_BIN += convert-dtsv0
TESTS_BIN += fdtput
TESTS_BIN += fdtget
TESTS_BIN += fdtdump
TESTS_PYLIBFDT += maybe_pylibfdt

include tests/Makefile.tests


14
README

@ -50,12 +50,18 @@ If you add new features, please check code coverage: @@ -50,12 +50,18 @@ If you add new features, please check code coverage:
# Open 'htmlcov/index.html' in your browser


To install the library use:
To install the library via the normal setup.py method, use:

make install_pylibfdt SETUP_PREFIX=/path/to/install_dir
./pylibfdt/setup.py [--prefix=/path/to/install_dir]

If SETUP_PREFIX is not provided, the default prefix is used, typically '/usr'
or '/usr/local'. See Python's distutils documentation for details.
If --prefix is not provided, the default prefix is used, typically '/usr'
or '/usr/local'. See Python's distutils documentation for details. You can
also install via the Makefile if you like, but the above is more common.

To install both libfdt and pylibfdt you can use:

make install [SETUP_PREFIX=/path/to/install_dir] \
[PREFIX=/path/to/install_dir]

To disable building the python library, even if swig and Python are available,
use:

9
pylibfdt/Makefile.pylibfdt

@ -5,13 +5,16 @@ PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) @@ -5,13 +5,16 @@ PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS))
WRAP = $(PYLIBFDT_objdir)/libfdt_wrap.c
PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so

run_setup = SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \
VERSION="$(dtc_version)" \
python $(PYLIBFDT_objdir)/setup.py --quiet $(2)
define run_setup
SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)"
VERSION="$(dtc_version)"
$(PYLIBFDT_objdir)/setup.py --quiet $(2)
endef

$(PYMODULE): $(PYLIBFDT_srcs) $(WRAP)
@$(VECHO) PYMOD $@
$(call run_setup, $^, build_ext --inplace)
mv _libfdt.so $@

$(WRAP): $(PYLIBFDT_srcdir)/libfdt.i
@$(VECHO) SWIG $@

98
pylibfdt/setup.py

@ -2,26 +2,112 @@ @@ -2,26 +2,112 @@

"""
setup.py file for SWIG libfdt
Copyright (C) 2017 Google, Inc.
Written by Simon Glass <sjg@chromium.org>

Files to be built into the extension are provided in SOURCES
C flags to use are provided in CPPFLAGS
Object file directory is provided in OBJDIR
Version is provided in VERSION

If these variables are not given they are parsed from the Makefiles. This
allows this script to be run stand-alone, e.g.:

./pylibfdt/setup.py install [--prefix=...]
"""

from distutils.core import setup, Extension
import os
import re
import sys

# Decodes a Makefile assignment line into key and value (and plus for +=)
RE_KEY_VALUE = re.compile('(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$')


def ParseMakefile(fname):
"""Parse a Makefile to obtain its variables.

This collects variable assigments of the form:

VAR = value
VAR += more

It does not pick out := assignments, as these are not needed here. It does
handle line continuation.

Returns a dict:
key: Variable name (e.g. 'VAR')
value: Variable value (e.g. 'value more')
"""
makevars = {}
with open(fname) as fd:
prev_text = '' # Continuation text from previous line(s)
for line in fd.read().splitlines():
if line and line[-1] == '\\': # Deal with line continuation
prev_text += line[:-1]
continue
elif prev_text:
line = prev_text + line
prev_text = '' # Continuation is now used up
m = RE_KEY_VALUE.match(line)
if m:
value = m.group('value') or ''
key = m.group('key')

# Appending to a variable inserts a space beforehand
if 'plus' in m.groupdict() and key in makevars:
makevars[key] += ' ' + value
else:
makevars[key] = value
return makevars

def GetEnvFromMakefiles():
"""Scan the Makefiles to obtain the settings we need.

This assumes that this script is being run from the top-level directory,
not the pylibfdt directory.

Returns:
Tuple with:
List of swig options
Version string
List of files to build
List of extra C preprocessor flags needed
Object directory to use (always '')
"""
basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
swig_opts = ['-I%s' % basedir]
makevars = ParseMakefile(os.path.join(basedir, 'Makefile'))
version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'],
makevars['SUBLEVEL'])
makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt'))
files = makevars['LIBFDT_SRCS'].split()
files = [os.path.join(basedir, 'libfdt', fname) for fname in files]
files.append('pylibfdt/libfdt.i')
cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir]
objdir = ''
return swig_opts, version, files, cflags, objdir


progname = sys.argv[0]
files = os.environ['SOURCES'].split()
cflags = os.environ['CPPFLAGS'].split()
objdir = os.environ['OBJDIR']
version = os.environ['VERSION']
files = os.environ.get('SOURCES', '').split()
cflags = os.environ.get('CPPFLAGS', '').split()
objdir = os.environ.get('OBJDIR')
version = os.environ.get('VERSION')
swig_opts = []

# If we were called directly rather than through our Makefile (which is often
# the case with Python module installation), read the settings from the
# Makefile.
if not all((version, files, cflags, objdir)):
swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles()

libfdt_module = Extension(
'_libfdt',
sources = files,
extra_compile_args = cflags
extra_compile_args = cflags,
swig_opts = swig_opts,
)

setup(
@ -31,5 +117,5 @@ setup( @@ -31,5 +117,5 @@ setup(
description='Python binding for libfdt',
ext_modules=[libfdt_module],
package_dir={'': objdir},
py_modules=['libfdt'],
py_modules=['pylibfdt/libfdt'],
)

6
tests/Makefile.tests

@ -72,13 +72,13 @@ tests_clean: @@ -72,13 +72,13 @@ tests_clean:
rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
rm -f $(TESTS_CLEANFILES)

check: tests ${TESTS_BIN}
check: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh

checkm: tests ${TESTS_BIN}
checkm: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$

checkv: tests ${TESTS_BIN}
checkv: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh -v

ifneq ($(DEPTARGETS),)

Loading…
Cancel
Save