* [PATCH 0/4] Introduce Python bindings for libfdt @ 2016-11-17 22:53 Simon Glass [not found] ` <1479423205-9817-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Simon Glass @ 2016-11-17 22:53 UTC (permalink / raw) To: Devicetree Compiler; +Cc: David Gibson, Simon Glass At present libfdt consists of only a C implementation. Many scripts are written using Python so it useful to have Python bindings for libfdt. Apparently this has never been attempted before, or if so I cannot find a reference. This series starts the process of adding this support, with just a bare-bones set of methods, to attract initial comments. Simon Glass (4): Add an initial Python library for libfdt Add tests for pylibfdt Mention pylibfdt in the documentation RFC: Build pylibfdt as part of the normal build process Makefile | 16 +++- README | 6 ++ pylibfdt/.gitignore | 3 + pylibfdt/Makefile.pylibfdt | 21 ++++++ pylibfdt/libfdt.swig | 157 +++++++++++++++++++++++++++++++++++++++ pylibfdt/setup.py | 34 +++++++++ tests/pylibfdt_tests.py | 179 +++++++++++++++++++++++++++++++++++++++++++++ tests/run_tests.sh | 19 ++++- 8 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 pylibfdt/.gitignore create mode 100644 pylibfdt/Makefile.pylibfdt create mode 100644 pylibfdt/libfdt.swig create mode 100644 pylibfdt/setup.py create mode 100644 tests/pylibfdt_tests.py -- 2.8.0.rc3.226.g39d4020 ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <1479423205-9817-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>]
* [PATCH 1/4] Add an initial Python library for libfdt [not found] ` <1479423205-9817-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> @ 2016-11-17 22:53 ` Simon Glass [not found] ` <1479423205-9817-2-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2016-11-17 22:53 ` [PATCH 2/4] Add tests for pylibfdt Simon Glass ` (2 subsequent siblings) 3 siblings, 1 reply; 8+ messages in thread From: Simon Glass @ 2016-11-17 22:53 UTC (permalink / raw) To: Devicetree Compiler; +Cc: David Gibson, Simon Glass 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 <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> --- pylibfdt/.gitignore | 3 + pylibfdt/Makefile.pylibfdt | 21 ++++++ pylibfdt/libfdt.swig | 157 +++++++++++++++++++++++++++++++++++++++++++++ pylibfdt/setup.py | 34 ++++++++++ 4 files changed, 215 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/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..fbdbca5 --- /dev/null +++ b/pylibfdt/Makefile.pylibfdt @@ -0,0 +1,21 @@ +# Makefile.pylibfdt +# +# This is not a complete Makefile of itself. Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# + +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 +PYLIBFDT_CLEANFILES = $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles)) diff --git a/pylibfdt/libfdt.swig b/pylibfdt/libfdt.swig new file mode 100644 index 0000000..91887da --- /dev/null +++ b/pylibfdt/libfdt.swig @@ -0,0 +1,157 @@ +/* + * pylibfdt - Flat Device Tree manipulation in Python + * Copyright (C) 2016 Google, Inc. + * Written by Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> + * + * 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 %{ + +def Raise(errnum): + raise ValueError('Error %s' % fdt_strerror(errnum)) + +def Name(fdt, offset): + name, len = fdt_get_name(fdt, offset) + return name + +def String(fdt, offset): + offset = fdt32_to_cpu(offset) + name = fdt_string(fdt, offset) + return name + +def fdt32_to_cpu(val): + return struct.unpack("=I", struct.pack(">I", val))[0] + +def Data(prop): + set_prop(prop) + return get_prop_data() +%} + +%include "typemaps.i" +%include "cstring.i" + +%typemap(in) void* = char*; + +typedef int fdt32_t; + +struct fdt_property { + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[0]; +}; + +/* + * This is a work-around since I'm not sure of a better way to copy out the + * contents of a string. This is used in dtoc/GetProps(). The intent is to + * pass in a pointer to a property and access the data field at the end of + * it. Ideally the Data() function above would be able to do this directly, + * but I'm not sure how to do that. Needs another look. + */ +#pragma SWIG nowarn=454 +%inline %{ + static struct fdt_property *cur_prop; + + void set_prop(struct fdt_property *prop) { + cur_prop = prop; + } +%} + +%cstring_output_allocate_size(char **s, int *sz, free(*$1)); +%inline %{ + void get_prop_data(char **s, int *sz) { + *sz = fdt32_to_cpu(cur_prop->len); + *s = (char *)malloc(*sz); + if (!*s) + *sz = 0; + else + memcpy(*s, cur_prop + 1, *sz); + } +%} + +%typemap(in) (const void *) { + if (!PyByteArray_Check($input)) { + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " + "$argnum"" of type '" "$type""'"); + } + $1 = (void *) PyByteArray_AsString($input); +} + +int fdt_path_offset(const void *fdt, const char *path); +int fdt_first_property_offset(const void *fdt, int nodeoffset); +int fdt_next_property_offset(const void *fdt, int offset); +const char *fdt_get_name(const void *fdt, int nodeoffset, int *OUTPUT); +const char *fdt_string(const void *fdt, int stroffset); +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *OUTPUT); +const char *fdt_strerror(int errval); +int fdt_first_subnode(const void *fdt, int offset); +int fdt_next_subnode(const void *fdt, int offset); + +%typemap(in) (void *) { + if (!PyByteArray_Check($input)) { + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " + "$argnum"" of type '" "$type""'"); + } + $1 = PyByteArray_AsString($input); +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name); + +int fdt_pack(void *fdt); + +int fdt_totalsize(const void *fdt); +int fdt_off_dt_struct(const void *fdt); diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py new file mode 100644 index 0000000..8f8618e --- /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 = "SWIG Docs", + description = """Simple swig libfdt from docs""", + ext_modules = [libfdt_module], + py_modules = ["libfdt"], + ) -- 2.8.0.rc3.226.g39d4020 ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <1479423205-9817-2-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>]
* Re: [PATCH 1/4] Add an initial Python library for libfdt [not found] ` <1479423205-9817-2-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> @ 2016-11-18 0:36 ` David Gibson [not found] ` <20161118003645.GC31640-K0bRW+63XPQe6aEkudXLsA@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: David Gibson @ 2016-11-18 0:36 UTC (permalink / raw) To: Simon Glass; +Cc: Devicetree Compiler [-- Attachment #1: Type: text/plain, Size: 10393 bytes --] On Thu, Nov 17, 2016 at 03:53:22PM -0700, Simon Glass wrote: > Add Python bindings for a bare-bones set of libfdt functions. These allow > navigating the tree and reading node names and properties. Nice idea. Some nits in the details.. > > Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> > --- > > pylibfdt/.gitignore | 3 + > pylibfdt/Makefile.pylibfdt | 21 ++++++ > pylibfdt/libfdt.swig | 157 +++++++++++++++++++++++++++++++++++++++++++++ > pylibfdt/setup.py | 34 ++++++++++ > 4 files changed, 215 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/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..fbdbca5 > --- /dev/null > +++ b/pylibfdt/Makefile.pylibfdt > @@ -0,0 +1,21 @@ > +# Makefile.pylibfdt > +# > +# This is not a complete Makefile of itself. Instead, it is designed to > +# be easily embeddable into other systems of Makefiles. So, Makefile.libfdt is explicitly designed for easily embedding libfdt in other projecs - even ones with weird build environments, like bootloaders. It's less clear that that's valuable for Python wrappers. > +# > + > +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 > +PYLIBFDT_CLEANFILES = $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles)) > diff --git a/pylibfdt/libfdt.swig b/pylibfdt/libfdt.swig > new file mode 100644 > index 0000000..91887da > --- /dev/null > +++ b/pylibfdt/libfdt.swig > @@ -0,0 +1,157 @@ > +/* > + * pylibfdt - Flat Device Tree manipulation in Python > + * Copyright (C) 2016 Google, Inc. > + * Written by Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> > + * > + * 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 %{ > + > +def Raise(errnum): > + raise ValueError('Error %s' % fdt_strerror(errnum)) So, first, I believe this and several things below break normal Python capitalization conventions for functions (capital-followed-by-lower generally indicates a class). More importantly, wouldn't it make more sense to have an Exception subclass for libfdt errors, rather than shuffling everything through ValueError? > +def Name(fdt, offset): > + name, len = fdt_get_name(fdt, offset) > + return name > + > +def String(fdt, offset): > + offset = fdt32_to_cpu(offset) > + name = fdt_string(fdt, offset) > + return name > + > +def fdt32_to_cpu(val): > + return struct.unpack("=I", struct.pack(">I", val))[0] > + > +def Data(prop): > + set_prop(prop) > + return get_prop_data() > +%} > + > +%include "typemaps.i" > +%include "cstring.i" > + > +%typemap(in) void* = char*; > + > +typedef int fdt32_t; > + > +struct fdt_property { > + fdt32_t tag; > + fdt32_t len; > + fdt32_t nameoff; > + char data[0]; > +}; Can't you include this directly from fdt.h? That header is guaranteed never to have actual function definitions, just data structures and constants. > +/* > + * This is a work-around since I'm not sure of a better way to copy out the > + * contents of a string. This is used in dtoc/GetProps(). The intent is to > + * pass in a pointer to a property and access the data field at the end of > + * it. Ideally the Data() function above would be able to do this directly, > + * but I'm not sure how to do that. Needs another look. > + */ > +#pragma SWIG nowarn=454 > +%inline %{ > + static struct fdt_property *cur_prop; > + > + void set_prop(struct fdt_property *prop) { > + cur_prop = prop; > + } Eugh... a global variable making this totally non thread safe. You really need a better solution. Property values you should be able to represent nicely as Python strings (since unlike C strings, those can include embedded \0). Uh.. I guess that's 'bytes' for Python3 Of course, in the other direction, node and property names can't include \0, so you probably need some sort of exception if a Python string which includes them is passed in. > +%} > + > +%cstring_output_allocate_size(char **s, int *sz, free(*$1)); > +%inline %{ > + void get_prop_data(char **s, int *sz) { > + *sz = fdt32_to_cpu(cur_prop->len); > + *s = (char *)malloc(*sz); > + if (!*s) > + *sz = 0; > + else > + memcpy(*s, cur_prop + 1, *sz); > + } > +%} > + > +%typemap(in) (const void *) { > + if (!PyByteArray_Check($input)) { > + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " > + "$argnum"" of type '" "$type""'"); > + } > + $1 = (void *) PyByteArray_AsString($input); > +} > + > +int fdt_path_offset(const void *fdt, const char *path); > +int fdt_first_property_offset(const void *fdt, int nodeoffset); > +int fdt_next_property_offset(const void *fdt, int offset); > +const char *fdt_get_name(const void *fdt, int nodeoffset, int *OUTPUT); > +const char *fdt_string(const void *fdt, int stroffset); > +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, > + int offset, > + int *OUTPUT); > +const char *fdt_strerror(int errval); > +int fdt_first_subnode(const void *fdt, int offset); > +int fdt_next_subnode(const void *fdt, int offset); > + > +%typemap(in) (void *) { > + if (!PyByteArray_Check($input)) { > + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " > + "$argnum"" of type '" "$type""'"); > + } > + $1 = PyByteArray_AsString($input); > +} > + > +int fdt_delprop(void *fdt, int nodeoffset, const char *name); > + > +int fdt_pack(void *fdt); > + > +int fdt_totalsize(const void *fdt); > +int fdt_off_dt_struct(const void *fdt); > diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py > new file mode 100644 > index 0000000..8f8618e > --- /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 = "SWIG Docs", > + description = """Simple swig libfdt from docs""", > + ext_modules = [libfdt_module], > + py_modules = ["libfdt"], > + ) -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <20161118003645.GC31640-K0bRW+63XPQe6aEkudXLsA@public.gmane.org>]
* Re: [PATCH 1/4] Add an initial Python library for libfdt [not found] ` <20161118003645.GC31640-K0bRW+63XPQe6aEkudXLsA@public.gmane.org> @ 2016-11-24 18:08 ` Simon Glass [not found] ` <CAPnjgZ1=QTBNZa4G_uFpka3acr91ywH2P1QF8FJkfS-7Wpd5OQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Simon Glass @ 2016-11-24 18:08 UTC (permalink / raw) To: David Gibson; +Cc: Devicetree Compiler Hi David, On 17 November 2016 at 17:36, David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org> wrote: > On Thu, Nov 17, 2016 at 03:53:22PM -0700, Simon Glass wrote: >> Add Python bindings for a bare-bones set of libfdt functions. These allow >> navigating the tree and reading node names and properties. > > Nice idea. Some nits in the details.. > >> >> Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> >> --- >> >> pylibfdt/.gitignore | 3 + >> pylibfdt/Makefile.pylibfdt | 21 ++++++ >> pylibfdt/libfdt.swig | 157 +++++++++++++++++++++++++++++++++++++++++++++ >> pylibfdt/setup.py | 34 ++++++++++ >> 4 files changed, 215 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/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..fbdbca5 >> --- /dev/null >> +++ b/pylibfdt/Makefile.pylibfdt >> @@ -0,0 +1,21 @@ >> +# Makefile.pylibfdt >> +# >> +# This is not a complete Makefile of itself. Instead, it is designed to >> +# be easily embeddable into other systems of Makefiles. > > So, Makefile.libfdt is explicitly designed for easily embedding libfdt > in other projecs - even ones with weird build environments, like > bootloaders. It's less clear that that's valuable for Python > wrappers. OK, but what should i do instead? Regards, Simon ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <CAPnjgZ1=QTBNZa4G_uFpka3acr91ywH2P1QF8FJkfS-7Wpd5OQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 1/4] Add an initial Python library for libfdt [not found] ` <CAPnjgZ1=QTBNZa4G_uFpka3acr91ywH2P1QF8FJkfS-7Wpd5OQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2016-11-24 22:03 ` David Gibson 0 siblings, 0 replies; 8+ messages in thread From: David Gibson @ 2016-11-24 22:03 UTC (permalink / raw) To: Simon Glass; +Cc: Devicetree Compiler [-- Attachment #1: Type: text/plain, Size: 2259 bytes --] On Thu, Nov 24, 2016 at 11:08:00AM -0700, Simon Glass wrote: > Hi David, > > On 17 November 2016 at 17:36, David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org> wrote: > > On Thu, Nov 17, 2016 at 03:53:22PM -0700, Simon Glass wrote: > >> Add Python bindings for a bare-bones set of libfdt functions. These allow > >> navigating the tree and reading node names and properties. > > > > Nice idea. Some nits in the details.. > > > >> > >> Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> > >> --- > >> > >> pylibfdt/.gitignore | 3 + > >> pylibfdt/Makefile.pylibfdt | 21 ++++++ > >> pylibfdt/libfdt.swig | 157 +++++++++++++++++++++++++++++++++++++++++++++ > >> pylibfdt/setup.py | 34 ++++++++++ > >> 4 files changed, 215 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/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..fbdbca5 > >> --- /dev/null > >> +++ b/pylibfdt/Makefile.pylibfdt > >> @@ -0,0 +1,21 @@ > >> +# Makefile.pylibfdt > >> +# > >> +# This is not a complete Makefile of itself. Instead, it is designed to > >> +# be easily embeddable into other systems of Makefiles. > > > > So, Makefile.libfdt is explicitly designed for easily embedding libfdt > > in other projecs - even ones with weird build environments, like > > bootloaders. It's less clear that that's valuable for Python > > wrappers. > > OK, but what should i do instead? Sorry, I just meant that that copied comment doesn't really make sense in its entirity here. Otherwise the makefile is fine. -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] Add tests for pylibfdt [not found] ` <1479423205-9817-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2016-11-17 22:53 ` [PATCH 1/4] Add an initial Python library " Simon Glass @ 2016-11-17 22:53 ` Simon Glass 2016-11-17 22:53 ` [PATCH 3/4] Mention pylibfdt in the documentation Simon Glass 2016-11-17 22:53 ` [PATCH 4/4] RFC: Build pylibfdt as part of the normal build process Simon Glass 3 siblings, 0 replies; 8+ messages in thread From: Simon Glass @ 2016-11-17 22:53 UTC (permalink / raw) To: Devicetree Compiler; +Cc: David Gibson, Simon Glass Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> --- tests/pylibfdt_tests.py | 179 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/run_tests.sh | 19 ++++- 2 files changed, 197 insertions(+), 1 deletion(-) 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..c406ac9 --- /dev/null +++ b/tests/pylibfdt_tests.py @@ -0,0 +1,179 @@ +# pylibfdt - Tests for Flat Device Tree manipulation in Python +# Copyright (C) 2016 Google, Inc. +# Written by Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> +# +# 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 unittest + +sys.path.append('../pylibfdt') +import libfdt + +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 = self._ReadFdt('test_tree1.dtb') + + def _ReadFdt(self, fname): + """Read a device tree file into a bytearray ready for use + + Args: + fname: Filename to read from + + Returns: + Fdt bytearray suitable for passing to libfdt functions + """ + return bytearray(open(fname).read()) + + 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 = libfdt.fdt_path_offset(self.fdt, node_path) + poffset = libfdt.fdt_first_property_offset(self.fdt, node) + while poffset >= 0: + pdata, plen = libfdt.fdt_get_property_by_offset(self.fdt, poffset) + prop_list.append(libfdt.String(self.fdt, pdata.nameoff)) + poffset = libfdt.fdt_next_property_offset(self.fdt, poffset) + return prop_list + + def testImport(self): + """Check that we can import the library correctly""" + self.assertEquals(type(libfdt), type(sys)) + + def testPathOffset(self): + """Check that we can find the offset of a node""" + self.assertEquals(libfdt.fdt_path_offset(self.fdt, '/'), 0) + self.assertEquals(libfdt.fdt_path_offset(self.fdt, '/subnode@1'), 124) + + def testPropertyOffset(self): + """Walk through all the properties in the root node""" + self.assertEquals(libfdt.fdt_first_property_offset(self.fdt, 0), 8) + self.assertEquals(libfdt.fdt_next_property_offset(self.fdt, 8), 32) + self.assertEquals(libfdt.fdt_next_property_offset(self.fdt, 32), 48) + self.assertEquals(libfdt.fdt_next_property_offset(self.fdt, 48), 68) + self.assertEquals(libfdt.fdt_next_property_offset(self.fdt, 68), 92) + self.assertEquals(libfdt.fdt_next_property_offset(self.fdt, 92), 108) + self.assertEquals(libfdt.fdt_next_property_offset(self.fdt, 108), -1) + + def testGetName(self): + """Check that we can get the name of a node""" + self.assertEquals(libfdt.fdt_get_name(self.fdt, 0), ['', 0]) + node = libfdt.fdt_path_offset(self.fdt, '/subnode@1/subsubnode') + self.assertEquals(libfdt.fdt_get_name(self.fdt, node), + ['subsubnode', 10]) + + def testGetString(self): + """Test that we can get a string from the string table""" + node = libfdt.fdt_path_offset(self.fdt, '/subnode@2') + poffset = libfdt.fdt_first_property_offset(self.fdt, node) + pdata, plen = libfdt.fdt_get_property_by_offset(self.fdt, poffset) + self.assertEquals(libfdt.String(self.fdt, pdata.nameoff), 'reg') + + def testGetPropertyByOffset(self): + """Check that we can read the name and contents of a property""" + root = libfdt.fdt_path_offset(self.fdt, '/') + poffset = libfdt.fdt_first_property_offset(self.fdt, root) + pdata, plen = libfdt.fdt_get_property_by_offset(self.fdt, poffset) + self.assertEquals(libfdt.fdt32_to_cpu(pdata.tag), 3) + self.assertEquals(libfdt.fdt32_to_cpu(pdata.len), 11) + self.assertEquals(libfdt.String(self.fdt, pdata.nameoff), 'compatible') + self.assertEquals(libfdt.Data(pdata), 'test_tree1\0') + + def testStrError(self): + """Check that we can get an error string""" + self.assertEquals(libfdt.fdt_strerror(-1), 'FDT_ERR_NOTFOUND') + + def testFirstNextSubnode(self): + """Check that we can walk through subnodes""" + node_list = [] + node = libfdt.fdt_first_subnode(self.fdt, 0) + while node >= 0: + node_list.append(libfdt.fdt_get_name(self.fdt, node)[0]) + node = libfdt.fdt_next_subnode(self.fdt, node) + self.assertEquals(node_list, ['subnode@1', 'subnode@2']) + + 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 = libfdt.fdt_path_offset(self.fdt, '/%s' % node_name) + self.assertEquals(libfdt.fdt_delprop(self.fdt, 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(libfdt.fdt_totalsize(self.fdt), 693) + self.assertEquals(libfdt.fdt_off_dt_struct(self.fdt), 88) + + def testPack(self): + """Test that we can pack the tree after deleting something""" + self.assertEquals(libfdt.fdt_totalsize(self.fdt), 693) + node = libfdt.fdt_path_offset(self.fdt, '/subnode@2') + self.assertEquals(libfdt.fdt_delprop(self.fdt, node, 'prop-int'), 0) + self.assertEquals(libfdt.fdt_totalsize(self.fdt), 693) + self.assertEquals(libfdt.fdt_pack(self.fdt), 0) + self.assertEquals(libfdt.fdt_totalsize(self.fdt), 677) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/run_tests.sh b/tests/run_tests.sh index e4139dd..707702d 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -720,6 +720,20 @@ fdtdump_tests () { run_fdtdump_test fdtdump.dts } +pylibfdt_tests () { + TMP=/tmp/tests.stderr.$$ + python pylibfdt_tests.py 2> ${TMP} + result=$(head -1 ${TMP} | awk \ + '{ for (i = 1; i <= length($0); i++) { \ + result = substr($0,i,1); fail = fail + (result == "F"); \ + ok = ok + (result == ".")}; } END { print fail, ok, fail + ok}') + + # Extract the test results and add them to our totals + tot_fail=$((tot_fail + $(echo $result | cut -d" " -f 1))) + tot_pass=$((tot_pass + $(echo $result | cut -d" " -f 2))) + tot_tests=$((tot_tests + $(echo $result | cut -d" " -f 3))) +} + while getopts "vt:me" ARG ; do case $ARG in "v") @@ -738,7 +752,7 @@ while getopts "vt:me" ARG ; do done if [ -z "$TESTSETS" ]; then - TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump" + TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump pylibfdt" fi # Make sure we don't have stale blobs lying around @@ -767,6 +781,9 @@ for set in $TESTSETS; do "fdtdump") fdtdump_tests ;; + "pylibfdt") + pylibfdt_tests + ;; esac done -- 2.8.0.rc3.226.g39d4020 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/4] Mention pylibfdt in the documentation [not found] ` <1479423205-9817-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2016-11-17 22:53 ` [PATCH 1/4] Add an initial Python library " Simon Glass 2016-11-17 22:53 ` [PATCH 2/4] Add tests for pylibfdt Simon Glass @ 2016-11-17 22:53 ` Simon Glass 2016-11-17 22:53 ` [PATCH 4/4] RFC: Build pylibfdt as part of the normal build process Simon Glass 3 siblings, 0 replies; 8+ messages in thread From: Simon Glass @ 2016-11-17 22:53 UTC (permalink / raw) To: Devicetree Compiler; +Cc: David Gibson, Simon Glass Add a note about pylibfdt in the README. Full documentation for pylibfdt will need to be provided also. Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> --- README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README b/README index f92008f..dee77c8 100644 --- a/README +++ b/README @@ -7,6 +7,12 @@ DTC and LIBFDT are maintained by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org> Jon Loeliger <jdl-CYoMK+44s/E@public.gmane.org> +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 + + Mailing list ------------ The following list is for discussion about dtc and libfdt implementation -- 2.8.0.rc3.226.g39d4020 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/4] RFC: Build pylibfdt as part of the normal build process [not found] ` <1479423205-9817-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> ` (2 preceding siblings ...) 2016-11-17 22:53 ` [PATCH 3/4] Mention pylibfdt in the documentation Simon Glass @ 2016-11-17 22:53 ` Simon Glass 3 siblings, 0 replies; 8+ messages in thread From: Simon Glass @ 2016-11-17 22:53 UTC (permalink / raw) To: Devicetree Compiler; +Cc: David Gibson, Simon Glass Possible this needs to be made optional. For now just hook it up. Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> --- Makefile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 32dcfcf..4996cfd 100644 --- a/Makefile +++ b/Makefile @@ -115,7 +115,7 @@ BIN += fdtput SCRIPTS = dtdiff -all: $(BIN) libfdt +all: $(BIN) libfdt pylibfdt ifneq ($(DEPTARGETS),) @@ -202,6 +202,19 @@ 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 + + # # Release signing and uploading # This is for maintainer convenience, don't try this at home. @@ -240,6 +253,7 @@ STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \ clean: libfdt_clean tests_clean @$(VECHO) CLEAN rm -f $(STD_CLEANFILES) + rm -f $(PYLIBFDT_CLEANFILES) rm -f $(VERSION_FILE) rm -f $(BIN) rm -f dtc-*.tar dtc-*.tar.sign dtc-*.tar.asc -- 2.8.0.rc3.226.g39d4020 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-11-24 22:03 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-11-17 22:53 [PATCH 0/4] Introduce Python bindings for libfdt Simon Glass [not found] ` <1479423205-9817-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2016-11-17 22:53 ` [PATCH 1/4] Add an initial Python library " Simon Glass [not found] ` <1479423205-9817-2-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2016-11-18 0:36 ` David Gibson [not found] ` <20161118003645.GC31640-K0bRW+63XPQe6aEkudXLsA@public.gmane.org> 2016-11-24 18:08 ` Simon Glass [not found] ` <CAPnjgZ1=QTBNZa4G_uFpka3acr91ywH2P1QF8FJkfS-7Wpd5OQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2016-11-24 22:03 ` David Gibson 2016-11-17 22:53 ` [PATCH 2/4] Add tests for pylibfdt Simon Glass 2016-11-17 22:53 ` [PATCH 3/4] Mention pylibfdt in the documentation Simon Glass 2016-11-17 22:53 ` [PATCH 4/4] RFC: Build pylibfdt as part of the normal build process Simon Glass
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).