diff --git a/dtc-python-bindings.patch b/dtc-python-bindings.patch new file mode 100644 index 0000000..151c303 --- /dev/null +++ b/dtc-python-bindings.patch @@ -0,0 +1,2299 @@ +From 50f2507016315e0b9499dd58876ffc1acf91cc5a Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 17 Mar 2017 16:14:30 -0600 +Subject: [PATCH 01/29] Add an initial Python library for libfdt + +Add Python bindings for a bare-bones set of libfdt functions. These allow +navigating the tree and reading node names and properties. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + Makefile | 1 + + pylibfdt/.gitignore | 3 + + pylibfdt/Makefile.pylibfdt | 17 ++ + pylibfdt/libfdt.swig | 433 +++++++++++++++++++++++++++++++++++++++++++++ + pylibfdt/setup.py | 34 ++++ + 5 files changed, 488 insertions(+) + create mode 100644 pylibfdt/.gitignore + create mode 100644 pylibfdt/Makefile.pylibfdt + create mode 100644 pylibfdt/libfdt.swig + create mode 100644 pylibfdt/setup.py + +diff --git a/Makefile b/Makefile +index c3f72e0..1b69f53 100644 +--- a/Makefile ++++ b/Makefile +@@ -22,6 +22,7 @@ CFLAGS = -g -Os -fPIC -Werror $(WARNINGS) + + BISON = bison + LEX = flex ++SWIG = swig + + INSTALL = /usr/bin/install + DESTDIR = +diff --git a/pylibfdt/.gitignore b/pylibfdt/.gitignore +new file mode 100644 +index 0000000..5e8c5e3 +--- /dev/null ++++ b/pylibfdt/.gitignore +@@ -0,0 +1,3 @@ ++libfdt.py ++libfdt.pyc ++libfdt_wrap.c +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +new file mode 100644 +index 0000000..0d8c010 +--- /dev/null ++++ b/pylibfdt/Makefile.pylibfdt +@@ -0,0 +1,17 @@ ++# Makefile.pylibfdt ++# ++ ++PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) ++WRAP = $(PYLIBFDT_objdir)/libfdt_wrap.c ++PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so ++ ++$(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) ++ @$(VECHO) PYMOD $@ ++ python $(PYLIBFDT_objdir)/setup.py "$(CPPFLAGS)" $^ ++ mv _libfdt.so $(PYMODULE) ++ ++$(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig ++ @$(VECHO) SWIG $@ ++ $(SWIG) -python -o $@ $< ++ ++PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so +diff --git a/pylibfdt/libfdt.swig b/pylibfdt/libfdt.swig +new file mode 100644 +index 0000000..cd1c6a9 +--- /dev/null ++++ b/pylibfdt/libfdt.swig +@@ -0,0 +1,433 @@ ++/* ++ * pylibfdt - Flat Device Tree manipulation in Python ++ * Copyright (C) 2017 Google, Inc. ++ * Written by Simon Glass ++ * ++ * libfdt is dual licensed: you can use it either under the terms of ++ * the GPL, or the BSD license, at your option. ++ * ++ * a) This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 library; if not, write to the Free ++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, ++ * MA 02110-1301 USA ++ * ++ * Alternatively, ++ * ++ * b) Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ++ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, ++ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++%module libfdt ++ ++%{ ++#define SWIG_FILE_WITH_INIT ++#include "libfdt.h" ++%} ++ ++%pythoncode %{ ++ ++import struct ++ ++# Error codes, corresponding to FDT_ERR_... in libfdt.h ++(NOTFOUND, ++ EXISTS, ++ NOSPACE, ++ BADOFFSET, ++ BADPATH, ++ BADPHANDLE, ++ BADSTATE, ++ TRUNCATED, ++ BADMAGIC, ++ BADVERSION, ++ BADSTRUCTURE, ++ BADLAYOUT, ++ INTERNAL, ++ BADNCELLS, ++ BADVALUE, ++ BADOVERLAY, ++ NOPHANDLES) = QUIET_ALL = range(1, 18) ++# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions ++# altogether. All # functions passed this value will return an error instead ++# of raising an exception. ++ ++# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors, ++# instead of raising an exception. ++QUIET_NOTFOUND = (NOTFOUND,) ++ ++ ++class FdtException(Exception): ++ """An exception caused by an error such as one of the codes above""" ++ def __init__(self, err): ++ self.err = err ++ ++ def __str__(self): ++ return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err)) ++ ++def strerror(fdt_err): ++ """Get the string for an error number ++ ++ Args: ++ fdt_err: Error number (-ve) ++ ++ Returns: ++ String containing the associated error ++ """ ++ return fdt_strerror(fdt_err) ++ ++def check_err(val, quiet=()): ++ """Raise an error if the return value is -ve ++ ++ This is used to check for errors returned by libfdt C functions. ++ ++ Args: ++ val: Return value from a libfdt function ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ val if val >= 0 ++ ++ Raises ++ FdtException if val < 0 ++ """ ++ if val < 0: ++ if -val not in quiet: ++ raise FdtException(val) ++ return val ++ ++def check_err_null(val, quiet=()): ++ """Raise an error if the return value is NULL ++ ++ This is used to check for a NULL return value from certain libfdt C ++ functions ++ ++ Args: ++ val: Return value from a libfdt function ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ val if val is a list, None if not ++ ++ Raises ++ FdtException if val indicates an error was reported and the error ++ is not in @quiet. ++ """ ++ # Normally a list is returned which contains the data and its length. ++ # If we get just an integer error code, it means the function failed. ++ if not isinstance(val, list): ++ if -val not in quiet: ++ raise FdtException(val) ++ return val ++ ++class Fdt: ++ """Device tree class, supporting all operations ++ ++ The Fdt object is created is created from a device tree binary file, ++ e.g. with something like: ++ ++ fdt = Fdt(open("filename.dtb").read()) ++ ++ Operations can then be performed using the methods in this class. Each ++ method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...). ++ ++ All methods raise an FdtException if an error occurs. To avoid this ++ behaviour a 'quiet' parameter is provided for some functions. This ++ defaults to empty, but you can pass a list of errors that you expect. ++ If one of these errors occurs, the function will return an error number ++ (e.g. -NOTFOUND). ++ """ ++ def __init__(self, data): ++ self._fdt = bytearray(data) ++ check_err(fdt_check_header(self._fdt)); ++ ++ def path_offset(self, path, quiet=()): ++ """Get the offset for a given path ++ ++ Args: ++ path: Path to the required node, e.g. '/node@3/subnode@1' ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ Node offset ++ ++ Raises ++ FdtException if the path is not valid or not found ++ """ ++ return check_err(fdt_path_offset(self._fdt, path), quiet) ++ ++ def first_property_offset(self, nodeoffset, quiet=()): ++ """Get the offset of the first property in a node offset ++ ++ Args: ++ nodeoffset: Offset to the node to check ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ Offset of the first property ++ ++ Raises ++ FdtException if the associated node has no properties, or some ++ other error occurred ++ """ ++ return check_err(fdt_first_property_offset(self._fdt, nodeoffset), ++ quiet) ++ ++ def next_property_offset(self, prop_offset, quiet=()): ++ """Get the next property in a node ++ ++ Args: ++ prop_offset: Offset of the previous property ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ Offset of the next property ++ ++ Raises: ++ FdtException if the associated node has no more properties, or ++ some other error occurred ++ """ ++ return check_err(fdt_next_property_offset(self._fdt, prop_offset), ++ quiet) ++ ++ def get_name(self, nodeoffset): ++ """Get the name of a node ++ ++ Args: ++ nodeoffset: Offset of node to check ++ ++ Returns: ++ Node name ++ ++ Raises: ++ FdtException on error (e.g. nodeoffset is invalid) ++ """ ++ return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0] ++ ++ def get_property_by_offset(self, prop_offset, quiet=()): ++ """Obtains a property that can be examined ++ ++ Args: ++ prop_offset: Offset of property (e.g. from first_property_offset()) ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ Property object, or None if not found ++ ++ Raises: ++ FdtException on error (e.g. invalid prop_offset or device ++ tree format) ++ """ ++ pdata = check_err_null( ++ fdt_get_property_by_offset(self._fdt, prop_offset), quiet) ++ if isinstance(pdata, (int)): ++ return pdata ++ return Property(pdata[0], pdata[1]) ++ ++ def first_subnode(self, nodeoffset, quiet=()): ++ """Find the first subnode of a parent node ++ ++ Args: ++ nodeoffset: Node offset of parent node ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ The offset of the first subnode, if any ++ ++ Raises: ++ FdtException if no subnode found or other error occurs ++ """ ++ return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet) ++ ++ def next_subnode(self, nodeoffset, quiet=()): ++ """Find the next subnode ++ ++ Args: ++ nodeoffset: Node offset of previous subnode ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ The offset of the next subnode, if any ++ ++ Raises: ++ FdtException if no more subnode found or other error occurs ++ """ ++ return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet) ++ ++ def totalsize(self): ++ """Return the total size of the device tree ++ ++ Returns: ++ Total tree size in bytes ++ """ ++ return check_err(fdt_totalsize(self._fdt)) ++ ++ def off_dt_struct(self): ++ """Return the start of the device tree struct area ++ ++ Returns: ++ Start offset of struct area ++ """ ++ return check_err(fdt_off_dt_struct(self._fdt)) ++ ++ def pack(self, quiet=()): ++ """Pack the device tree to remove unused space ++ ++ This adjusts the tree in place. ++ ++ Args: ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Raises: ++ FdtException if any error occurs ++ """ ++ return check_err(fdt_pack(self._fdt), quiet) ++ ++ def delprop(self, nodeoffset, prop_name): ++ """Delete a property from a node ++ ++ Args: ++ nodeoffset: Node offset containing property to delete ++ prop_name: Name of property to delete ++ ++ Raises: ++ FdtError if the property does not exist, or another error occurs ++ """ ++ return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name)) ++ ++ def getprop(self, nodeoffset, prop_name, quiet=()): ++ """Get a property from a node ++ ++ Args: ++ nodeoffset: Node offset containing property to get ++ prop_name: Name of property to get ++ quiet: Errors to ignore (empty to raise on all errors) ++ ++ Returns: ++ Value of property as a bytearray, or -ve error number ++ ++ Raises: ++ FdtError if any error occurs (e.g. the property is not found) ++ """ ++ pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name), ++ quiet) ++ if isinstance(pdata, (int)): ++ return pdata ++ return bytearray(pdata[0]) ++ ++ ++class Property: ++ """Holds a device tree property name and value. ++ ++ This holds a copy of a property taken from the device tree. It does not ++ reference the device tree, so if anything changes in the device tree, ++ a Property object will remain valid. ++ ++ Properties: ++ name: Property name ++ value: Proper value as a bytearray ++ """ ++ def __init__(self, name, value): ++ self.name = name ++ self.value = value ++%} ++ ++%rename(fdt_property) fdt_property_func; ++ ++typedef int fdt32_t; ++ ++%include "libfdt/fdt.h" ++ ++%include "typemaps.i" ++ ++/* Most functions don't change the device tree, so use a const void * */ ++%typemap(in) (const void *)(const void *fdt) { ++ if (!PyByteArray_Check($input)) { ++ SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" ++ "', argument " "$argnum"" of type '" "$type""'"); ++ } ++ $1 = (void *)PyByteArray_AsString($input); ++ fdt = $1; ++ fdt = fdt; /* avoid unused variable warning */ ++} ++ ++/* Some functions do change the device tree, so use void * */ ++%typemap(in) (void *)(const void *fdt) { ++ if (!PyByteArray_Check($input)) { ++ SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" ++ "', argument " "$argnum"" of type '" "$type""'"); ++ } ++ $1 = PyByteArray_AsString($input); ++ fdt = $1; ++ fdt = fdt; /* avoid unused variable warning */ ++} ++ ++%typemap(out) (struct fdt_property *) { ++ PyObject *buff; ++ ++ if ($1) { ++ resultobj = PyString_FromString( ++ fdt_string(fdt1, fdt32_to_cpu($1->nameoff))); ++ buff = PyByteArray_FromStringAndSize( ++ (const char *)($1 + 1), fdt32_to_cpu($1->len)); ++ resultobj = SWIG_Python_AppendOutput(resultobj, buff); ++ } ++} ++ ++%apply int *OUTPUT { int *lenp }; ++ ++/* typemap used for fdt_getprop() */ ++%typemap(out) (const void *) { ++ if (!$1) ++ $result = Py_None; ++ else ++ $result = Py_BuildValue("s#", $1, *arg4); ++} ++ ++/* We have both struct fdt_property and a function fdt_property() */ ++%warnfilter(302) fdt_property; ++ ++/* These are macros in the header so have to be redefined here */ ++int fdt_magic(const void *fdt); ++int fdt_totalsize(const void *fdt); ++int fdt_off_dt_struct(const void *fdt); ++int fdt_off_dt_strings(const void *fdt); ++int fdt_off_mem_rsvmap(const void *fdt); ++int fdt_version(const void *fdt); ++int fdt_last_comp_version(const void *fdt); ++int fdt_boot_cpuid_phys(const void *fdt); ++int fdt_size_dt_strings(const void *fdt); ++int fdt_size_dt_struct(const void *fdt); ++ ++%include <../libfdt/libfdt.h> +diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py +new file mode 100644 +index 0000000..0ff160c +--- /dev/null ++++ b/pylibfdt/setup.py +@@ -0,0 +1,34 @@ ++#!/usr/bin/env python ++ ++""" ++setup.py file for SWIG libfdt ++""" ++ ++from distutils.core import setup, Extension ++import os ++import sys ++ ++progname = sys.argv[0] ++cflags = sys.argv[1] ++files = sys.argv[2:] ++ ++if cflags: ++ cflags = [flag for flag in cflags.split(' ') if flag] ++else: ++ cflags = None ++ ++libfdt_module = Extension( ++ '_libfdt', ++ sources = files, ++ extra_compile_args = cflags ++) ++ ++sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] ++ ++setup (name = 'libfdt', ++ version = '0.1', ++ author = "Simon Glass ", ++ description = """Python binding for libfdt""", ++ ext_modules = [libfdt_module], ++ py_modules = ["libfdt"], ++ ) +-- +2.13.0 + +From 12cfb740cc76c9c9fa906fee240dc028da2bddd0 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 17 Mar 2017 16:14:31 -0600 +Subject: [PATCH 02/29] Add tests for pylibfdt + +Add a set of tests to cover the functionality in pylibfdt. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + tests/pylibfdt_tests.py | 288 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 288 insertions(+) + create mode 100644 tests/pylibfdt_tests.py + +diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py +new file mode 100644 +index 0000000..ae392bb +--- /dev/null ++++ b/tests/pylibfdt_tests.py +@@ -0,0 +1,288 @@ ++# pylibfdt - Tests for Flat Device Tree manipulation in Python ++# Copyright (C) 2017 Google, Inc. ++# Written by Simon Glass ++# ++# libfdt is dual licensed: you can use it either under the terms of ++# the GPL, or the BSD license, at your option. ++# ++# a) This library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2 of the ++# License, or (at your option) any later version. ++# ++# This library 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 library; if not, write to the Free ++# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, ++# MA 02110-1301 USA ++# ++# Alternatively, ++# ++# b) Redistribution and use in source and binary forms, with or ++# without modification, are permitted provided that the following ++# conditions are met: ++# ++# 1. Redistributions of source code must retain the above ++# copyright notice, this list of conditions and the following ++# disclaimer. ++# 2. Redistributions in binary form must reproduce the above ++# copyright notice, this list of conditions and the following ++# disclaimer in the documentation and/or other materials ++# provided with the distribution. ++# ++# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ++# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ++# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, ++# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++# ++ ++import sys ++import types ++import unittest ++ ++sys.path.append('../pylibfdt') ++import libfdt ++from libfdt import FdtException, QUIET_NOTFOUND, QUIET_ALL ++ ++def get_err(err_code): ++ """Convert an error code into an error message ++ ++ Args: ++ err_code: Error code value (FDT_ERR_...) ++ ++ Returns: ++ String error code ++ """ ++ return 'pylibfdt error %d: %s' % (-err_code, libfdt.fdt_strerror(-err_code)) ++ ++def _ReadFdt(fname): ++ """Read a device tree file into an Fdt object, ready for use ++ ++ Args: ++ fname: Filename to read from ++ ++ Returns: ++ Fdt bytearray suitable for passing to libfdt functions ++ """ ++ return libfdt.Fdt(open(fname).read()) ++ ++class PyLibfdtTests(unittest.TestCase): ++ """Test class for pylibfdt ++ ++ Properties: ++ fdt: Device tree file used for testing ++ """ ++ ++ def setUp(self): ++ """Read in the device tree we use for testing""" ++ self.fdt = _ReadFdt('test_tree1.dtb') ++ ++ def GetPropList(self, node_path): ++ """Read a list of properties from a node ++ ++ Args: ++ node_path: Full path to node, e.g. '/subnode@1/subsubnode' ++ ++ Returns: ++ List of property names for that node, e.g. ['compatible', 'reg'] ++ """ ++ prop_list = [] ++ node = self.fdt.path_offset(node_path) ++ poffset = self.fdt.first_property_offset(node, QUIET_NOTFOUND) ++ while poffset > 0: ++ prop = self.fdt.get_property_by_offset(poffset) ++ prop_list.append(prop.name) ++ poffset = self.fdt.next_property_offset(poffset, QUIET_NOTFOUND) ++ return prop_list ++ ++ def testImport(self): ++ """Check that we can import the library correctly""" ++ self.assertEquals(type(libfdt), types.ModuleType) ++ ++ def testBadFdt(self): ++ """Check that a filename provided accidentally is not accepted""" ++ with self.assertRaises(FdtException) as e: ++ fdt = libfdt.Fdt('a string') ++ self.assertEquals(e.exception.err, -libfdt.BADMAGIC) ++ ++ def testPathOffset(self): ++ """Check that we can find the offset of a node""" ++ self.assertEquals(self.fdt.path_offset('/'), 0) ++ self.assertTrue(self.fdt.path_offset('/subnode@1') > 0) ++ with self.assertRaises(FdtException) as e: ++ self.fdt.path_offset('/wibble') ++ self.assertEquals(e.exception.err, -libfdt.NOTFOUND) ++ self.assertEquals(self.fdt.path_offset('/wibble', QUIET_NOTFOUND), ++ -libfdt.NOTFOUND) ++ ++ def testPropertyOffset(self): ++ """Walk through all the properties in the root node""" ++ offset = self.fdt.first_property_offset(0) ++ self.assertTrue(offset > 0) ++ for i in range(5): ++ next_offset = self.fdt.next_property_offset(offset) ++ self.assertTrue(next_offset > offset) ++ offset = next_offset ++ self.assertEquals(self.fdt.next_property_offset(offset, QUIET_NOTFOUND), ++ -libfdt.NOTFOUND) ++ ++ def testPropertyOffsetExceptions(self): ++ """Check that exceptions are raised as expected""" ++ with self.assertRaises(FdtException) as e: ++ self.fdt.first_property_offset(107) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ ++ # Quieten the NOTFOUND exception and check that a BADOFFSET ++ # exception is still raised. ++ with self.assertRaises(FdtException) as e: ++ self.fdt.first_property_offset(107, QUIET_NOTFOUND) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ with self.assertRaises(FdtException) as e: ++ self.fdt.next_property_offset(107, QUIET_NOTFOUND) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ ++ # Check that NOTFOUND can be quietened. ++ node = self.fdt.path_offset('/subnode@1/ss1') ++ self.assertEquals(self.fdt.first_property_offset(node, QUIET_NOTFOUND), ++ -libfdt.NOTFOUND) ++ with self.assertRaises(FdtException) as e: ++ self.fdt.first_property_offset(node) ++ self.assertEquals(e.exception.err, -libfdt.NOTFOUND) ++ ++ def testGetName(self): ++ """Check that we can get the name of a node""" ++ self.assertEquals(self.fdt.get_name(0), '') ++ node = self.fdt.path_offset('/subnode@1/subsubnode') ++ self.assertEquals(self.fdt.get_name(node), 'subsubnode') ++ ++ with self.assertRaises(FdtException) as e: ++ self.fdt.get_name(-2) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ ++ def testGetPropertyByOffset(self): ++ """Check that we can read the name and contents of a property""" ++ root = 0 ++ poffset = self.fdt.first_property_offset(root) ++ prop = self.fdt.get_property_by_offset(poffset) ++ self.assertEquals(prop.name, 'compatible') ++ self.assertEquals(prop.value, 'test_tree1\0') ++ ++ with self.assertRaises(FdtException) as e: ++ self.fdt.get_property_by_offset(-2) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ self.assertEquals( ++ -libfdt.BADOFFSET, ++ self.fdt.get_property_by_offset(-2, [libfdt.BADOFFSET])) ++ ++ def testGetProp(self): ++ """Check that we can read the contents of a property by name""" ++ root = self.fdt.path_offset('/') ++ value = self.fdt.getprop(root, "compatible") ++ self.assertEquals(value, 'test_tree1\0') ++ self.assertEquals(-libfdt.NOTFOUND, self.fdt.getprop(root, 'missing', ++ QUIET_NOTFOUND)) ++ ++ with self.assertRaises(FdtException) as e: ++ self.fdt.getprop(root, 'missing') ++ self.assertEquals(e.exception.err, -libfdt.NOTFOUND) ++ ++ node = self.fdt.path_offset('/subnode@1/subsubnode') ++ value = self.fdt.getprop(node, "compatible") ++ self.assertEquals(value, 'subsubnode1\0subsubnode\0') ++ ++ def testStrError(self): ++ """Check that we can get an error string""" ++ self.assertEquals(libfdt.strerror(-libfdt.NOTFOUND), ++ 'FDT_ERR_NOTFOUND') ++ ++ def testFirstNextSubnodeOffset(self): ++ """Check that we can walk through subnodes""" ++ node_list = [] ++ node = self.fdt.first_subnode(0, QUIET_NOTFOUND) ++ while node >= 0: ++ node_list.append(self.fdt.get_name(node)) ++ node = self.fdt.next_subnode(node, QUIET_NOTFOUND) ++ self.assertEquals(node_list, ['subnode@1', 'subnode@2']) ++ ++ def testFirstNextSubnodeOffsetExceptions(self): ++ """Check except handling for first/next subnode functions""" ++ node = self.fdt.path_offset('/subnode@1/subsubnode', QUIET_NOTFOUND) ++ self.assertEquals(self.fdt.first_subnode(node, QUIET_NOTFOUND), ++ -libfdt.NOTFOUND) ++ with self.assertRaises(FdtException) as e: ++ self.fdt.first_subnode(node) ++ self.assertEquals(e.exception.err, -libfdt.NOTFOUND) ++ ++ node = self.fdt.path_offset('/subnode@1/ss1', QUIET_NOTFOUND) ++ self.assertEquals(self.fdt.next_subnode(node, QUIET_NOTFOUND), ++ -libfdt.NOTFOUND) ++ with self.assertRaises(FdtException) as e: ++ self.fdt.next_subnode(node) ++ self.assertEquals(e.exception.err, -libfdt.NOTFOUND) ++ ++ def testDeleteProperty(self): ++ """Test that we can delete a property""" ++ node_name = '/subnode@1' ++ self.assertEquals(self.GetPropList(node_name), ++ ['compatible', 'reg', 'prop-int']) ++ node = self.fdt.path_offset('/%s' % node_name) ++ self.assertEquals(self.fdt.delprop(node, 'reg'), 0) ++ self.assertEquals(self.GetPropList(node_name), ++ ['compatible', 'prop-int']) ++ ++ def testHeader(self): ++ """Test that we can access the header values""" ++ self.assertEquals(self.fdt.totalsize(), len(self.fdt._fdt)) ++ self.assertEquals(self.fdt.off_dt_struct(), 88) ++ ++ def testPack(self): ++ """Test that we can pack the tree after deleting something""" ++ orig_size = self.fdt.totalsize() ++ node = self.fdt.path_offset('/subnode@2', QUIET_NOTFOUND) ++ self.assertEquals(self.fdt.delprop(node, 'prop-int'), 0) ++ self.assertEquals(orig_size, self.fdt.totalsize()) ++ self.assertEquals(self.fdt.pack(), 0) ++ self.assertTrue(self.fdt.totalsize() < orig_size) ++ ++ def testBadPropertyOffset(self): ++ """Test that bad property offsets are detected""" ++ with self.assertRaises(FdtException) as e: ++ self.fdt.get_property_by_offset(13) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ with self.assertRaises(FdtException) as e: ++ self.fdt.first_property_offset(3) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ with self.assertRaises(FdtException) as e: ++ self.fdt.next_property_offset(3) ++ self.assertEquals(e.exception.err, -libfdt.BADOFFSET) ++ ++ def testBadPathOffset(self): ++ """Test that bad path names are detected""" ++ with self.assertRaisesRegexp(FdtException, get_err(libfdt.BADPATH)): ++ self.fdt.path_offset('not-present') ++ ++ def testQuietAll(self): ++ """Check that exceptions can be masked by QUIET_ALL""" ++ self.assertEquals(-libfdt.NOTFOUND, ++ self.fdt.path_offset('/missing', QUIET_ALL)) ++ self.assertEquals(-libfdt.BADOFFSET, ++ self.fdt.get_property_by_offset(13, QUIET_ALL)) ++ self.assertEquals(-libfdt.BADPATH, ++ self.fdt.path_offset('missing', QUIET_ALL)) ++ ++ ++if __name__ == "__main__": ++ unittest.main() +-- +2.13.0 + +From b40aa8359affa52bd79afe468c26683d6bb41c68 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 17 Mar 2017 16:14:32 -0600 +Subject: [PATCH 03/29] Mention pylibfdt in the documentation + +Add a note about pylibfdt in the README. + +Signed-off-by: Simon Glass +Reviewed-by: David Gibson +Signed-off-by: David Gibson +--- + README | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/README b/README +index f92008f..96d8486 100644 +--- a/README ++++ b/README +@@ -7,6 +7,53 @@ DTC and LIBFDT are maintained by: + David Gibson + Jon Loeliger + ++ ++Python library ++-------------- ++ ++A Python library is also available. To build this you will need to install ++swig and Python development files. On Debian distributions: ++ ++ sudo apt-get install swig python-dev ++ ++The library provides an Fdt class which you can use like this: ++ ++$ PYTHONPATH=../pylibfdt python ++>>> import libfdt ++>>> fdt = libfdt.Fdt(open('test_tree1.dtb').read()) ++>>> node = fdt.path_offset('/subnode@1') ++>>> print node ++124 ++>>> prop_offset = fdt.first_property_offset(node) ++>>> prop = fdt.get_property_by_offset(prop_offset) ++>>> print '%s=%r' % (prop.name, prop.value) ++compatible=bytearray(b'subnode1\x00') ++>>> print '%s=%s' % (prop.name, prop.value) ++compatible=subnode1 ++>>> node2 = fdt.path_offset('/') ++>>> print fdt.getprop(node2, 'compatible') ++test_tree1 ++ ++You will find tests in tests/pylibfdt_tests.py showing how to use each ++method. Help is available using the Python help command, e.g.: ++ ++ $ cd pylibfdt ++ $ python -c "import libfdt; help(libfdt)" ++ ++If you add new features, please check code coverage: ++ ++ $ sudo apt-get install python-pip python-pytest ++ $ sudo pip install coverage ++ $ cd tests ++ $ coverage run pylibfdt_tests.py ++ $ coverage html ++ # Open 'htmlcov/index.html' in your browser ++ ++ ++More work remains to support all of libfdt, including access to numeric ++values. ++ ++ + Mailing list + ------------ + The following list is for discussion about dtc and libfdt implementation +-- +2.13.0 + +From 8cb3896358e9f70b6f742772734b038ed0d4ea19 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 17 Mar 2017 16:14:33 -0600 +Subject: [PATCH 04/29] Adjust libfdt.h to work with swig + +There are a few places where libfdt.h cannot be used as is with swig: + +- macros like fdt_totalsize() have to be defined as C declarations +- fdt_offset_ptr() and fdt_getprop_namelen() need special treatment due to + a TODO in the wrapper for fdt_getprop(). However they are not useful to + Python so can be removed + +Add #ifdefs to work around these problem. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + libfdt/libfdt.h | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h +index ac42e04..2c9ddb4 100644 +--- a/libfdt/libfdt.h ++++ b/libfdt/libfdt.h +@@ -143,7 +143,9 @@ + /* Low-level functions (you probably don't need these) */ + /**********************************************************************/ + ++#ifndef SWIG /* This function is not useful in Python */ + const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); ++#endif + static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) + { + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); +@@ -210,7 +212,6 @@ int fdt_next_subnode(const void *fdt, int offset); + /**********************************************************************/ + /* General functions */ + /**********************************************************************/ +- + #define fdt_get_header(fdt, field) \ + (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) + #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +@@ -354,8 +355,10 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + const char *name, int namelen); ++#endif + /** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob +@@ -391,7 +394,9 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + * Identical to fdt_path_offset(), but only consider the first namelen + * characters of path as the path name. + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); ++#endif + + /** + * fdt_path_offset - find a tree node by its full path +@@ -550,10 +555,12 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + * Identical to fdt_get_property(), but only examine the first namelen + * characters of name for matching the property name. + */ ++#ifndef SWIG /* Not available in Python */ + const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); ++#endif + + /** + * fdt_get_property - find a given property in a given node +@@ -624,8 +631,10 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ ++#ifndef SWIG /* This function is not useful in Python */ + const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); ++#endif + + /** + * fdt_getprop_namelen - get property value based on substring +@@ -638,6 +647,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ ++#ifndef SWIG /* Not available in Python */ + const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); + static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, +@@ -647,6 +657,7 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); + } ++#endif + + /** + * fdt_getprop - retrieve the value of a given property +@@ -707,8 +718,10 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ ++#ifndef SWIG /* Not available in Python */ + const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); ++#endif + + /** + * fdt_get_alias - retrieve the path referenced by a given alias +@@ -1106,10 +1119,12 @@ int fdt_size_cells(const void *fdt, int nodeoffset); + * of the name. It is useful when you want to manipulate only one value of + * an array and you have a string that doesn't end with \0. + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len); ++#endif + + /** + * fdt_setprop_inplace - change a property's value, but not its size +@@ -1139,8 +1154,10 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len); ++#endif + + /** + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property +@@ -1734,8 +1751,10 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name); + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen); ++#endif + + /** + * fdt_add_subnode - creates a new node +-- +2.13.0 + +From 756ffc4f52f6863ba8bf3a67129271566ba2000c Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 17 Mar 2017 16:14:34 -0600 +Subject: [PATCH 05/29] Build pylibfdt as part of the normal build process + +If swig and the Python are available, build pylibfdt automatically. +Adjust the tests to run Python tests too in this case. + +Signed-off-by: Simon Glass +[dwg: Make error message clearer that missing swig or python-dev isn't + fatal to the whole build] +Signed-off-by: David Gibson +--- + Makefile | 34 ++++++++++++++++++++++++++++++++-- + tests/run_tests.sh | 28 ++++++++++++++++++++++++++++ + 2 files changed, 60 insertions(+), 2 deletions(-) + +diff --git a/Makefile b/Makefile +index 1b69f53..ed95384 100644 +--- a/Makefile ++++ b/Makefile +@@ -116,7 +116,21 @@ BIN += fdtput + + SCRIPTS = dtdiff + +-all: $(BIN) libfdt ++# We need both Python and swig to build pylibfdt. ++.PHONY: maybe_pylibfdt ++maybe_pylibfdt: FORCE ++ if pkg-config --cflags python >/dev/null 2>&1; then \ ++ if which swig >/dev/null 2>&1; then \ ++ can_build=yes; \ ++ fi; \ ++ fi; \ ++ if [ "$$can_build" = "yes" ]; then \ ++ $(MAKE) pylibfdt; \ ++ else \ ++ echo "## Skipping pylibgfdt (install python dev and swig to build)"; \ ++ fi ++ ++all: $(BIN) libfdt maybe_pylibfdt + + + ifneq ($(DEPTARGETS),) +@@ -203,6 +217,22 @@ dist: + cat ../dtc-$(dtc_version).tar | \ + gzip -9 > ../dtc-$(dtc_version).tar.gz + ++ ++# ++# Rules for pylibfdt ++# ++PYLIBFDT_srcdir = pylibfdt ++PYLIBFDT_objdir = pylibfdt ++ ++include $(PYLIBFDT_srcdir)/Makefile.pylibfdt ++ ++.PHONY: pylibfdt ++pylibfdt: $(PYLIBFDT_objdir)/_libfdt.so ++ ++pylibfdt_clean: ++ @$(VECHO) CLEAN "(pylibfdt)" ++ rm -f $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles)) ++ + # + # Release signing and uploading + # This is for maintainer convenience, don't try this at home. +@@ -244,7 +274,7 @@ include tests/Makefile.tests + STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \ + *.tab.[ch] *.lex.c *.output + +-clean: libfdt_clean tests_clean ++clean: libfdt_clean pylibfdt_clean tests_clean + @$(VECHO) CLEAN + rm -f $(STD_CLEANFILES) + rm -f $(VERSION_FILE) +diff --git a/tests/run_tests.sh b/tests/run_tests.sh +index 0f5c3db..2a1ba44 100755 +--- a/tests/run_tests.sh ++++ b/tests/run_tests.sh +@@ -771,6 +771,26 @@ fdtdump_tests () { + run_fdtdump_test fdtdump.dts + } + ++pylibfdt_tests () { ++ TMP=/tmp/tests.stderr.$$ ++ python pylibfdt_tests.py -v 2> $TMP ++ ++ # Use the 'ok' message meaning the test passed, 'ERROR' meaning it failed ++ # and the summary line for total tests (e.g. 'Ran 17 tests in 0.002s'). ++ # We could add pass + fail to get total tests, but this provides a useful ++ # sanity check. ++ pass_count=$(grep "\.\.\. ok$" $TMP | wc -l) ++ fail_count=$(grep "^ERROR: " $TMP | wc -l) ++ total_tests=$(sed -n 's/^Ran \([0-9]*\) tests.*$/\1/p' $TMP) ++ cat $TMP ++ rm $TMP ++ ++ # Extract the test results and add them to our totals ++ tot_fail=$((tot_fail + $fail_count)) ++ tot_pass=$((tot_pass + $pass_count)) ++ tot_tests=$((tot_tests + $total_tests)) ++} ++ + while getopts "vt:me" ARG ; do + case $ARG in + "v") +@@ -790,6 +810,11 @@ done + + if [ -z "$TESTSETS" ]; then + TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump" ++ ++ # Test pylibfdt if the libfdt Python module is available. ++ if [ -f ../pylibfdt/_libfdt.so ]; then ++ TESTSETS="$TESTSETS pylibfdt" ++ fi + fi + + # Make sure we don't have stale blobs lying around +@@ -818,6 +843,9 @@ for set in $TESTSETS; do + "fdtdump") + fdtdump_tests + ;; ++ "pylibfdt") ++ pylibfdt_tests ++ ;; + esac + done + +-- +2.13.0 + +From 6afd7d9688f58436bcc6025180473aa2ec1cdec4 Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Wed, 22 Mar 2017 16:34:39 +1100 +Subject: [PATCH 06/29] Correct typo: s/pylibgfdt/pylibfdt/ + +Signed-off-by: David Gibson +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index ed95384..1d08ec1 100644 +--- a/Makefile ++++ b/Makefile +@@ -127,7 +127,7 @@ maybe_pylibfdt: FORCE + if [ "$$can_build" = "yes" ]; then \ + $(MAKE) pylibfdt; \ + else \ +- echo "## Skipping pylibgfdt (install python dev and swig to build)"; \ ++ echo "## Skipping pylibfdt (install python dev and swig to build)"; \ + fi + + all: $(BIN) libfdt maybe_pylibfdt +-- +2.13.0 + +From 4e0e0d049757b15d53209a9687d9ea33ab3704c5 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sun, 26 Mar 2017 13:06:17 -0600 +Subject: [PATCH 07/29] pylibfdt: Allow pkg-config to be supplied in the + environment + +Some build systems have their own version of the pkg-config tool. +Use a variable for this instead of hard-coding it, to allow for this. + +Signed-off-by: Simon Glass +Suggested-by: Mike Frysinger +Signed-off-by: David Gibson +--- + Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 1d08ec1..e6d8251 100644 +--- a/Makefile ++++ b/Makefile +@@ -23,6 +23,7 @@ CFLAGS = -g -Os -fPIC -Werror $(WARNINGS) + BISON = bison + LEX = flex + SWIG = swig ++PKG_CONFIG ?= pkg-config + + INSTALL = /usr/bin/install + DESTDIR = +@@ -119,7 +120,7 @@ SCRIPTS = dtdiff + # We need both Python and swig to build pylibfdt. + .PHONY: maybe_pylibfdt + maybe_pylibfdt: FORCE +- if pkg-config --cflags python >/dev/null 2>&1; then \ ++ if $(PKG_CONFIG) --cflags python >/dev/null 2>&1; then \ + if which swig >/dev/null 2>&1; then \ + can_build=yes; \ + fi; \ +-- +2.13.0 + +From 89a5062ab23163a7cc4f6ec3d693e6b6883ac0a1 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sun, 26 Mar 2017 13:06:19 -0600 +Subject: [PATCH 08/29] pylibfdt: Use environment to pass C flags and files + +At present setup.py adjusts its command line when running, so that the +C flags and file list can be passed as arguments. Pass them in environment +variables instead, so we can avoid this messiness. It also allows us to +support the 'install' command. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + pylibfdt/Makefile.pylibfdt | 3 ++- + pylibfdt/setup.py | 16 ++++++---------- + 2 files changed, 8 insertions(+), 11 deletions(-) + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index 0d8c010..3d99fd4 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -7,7 +7,8 @@ PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so + + $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) + @$(VECHO) PYMOD $@ +- python $(PYLIBFDT_objdir)/setup.py "$(CPPFLAGS)" $^ ++ SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" \ ++ python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace + mv _libfdt.so $(PYMODULE) + + $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig +diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py +index 0ff160c..e45f110 100644 +--- a/pylibfdt/setup.py ++++ b/pylibfdt/setup.py +@@ -2,6 +2,9 @@ + + """ + setup.py file for SWIG libfdt ++ ++Files to be built into the extension are provided in SOURCES ++C flags to use are provided in CPPFLAGS + """ + + from distutils.core import setup, Extension +@@ -9,22 +12,15 @@ import os + import sys + + progname = sys.argv[0] +-cflags = sys.argv[1] +-files = sys.argv[2:] +- +-if cflags: +- cflags = [flag for flag in cflags.split(' ') if flag] +-else: +- cflags = None ++files = os.environ['SOURCES'].split() ++cflags = os.environ['CPPFLAGS'].split() + + libfdt_module = Extension( + '_libfdt', + sources = files, +- extra_compile_args = cflags ++ extra_compile_args = cflags + ) + +-sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] +- + setup (name = 'libfdt', + version = '0.1', + author = "Simon Glass ", +-- +2.13.0 + +From 14c4171f4f9ad2674249e06c54eb9ce0b533d4b6 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sun, 26 Mar 2017 13:06:20 -0600 +Subject: [PATCH 09/29] pylibfdt: Use package_dir to set the package directory + +At present we manually move _libfdt.so into the correct place. Provide a +package directory so we can avoid needing to do this. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + pylibfdt/Makefile.pylibfdt | 3 +-- + pylibfdt/setup.py | 3 +++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index 3d99fd4..861e67c 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -7,9 +7,8 @@ PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so + + $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) + @$(VECHO) PYMOD $@ +- SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" \ ++ SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ + python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace +- mv _libfdt.so $(PYMODULE) + + $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig + @$(VECHO) SWIG $@ +diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py +index e45f110..ef6e2c0 100644 +--- a/pylibfdt/setup.py ++++ b/pylibfdt/setup.py +@@ -5,6 +5,7 @@ setup.py file for SWIG libfdt + + 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 + """ + + from distutils.core import setup, Extension +@@ -14,6 +15,7 @@ import sys + progname = sys.argv[0] + files = os.environ['SOURCES'].split() + cflags = os.environ['CPPFLAGS'].split() ++objdir = os.environ['OBJDIR'] + + libfdt_module = Extension( + '_libfdt', +@@ -26,5 +28,6 @@ setup (name = 'libfdt', + author = "Simon Glass ", + description = """Python binding for libfdt""", + ext_modules = [libfdt_module], ++ package_dir = {'': objdir}, + py_modules = ["libfdt"], + ) +-- +2.13.0 + +From 8a892fd85d94c733bbf184ff6df5d0ad5422be12 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sun, 26 Mar 2017 13:06:18 -0600 +Subject: [PATCH 11/29] pylibfdt: Allow building to be disabled + +Some build systems want to build python libraries separately from the +rest of the build. + +Add a NO_PYTHON option to enable this. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + Makefile | 1 + + README | 6 ++++++ + 2 files changed, 7 insertions(+) + +diff --git a/Makefile b/Makefile +index e6d8251..5cf4aee 100644 +--- a/Makefile ++++ b/Makefile +@@ -120,6 +120,7 @@ SCRIPTS = dtdiff + # We need both Python and swig to build pylibfdt. + .PHONY: maybe_pylibfdt + maybe_pylibfdt: FORCE ++ if [ -n "${NO_PYTHON}" ]; then exit; fi; \ + if $(PKG_CONFIG) --cflags python >/dev/null 2>&1; then \ + if which swig >/dev/null 2>&1; then \ + can_build=yes; \ +diff --git a/README b/README +index 96d8486..d2323fd 100644 +--- a/README ++++ b/README +@@ -50,6 +50,12 @@ If you add new features, please check code coverage: + # Open 'htmlcov/index.html' in your browser + + ++To disable building the python library, even if swig and Python are available, ++use: ++ ++ make NO_PYTHON=1 ++ ++ + More work remains to support all of libfdt, including access to numeric + values. + +-- +2.13.0 + +From e91c652af21557698751c3944ceb7c46e5e58164 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sun, 26 Mar 2017 13:06:21 -0600 +Subject: [PATCH 12/29] pylibfdt: Enable installation of Python module + +Adjust the setup script to support installation, and call it from the +Makefile if enabled. It will be disabled if we were unable to build the +module (e.g. due to swig being missing), or the NO_PYTHON environment +variable is set. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + Makefile | 2 +- + README | 7 +++++++ + pylibfdt/Makefile.pylibfdt | 14 ++++++++++++++ + 3 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 5cf4aee..52ff72c 100644 +--- a/Makefile ++++ b/Makefile +@@ -195,7 +195,7 @@ install-includes: + $(INSTALL) -d $(DESTDIR)$(INCLUDEDIR) + $(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR) + +-install: install-bin install-lib install-includes ++install: install-bin install-lib install-includes maybe_install_pylibfdt + + $(VERSION_FILE): Makefile FORCE + $(call filechk,version) +diff --git a/README b/README +index d2323fd..5add557 100644 +--- a/README ++++ b/README +@@ -50,6 +50,13 @@ If you add new features, please check code coverage: + # Open 'htmlcov/index.html' in your browser + + ++To install the library use: ++ ++ make install_pylibfdt SETUP_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. ++ + To disable building the python library, even if swig and Python are available, + use: + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index 861e67c..a0271da 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -14,4 +14,18 @@ $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig + @$(VECHO) SWIG $@ + $(SWIG) -python -o $@ $< + ++install_pylibfdt: $(WRAP) $(PYMODULE) ++ $(VECHO) INSTALL-PYLIB; \ ++ SOURCES="$(PYLIBFDT_srcs) $(WRAP)" CPPFLAGS="$(CPPFLAGS)" \ ++ OBJDIR="$(PYLIBFDT_objdir)" \ ++ python $(PYLIBFDT_objdir)/setup.py --quiet install \ ++ $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)) ++ ++maybe_install_pylibfdt: ++ if [ -e $(PYMODULE) ]; then \ ++ if [ -z "$(NO_PYTHON)" ]; then \ ++ $(MAKE) install_pylibfdt; \ ++ fi; \ ++ fi ++ + PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so +-- +2.13.0 + +From 9f2e3a3a1f19b569b9524fa0f4cb4790e23ad983 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sun, 26 Mar 2017 13:06:22 -0600 +Subject: [PATCH 13/29] pylibfdt: Use the correct libfdt version in the module + +Use the same version number in the module as with the rest of libfdt. This +can be examined with: + + import pkg_resources + print pkg_resources.require('libfdt')[0].version + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + pylibfdt/Makefile.pylibfdt | 3 ++- + pylibfdt/setup.py | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index a0271da..a74cd30 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -8,6 +8,7 @@ PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so + $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) + @$(VECHO) PYMOD $@ + SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ ++ VERSION="$(dtc_version)" \ + python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace + + $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig +@@ -17,7 +18,7 @@ $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig + install_pylibfdt: $(WRAP) $(PYMODULE) + $(VECHO) INSTALL-PYLIB; \ + SOURCES="$(PYLIBFDT_srcs) $(WRAP)" CPPFLAGS="$(CPPFLAGS)" \ +- OBJDIR="$(PYLIBFDT_objdir)" \ ++ OBJDIR="$(PYLIBFDT_objdir)" VERSION="$(dtc_version)" \ + python $(PYLIBFDT_objdir)/setup.py --quiet install \ + $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)) + +diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py +index ef6e2c0..3bafe30 100644 +--- a/pylibfdt/setup.py ++++ b/pylibfdt/setup.py +@@ -16,6 +16,7 @@ progname = sys.argv[0] + files = os.environ['SOURCES'].split() + cflags = os.environ['CPPFLAGS'].split() + objdir = os.environ['OBJDIR'] ++version = os.environ['VERSION'] + + libfdt_module = Extension( + '_libfdt', +@@ -24,7 +25,7 @@ libfdt_module = Extension( + ) + + setup (name = 'libfdt', +- version = '0.1', ++ version = version, + author = "Simon Glass ", + description = """Python binding for libfdt""", + ext_modules = [libfdt_module], +-- +2.13.0 + +From ab15256d8d027fc379438a18a8bd85e7765557c6 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sun, 26 Mar 2017 13:06:23 -0600 +Subject: [PATCH 14/29] pylibfdt: Use the call function to simplify the + Makefile + +This is in a separate patch since I not sure if GNU make features +are permitted in the Makefile. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + pylibfdt/Makefile.pylibfdt | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index a74cd30..0d95c11 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -5,11 +5,13 @@ 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) ++ + $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) + @$(VECHO) PYMOD $@ +- SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ +- VERSION="$(dtc_version)" \ +- python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace ++ $(call run_setup, $^, build_ext --inplace) + + $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig + @$(VECHO) SWIG $@ +@@ -17,10 +19,8 @@ $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig + + install_pylibfdt: $(WRAP) $(PYMODULE) + $(VECHO) INSTALL-PYLIB; \ +- SOURCES="$(PYLIBFDT_srcs) $(WRAP)" CPPFLAGS="$(CPPFLAGS)" \ +- OBJDIR="$(PYLIBFDT_objdir)" VERSION="$(dtc_version)" \ +- python $(PYLIBFDT_objdir)/setup.py --quiet install \ +- $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)) ++ $(call run_setup, $(PYLIBFDT_srcs) $(WRAP), \ ++ install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX))) + + maybe_install_pylibfdt: + if [ -e $(PYMODULE) ]; then \ +-- +2.13.0 + +From 580a9f6c288079e952eae6707c267644338f7c7b Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Sat, 1 Apr 2017 09:31:41 -0600 +Subject: [PATCH 15/29] Add a libfdt function to write a property placeholder + +The existing function to add a new property to a tree being built requires +that the entire contents of the new property be passed in. For some +applications it is more convenient to be able to add the property contents +later, perhaps by reading from a file. This avoids double-buffering of the +contents. + +Add a new function to support this and adjust the existing fdt_property() to +use it. +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + libfdt/fdt_sw.c | 16 ++++++++++++++-- + libfdt/libfdt.h | 16 ++++++++++++++++ + tests/include7.dts | 1 + + tests/sw_tree1.c | 5 +++++ + tests/test_tree1.dts | 1 + + tests/test_tree1_label_noderef.dts | 1 + + tests/trees.S | 2 ++ + 7 files changed, 40 insertions(+), 2 deletions(-) + +diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c +index 6a80485..2bd15e7 100644 +--- a/libfdt/fdt_sw.c ++++ b/libfdt/fdt_sw.c +@@ -220,7 +220,7 @@ static int _fdt_find_add_string(void *fdt, const char *s) + return offset; + } + +-int fdt_property(void *fdt, const char *name, const void *val, int len) ++int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) + { + struct fdt_property *prop; + int nameoff; +@@ -238,7 +238,19 @@ int fdt_property(void *fdt, const char *name, const void *val, int len) + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); +- memcpy(prop->data, val, len); ++ *valp = prop->data; ++ return 0; ++} ++ ++int fdt_property(void *fdt, const char *name, const void *val, int len) ++{ ++ void *ptr; ++ int ret; ++ ++ ret = fdt_property_placeholder(fdt, name, len, &ptr); ++ if (ret) ++ return ret; ++ memcpy(ptr, val, len); + return 0; + } + +diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h +index 2c9ddb4..a248b1b 100644 +--- a/libfdt/libfdt.h ++++ b/libfdt/libfdt.h +@@ -1314,6 +1314,22 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) + { + return fdt_property_u32(fdt, name, val); + } ++ ++/** ++ * fdt_property_placeholder - add a new property and return a ptr to its value ++ * ++ * @fdt: pointer to the device tree blob ++ * @name: name of property to add ++ * @len: length of property value in bytes ++ * @valp: returns a pointer to where where the value should be placed ++ * ++ * returns: ++ * 0, on success ++ * -FDT_ERR_BADMAGIC, ++ * -FDT_ERR_NOSPACE, standard meanings ++ */ ++int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp); ++ + #define fdt_property_string(fdt, name, str) \ + fdt_property(fdt, name, str, strlen(str)+1) + int fdt_end_node(void *fdt); +diff --git a/tests/include7.dts b/tests/include7.dts +index 2f6eb89..ab2c948 100644 +--- a/tests/include7.dts ++++ b/tests/include7.dts +@@ -5,6 +5,7 @@ + + subsubnode { + compatible = "subsubnode1", "subsubnode"; ++ placeholder = "this is a placeholder string", "string2"; + prop-int = <0xdeadbeef>; + }; + +diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c +index 4887dc3..6a338fc 100644 +--- a/tests/sw_tree1.c ++++ b/tests/sw_tree1.c +@@ -85,6 +85,9 @@ int main(int argc, char *argv[]) + size_t size; + int err; + bool created = false; ++ void *place; ++ const char place_str[] = "this is a placeholder string\0string2"; ++ int place_len = sizeof(place_str); + + test_init(argc, argv); + +@@ -135,6 +138,8 @@ int main(int argc, char *argv[]) + CHECK(fdt_begin_node(fdt, "subsubnode")); + CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode", + 23)); ++ CHECK(fdt_property_placeholder(fdt, "placeholder", place_len, &place)); ++ memcpy(place, place_str, place_len); + CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1)); + CHECK(fdt_end_node(fdt)); + CHECK(fdt_begin_node(fdt, "ss1")); +diff --git a/tests/test_tree1.dts b/tests/test_tree1.dts +index 67ecfd0..77ea325 100644 +--- a/tests/test_tree1.dts ++++ b/tests/test_tree1.dts +@@ -18,6 +18,7 @@ + + subsubnode { + compatible = "subsubnode1", "subsubnode"; ++ placeholder = "this is a placeholder string", "string2"; + prop-int = <0xdeadbeef>; + }; + +diff --git a/tests/test_tree1_label_noderef.dts b/tests/test_tree1_label_noderef.dts +index b2b194c..cfe5946 100644 +--- a/tests/test_tree1_label_noderef.dts ++++ b/tests/test_tree1_label_noderef.dts +@@ -18,6 +18,7 @@ + + subsubnode { + compatible = "subsubnode1", "subsubnode"; ++ placeholder = "this is a placeholder string", "string2"; + prop-int = <0xdeadbeef>; + }; + +diff --git a/tests/trees.S b/tests/trees.S +index 3d24aa2..9854d1d 100644 +--- a/tests/trees.S ++++ b/tests/trees.S +@@ -102,6 +102,7 @@ test_tree1_struct: + + BEGIN_NODE("subsubnode") + PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode") ++ PROP_STR(test_tree1, placeholder, "this is a placeholder string\0string2") + PROP_INT(test_tree1, prop_int, TEST_VALUE_1) + END_NODE + +@@ -141,6 +142,7 @@ test_tree1_strings: + STRING(test_tree1, linux_phandle, "linux,phandle") + STRING(test_tree1, phandle, "phandle") + STRING(test_tree1, reg, "reg") ++ STRING(test_tree1, placeholder, "placeholder") + STRING(test_tree1, address_cells, "#address-cells") + STRING(test_tree1, size_cells, "#size-cells") + test_tree1_strings_end: +-- +2.13.0 + +From 1c5170d3a466dc96ec67c08f71a570631b404c62 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Wed, 5 Apr 2017 10:01:38 -0600 +Subject: [PATCH 16/29] pylibfdt: Rename libfdt.swig to libfdt.i + +The .i extension allows Python distutils to automatically handle the swig +file. Rename it. + +Signed-off-by: Simon Glass +Suggested-by: Mike Frysinger +Signed-off-by: David Gibson +--- + pylibfdt/Makefile.pylibfdt | 2 +- + pylibfdt/{libfdt.swig => libfdt.i} | 0 + 2 files changed, 1 insertion(+), 1 deletion(-) + rename pylibfdt/{libfdt.swig => libfdt.i} (100%) + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index 0d95c11..06f9296 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -13,7 +13,7 @@ $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) + @$(VECHO) PYMOD $@ + $(call run_setup, $^, build_ext --inplace) + +-$(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig ++$(WRAP): $(PYLIBFDT_srcdir)/libfdt.i + @$(VECHO) SWIG $@ + $(SWIG) -python -o $@ $< + +diff --git a/pylibfdt/libfdt.swig b/pylibfdt/libfdt.i +similarity index 100% +rename from pylibfdt/libfdt.swig +rename to pylibfdt/libfdt.i +-- +2.13.0 + +From b04a2cf08862ddac1ff7da40eef58ecb360da941 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Wed, 5 Apr 2017 10:01:39 -0600 +Subject: [PATCH 17/29] pylibfdt: Fix code style in setup.py + +We should follow PEP8 even for our setup() call. + +Signed-off-by: Simon Glass +Suggested-by: Mike Frysinger +Signed-off-by: David Gibson +--- + pylibfdt/setup.py | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py +index 3bafe30..1597b44 100644 +--- a/pylibfdt/setup.py ++++ b/pylibfdt/setup.py +@@ -24,11 +24,12 @@ libfdt_module = Extension( + extra_compile_args = cflags + ) + +-setup (name = 'libfdt', +- version = version, +- author = "Simon Glass ", +- description = """Python binding for libfdt""", +- ext_modules = [libfdt_module], +- package_dir = {'': objdir}, +- py_modules = ["libfdt"], +- ) ++setup( ++ name='libfdt', ++ version= version, ++ author='Simon Glass ', ++ description='Python binding for libfdt', ++ ext_modules=[libfdt_module], ++ package_dir={'': objdir}, ++ py_modules=['libfdt'], ++) +-- +2.13.0 + +From 90db6d9989ca09ed3c32fbdc646d284ebf9fe1cf Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 7 Apr 2017 15:51:32 -0600 +Subject: [PATCH 19/29] 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 +Signed-off-by: David Gibson +--- + Makefile | 1 + + README | 14 +++++-- + pylibfdt/Makefile.pylibfdt | 9 +++-- + pylibfdt/setup.py | 98 +++++++++++++++++++++++++++++++++++++++++++--- + tests/Makefile.tests | 6 +-- + 5 files changed, 112 insertions(+), 16 deletions(-) + mode change 100644 => 100755 pylibfdt/setup.py + +diff --git a/Makefile b/Makefile +index 52ff72c..154f5bf 100644 +--- a/Makefile ++++ b/Makefile +@@ -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 + +diff --git a/README b/README +index 5add557..17dc845 100644 +--- a/README ++++ b/README +@@ -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: +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index 06f9296..0e8ac5f 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -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 $@ +diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py +old mode 100644 +new mode 100755 +index 1597b44..90e80f3 +--- a/pylibfdt/setup.py ++++ b/pylibfdt/setup.py +@@ -2,26 +2,112 @@ + + """ + setup.py file for SWIG libfdt ++Copyright (C) 2017 Google, Inc. ++Written by Simon Glass + + 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\w+) *(?P[+])?= *(?P.*)$') ++ ++ ++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( + description='Python binding for libfdt', + ext_modules=[libfdt_module], + package_dir={'': objdir}, +- py_modules=['libfdt'], ++ py_modules=['pylibfdt/libfdt'], + ) +diff --git a/tests/Makefile.tests b/tests/Makefile.tests +index 3d7a4f8..2258135 100644 +--- a/tests/Makefile.tests ++++ b/tests/Makefile.tests +@@ -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),) +-- +2.13.0 + +From 896f1c1332650f5370a21c1c507106a87d17fd3d Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 7 Apr 2017 15:51:33 -0600 +Subject: [PATCH 20/29] pylibfdt: Use Makefile constructs to implement + NO_PYTHON + +The current mechanism uses a shell construct, but it seems better to use +a Makefile approach. + +Signed-off-by: Simon Glass +Suggested-by: Mike Frysinger +Signed-off-by: David Gibson +--- + Makefile | 15 ++++++++++++--- + pylibfdt/Makefile.pylibfdt | 7 ------- + 2 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/Makefile b/Makefile +index 154f5bf..beca4a0 100644 +--- a/Makefile ++++ b/Makefile +@@ -117,10 +117,11 @@ BIN += fdtput + + SCRIPTS = dtdiff + ++all: $(BIN) libfdt ++ + # We need both Python and swig to build pylibfdt. + .PHONY: maybe_pylibfdt + maybe_pylibfdt: FORCE +- if [ -n "${NO_PYTHON}" ]; then exit; fi; \ + if $(PKG_CONFIG) --cflags python >/dev/null 2>&1; then \ + if which swig >/dev/null 2>&1; then \ + can_build=yes; \ +@@ -132,7 +133,9 @@ maybe_pylibfdt: FORCE + echo "## Skipping pylibfdt (install python dev and swig to build)"; \ + fi + +-all: $(BIN) libfdt maybe_pylibfdt ++ifeq ($(NO_PYTHON),) ++all: maybe_pylibfdt ++endif + + + ifneq ($(DEPTARGETS),) +@@ -195,7 +198,11 @@ install-includes: + $(INSTALL) -d $(DESTDIR)$(INCLUDEDIR) + $(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR) + +-install: install-bin install-lib install-includes maybe_install_pylibfdt ++install: install-bin install-lib install-includes ++ ++ifeq ($(NO_PYTHON),) ++install: install_pylibfdt ++endif + + $(VERSION_FILE): Makefile FORCE + $(call filechk,version) +@@ -267,7 +274,9 @@ TESTS_BIN += convert-dtsv0 + TESTS_BIN += fdtput + TESTS_BIN += fdtget + TESTS_BIN += fdtdump ++ifeq ($(NO_PYTHON),) + TESTS_PYLIBFDT += maybe_pylibfdt ++endif + + include tests/Makefile.tests + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index 0e8ac5f..4036b1f 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -25,11 +25,4 @@ install_pylibfdt: $(WRAP) $(PYMODULE) + $(call run_setup, $(PYLIBFDT_srcs) $(WRAP), \ + install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX))) + +-maybe_install_pylibfdt: +- if [ -e $(PYMODULE) ]; then \ +- if [ -z "$(NO_PYTHON)" ]; then \ +- $(MAKE) install_pylibfdt; \ +- fi; \ +- fi +- + PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so +-- +2.13.0 + +From e56f2b07be3866eff49651cbe34be3bce79ceb38 Mon Sep 17 00:00:00 2001 +From: Simon Glass +Date: Fri, 7 Apr 2017 15:51:34 -0600 +Subject: [PATCH 21/29] pylibfdt: Use setup.py to build the swig file + +Since we are using the standard .i extension for the swig file, we can use +setup.py to build the wrapper. Drop the existing build code since it is +not needed. + +Signed-off-by: Simon Glass +Signed-off-by: David Gibson +--- + pylibfdt/Makefile.pylibfdt | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt +index 4036b1f..9507d3d 100644 +--- a/pylibfdt/Makefile.pylibfdt ++++ b/pylibfdt/Makefile.pylibfdt +@@ -1,8 +1,8 @@ + # Makefile.pylibfdt + # + +-PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) +-WRAP = $(PYLIBFDT_objdir)/libfdt_wrap.c ++PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \ ++ $(PYLIBFDT_srcdir)/libfdt.i + PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so + + define run_setup +@@ -11,18 +11,14 @@ define run_setup + $(PYLIBFDT_objdir)/setup.py --quiet $(2) + endef + +-$(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) ++$(PYMODULE): $(PYLIBFDT_srcs) + @$(VECHO) PYMOD $@ + $(call run_setup, $^, build_ext --inplace) + mv _libfdt.so $@ + +-$(WRAP): $(PYLIBFDT_srcdir)/libfdt.i +- @$(VECHO) SWIG $@ +- $(SWIG) -python -o $@ $< +- +-install_pylibfdt: $(WRAP) $(PYMODULE) ++install_pylibfdt: $(PYMODULE) + $(VECHO) INSTALL-PYLIB; \ +- $(call run_setup, $(PYLIBFDT_srcs) $(WRAP), \ ++ $(call run_setup, $(PYLIBFDT_srcs), \ + install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX))) + + PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so +-- +2.13.0 + diff --git a/dtc.spec b/dtc.spec index 13677ce..0866b83 100644 --- a/dtc.spec +++ b/dtc.spec @@ -1,22 +1,27 @@ -Name: dtc -Version: 1.4.4 -Release: 1%{?dist} -Summary: Device Tree Compiler -Group: Development/Tools -License: GPLv2+ -URL: http://devicetree.org/Device_Tree_Compiler -Source: https://ftp.kernel.org/pub/software/utils/%{name}/%{name}-%{version}.tar.xz -Patch1: use-tx-as-the-type-specifier-instead-of-zx.patch +Name: dtc +Version: 1.4.4 +Release: 2%{?dist} +Summary: Device Tree Compiler +License: GPLv2+ +URL: https://devicetree.org/ -BuildRequires: flex, bison +Source: https://ftp.kernel.org/pub/software/utils/%{name}/%{name}-%{version}.tar.xz +Patch1: use-tx-as-the-type-specifier-instead-of-zx.patch +Patch2: dtc-python-bindings.patch + +BuildRequires: flex bison swig +BuildRequires: python2-devel python2-setuptools %description -The Device Tree Compiler generates flattened Open Firmware style device trees -for use with PowerPC machines that lack an Open Firmware implementation +Devicetree is a data structure for describing hardware. Rather than hard coding +every detail of a device into an operating system, many aspects of the hardware +can be described in a data structure that is passed to the operating system at +boot time. The devicetree is used by OpenFirmware, OpenPOWER Abstraction Layer +(OPAL), Power Architecture Platform Requirements (PAPR) and in the standalone +Flattened Device Tree (FDT) form. %package -n libfdt Summary: Device tree library -Group: Development/Libraries %description -n libfdt libfdt is a library to process Open Firmware style device trees on various @@ -24,27 +29,38 @@ architectures. %package -n libfdt-devel Summary: Development headers for device tree library -Group: Development/Libraries Requires: libfdt = %{version}-%{release} %description -n libfdt-devel This package provides development files for libfdt +%package -n python2-libfdt +Summary: Python 2 bindings for device tree library +%{?python_provide:%python_provide python2-libfdt} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description -n python2-libfdt +This package provides python2 bindings for libfdt + %prep %setup -q %patch1 -p1 +%patch2 -p1 %build make %{?_smp_mflags} V=1 %install -make install DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr LIBDIR=%{_libdir} +make install DESTDIR=$RPM_BUILD_ROOT SETUP_PREFIX=$RPM_BUILD_ROOT/usr PREFIX=/usr LIBDIR=%{_libdir} find %{buildroot} -type f -name "*.a" -delete # we don't want or need ftdump and it conflicts with freetype-demos, so drop # it (rhbz 797805) rm -f $RPM_BUILD_ROOT/%{_bindir}/ftdump +%post -n libfdt -p /sbin/ldconfig + +%postun -n libfdt -p /sbin/ldconfig %files %{!?_licensedir:%global license %%doc} @@ -62,11 +78,13 @@ rm -f $RPM_BUILD_ROOT/%{_bindir}/ftdump %{_libdir}/libfdt.so %{_includedir}/* -%post -n libfdt -p /sbin/ldconfig - -%postun -n libfdt -p /sbin/ldconfig +%files -n python2-libfdt +%{python_sitearch}/* %changelog +* Mon Jun 12 2017 Peter Robinson 1.4.4-2 +- Add upstream patches for python bindings + * Fri Mar 17 2017 Peter Robinson 1.4.4-1 - New dtc 1.4.4 release