summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael 'Mickey' Lauer <mickey@vanille-media.de>2005-07-05 13:24:07 +0000
committerMichael 'Mickey' Lauer <mickey@vanille-media.de>2005-07-05 13:24:07 +0000
commit7247d4db438a1994e903250a9edaad0592dd5e2a (patch)
treee650c21e0750e97c34c5f2535c824c47842d229a
parent75f4537cde17796b6b9c24efda3c5eea6b088159 (diff)
downloadbitbake-1.3.1.tar.gz
retagging before reintegration of make.py1.3.1
-rw-r--r--trunk/bitbake-data/AUTHORS1
-rw-r--r--trunk/bitbake-data/ChangeLog41
-rw-r--r--trunk/bitbake-data/Makefile.am23
-rw-r--r--trunk/bitbake-data/README2
-rw-r--r--trunk/bitbake-data/TODO23
-rw-r--r--trunk/bitbake-data/acinclude.m411
-rw-r--r--trunk/bitbake-data/bitbake-data.pc.in10
-rwxr-xr-xtrunk/bitbake-data/config/autogen.sh3
-rw-r--r--trunk/bitbake-data/config/version.m416
-rw-r--r--trunk/bitbake-data/configure.ac118
-rw-r--r--trunk/bitbake-data/doc/Makefile.am4
-rw-r--r--trunk/bitbake-data/doc/REQUIREMENTS33
-rw-r--r--trunk/bitbake-data/doc/doxygen/Makefile.am10
-rw-r--r--trunk/bitbake-data/doc/doxygen/doxygen.am186
-rw-r--r--trunk/bitbake-data/doc/doxygen/doxygen.cfg212
-rw-r--r--trunk/bitbake-data/doc/test_scoped_lookups.sql92
-rw-r--r--trunk/bitbake-data/include/bitbake-data.h144
-rw-r--r--trunk/bitbake-data/include/bitbake-data/common.h82
-rw-r--r--trunk/bitbake-data/include/bitbake-data/private.h148
-rw-r--r--trunk/bitbake-data/m4/external/check.m4133
-rw-r--r--trunk/bitbake-data/m4/internal/doxygen.m4312
-rw-r--r--trunk/bitbake-data/m4/internal/visibility.m474
-rw-r--r--trunk/bitbake-data/src/Makefile.am13
-rw-r--r--trunk/bitbake-data/src/backend-sqlite3.c372
-rw-r--r--trunk/bitbake-data/tests/Makefile.am19
-rw-r--r--trunk/bitbake-data/tests/check_bitbake_data.c210
-rw-r--r--trunk/bitbake-ng/ChangeLog36
-rw-r--r--trunk/bitbake-ng/Makefile.am19
-rw-r--r--trunk/bitbake-ng/acinclude.m411
-rw-r--r--trunk/bitbake-ng/bitbake-0.0.pc.in10
-rwxr-xr-xtrunk/bitbake-ng/config/autogen.sh3
-rw-r--r--trunk/bitbake-ng/config/version.m416
-rw-r--r--trunk/bitbake-ng/configure.ac114
-rw-r--r--trunk/bitbake-ng/doc/Makefile.am11
-rw-r--r--trunk/bitbake-ng/doc/design_spec/Makefile.am20
-rw-r--r--trunk/bitbake-ng/doc/design_spec/design_spec.xml156
-rw-r--r--trunk/bitbake-ng/doc/design_spec/html.css281
-rw-r--r--trunk/bitbake-ng/doc/doxygen.am186
-rw-r--r--trunk/bitbake-ng/doc/doxygen.cfg212
-rw-r--r--trunk/bitbake-ng/doc/ramblings/bbtree.txt39
-rw-r--r--trunk/bitbake-ng/doc/ramblings/bitbakeng-metadata.txt103
-rw-r--r--trunk/bitbake-ng/doc/ramblings/bitbakeng-parser-frontend.txt21
-rw-r--r--trunk/bitbake-ng/include/Makefile.am2
-rw-r--r--trunk/bitbake-ng/include/bitbake.h40
-rw-r--r--trunk/bitbake-ng/include/bitbake/common.h82
-rw-r--r--trunk/bitbake-ng/include/bitbake/data-private.h139
-rw-r--r--trunk/bitbake-ng/include/bitbake/data.h183
-rw-r--r--trunk/bitbake-ng/include/bitbake/recipe-modules.h50
-rw-r--r--trunk/bitbake-ng/include/bitbake/recipe.h58
-rw-r--r--trunk/bitbake-ng/m4/external/check.m4133
-rw-r--r--trunk/bitbake-ng/m4/internal/binreloc.m476
-rw-r--r--trunk/bitbake-ng/m4/internal/doxygen.m4312
-rw-r--r--trunk/bitbake-ng/m4/internal/visibility.m474
-rw-r--r--trunk/bitbake-ng/src/Makefile.am12
-rw-r--r--trunk/bitbake-ng/src/binreloc.c436
-rw-r--r--trunk/bitbake-ng/src/binreloc.h121
-rw-r--r--trunk/bitbake-ng/src/data.c173
-rw-r--r--trunk/bitbake-ng/tests/Makefile.am19
-rw-r--r--trunk/bitbake-ng/tests/check_bitbake_data.c125
-rw-r--r--trunk/bitbake/AUTHORS5
-rw-r--r--trunk/bitbake/ChangeLog26
-rw-r--r--trunk/bitbake/MANIFEST27
-rw-r--r--trunk/bitbake/TODO18
-rwxr-xr-xtrunk/bitbake/bin/bbimage154
-rwxr-xr-xtrunk/bitbake/bin/bbread50
-rwxr-xr-xtrunk/bitbake/bin/bitbake716
-rwxr-xr-xtrunk/bitbake/bin/bitdoc510
-rw-r--r--trunk/bitbake/classes/base.bbclass79
-rw-r--r--trunk/bitbake/conf/bitbake.conf55
-rw-r--r--trunk/bitbake/contrib/README1
-rw-r--r--trunk/bitbake/contrib/bbdev.sh31
-rw-r--r--trunk/bitbake/contrib/vim/syntax/bitbake.vim120
-rw-r--r--trunk/bitbake/doc/COPYING.GPL340
-rw-r--r--trunk/bitbake/doc/COPYING.MIT17
-rw-r--r--trunk/bitbake/doc/manual/Makefile56
-rw-r--r--trunk/bitbake/doc/manual/html.css281
-rw-r--r--trunk/bitbake/doc/manual/usermanual.xml329
-rw-r--r--trunk/bitbake/lib/bb/__init__.py1267
-rw-r--r--trunk/bitbake/lib/bb/build.py395
-rw-r--r--trunk/bitbake/lib/bb/data.py579
-rw-r--r--trunk/bitbake/lib/bb/data_smart.py328
-rw-r--r--trunk/bitbake/lib/bb/event.py210
-rw-r--r--trunk/bitbake/lib/bb/fetch.py646
-rw-r--r--trunk/bitbake/lib/bb/make.py246
-rw-r--r--trunk/bitbake/lib/bb/manifest.py144
-rw-r--r--trunk/bitbake/lib/bb/parse/BBHandler.py378
-rw-r--r--trunk/bitbake/lib/bb/parse/ConfHandler.py194
-rw-r--r--trunk/bitbake/lib/bb/parse/__init__.py76
-rw-r--r--trunk/bitbake/lib/bb/shell.py764
-rwxr-xr-xtrunk/bitbake/setup.py70
-rwxr-xr-xtrunk/bitbake_qa/bin/bittest208
-rwxr-xr-xtrunk/bitbake_qa/classes/base.bbclass775
-rw-r--r--trunk/bitbake_qa/conf/bitbake.conf379
-rw-r--r--trunk/bitbake_qa/conf/testrun.conf.sample9
-rw-r--r--trunk/bitbake_qa/content_checker/__init__.py40
-rw-r--r--trunk/bitbake_qa/content_checker/content_checker.py67
-rw-r--r--trunk/bitbake_qa/doc/README29
-rw-r--r--trunk/bitbake_qa/doc_checker/__init__.py40
-rw-r--r--trunk/bitbake_qa/doc_checker/doc_checker.py74
-rw-r--r--trunk/bitbake_qa/example/__init__.py41
-rw-r--r--trunk/bitbake_qa/example/example.py59
-rw-r--r--trunk/bitbake_qa/lib/bittest/__init__.py14
-rw-r--r--trunk/bitbake_qa/lib/bittest/config.py79
-rw-r--r--trunk/bitbake_qa/lib/bittest/fileparser.py52
-rw-r--r--trunk/bitbake_qa/lib/bittest/testoutput_text.py52
-rw-r--r--trunk/bitbake_qa/lib/bittest/testresult.py116
-rw-r--r--trunk/bitbake_qa/patch_checker/__init__.py42
-rw-r--r--trunk/bitbake_qa/patch_checker/patch_checker.py82
-rw-r--r--trunk/bitbake_qa/source_checker/__init__.py40
-rw-r--r--trunk/bitbake_qa/source_checker/source_checker.py80
110 files changed, 15955 insertions, 0 deletions
diff --git a/trunk/bitbake-data/AUTHORS b/trunk/bitbake-data/AUTHORS
new file mode 100644
index 000000000..19beca158
--- /dev/null
+++ b/trunk/bitbake-data/AUTHORS
@@ -0,0 +1 @@
+Chris Larson <kergoth@handhelds.org>
diff --git a/trunk/bitbake-data/ChangeLog b/trunk/bitbake-data/ChangeLog
new file mode 100644
index 000000000..020302959
--- /dev/null
+++ b/trunk/bitbake-data/ChangeLog
@@ -0,0 +1,41 @@
+2005-02-17 Chris Larson <kergoth@handhelds.org>
+
+ * src/backend-sqlite3.c, include/bitbake-data.h: Adjust the API so
+ that bitbake-data users aren't required to link against glib-2.0
+ themselves.
+
+2005-02-03 Chris Larson <kergoth@handhelds.org>
+
+ * doc/doxygen.cfg, doc/doxygen.m4, doc/Makefile.am, configure.ac,
+ Makefile.am: Add doxygen doc generation.
+ * include/bitbake-data.h, src/backend-sqlite3.h: Add datastore process
+ wide initialization and shutdown based on usage count.
+ * src/backend-sqlite3.h: Add calls to sqlite3 to open and close the
+ recipe database.
+ * src/backend-sqlite3.h, include/bitbake-data.h: Adjust the
+ bb_data_destroy function. Now accepts a new gboolean
+ parameter to indicate that the data can be truly removed -- only
+ affects behavior of stores which are persistant. Setting said
+ parameter to TRUE will remove the data for the recipe in question
+ from the persistant store completely, rather than just freeing our
+ datastructures.
+ * bitbake-data-0.0.pc.in, bitbake-data.pc.in: Renamed.
+ * configure.ac: Update per .pc.in rename.
+ * Makefile.am: Create a .pc based on LT_RELEASE, and install our .pc.
+ * src/Makefile.am: Don't hardcode the library release. Use
+ @LT_RELEASE@ where appropriate instead.
+ * README, AUTHORS: New file.
+ * configure.ac, Makefile.am, tests/Makefile.am, tests/check_bitbake_data.c:
+ Add the first of our unit tests using 'check'.
+ * src/backend-sqlite3.c, include/bitbake-data/private.h, tests/check_bitbake_data.c:
+ Add the variable and variable attribute lookup, insertion, and
+ removal routines.
+ * src/backend-sqlite3.c, tests/check_bitbake_data.c: Start rework of
+ sqlite tables to accomidate scope resolution.
+
+2005-02-02 Chris Larson <kergoth@handhelds.org>
+
+ * Many files: Created initial repository.
+ * include/bitbake-data/common.h: Add common header for things like gcc
+ visibility macros.
+ * doc/REQUIREMENTS: Add musings on requirements.
diff --git a/trunk/bitbake-data/Makefile.am b/trunk/bitbake-data/Makefile.am
new file mode 100644
index 000000000..b88978ac4
--- /dev/null
+++ b/trunk/bitbake-data/Makefile.am
@@ -0,0 +1,23 @@
+# SUBDIRS = include src tests doc
+SUBDIRS = src doc tests
+
+ACLOCAL_AMFLAGS = -I m4/internal -I m4/external
+AUTOMAKE_OPTIONS = foreign 1.6
+
+MAINT_CLEAN_FILES_AUX = config.guess config.sub depcomp \
+ install-sh missing ltmain.sh \
+ compile mkinstalldirs
+MAINT_CLEAN_FILES_TOP = config.h.in aclocal.m4 \
+ configure Makefile.in stamp-h.in
+MAINT_CLEAN_FILES = $(foreach f,$(MAINT_CLEAN_FILES_TOP),$(top_srcdir)/$(f) $(top_srcdir)/$(f)\~) \
+ $(foreach f,$(MAINT_CLEAN_FILES_AUX),$(auxdir)/$(f) $(auxdir)/$(f)\~)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = bitbake-data-@LT_RELEASE@.pc
+
+maintainer-clean-local:
+ rm -f $(MAINT_CLEAN_FILES)
+
+.PHONY: test
+test:
+ @$(MAKE) -C tests $@
diff --git a/trunk/bitbake-data/README b/trunk/bitbake-data/README
new file mode 100644
index 000000000..80120841a
--- /dev/null
+++ b/trunk/bitbake-data/README
@@ -0,0 +1,2 @@
+bitbake-data is a supplementary library to be used by recipe handlers
+in the bitbake 2.0 library. It provides a metadata store for the recipes.
diff --git a/trunk/bitbake-data/TODO b/trunk/bitbake-data/TODO
new file mode 100644
index 000000000..689c12106
--- /dev/null
+++ b/trunk/bitbake-data/TODO
@@ -0,0 +1,23 @@
+TODO List
+---------
+NOTE: This is a very simple library with a specific purpose in mind, but we want to
+make sure it's done right, since performance or scalability problems could impact the
+entirety of bitbake and bitbake-ng. --CML
+
+[ ] Fix up the API to accomidate proper error handling, in order to respond to the user
+ and let them know what's going on. A common problem would be not having write access
+ to the default BBDATAPATH. Perhaps a more sane default for a normal user would be a
+ file in /var/tmp.
+[ ] Test repeatedly the basic variable set/get/delete operations.
+[ ] Document whether or not the set functions copy the strings of the key/value or use
+ them as is, in the doxygen markup.
+[ ] Code/test/sanity check variable attribute operations.
+[ ] Code/test the last modif date function.
+[ ] Profile the code to ensure it will meet our needs.
+[ ] If necessary, optimize the bottlenecks.
+[ ] Add functions to supply optimization hints to the datastore. This is almost certain
+ to be necessary, as writes to sqlite are quickest when done in a single transaction.
+ So, you'd have a function stating that you'll be using this heavily for a while, as
+ a hint that perhaps it should be keeping it in RAM until you're done, or postpone
+ COMMIT until you're done.
+[ ] Start using it.
diff --git a/trunk/bitbake-data/acinclude.m4 b/trunk/bitbake-data/acinclude.m4
new file mode 100644
index 000000000..4550d1cb8
--- /dev/null
+++ b/trunk/bitbake-data/acinclude.m4
@@ -0,0 +1,11 @@
+# BB_DEFAULT_FLAGS
+# ----------
+# Set our default FLAGS variables.
+# Remember to call before the AC_PROG_ macros, otherwise those
+# defaults will be used instead of ours.
+AC_DEFUN([BB_DEFAULT_FLAGS],
+[
+ if test x"$CFLAGS" = "x"; then
+ CFLAGS="-O2 -Wall -W"
+ fi
+]) # BB_DEFAULT_FLAGS
diff --git a/trunk/bitbake-data/bitbake-data.pc.in b/trunk/bitbake-data/bitbake-data.pc.in
new file mode 100644
index 000000000..9ed4c60a2
--- /dev/null
+++ b/trunk/bitbake-data/bitbake-data.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE@
+Description: @PACKAGE_DESCRIPTION@
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lbitbake-@LT_RELEASE@
+Cflags: -I${includedir}/bitbake-@LT_RELEASE@
diff --git a/trunk/bitbake-data/config/autogen.sh b/trunk/bitbake-data/config/autogen.sh
new file mode 100755
index 000000000..adb32b638
--- /dev/null
+++ b/trunk/bitbake-data/config/autogen.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+autoreconf -f -i -I `pwd`/m4
diff --git a/trunk/bitbake-data/config/version.m4 b/trunk/bitbake-data/config/version.m4
new file mode 100644
index 000000000..79017ddce
--- /dev/null
+++ b/trunk/bitbake-data/config/version.m4
@@ -0,0 +1,16 @@
+dnl bitbake-ng package version
+m4_define([BBDATA_VER], [0.1])
+
+dnl bitbake-ng library "release" version
+dnl "0.0" in bitbake-ng-0.0.so
+dnl Increment on API break.
+m4_define([BBDATA_LT_REL], [0.0])
+
+dnl bitbake-ng libtool library version
+
+dnl Current, increment on ABI break
+m4_define([BBDATA_LT_CUR], [0])
+dnl Revision, increment at release
+m4_define([BBDATA_LT_REV], [0])
+dnl Age
+m4_define([BBDATA_LT_AGE], [0])
diff --git a/trunk/bitbake-data/configure.ac b/trunk/bitbake-data/configure.ac
new file mode 100644
index 000000000..69726034d
--- /dev/null
+++ b/trunk/bitbake-data/configure.ac
@@ -0,0 +1,118 @@
+# get our package versions
+m4_include([config/version.m4])
+
+
+# initialization
+AC_INIT(bitbake-data, BBDATA_VER, bitbake-dev@lists.berlios.de)
+AC_PREREQ(2.57)
+
+AC_CONFIG_SRCDIR([include/bitbake-data.h])
+AC_CONFIG_AUX_DIR(config)
+AM_CONFIG_HEADER([config.h])
+
+AM_INIT_AUTOMAKE
+
+
+PACKAGE_DESCRIPTION="A supplementary library to the bitbake project to act as a datastore."
+AC_SUBST([PACKAGE_DESCRIPTION])
+
+# library versioning
+LT_RELEASE=BBDATA_LT_REL
+AC_SUBST([LT_RELEASE])
+
+LT_CURRENT=BBDATA_LT_CUR
+AC_SUBST([LT_CURRENT])
+
+LT_REVISION=BBDATA_LT_REV
+AC_SUBST([LT_REVISION])
+
+LT_AGE=BBDATA_LT_AGE
+AC_SUBST([LT_AGE])
+
+
+# system
+AC_CANONICAL_SYSTEM
+
+
+# paths
+auxdir="\$(top_srcdir)/$ac_aux_dir"
+AC_SUBST(auxdir)
+
+reldatadir="\$(datadir)/bitbake-data-\$(LT_RELEASE)"
+rellibdir="\$(libdir)/bitbake-data-\$(LT_RELEASE)"
+relincludedir="\$(includedir)/bitbake-data-\$(LT_RELEASE)"
+AC_SUBST([reldatadir])
+AC_SUBST([rellibdir])
+AC_SUBST([relincludedir])
+
+
+# programs
+BB_DEFAULT_FLAGS
+
+AC_PROG_CC
+BB_CC_HIDDEN_VISIBILITY
+
+AC_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+
+
+
+# dependencies
+PKG_CHECK_MODULES([GLIB2], [glib-2.0])
+PKG_CHECK_MODULES([SQLITE3], [sqlite3])
+
+
+# docbook documentation
+# AC_CHECK_PROGS([XMLLINT], [xmllint])
+# AC_CHECK_PROGS([XSLTPROC], [xsltproc])
+
+# doxygen documentation
+DX_HTML_FEATURE(ON)
+DX_CHM_FEATURE(OFF)
+DX_CHI_FEATURE(OFF)
+DX_MAN_FEATURE(ON)
+DX_RTF_FEATURE(OFF)
+DX_XML_FEATURE(OFF)
+DX_PDF_FEATURE(ON)
+DX_PS_FEATURE(OFF)
+DX_INIT_DOXYGEN($PACKAGE, [doc/doxygen/doxygen.cfg], [doc/doxygen/output])
+
+
+# options
+AC_MSG_CHECKING([whether user requested building tests])
+AC_ARG_ENABLE(tests,
+ AS_HELP_STRING([--enable-tests],
+ [Enable building of tests (default=no)]),
+ [enable_tests=$enableval],
+ [enable_tests=no])
+AC_MSG_RESULT($enable_tests)
+AM_CONDITIONAL(BB_TESTS, test "$enable_tests" = "yes")
+
+# see if 'check', the unit testing framework, is installed
+if test x"$enable_tests" != "xno"; then
+ AM_PATH_CHECK
+fi
+
+
+# other
+# AM_BINRELOC
+
+
+# This variable is used to indicate whether we're compiling
+# a part of our library itself, or external binaries.
+BBDATA_DLL_EXPORTS="-DBBDATA_DLL_EXPORTS"
+AC_SUBST([BBDATA_DLL_EXPORTS])
+
+
+# output
+AC_CONFIG_FILES([Makefile
+ src/Makefile
+ doc/Makefile
+ doc/doxygen/Makefile
+ tests/Makefile
+ bitbake-data-$LT_RELEASE.pc:bitbake-data.pc.in])
+# AC_CONFIG_FILES([Makefile
+# include/Makefile
+# doc/design_spec/Makefile
+# bitbake-data-0.0.pc])
+AC_OUTPUT
diff --git a/trunk/bitbake-data/doc/Makefile.am b/trunk/bitbake-data/doc/Makefile.am
new file mode 100644
index 000000000..c2bde057a
--- /dev/null
+++ b/trunk/bitbake-data/doc/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = doxygen
+
+maintainer-clean-local:
+ rm -f $(srcdir)/Makefile.in
diff --git a/trunk/bitbake-data/doc/REQUIREMENTS b/trunk/bitbake-data/doc/REQUIREMENTS
new file mode 100644
index 000000000..5f471332f
--- /dev/null
+++ b/trunk/bitbake-data/doc/REQUIREMENTS
@@ -0,0 +1,33 @@
+[ ] Key/value pairs, as close to O(1) as is possible
+[ ] "Attributes".. that is, metadata about our metadata
+[ ] Each store of metadata is bound to a recipe, and we need a way for the
+ recipe handler to deal with the determination of whether the information
+ in the metadata store is current. Either it asks the store for a last
+ modification date, or the other way around.
+
+[ ] Persistance? Is persistance a requirement or an optimization?
+ Really, it's an optimization. If the metadata store isn't persistant,
+ then we need to use whatever other intermediate form is available (i.e.
+ compiled form) to repopulate it on every execution.
+
+ So it isn't a requirement, but the recipe handler needs to be able to
+ determine whether the bitbake-data store in question is up to date or not.
+
+ Perhaps something as simple as a "last modification" date would do.
+
+[ ] If it is persistant, where is the persistant form stored? Who makes that
+ decision? A variable in the store itself? The recipe handler via a function
+ call? This data really is specific to a certain bitbake recipe or set of
+ bitbake recipes. We could probably store this in /var/ if we're careful
+ about tracking the sources of the data.
+
+ We have to track what bitbake recipe this data belongs to regardless. Either
+ one big sqlite3 db, or a bunch of individual files, the info we have to track
+ remains the same. The choice of implementation just comes down to efficiency.
+
+[ ] Do we really need more than one backend module at runtime, or would compiletime
+ suffice? Are the needs for metadata handling between recipe handlers the same?
+ And if not, how does the recipe handler go about choosing a metadata module? Or
+ should that be in the hands of the user? I'm voting for a single compiletime
+ module, so it's easy to replace later, but without having to deal with module
+ selection at runtime.
diff --git a/trunk/bitbake-data/doc/doxygen/Makefile.am b/trunk/bitbake-data/doc/doxygen/Makefile.am
new file mode 100644
index 000000000..36f4d8649
--- /dev/null
+++ b/trunk/bitbake-data/doc/doxygen/Makefile.am
@@ -0,0 +1,10 @@
+MOSTLYCLEANFILES = $(DX_CLEANFILES)
+EXTRA_DIST = $(DX_CONFIG)
+
+include doxygen.am
+
+# all: doxygen-doc
+
+maintainer-clean-local:
+ rm -f $(srcdir)/Makefile.in
+ -rmdir output
diff --git a/trunk/bitbake-data/doc/doxygen/doxygen.am b/trunk/bitbake-data/doc/doxygen/doxygen.am
new file mode 100644
index 000000000..420049eca
--- /dev/null
+++ b/trunk/bitbake-data/doc/doxygen/doxygen.am
@@ -0,0 +1,186 @@
+# Copyright (C) 2004 Oren Ben-Kiki
+# This file is distributed under the same terms as the Automake macro files.
+
+# Generate automatic documentation using Doxygen. Goals and variables values
+# are controlled by the various DX_COND_??? conditionals set by autoconf.
+#
+# The provided goals are:
+# doxygen-doc: Generate all doxygen documentation.
+# doxygen-run: Run doxygen, which will generate some of the documentation
+# (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post
+# processing required for the rest of it (PS, PDF, and some MAN).
+# doxygen-man: Rename some doxygen generated man pages.
+# doxygen-ps: Generate doxygen PostScript documentation.
+# doxygen-pdf: Generate doxygen PDF documentation.
+#
+# Note that by default these are not integrated into the automake goals. If
+# doxygen is used to generate man pages, you can achieve this integration by
+# setting man3_MANS to the list of man pages generated and then adding the
+# dependency:
+#
+# $(man3_MANS): doxygen-doc
+#
+# This will cause make to run doxygen and generate all the documentation.
+#
+# The following variable is intended for use in Makefile.am:
+#
+# DX_CLEANFILES = everything to clean.
+#
+# This is usually added to MOSTLYCLEANFILES.
+
+## --------------------------------- ##
+## Format-independent Doxygen rules. ##
+## --------------------------------- ##
+
+if DX_COND_doc
+
+## ------------------------------- ##
+## Rules specific for HTML output. ##
+## ------------------------------- ##
+
+if DX_COND_html
+
+DX_CLEAN_HTML = @DX_DOCDIR@/html
+
+endif DX_COND_html
+
+## ------------------------------ ##
+## Rules specific for CHM output. ##
+## ------------------------------ ##
+
+if DX_COND_chm
+
+DX_CLEAN_CHM = @DX_DOCDIR@/chm
+
+if DX_COND_chi
+
+DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi
+
+endif DX_COND_chi
+
+endif DX_COND_chm
+
+## ------------------------------ ##
+## Rules specific for MAN output. ##
+## ------------------------------ ##
+
+if DX_COND_man
+
+DX_CLEAN_MAN = @DX_DOCDIR@/man
+
+endif DX_COND_man
+
+## ------------------------------ ##
+## Rules specific for RTF output. ##
+## ------------------------------ ##
+
+if DX_COND_rtf
+
+DX_CLEAN_RTF = @DX_DOCDIR@/rtf
+
+endif DX_COND_rtf
+
+## ------------------------------ ##
+## Rules specific for XML output. ##
+## ------------------------------ ##
+
+if DX_COND_xml
+
+DX_CLEAN_XML = @DX_DOCDIR@/xml
+
+endif DX_COND_xml
+
+## ----------------------------- ##
+## Rules specific for PS output. ##
+## ----------------------------- ##
+
+if DX_COND_ps
+
+DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps
+
+DX_PS_GOAL = doxygen-ps
+
+doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps
+
+@DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag
+ cd @DX_DOCDIR@/latex; \
+ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
+ $(DX_LATEX) refman.tex; \
+ $(MAKEINDEX_PATH) refman.idx; \
+ $(DX_LATEX) refman.tex; \
+ countdown=5; \
+ while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
+ refman.log > /dev/null 2>&1 \
+ && test $$countdown -gt 0; do \
+ $(DX_LATEX) refman.tex; \
+ countdown=`expr $$countdown - 1`; \
+ done; \
+ $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi
+
+endif DX_COND_ps
+
+## ------------------------------ ##
+## Rules specific for PDF output. ##
+## ------------------------------ ##
+
+if DX_COND_pdf
+
+DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf
+
+DX_PDF_GOAL = doxygen-pdf
+
+doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf
+
+@DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag
+ cd @DX_DOCDIR@/latex; \
+ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
+ $(DX_PDFLATEX) refman.tex; \
+ $(DX_MAKEINDEX) refman.idx; \
+ $(DX_PDFLATEX) refman.tex; \
+ countdown=5; \
+ while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
+ refman.log > /dev/null 2>&1 \
+ && test $$countdown -gt 0; do \
+ $(DX_PDFLATEX) refman.tex; \
+ countdown=`expr $$countdown - 1`; \
+ done; \
+ mv refman.pdf ../@PACKAGE@.pdf
+
+endif DX_COND_pdf
+
+## ------------------------------------------------- ##
+## Rules specific for LaTeX (shared for PS and PDF). ##
+## ------------------------------------------------- ##
+
+if DX_COND_latex
+
+DX_CLEAN_LATEX = @DX_DOCDIR@/latex
+
+endif DX_COND_latex
+
+.PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)
+
+.INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
+
+doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag
+
+doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
+
+@DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS)
+ rm -rf @DX_DOCDIR@
+ $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)
+
+DX_CLEANFILES = \
+ @DX_DOCDIR@/@PACKAGE@.tag \
+ -r \
+ $(DX_CLEAN_HTML) \
+ $(DX_CLEAN_CHM) \
+ $(DX_CLEAN_CHI) \
+ $(DX_CLEAN_MAN) \
+ $(DX_CLEAN_RTF) \
+ $(DX_CLEAN_XML) \
+ $(DX_CLEAN_PS) \
+ $(DX_CLEAN_PDF) \
+ $(DX_CLEAN_LATEX)
+
+endif DX_COND_doc
diff --git a/trunk/bitbake-data/doc/doxygen/doxygen.cfg b/trunk/bitbake-data/doc/doxygen/doxygen.cfg
new file mode 100644
index 000000000..cacfca060
--- /dev/null
+++ b/trunk/bitbake-data/doc/doxygen/doxygen.cfg
@@ -0,0 +1,212 @@
+# Doxyfile 1.3.7
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = $(PROJECT)-$(VERSION)
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = $(DOCDIR)
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+STRIP_FROM_INC_PATH = $(SRCDIR)
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = $(SRCDIR)/include $(SRCDIR)
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = YES
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = YES
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = NO
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = $(SRCDIR)/include $(SRCDIR)/src
+FILE_PATTERNS = *.c *.h
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS = *-private*
+EXAMPLE_PATH = $(SRCDIR)
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = $(GENERATE_HTML)
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = $(GENERATE_CHM)
+CHM_FILE = ../$(PROJECT).chm
+HHC_LOCATION = $(HHC_PATH)
+GENERATE_CHI = $(GENERATE_CHI)
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = $(GENERATE_LATEX)
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = $(PAPER_SIZE)
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = YES
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = $(GENERATE_RTF)
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = $(GENERATE_MAN)
+MAN_OUTPUT = man
+MAN_EXTENSION = .1
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = $(GENERATE_XML)
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = $(PERL_PATH)
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = $(HAVE_DOT)
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH = $(DOT_PATH)
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/trunk/bitbake-data/doc/test_scoped_lookups.sql b/trunk/bitbake-data/doc/test_scoped_lookups.sql
new file mode 100644
index 000000000..9d70db059
--- /dev/null
+++ b/trunk/bitbake-data/doc/test_scoped_lookups.sql
@@ -0,0 +1,92 @@
+BEGIN TRANSACTION;
+CREATE TABLE recipes(id integer primary key, recipe text not null);
+CREATE TABLE scope(id integer primary key, priority integer, scope_recipe_id integer, recipe_id integer);
+CREATE TABLE vars(id integer primary key, var text, val text, recipe_id integer);
+
+INSERT INTO "recipes" VALUES(NULL, 'bitbake.conf');
+INSERT INTO "recipes" VALUES(NULL, 'base.bbclass');
+INSERT INTO "recipes" VALUES(NULL, 'autotools.bbclass');
+INSERT INTO "recipes" VALUES(NULL, 'a.bb');
+INSERT INTO "recipes" VALUES(NULL, 'b.bb');
+
+-- Attach scopes to base.bbclass, in this case only bitbake.conf and itself.
+INSERT INTO "scope" VALUES(NULL, 2, 2, 2);
+INSERT INTO "scope" VALUES(NULL, 1, 1, 2);
+
+-- Attach scopes to autotools.bbclass, in this case bitbake.conf, base.bbclass, and itself.
+INSERT INTO "scope" VALUES(NULL, 3, 3, 3);
+INSERT INTO "scope" VALUES(NULL, 2, 2, 3);
+INSERT INTO "scope" VALUES(NULL, 1, 1, 3);
+
+-- Attach scopes to a.bb, in this case bitbake.conf, base.bbclass, and itself.
+INSERT INTO "scope" VALUES(NULL, 3, 4, 4);
+INSERT INTO "scope" VALUES(NULL, 2, 2, 4);
+INSERT INTO "scope" VALUES(NULL, 1, 1, 4);
+
+-- Attach scopes to a.bb, in this case bitbake.conf, base.bbclass, autotools.bbclass and itself.
+INSERT INTO "scope" VALUES(NULL, 1, 1, 5);
+INSERT INTO "scope" VALUES(NULL, 2, 2, 5);
+INSERT INTO "scope" VALUES(NULL, 3, 3, 5);
+INSERT INTO "scope" VALUES(NULL, 4, 5, 5);
+
+-- Populate a variety of variables and values so that we can see what's happening.
+INSERT INTO "vars" VALUES(NULL, 'CC', 'bitbake.conf_cc', 1);
+INSERT INTO "vars" VALUES(NULL, 'CXX', 'bitbake.conf_cxx', 1);
+INSERT INTO "vars" VALUES(NULL, 'CC', 'base.bbclass_cc', 2);
+INSERT INTO "vars" VALUES(NULL, 'CC', 'autotools.bbclass_cc', 3);
+INSERT INTO "vars" VALUES(NULL, 'CC', 'a.bb_cc', 4);
+INSERT INTO "vars" VALUES(NULL, 'CC', 'b.bb_cc', 5);
+INSERT INTO "vars" VALUES(NULL, 'CPP', 'b.bb_cpp', 5);
+
+COMMIT;
+
+-- Gets the highest priority value for 'CC', from base.bbclass and its scopes, by name
+
+-- SELECT val FROM vars
+-- JOIN scope ON vars.recipe_id = scope.scope_recipe_id
+-- JOIN recipes ON scope.recipe_id = recipes.id
+-- WHERE vars.var = 'CC' AND recipes.recipe = 'base.bbclass'
+-- ORDER BY scope.priority DESC
+-- limit 1;
+
+
+-- Gets the highest priority value for 'CC', from a.bb and its scopes
+
+-- SELECT val FROM vars
+-- JOIN scope ON vars.recipe_id = scope.scope_recipe_id
+-- WHERE vars.var = 'CC' AND scope.recipe_id = 4
+-- ORDER BY scope.priority DESC
+-- limit 1;
+
+
+-- Gets the variable name and max priority for that variable, for each var
+
+-- SELECT vars.var, MAX(scope.priority) FROM vars
+-- JOIN scope ON vars.recipe_id = scope.scope_recipe_id
+-- WHERE scope.recipe_id = 4
+-- GROUP BY vars.var;
+
+
+-- Gets all the variables, values, and priorities for a given recipe and its scopes
+-- Includes all the values for a given var, not just the highest priority one, leaving
+-- that piece in the hands of the C code.
+
+-- SELECT vars.var, vars.val, scope.priority FROM vars
+-- JOIN scope ON vars.recipe_id = scope.scope_recipe_id
+-- WHERE scope.recipe_id = 4;
+
+
+-- Get the highest priority value for each and every variable in a given
+-- recipe and its scopes (not unlike running bbread on a .bb file)
+
+-- SELECT vars.var, vars.val, scope.priority, maxes.max FROM vars, scope, recipes
+-- JOIN (SELECT vars.var var, MAX(scope.priority) max
+-- FROM vars, scope, recipes
+-- WHERE vars.recipe_id = scope.scope_recipe_id AND
+-- scope.recipe_id = recipes.id AND
+-- recipes.recipe = 'b.bb'
+-- GROUP BY vars.var) maxes ON vars.var = maxes.var
+-- WHERE recipes.recipe = 'b.bb' AND
+-- vars.recipe_id = scope.scope_recipe_id AND
+-- scope.recipe_id = recipes.id AND
+-- scope.priority = maxes.max;
diff --git a/trunk/bitbake-data/include/bitbake-data.h b/trunk/bitbake-data/include/bitbake-data.h
new file mode 100644
index 000000000..23a6ed65a
--- /dev/null
+++ b/trunk/bitbake-data/include/bitbake-data.h
@@ -0,0 +1,144 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BITBAKE_DATA_H
+# define _BITBAKE_DATA_H
+
+# include <bitbake-data/common.h>
+
+BBDATA_HDR_BEGIN
+
+
+/** @file bitbake-data.h
+ * @brief Header for bitbake metadata handling */
+
+/**
+ *@brief Creates a new bitbake metadata store
+ *
+ *@param recipe A unique identifier for a given recipe for use in the store.
+ * The most common case would be to pass the full path + filename
+ * of the recipe in the filesystem.
+ *
+ *@return A bitbake datastore that's associated to the recipe.
+ * Will be empty if we have no info about this recipe, or if the store backend
+ * is not persistant.
+ */
+BBDATA_API void *bb_data_new(const unsigned char *recipe);
+
+/**
+ *@brief Obtains the last modification date of this metadata store.
+ *
+ *@param data The bitbake metadata store in question.
+ *
+ *@return Last modification date of the datastore.
+ */
+BBDATA_API struct timeval bb_data_get_modif_date(void *data);
+
+/**
+ *@brief Obtains the value of an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *
+ *@return The variable's value as a unsigned char *. This was malloc'd for the caller's use.
+ * The caller is therefore responsible for freeing this.
+ */
+BBDATA_API unsigned char *bb_data_lookup(const void *data, const unsigned char *var);
+
+
+/**
+ *Sets the value of an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param val The value to be set the variable to.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBDATA_API int bb_data_insert(void *data, const unsigned char *var, const unsigned char *val);
+
+
+/**
+ *Deletes an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBDATA_API int bb_data_remove(void *data, const unsigned char *var);
+
+
+/**
+ *Obtains the value of one of the attributes of an bitbake variable.
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param attr The attribute name.
+ *
+ *@return The attribute in question as a unsigned char *. This was malloc'd for the
+ * caller's use. The caller is therefore responsible for freeing this.
+ */
+BBDATA_API unsigned char *bb_data_lookup_attr(const void *data, const unsigned char *var, const unsigned char *attr);
+
+
+/**
+ *Sets the value of one of the attributes of an bitbake variable.
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param val The value to set this attribute to.
+ *@param attr The attribute name.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBDATA_API int bb_data_insert_attr(void *data, const unsigned char *var, const unsigned char *attr, const unsigned char *val);
+
+
+/**
+ *Deletes a given attribute from an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param attr The attribute name.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBDATA_API int bb_data_remove_attr(void *data, const unsigned char *var, const unsigned char *attr);
+
+/**
+ *@brief Deletes a given attribute from an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param flush This parameter only makes sense for persistant datastores.
+ * for those, we need a means of indicating when the data can
+ * truly be removed, when is no longer needed. That is the
+ * purpose of this parameter.
+ */
+BBDATA_API void bb_data_destroy(void *data, int flush);
+
+
+BBDATA_HDR_END
+
+#endif /*_BITBAKE_DATA_H */
diff --git a/trunk/bitbake-data/include/bitbake-data/common.h b/trunk/bitbake-data/include/bitbake-data/common.h
new file mode 100644
index 000000000..fbe93d036
--- /dev/null
+++ b/trunk/bitbake-data/include/bitbake-data/common.h
@@ -0,0 +1,82 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BITBAKE_DATA_COMMON_H
+# define _BITBAKE_DATA_COMMON_H
+
+# ifdef __cplusplus
+# define BBDATA_HDR_BEGIN extern "C" {
+# define BBDATA_HDR_END }
+# else
+# define BBDATA_HDR_BEGIN
+# define BBDATA_HDR_END
+# endif /* __cplusplus */
+
+BBDATA_HDR_BEGIN
+
+/** @file common.h
+ * @brief Header for bitbake's commonly used macros */
+
+/* Shared library support */
+# ifdef WIN32
+# define BBDATA_IMPORT __declspec(dllimport)
+# define BBDATA_EXPORT __declspec(dllexport)
+# define BBDATA_DLLLOCAL
+# define BBDATA_DLLPUBLIC
+# else
+# define BBDATA_IMPORT
+# ifdef GCC_HASCLASSVISIBILITY
+# define BBDATA_EXPORT __attribute__ ((visibility("default")))
+# define BBDATA_DLLLOCAL __attribute__ ((visibility("hidden")))
+# define BBDATA_DLLPUBLIC __attribute__ ((visibility("default")))
+# else
+# define BBDATA_EXPORT
+# define BBDATA_DLLLOCAL
+# define BBDATA_DLLPUBLIC
+# endif
+# endif
+
+/* Define BBDATA_API for DLL builds */
+# ifdef BBDATA_DLL
+# ifdef BBDATA_DLL_EXPORTS
+# define BBDATA_API BBDATA_EXPORT
+# else
+# define BBDATA_API BBDATA_IMPORT
+# endif /* BBDATA_DLL_EXPORTS */
+# else
+# define BBDATA_API
+# endif /* BBDATA_DLL */
+
+/* Throwable classes must always be visible on GCC in all binaries */
+# ifdef WIN32
+# define BBDATA_EXCEPTIONAPI(api) api
+# elif defined(GCC_HASCLASSVISIBILITY)
+# define BBDATA_EXCEPTIONAPI(api) BBDATA_EXPORT
+# else
+# define BBDATA_EXCEPTIONAPI(api)
+# endif
+
+BBDATA_HDR_END
+
+#endif /* _BITBAKE_DATA_COMMON_H */
diff --git a/trunk/bitbake-data/include/bitbake-data/private.h b/trunk/bitbake-data/include/bitbake-data/private.h
new file mode 100644
index 000000000..140f1057e
--- /dev/null
+++ b/trunk/bitbake-data/include/bitbake-data/private.h
@@ -0,0 +1,148 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BITBAKE_DATA_PRIVATE_H
+# define _BITBAKE_DATA_PRIVATE_H
+# ifdef BBDATA_DLL_EXPORTS
+
+# include <bitbake-data/common.h>
+# include <glib.h>
+
+BBDATA_HDR_BEGIN
+
+
+/** @file data-private.h
+ * @brief Private header for bitbake metadata handling */
+
+/**
+ * Data for a given recipe
+ */
+struct bb_data {
+ gchar *recipe;
+};
+
+#if 0
+/**
+ * Bitbake variable chunk types
+ */
+enum bb_var_chunk_type {
+ /**
+ * Indicates that the variable chunk in question is a string
+ */
+ BB_VAR_STR,
+
+ /**
+ * Indicates that the variable chunk in question is a
+ * reference to another bitbake variable.
+ */
+ BB_VAR_REF,
+};
+
+
+/**
+ * \brief BitBake variable chunk
+ *
+ * BitBake variables consist of multiple pieces, including, but not
+ * limited to, strings and references to other variables.
+ */
+struct bb_var_chunk {
+ /**
+ * Type of chunk (i.e. BB_VAR_REF, BBVAR_STR, etc)
+ */
+ enum bb_var_chunk_type type;
+
+ /**
+ * Pointer to this chunk's data
+ */
+ gpointer *data;
+};
+
+
+/**
+ * BitBake variable
+ */
+struct bb_var {
+ /**
+ * Variable name
+ */
+ gchar *key;
+
+ /**
+ * Cached value (post-expansion)
+ */
+ gchar *val;
+
+ /**
+ * Uncached value (pre-expansion)
+ */
+ gchar *orig_val;
+
+ /**
+ * List of variable chunks (of type struct bb_var_chunk)
+ */
+ GList *chunks;
+
+ /**
+ * Dirty flag -- indicates whether the cached value needs to
+ * be updated, most likely due to referees changing.
+ */
+ int dirty;
+
+ /**
+ * List of variables that refer to this variable
+ */
+ GList *referrers;
+
+ /**
+ * Hash table of bitbake variable "attributes". Bitbake variable
+ * attributes are metadata about our metadata. This allows us to
+ * set flags about the metadata. For example, we can specify the
+ * interpreter for a given block of executable code.
+ *
+ * The hash table is attribute name -> gcchar *.
+ */
+ GHashTable *attributes;
+};
+
+/**
+ * BitBake Datastore
+ */
+struct bb_data {
+ /**
+ * Links to context / higher scopes
+ */
+ GList *parents;
+
+ /**
+ * Hash table of variable name -> struct bb_var
+ */
+ GHashTable *data;
+};
+#endif
+
+
+BBDATA_HDR_BEGIN
+
+#endif /* BBDATA_DLL_EXPORTS */
+#endif /* _BITBAKE_DATA_PRIVATE_H */
diff --git a/trunk/bitbake-data/m4/external/check.m4 b/trunk/bitbake-data/m4/external/check.m4
new file mode 100644
index 000000000..a2e0812d4
--- /dev/null
+++ b/trunk/bitbake-data/m4/external/check.m4
@@ -0,0 +1,133 @@
+dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS
+dnl
+
+AC_DEFUN([AM_PATH_CHECK],
+[
+ AC_ARG_WITH(check,
+ [ --with-check=PATH prefix where check is installed [default=auto]])
+
+ min_check_version=ifelse([$1], ,0.8.2,$1)
+
+ AC_MSG_CHECKING(for check - version >= $min_check_version)
+
+ if test x$with_check = xno; then
+ AC_MSG_RESULT(disabled)
+ ifelse([$3], , AC_MSG_ERROR([disabling check is not supported]), [$3])
+ else
+ if test "x$with_check" != x; then
+ CHECK_CFLAGS="-I$with_check/include"
+ CHECK_LIBS="-L$with_check/lib -lcheck"
+ else
+ CHECK_CFLAGS=""
+ CHECK_LIBS="-lcheck"
+ fi
+
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+
+ CFLAGS="$CFLAGS $CHECK_CFLAGS"
+ LIBS="$CHECK_LIBS $LIBS"
+
+ rm -f conf.check-test
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <check.h>
+
+int main ()
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ system ("touch conf.check-test");
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = strdup("$min_check_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_check_version");
+ return 1;
+ }
+
+ if ((CHECK_MAJOR_VERSION != check_major_version) ||
+ (CHECK_MINOR_VERSION != check_minor_version) ||
+ (CHECK_MICRO_VERSION != check_micro_version))
+ {
+ printf("\n*** The check header file (version %d.%d.%d) does not match\n",
+ CHECK_MAJOR_VERSION, CHECK_MINOR_VERSION, CHECK_MICRO_VERSION);
+ printf("*** the check library (version %d.%d.%d).\n",
+ check_major_version, check_minor_version, check_micro_version);
+ return 1;
+ }
+
+ if ((check_major_version > major) ||
+ ((check_major_version == major) && (check_minor_version > minor)) ||
+ ((check_major_version == major) && (check_minor_version == minor) && (check_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** An old version of check (%d.%d.%d) was found.\n",
+ check_major_version, check_minor_version, check_micro_version);
+ printf("*** You need a version of check being at least %d.%d.%d.\n", major, minor, micro);
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the check library and header\n");
+ printf("*** file is being found. Rerun configure with the --with-check=PATH option\n");
+ printf("*** to specify the prefix where the correct version was installed.\n");
+ }
+
+ return 1;
+}
+],, no_check=yes, [echo $ac_n "cross compiling; assumed OK... $ac_c"])
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+
+ if test "x$no_check" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test -f conf.check-test ; then
+ :
+ else
+ echo "*** Could not run check test program, checking why..."
+ CFLAGS="$CFLAGS $CHECK_CFLAGS"
+ LIBS="$CHECK_LIBS $LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <check.h>
+], , [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding check. You'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for"
+ echo "*** the exact error that occured." ])
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+ CHECK_CFLAGS=""
+ CHECK_LIBS=""
+
+ rm -f conf.check-test
+ ifelse([$3], , AC_MSG_ERROR([check not found]), [$3])
+ fi
+
+ AC_SUBST(CHECK_CFLAGS)
+ AC_SUBST(CHECK_LIBS)
+
+ rm -f conf.check-test
+
+ fi
+])
diff --git a/trunk/bitbake-data/m4/internal/doxygen.m4 b/trunk/bitbake-data/m4/internal/doxygen.m4
new file mode 100644
index 000000000..877c8fdf9
--- /dev/null
+++ b/trunk/bitbake-data/m4/internal/doxygen.m4
@@ -0,0 +1,312 @@
+# This file is part of Autoconf. -*- Autoconf -*-
+
+# Copyright (C) 2004 Oren Ben-Kiki
+# This file is distributed under the same terms as the Autoconf macro files.
+
+# Generate automatic documentation using Doxygen. Works in concert with the
+# aminclude.m4 file and a compatible doxygen configuration file. Defines the
+# following public macros:
+#
+# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature.
+# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics,
+# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI'
+# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF',
+# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment
+# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide'
+# paper size.
+#
+# By default, HTML, PDF and PS documentation is generated as this seems to be
+# the most popular and portable combination. MAN pages created by Doxygen are
+# usually problematic, though by picking an appropriate subset and doing some
+# massaging they might be better than nothing. CHM and RTF are specific for MS
+# (note that you can't generate both HTML and CHM at the same time). The XML is
+# rather useless unless you apply specialized post-processing to it.
+#
+# The macro mainly controls the default state of the feature. The use can
+# override the default by specifying --enable or --disable. The macros ensure
+# that contradictory flags are not given (e.g., --enable-doxygen-html and
+# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.)
+# Finally, each feature will be automatically disabled (with a warning) if the
+# required programs are missing.
+#
+# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with
+# the following parameters: a one-word name for the project for use as a
+# filename base etc., an optional configuration file name (the default is
+# 'Doxyfile', the same as Doxygen's default), and an optional output directory
+# name (the default is 'doxygen-doc').
+
+## ----------##
+## Defaults. ##
+## ----------##
+
+DX_ENV=""
+AC_DEFUN([DX_FEATURE_doc], ON)
+AC_DEFUN([DX_FEATURE_dot], ON)
+AC_DEFUN([DX_FEATURE_man], OFF)
+AC_DEFUN([DX_FEATURE_html], ON)
+AC_DEFUN([DX_FEATURE_chm], OFF)
+AC_DEFUN([DX_FEATURE_chi], OFF)
+AC_DEFUN([DX_FEATURE_rtf], OFF)
+AC_DEFUN([DX_FEATURE_xml], OFF)
+AC_DEFUN([DX_FEATURE_pdf], ON)
+AC_DEFUN([DX_FEATURE_ps], ON)
+
+## --------------- ##
+## Private macros. ##
+## --------------- ##
+
+# DX_ENV_APPEND(VARIABLE, VALUE)
+# ------------------------------
+# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen.
+AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])])
+
+# DX_DIRNAME_EXPR
+# ---------------
+# Expand into a shell expression prints the directory part of a path.
+AC_DEFUN([DX_DIRNAME_EXPR],
+ [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
+
+# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
+# -------------------------------------
+# Expands according to the M4 (static) status of the feature.
+AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
+
+# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
+# ----------------------------------
+# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
+AC_DEFUN([DX_REQUIRE_PROG], [
+AC_PATH_TOOL([$1], [$2])
+if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
+ AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
+ AC_SUBST([DX_FLAG_[]DX_CURRENT_FEATURE], 0)
+fi
+])
+
+# DX_TEST_FEATURE(FEATURE)
+# ------------------------
+# Expand to a shell expression testing whether the feature is active.
+AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
+
+# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
+# -------------------------------------------------
+# Verify that a required features has the right state before trying to turn on
+# the DX_CURRENT_FEATURE.
+AC_DEFUN([DX_CHECK_DEPEND], [
+test "$DX_FLAG_$1" = "$2" \
+|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
+ requires, contradicts) doxygen-DX_CURRENT_FEATURE])
+])
+
+# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
+# ----------------------------------------------------------
+# Turn off the DX_CURRENT_FEATURE if the required feature is off.
+AC_DEFUN([DX_CLEAR_DEPEND], [
+test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_[]DX_CURRENT_FEATURE], 0)
+])
+
+# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
+# CHECK_DEPEND, CLEAR_DEPEND,
+# REQUIRE, DO-IF-ON, DO-IF-OFF)
+# --------------------------------------------
+# Parse the command-line option controlling a feature. CHECK_DEPEND is called
+# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
+# otherwise CLEAR_DEPEND is called to turn off the default state if a required
+# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
+# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
+# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
+AC_DEFUN([DX_ARG_ABLE], [
+ AC_DEFUN([DX_CURRENT_FEATURE], [$1])
+ AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
+ AC_ARG_ENABLE(doxygen-$1,
+ [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
+ [--enable-doxygen-$1]),
+ DX_IF_FEATURE([$1], [don't $2], [$2]))],
+ [
+case "$enableval" in
+#(
+y|Y|yes|Yes|YES)
+ AC_SUBST([DX_FLAG_$1], 1)
+ $3
+;; #(
+n|N|no|No|NO)
+ AC_SUBST([DX_FLAG_$1], 0)
+;; #(
+*)
+ AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
+;;
+esac
+], [
+AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
+$4
+])
+if DX_TEST_FEATURE([$1]); then
+ $5
+ :
+fi
+if DX_TEST_FEATURE([$1]); then
+ AM_CONDITIONAL(DX_COND_$1, :)
+ $6
+ :
+else
+ AM_CONDITIONAL(DX_COND_$1, false)
+ $7
+ :
+fi
+])
+
+## -------------- ##
+## Public macros. ##
+## -------------- ##
+
+# DX_XXX_FEATURE(DEFAULT_STATE)
+# -----------------------------
+AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
+AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
+AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
+AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
+AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
+AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
+AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
+AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
+AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
+AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
+
+# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])
+# ---------------------------------------------------------
+# PROJECT also serves as the base name for the documentation files.
+# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc".
+AC_DEFUN([DX_INIT_DOXYGEN], [
+
+# Files:
+AC_SUBST([DX_PROJECT], [$1])
+AC_SUBST([DX_CONFIG], [[\$\(top_srcdir\)/]ifelse([$2], [], Doxyfile, [$2])])
+AC_SUBST([DX_DOCDIR], [[\$\(top_srcdir\)/]ifelse([$3], [], doxygen-doc, [$3])])
+
+# Environment variables used inside doxygen.cfg:
+DX_ENV_APPEND(SRCDIR, [\$(top_srcdir)])
+DX_ENV_APPEND(PROJECT, $DX_PROJECT)
+DX_ENV_APPEND(DOCDIR, $DX_DOCDIR)
+DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
+
+# Doxygen itself:
+DX_ARG_ABLE(doc, [generate any doxygen documentation],
+ [],
+ [],
+ [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
+ DX_REQUIRE_PROG([DX_PERL], perl)],
+ [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
+
+# Dot for graphics:
+DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_DOT], dot)],
+ [DX_ENV_APPEND(HAVE_DOT, YES)
+ DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
+ [DX_ENV_APPEND(HAVE_DOT, NO)])
+
+# Man pages generation:
+DX_ARG_ABLE(man, [generate doxygen manual pages],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_MAN, YES)],
+ [DX_ENV_APPEND(GENERATE_MAN, NO)])
+
+# RTF file generation:
+DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_RTF, YES)],
+ [DX_ENV_APPEND(GENERATE_RTF, NO)])
+
+# XML file generation:
+DX_ARG_ABLE(xml, [generate doxygen XML documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_XML, YES)],
+ [DX_ENV_APPEND(GENERATE_XML, NO)])
+
+# (Compressed) HTML help generation:
+DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_HHC], hhc)],
+ [DX_ENV_APPEND(HHC_PATH, $DX_HHC)
+ DX_ENV_APPEND(GENERATE_HTML, YES)
+ DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
+ [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
+
+# Seperate CHI file generation.
+DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],
+ [DX_CHECK_DEPEND(chm, 1)],
+ [DX_CLEAR_DEPEND(chm, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_CHI, YES)],
+ [DX_ENV_APPEND(GENERATE_CHI, NO)])
+
+# Plain HTML pages generation:
+DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
+ [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
+ [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
+ [],
+ [DX_ENV_APPEND(GENERATE_HTML, YES)],
+ [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
+
+# PostScript file generation:
+DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_LATEX], latex)
+ DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+ DX_REQUIRE_PROG([DX_DVIPS], dvips)
+ DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# PDF file generation:
+DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
+ DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+ DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# LaTeX generation for PS and/or PDF:
+if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
+ AM_CONDITIONAL(DX_COND_latex, :)
+ DX_ENV_APPEND(GENERATE_LATEX, YES)
+else
+ AM_CONDITIONAL(DX_COND_latex, false)
+ DX_ENV_APPEND(GENERATE_LATEX, NO)
+fi
+
+# Paper size for PS and/or PDF:
+AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
+ [a4wide (default), a4, letter, legal or executive])
+case "$DOXYGEN_PAPER_SIZE" in
+#(
+"")
+ AC_SUBST(DOXYGEN_PAPER_SIZE, "")
+;; #(
+a4wide|a4|letter|legal|executive)
+ DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
+;; #(
+*)
+ AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
+;;
+esac
+
+#For debugging:
+#echo DX_FLAG_doc=$DX_FLAG_doc
+#echo DX_FLAG_dot=$DX_FLAG_dot
+#echo DX_FLAG_man=$DX_FLAG_man
+#echo DX_FLAG_html=$DX_FLAG_html
+#echo DX_FLAG_chm=$DX_FLAG_chm
+#echo DX_FLAG_chi=$DX_FLAG_chi
+#echo DX_FLAG_rtf=$DX_FLAG_rtf
+#echo DX_FLAG_xml=$DX_FLAG_xml
+#echo DX_FLAG_pdf=$DX_FLAG_pdf
+#echo DX_FLAG_ps=$DX_FLAG_ps
+#echo DX_ENV=$DX_ENV
+])
diff --git a/trunk/bitbake-data/m4/internal/visibility.m4 b/trunk/bitbake-data/m4/internal/visibility.m4
new file mode 100644
index 000000000..eb2c8f923
--- /dev/null
+++ b/trunk/bitbake-data/m4/internal/visibility.m4
@@ -0,0 +1,74 @@
+# BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES
+# ----------
+# Check the C++ compiler for support for -fvisibility-inlines-hidden.
+AC_DEFUN([BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES],
+[AC_REQUIRE([AC_PROG_CXX])
+ bb_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="-fvisibility-inlines-hidden $bb_save_CXXFLAGS"
+ AC_CACHE_CHECK([whether the C++ compiler supports -fvisibility-inlines-hidden],
+ [bb_cv_cc_supports_hidden_visibility_inlines], [
+ AC_LANG_PUSH(C++)
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [bb_cv_cc_supports_hidden_visibility_inlines=yes], [bb_cv_cc_supports_hidden_visibility_inlines=no])
+ AC_LANG_POP(C++)
+ ])
+ CXXFLAGS="$bb_save_CXXFLAGS"
+]) # BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES
+
+
+# BB_CXX_HIDDEN_VISIBILITY_INLINES
+# ----------
+# Decide whether or not to use -fvisibility-inlines-hidden for c++ applications.
+AC_DEFUN([BB_CXX_HIDDEN_VISIBILITY_INLINES],
+[AC_REQUIRE([BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES])
+ AC_MSG_CHECKING([whether to use -fvisibility-inlines-hidden])
+ AC_ARG_WITH([hidden_visibility_inlines],
+ AC_HELP_STRING([--with-hidden_visibility_inlines=VAL],
+ [use -fvisibility-inlines-hidden (default VAL is 'auto')]),
+ [bb_with_hidden_visibility_inlines=$withval], [bb_with_hidden_visibility_inlines=auto])
+
+ if test "x$bb_with_hidden_visibility_inlines" != "xno" && \
+ test "x$bb_cv_cc_supports_hidden_visibility_inlines" != "xno"; then
+ AC_MSG_RESULT([yes])
+ CXXFLAGS="-fvisibility-inlines-hidden $CXXFLAGS"
+ AC_MSG_NOTICE([prepending -fvisibility-inlines-hidden to CXXFLAGS])
+ else
+ AC_MSG_RESULT([no])
+ fi
+]) # BB_CXX_HIDDEN_VISIBILITY_INLINES
+
+
+# BB_CC_SUPPORTS_HIDDEN_VISIBILITY
+# ----------
+# Check the C compiler for support for -fvisibility=hidden.
+AC_DEFUN([BB_CC_SUPPORTS_HIDDEN_VISIBILITY],
+[AC_REQUIRE([AC_PROG_CC])
+ bb_save_CFLAGS="$CFLAGS"
+ CFLAGS="-fvisibility=hidden $bb_save_CFLAGS"
+ AC_CACHE_CHECK([whether the C compiler supports -fvisibility=hidden],
+ [bb_cv_cc_supports_hidden_visibility], [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [bb_cv_cc_supports_hidden_visibility=yes], [bb_cv_cc_supports_hidden_visibility=no])
+ ])
+ CFLAGS="$bb_save_CFLAGS"
+]) # BB_CC_SUPPORTS_HIDDEN_VISIBILITY
+
+
+# BB_CC_HIDDEN_VISIBILITY
+# ----------
+# Decide whether or not to use -fvisibility=hidden.
+AC_DEFUN([BB_CC_HIDDEN_VISIBILITY],
+[AC_REQUIRE([BB_CC_SUPPORTS_HIDDEN_VISIBILITY])
+ AC_MSG_CHECKING([whether to use -fvisibility=hidden])
+ AC_ARG_WITH([hidden_visibility],
+ AC_HELP_STRING([--with-hidden_visibility=VAL],
+ [use -fvisibility=hidden (default VAL is 'auto')]),
+ [bb_with_hidden_visibility=$withval], [bb_with_hidden_visibility=auto])
+
+ if test "x$bb_with_hidden_visibility" != "xno" && \
+ test "x$bb_cv_cc_supports_hidden_visibility" != "xno"; then
+ AC_MSG_RESULT([yes])
+ CFLAGS="-DGCC_HASCLASSVISIBILITY -fvisibility=hidden $CFLAGS"
+ AC_MSG_NOTICE([prepending -DGCC_HASCLASSVISIBILITY -fvisibility=hidden to CFLAGS])
+ else
+ AC_MSG_RESULT([no])
+ fi
+]) # BB_CC_HIDDEN_VISIBILITY
diff --git a/trunk/bitbake-data/src/Makefile.am b/trunk/bitbake-data/src/Makefile.am
new file mode 100644
index 000000000..223f549ed
--- /dev/null
+++ b/trunk/bitbake-data/src/Makefile.am
@@ -0,0 +1,13 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ $(BBDATA_DLL_EXPORTS)
+
+lib_LTLIBRARIES = libbitbake-data-@LT_RELEASE@.la
+libbitbake_data_@LT_RELEASE@_la_SOURCES = backend-sqlite3.c
+libbitbake_data_@LT_RELEASE@_la_CFLAGS = $(GLIB2_CFLAGS) $(SQLITE3_CFLAGS) \
+ -DLOCALSTATEDIR="\"@localstatedir@\""
+libbitbake_data_@LT_RELEASE@_la_LIBADD = $(GLIB2_LIBS) $(SQLITE3_LIBS)
+libbitbake_data_@LT_RELEASE@_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -export-dynamic
+
+maintainer-clean-local:
+ rm -f $(srcdir)/Makefile.in
diff --git a/trunk/bitbake-data/src/backend-sqlite3.c b/trunk/bitbake-data/src/backend-sqlite3.c
new file mode 100644
index 000000000..80d2d9e44
--- /dev/null
+++ b/trunk/bitbake-data/src/backend-sqlite3.c
@@ -0,0 +1,372 @@
+/* vi:ts=8:sw=4:sts=4:et
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h> /* for printf */
+#include <stdlib.h> /* for strtol */
+#include <glib.h>
+#include <sqlite3.h>
+#include <bitbake-data.h>
+#include <bitbake-data/private.h>
+
+#include "config.h"
+
+/**
+ * Static structure to hold process wide information associated with
+ * our bitbake data. In this case, this holds our pointer to our open
+ * sqlite3 database, its path, and so on. Protected by a GStaticMutex.
+ */
+static struct {
+ int initialized;
+ GStaticMutex mutex;
+ unsigned char *datapath;
+ sqlite3 *db;
+ guint users;
+} bbdata_setup = {
+ .initialized = FALSE,
+ .mutex = G_STATIC_MUTEX_INIT,
+};
+
+
+static inline int add_tables()
+{
+ char **results;
+ int nrow, ncol;
+ int sret;
+
+ sqlite3_get_table(bbdata_setup.db, "select name from sqlite_master where type = 'table' and name = 'recipes'",
+ &results, &nrow, &ncol, NULL);
+ sqlite3_free_table(results);
+ if (nrow < 1) {
+ sret = sqlite3_exec(bbdata_setup.db, "create table recipes(key integer primary key, recipe text not null)",
+ NULL, 0, NULL);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ }
+
+ sqlite3_get_table(bbdata_setup.db, "select name from sqlite_master where type = 'table' and name = 'scopes'",
+ &results, &nrow, &ncol, NULL);
+ sqlite3_free_table(results);
+ if (nrow < 1) {
+ sret = sqlite3_exec(bbdata_setup.db,
+ "create table scopes(key integer primary key, priority integer, scope integer, recipe integer)",
+ NULL, 0, NULL);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ }
+
+ sqlite3_get_table(bbdata_setup.db, "select name from sqlite_master where type = 'table' and name = 'vars'",
+ &results, &nrow, &ncol, NULL);
+ sqlite3_free_table(results);
+ if (nrow < 1) {
+ sret = sqlite3_exec(bbdata_setup.db,
+ "create table vars(key integer primary key, var text not null, val text, recipe integer)",
+ NULL, 0, NULL);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Process wide initialization
+ */
+static int __bb_data_init(void)
+{
+ int ret = TRUE;
+ const gchar *datapath = g_getenv("BBDATAPATH");
+ unsigned char *fpath = NULL;
+ guint sret;
+
+ if (datapath)
+ bbdata_setup.datapath = g_filename_to_utf8(datapath, -1, NULL, NULL, NULL);
+
+ if (!bbdata_setup.datapath)
+ bbdata_setup.datapath = g_build_path(LOCALSTATEDIR, "lib", "bitbake-data", NULL);
+
+ fpath = g_build_filename(bbdata_setup.datapath, "data");
+
+ sret = sqlite3_open(fpath, &bbdata_setup.db);
+ if (sret)
+ goto out_fail;
+
+ ret = add_tables();
+ if (!ret)
+ goto out_fail;
+
+ g_free(fpath);
+
+ bbdata_setup.initialized = TRUE;
+ return ret;
+
+out_fail:
+ sqlite3_close(bbdata_setup.db);
+ g_free(bbdata_setup.datapath);
+ g_free(fpath);
+ return FALSE;
+}
+
+/**
+ * Process wide shutdown
+ */
+static void __bb_data_shutdown(void)
+{
+ bbdata_setup.initialized = FALSE;
+ sqlite3_close(bbdata_setup.db);
+ g_free(bbdata_setup.datapath);
+}
+
+/**
+ * Wrapper that initializes when necessary
+ */
+static inline int bb_data_init(void)
+{
+ if (!bbdata_setup.initialized)
+ return __bb_data_init();
+ else
+ return TRUE;
+}
+
+/**
+ * Wrapper that shuts down when necessary
+ */
+static inline void bb_data_shutdown(void)
+{
+ if (bbdata_setup.initialized) {
+ bbdata_setup.users -= 1;
+
+ if (bbdata_setup.users < 1)
+ __bb_data_shutdown();
+ }
+}
+
+
+static inline int add_recipe_to_db(const char *recipe)
+{
+ char **results;
+ char *query;
+ int nrow, ncol;
+
+ query = sqlite3_mprintf("select key from recipes where recipe = '%q'", recipe);
+ sqlite3_get_table(bbdata_setup.db, query, &results, &nrow, &ncol, NULL);
+ sqlite3_free_table(results);
+ sqlite3_free(query);
+ if (nrow < 1) {
+ int sret;
+ char *insert = sqlite3_mprintf("insert into recipes values(NULL, '%q')", recipe);
+ sret = sqlite3_exec(bbdata_setup.db, insert, NULL, 0, NULL);
+ sqlite3_free(insert);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void *bb_data_new(const unsigned char *recipe)
+{
+ void *ret = NULL;
+ struct bb_data *data;
+ int sret;
+
+ g_static_mutex_lock(&bbdata_setup.mutex);
+ if (!bb_data_init()) {
+ g_static_mutex_unlock(&bbdata_setup.mutex);
+ return ret;
+ }
+
+ bbdata_setup.users += 1;
+ g_static_mutex_unlock(&bbdata_setup.mutex);
+
+ ret = g_malloc0(sizeof(struct bb_data));
+ data = (struct bb_data *)ret;
+ data->recipe = g_strdup(recipe);
+
+ sret = sqlite3_exec(bbdata_setup.db, "begin", NULL, 0, NULL);
+ if (sret != SQLITE_OK)
+ goto sqliteerror;
+
+ if (!add_recipe_to_db(recipe))
+ goto sqliteerror;
+
+ sret = sqlite3_exec(bbdata_setup.db, "commit", NULL, 0, NULL);
+ if (sret != SQLITE_OK)
+ goto sqliteerror;
+ return ret;
+sqliteerror:
+ sqlite3_exec(bbdata_setup.db, "rollback", NULL, 0, NULL);
+ g_static_mutex_lock(&bbdata_setup.mutex);
+ bbdata_setup.users -= 1;
+ bb_data_shutdown();
+ g_static_mutex_unlock(&bbdata_setup.mutex);
+ g_free(ret);
+ return NULL;
+}
+
+void bb_data_destroy(void *data, int flush)
+{
+ struct bb_data *d = (struct bb_data *)data;
+ if (flush) {
+ char *str;
+#if 0
+ str = sqlite3_mprintf("drop table '%q'", d->recipe);
+ sqlite3_exec(bbdata_setup.db, str, NULL, 0, NULL);
+ sqlite3_free(str);
+#endif
+ str = sqlite3_mprintf("delete from recipes where recipe = '%q'", d->recipe);
+ sqlite3_exec(bbdata_setup.db, str, NULL, 0, NULL);
+ sqlite3_free(str);
+ }
+
+ g_free(data);
+
+ g_static_mutex_lock(&bbdata_setup.mutex);
+
+ if (bbdata_setup.initialized) {
+ bbdata_setup.users -= 1;
+
+ if (bbdata_setup.users < 1) {
+ bb_data_shutdown();
+ }
+ }
+
+ g_static_mutex_unlock(&bbdata_setup.mutex);
+}
+
+unsigned char *bb_data_lookup(const void *data, const unsigned char *var)
+{
+ struct bb_data *d = (struct bb_data *)data;
+ char **results;
+ char *query;
+ int nrow, ncol;
+ unsigned char *ret = NULL;
+
+ query = sqlite3_mprintf("select val from vars join scopes on vars.recipe = scopes.scope join recipes on recipes.key = scopes.recipe where var = '%q' and recipes.recipe = '%q' order by scopes.priority desc limit 1", var, d->recipe);
+ sqlite3_get_table(bbdata_setup.db, query, &results, &nrow, &ncol, NULL);
+ sqlite3_free(query);
+ printf("nrow is %d\n", nrow);
+ if (nrow > 0)
+ if (results && results[1])
+ ret = g_strdup(results[1]);
+ sqlite3_free_table(results);
+ return ret;
+}
+
+long __get_recipe_num(void *data)
+{
+ struct bb_data *d = (struct bb_data *)data;
+ char *query;
+ char **results;
+ int nrow, ncol;
+ long recipenum = 0;
+
+ query = sqlite3_mprintf("select key from recipes where recipe = '%q'", d->recipe);
+ sqlite3_get_table(bbdata_setup.db, query, &results, &nrow, &ncol, NULL);
+ sqlite3_free(query);
+ printf("nrow is %d", nrow);
+ if (nrow > 0)
+ if (results && results[1]) {
+ recipenum = strtol(results[1], NULL, 10);
+ printf("recipenum is %ld\n", recipenum);
+ }
+ sqlite3_free_table(results);
+ return recipenum;
+}
+
+int bb_data_insert(void *data, const unsigned char *var, const unsigned char *val)
+{
+ char *query;
+ int sret;
+ long recipenum = __get_recipe_num(data);
+
+ query = sqlite3_mprintf("insert into vars values(NULL, '%q', '%q', %d)", var, val, recipenum);
+ sret = sqlite3_exec(bbdata_setup.db, query, NULL, 0, NULL);
+ sqlite3_free(query);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ return TRUE;
+}
+
+int bb_data_remove(void *data, const unsigned char *var)
+{
+ struct bb_data *d = (struct bb_data *)data;
+ char *query;
+ int sret;
+ long recipenum = __get_recipe_num(data);
+
+ query = sqlite3_mprintf("delete from vars where var = '%q' and recipe = %d", d->recipe, var, recipenum);
+ sret = sqlite3_exec(bbdata_setup.db, query, NULL, 0, NULL);
+ sqlite3_free(query);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ return TRUE;
+}
+
+unsigned char *bb_data_lookup_attr(const void *data, const unsigned char *var, const unsigned char *attr)
+{
+ struct bb_data *d = (struct bb_data *)data;
+ char **results;
+ char *query;
+ int nrow, ncol;
+ unsigned char *ret = NULL;
+
+ query = sqlite3_mprintf("select attr from '%q' where var = '%q' and attr not null and val = '%q'", d->recipe, var, attr);
+ sqlite3_get_table(bbdata_setup.db, query, &results, &nrow, &ncol, NULL);
+ sqlite3_free(query);
+ if (nrow > 0)
+ if (results && results[1])
+ ret = g_strdup(results[1]);
+ sqlite3_free_table(results);
+ return ret;
+}
+
+int bb_data_insert_attr(void *data, const unsigned char *var, const unsigned char *attr, const unsigned char *val)
+{
+ struct bb_data *d = (struct bb_data *)data;
+ char *query;
+ int sret;
+
+ query = sqlite3_mprintf("delete from '%q' where var = '%q' and attr not null and val = '%q'", d->recipe, var, attr);
+ sret = sqlite3_exec(bbdata_setup.db, query, NULL, 0, NULL);
+ sqlite3_free(query);
+
+ query = sqlite3_mprintf("insert into '%q' values(NULL, '%q', '%q', '%q')", d->recipe, var, attr, val);
+ sret = sqlite3_exec(bbdata_setup.db, query, NULL, 0, NULL);
+ sqlite3_free(query);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ return TRUE;
+}
+
+int bb_data_remove_attr(void *data, const unsigned char *var, const unsigned char *attr)
+{
+ struct bb_data *d = (struct bb_data *)data;
+ char *query;
+ int sret;
+
+ query = sqlite3_mprintf("delete from '%q' where var = '%q' and val = '%q' and attr not null", d->recipe, var, attr);
+ sret = sqlite3_exec(bbdata_setup.db, query, NULL, 0, NULL);
+ sqlite3_free(query);
+ if (sret != SQLITE_OK)
+ return FALSE;
+ return TRUE;
+}
diff --git a/trunk/bitbake-data/tests/Makefile.am b/trunk/bitbake-data/tests/Makefile.am
new file mode 100644
index 000000000..bcb8c339c
--- /dev/null
+++ b/trunk/bitbake-data/tests/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ $(BBDLL_EXPORTS)
+AM_LDFLAGS = -L$(top_srcdir)/src
+
+.PHONY: test
+if BB_TESTS
+noinst_PROGRAMS = check_bitbake_data
+check_bitbake_data_SOURCES = check_bitbake_data.c
+check_bitbake_data_CFLAGS = $(CHECK_CFLAGS)
+check_bitbake_data_LDADD = $(CHECK_LIBS) -lbitbake-data-@LT_RELEASE@
+
+test:
+ @./check_bitbake_data
+else
+test:
+endif
+
+maintainer-clean-local:
+ rm -f $(srcdir)/Makefile.in
diff --git a/trunk/bitbake-data/tests/check_bitbake_data.c b/trunk/bitbake-data/tests/check_bitbake_data.c
new file mode 100644
index 000000000..c3afc15ac
--- /dev/null
+++ b/trunk/bitbake-data/tests/check_bitbake_data.c
@@ -0,0 +1,210 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file check_bitbake_data.c
+ * @brief First group of metadata tests */
+
+#include <stdlib.h>
+#include <string.h>
+#include <check.h>
+#include <bitbake-data.h>
+
+/**
+ * Test the creation and destruction of a struct bb_data
+ * using the bb_data_new("test") and bb_data_destroy() functions.
+ */
+
+START_TEST (test_data_create_destroy)
+{
+ void *data;
+
+ data = bb_data_new("test_data_create_destroy");
+ if (data == NULL)
+ fail("Metadata store allocation returned a NULL pointer");
+ bb_data_destroy(data, 1);
+}
+END_TEST
+
+START_TEST (test_data_var_insert)
+{
+ void *data;
+ unsigned char *var, *val;
+ int ret;
+
+ data = bb_data_new("test_data_var_insert");
+ var = "CC";
+ val = "gcc";
+
+ ret = bb_data_insert(data, var, val);
+ if (!ret)
+ fail("Failed to insert");
+}
+END_TEST
+
+START_TEST (test_data_var_lookup)
+{
+ void *data;
+ unsigned char *var, *val;
+ int ret;
+
+ data = bb_data_new("test_data_var_lookup");
+
+ var = "CC";
+ val = "gcc";
+ ret = bb_data_insert(data, var, val);
+ if (!ret)
+ fail("Failed to insert");
+
+ val = bb_data_lookup(data, "CC");
+ if (!val)
+ fail("bb_data_lookup(data, \"CC\") returned NULL");
+ if (strcmp(val, "gcc") != 0)
+ fail("CC does not have the correct value");
+
+ bb_data_destroy(data, 1);
+}
+END_TEST
+
+START_TEST (test_data_var_remove)
+{
+ void *data;
+ unsigned char *var, *val;
+ int ret;
+
+ data = bb_data_new("test_data_var_remove");
+
+ var = "CC";
+ val = "gcc";
+ ret = bb_data_insert(data, var, val);
+ if (!ret)
+ fail("Failed to insert");
+ ret = bb_data_remove(data, var);
+ if (!ret)
+ fail("Failed to remove");
+
+ bb_data_destroy(data, 1);
+}
+END_TEST
+
+#if 0
+START_TEST (test_data_attr_insert)
+{
+ void *data;
+ unsigned char *var, *val, *attr;
+ int ret;
+
+ data = bb_data_new("test_data_attr_insert");
+ var = "CC";
+ attr = "export";
+ val = "1";
+
+ ret = bb_data_insert_attr(data, var, attr, val);
+ if (!ret)
+ fail("Failed to insert attribute");
+}
+END_TEST
+
+START_TEST (test_data_attr_lookup)
+{
+ void *data;
+ unsigned char *var, *val, *attr;
+ int ret;
+
+ data = bb_data_new("test_data_attr_lookup");
+
+ var = "CC";
+ attr = "export";
+ val = "1";
+ ret = bb_data_insert_attr(data, var, attr, val);
+ if (!ret)
+ fail("Failed to insert attribute");
+
+ val = bb_data_lookup_attr(data, var, attr);
+ if (!val)
+ fail("bb_data_lookup_attr(data, \"CC\", \"export\") returned NULL");
+ if (strcmp(val, "1") != 0)
+ fail("CC export attribute does not have the correct value");
+
+ bb_data_destroy(data, 1);
+}
+END_TEST
+
+START_TEST (test_data_attr_remove)
+{
+ void *data;
+ unsigned char *var, *val, *attr;
+ int ret;
+
+ data = bb_data_new("test_data_attr_remove");
+
+ var = "CC";
+ attr = "export";
+ val = "1";
+ ret = bb_data_insert_attr(data, var, attr, val);
+ if (!ret)
+ fail("Failed to insert attribute");
+ ret = bb_data_remove_attr(data, var, attr);
+ if (!ret)
+ fail("Failed to remove attribute");
+
+ bb_data_destroy(data, 1);
+}
+END_TEST
+#endif
+
+Suite *bitbake_data_suite(void)
+{
+ Suite *s = suite_create("Bitbake Data");
+ TCase *tc_core = tcase_create("Core");
+ TCase *tc_var = tcase_create("Variable");
+ TCase *tc_attr = tcase_create("Variable Attributes");
+
+ suite_add_tcase (s, tc_core);
+ suite_add_tcase (s, tc_var);
+ suite_add_tcase (s, tc_attr);
+
+ tcase_add_test(tc_core, test_data_create_destroy);
+
+// tcase_add_test(tc_var, test_data_var_insert);
+ tcase_add_test(tc_var, test_data_var_lookup);
+// tcase_add_test(tc_var, test_data_var_remove);
+
+#if 0
+ tcase_add_test(tc_attr, test_data_attr_insert);
+ tcase_add_test(tc_attr, test_data_attr_lookup);
+ tcase_add_test(tc_attr, test_data_attr_remove);
+#endif
+ return s;
+}
+
+int main(void)
+{
+ int nf;
+ Suite *s = bitbake_data_suite();
+ SRunner *sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ nf = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/trunk/bitbake-ng/ChangeLog b/trunk/bitbake-ng/ChangeLog
new file mode 100644
index 000000000..3c8fc2d0b
--- /dev/null
+++ b/trunk/bitbake-ng/ChangeLog
@@ -0,0 +1,36 @@
+2005-01-17 Chris Larson <kergoth@handhelds.org>
+
+ * design_spec.xml: Add specification of the metadata component,
+ update vim modeline to set the filetype to 'docbk'.
+
+2005-01-13 Chris Larson <kergoth@handhelds.org>
+
+ * Minor rearranging.. now we have m4/internal and m4/external,
+ to make it possible to run autoreconf in this tree even on
+ machines without 'check' installed.
+
+2005-01-10 Chris Larson <kergoth@handhelds.org>
+
+ * Update library linking so that the dev symlink is
+ libbitbake-[release].so rather than libbitbake.so.
+
+2005-01-09 Chris Larson <kergoth@handhelds.org>
+
+ * Correct library linking to set libtool's versioning.
+ * Add 'test' target to makefiles, which runs the 'check' unit tests.
+ * Add pkgconfig .pc file.
+
+2005-01-08 Chris Larson <kergoth@handhelds.org>
+
+ * Improve documentation generation. Use a decent set of
+ autoconf macros to handle selection of the types of
+ doxygen output (taken from the "doxample" project).
+ * Use 'check' (http://check.sourceforge.net/) for unit testing.
+ * Add basic variable insert/remove/lookup implementations for the
+ bitbake metadata (RAM backed for now).
+
+2004-12-30 Chris Larson <kergoth@handhelds.org>
+
+ * Create initial tree for bitbake-ng.
+ * Add autoconf macros for gcc 4.0 (and patched 3.4.x) symbol visibility.
+ * Add initial BitBake-ng Design Specification document.
diff --git a/trunk/bitbake-ng/Makefile.am b/trunk/bitbake-ng/Makefile.am
new file mode 100644
index 000000000..fe77f381d
--- /dev/null
+++ b/trunk/bitbake-ng/Makefile.am
@@ -0,0 +1,19 @@
+SUBDIRS = include src tests doc
+
+ACLOCAL_AMFLAGS = -I m4/internal -I m4/external
+AUTOMAKE_OPTIONS = foreign 1.6
+
+MAINT_CLEAN_FILES_AUX = config.guess config.sub depcomp \
+ install-sh missing ltmain.sh \
+ compile mkinstalldirs
+MAINT_CLEAN_FILES_TOP = config.h.in aclocal.m4 \
+ configure Makefile.in stamp-h.in
+MAINT_CLEAN_FILES = $(foreach f,$(MAINT_CLEAN_FILES_TOP),$(top_srcdir)/$(f) $(top_srcdir)/$(f)\~) \
+ $(foreach f,$(MAINT_CLEAN_FILES_AUX),$(auxdir)/$(f) $(auxdir)/$(f)\~)
+
+maintainer-clean-local:
+ rm -f $(MAINT_CLEAN_FILES)
+
+.PHONY: test
+test:
+ @$(MAKE) -C tests $@
diff --git a/trunk/bitbake-ng/acinclude.m4 b/trunk/bitbake-ng/acinclude.m4
new file mode 100644
index 000000000..41bc14038
--- /dev/null
+++ b/trunk/bitbake-ng/acinclude.m4
@@ -0,0 +1,11 @@
+# BB_DEFAULT_FLAGS
+# ----------
+# Set our default FLAGS variables.
+# Remember to call before the AC_PROG_ variables, otherwise those
+# defaults will be used instead of ours.
+AC_DEFUN([BB_DEFAULT_FLAGS],
+[
+ if test x"$CFLAGS" = "x"; then
+ CFLAGS="-O2 -Wall -W"
+ fi
+]) # BB_DEFAULT_FLAGS
diff --git a/trunk/bitbake-ng/bitbake-0.0.pc.in b/trunk/bitbake-ng/bitbake-0.0.pc.in
new file mode 100644
index 000000000..9ed4c60a2
--- /dev/null
+++ b/trunk/bitbake-ng/bitbake-0.0.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE@
+Description: @PACKAGE_DESCRIPTION@
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lbitbake-@LT_RELEASE@
+Cflags: -I${includedir}/bitbake-@LT_RELEASE@
diff --git a/trunk/bitbake-ng/config/autogen.sh b/trunk/bitbake-ng/config/autogen.sh
new file mode 100755
index 000000000..adb32b638
--- /dev/null
+++ b/trunk/bitbake-ng/config/autogen.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+autoreconf -f -i -I `pwd`/m4
diff --git a/trunk/bitbake-ng/config/version.m4 b/trunk/bitbake-ng/config/version.m4
new file mode 100644
index 000000000..fa0421320
--- /dev/null
+++ b/trunk/bitbake-ng/config/version.m4
@@ -0,0 +1,16 @@
+dnl bitbake-ng package version
+m4_define([BITBAKE_VER], [0.1])
+
+dnl bitbake-ng library "release" version
+dnl "0.0" in bitbake-ng-0.0.so
+dnl Increment on API break.
+m4_define([BITBAKE_LT_REL], [0.0])
+
+dnl bitbake-ng libtool library version
+
+dnl Current, increment on ABI break
+m4_define([BITBAKE_LT_CUR], [0])
+dnl Revision, increment at release
+m4_define([BITBAKE_LT_REV], [0])
+dnl Age
+m4_define([BITBAKE_LT_AGE], [0])
diff --git a/trunk/bitbake-ng/configure.ac b/trunk/bitbake-ng/configure.ac
new file mode 100644
index 000000000..39d826192
--- /dev/null
+++ b/trunk/bitbake-ng/configure.ac
@@ -0,0 +1,114 @@
+# get our package versions
+m4_include([config/version.m4])
+
+
+# initialization
+AC_INIT(bitbake-ng, BITBAKE_VER, bitbake-dev@lists.berlios.de)
+AC_PREREQ(2.57)
+
+AC_CONFIG_SRCDIR([include/bitbake.h])
+AC_CONFIG_AUX_DIR(config)
+AM_CONFIG_HEADER([config.h])
+
+AM_INIT_AUTOMAKE
+
+
+PACKAGE_DESCRIPTION="A library for the execution of recipes."
+AC_SUBST([PACKAGE_DESCRIPTION])
+
+# library versioning
+LT_RELEASE=BITBAKE_LT_REL
+AC_SUBST([LT_RELEASE])
+
+LT_CURRENT=BITBAKE_LT_CUR
+AC_SUBST([LT_CURRENT])
+
+LT_REVISION=BITBAKE_LT_REV
+AC_SUBST([LT_REVISION])
+
+LT_AGE=BITBAKE_LT_AGE
+AC_SUBST([LT_AGE])
+
+
+# system
+AC_CANONICAL_SYSTEM
+
+
+# paths
+auxdir="\$(top_srcdir)/$ac_aux_dir"
+AC_SUBST(auxdir)
+
+reldatadir="\$(datadir)/bitbake-\$(LT_RELEASE)"
+rellibdir="\$(libdir)/bitbake-\$(LT_RELEASE)"
+relincludedir="\$(includedir)/bitbake-\$(LT_RELEASE)"
+AC_SUBST([reldatadir])
+AC_SUBST([rellibdir])
+AC_SUBST([relincludedir])
+
+
+# programs
+BB_DEFAULT_FLAGS
+
+AC_PROG_CC
+BB_CC_HIDDEN_VISIBILITY
+
+AC_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+
+
+
+# dependencies
+PKG_CHECK_MODULES([GLIB2], [glib-2.0])
+
+
+# docbook documentation
+AC_CHECK_PROGS([XMLLINT], [xmllint])
+AC_CHECK_PROGS([XSLTPROC], [xsltproc])
+
+# doxygen documentation
+DX_HTML_FEATURE(ON)
+DX_CHM_FEATURE(OFF)
+DX_CHI_FEATURE(OFF)
+DX_MAN_FEATURE(ON)
+DX_RTF_FEATURE(OFF)
+DX_XML_FEATURE(OFF)
+DX_PDF_FEATURE(ON)
+DX_PS_FEATURE(OFF)
+DX_INIT_DOXYGEN($PACKAGE, [doc/doxygen.cfg], [doc/doxygen])
+
+
+# options
+AC_MSG_CHECKING([whether user requested building tests])
+AC_ARG_ENABLE(tests,
+ AS_HELP_STRING([--enable-tests],
+ [Enable building of tests (default=no)]),
+ [enable_tests=$enableval],
+ [enable_tests=no])
+AC_MSG_RESULT($enable_tests)
+AM_CONDITIONAL(BB_TESTS, test "$enable_tests" = "yes")
+
+# see if 'check', the unit testing framework, is installed
+if test x"$enable_tests" != "xno"; then
+ AM_PATH_CHECK
+fi
+
+
+# other
+AM_BINRELOC
+
+
+# This variable is used to indicate whether we're compiling
+# a part of our library itself, or external binaries.
+BBDLL_EXPORTS="-DBBDLL_EXPORTS"
+AC_SUBST([BBDLL_EXPORTS])
+
+
+# output
+AC_CONFIG_FILES([Makefile
+ include/Makefile
+ src/Makefile
+ tests/Makefile
+ doc/Makefile
+ doc/design_spec/Makefile
+ bitbake-0.0.pc])
+AC_OUTPUT
diff --git a/trunk/bitbake-ng/doc/Makefile.am b/trunk/bitbake-ng/doc/Makefile.am
new file mode 100644
index 000000000..914cc4149
--- /dev/null
+++ b/trunk/bitbake-ng/doc/Makefile.am
@@ -0,0 +1,11 @@
+SUBDIRS = design_spec
+
+MOSTLYCLEANFILES = $(DX_CLEANFILES)
+EXTRA_DIST = $(DX_CONFIG)
+
+include doxygen.am
+
+all: doxygen-doc
+
+maintainer-clean-local:
+ rm -f $(srcdir)/Makefile.in
diff --git a/trunk/bitbake-ng/doc/design_spec/Makefile.am b/trunk/bitbake-ng/doc/design_spec/Makefile.am
new file mode 100644
index 000000000..92fd80171
--- /dev/null
+++ b/trunk/bitbake-ng/doc/design_spec/Makefile.am
@@ -0,0 +1,20 @@
+BUILT_SOURCES = html/index.html
+xmldoc = design_spec.xml
+cssfile = html.css
+docbooktypes = html
+
+
+html/index.html: $(xmldoc) html/docbook.css
+ $(XMLLINT) --xinclude --postvalid --noout $(xmldoc)
+ $(XSLTPROC) --stringparam base.dir html/ --stringparam html.stylesheet docbook.css http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl $(xmldoc)
+
+html/docbook.css:
+ install -d html
+ install -m 0644 $(cssfile) $@
+
+install-hook: install-design-spec
+install-design-spec:
+ install -d $(docdir)/design_spec/html
+ install -m 0644 html/*.html $(docdir)/design_spec/html
+
+CLEANFILES = html/*
diff --git a/trunk/bitbake-ng/doc/design_spec/design_spec.xml b/trunk/bitbake-ng/doc/design_spec/design_spec.xml
new file mode 100644
index 000000000..00fa10c5f
--- /dev/null
+++ b/trunk/bitbake-ng/doc/design_spec/design_spec.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0"?>
+<!--
+ ex:ts=4:sw=4:sts=4:et:ft=docbk
+ -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+-->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<book>
+ <bookinfo>
+ <title>BitBake-Ng Design Specification</title>
+ <authorgroup>
+ <corpauthor>BitBake Team</corpauthor>
+ </authorgroup>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <holder>Chris Larson</holder>
+ </copyright>
+ <legalnotice>
+ <para>This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit <ulink url="http://creativecommons.org/licenses/by/2.0/">http://creativecommons.org/licenses/by/2.0/</ulink> or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.</para>
+ </legalnotice>
+ </bookinfo>
+ <preface>
+ <title>Introduction</title>
+ <para>It is said that a developer should always plan on at least one rewrite in a given project. Such is the case here. This document outlines the design of bitbake 2.0, the upcoming rewrite of the BitBake project. It is expected that the reader will have at least a passing familiarity with the bitbake project. I would recommend perusing the <ulink url="http://bitbake.berlios.de/manual/">bitbake users manual</ulink> if this is not the case.</para>
+ </preface>
+ <preface>
+ <title>Terminology</title>
+ <table><title>Terminology</title>
+ <tgroup cols='2'>
+ <colspec colname='term'/>
+ <colspec colname='definition'/>
+ <tbody>
+ <row>
+ <entry>Recipe</entry>
+ <entry>A set of directions with a list of ingredients for making or preparing something. In this context, an ordered sequence of steps to be executed, with associated metadata.</entry>
+ </row>
+ <row>
+ <entry>Recipe Box</entry>
+ <entry>The bitbake component that manages the available recipes.</entry>
+ </row>
+ <row>
+ <entry>Metadata</entry>
+ <entry>The bitbake component that manages the metadata for bitbake recipes. The <quote>ingredients</quote>, as it were.</entry>
+ </row>
+ <row>
+ <entry>Bakers</entry>
+ <entry>The bitbake component consisting of the threads that execute recipes, obeying recipe interdependencies.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </preface>
+ <chapter>
+ <title>General Requirements</title>
+ <itemizedlist>
+ <listitem><para><emphasis>MUST</emphasis> be thread-safe.</para></listitem>
+ </itemizedlist>
+ </chapter>
+ <chapter>
+ <title>Components</title>
+ <section>
+ <title>Metadata</title>
+ <section>
+ <title>Overview</title>
+ <para>The <quote>metadata</quote> component governs the backend datastore for bitbake. It will store all the metadata associated with bitbake's recipes. This may or may not include actual functions, depending on the nature of the recipes being used.</para>
+ </section>
+ <section>
+ <title>Requirements</title>
+ <itemizedlist>
+ <listitem><para>The metadata is expected to be in the form of key/value pairs.</para></listitem>
+ <listitem><para>There needs to be a means of specifying metadata about other metadata (key/value pairs that correspond to a specific existing key).</para></listitem>
+ <listitem><para>We know from the previous implementation that it is very important that we keep memory usage down, and ensure that we do not have multiple copies of the same metadata in RAM at any given time.</para></listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Component Architecture</title>
+ <para>The metadata for a given recipe will be laid out as a hash table. Each key (UTF-8 string) in the table will be associated with a <quote>BitBake variable</quote>. A BitBake variable consists of the following:</para>
+ <para>
+ <itemizedlist>
+ <listitem><para>linked list of variables that refer to this one</para></listitem>
+ <listitem><para>linked list of <quote>variable chunks</quote></para></listitem>
+ <listitem><para>a cached value (UTF-8 string), which is the resolved form of the variable chunks</para></listitem>
+ <listitem><para><quote>dirty</quote> flag to indicate whether the cached value is current</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>Variable chunks are independent, ordered, components of the value of a given piece of metadata. A chunk can take the form of a string or a reference to another variable. The cached form will be updated automatically whenever a variable that we refer to changes.</para>
+ </section>
+ </section>
+ <section>
+ <title>Recipes</title>
+ <section>
+ <title>Overview</title>
+ <para>The <quote>recipe</quote> component governs the parsing, storing, and execution of individual bitbake recipes. A bitbake recipe consists of an ordered sequence of steps to be executed and the associated metadata.</para>
+ </section>
+ <section>
+ <title>Requirements</title>
+ <itemizedlist>
+ <listitem><para>The parsers should be token-based rather than regular expression based.</para></listitem>
+ <listitem>
+ <para>We need to support multiple file formats for our metadata:</para>
+ <itemizedlist>
+ <listitem><para>.conf</para></listitem>
+ <listitem><para>.bb</para></listitem>
+ <listitem><para>.inc</para></listitem>
+ <listitem><para>.bbclass</para></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem><para>The file formats need to be well defined and have a BNF syntax.</para></listitem>
+ <listitem><para>The file formats need to be easily editable by a user.</para></listitem>
+ <listitem><para>We should ensure that very little escaping is necessary in the use of our metadata for the common case (avoid using ${} for variable expansion, for example, because that's what the shell uses).</para></listitem>
+ <listitem><para>The parser must do a good job of detecting and reporting syntax errors.</para></listitem>
+ <listitem><para>The valid escape sequences (i.e. \n, \r) and anything else that needs escaping must be well defined and documented.</para></listitem>
+ <listitem><para>We must have well defined namespaces/scopes, with defined rules for merging them (inheritence/inclusion).</para></listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Component Architecture</title>
+ <para>A bitbake recipe consists of a number of individual pieces. Naturally, being a recipe, it has a set of ordered steps to be followed. It also has a set of ingredients (associated bitbake metadata). The first of the bitbake specific aspects of the recipe is that it has links to its <quote>parents</quote>. The parents of a given bitbake recipe are essentially the context for the recipe, or the <quote>scope</quote> the recipe is in. This may be global user specified configuration parameters, or <quote>classes</quote> to abstract out common parts of the recipe. To give a real world example, you might have a recipe class for cookies. Each recipe has its own unique steps, but for the most part, the steps involved in making cookies are the same.</para>
+ </section>
+ </section>
+ <section>
+ <title>Recipe Box</title>
+ <para><emphasis>Insert content here.</emphasis></para>
+ </section>
+ <section>
+ <title>Bakers</title>
+ <section>
+ <title>Requirements</title>
+ <itemizedlist>
+ <listitem><para>We must be able to build .bb files in dependency order (package A depends on package B).</para></listitem>
+ <listitem><para>We must handle inter-task dependency for a single .bb.</para></listitem>
+ <listitem><para>We <emphasis>MAY</emphasis> want to allow inter-task dependencies across package boundaries (package A's configure and compile tasks depend on package B's staging task).</para></listitem>
+ <listitem><para>We must handle PROVIDES, and multiple-provides situations (the user must be able to extert control over what providers they would prefer and/or require).</para></listitem>
+ <listitem><para>We should support multiple interpreters for the executed code (python, shell, etc).</para></listitem>
+ <listitem><para>We need to handle package version comparisons when selecting providers, and again, the user needs to be able to extert control over this.</para></listitem>
+ <listitem><para>It would be useful if there was a way to depend on a condition regarding another package's metadata. In other words, package A depends on package B being built in a certain way.</para></listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Possible Solutions</title>
+ <itemizedlist>
+ <listitem><para><emphasis>Insert content here.</emphasis></para></listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Implementation Decision</title>
+ <para><emphasis>Insert content here.</emphasis></para>
+ </section>
+ </section>
+ </chapter>
+ <chapter>
+ <title>Component Relationships</title>
+ <para><emphasis>Insert content here.</emphasis></para>
+ </chapter>
+</book>
diff --git a/trunk/bitbake-ng/doc/design_spec/html.css b/trunk/bitbake-ng/doc/design_spec/html.css
new file mode 100644
index 000000000..6eedfd318
--- /dev/null
+++ b/trunk/bitbake-ng/doc/design_spec/html.css
@@ -0,0 +1,281 @@
+/* Feuille de style DocBook du projet Traduc.org */
+/* DocBook CSS stylesheet of the Traduc.org project */
+
+/* (c) Jean-Philippe Guérard - 14 août 2004 */
+/* (c) Jean-Philippe Guérard - 14 August 2004 */
+
+/* Cette feuille de style est libre, vous pouvez la */
+/* redistribuer et la modifier selon les termes de la Licence */
+/* Art Libre. Vous trouverez un exemplaire de cette Licence sur */
+/* http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
+
+/* This work of art is free, you can redistribute it and/or */
+/* modify it according to terms of the Free Art license. You */
+/* will find a specimen of this license on the Copyleft */
+/* Attitude web site: http://artlibre.org as well as on other */
+/* sites. */
+/* Please note that the French version of this licence as shown */
+/* on http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
+/* is only official licence of this document. The English */
+/* is only provided to help you understand this licence. */
+
+/* La dernière version de cette feuille de style est toujours */
+/* disponible sur : http://tigreraye.org/style.css */
+/* Elle est également disponible sur : */
+/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
+
+/* The latest version of this stylesheet is available from: */
+/* http://tigreraye.org/style.css */
+/* It is also available on: */
+/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
+
+/* N'hésitez pas à envoyer vos commentaires et corrections à */
+/* Jean-Philippe Guérard <jean-philippe.guerard@tigreraye.org> */
+
+/* Please send feedback and bug reports to */
+/* Jean-Philippe Guérard <jean-philippe.guerard@tigreraye.org> */
+
+/* $Id: style.css,v 1.14 2004/09/10 20:12:09 fevrier Exp fevrier $ */
+
+/* Présentation générale du document */
+/* Overall document presentation */
+
+body {
+ /*
+ font-family: Apolline, "URW Palladio L", Garamond, jGaramond,
+ "Bitstream Cyberbit", "Palatino Linotype", serif;
+ */
+ margin: 7%;
+ background-color: white;
+}
+
+/* Taille du texte */
+/* Text size */
+
+* { font-size: 100%; }
+
+/* Gestion des textes mis en relief imbriqués */
+/* Embedded emphasis */
+
+em { font-style: italic; }
+em em { font-style: normal; }
+em em em { font-style: italic; }
+
+/* Titres */
+/* Titles */
+
+h1 { font-size: 200%; font-weight: 900; }
+h2 { font-size: 160%; font-weight: 900; }
+h3 { font-size: 130%; font-weight: bold; }
+h4 { font-size: 115%; font-weight: bold; }
+h5 { font-size: 108%; font-weight: bold; }
+h6 { font-weight: bold; }
+
+/* Nom de famille en petites majuscules (uniquement en français) */
+/* Last names in small caps (for French only) */
+
+*[class~="surname"]:lang(fr) { font-variant: small-caps; }
+
+/* Blocs de citation */
+/* Quotation blocs */
+
+div[class~="blockquote"] {
+ border: solid 2px #AAA;
+ padding: 5px;
+ margin: 5px;
+}
+
+div[class~="blockquote"] > table {
+ border: none;
+}
+
+/* Blocs litéraux : fond gris clair */
+/* Literal blocs: light gray background */
+
+*[class~="literallayout"] {
+ background: #f0f0f0;
+ padding: 5px;
+ margin: 5px;
+}
+
+/* Programmes et captures texte : fond bleu clair */
+/* Listing and text screen snapshots: light blue background */
+
+*[class~="programlisting"], *[class~="screen"] {
+ background: #f0f0ff;
+ padding: 5px;
+ margin: 5px;
+}
+
+/* Les textes à remplacer sont surlignés en vert pâle */
+/* Replaceable text in highlighted in pale green */
+
+*[class~="replaceable"] {
+ background-color: #98fb98;
+ font-style: normal; }
+
+/* Tables : fonds gris clair & bords simples */
+/* Tables: light gray background and solid borders */
+
+*[class~="table"] *[class~="title"] { width:100%; border: 0px; }
+
+table {
+ border: 1px solid #aaa;
+ border-collapse: collapse;
+ padding: 2px;
+ margin: 5px;
+}
+
+/* Listes simples en style table */
+/* Simples lists in table presentation */
+
+table[class~="simplelist"] {
+ background-color: #F0F0F0;
+ margin: 5px;
+ border: solid 1px #AAA;
+}
+
+table[class~="simplelist"] td {
+ border: solid 1px #AAA;
+}
+
+/* Les tables */
+/* Tables */
+
+*[class~="table"] table {
+ background-color: #F0F0F0;
+ border: solid 1px #AAA;
+}
+*[class~="informaltable"] table { background-color: #F0F0F0; }
+
+th,td {
+ vertical-align: baseline;
+ text-align: left;
+ padding: 0.1em 0.3em;
+ empty-cells: show;
+}
+
+/* Alignement des colonnes */
+/* Colunms alignment */
+
+td[align=center] , th[align=center] { text-align: center; }
+td[align=right] , th[align=right] { text-align: right; }
+td[align=left] , th[align=left] { text-align: left; }
+td[align=justify] , th[align=justify] { text-align: justify; }
+
+/* Pas de marge autour des images */
+/* No inside margins for images */
+
+img { border: 0; }
+
+/* Les liens ne sont pas soulignés */
+/* No underlines for links */
+
+:link , :visited , :active { text-decoration: none; }
+
+/* Prudence : cadre jaune et fond jaune clair */
+/* Caution: yellow border and light yellow background */
+
+*[class~="caution"] {
+ border: solid 2px yellow;
+ background-color: #ffffe0;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="caution"] th {
+ vertical-align: middle
+}
+
+*[class~="caution"] table {
+ background-color: #ffffe0;
+ border: none;
+}
+
+/* Note importante : cadre jaune et fond jaune clair */
+/* Important: yellow border and light yellow background */
+
+*[class~="important"] {
+ border: solid 2px yellow;
+ background-color: #ffffe0;
+ padding: 1em 6px 1em;
+ margin: 5px;
+}
+
+*[class~="important"] th {
+ vertical-align: middle
+}
+
+*[class~="important"] table {
+ background-color: #ffffe0;
+ border: none;
+}
+
+/* Mise en évidence : texte légèrement plus grand */
+/* Highlights: slightly larger texts */
+
+*[class~="highlights"] {
+ font-size: 110%;
+}
+
+/* Note : cadre bleu et fond bleu clair */
+/* Notes: blue border and light blue background */
+
+*[class~="note"] {
+ border: solid 2px #7099C5;
+ background-color: #f0f0ff;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="note"] th {
+ vertical-align: middle
+}
+
+*[class~="note"] table {
+ background-color: #f0f0ff;
+ border: none;
+}
+
+/* Astuce : cadre vert et fond vert clair */
+/* Tip: green border and light green background */
+
+*[class~="tip"] {
+ border: solid 2px #00ff00;
+ background-color: #f0ffff;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="tip"] th {
+ vertical-align: middle;
+}
+
+*[class~="tip"] table {
+ background-color: #f0ffff;
+ border: none;
+}
+
+/* Avertissement : cadre rouge et fond rouge clair */
+/* Warning: red border and light red background */
+
+*[class~="warning"] {
+ border: solid 2px #ff0000;
+ background-color: #fff0f0;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="warning"] th {
+ vertical-align: middle;
+}
+
+
+*[class~="warning"] table {
+ background-color: #fff0f0;
+ border: none;
+}
+
+/* Fin */
+/* The End */
+
diff --git a/trunk/bitbake-ng/doc/doxygen.am b/trunk/bitbake-ng/doc/doxygen.am
new file mode 100644
index 000000000..420049eca
--- /dev/null
+++ b/trunk/bitbake-ng/doc/doxygen.am
@@ -0,0 +1,186 @@
+# Copyright (C) 2004 Oren Ben-Kiki
+# This file is distributed under the same terms as the Automake macro files.
+
+# Generate automatic documentation using Doxygen. Goals and variables values
+# are controlled by the various DX_COND_??? conditionals set by autoconf.
+#
+# The provided goals are:
+# doxygen-doc: Generate all doxygen documentation.
+# doxygen-run: Run doxygen, which will generate some of the documentation
+# (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post
+# processing required for the rest of it (PS, PDF, and some MAN).
+# doxygen-man: Rename some doxygen generated man pages.
+# doxygen-ps: Generate doxygen PostScript documentation.
+# doxygen-pdf: Generate doxygen PDF documentation.
+#
+# Note that by default these are not integrated into the automake goals. If
+# doxygen is used to generate man pages, you can achieve this integration by
+# setting man3_MANS to the list of man pages generated and then adding the
+# dependency:
+#
+# $(man3_MANS): doxygen-doc
+#
+# This will cause make to run doxygen and generate all the documentation.
+#
+# The following variable is intended for use in Makefile.am:
+#
+# DX_CLEANFILES = everything to clean.
+#
+# This is usually added to MOSTLYCLEANFILES.
+
+## --------------------------------- ##
+## Format-independent Doxygen rules. ##
+## --------------------------------- ##
+
+if DX_COND_doc
+
+## ------------------------------- ##
+## Rules specific for HTML output. ##
+## ------------------------------- ##
+
+if DX_COND_html
+
+DX_CLEAN_HTML = @DX_DOCDIR@/html
+
+endif DX_COND_html
+
+## ------------------------------ ##
+## Rules specific for CHM output. ##
+## ------------------------------ ##
+
+if DX_COND_chm
+
+DX_CLEAN_CHM = @DX_DOCDIR@/chm
+
+if DX_COND_chi
+
+DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi
+
+endif DX_COND_chi
+
+endif DX_COND_chm
+
+## ------------------------------ ##
+## Rules specific for MAN output. ##
+## ------------------------------ ##
+
+if DX_COND_man
+
+DX_CLEAN_MAN = @DX_DOCDIR@/man
+
+endif DX_COND_man
+
+## ------------------------------ ##
+## Rules specific for RTF output. ##
+## ------------------------------ ##
+
+if DX_COND_rtf
+
+DX_CLEAN_RTF = @DX_DOCDIR@/rtf
+
+endif DX_COND_rtf
+
+## ------------------------------ ##
+## Rules specific for XML output. ##
+## ------------------------------ ##
+
+if DX_COND_xml
+
+DX_CLEAN_XML = @DX_DOCDIR@/xml
+
+endif DX_COND_xml
+
+## ----------------------------- ##
+## Rules specific for PS output. ##
+## ----------------------------- ##
+
+if DX_COND_ps
+
+DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps
+
+DX_PS_GOAL = doxygen-ps
+
+doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps
+
+@DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag
+ cd @DX_DOCDIR@/latex; \
+ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
+ $(DX_LATEX) refman.tex; \
+ $(MAKEINDEX_PATH) refman.idx; \
+ $(DX_LATEX) refman.tex; \
+ countdown=5; \
+ while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
+ refman.log > /dev/null 2>&1 \
+ && test $$countdown -gt 0; do \
+ $(DX_LATEX) refman.tex; \
+ countdown=`expr $$countdown - 1`; \
+ done; \
+ $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi
+
+endif DX_COND_ps
+
+## ------------------------------ ##
+## Rules specific for PDF output. ##
+## ------------------------------ ##
+
+if DX_COND_pdf
+
+DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf
+
+DX_PDF_GOAL = doxygen-pdf
+
+doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf
+
+@DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag
+ cd @DX_DOCDIR@/latex; \
+ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
+ $(DX_PDFLATEX) refman.tex; \
+ $(DX_MAKEINDEX) refman.idx; \
+ $(DX_PDFLATEX) refman.tex; \
+ countdown=5; \
+ while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
+ refman.log > /dev/null 2>&1 \
+ && test $$countdown -gt 0; do \
+ $(DX_PDFLATEX) refman.tex; \
+ countdown=`expr $$countdown - 1`; \
+ done; \
+ mv refman.pdf ../@PACKAGE@.pdf
+
+endif DX_COND_pdf
+
+## ------------------------------------------------- ##
+## Rules specific for LaTeX (shared for PS and PDF). ##
+## ------------------------------------------------- ##
+
+if DX_COND_latex
+
+DX_CLEAN_LATEX = @DX_DOCDIR@/latex
+
+endif DX_COND_latex
+
+.PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)
+
+.INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
+
+doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag
+
+doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
+
+@DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS)
+ rm -rf @DX_DOCDIR@
+ $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)
+
+DX_CLEANFILES = \
+ @DX_DOCDIR@/@PACKAGE@.tag \
+ -r \
+ $(DX_CLEAN_HTML) \
+ $(DX_CLEAN_CHM) \
+ $(DX_CLEAN_CHI) \
+ $(DX_CLEAN_MAN) \
+ $(DX_CLEAN_RTF) \
+ $(DX_CLEAN_XML) \
+ $(DX_CLEAN_PS) \
+ $(DX_CLEAN_PDF) \
+ $(DX_CLEAN_LATEX)
+
+endif DX_COND_doc
diff --git a/trunk/bitbake-ng/doc/doxygen.cfg b/trunk/bitbake-ng/doc/doxygen.cfg
new file mode 100644
index 000000000..73f408337
--- /dev/null
+++ b/trunk/bitbake-ng/doc/doxygen.cfg
@@ -0,0 +1,212 @@
+# Doxyfile 1.3.7
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = $(PROJECT)-$(VERSION)
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = $(DOCDIR)
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+STRIP_FROM_INC_PATH = $(SRCDIR)
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = $(SRCDIR)/include $(SRCDIR)
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = YES
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = YES
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = $(SRCDIR)/include
+FILE_PATTERNS = *.c *.h
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS = *-private*
+EXAMPLE_PATH = $(SRCDIR)
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = $(GENERATE_HTML)
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = $(GENERATE_CHM)
+CHM_FILE = ../$(PROJECT).chm
+HHC_LOCATION = $(HHC_PATH)
+GENERATE_CHI = $(GENERATE_CHI)
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = $(GENERATE_LATEX)
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = $(PAPER_SIZE)
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = YES
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = $(GENERATE_RTF)
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = $(GENERATE_MAN)
+MAN_OUTPUT = man
+MAN_EXTENSION = .1
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = $(GENERATE_XML)
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = $(PERL_PATH)
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = $(HAVE_DOT)
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH = $(DOT_PATH)
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/trunk/bitbake-ng/doc/ramblings/bbtree.txt b/trunk/bitbake-ng/doc/ramblings/bbtree.txt
new file mode 100644
index 000000000..dfff8d13c
--- /dev/null
+++ b/trunk/bitbake-ng/doc/ramblings/bbtree.txt
@@ -0,0 +1,39 @@
+F = Fetch
+P = Patch
+Cf = Configure
+Cp = Compile
+S = Stage
+Pk = Package
+
+
+
+F1 <-- P1 <-- Cf1 <-- Cp1 <-- S1 <-- Pk1
+ ^
+ ---------------|
+ |
+F2 <-- P2 <-- Cf2 <-- Cp2 <-- S2 <-- Pk2
+ ^
+ ---------------|
+ |
+F3 <-- P3 <-- Cf3 <-- Cp3 <-- S3 <-- Pk3
+
+
+Counts (start at the end products and work backwards)
+Pk1 - 1
+Pk2 - 1
+Pk3 - 1
+S1 - 3
+S2 - 2
+S3 - 1
+Cp1 - 3
+Cp2 - 2
+Cp3 - 1
+Cf1 - 3
+Cf2 - 2
+Cf3 - 1
+P1 - 3
+P2 - 2
+P3 - 1
+F1 - 3
+F2 - 2
+F3 - 1 \ No newline at end of file
diff --git a/trunk/bitbake-ng/doc/ramblings/bitbakeng-metadata.txt b/trunk/bitbake-ng/doc/ramblings/bitbakeng-metadata.txt
new file mode 100644
index 000000000..ac02d16a8
--- /dev/null
+++ b/trunk/bitbake-ng/doc/ramblings/bitbakeng-metadata.txt
@@ -0,0 +1,103 @@
+NOTE: this doc is slightly coherent mumbling and psuedo code. I'll make it
+have actual implementations of the structures, and more coherent outlining of
+the design, shortly.
+
+struct var_chunk {
+ type;
+ data;
+ condition; /* A in B .. any chunk of a var can be conditional, to
+ facilitate conditional prepend/append */
+}
+
+struct var_chunk_set {
+ list of var_chunks;
+ condition; /* A in B .. any var itself's value can be conditional */
+}
+
+struct var {
+ name;
+ cached_val; /* expanded version of the value */
+ list of var_chunk_sets; /* unexpanded version of the value */
+ bool dirty; /* dbbs it need re-expansion due to the referees changing? */
+ list of vars; /* referrers */
+}
+
+enum bb_opcode {
+ BB_VAR_SET,
+ BB_VAR_APPEND,
+ BB_VAR_APPEND_NOSPACE,
+ BB_VAR_PREPEND,
+ BB_VAR_PREPEND_NOSPACE,
+ BB_VAR_DEL
+ BB_VAR_ATTR_SET,
+ BB_VAR_ATTR_APPEND,
+ BB_VAR_ATTR_APPEND_NOSPACE,
+ BB_VAR_ATTR_PREPEND
+ BB_VAR_ATTR_PREPEND_NOSPACE,
+ BB_VAR_ATTR_DEL
+};
+
+struct bb_cmd {
+ enum bb_opcode;
+ list of data;
+};
+
+struct bb_compiled {
+ list of struct bbc's;
+}
+
+struct pre_metadata_set {
+ list of:
+ {
+ if resolved -> struct var
+ if unresolved -> bbc
+ }
+}
+
+struct metadata_set {
+ parents; /* links to higher scopes */
+ hash table of var name -> struct var;
+}
+
+NOTE: we track variable referrers (who has me in their var chunks?)
+
+example:
+A := ${B} /* unresolved */
+C := a /* resolved */
+D := ${A} /* unresolved */
+C += ${B} /* unresolved */
+E := ${C} /* resolved */
+F = ${B} /* unresolved, but its contents can be a struct var, not an bbc */
+
+Then, when you link a metadata set to another (set our scope under his),
+all the unresolved bbc's can be immediately executed, producing a new
+metadata set which is entirely struct var's.
+
+Once a pre metadata set is executed / attached to its parent scopes, we know
+that the pre_metadata_set -> metadata_set needs to occur again whenever one of
+its parents is dirtied. Technically, we know which variables in its parents
+affect which variables of ours, but unless we track which bbc's affected which
+variables, we'll have to rerun the pre metadata set -> metadata set operation
+whenever its parents change.
+
+In conclusion, precompiling the .bb with bbc's, and using the pre metadata set,
+enables us to avoid reparsing files that depend on their context in each possible
+context, and when its context changes. For example, this will enable us to
+avoid reparsing all the .bb files when bb.conf or local.conf changes.
+
+Caching the pre metadata set as well as the compiled bb reduces the number of
+bbc executions necessary when attaching to a new parent scope (i.e. taking
+base.bbclass and attaching it to each and every .bb).
+
+Caching the metadata set allows us to avoid reexecution of any bbc's when
+context hasn't changed, and the compiled bb isnt dirty.
+
+bbmake runs:
+ reparse any changed/new files
+ re execution bbc's whereever someone was affected by the reparses
+ store the metadata sets in an sqlite db
+
+ Now, after this, we know that the db contains the current metadata sets for
+ all existing files. We can issue sql queries to obtain all the dependency
+ information to construct our build paths, and can obtain the package data
+ whenever we're ready for it.
diff --git a/trunk/bitbake-ng/doc/ramblings/bitbakeng-parser-frontend.txt b/trunk/bitbake-ng/doc/ramblings/bitbakeng-parser-frontend.txt
new file mode 100644
index 000000000..52ec47f2c
--- /dev/null
+++ b/trunk/bitbake-ng/doc/ramblings/bitbakeng-parser-frontend.txt
@@ -0,0 +1,21 @@
+enum metadata_source_type {
+ OE_METADATA_ENV,
+ OE_METADATA_FILE
+}
+
+struct metadata_source {
+ enum metadata_source_type;
+ gcchar *location;
+ struct oe_metadata *data;
+ void *private;
+}
+
+#if 0
+/* this probably belongs in whomever is doing the parsing and
+ storing of the metadata */
+struct metadata_sources {
+ hash of metadata_source's, keyed by location?;
+}
+#endif
+
+struct metadata_source_type *oe_getmetadata_sync(enum metadata_source_type, location);
diff --git a/trunk/bitbake-ng/include/Makefile.am b/trunk/bitbake-ng/include/Makefile.am
new file mode 100644
index 000000000..babda4833
--- /dev/null
+++ b/trunk/bitbake-ng/include/Makefile.am
@@ -0,0 +1,2 @@
+noinst_HEADERS = bitbake/data-private.h
+nobase_relinclude_HEADERS = bitbake/common.h bitbake/data.h bitbake.h
diff --git a/trunk/bitbake-ng/include/bitbake.h b/trunk/bitbake-ng/include/bitbake.h
new file mode 100644
index 000000000..35d1eff5e
--- /dev/null
+++ b/trunk/bitbake-ng/include/bitbake.h
@@ -0,0 +1,40 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BITBAKE_H
+# define _BITBAKE_H
+
+#include <bitbake/common.h>
+#include <bitbake/data.h>
+#include <bitbake/recipe.h>
+#include <bitbake/recipe-modules.h>
+
+BITBAKE_HDR_BEGIN
+
+/** @file bitbake.h
+ * @brief Bitbake primary header file */
+
+BITBAKE_HDR_END
+
+#endif /* _BITBAKE_H */
diff --git a/trunk/bitbake-ng/include/bitbake/common.h b/trunk/bitbake-ng/include/bitbake/common.h
new file mode 100644
index 000000000..516b72e94
--- /dev/null
+++ b/trunk/bitbake-ng/include/bitbake/common.h
@@ -0,0 +1,82 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BB_COMMON_H
+# define _BB_COMMON_H
+
+# ifdef __cplusplus
+# define BITBAKE_HDR_BEGIN extern "C" {
+# define BITBAKE_HDR_END }
+# else
+# define BITBAKE_HDR_BEGIN
+# define BITBAKE_HDR_END
+# endif /* __cplusplus */
+
+BITBAKE_HDR_BEGIN
+
+/** @file common.h
+ * @brief Header for bitbake's commonly used macros */
+
+/* Shared library support */
+# ifdef WIN32
+# define BBIMPORT __declspec(dllimport)
+# define BBEXPORT __declspec(dllexport)
+# define BBDLLLOCAL
+# define BBDLLPUBLIC
+# else
+# define BBIMPORT
+# ifdef GCC_HASCLASSVISIBILITY
+# define BBEXPORT __attribute__ ((visibility("default")))
+# define BBDLLLOCAL __attribute__ ((visibility("hidden")))
+# define BBDLLPUBLIC __attribute__ ((visibility("default")))
+# else
+# define BBEXPORT
+# define BBDLLLOCAL
+# define BBDLLPUBLIC
+# endif
+# endif
+
+/* Define BBAPI for DLL builds */
+# ifdef BBDLL
+# ifdef BBDLL_EXPORTS
+# define BBAPI BBEXPORT
+# else
+# define BBAPI BBIMPORT
+# endif /* BBDLL_EXPORTS */
+# else
+# define BBAPI
+# endif /* BBDLL */
+
+/* Throwable classes must always be visible on GCC in all binaries */
+# ifdef WIN32
+# define BBEXCEPTIONAPI(api) api
+# elif defined(GCC_HASCLASSVISIBILITY)
+# define BBEXCEPTIONAPI(api) BBEXPORT
+# else
+# define BBEXCEPTIONAPI(api)
+# endif
+
+BITBAKE_HDR_END
+
+#endif /* _BITBAKE_H */
diff --git a/trunk/bitbake-ng/include/bitbake/data-private.h b/trunk/bitbake-ng/include/bitbake/data-private.h
new file mode 100644
index 000000000..fbe4fb83b
--- /dev/null
+++ b/trunk/bitbake-ng/include/bitbake/data-private.h
@@ -0,0 +1,139 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BB_DATA_PRIVATE_H
+# define _BB_DATA_PRIVATE_H
+# ifdef BBDLL_EXPORTS
+
+# include <bitbake/common.h>
+# include <glib.h>
+
+BITBAKE_HDR_BEGIN
+
+
+/** @file data-private.h
+ * @brief Private header for bitbake metadata handling */
+
+/**
+ * Bitbake variable chunk types
+ */
+enum bb_var_chunk_type {
+ /**
+ * Indicates that the variable chunk in question is a string
+ */
+ BB_VAR_STR,
+
+ /**
+ * Indicates that the variable chunk in question is a
+ * reference to another bitbake variable.
+ */
+ BB_VAR_REF,
+};
+
+
+/**
+ * \brief BitBake variable chunk
+ *
+ * BitBake variables consist of multiple pieces, including, but not
+ * limited to, strings and references to other variables.
+ */
+struct bb_var_chunk {
+ /**
+ * Type of chunk (i.e. BB_VAR_REF, BBVAR_STR, etc)
+ */
+ enum bb_var_chunk_type type;
+
+ /**
+ * Pointer to this chunk's data
+ */
+ gpointer *data;
+};
+
+
+/**
+ * BitBake variable
+ */
+struct bb_var {
+ /**
+ * Variable name
+ */
+ gchar *key;
+
+ /**
+ * Cached value (post-expansion)
+ */
+ gchar *val;
+
+ /**
+ * Uncached value (pre-expansion)
+ */
+ gchar *orig_val;
+
+ /**
+ * List of variable chunks (of type struct bb_var_chunk)
+ */
+ GList *chunks;
+
+ /**
+ * Dirty flag -- indicates whether the cached value needs to
+ * be updated, most likely due to referees changing.
+ */
+ int dirty;
+
+ /**
+ * List of variables that refer to this variable
+ */
+ GList *referrers;
+
+ /**
+ * Hash table of bitbake variable "attributes". Bitbake variable
+ * attributes are metadata about our metadata. This allows us to
+ * set flags about the metadata. For example, we can specify the
+ * interpreter for a given block of executable code.
+ *
+ * The hash table is attribute name -> gcchar *.
+ */
+ GHashTable *attributes;
+};
+
+/**
+ * BitBake Datastore
+ */
+struct bb_data {
+ /**
+ * Links to context / higher scopes
+ */
+ GList *parents;
+
+ /**
+ * Hash table of variable name -> struct bb_var
+ */
+ GHashTable *data;
+};
+
+
+BITBAKE_HDR_BEGIN
+
+#endif /* BBDLL_EXPORTS */
+#endif /* _BB_DATA_PRIVATE_H */
diff --git a/trunk/bitbake-ng/include/bitbake/data.h b/trunk/bitbake-ng/include/bitbake/data.h
new file mode 100644
index 000000000..24357dbae
--- /dev/null
+++ b/trunk/bitbake-ng/include/bitbake/data.h
@@ -0,0 +1,183 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BB_DATA_H
+# define _BB_DATA_H
+
+# include <bitbake/common.h>
+# include <glib/gtypes.h>
+
+BITBAKE_HDR_BEGIN
+
+
+/** @file data.h
+ * @brief Header for bitbake metadata handling */
+
+/**
+ *@brief Creates a new bitbake metadata store
+ *
+ *@return An empty bitbake metadata store
+ */
+BBAPI gpointer bb_data_new(void);
+
+/**
+ *Obtains the value of an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *
+ *@return The variable's value.
+ */
+BBAPI gchar *bb_data_lookup(gconstpointer data, gchar *var);
+
+
+/**
+ *Sets the value of an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param val The value to be set the variable to.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBAPI gboolean bb_data_insert(gpointer data, gchar *var, gchar *val);
+
+
+/**
+ *Deletes an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBAPI gboolean bb_data_remove(gpointer data, gchar *var);
+
+
+#if 0
+/**
+ *Obtains a certain conditional value associated with an bitbake variable.
+ *
+ *An bitbake variable has a default value (that which is
+ *accessed by the usual bb_data_insert api), and any
+ *number of possible values which are bound to conditions.
+ *
+ *This function obtains one of those conditional values.
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param conditions The conditions which apply to the value we're
+ * attempting to get.
+ *
+ *@return The conditional value.
+ */
+BBAPI gchar *bb_data_lookup_cond(gconstpointer data, gchar *var, gchar *conditions[2]);
+
+
+/**
+ *Sets a certain conditional value associated with an bitbake variable.
+ *
+ *An bitbake variable has a default value (that which is
+ *accessed by the usual bb_data_insert api), and any
+ *number of possible values which are bound to conditions.
+ *
+ *This function removes one of those conditional values.
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param val The value to set this variable to when these conditions are true.
+ *@param conditions The conditions which apply to the value we're
+ * attempting to remove.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBAPI gboolean bb_data_insert_cond(gpointer data, gchar *var, gchar *val, gchar *conditions[2]);
+
+
+/**
+ *Deletes a certain conditional value associated with an bitbake variable.
+ *
+ *An bitbake variable has a default value (that which is
+ *accessed by the usual bb_data_insert api), and any
+ *number of possible values which are bound to conditions.
+ *
+ *This function removes one of those conditional values.
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param conditions The conditions which apply to the value we're
+ * attempting to remove.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBAPI gboolean bb_data_remove_cond(gpointer data, gchar *var, gchar *conditions[2]);
+#endif
+
+
+/**
+ *Obtains the value of one of the attributes of an bitbake variable.
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param attr The attribute name.
+ *
+ *@return The attribute in question.
+ */
+BBAPI gchar *bb_data_lookup_attr(gconstpointer data, gchar *var, gchar *attr);
+
+
+/**
+ *Sets the value of one of the attributes of an bitbake variable.
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param val The value to set this attribute to.
+ *@param attr The attribute name.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBAPI gboolean bb_data_insert_attr(gpointer data, gchar *var, gchar *attr, gchar *val);
+
+
+/**
+ *Deletes a given attribute from an bitbake variable
+ *
+ *@param data The bitbake metadata store in question.
+ *@param var The variable name.
+ *@param attr The attribute name.
+ *
+ *@return TRUE if succeeded, FALSE if failed.
+ */
+BBAPI gboolean bb_data_remove_attr(gpointer data, gchar *var, gchar *attr);
+
+/**
+ *Destroys a bitbake metadata store and all of its variables
+ *
+ */
+BBAPI void bb_data_destroy(gpointer data);
+
+
+BITBAKE_HDR_END
+
+#endif /*_BB_DATA_H */
diff --git a/trunk/bitbake-ng/include/bitbake/recipe-modules.h b/trunk/bitbake-ng/include/bitbake/recipe-modules.h
new file mode 100644
index 000000000..e8045ae09
--- /dev/null
+++ b/trunk/bitbake-ng/include/bitbake/recipe-modules.h
@@ -0,0 +1,50 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BB_RECIPE_MODULES_H
+# define _BB_RECIPE_MODULES_H
+
+# include <bitbake/common.h>
+# include <glib/gtypes.h>
+
+BITBAKE_HDR_BEGIN
+
+
+/** @file recipe-modules.h
+ * @brief Header for bitbake recipe handling (backend modules) */
+
+BBAPI gboolean bb_recipe_load_parsers();
+BBAPI gboolean bb_recipe_register_parser();
+BBAPI void bb_recipe_unregister_parser();
+BBAPI void bb_recipe_unload_parsers();
+
+BBAPI gboolean bb_recipe_load_workers();
+BBAPI gboolean bb_recipe_register_worker();
+BBAPI void bb_recipe_unregister_worker();
+BBAPI void bb_recipe_unload_workers();
+
+
+BITBAKE_HDR_END
+
+#endif /* _BB_RECIPE_MODULES_H */
diff --git a/trunk/bitbake-ng/include/bitbake/recipe.h b/trunk/bitbake-ng/include/bitbake/recipe.h
new file mode 100644
index 000000000..f815fd910
--- /dev/null
+++ b/trunk/bitbake-ng/include/bitbake/recipe.h
@@ -0,0 +1,58 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _BB_RECIPE_H
+# define _BB_RECIPE_H
+
+# include <bitbake/common.h>
+# include <glib/gtypes.h>
+
+BITBAKE_HDR_BEGIN
+
+
+/** @file recipe.h
+ * @brief Header for bitbake recipe handling (frontend) */
+
+BBAPI gpointer bb_recipe_new(void);
+
+BBAPI gboolean bb_recipe_load(gpointer recipe, gchar *location);
+BBAPI gboolean bb_recipe_load_into_box(gpointer recipe, gpointer recipe_box, gchar *location);
+BBAPI gboolean bb_recipe_sync(gpointer recipe);
+
+BBAPI gboolean bb_recipe_add_parent(gpointer recipe, gpointer parent);
+BBAPI gpointer bb_recipe_foreach_parent(gpointer recipe, char *callback);
+BBAPI gboolean bb_recipe_remove_parent(gpointer recipe, gchar *parent_loc);
+
+gchar *bb_recipe_lookup_var(gpointer recipe, gchar *var);
+BBAPI gpointer bb_recipe_get_metadata(gpointer recipe);
+
+BBAPI gboolean bb_recipe_can_execute(gpointer recipe);
+BBAPI gboolean bb_recipe_execute(gpointer recipe);
+
+BBAPI void bb_recipe_destroy(gpointer recipe);
+
+
+BITBAKE_HDR_END
+
+#endif /* _BB_RECIPE_H */
diff --git a/trunk/bitbake-ng/m4/external/check.m4 b/trunk/bitbake-ng/m4/external/check.m4
new file mode 100644
index 000000000..97bfd9c47
--- /dev/null
+++ b/trunk/bitbake-ng/m4/external/check.m4
@@ -0,0 +1,133 @@
+dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS
+dnl
+
+AC_DEFUN(AM_PATH_CHECK,
+[
+ AC_ARG_WITH(check,
+ [ --with-check=PATH prefix where check is installed [default=auto]])
+
+ min_check_version=ifelse([$1], ,0.8.2,$1)
+
+ AC_MSG_CHECKING(for check - version >= $min_check_version)
+
+ if test x$with_check = xno; then
+ AC_MSG_RESULT(disabled)
+ ifelse([$3], , AC_MSG_ERROR([disabling check is not supported]), [$3])
+ else
+ if test "x$with_check" != x; then
+ CHECK_CFLAGS="-I$with_check/include"
+ CHECK_LIBS="-L$with_check/lib -lcheck"
+ else
+ CHECK_CFLAGS=""
+ CHECK_LIBS="-lcheck"
+ fi
+
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+
+ CFLAGS="$CFLAGS $CHECK_CFLAGS"
+ LIBS="$CHECK_LIBS $LIBS"
+
+ rm -f conf.check-test
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <check.h>
+
+int main ()
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ system ("touch conf.check-test");
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = strdup("$min_check_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_check_version");
+ return 1;
+ }
+
+ if ((CHECK_MAJOR_VERSION != check_major_version) ||
+ (CHECK_MINOR_VERSION != check_minor_version) ||
+ (CHECK_MICRO_VERSION != check_micro_version))
+ {
+ printf("\n*** The check header file (version %d.%d.%d) does not match\n",
+ CHECK_MAJOR_VERSION, CHECK_MINOR_VERSION, CHECK_MICRO_VERSION);
+ printf("*** the check library (version %d.%d.%d).\n",
+ check_major_version, check_minor_version, check_micro_version);
+ return 1;
+ }
+
+ if ((check_major_version > major) ||
+ ((check_major_version == major) && (check_minor_version > minor)) ||
+ ((check_major_version == major) && (check_minor_version == minor) && (check_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** An old version of check (%d.%d.%d) was found.\n",
+ check_major_version, check_minor_version, check_micro_version);
+ printf("*** You need a version of check being at least %d.%d.%d.\n", major, minor, micro);
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the check library and header\n");
+ printf("*** file is being found. Rerun configure with the --with-check=PATH option\n");
+ printf("*** to specify the prefix where the correct version was installed.\n");
+ }
+
+ return 1;
+}
+],, no_check=yes, [echo $ac_n "cross compiling; assumed OK... $ac_c"])
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+
+ if test "x$no_check" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test -f conf.check-test ; then
+ :
+ else
+ echo "*** Could not run check test program, checking why..."
+ CFLAGS="$CFLAGS $CHECK_CFLAGS"
+ LIBS="$CHECK_LIBS $LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <check.h>
+], , [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding check. You'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for"
+ echo "*** the exact error that occured." ])
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+ CHECK_CFLAGS=""
+ CHECK_LIBS=""
+
+ rm -f conf.check-test
+ ifelse([$3], , AC_MSG_ERROR([check not found]), [$3])
+ fi
+
+ AC_SUBST(CHECK_CFLAGS)
+ AC_SUBST(CHECK_LIBS)
+
+ rm -f conf.check-test
+
+ fi
+])
diff --git a/trunk/bitbake-ng/m4/internal/binreloc.m4 b/trunk/bitbake-ng/m4/internal/binreloc.m4
new file mode 100644
index 000000000..c569de498
--- /dev/null
+++ b/trunk/bitbake-ng/m4/internal/binreloc.m4
@@ -0,0 +1,76 @@
+# Check for binary relocation support
+# Hongli Lai
+# http://autopackage.org/
+
+AC_DEFUN([AM_BINRELOC],
+[
+ AC_ARG_ENABLE(binreloc,
+ [ --enable-binreloc compile with binary relocation support
+ (default=enable when available)],
+ enable_binreloc=$enableval,enable_binreloc=auto)
+
+ AC_ARG_ENABLE(binreloc-threads,
+ [ --enable-binreloc-threads compile binary relocation with threads support
+ (default=yes)],
+ enable_binreloc_threads=$enableval,enable_binreloc_threads=yes)
+
+ BINRELOC_CFLAGS=
+ BINRELOC_LIBS=
+ if test "x$enable_binreloc" = "xauto"; then
+ AC_CHECK_FILE([/proc/self/maps])
+ AC_CACHE_CHECK([whether everything is installed to the same prefix],
+ [br_cv_valid_prefixes], [
+ if test "$bindir" = '${exec_prefix}/bin' -a "$sbindir" = '${exec_prefix}/sbin' -a \
+ "$datadir" = '${prefix}/share' -a "$libdir" = '${exec_prefix}/lib' -a \
+ "$libexecdir" = '${exec_prefix}/libexec' -a "$sysconfdir" = '${prefix}/etc'
+ then
+ br_cv_valid_prefixes=yes
+ else
+ br_cv_valid_prefixes=no
+ fi
+ ])
+ fi
+ AC_CACHE_CHECK([whether binary relocation support should be enabled],
+ [br_cv_binreloc],
+ [if test "x$enable_binreloc" = "xyes"; then
+ br_cv_binreloc=yes
+ elif test "x$enable_binreloc" = "xauto"; then
+ if test "x$br_cv_valid_prefixes" = "xyes" -a \
+ "x$ac_cv_file__proc_self_maps" = "xyes"; then
+ br_cv_binreloc=yes
+ else
+ br_cv_binreloc=no
+ fi
+ else
+ br_cv_binreloc=no
+ fi])
+
+ if test "x$br_cv_binreloc" = "xyes"; then
+ BINRELOC_CFLAGS="-DENABLE_BINRELOC"
+ if test "x$enable_binreloc_threads" = "xyes"; then
+ safe_LIBS=$LIBS
+ AC_CHECK_LIB([pthread], [pthread_getspecific])
+ LIBS=$safe_LIBS
+ fi
+
+ AC_CACHE_CHECK([whether binary relocation should use threads],
+ [br_cv_binreloc_threads],
+ [if test "x$enable_binreloc_threads" = "xyes"; then
+ if test "x$ac_cv_lib_pthread_pthread_getspecific" = "xyes"; then
+ br_cv_binreloc_threads=yes
+ else
+ br_cv_binreloc_threads=no
+ fi
+ else
+ br_cv_binreloc_threads=no
+ fi])
+
+ if test "x$br_cv_binreloc_threads" = "xyes"; then
+ BINRELOC_LIBS="-lpthread"
+ else
+ BINRELOC_CFLAGS="$BINRELOC_CFLAGS -DBR_PTHREAD=0"
+ fi
+ fi
+ AC_SUBST(BINRELOC_CFLAGS)
+ AC_SUBST(BINRELOC_LIBS)
+])
diff --git a/trunk/bitbake-ng/m4/internal/doxygen.m4 b/trunk/bitbake-ng/m4/internal/doxygen.m4
new file mode 100644
index 000000000..877c8fdf9
--- /dev/null
+++ b/trunk/bitbake-ng/m4/internal/doxygen.m4
@@ -0,0 +1,312 @@
+# This file is part of Autoconf. -*- Autoconf -*-
+
+# Copyright (C) 2004 Oren Ben-Kiki
+# This file is distributed under the same terms as the Autoconf macro files.
+
+# Generate automatic documentation using Doxygen. Works in concert with the
+# aminclude.m4 file and a compatible doxygen configuration file. Defines the
+# following public macros:
+#
+# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature.
+# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics,
+# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI'
+# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF',
+# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment
+# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide'
+# paper size.
+#
+# By default, HTML, PDF and PS documentation is generated as this seems to be
+# the most popular and portable combination. MAN pages created by Doxygen are
+# usually problematic, though by picking an appropriate subset and doing some
+# massaging they might be better than nothing. CHM and RTF are specific for MS
+# (note that you can't generate both HTML and CHM at the same time). The XML is
+# rather useless unless you apply specialized post-processing to it.
+#
+# The macro mainly controls the default state of the feature. The use can
+# override the default by specifying --enable or --disable. The macros ensure
+# that contradictory flags are not given (e.g., --enable-doxygen-html and
+# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.)
+# Finally, each feature will be automatically disabled (with a warning) if the
+# required programs are missing.
+#
+# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with
+# the following parameters: a one-word name for the project for use as a
+# filename base etc., an optional configuration file name (the default is
+# 'Doxyfile', the same as Doxygen's default), and an optional output directory
+# name (the default is 'doxygen-doc').
+
+## ----------##
+## Defaults. ##
+## ----------##
+
+DX_ENV=""
+AC_DEFUN([DX_FEATURE_doc], ON)
+AC_DEFUN([DX_FEATURE_dot], ON)
+AC_DEFUN([DX_FEATURE_man], OFF)
+AC_DEFUN([DX_FEATURE_html], ON)
+AC_DEFUN([DX_FEATURE_chm], OFF)
+AC_DEFUN([DX_FEATURE_chi], OFF)
+AC_DEFUN([DX_FEATURE_rtf], OFF)
+AC_DEFUN([DX_FEATURE_xml], OFF)
+AC_DEFUN([DX_FEATURE_pdf], ON)
+AC_DEFUN([DX_FEATURE_ps], ON)
+
+## --------------- ##
+## Private macros. ##
+## --------------- ##
+
+# DX_ENV_APPEND(VARIABLE, VALUE)
+# ------------------------------
+# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen.
+AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])])
+
+# DX_DIRNAME_EXPR
+# ---------------
+# Expand into a shell expression prints the directory part of a path.
+AC_DEFUN([DX_DIRNAME_EXPR],
+ [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
+
+# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
+# -------------------------------------
+# Expands according to the M4 (static) status of the feature.
+AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
+
+# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
+# ----------------------------------
+# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
+AC_DEFUN([DX_REQUIRE_PROG], [
+AC_PATH_TOOL([$1], [$2])
+if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
+ AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
+ AC_SUBST([DX_FLAG_[]DX_CURRENT_FEATURE], 0)
+fi
+])
+
+# DX_TEST_FEATURE(FEATURE)
+# ------------------------
+# Expand to a shell expression testing whether the feature is active.
+AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
+
+# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
+# -------------------------------------------------
+# Verify that a required features has the right state before trying to turn on
+# the DX_CURRENT_FEATURE.
+AC_DEFUN([DX_CHECK_DEPEND], [
+test "$DX_FLAG_$1" = "$2" \
+|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
+ requires, contradicts) doxygen-DX_CURRENT_FEATURE])
+])
+
+# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
+# ----------------------------------------------------------
+# Turn off the DX_CURRENT_FEATURE if the required feature is off.
+AC_DEFUN([DX_CLEAR_DEPEND], [
+test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_[]DX_CURRENT_FEATURE], 0)
+])
+
+# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
+# CHECK_DEPEND, CLEAR_DEPEND,
+# REQUIRE, DO-IF-ON, DO-IF-OFF)
+# --------------------------------------------
+# Parse the command-line option controlling a feature. CHECK_DEPEND is called
+# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
+# otherwise CLEAR_DEPEND is called to turn off the default state if a required
+# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
+# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
+# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
+AC_DEFUN([DX_ARG_ABLE], [
+ AC_DEFUN([DX_CURRENT_FEATURE], [$1])
+ AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
+ AC_ARG_ENABLE(doxygen-$1,
+ [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
+ [--enable-doxygen-$1]),
+ DX_IF_FEATURE([$1], [don't $2], [$2]))],
+ [
+case "$enableval" in
+#(
+y|Y|yes|Yes|YES)
+ AC_SUBST([DX_FLAG_$1], 1)
+ $3
+;; #(
+n|N|no|No|NO)
+ AC_SUBST([DX_FLAG_$1], 0)
+;; #(
+*)
+ AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
+;;
+esac
+], [
+AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
+$4
+])
+if DX_TEST_FEATURE([$1]); then
+ $5
+ :
+fi
+if DX_TEST_FEATURE([$1]); then
+ AM_CONDITIONAL(DX_COND_$1, :)
+ $6
+ :
+else
+ AM_CONDITIONAL(DX_COND_$1, false)
+ $7
+ :
+fi
+])
+
+## -------------- ##
+## Public macros. ##
+## -------------- ##
+
+# DX_XXX_FEATURE(DEFAULT_STATE)
+# -----------------------------
+AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
+AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
+AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
+AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
+AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
+AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
+AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
+AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
+AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
+AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
+
+# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])
+# ---------------------------------------------------------
+# PROJECT also serves as the base name for the documentation files.
+# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc".
+AC_DEFUN([DX_INIT_DOXYGEN], [
+
+# Files:
+AC_SUBST([DX_PROJECT], [$1])
+AC_SUBST([DX_CONFIG], [[\$\(top_srcdir\)/]ifelse([$2], [], Doxyfile, [$2])])
+AC_SUBST([DX_DOCDIR], [[\$\(top_srcdir\)/]ifelse([$3], [], doxygen-doc, [$3])])
+
+# Environment variables used inside doxygen.cfg:
+DX_ENV_APPEND(SRCDIR, [\$(top_srcdir)])
+DX_ENV_APPEND(PROJECT, $DX_PROJECT)
+DX_ENV_APPEND(DOCDIR, $DX_DOCDIR)
+DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
+
+# Doxygen itself:
+DX_ARG_ABLE(doc, [generate any doxygen documentation],
+ [],
+ [],
+ [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
+ DX_REQUIRE_PROG([DX_PERL], perl)],
+ [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
+
+# Dot for graphics:
+DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_DOT], dot)],
+ [DX_ENV_APPEND(HAVE_DOT, YES)
+ DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
+ [DX_ENV_APPEND(HAVE_DOT, NO)])
+
+# Man pages generation:
+DX_ARG_ABLE(man, [generate doxygen manual pages],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_MAN, YES)],
+ [DX_ENV_APPEND(GENERATE_MAN, NO)])
+
+# RTF file generation:
+DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_RTF, YES)],
+ [DX_ENV_APPEND(GENERATE_RTF, NO)])
+
+# XML file generation:
+DX_ARG_ABLE(xml, [generate doxygen XML documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_XML, YES)],
+ [DX_ENV_APPEND(GENERATE_XML, NO)])
+
+# (Compressed) HTML help generation:
+DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_HHC], hhc)],
+ [DX_ENV_APPEND(HHC_PATH, $DX_HHC)
+ DX_ENV_APPEND(GENERATE_HTML, YES)
+ DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
+ [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
+
+# Seperate CHI file generation.
+DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],
+ [DX_CHECK_DEPEND(chm, 1)],
+ [DX_CLEAR_DEPEND(chm, 1)],
+ [],
+ [DX_ENV_APPEND(GENERATE_CHI, YES)],
+ [DX_ENV_APPEND(GENERATE_CHI, NO)])
+
+# Plain HTML pages generation:
+DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
+ [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
+ [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
+ [],
+ [DX_ENV_APPEND(GENERATE_HTML, YES)],
+ [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
+
+# PostScript file generation:
+DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_LATEX], latex)
+ DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+ DX_REQUIRE_PROG([DX_DVIPS], dvips)
+ DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# PDF file generation:
+DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
+ [DX_CHECK_DEPEND(doc, 1)],
+ [DX_CLEAR_DEPEND(doc, 1)],
+ [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
+ DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+ DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# LaTeX generation for PS and/or PDF:
+if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
+ AM_CONDITIONAL(DX_COND_latex, :)
+ DX_ENV_APPEND(GENERATE_LATEX, YES)
+else
+ AM_CONDITIONAL(DX_COND_latex, false)
+ DX_ENV_APPEND(GENERATE_LATEX, NO)
+fi
+
+# Paper size for PS and/or PDF:
+AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
+ [a4wide (default), a4, letter, legal or executive])
+case "$DOXYGEN_PAPER_SIZE" in
+#(
+"")
+ AC_SUBST(DOXYGEN_PAPER_SIZE, "")
+;; #(
+a4wide|a4|letter|legal|executive)
+ DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
+;; #(
+*)
+ AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
+;;
+esac
+
+#For debugging:
+#echo DX_FLAG_doc=$DX_FLAG_doc
+#echo DX_FLAG_dot=$DX_FLAG_dot
+#echo DX_FLAG_man=$DX_FLAG_man
+#echo DX_FLAG_html=$DX_FLAG_html
+#echo DX_FLAG_chm=$DX_FLAG_chm
+#echo DX_FLAG_chi=$DX_FLAG_chi
+#echo DX_FLAG_rtf=$DX_FLAG_rtf
+#echo DX_FLAG_xml=$DX_FLAG_xml
+#echo DX_FLAG_pdf=$DX_FLAG_pdf
+#echo DX_FLAG_ps=$DX_FLAG_ps
+#echo DX_ENV=$DX_ENV
+])
diff --git a/trunk/bitbake-ng/m4/internal/visibility.m4 b/trunk/bitbake-ng/m4/internal/visibility.m4
new file mode 100644
index 000000000..eb2c8f923
--- /dev/null
+++ b/trunk/bitbake-ng/m4/internal/visibility.m4
@@ -0,0 +1,74 @@
+# BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES
+# ----------
+# Check the C++ compiler for support for -fvisibility-inlines-hidden.
+AC_DEFUN([BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES],
+[AC_REQUIRE([AC_PROG_CXX])
+ bb_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="-fvisibility-inlines-hidden $bb_save_CXXFLAGS"
+ AC_CACHE_CHECK([whether the C++ compiler supports -fvisibility-inlines-hidden],
+ [bb_cv_cc_supports_hidden_visibility_inlines], [
+ AC_LANG_PUSH(C++)
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [bb_cv_cc_supports_hidden_visibility_inlines=yes], [bb_cv_cc_supports_hidden_visibility_inlines=no])
+ AC_LANG_POP(C++)
+ ])
+ CXXFLAGS="$bb_save_CXXFLAGS"
+]) # BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES
+
+
+# BB_CXX_HIDDEN_VISIBILITY_INLINES
+# ----------
+# Decide whether or not to use -fvisibility-inlines-hidden for c++ applications.
+AC_DEFUN([BB_CXX_HIDDEN_VISIBILITY_INLINES],
+[AC_REQUIRE([BB_CXX_SUPPORTS_HIDDEN_VISIBILITY_INLINES])
+ AC_MSG_CHECKING([whether to use -fvisibility-inlines-hidden])
+ AC_ARG_WITH([hidden_visibility_inlines],
+ AC_HELP_STRING([--with-hidden_visibility_inlines=VAL],
+ [use -fvisibility-inlines-hidden (default VAL is 'auto')]),
+ [bb_with_hidden_visibility_inlines=$withval], [bb_with_hidden_visibility_inlines=auto])
+
+ if test "x$bb_with_hidden_visibility_inlines" != "xno" && \
+ test "x$bb_cv_cc_supports_hidden_visibility_inlines" != "xno"; then
+ AC_MSG_RESULT([yes])
+ CXXFLAGS="-fvisibility-inlines-hidden $CXXFLAGS"
+ AC_MSG_NOTICE([prepending -fvisibility-inlines-hidden to CXXFLAGS])
+ else
+ AC_MSG_RESULT([no])
+ fi
+]) # BB_CXX_HIDDEN_VISIBILITY_INLINES
+
+
+# BB_CC_SUPPORTS_HIDDEN_VISIBILITY
+# ----------
+# Check the C compiler for support for -fvisibility=hidden.
+AC_DEFUN([BB_CC_SUPPORTS_HIDDEN_VISIBILITY],
+[AC_REQUIRE([AC_PROG_CC])
+ bb_save_CFLAGS="$CFLAGS"
+ CFLAGS="-fvisibility=hidden $bb_save_CFLAGS"
+ AC_CACHE_CHECK([whether the C compiler supports -fvisibility=hidden],
+ [bb_cv_cc_supports_hidden_visibility], [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [bb_cv_cc_supports_hidden_visibility=yes], [bb_cv_cc_supports_hidden_visibility=no])
+ ])
+ CFLAGS="$bb_save_CFLAGS"
+]) # BB_CC_SUPPORTS_HIDDEN_VISIBILITY
+
+
+# BB_CC_HIDDEN_VISIBILITY
+# ----------
+# Decide whether or not to use -fvisibility=hidden.
+AC_DEFUN([BB_CC_HIDDEN_VISIBILITY],
+[AC_REQUIRE([BB_CC_SUPPORTS_HIDDEN_VISIBILITY])
+ AC_MSG_CHECKING([whether to use -fvisibility=hidden])
+ AC_ARG_WITH([hidden_visibility],
+ AC_HELP_STRING([--with-hidden_visibility=VAL],
+ [use -fvisibility=hidden (default VAL is 'auto')]),
+ [bb_with_hidden_visibility=$withval], [bb_with_hidden_visibility=auto])
+
+ if test "x$bb_with_hidden_visibility" != "xno" && \
+ test "x$bb_cv_cc_supports_hidden_visibility" != "xno"; then
+ AC_MSG_RESULT([yes])
+ CFLAGS="-DGCC_HASCLASSVISIBILITY -fvisibility=hidden $CFLAGS"
+ AC_MSG_NOTICE([prepending -DGCC_HASCLASSVISIBILITY -fvisibility=hidden to CFLAGS])
+ else
+ AC_MSG_RESULT([no])
+ fi
+]) # BB_CC_HIDDEN_VISIBILITY
diff --git a/trunk/bitbake-ng/src/Makefile.am b/trunk/bitbake-ng/src/Makefile.am
new file mode 100644
index 000000000..953fa5dbf
--- /dev/null
+++ b/trunk/bitbake-ng/src/Makefile.am
@@ -0,0 +1,12 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ $(BBDLL_EXPORTS)
+
+lib_LTLIBRARIES = libbitbake-0.0.la
+libbitbake_0_0_la_SOURCES = data.c
+libbitbake_0_0_la_CFLAGS = $(GLIB2_CFLAGS)
+libbitbake_0_0_la_LIBADD = $(GLIB2_LIBS)
+libbitbake_0_0_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -export-dynamic
+
+maintainer-clean-local:
+ rm -f $(srcdir)/Makefile.in
diff --git a/trunk/bitbake-ng/src/binreloc.c b/trunk/bitbake-ng/src/binreloc.c
new file mode 100644
index 000000000..a392297bc
--- /dev/null
+++ b/trunk/bitbake-ng/src/binreloc.c
@@ -0,0 +1,436 @@
+/*
+ * BinReloc - a library for creating relocatable executables
+ * Written by: Mike Hearn <mike@theoretic.com>
+ * Hongli Lai <h.lai@chello.nl>
+ * http://autopackage.org/
+ *
+ * This source code is public domain. You can relicense this code
+ * under whatever license you want.
+ *
+ * NOTE: if you're using C++ and are getting "undefined reference
+ * to br_*", try renaming prefix.c to prefix.cpp
+ */
+
+/* WARNING, BEFORE YOU MODIFY PREFIX.C:
+ *
+ * If you make changes to any of the functions in prefix.c, you MUST
+ * change the BR_NAMESPACE macro (in prefix.h).
+ * This way you can avoid symbol table conflicts with other libraries
+ * that also happen to use BinReloc.
+ *
+ * Example:
+ * #define BR_NAMESPACE(funcName) foobar_ ## funcName
+ * --> expands br_locate to foobar_br_locate
+ */
+
+#ifndef _PREFIX_C_
+#define _PREFIX_C_
+
+#ifndef BR_PTHREADS
+ /* Change 1 to 0 if you don't want pthread support */
+ #define BR_PTHREADS 1
+#endif /* BR_PTHREADS */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <limits.h>
+#include <string.h>
+#include "binreloc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#undef NULL
+#define NULL ((void *) 0)
+
+#ifdef __GNUC__
+ #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;}
+#else
+ #define br_return_val_if_fail(expr,val) if (!(expr)) return val
+#endif /* __GNUC__ */
+
+
+#ifdef ENABLE_BINRELOC
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+
+/**
+ * br_locate:
+ * symbol: A symbol that belongs to the app/library you want to locate.
+ * Returns: A newly allocated string containing the full path of the
+ * app/library that func belongs to, or NULL on error. This
+ * string should be freed when not when no longer needed.
+ *
+ * Finds out to which application or library symbol belongs, then locate
+ * the full path of that application or library.
+ * Note that symbol cannot be a pointer to a function. That will not work.
+ *
+ * Example:
+ * --> main.c
+ * #include "prefix.h"
+ * #include "bitbake-ng.h"
+ *
+ * int main (int argc, char *argv[]) {
+ * printf ("Full path of this app: %s\n", br_locate (&argc));
+ * bitbake-ng_start ();
+ * return 0;
+ * }
+ *
+ * --> bitbake-ng.c starts here
+ * #include "prefix.h"
+ *
+ * void bitbake-ng_start () {
+ * --> "" is a symbol that belongs to bitbake-ng (because it's called
+ * --> from bitbake-ng_start()); that's why this works.
+ * printf ("bitbake-ng is located in: %s\n", br_locate (""));
+ * }
+ */
+char *
+br_locate (void *symbol)
+{
+ char line[5000];
+ FILE *f;
+ char *path;
+
+ br_return_val_if_fail (symbol != NULL, NULL);
+
+ f = fopen ("/proc/self/maps", "r");
+ if (!f)
+ return NULL;
+
+ while (!feof (f))
+ {
+ unsigned int start, end;
+
+ if (!fgets (line, sizeof (line), f))
+ continue;
+ if (!strstr (line, " r-xp ") || !strchr (line, '/'))
+ continue;
+
+ sscanf (line, "%x-%x ", &start, &end);
+ if (((unsigned int) symbol) >= start && ((unsigned int) symbol) < end)
+ {
+ char *tmp;
+ size_t len;
+
+ /* Extract the filename; it is always an absolute path */
+ path = strchr (line, '/');
+
+ /* Get rid of the newline */
+ tmp = strrchr (path, '\n');
+ if (tmp) *tmp = 0;
+
+ /* Get rid of "(deleted)" */
+ len = strlen (path);
+ if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0)
+ {
+ tmp = path + len - 10;
+ *tmp = 0;
+ }
+
+ fclose(f);
+ return strdup (path);
+ }
+ }
+
+ fclose (f);
+ return NULL;
+}
+
+
+/**
+ * br_locate_prefix:
+ * symbol: A symbol that belongs to the app/library you want to locate.
+ * Returns: A prefix. This string should be freed when no longer needed.
+ *
+ * Locates the full path of the app/library that symbol belongs to, and return
+ * the prefix of that path, or NULL on error.
+ * Note that symbol cannot be a pointer to a function. That will not work.
+ *
+ * Example:
+ * --> This application is located in /usr/bin/foo
+ * br_locate_prefix (&argc); --> returns: "/usr"
+ */
+char *
+br_locate_prefix (void *symbol)
+{
+ char *path, *prefix;
+
+ br_return_val_if_fail (symbol != NULL, NULL);
+
+ path = br_locate (symbol);
+ if (!path) return NULL;
+
+ prefix = br_extract_prefix (path);
+ free (path);
+ return prefix;
+}
+
+
+/**
+ * br_prepend_prefix:
+ * symbol: A symbol that belongs to the app/library you want to locate.
+ * path: The path that you want to prepend the prefix to.
+ * Returns: The new path, or NULL on error. This string should be freed when no
+ * longer needed.
+ *
+ * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path.
+ * Note that symbol cannot be a pointer to a function. That will not work.
+ *
+ * Example:
+ * --> The application is /usr/bin/foo
+ * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png"
+ */
+char *
+br_prepend_prefix (void *symbol, char *path)
+{
+ char *tmp, *newpath;
+
+ br_return_val_if_fail (symbol != NULL, NULL);
+ br_return_val_if_fail (path != NULL, NULL);
+
+ tmp = br_locate_prefix (symbol);
+ if (!tmp) return NULL;
+
+ if (strcmp (tmp, "/") == 0)
+ newpath = strdup (path);
+ else
+ newpath = br_strcat (tmp, path);
+
+ /* Get rid of compiler warning ("br_prepend_prefix never used") */
+ if (0) br_prepend_prefix (NULL, NULL);
+
+ free (tmp);
+ return newpath;
+}
+
+#endif /* ENABLE_BINRELOC */
+
+
+/* Pthread stuff for thread safetiness */
+#if BR_PTHREADS
+
+static pthread_key_t br_thread_key;
+static pthread_once_t br_thread_key_once = PTHREAD_ONCE_INIT;
+
+
+static void
+br_thread_local_store_fini ()
+{
+ char *specific;
+
+ specific = (char *) pthread_getspecific (br_thread_key);
+ if (specific)
+ {
+ free (specific);
+ pthread_setspecific (br_thread_key, NULL);
+ }
+ pthread_key_delete (br_thread_key);
+ br_thread_key = 0;
+}
+
+
+static void
+br_str_free (void *str)
+{
+ if (str)
+ free (str);
+}
+
+
+static void
+br_thread_local_store_init ()
+{
+ if (pthread_key_create (&br_thread_key, br_str_free) == 0)
+ atexit (br_thread_local_store_fini);
+}
+
+#else /* BR_PTHREADS */
+
+static char *br_last_value = NULL;
+
+static void
+br_free_last_value ()
+{
+ if (br_last_value)
+ free (br_last_value);
+}
+
+#endif /* BR_PTHREADS */
+
+
+/**
+ * br_thread_local_store:
+ * str: A dynamically allocated string.
+ * Returns: str. This return value must not be freed.
+ *
+ * Store str in a thread-local variable and return str. The next
+ * you run this function, that variable is freed too.
+ * This function is created so you don't have to worry about freeing
+ * strings.
+ *
+ * Example:
+ * char *foo;
+ * foo = thread_local_store (strdup ("hello")); --> foo == "hello"
+ * foo = thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed.
+ */
+const char *
+br_thread_local_store (char *str)
+{
+ #if BR_PTHREADS
+ char *specific;
+
+ pthread_once (&br_thread_key_once, br_thread_local_store_init);
+
+ specific = (char *) pthread_getspecific (br_thread_key);
+ br_str_free (specific);
+ pthread_setspecific (br_thread_key, str);
+
+ #else /* BR_PTHREADS */
+ static int initialized = 0;
+
+ if (!initialized)
+ {
+ atexit (br_free_last_value);
+ initialized = 1;
+ }
+
+ if (br_last_value)
+ free (br_last_value);
+ br_last_value = str;
+ #endif /* BR_PTHREADS */
+
+ return (const char *) str;
+}
+
+
+/**
+ * br_strcat:
+ * str1: A string.
+ * str2: Another string.
+ * Returns: A newly-allocated string. This string should be freed when no longer needed.
+ *
+ * Concatenate str1 and str2 to a newly allocated string.
+ */
+char *
+br_strcat (const char *str1, const char *str2)
+{
+ char *result;
+
+ if (!str1) str1 = "";
+ if (!str2) str2 = "";
+
+ result = (char *) calloc (sizeof (char), strlen (str1) + strlen (str2) + 1);
+ result = strcpy (result, str1);
+ result = strcat (result, str2);
+ return result;
+}
+
+
+/* Emulates glibc's strndup() */
+static char *
+br_strndup (char *str, size_t size)
+{
+ char *result = NULL;
+ size_t len;
+
+ br_return_val_if_fail (str != NULL, NULL);
+
+ len = strlen (str);
+ if (!len) return strdup ("");
+
+ result = (char *) calloc (sizeof (char), len + 1);
+ memcpy (result, str, size);
+ return result;
+}
+
+
+/**
+ * br_extract_dir:
+ * path: A path.
+ * Returns: A directory name. This string should be freed when no longer needed.
+ *
+ * Extracts the directory component of path. Similar to g_dirname() or the dirname
+ * commandline application.
+ *
+ * Example:
+ * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local"
+ */
+char *
+br_extract_dir (const char *path)
+{
+ char *end, *result;
+
+ br_return_val_if_fail (path != NULL, NULL);
+
+ end = strrchr (path, '/');
+ if (!end) return strdup (".");
+
+ while (end > path && *end == '/')
+ end--;
+ result = br_strndup ((char *) path, end - path + 1);
+ if (!*result)
+ {
+ free (result);
+ return strdup ("/");
+ } else
+ return result;
+}
+
+
+/**
+ * br_extract_prefix:
+ * path: The full path of an executable or library.
+ * Returns: The prefix, or NULL on error. This string should be freed when no longer needed.
+ *
+ * Extracts the prefix from path. This function assumes that your executable
+ * or library is installed in an LSB-compatible directory structure.
+ *
+ * Example:
+ * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr"
+ * br_extract_prefix ("/usr/local/bitbake-ng.so"); --> Returns "/usr/local"
+ */
+char *
+br_extract_prefix (const char *path)
+{
+ char *end, *tmp, *result;
+
+ br_return_val_if_fail (path != NULL, NULL);
+
+ if (!*path) return strdup ("/");
+ end = strrchr (path, '/');
+ if (!end) return strdup (path);
+
+ tmp = br_strndup ((char *) path, end - path);
+ if (!*tmp)
+ {
+ free (tmp);
+ return strdup ("/");
+ }
+ end = strrchr (tmp, '/');
+ if (!end) return tmp;
+
+ result = br_strndup (tmp, end - tmp);
+ free (tmp);
+
+ if (!*result)
+ {
+ free (result);
+ result = strdup ("/");
+ }
+
+ return result;
+}
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _PREFIX_C */
diff --git a/trunk/bitbake-ng/src/binreloc.h b/trunk/bitbake-ng/src/binreloc.h
new file mode 100644
index 000000000..9c450c60e
--- /dev/null
+++ b/trunk/bitbake-ng/src/binreloc.h
@@ -0,0 +1,121 @@
+/*
+ * BinReloc - a library for creating relocatable executables
+ * Written by: Mike Hearn <mike@theoretic.com>
+ * Hongli Lai <h.lai@chello.nl>
+ * http://autopackage.org/
+ *
+ * This source code is public domain. You can relicense this code
+ * under whatever license you want.
+ *
+ * See http://autopackage.org/docs/binreloc/ for
+ * more information and how to use this.
+ *
+ * NOTE: if you're using C++ and are getting "undefined reference
+ * to br_*", try renaming prefix.c to prefix.cpp
+ */
+
+#ifndef _PREFIX_H_
+#define _PREFIX_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* WARNING, BEFORE YOU MODIFY PREFIX.C:
+ *
+ * If you make changes to any of the functions in prefix.c, you MUST
+ * change the BR_NAMESPACE macro.
+ * This way you can avoid symbol table conflicts with other libraries
+ * that also happen to use BinReloc.
+ *
+ * Example:
+ * #define BR_NAMESPACE(funcName) foobar_ ## funcName
+ * --> expands br_locate to foobar_br_locate
+ */
+#undef BR_NAMESPACE
+#define BR_NAMESPACE(funcName) funcName
+
+
+#ifdef ENABLE_BINRELOC
+
+#define br_thread_local_store BR_NAMESPACE(br_thread_local_store)
+#define br_locate BR_NAMESPACE(br_locate)
+#define br_locate_prefix BR_NAMESPACE(br_locate_prefix)
+#define br_prepend_prefix BR_NAMESPACE(br_prepend_prefix)
+
+#ifndef BR_NO_MACROS
+ /* These are convience macros that replace the ones usually used
+ in Autoconf/Automake projects */
+ #undef SELFPATH
+ #undef PREFIX
+ #undef PREFIXDIR
+ #undef BINDIR
+ #undef SBINDIR
+ #undef DATADIR
+ #undef LIBDIR
+ #undef LIBEXECDIR
+ #undef ETCDIR
+ #undef SYSCONFDIR
+ #undef CONFDIR
+ #undef LOCALEDIR
+
+ #define SELFPATH (br_thread_local_store (br_locate ((void *) "")))
+ #define PREFIX (br_thread_local_store (br_locate_prefix ((void *) "")))
+ #define PREFIXDIR (br_thread_local_store (br_locate_prefix ((void *) "")))
+ #define BINDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/bin")))
+ #define SBINDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/sbin")))
+ #define DATADIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/share")))
+ #define LIBDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/lib")))
+ #define LIBEXECDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/libexec")))
+ #define ETCDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/etc")))
+ #define SYSCONFDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/etc")))
+ #define CONFDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/etc")))
+ #define LOCALEDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/share/locale")))
+#endif /* BR_NO_MACROS */
+
+
+/* The following functions are used internally by BinReloc
+ and shouldn't be used directly in applications. */
+
+const char *br_thread_local_store (char *str);
+char *br_locate (void *symbol);
+char *br_locate_prefix (void *symbol);
+char *br_prepend_prefix (void *symbol, char *path);
+
+
+#endif /* ENABLE_BINRELOC */
+
+
+/* These macros and functions are not guarded by the ENABLE_BINRELOC
+ * macro because they are portable. You can use these functions.
+ */
+
+#define br_strcat BR_NAMESPACE(br_strcat)
+#define br_extract_dir BR_NAMESPACE(br_extract_dir)
+#define br_extract_prefix BR_NAMESPACE(br_extract_prefix)
+
+#ifndef BR_NO_MACROS
+ /* Convenience functions for concatenating paths */
+ #define BR_SELFPATH(suffix) (br_thread_local_store (br_strcat (SELFPATH, suffix)))
+ #define BR_PREFIX(suffix) (br_thread_local_store (br_strcat (PREFIX, suffix)))
+ #define BR_PREFIXDIR(suffix) (br_thread_local_store (br_strcat (BR_PREFIX, suffix)))
+ #define BR_BINDIR(suffix) (br_thread_local_store (br_strcat (BINDIR, suffix)))
+ #define BR_SBINDIR(suffix) (br_thread_local_store (br_strcat (SBINDIR, suffix)))
+ #define BR_DATADIR(suffix) (br_thread_local_store (br_strcat (DATADIR, suffix)))
+ #define BR_LIBDIR(suffix) (br_thread_local_store (br_strcat (LIBDIR, suffix)))
+ #define BR_ETCDIR(suffix) (br_thread_local_store (br_strcat (ETCDIR, suffix)))
+ #define BR_SYSCONFDIR(suffix) (br_thread_local_store (br_strcat (SYSCONFDIR, suffix)))
+ #define BR_CONFDIR(suffix) (br_thread_local_store (br_strcat (CONFDIR, suffix)))
+ #define BR_LOCALEDIR(suffix) (br_thread_local_store (br_strcat (LOCALEDIR, suffix)))
+#endif
+
+char *br_strcat (const char *str1, const char *str2);
+char *br_extract_dir (const char *path);
+char *br_extract_prefix(const char *path);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _PREFIX_H_ */
diff --git a/trunk/bitbake-ng/src/data.c b/trunk/bitbake-ng/src/data.c
new file mode 100644
index 000000000..c563c5b6e
--- /dev/null
+++ b/trunk/bitbake-ng/src/data.c
@@ -0,0 +1,173 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file data.c
+ * @brief Bitbake Metadata Handling Code */
+
+# include <bitbake/common.h>
+# include <bitbake/data.h>
+# include <bitbake/data-private.h>
+# include <glib.h>
+
+static void _bb_data_destroy_element(gpointer data)
+{
+ g_free(data);
+}
+
+static void _bb_data_var_list_free(gpointer data, gpointer user_data)
+{
+ user_data=user_data;
+ g_free(data);
+}
+
+static void _bb_data_destroy_var(gpointer data)
+{
+ struct bb_var *var = data;
+ g_free(var->key);
+ g_free(var->val);
+ g_list_foreach(var->chunks, _bb_data_var_list_free, NULL);
+ g_list_free(var->chunks);
+ g_list_foreach(var->referrers, _bb_data_var_list_free, NULL);
+ g_list_free(var->referrers);
+ g_hash_table_destroy(var->attributes);
+}
+
+gpointer bb_data_new(void)
+{
+ struct bb_data *data;
+
+ data = g_new0(struct bb_data, 1);
+ data->data = g_hash_table_new_full(g_str_hash, g_str_equal, _bb_data_destroy_element, _bb_data_destroy_var);
+
+ return data;
+}
+
+gchar *bb_data_lookup(gconstpointer ptr, gchar *var)
+{
+ const struct bb_data *data = ptr;
+ const struct bb_var *bbvar;
+
+ g_return_val_if_fail(G_LIKELY(data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(data->data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(var != NULL), FALSE);
+
+ bbvar = g_hash_table_lookup(data->data, var);
+ return bbvar->val;
+}
+
+gboolean bb_data_insert(gpointer ptr, gchar *var, gchar *val)
+{
+ struct bb_data *data = ptr;
+ struct bb_var *bbvar;
+ struct bb_var_chunk *main_chunk;
+
+ g_return_val_if_fail(G_LIKELY(data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(data->data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(var != NULL), FALSE);
+
+ bbvar = g_new0(struct bb_var, 1);
+ bbvar->attributes = g_hash_table_new_full(g_str_hash, g_str_equal, _bb_data_destroy_element, _bb_data_destroy_element);
+ bbvar->key = var;
+
+ /* FIXME: rip apart the string into its chunks, and update our referrers
+ * list based on our chunks which are variable references */
+ main_chunk = g_new0(struct bb_var_chunk, 1);
+ main_chunk->data = (void *)val;
+ main_chunk->type = BB_VAR_STR;
+ g_list_append(bbvar->chunks, main_chunk);
+
+ /* FIXME: set our cached value correctly, using the values of the vars
+ * that we reference */
+ bbvar->val = val;
+
+ /* FIXME: need to check the hash table before inserting. if this key
+ * already exists, then we need to update its value and update
+ * the cached value of any variables that reference us */
+ g_hash_table_insert(data->data, var, bbvar);
+
+ return TRUE;
+}
+
+gboolean bb_data_remove(gpointer ptr, gchar *var)
+{
+ struct bb_data *data = ptr;
+
+ g_return_val_if_fail(G_LIKELY(data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(data->data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(var != NULL), FALSE);
+
+ g_hash_table_remove(data->data, var);
+ return TRUE;
+}
+
+gchar *bb_data_lookup_attr(gconstpointer ptr, gchar *var, gchar *attr)
+{
+ const struct bb_data *data = ptr;
+
+ g_return_val_if_fail(G_LIKELY(data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(data->data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(var != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(attr != NULL), FALSE);
+
+ return NULL;
+}
+
+gboolean bb_data_insert_attr(gpointer ptr, gchar *var, gchar *attr, gchar *val)
+{
+ struct bb_data *data = ptr;
+
+ g_return_val_if_fail(G_LIKELY(data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(data->data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(var != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(attr != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(val != NULL), FALSE);
+
+ g_assert_not_reached(); /* unimplemented */
+
+ return FALSE;
+}
+
+gboolean bb_data_remove_attr(gpointer ptr, gchar *var, gchar *attr)
+{
+ struct bb_data *data = ptr;
+
+ g_return_val_if_fail(G_LIKELY(data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(data->data != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(var != NULL), FALSE);
+ g_return_val_if_fail(G_LIKELY(attr != NULL), FALSE);
+
+ g_assert_not_reached(); /* unimplemented */
+
+ return FALSE;
+}
+
+void bb_data_destroy(gpointer ptr)
+{
+ struct bb_data *data = ptr;
+
+ g_return_if_fail(G_LIKELY(data != NULL));
+
+ g_hash_table_destroy(data->data);
+ g_free(ptr);
+}
diff --git a/trunk/bitbake-ng/tests/Makefile.am b/trunk/bitbake-ng/tests/Makefile.am
new file mode 100644
index 000000000..2984f1225
--- /dev/null
+++ b/trunk/bitbake-ng/tests/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ $(BBDLL_EXPORTS)
+AM_LDFLAGS = -L$(top_srcdir)/src
+
+.PHONY: test
+if BB_TESTS
+noinst_PROGRAMS = check_bitbake_data
+check_bitbake_data_SOURCES = check_bitbake_data.c
+check_bitbake_data_CFLAGS = $(GLIB2_CFLAGS) $(CHECK_CFLAGS)
+check_bitbake_data_LDADD = $(GLIB2_LIBS) $(CHECK_LIBS) -lbitbake-0.0
+
+test:
+ @./check_bitbake_data
+else
+test:
+endif
+
+maintainer-clean-local:
+ rm -f $(srcdir)/Makefile.in
diff --git a/trunk/bitbake-ng/tests/check_bitbake_data.c b/trunk/bitbake-ng/tests/check_bitbake_data.c
new file mode 100644
index 000000000..016dfb81d
--- /dev/null
+++ b/trunk/bitbake-ng/tests/check_bitbake_data.c
@@ -0,0 +1,125 @@
+/* ex:ts=4:sw=4:sts=4:et
+ * -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright (C) 2004, 2005 Chris Larson <kergoth@handhelds.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file check_bitbake_data.c
+ * @brief First group of metadata tests */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <check.h>
+#include <bitbake.h>
+
+/**
+ * Test the creation and destruction of a struct bb_data
+ * using the bb_data_new() and bb_data_destroy() functions.
+ */
+
+START_TEST (test_data_create_destroy)
+{
+ gpointer data;
+
+ data = bb_data_new();
+ if (data == NULL)
+ fail("Metadata store allocation returned a NULL pointer");
+ bb_data_destroy(data);
+}
+END_TEST
+
+START_TEST (test_data_var_insert)
+{
+ gpointer data;
+ gchar *var, *val;
+
+ data = bb_data_new();
+ var = g_strdup("CC");
+ val = g_strdup("gcc");
+
+ bb_data_insert(data, var, val);
+}
+END_TEST
+
+START_TEST (test_data_var_lookup)
+{
+ gpointer data;
+ gchar *var, *val;
+
+ data = bb_data_new();
+
+ var = g_strdup("CC");
+ val = g_strdup("gcc");
+ bb_data_insert(data, var, val);
+
+ val = bb_data_lookup(data, "CC");
+ if (strcmp(val, "gcc") != 0)
+ fail("CC does not have the correct value");
+
+ bb_data_destroy(data);
+}
+END_TEST
+
+START_TEST (test_data_var_remove)
+{
+ gpointer data;
+ gchar *var, *val;
+
+ data = bb_data_new();
+
+ var = g_strdup("CC");
+ val = g_strdup("gcc");
+ bb_data_insert(data, var, val);
+
+ bb_data_remove(data, var);
+
+ bb_data_destroy(data);
+}
+END_TEST
+
+Suite *bitbake_data_suite(void)
+{
+ Suite *s = suite_create("Bitbake Data");
+ TCase *tc_core = tcase_create("Core");
+ TCase *tc_var = tcase_create("Variable");
+
+ suite_add_tcase (s, tc_core);
+ suite_add_tcase (s, tc_var);
+
+ tcase_add_test(tc_core, test_data_create_destroy);
+
+ tcase_add_test(tc_var, test_data_var_insert);
+ tcase_add_test(tc_var, test_data_var_lookup);
+ tcase_add_test(tc_var, test_data_var_remove);
+ return s;
+}
+
+int main(void)
+{
+ int nf;
+ Suite *s = bitbake_data_suite();
+ SRunner *sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ nf = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/trunk/bitbake/AUTHORS b/trunk/bitbake/AUTHORS
new file mode 100644
index 000000000..4129e4c52
--- /dev/null
+++ b/trunk/bitbake/AUTHORS
@@ -0,0 +1,5 @@
+Holger Freyther <zecke@handhelds.org>
+Chris Larson <kergoth@handhelds.org>
+Mickey Lauer <mickey@Vanille.de>
+Holger Schurig <holgerschurig@gmx.de>
+Phil Blundell <pb@handhelds.org>
diff --git a/trunk/bitbake/ChangeLog b/trunk/bitbake/ChangeLog
new file mode 100644
index 000000000..921be2321
--- /dev/null
+++ b/trunk/bitbake/ChangeLog
@@ -0,0 +1,26 @@
+Changes in bitbake 1.3.0:
+ - add bitbake interactive shell (bitbake -i)
+ - refactor bitbake utility in OO style
+ - kill default arguments in methods in the bb.data module
+ - kill default arguments in methods in the bb.fetch module
+ - the http/https/ftp fetcher will fail if the to be
+ downloaded file was not found in DL_DIR (this is needed
+ to avoid unpacking the sourceforge mirror page)
+ - Switch to a cow like data instance for persistent and non
+ persisting mode (called data_smart.py)
+ - Changed the callback of bb.make.collect_bbfiles to carry
+ additional parameters
+ - Drastically reduced the amount of needed RAM by not holding
+ each data instance in memory when using a cache/persistent
+ storage
+
+Changes in bitbake 1.2.1:
+ The 1.2.1 release is meant as a intermediate release to lay the
+ground for more radical changes. The most notable changes are:
+
+ -Do not hardcode {}, use bb.data.init() instead if you want to
+get a instance of a data class
+ -bb.data.init() is a factory and the old bb.data methods are delegates
+ -Do not use deepcopy use bb.data.createCopy() instead.
+ -Removed default arguments in bb.fetch
+
diff --git a/trunk/bitbake/MANIFEST b/trunk/bitbake/MANIFEST
new file mode 100644
index 000000000..cc4014ab5
--- /dev/null
+++ b/trunk/bitbake/MANIFEST
@@ -0,0 +1,27 @@
+AUTHORS
+ChangeLog
+MANIFEST
+setup.py
+bin/bbimage
+bin/bitbake
+bin/bbread
+lib/bb/__init__.py
+lib/bb/build.py
+lib/bb/data.py
+lib/bb/data_smart.py
+lib/bb/event.py
+lib/bb/fetch.py
+lib/bb/make.py
+lib/bb/manifest.py
+lib/bb/parse/BBHandler.py
+lib/bb/parse/ConfHandler.py
+lib/bb/parse/__init__.py
+lib/bb/shell.py
+doc/COPYING.GPL
+doc/COPYING.MIT
+doc/manual/html.css
+doc/manual/Makefile
+doc/manual/usermanual.xml
+contrib/bbdev.sh
+conf/bitbake.conf
+classes/base.bbclass
diff --git a/trunk/bitbake/TODO b/trunk/bitbake/TODO
new file mode 100644
index 000000000..511fae4a2
--- /dev/null
+++ b/trunk/bitbake/TODO
@@ -0,0 +1,18 @@
+On popular request by popular people a list of tasks to-do:
+
+ -Kill insecure usage of os.system either by properly escaping
+ the strings or a faster replacement not involving /bin/sh
+ -Introduce a -p option to automatically hotshot/profile the
+ run
+ -Cache dependencies separately and invalidate them when any file
+ changed.
+ -...
+
+
+DONE:
+· -On generating the inter package deps do not parse each file multiply
+· times.
+ -We build the lists while parsing the data now
+· (WAS: Do not generate the world dependency tree, only when someone
+· requests it.
+
diff --git a/trunk/bitbake/bin/bbimage b/trunk/bitbake/bin/bbimage
new file mode 100755
index 000000000..df6caa28e
--- /dev/null
+++ b/trunk/bitbake/bin/bbimage
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# Copyright (C) 2003 Chris Larson
+#
+# This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+
+import sys, os
+sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+import bb
+from bb import *
+
+__version__ = 1.0
+type = "jffs2"
+cfg_bb = data.init()
+cfg_oespawn = data.init()
+
+
+def usage():
+ print "Usage: bbimage [options ...]"
+ print "Creates an image for a target device from a root filesystem,"
+ print "obeying configuration parameters from the BitBake"
+ print "configuration files, thereby easing handling of deviceisms."
+ print ""
+ print " %s\t\t%s" % ("-r [arg], --root [arg]", "root directory (default=${IMAGE_ROOTFS})")
+ print " %s\t\t%s" % ("-t [arg], --type [arg]", "image type (jffs2[default], cramfs)")
+ print " %s\t\t%s" % ("-n [arg], --name [arg]", "image name (override IMAGE_NAME variable)")
+ print " %s\t\t%s" % ("-v, --version", "output version information and exit")
+ sys.exit(0)
+
+def version():
+ print "BitBake Build Tool Core version %s" % bb.__version__
+ print "BBImage version %s" % __version__
+
+def emit_bb(d, base_d = {}):
+ for v in d.keys():
+ if d[v] != base_d[v]:
+ data.emit_var(v, d)
+
+def getopthash(l):
+ h = {}
+ for (opt, val) in l:
+ h[opt] = val
+ return h
+
+import getopt
+try:
+ (opts, args) = getopt.getopt(sys.argv[1:], 'vr:t:e:n:', [ 'version', 'root=', 'type=', 'bbfile=', 'name=' ])
+except getopt.GetoptError:
+ usage()
+
+# handle opts
+opthash = getopthash(opts)
+
+if '--version' in opthash or '-v' in opthash:
+ version()
+ sys.exit(0)
+
+try:
+ cfg_bb = parse.handle(os.path.join('conf', 'bitbake.conf'), cfg_bb)
+except IOError:
+ fatal("Unable to open bitbake.conf")
+
+# sanity check
+if cfg_bb is None:
+ fatal("Unable to open/parse %s" % os.path.join('conf', 'bitbake.conf'))
+ usage(1)
+
+rootfs = None
+extra_files = []
+
+if '--root' in opthash:
+ rootfs = opthash['--root']
+if '-r' in opthash:
+ rootfs = opthash['-r']
+
+if '--type' in opthash:
+ type = opthash['--type']
+if '-t' in opthash:
+ type = opthash['-t']
+
+if '--bbfile' in opthash:
+ extra_files.append(opthash['--bbfile'])
+if '-e' in opthash:
+ extra_files.append(opthash['-e'])
+
+for f in extra_files:
+ try:
+ cfg_bb = parse.handle(f, cfg_bb)
+ except IOError:
+ print "unable to open %s" % f
+
+if not rootfs:
+ rootfs = data.getVar('IMAGE_ROOTFS', cfg_bb, 1)
+
+if not rootfs:
+ bb.fatal("IMAGE_ROOTFS not defined")
+
+data.setVar('IMAGE_ROOTFS', rootfs, cfg_bb)
+
+from copy import copy, deepcopy
+localdata = data.createCopy(cfg_bb)
+
+overrides = data.getVar('OVERRIDES', localdata)
+if not overrides:
+ bb.fatal("OVERRIDES not defined.")
+data.setVar('OVERRIDES', '%s:%s' % (overrides, type), localdata)
+data.update_data(localdata)
+data.setVar('OVERRIDES', overrides, localdata)
+
+if '-n' in opthash:
+ data.setVar('IMAGE_NAME', opthash['-n'], localdata)
+if '--name' in opthash:
+ data.setVar('IMAGE_NAME', opthash['--name'], localdata)
+
+topdir = data.getVar('TOPDIR', localdata, 1) or os.getcwd()
+
+cmd = data.getVar('IMAGE_CMD', localdata, 1)
+if not cmd:
+ bb.fatal("IMAGE_CMD not defined")
+
+outdir = data.getVar('DEPLOY_DIR_IMAGE', localdata, 1)
+if not outdir:
+ bb.fatal('DEPLOY_DIR_IMAGE not defined')
+mkdirhier(outdir)
+
+#depends = data.getVar('IMAGE_DEPENDS', localdata, 1) or ""
+#if depends:
+# bb.note("Spawning bbmake to satisfy dependencies: %s" % depends)
+# ret = os.system('bbmake %s' % depends)
+# if ret != 0:
+# bb.error("executing bbmake to satisfy dependencies")
+
+bb.note("Executing %s" % cmd)
+data.setVar('image_cmd', cmd, localdata)
+data.setVarFlag('image_cmd', 'func', 1, localdata)
+try:
+ bb.build.exec_func('image_cmd', localdata)
+except bb.build.FuncFailed:
+ sys.exit(1)
+#ret = os.system(cmd)
+#sys.exit(ret)
diff --git a/trunk/bitbake/bin/bbread b/trunk/bitbake/bin/bbread
new file mode 100755
index 000000000..83b262e6f
--- /dev/null
+++ b/trunk/bitbake/bin/bbread
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# Copyright (C) 2003, 2004 Chris Larson
+#
+# This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+
+import sys, copy, os
+sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+import bb, bb.parse, bb.build, bb.make
+
+d = bb.data.init()
+try:
+ bb.make.cfg = bb.parse.handle(os.path.join('conf', 'bitbake.conf'), d)
+except IOError, e:
+ bb.fatal("Unable to read conf/bitbake.conf: %s" % e)
+
+if len(sys.argv) == 2:
+ bbfile = sys.argv[1]
+ try:
+ d, fromCache = bb.make.load_bbfile(bbfile)
+ except IOError, e:
+ bb.fatal("Unable to read %s: %s" % (bbfile, e))
+ except Exception, e:
+ bb.fatal("%s" % e)
+
+# emit variables and shell functions
+try:
+ bb.data.update_data(d)
+ bb.data.emit_env(sys.__stdout__, d, True)
+except bb.build.FuncFailed:
+ pass
+except Exception, e:
+ bb.fatal("%s" % e)
+# emit the metadata which isnt valid shell
+for e in d.keys():
+ if bb.data.getVarFlag(e, 'python', d):
+ sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, bb.data.getVar(e, d, 1)))
diff --git a/trunk/bitbake/bin/bitbake b/trunk/bitbake/bin/bitbake
new file mode 100755
index 000000000..98ff708da
--- /dev/null
+++ b/trunk/bitbake/bin/bitbake
@@ -0,0 +1,716 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# Copyright (C) 2003, 2004 Chris Larson
+# Copyright (C) 2003, 2004 Phil Blundell
+# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# Copyright (C) 2005 ROAD GmbH
+#
+# This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+
+import sys, os, getopt, glob, copy, os.path, re
+sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+import bb
+from bb import make
+from sets import Set
+import itertools, optparse
+
+parsespin = itertools.cycle( r'|/-\\' )
+bbdebug = 0
+
+__version__ = "1.3.1"
+
+#============================================================================#
+# BBParsingStatus
+#============================================================================#
+class BBParsingStatus:
+ """
+ The initial idea for this status class is to use the data when it is
+ already loaded instead of loading it from various place over and over
+ again.
+ """
+
+ def __init__(self):
+ self.cache_dirty = False
+ self.providers = {}
+ self.bbfile_priority = {}
+ self.bbfile_config_priorities = []
+ self.ignored_depedencies = None
+ self.possible_world = []
+ self.world_target = Set()
+ self.pkg_pn = {}
+ self.pkg_fn = {}
+ self.pkg_pvpr = {}
+ self.pkg_dp = {}
+ self.pn_provides = {}
+ self.all_depends = Set()
+
+ def handle_bb_data(self, file_name, bb_data, cached):
+ """
+ We will fill the dictionaries with the stuff we
+ need for building the tree more fast
+ """
+ if bb_data == None:
+ return
+
+ if not cached:
+ self.cache_dirty = True
+
+ pn = bb.data.getVar('PN', bb_data, True)
+ pv = bb.data.getVar('PV', bb_data, True)
+ pr = bb.data.getVar('PR', bb_data, True)
+ dp = int(bb.data.getVar('DEFAULT_PREFERENCE', bb_data, True) or "0")
+ provides = Set([pn] + (bb.data.getVar("PROVIDES", bb_data, 1) or "").split())
+ depends = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
+
+
+ # build PackageName to FileName lookup table
+ if pn not in self.pkg_pn:
+ self.pkg_pn[pn] = []
+ self.pkg_pn[pn].append(file_name)
+
+ # build FileName to PackageName lookup table
+ self.pkg_fn[file_name] = pn
+ self.pkg_pvpr[file_name] = (pv,pr)
+ self.pkg_dp[file_name] = dp
+
+ # Build forward and reverse provider hashes
+ # Forward: virtual -> [filenames]
+ # Reverse: PN -> [virtuals]
+ if pn not in self.pn_provides:
+ self.pn_provides[pn] = Set()
+ self.pn_provides[pn] |= provides
+
+ for provide in provides:
+ if provide not in self.providers:
+ self.providers[provide] = []
+ self.providers[provide].append(file_name)
+
+ for dep in depends:
+ self.all_depends.add(dep)
+
+ # Collect files we may need for possible world-dep
+ # calculations
+ if not bb.data.getVar('BROKEN', bb_data, True) and not bb.data.getVar('EXCLUDE_FROM_WORLD', bb_data, True):
+ self.possible_world.append(file_name)
+
+
+#============================================================================#
+# BBStatistics
+#============================================================================#
+class BBStatistics:
+ """
+ Manage build statistics for one run
+ """
+ def __init__(self ):
+ self.attempt = 0
+ self.success = 0
+ self.fail = 0
+ self.deps = 0
+
+ def show( self ):
+ print "Build statistics:"
+ print " Attempted builds: %d" % self.attempt
+ if self.fail:
+ print " Failed builds: %d" % self.fail
+ if self.deps:
+ print " Dependencies not satisfied: %d" % self.deps
+ if self.fail or self.deps: return 1
+ else: return 0
+
+
+#============================================================================#
+# BBCooker
+#============================================================================#
+class BBCooker:
+ """
+ Manages one bitbake build run
+ """
+
+ ParsingStatus = BBParsingStatus # make it visible from the shell
+ Statistics = BBStatistics # make it visible from the shell
+
+ def __init__( self ):
+ self.build_cache_fail = []
+ self.build_cache = []
+ self.building_list = []
+ self.build_path = []
+ self.consider_msgs_cache = []
+ self.preferred = {}
+ self.stats = BBStatistics()
+ self.status = None
+
+ def tryBuildPackage( self, fn, item, the_data ):
+ """Build one package"""
+ bb.event.fire(bb.event.PkgStarted(item, the_data))
+ try:
+ self.stats.attempt += 1
+ if make.options.force:
+ bb.data.setVarFlag('do_%s' % make.options.cmd, 'force', 1, the_data)
+ if not make.options.dry_run:
+ bb.build.exec_task('do_%s' % make.options.cmd, the_data)
+ bb.event.fire(bb.event.PkgSucceeded(item, the_data))
+ self.build_cache.append(fn)
+ return True
+ except bb.build.FuncFailed:
+ self.stats.fail += 1
+ bb.error("task stack execution failed")
+ bb.event.fire(bb.event.PkgFailed(item, the_data))
+ self.build_cache_fail.append(fn)
+ raise
+ except bb.build.EventException, e:
+ self.stats.fail += 1
+ event = e.args[1]
+ bb.error("%s event exception, aborting" % bb.event.getName(event))
+ bb.event.fire(bb.event.PkgFailed(item, the_data))
+ self.build_cache_fail.append(fn)
+ raise
+
+ def tryBuild( self, fn, virtual ):
+ """Build a provider and its dependencies"""
+ if fn in self.building_list:
+ bb.error("%s depends on itself (eventually)" % fn)
+ bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
+ return False
+
+ the_data = make.pkgdata[fn]
+ item = self.status.pkg_fn[fn]
+
+ self.building_list.append(fn)
+
+ pathstr = "%s (%s)" % (item, virtual)
+ self.build_path.append(pathstr)
+
+ depends_list = (bb.data.getVar('DEPENDS', the_data, 1) or "").split()
+ if make.options.verbose:
+ bb.note("current path: %s" % (" -> ".join(self.build_path)))
+ bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
+
+ try:
+ failed = False
+
+ depcmd = make.options.cmd
+ bbdepcmd = bb.data.getVarFlag('do_%s' % make.options.cmd, 'bbdepcmd', the_data)
+ if bbdepcmd is not None:
+ if bbdepcmd == "":
+ depcmd = None
+ else:
+ depcmd = bbdepcmd
+
+ if depcmd:
+ oldcmd = make.options.cmd
+ make.options.cmd = depcmd
+
+ for dependency in depends_list:
+ if dependency in self.status.ignored_dependencies:
+ continue
+ if not depcmd:
+ continue
+ if self.buildProvider( dependency ) == 0:
+ bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
+ failed = True
+ if make.options.abort:
+ break
+
+ if depcmd:
+ make.options.cmd = oldcmd
+
+ if failed:
+ self.stats.deps += 1
+ return False
+
+ if bb.build.stamp_is_current('do_%s' % make.options.cmd, the_data):
+ self.build_cache.append(fn)
+ return True
+
+ return self.tryBuildPackage( fn, item, the_data )
+
+ finally:
+ self.building_list.remove(fn)
+ self.build_path.remove(pathstr)
+
+ def findBestProvider( self, pn, pkg_pn = None):
+ """
+ If there is a PREFERRED_VERSION, find the highest-priority bbfile
+ providing that version. If not, find the latest version provided by
+ an bbfile in the highest-priority set.
+ """
+ if not pkg_pn:
+ pkg_pn = self.status.pkg_pn
+
+ files = pkg_pn[pn]
+ priorities = {}
+ for f in files:
+ priority = self.status.bbfile_priority[f]
+ if priority not in priorities:
+ priorities[priority] = []
+ priorities[priority].append(f)
+ p_list = priorities.keys()
+ p_list.sort(lambda a, b: a - b)
+ tmp_pn = []
+ for p in p_list:
+ tmp_pn = priorities[p] + tmp_pn
+ pkg_pn[pn] = tmp_pn
+
+ preferred_file = None
+
+ preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, make.cfg, 1)
+ if preferred_v:
+ m = re.match('(.*)_(.*)', preferred_v)
+ if m:
+ preferred_v = m.group(1)
+ preferred_r = m.group(2)
+ else:
+ preferred_r = None
+
+ for f in pkg_pn[pn]:
+ pv,pr = self.status.pkg_pvpr[f]
+ if preferred_v == pv and (preferred_r == pr or preferred_r == None):
+ preferred_file = f
+ preferred_ver = (pv, pr)
+ break
+ if preferred_r:
+ pv_str = '%s-%s' % (preferred_v, preferred_r)
+ else:
+ pv_str = preferred_v
+ if preferred_file is None:
+ bb.note("preferred version %s of %s not available" % (pv_str, pn))
+ else:
+ bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
+
+ # get highest priority file set
+ files = pkg_pn[pn]
+ latest = None
+ latest_p = 0
+ latest_f = None
+ for file_name in files:
+ pv,pr = self.status.pkg_pvpr[file_name]
+ dp = self.status.pkg_dp[file_name]
+
+ if (latest is None) or ((latest_p == dp) and (make.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
+ latest = (pv, pr)
+ latest_f = file_name
+ latest_p = dp
+ if preferred_file is None:
+ preferred_file = latest_f
+ preferred_ver = latest
+
+ return (latest,latest_f,preferred_ver, preferred_file)
+
+ def showVersions( self ):
+ pkg_pn = self.status.pkg_pn
+ preferred_versions = {}
+ latest_versions = {}
+
+ # Sort by priority
+ for pn in pkg_pn.keys():
+ (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
+ preferred_versions[pn] = (pref_ver, pref_file)
+ latest_versions[pn] = (last_ver, last_file)
+
+ pkg_list = pkg_pn.keys()
+ pkg_list.sort()
+
+ for p in pkg_list:
+ pref = preferred_versions[p]
+ latest = latest_versions[p]
+
+ if pref != latest:
+ prefstr = pref[0][0] + "-" + pref[0][1]
+ else:
+ prefstr = ""
+
+ print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
+ prefstr)
+
+ def buildProvider( self, item ):
+ fn = None
+
+ discriminated = False
+
+ if item not in self.status.providers:
+ bb.error("Nothing provides %s" % item)
+ return 0
+
+ all_p = self.status.providers[item]
+
+ for p in all_p:
+ if p in self.build_cache:
+ bb.debug(1, "already built %s in this run\n" % p)
+ return 1
+
+ eligible = []
+ preferred_versions = {}
+
+ # Collate providers by PN
+ pkg_pn = {}
+ for p in all_p:
+ pn = self.status.pkg_fn[p]
+ if pn not in pkg_pn:
+ pkg_pn[pn] = []
+ pkg_pn[pn].append(p)
+
+ bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
+
+ for pn in pkg_pn.keys():
+ preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
+ eligible.append(preferred_versions[pn][1])
+
+ for p in eligible:
+ if p in self.build_cache_fail:
+ bb.debug(1, "rejecting already-failed %s" % p)
+ eligible.remove(p)
+
+ if len(eligible) == 0:
+ bb.error("no eligible providers for %s" % item)
+ return 0
+
+ # look to see if one of them is already staged, or marked as preferred.
+ # if so, bump it to the head of the queue
+ for p in all_p:
+ the_data = make.pkgdata[p]
+ pn = bb.data.getVar('PN', the_data, 1)
+ pv = bb.data.getVar('PV', the_data, 1)
+ pr = bb.data.getVar('PR', the_data, 1)
+ tmpdir = bb.data.getVar('TMPDIR', the_data, 1)
+ stamp = '%s/stamps/%s-%s-%s.do_populate_staging' % (tmpdir, pn, pv, pr)
+ if os.path.exists(stamp):
+ (newvers, fn) = preferred_versions[pn]
+ if not fn in eligible:
+ # package was made ineligible by already-failed check
+ continue
+ oldver = "%s-%s" % (pv, pr)
+ newver = '-'.join(newvers)
+ if (newver != oldver):
+ extra_chat = "; upgrading from %s to %s" % (oldver, newver)
+ else:
+ extra_chat = ""
+ if make.options.verbose:
+ bb.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
+ eligible.remove(fn)
+ eligible = [fn] + eligible
+ discriminated = True
+ break
+
+ prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, make.cfg, 1)
+ if prefervar:
+ self.preferred[item] = prefervar
+
+ if item in self.preferred:
+ for p in eligible:
+ pn = self.status.pkg_fn[p]
+ if self.preferred[item] == pn:
+ if make.options.verbose:
+ bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
+ eligible.remove(p)
+ eligible = [p] + eligible
+ discriminated = True
+ break
+
+ if len(eligible) > 1 and discriminated == False:
+ if item not in self.consider_msgs_cache:
+ providers_list = []
+ for fn in eligible:
+ providers_list.append(self.status.pkg_fn[fn])
+ bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
+ bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
+ self.consider_msgs_cache.append(item)
+
+
+ # run through the list until we find one that we can build
+ for fn in eligible:
+ bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
+ if self.tryBuild(fn, item):
+ return 1
+
+ bb.note("no buildable providers for %s" % item)
+ return 0
+
+ def buildDepgraph( self ):
+ all_depends = self.status.all_depends
+ pn_provides = self.status.pn_provides
+
+ def calc_bbfile_priority(filename):
+ for (regex, pri) in self.status.bbfile_config_priorities:
+ if regex.match(filename):
+ return pri
+ return 0
+
+ # Handle PREFERRED_PROVIDERS
+ for p in (bb.data.getVar('PREFERRED_PROVIDERS', make.cfg, 1) or "").split():
+ (providee, provider) = p.split(':')
+ if providee in self.preferred and self.preferred[providee] != provider:
+ bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
+ self.preferred[providee] = provider
+
+ # Calculate priorities for each file
+ for p in make.pkgdata.keys():
+ self.status.bbfile_priority[p] = calc_bbfile_priority(p)
+
+ # Build package list for "bitbake world"
+ bb.debug(1, "collating packages for \"world\"")
+ for f in self.status.possible_world:
+ terminal = True
+ pn = self.status.pkg_fn[f]
+
+ for p in pn_provides[pn]:
+ if p.startswith('virtual/'):
+ bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
+ terminal = False
+ break
+ for pf in self.status.providers[p]:
+ if self.status.pkg_fn[pf] != pn:
+ bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
+ terminal = False
+ break
+ if terminal:
+ self.status.world_target.add(pn)
+
+ # drop reference count now
+ self.status.possible_world = None
+ self.status.all_depends = None
+
+ def myProgressCallback( self, x, y, f, file_data, from_cache ):
+ # feed the status with new input
+ self.status.handle_bb_data(f, file_data, from_cache)
+
+ if bbdebug > 0:
+ return
+ if os.isatty(sys.stdout.fileno()):
+ sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
+ sys.stdout.flush()
+ else:
+ if x == 1:
+ sys.stdout.write("Parsing .bb files, please wait...")
+ sys.stdout.flush()
+ if x == y:
+ sys.stdout.write("done.")
+ sys.stdout.flush()
+
+ def interactiveMode( self ):
+ """Drop off into a shell"""
+ try:
+ from bb import shell
+ except ImportError, details:
+ bb.fatal("Sorry, shell not available (%s)" % details )
+ else:
+ shell.start( self )
+ sys.exit( 0 )
+
+ def parseConfigurationFile( self, afile ):
+ try:
+ make.cfg = bb.parse.handle( afile, make.cfg )
+ except IOError:
+ bb.fatal( "Unable to open %s" % afile )
+ except bb.parse.ParseError, details:
+ bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
+
+ def handleCollections( self, collections ):
+ """Handle collections"""
+ if collections:
+ collection_list = collections.split()
+ for c in collection_list:
+ regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, make.cfg, 1)
+ if regex == None:
+ bb.error("BBFILE_PATTERN_%s not defined" % c)
+ continue
+ priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, make.cfg, 1)
+ if priority == None:
+ bb.error("BBFILE_PRIORITY_%s not defined" % c)
+ continue
+ try:
+ cre = re.compile(regex)
+ except re.error:
+ bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
+ continue
+ try:
+ pri = int(priority)
+ self.status.bbfile_config_priorities.append((cre, pri))
+ except ValueError:
+ bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
+
+
+ def cook( self, args ):
+ if not make.options.cmd:
+ make.options.cmd = "build"
+
+ if make.options.debug:
+ bb.debug_level = make.options.debug
+
+ make.cfg = bb.data.init()
+
+ for f in make.options.file:
+ self.parseConfigurationFile( f )
+
+ self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
+
+ if not bb.data.getVar("BUILDNAME", make.cfg):
+ bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), make.cfg)
+
+ buildname = bb.data.getVar("BUILDNAME", make.cfg)
+
+ if make.options.interactive:
+ self.interactiveMode()
+
+ if make.options.buildfile is not None:
+ bf = os.path.abspath( make.options.buildfile )
+ try:
+ bbfile_data = bb.parse.handle(bf, make.cfg)
+ except IOError:
+ bb.fatal("Unable to open %s" % bf)
+
+ item = bb.data.getVar('PN', bbfile_data, 1)
+ try:
+ self.tryBuildPackage( bf, item, bbfile_data )
+ except bb.build.EventException:
+ bb.error( "Build of '%s' failed" % item )
+
+ sys.exit( self.stats.show() )
+
+ # initialise the parsing status now we know we will need deps
+ self.status = BBParsingStatus()
+
+ ignore = bb.data.getVar("ASSUME_PROVIDED", make.cfg, 1) or ""
+ self.status.ignored_dependencies = Set( ignore.split() )
+
+ self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", make.cfg, 1) )
+
+ pkgs_to_build = None
+ if args:
+ if not pkgs_to_build:
+ pkgs_to_build = []
+ pkgs_to_build.extend(args)
+ if not pkgs_to_build:
+ bbpkgs = bb.data.getVar('BBPKGS', make.cfg, 1)
+ if bbpkgs:
+ pkgs_to_build = bbpkgs.split()
+ if not pkgs_to_build and not make.options.show_versions and not make.options.interactive:
+ print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
+ print "for usage information."
+ sys.exit(0)
+
+ # Import Psyco if available and not disabled
+ if not make.options.disable_psyco:
+ try:
+ import psyco
+ except ImportError:
+ if bbdebug == 0:
+ bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
+ else:
+ psyco.bind( make.collect_bbfiles )
+ else:
+ bb.note("You have disabled Psyco. This decreases performance.")
+
+ try:
+ bb.debug(1, "collecting .bb files")
+ make.collect_bbfiles( self.myProgressCallback )
+ bb.debug(1, "parsing complete")
+ if bbdebug == 0:
+ print
+ if make.options.parse_only:
+ print "Requested parsing .bb files only. Exiting."
+ return
+
+ bb.data.update_data( make.cfg )
+ self.buildDepgraph()
+
+ if make.options.show_versions:
+ self.showVersions()
+ sys.exit( 0 )
+ if 'world' in pkgs_to_build:
+ pkgs_to_build.remove('world')
+ for t in self.status.world_target:
+ pkgs_to_build.append(t)
+
+ bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, make.cfg))
+
+ for k in pkgs_to_build:
+ failed = False
+ try:
+ if self.buildProvider( k ) == 0:
+ # already diagnosed
+ failed = True
+ except bb.build.EventException:
+ bb.error("Build of " + k + " failed")
+ failed = True
+
+ if failed:
+ if make.options.abort:
+ sys.exit(1)
+
+ bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, make.cfg))
+
+ sys.exit( self.stats.show() )
+
+ except KeyboardInterrupt:
+ print "\nNOTE: KeyboardInterrupt - Build not completed."
+ sys.exit(1)
+
+#============================================================================#
+# main
+#============================================================================#
+
+if __name__ == "__main__":
+
+ parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
+ usage = """%prog [options] [package ...]
+
+Executes the specified task (default is 'build') for a given set of BitBake files.
+It expects that BBFILES is defined, which is a space seperated list of files to
+be executed. BBFILES does support wildcards.
+Default BBFILES are the .bb files in the current directory.""" )
+
+ parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
+ action = "store", dest = "buildfile", default = None )
+
+ parser.add_option( "-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
+ action = "store_false", dest = "abort", default = True )
+
+ parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
+ action = "store_true", dest = "force", default = False )
+
+ parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
+ action = "store_true", dest = "interactive", default = False )
+
+ parser.add_option( "-c", "--cmd", help = "Specify task to execute",
+ action = "store", dest = "cmd", default = "build" )
+
+ parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
+ action = "append", dest = "file", default = [] )
+
+ parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
+ action = "store_true", dest = "verbose", default = False )
+
+ parser.add_option( "-D", "--debug", help = "Increase the debug level",
+ action = "count", dest="debug", default = 0)
+
+ parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
+ action = "store_true", dest = "dry_run", default = False )
+
+ parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
+ action = "store_true", dest = "parse_only", default = False )
+
+ parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
+ action = "store_true", dest = "disable_psyco", default = False )
+
+ parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
+ action = "store_true", dest = "show_versions", default = False )
+
+ options, args = parser.parse_args( sys.argv )
+
+ make.options = options
+ cooker = BBCooker()
+ cooker.cook( args[1:] )
diff --git a/trunk/bitbake/bin/bitdoc b/trunk/bitbake/bin/bitdoc
new file mode 100755
index 000000000..fd9934f7a
--- /dev/null
+++ b/trunk/bitbake/bin/bitdoc
@@ -0,0 +1,510 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+#
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+# THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+#
+
+import optparse, os, sys
+
+# bitbake
+sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+import bb
+from bb import make
+from string import split, join
+
+__version__ = "0.0.2"
+
+class HTMLFormatter:
+ """
+ Simple class to help to generate some sort of HTML files. It is
+ quite inferior solution compared to docbook, gtkdoc, doxygen but it
+ should work for now.
+ We've a global introduction site (index.html) and then one site for
+ the list of keys (alphabetical sorted) and one for the list of groups,
+ one site for each key with links to the relations and groups.
+
+ index.html
+ keys.html
+ groups.html
+ groupNAME.html
+ keyNAME.html
+ """
+
+ def replace(self, text, *pairs):
+ """
+ From pydoc... almost identical at least
+ """
+ while pairs:
+ (a,b) = pairs[0]
+ text = join(split(text, a), b)
+ pairs = pairs[1:]
+ return text
+ def escape(self, text):
+ """
+ Escape string to be conform HTML
+ """
+ return self.replace(text,
+ ('&', '&amp;'),
+ ('<', '&lt;' ),
+ ('>', '&gt;' ) )
+ def createNavigator(self):
+ """
+ Create the navgiator
+ """
+ return """<table class="navigation" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2">
+<tr valign="middle">
+<td><a accesskey="g" href="index.html">Home</a></td>
+<td><a accesskey="n" href="groups.html">Groups</a></td>
+<td><a accesskey="u" href="keys.html">Keys</a></td>
+</tr></table>
+"""
+
+ def relatedKeys(self, item):
+ """
+ Create HTML to link to foreign keys
+ """
+ txt = "<p><b>See also:</b><br>"
+ for it in item.related():
+ txt += """<a href="key%s.html">%s</a>, """ % (it, it)
+
+ return txt
+
+ def groups(self,item):
+ """
+ Create HTML to link to related groups
+ """
+ txt = "<p><b>Seel also:</b><br>"
+ for group in item.groups():
+ txt += """<a href="group%s.html">%s</a>, """ % (group,group)
+
+ return txt
+
+
+ def createKeySite(self,item):
+ """
+ Create a site for a key. It contains the header/navigator, a heading,
+ the description, links to related keys and to the groups.
+ """
+
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head><title>Key %s</title></head>
+<link rel="stylesheet" href="style.css" type="text/css">
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+%s
+<h2><span class="refentrytitle">%s</span></h2>
+
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<pre class="synopsis">
+%s
+</pre>
+</div>
+
+<div class="refsynopsisdiv">
+<h2>Related Keys</h2>
+<pre class="synopsis">
+%s
+</pre>
+</div>
+
+<div class="refsynopsisdiv">
+<h2>Groups</h2>
+<pre class="synopsis">
+%s
+</pre>
+</div>
+
+
+</body>
+""" % (item.name(), self.createNavigator(), item.name(),
+ self.escape(item.description()), self.relatedKeys(item), self.groups(item))
+
+ def createGroupsSite(self, doc):
+ """
+ Create the Group Overview site
+ """
+
+ groups = ""
+ for group in doc.groups():
+ groups += """<a href="group%s.html">%s</a><br>""" % (group, group)
+
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head><title>Group overview</title></head>
+<link rel="stylesheet" href="style.css" type="text/css">
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+%s
+<h2>Available Groups</h2>
+%s
+</body>
+""" % (self.createNavigator(), groups)
+
+ def createIndex(self):
+ """
+ Create the index file
+ """
+
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head><title>Bitbake Documentation</title></head>
+<link rel="stylesheet" href="style.css" type="text/css">
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+%s
+<h2>Documentation Entrance</h2>
+<a href="groups.html">All available groups</a><br>
+<a href="keys.html">All available keys</a><br>
+</body>
+""" % self.createNavigator()
+
+ def createKeysSite(self, doc):
+ """
+ Create Overview of all avilable keys
+ """
+ keys = ""
+ for key in doc.doc_keys():
+ keys += """<a href="key%s.html">%s</a><br>""" % (key, key)
+
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head><title>Key overview</title></head>
+<link rel="stylesheet" href="style.css" type="text/css">
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+%s
+<h2>Available Keys</h2>
+%s
+</body>
+""" % (self.createNavigator(), keys)
+
+ def createGroupSite(self,gr, items):
+ """
+ Create a site for a group:
+ Group the name of the group, items contain the name of the keys
+ inside this group
+ """
+ groups = ""
+ for group in items:
+ groups += """<a href="group%s.html">%s</a><br>""" % (group.name(), group.name())
+
+ return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head><title>Group %s</title></head>
+<link rel="stylesheet" href="style.css" type="text/css">
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+%s
+<div class="refsynopsisdiv">
+<h2>Keys in Group %s</h2>
+<pre class="synopsis">
+%s
+</pre>
+</div>
+</body>
+""" % (gr, self.createNavigator(), gr, groups)
+
+
+
+ def createCSS(self):
+ """
+ Create the CSS file
+ """
+ return """.synopsis, .classsynopsis
+{
+ background: #eeeeee;
+ border: solid 1px #aaaaaa;
+ padding: 0.5em;
+}
+.programlisting
+{
+ background: #eeeeff;
+ border: solid 1px #aaaaff;
+ padding: 0.5em;
+}
+.variablelist
+{
+ padding: 4px;
+ margin-left: 3em;
+}
+.variablelist td:first-child
+{
+ vertical-align: top;
+}
+table.navigation
+{
+ background: #ffeeee;
+ border: solid 1px #ffaaaa;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+.navigation a
+{
+ color: #770000;
+}
+.navigation a:visited
+{
+ color: #550000;
+}
+.navigation .title
+{
+ font-size: 200%;
+}
+div.refnamediv
+{
+ margin-top: 2em;
+}
+div.gallery-float
+{
+ float: left;
+ padding: 10px;
+}
+div.gallery-float img
+{
+ border-style: none;
+}
+div.gallery-spacer
+{
+ clear: both;
+}
+a
+{
+ text-decoration: none;
+}
+a:hover
+{
+ text-decoration: underline;
+ color: #FF0000;
+}
+"""
+
+
+
+class DocumentationItem:
+ """
+ A class to hold information about a configuration
+ item. It contains the key name, description, a list of related names,
+ and the group this item is contained in.
+ """
+
+ def __init__(self):
+ self._groups = []
+ self._related = []
+ self._name = ""
+ self._desc = ""
+
+ def groups(self):
+ return self._groups
+
+ def name(self):
+ return self._name
+
+ def description(self):
+ return self._desc
+
+ def related(self):
+ return self._related
+
+ def setName(self, name):
+ self._name = name
+
+ def setDescription(self, desc):
+ self._desc = desc
+
+ def addGroup(self, group):
+ self._groups.append(group)
+
+ def addRelation(self,relation):
+ self._related.append(relation)
+
+
+class Documentation:
+ """
+ Holds the documentation... with mappings from key to items...
+ """
+
+ def __init__(self):
+ self.__keys = {}
+ self.__groups = {}
+
+ def insert_doc_item(self, item):
+ """
+ Insert the Doc Item into the internal list
+ of representation
+ """
+ self.__keys[item.name()] = item
+
+ for group in item.groups():
+ if not group in self.__groups:
+ self.__groups[group] = []
+ self.__groups[group].append(item)
+
+
+ def doc_item(self, key):
+ """
+ Return the DocumentationInstance describing the key
+ """
+ try:
+ return self.__keys[key]
+ except KeyError:
+ return None
+
+ def doc_keys(self):
+ """
+ Return the documented KEYS (names)
+ """
+ return self.__keys.keys()
+
+ def groups(self):
+ """
+ Return the names of available groups
+ """
+ return self.__groups.keys()
+
+ def group_content(self,group_name):
+ """
+ Return a list of keys/names that are in a specefic
+ group or the empty list
+ """
+ try:
+ return self.__groups[group_name]
+ except KeyError:
+ return []
+
+
+def parse_cmdline(args):
+ """
+ Parse the CMD line and return the result as a n-tuple
+ """
+
+ parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__,__version__))
+ usage = """%prog [options]
+
+Create a set of html pages (documentation) for a bitbake.conf....
+"""
+
+ # Add the needed options
+ parser.add_option( "-c", "--config", help = "Use the specified configuration file as source",
+ action = "store", dest = "config", default = os.path.join("conf", "documentation.conf") )
+
+ parser.add_option( "-o", "--output", help = "Output directory for html files",
+ action = "store", dest = "output", default = "html/" )
+
+ parser.add_option( "-D", "--debug", help = "Increase the debug level",
+ action = "count", dest = "debug", default = 0 )
+
+ parser.add_option( "-v","--verbose", help = "output more chit-char to the terminal",
+ action = "store_true", dest = "verbose", default = False )
+
+ options, args = parser.parse_args( sys.argv )
+
+ if options.debug:
+ bb.debug_level = options.debug
+
+ return options.config, options.output
+
+def main():
+ """
+ The main Method
+ """
+
+ (config_file,output_dir) = parse_cmdline( sys.argv )
+
+ # right to let us load the file now
+ try:
+ documentation = bb.parse.handle( config_file, bb.data.init() )
+ except IOError:
+ bb.fatal( "Unable to open %s" % config_file )
+ except bb.parse.ParseError:
+ bb.fatal( "Unable to parse %s" % config_file )
+
+
+ # Assuming we've the file loaded now, we will initialize the 'tree'
+ doc = Documentation()
+
+ # defined states
+ state_begin = 0
+ state_see = 1
+ state_group = 2
+
+ for key in bb.data.keys(documentation):
+ data = bb.data.getVarFlag(key, "doc", documentation)
+ if not data:
+ continue
+
+ # The Documentation now starts
+ doc_ins = DocumentationItem()
+ doc_ins.setName(key)
+
+
+ tokens = data.split(' ')
+ state = state_begin
+ string= ""
+ for token in tokens:
+ token = token.strip(',')
+
+ if not state == state_see and token == "@see":
+ state = state_see
+ continue
+ elif not state == state_group and token == "@group":
+ state = state_group
+ continue
+
+ if state == state_begin:
+ string += " %s" % token
+ elif state == state_see:
+ doc_ins.addRelation(token)
+ elif state == state_group:
+ doc_ins.addGroup(token)
+
+ # set the description
+ doc_ins.setDescription(string)
+ doc.insert_doc_item(doc_ins)
+
+ # let us create the HTML now...
+ bb.mkdirhier(output_dir)
+ os.chdir(output_dir)
+
+ # Let us create the sites now. We do it in the following order
+ # Start with the index.html. It will point to sites explaining all
+ # keys and groups
+ html_slave = HTMLFormatter()
+
+ f = file('style.css', 'w')
+ print >> f, html_slave.createCSS()
+
+ f = file('index.html', 'w')
+ print >> f, html_slave.createIndex()
+
+ f = file('groups.html', 'w')
+ print >> f, html_slave.createGroupsSite(doc)
+
+ f = file('keys.html', 'w')
+ print >> f, html_slave.createKeysSite(doc)
+
+ # now for each group create the site
+ for group in doc.groups():
+ f = file('group%s.html' % group, 'w')
+ print >> f, html_slave.createGroupSite(group, doc.group_content(group))
+
+ # now for the keys
+ for key in doc.doc_keys():
+ f = file('key%s.html' % doc.doc_item(key).name(), 'w')
+ print >> f, html_slave.createKeySite(doc.doc_item(key))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/trunk/bitbake/classes/base.bbclass b/trunk/bitbake/classes/base.bbclass
new file mode 100644
index 000000000..1d75964f5
--- /dev/null
+++ b/trunk/bitbake/classes/base.bbclass
@@ -0,0 +1,79 @@
+# Copyright (C) 2003 Chris Larson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+die() {
+ bbfatal "$*"
+}
+
+bbnote() {
+ echo "NOTE:" "$*"
+}
+
+bbwarn() {
+ echo "WARNING:" "$*"
+}
+
+bbfatal() {
+ echo "FATAL:" "$*"
+ exit 1
+}
+
+bbdebug() {
+ test $# -ge 2 || {
+ echo "Usage: bbdebug level \"message\""
+ exit 1
+ }
+
+ test ${@bb.debug_level} -ge $1 && {
+ shift
+ echo "DEBUG:" $*
+ }
+}
+
+addtask showdata
+do_showdata[nostamp] = "1"
+python do_showdata() {
+ import sys
+ # emit variables and shell functions
+ bb.data.emit_env(sys.__stdout__, d, True)
+ # emit the metadata which isnt valid shell
+ for e in bb.data.keys(d):
+ if bb.data.getVarFlag(e, 'python', d):
+ sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, bb.data.getVar(e, d, 1)))
+}
+
+addtask listtasks
+do_listtasks[nostamp] = "1"
+python do_listtasks() {
+ import sys
+ for e in bb.data.keys(d):
+ if bb.data.getVarFlag(e, 'task', d):
+ sys.__stdout__.write("%s\n" % e)
+}
+
+addtask build
+do_build[dirs] = "${TOPDIR}"
+do_build[nostamp] = "1"
+python base_do_build () {
+ bb.note("The included, default BB base.bbclass does not define a useful default task.")
+ bb.note("Try running the 'listtasks' task against a .bb to see what tasks are defined.")
+}
+
+EXPORT_FUNCTIONS do_clean do_mrproper do_build
diff --git a/trunk/bitbake/conf/bitbake.conf b/trunk/bitbake/conf/bitbake.conf
new file mode 100644
index 000000000..fd216a326
--- /dev/null
+++ b/trunk/bitbake/conf/bitbake.conf
@@ -0,0 +1,55 @@
+# Copyright (C) 2003 Chris Larson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+B = "${S}"
+CVSDIR = "${DL_DIR}/cvs"
+DEPENDS = ""
+DEPLOY_DIR = "${TMPDIR}/deploy"
+DEPLOY_DIR_IMAGE = "${DEPLOY_DIR}/images"
+DL_DIR = "${TMPDIR}/downloads"
+FETCHCOMMAND = ""
+FETCHCOMMAND_cvs = "/usr/bin/env cvs -d${CVSROOT} co ${CVSCOOPTS} ${CVSMODULE}"
+FETCHCOMMAND_svn = "/usr/bin/env svn co http://${SVNROOT} ${SVNCOOPTS} ${SVNMODULE}"
+FETCHCOMMAND_wget = "/usr/bin/env wget -t 5 --passive-ftp -P ${DL_DIR} ${URI}"
+FILESDIR = "${@bb.which(bb.data.getVar('FILESPATH', d, 1), '.')}"
+FILESPATH = "${FILE_DIRNAME}/${PF}:${FILE_DIRNAME}/${P}:${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/files:${FILE_DIRNAME}"
+FILE_DIRNAME = "${@os.path.dirname(bb.data.getVar('FILE', d))}"
+IMAGE_CMD = "_NO_DEFINED_IMAGE_TYPES_"
+IMAGE_ROOTFS = "${TMPDIR}/rootfs"
+MKTEMPCMD = "mktemp -q ${TMPBASE}"
+MKTEMPDIRCMD = "mktemp -d -q ${TMPBASE}"
+OVERRIDES = "local:${MACHINE}:${TARGET_OS}:${TARGET_ARCH}"
+P = "${PN}-${PV}"
+PF = "${PN}-${PV}-${PR}"
+PN = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[0] or 'defaultpkgname'}"
+PR = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[2] or 'r0'}"
+PROVIDES = ""
+PV = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[1] or '1.0'}"
+RESUMECOMMAND = ""
+RESUMECOMMAND_wget = "/usr/bin/env wget -c -t 5 --passive-ftp -P ${DL_DIR} ${URI}"
+S = "${WORKDIR}/${P}"
+SRC_URI = "file://${FILE}"
+STAMP = "${TMPDIR}/stamps/${PF}"
+T = "${WORKDIR}/temp"
+TARGET_ARCH = "${BUILD_ARCH}"
+TMPDIR = "${TOPDIR}/tmp"
+UPDATECOMMAND = ""
+UPDATECOMMAND_cvs = "/usr/bin/env cvs update ${CVSCOOPTS}"
+WORKDIR = "${TMPDIR}/work/${PF}"
diff --git a/trunk/bitbake/contrib/README b/trunk/bitbake/contrib/README
new file mode 100644
index 000000000..25e515661
--- /dev/null
+++ b/trunk/bitbake/contrib/README
@@ -0,0 +1 @@
+This directory is for additional contributed files which may be useful.
diff --git a/trunk/bitbake/contrib/bbdev.sh b/trunk/bitbake/contrib/bbdev.sh
new file mode 100644
index 000000000..33a78531e
--- /dev/null
+++ b/trunk/bitbake/contrib/bbdev.sh
@@ -0,0 +1,31 @@
+# This is a shell function to be sourced into your shell or placed in your .profile,
+# which makes setting things up for BitBake a bit easier.
+#
+# The author disclaims copyright to the contents of this file and places it in the
+# public domain.
+
+bbdev () {
+ local BBDIR PKGDIR BUILDDIR
+ if test x"$1" = "x--help"; then echo >&2 "syntax: bbdev [bbdir [pkgdir [builddir]]]"; return 1; fi
+ if test x"$1" = x; then BBDIR=`pwd`; else BBDIR=$1; fi
+ if test x"$2" = x; then PKGDIR=`pwd`; else PKGDIR=$2; fi
+ if test x"$3" = x; then BUILDDIR=`pwd`; else BUILDDIR=$3; fi
+
+ BBDIR=`readlink -f $BBDIR`
+ PKGDIR=`readlink -f $PKGDIR`
+ BUILDDIR=`readlink -f $BUILDDIR`
+ if ! (test -d $BBDIR && test -d $PKGDIR && test -d $BUILDDIR); then
+ echo >&2 "syntax: bbdev [bbdir [pkgdir [builddir]]]"
+ return 1
+ fi
+
+ PATH=$BBDIR/bin:$PATH
+ BBPATH=$BBDIR
+ if test x"$BBDIR" != x"$PKGDIR"; then
+ BBPATH=$PKGDIR:$BBPATH
+ fi
+ if test x"$PKGDIR" != x"$BUILDDIR"; then
+ BBPATH=$BUILDDIR:$BBPATH
+ fi
+ export BBPATH
+}
diff --git a/trunk/bitbake/contrib/vim/syntax/bitbake.vim b/trunk/bitbake/contrib/vim/syntax/bitbake.vim
new file mode 100644
index 000000000..5d2bc633e
--- /dev/null
+++ b/trunk/bitbake/contrib/vim/syntax/bitbake.vim
@@ -0,0 +1,120 @@
+" Vim syntax file
+"
+" Copyright (C) 2004 Chris Larson <kergoth@handhelds.org>
+" This file is licensed under the MIT license, see COPYING.MIT in
+" this source distribution for the terms.
+"
+" Language: BitBake
+" Maintainer: Chris Larson <kergoth@handhelds.org>
+" Filenames: *.bb, *.bbclass
+
+if version < 600
+ syntax clear
+elseif exists("b:current_syntax")
+ finish
+endif
+
+syn case match
+
+
+" Catch incorrect syntax (only matches if nothing else does)
+"
+syn match bbUnmatched "."
+
+
+" Other
+
+syn match bbComment "^#.*$" display contains=bbTodo
+syn keyword bbTodo TODO FIXME XXX contained
+syn match bbDelimiter "[(){}=]" contained
+syn match bbQuote /['"]/ contained
+syn match bbArrayBrackets "[\[\]]" contained
+
+
+" BitBake strings
+
+syn match bbContinue "\\$"
+syn region bbString matchgroup=bbQuote start=/"/ skip=/\\$/ excludenl end=/"/ contained keepend contains=bbTodo,bbContinue,bbVarDeref
+syn region bbString matchgroup=bbQuote start=/'/ skip=/\\$/ excludenl end=/'/ contained keepend contains=bbTodo,bbContinue,bbVarDeref
+
+
+" BitBake variable metadata
+
+syn keyword bbExportFlag export contained nextgroup=bbIdentifier skipwhite
+syn match bbVarDeref "${[a-zA-Z0-9\-_\.]\+}" contained
+syn match bbVarDef "^\(export\s*\)\?\([a-zA-Z0-9\-_\.]\+\(_[${}a-zA-Z0-9\-_\.]\+\)\?\)\s*\(\(:=\)\|\(+=\)\|\(=+\)\|\(?=\)\|=\)\@=" contains=bbExportFlag,bbIdentifier,bbVarDeref nextgroup=bbVarEq
+
+syn match bbIdentifier "[a-zA-Z0-9\-_\.]\+" display contained
+"syn keyword bbVarEq = display contained nextgroup=bbVarValue
+syn match bbVarEq "\(:=\)\|\(+=\)\|\(=+\)\|\(?=\)\|=" contained nextgroup=bbVarValue
+syn match bbVarValue ".*$" contained contains=bbString,bbVarDeref
+
+
+" BitBake variable metadata flags
+syn match bbVarFlagDef "^\([a-zA-Z0-9\-_\.]\+\)\(\[[a-zA-Z0-9\-_\.]\+\]\)\@=" contains=bbIdentifier nextgroup=bbVarFlagFlag
+syn region bbVarFlagFlag matchgroup=bbArrayBrackets start="\[" end="\]\s*\(=\)\@=" keepend excludenl contained contains=bbIdentifier nextgroup=bbVarEq
+"syn match bbVarFlagFlag "\[\([a-zA-Z0-9\-_\.]\+\)\]\s*\(=\)\@=" contains=bbIdentifier nextgroup=bbVarEq
+
+
+" Functions!
+syn match bbFunction "\h\w*" display contained
+
+
+" BitBake python metadata
+syn include @python syntax/python.vim
+if exists("b:current_syntax")
+ unlet b:current_syntax
+endif
+
+syn keyword bbPythonFlag python contained nextgroup=bbFunction
+syn match bbPythonFuncDef "^\(python\s\+\)\(\w\+\)\?\(\s*()\s*\)\({\)\@=" contains=bbPythonFlag,bbFunction,bbDelimiter nextgroup=bbPythonFuncRegion skipwhite
+syn region bbPythonFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" keepend contained contains=@python
+"hi def link bbPythonFuncRegion Comment
+
+
+" BitBake shell metadata
+syn include @shell syntax/sh.vim
+if exists("b:current_syntax")
+ unlet b:current_syntax
+endif
+
+syn keyword bbFakerootFlag fakeroot contained nextgroup=bbFunction
+syn match bbShellFuncDef "^\(fakeroot\s*\)\?\(\w\+\)\(python\)\@<!\(\s*()\s*\)\({\)\@=" contains=bbFakerootFlag,bbFunction,bbDelimiter nextgroup=bbShellFuncRegion skipwhite
+syn region bbShellFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" keepend contained contains=@shell
+"hi def link bbShellFuncRegion Comment
+
+
+" BitBake 'def'd python functions
+syn keyword bbDef def contained
+syn region bbDefRegion start='^def\s\+\w\+\s*([^)]*)\s*:\s*$' end='^\(\s\|$\)\@!' contains=@python
+
+
+" BitBake statements
+syn keyword bbStatement include inherit addtask addhandler EXPORT_FUNCTIONS display contained
+syn match bbStatementLine "^\(include\|inherit\|addtask\|addhandler\|EXPORT_FUNCTIONS\)\s\+" contains=bbStatement nextgroup=bbStatementRest
+syn match bbStatementRest ".*$" contained contains=bbString,bbVarDeref
+
+" Highlight
+"
+hi def link bbArrayBrackets Statement
+hi def link bbUnmatched Error
+hi def link bbVarDeref String
+hi def link bbContinue Special
+hi def link bbDef Statement
+hi def link bbPythonFlag Type
+hi def link bbExportFlag Type
+hi def link bbFakerootFlag Type
+hi def link bbStatement Statement
+hi def link bbString String
+hi def link bbTodo Todo
+hi def link bbComment Comment
+hi def link bbOperator Operator
+hi def link bbError Error
+hi def link bbFunction Function
+hi def link bbDelimiter Delimiter
+hi def link bbIdentifier Identifier
+hi def link bbVarEq Operator
+hi def link bbQuote String
+hi def link bbVarValue String
+
+let b:current_syntax = "bb"
diff --git a/trunk/bitbake/doc/COPYING.GPL b/trunk/bitbake/doc/COPYING.GPL
new file mode 100644
index 000000000..d60c31a97
--- /dev/null
+++ b/trunk/bitbake/doc/COPYING.GPL
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program 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 program 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 program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/trunk/bitbake/doc/COPYING.MIT b/trunk/bitbake/doc/COPYING.MIT
new file mode 100644
index 000000000..7e7d57413
--- /dev/null
+++ b/trunk/bitbake/doc/COPYING.MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/trunk/bitbake/doc/manual/Makefile b/trunk/bitbake/doc/manual/Makefile
new file mode 100644
index 000000000..a43c02545
--- /dev/null
+++ b/trunk/bitbake/doc/manual/Makefile
@@ -0,0 +1,56 @@
+topdir = .
+manual = $(topdir)/usermanual.xml
+# types = pdf txt rtf ps xhtml html man tex texi dvi
+# types = pdf txt
+types = $(xmltotypes) $(htmltypes)
+xmltotypes = pdf txt
+htmltypes = html xhtml
+htmlxsl = $(if $(filter $@,$(foreach type,$(htmltypes),$(type)-nochunks)),http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl,http://docbook.sourceforge.net/release/xsl/current/$@/chunk.xsl)
+htmlcssfile = docbook.css
+htmlcss = $(topdir)/html.css
+# htmlcssfile =
+# htmlcss =
+cleanfiles = $(foreach i,$(types),$(topdir)/$(i))
+
+ifdef DEBUG
+define command
+ $(1)
+endef
+else
+define command
+ @echo $(2) $(3) $(4)
+ @$(1) >/dev/null
+endef
+endif
+
+all: $(types)
+
+lint: $(manual) FORCE
+ $(call command,xmllint --xinclude --postvalid --noout $(manual),XMLLINT $(manual))
+
+$(types) $(foreach type,$(htmltypes),$(type)-nochunks): lint FORCE
+
+$(foreach type,$(htmltypes),$(type)-nochunks): $(if $(htmlcss),$(htmlcss)) $(manual)
+ @mkdir -p $@
+ifdef htmlcss
+ $(call command,install -m 0644 $(htmlcss) $@/$(htmlcssfile),CP $(htmlcss) $@/$(htmlcssfile))
+endif
+ $(call command,xsltproc --stringparam base.dir $@/ $(if $(htmlcssfile),--stringparam html.stylesheet $(htmlcssfile)) $(htmlxsl) $(manual) > $@/index.$(patsubst %-nochunks,%,$@),XSLTPROC $@ $(manual))
+
+$(htmltypes): $(if $(htmlcss),$(htmlcss)) $(manual)
+ @mkdir -p $@
+ifdef htmlcss
+ $(call command,install -m 0644 $(htmlcss) $@/$(htmlcssfile),CP $(htmlcss) $@/$(htmlcssfile))
+endif
+ $(call command,xsltproc --stringparam base.dir $@/ $(if $(htmlcssfile),--stringparam html.stylesheet $(htmlcssfile)) $(htmlxsl) $(manual),XSLTPROC $@ $(manual))
+
+$(xmltotypes): $(manual)
+ $(call command,xmlto --extensions -o $(topdir)/$@ $@ $(manual),XMLTO $@ $(manual))
+
+clean:
+ rm -rf $(cleanfiles)
+
+$(foreach i,$(types) $(foreach type,$(htmltypes),$(type)-nochunks),clean-$(i)):
+ rm -rf $(patsubst clean-%,%,$@)
+
+FORCE:
diff --git a/trunk/bitbake/doc/manual/html.css b/trunk/bitbake/doc/manual/html.css
new file mode 100644
index 000000000..6eedfd318
--- /dev/null
+++ b/trunk/bitbake/doc/manual/html.css
@@ -0,0 +1,281 @@
+/* Feuille de style DocBook du projet Traduc.org */
+/* DocBook CSS stylesheet of the Traduc.org project */
+
+/* (c) Jean-Philippe Guérard - 14 août 2004 */
+/* (c) Jean-Philippe Guérard - 14 August 2004 */
+
+/* Cette feuille de style est libre, vous pouvez la */
+/* redistribuer et la modifier selon les termes de la Licence */
+/* Art Libre. Vous trouverez un exemplaire de cette Licence sur */
+/* http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
+
+/* This work of art is free, you can redistribute it and/or */
+/* modify it according to terms of the Free Art license. You */
+/* will find a specimen of this license on the Copyleft */
+/* Attitude web site: http://artlibre.org as well as on other */
+/* sites. */
+/* Please note that the French version of this licence as shown */
+/* on http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
+/* is only official licence of this document. The English */
+/* is only provided to help you understand this licence. */
+
+/* La dernière version de cette feuille de style est toujours */
+/* disponible sur : http://tigreraye.org/style.css */
+/* Elle est également disponible sur : */
+/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
+
+/* The latest version of this stylesheet is available from: */
+/* http://tigreraye.org/style.css */
+/* It is also available on: */
+/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
+
+/* N'hésitez pas à envoyer vos commentaires et corrections à */
+/* Jean-Philippe Guérard <jean-philippe.guerard@tigreraye.org> */
+
+/* Please send feedback and bug reports to */
+/* Jean-Philippe Guérard <jean-philippe.guerard@tigreraye.org> */
+
+/* $Id: style.css,v 1.14 2004/09/10 20:12:09 fevrier Exp fevrier $ */
+
+/* Présentation générale du document */
+/* Overall document presentation */
+
+body {
+ /*
+ font-family: Apolline, "URW Palladio L", Garamond, jGaramond,
+ "Bitstream Cyberbit", "Palatino Linotype", serif;
+ */
+ margin: 7%;
+ background-color: white;
+}
+
+/* Taille du texte */
+/* Text size */
+
+* { font-size: 100%; }
+
+/* Gestion des textes mis en relief imbriqués */
+/* Embedded emphasis */
+
+em { font-style: italic; }
+em em { font-style: normal; }
+em em em { font-style: italic; }
+
+/* Titres */
+/* Titles */
+
+h1 { font-size: 200%; font-weight: 900; }
+h2 { font-size: 160%; font-weight: 900; }
+h3 { font-size: 130%; font-weight: bold; }
+h4 { font-size: 115%; font-weight: bold; }
+h5 { font-size: 108%; font-weight: bold; }
+h6 { font-weight: bold; }
+
+/* Nom de famille en petites majuscules (uniquement en français) */
+/* Last names in small caps (for French only) */
+
+*[class~="surname"]:lang(fr) { font-variant: small-caps; }
+
+/* Blocs de citation */
+/* Quotation blocs */
+
+div[class~="blockquote"] {
+ border: solid 2px #AAA;
+ padding: 5px;
+ margin: 5px;
+}
+
+div[class~="blockquote"] > table {
+ border: none;
+}
+
+/* Blocs litéraux : fond gris clair */
+/* Literal blocs: light gray background */
+
+*[class~="literallayout"] {
+ background: #f0f0f0;
+ padding: 5px;
+ margin: 5px;
+}
+
+/* Programmes et captures texte : fond bleu clair */
+/* Listing and text screen snapshots: light blue background */
+
+*[class~="programlisting"], *[class~="screen"] {
+ background: #f0f0ff;
+ padding: 5px;
+ margin: 5px;
+}
+
+/* Les textes à remplacer sont surlignés en vert pâle */
+/* Replaceable text in highlighted in pale green */
+
+*[class~="replaceable"] {
+ background-color: #98fb98;
+ font-style: normal; }
+
+/* Tables : fonds gris clair & bords simples */
+/* Tables: light gray background and solid borders */
+
+*[class~="table"] *[class~="title"] { width:100%; border: 0px; }
+
+table {
+ border: 1px solid #aaa;
+ border-collapse: collapse;
+ padding: 2px;
+ margin: 5px;
+}
+
+/* Listes simples en style table */
+/* Simples lists in table presentation */
+
+table[class~="simplelist"] {
+ background-color: #F0F0F0;
+ margin: 5px;
+ border: solid 1px #AAA;
+}
+
+table[class~="simplelist"] td {
+ border: solid 1px #AAA;
+}
+
+/* Les tables */
+/* Tables */
+
+*[class~="table"] table {
+ background-color: #F0F0F0;
+ border: solid 1px #AAA;
+}
+*[class~="informaltable"] table { background-color: #F0F0F0; }
+
+th,td {
+ vertical-align: baseline;
+ text-align: left;
+ padding: 0.1em 0.3em;
+ empty-cells: show;
+}
+
+/* Alignement des colonnes */
+/* Colunms alignment */
+
+td[align=center] , th[align=center] { text-align: center; }
+td[align=right] , th[align=right] { text-align: right; }
+td[align=left] , th[align=left] { text-align: left; }
+td[align=justify] , th[align=justify] { text-align: justify; }
+
+/* Pas de marge autour des images */
+/* No inside margins for images */
+
+img { border: 0; }
+
+/* Les liens ne sont pas soulignés */
+/* No underlines for links */
+
+:link , :visited , :active { text-decoration: none; }
+
+/* Prudence : cadre jaune et fond jaune clair */
+/* Caution: yellow border and light yellow background */
+
+*[class~="caution"] {
+ border: solid 2px yellow;
+ background-color: #ffffe0;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="caution"] th {
+ vertical-align: middle
+}
+
+*[class~="caution"] table {
+ background-color: #ffffe0;
+ border: none;
+}
+
+/* Note importante : cadre jaune et fond jaune clair */
+/* Important: yellow border and light yellow background */
+
+*[class~="important"] {
+ border: solid 2px yellow;
+ background-color: #ffffe0;
+ padding: 1em 6px 1em;
+ margin: 5px;
+}
+
+*[class~="important"] th {
+ vertical-align: middle
+}
+
+*[class~="important"] table {
+ background-color: #ffffe0;
+ border: none;
+}
+
+/* Mise en évidence : texte légèrement plus grand */
+/* Highlights: slightly larger texts */
+
+*[class~="highlights"] {
+ font-size: 110%;
+}
+
+/* Note : cadre bleu et fond bleu clair */
+/* Notes: blue border and light blue background */
+
+*[class~="note"] {
+ border: solid 2px #7099C5;
+ background-color: #f0f0ff;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="note"] th {
+ vertical-align: middle
+}
+
+*[class~="note"] table {
+ background-color: #f0f0ff;
+ border: none;
+}
+
+/* Astuce : cadre vert et fond vert clair */
+/* Tip: green border and light green background */
+
+*[class~="tip"] {
+ border: solid 2px #00ff00;
+ background-color: #f0ffff;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="tip"] th {
+ vertical-align: middle;
+}
+
+*[class~="tip"] table {
+ background-color: #f0ffff;
+ border: none;
+}
+
+/* Avertissement : cadre rouge et fond rouge clair */
+/* Warning: red border and light red background */
+
+*[class~="warning"] {
+ border: solid 2px #ff0000;
+ background-color: #fff0f0;
+ padding: 1em 6px 1em ;
+ margin: 5px;
+}
+
+*[class~="warning"] th {
+ vertical-align: middle;
+}
+
+
+*[class~="warning"] table {
+ background-color: #fff0f0;
+ border: none;
+}
+
+/* Fin */
+/* The End */
+
diff --git a/trunk/bitbake/doc/manual/usermanual.xml b/trunk/bitbake/doc/manual/usermanual.xml
new file mode 100644
index 000000000..3c3009d0e
--- /dev/null
+++ b/trunk/bitbake/doc/manual/usermanual.xml
@@ -0,0 +1,329 @@
+<?xml version="1.0"?>
+<!--
+ ex:ts=4:sw=4:sts=4:et
+ -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+-->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<book>
+ <bookinfo>
+ <title>BitBake User Manual</title>
+ <authorgroup>
+ <corpauthor>BitBake Team</corpauthor>
+ </authorgroup>
+ <copyright>
+ <year>2004</year>
+ <holder>Chris Larson</holder>
+ <holder>Phil Blundell</holder>
+ </copyright>
+ <legalnotice>
+ <para>This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit <ulink url="http://creativecommons.org/licenses/by/2.0/">http://creativecommons.org/licenses/by/2.0/</ulink> or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.</para>
+ </legalnotice>
+ </bookinfo>
+ <chapter>
+ <title>Introduction</title>
+ <section>
+ <title>Overview</title>
+ <para>BitBake is, at its simplest, a tool for executing
+tasks and managing metadata. As such, its similarities to GNU make and other
+build tools are readily apparent. It was inspired by Portage, the package management system used by the Gentoo Linux distribution. BitBake is the basis of the <ulink url="http://www.openembedded.org/">OpenEmbedded</ulink> project, which is being used to build and maintain a number of embedded Linux distributions, including OpenZaurus and Familiar.</para>
+ </section>
+ <section>
+ <title>Background and Goals</title>
+ <para>Prior to BitBake, no other build tool adequately met
+the needs of an aspiring embedded Linux distribution. All of the
+buildsystems used by traditional desktop Linux distributions lacked
+important functionality, and none of the ad-hoc
+<emphasis>buildroot</emphasis> systems, prevalent in the
+embedded space, were scalable or maintainable.</para>
+
+ <para>Some important goals for BitBake were:
+ <itemizedlist>
+ <listitem><para>Handle crosscompilation.</para></listitem>
+ <listitem><para>Handle interpackage dependencies (build time on target architecture, build time on native architecture, and runtime).</para></listitem>
+ <listitem><para>Support running any number of tasks within a given package, including, but not limited to, fetching upstream sources, unpacking them, patching them, configuring them, et cetera.</para></listitem>
+ <listitem><para>Must be linux distribution agnostic (both build and target).</para></listitem>
+ <listitem><para>Must be architecture agnostic</para></listitem>
+ <listitem><para>Must support multiple build and target operating systems (including cygwin, the BSDs, etc).</para></listitem>
+ <listitem><para>Must be able to be self contained, rather than tightly integrated into the build machine's root filesystem.</para></listitem>
+ <listitem><para>There must be a way to handle conditional metadata (on target architecture, operating system, distribution, machine).</para></listitem>
+ <listitem><para>It must be easy for the person using the tools to supply their own local metadata and packages to operate against.</para></listitem>
+ <listitem><para>Must make it easy to collaborate
+between multiple projects using BitBake for their
+builds.</para></listitem>
+ <listitem><para>Should provide an inheritance mechanism to
+share common metadata between many packages.</para></listitem>
+ <listitem><para>Et cetera...</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>BitBake satisfies all these and many more. Flexibility and power have always been the priorities. It is highly extensible, supporting embedded Python code and execution of any arbitrary tasks.</para>
+ </section>
+ </chapter>
+ <chapter>
+ <title>Metadata</title>
+ <section>
+ <title>Description</title>
+ <itemizedlist>
+ <para>BitBake metadata can be classified into 3 major areas:</para>
+ <listitem>
+ <para>Configuration Files</para>
+ </listitem>
+ <listitem>
+ <para>.bb Files</para>
+ </listitem>
+ <listitem>
+ <para>Classes</para>
+ </listitem>
+ </itemizedlist>
+ <para>What follows are a large number of examples of BitBake metadata. Any syntax which isn't supported in any of the aforementioned areas will be documented as such.</para>
+ <section>
+ <title>Basic variable setting</title>
+ <para><screen><varname>VARIABLE</varname> = "value"</screen></para>
+ <para>In this example, <varname>VARIABLE</varname> is <literal>value</literal>.</para>
+ </section>
+ <section>
+ <title>Variable expansion</title>
+ <para>BitBake supports variables referencing one another's contents using a syntax which is similar to shell scripting</para>
+ <para><screen><varname>A</varname> = "aval"
+<varname>B</varname> = "pre${A}post"</screen></para>
+ <para>This results in <varname>A</varname> containing <literal>aval</literal> and <varname>B</varname> containing <literal>preavalpost</literal>.</para>
+ </section>
+ <section>
+ <title>Immediate variable expansion (:=)</title>
+ <para>:= results in a variable's contents being expanded immediately, rather than when the variable is actually used.</para>
+ <para><screen><varname>T</varname> = "123"
+<varname>A</varname> := "${B} ${A} test ${T}"
+<varname>T</varname> = "456"
+<varname>B</varname> = "${T} bval"
+
+<varname>C</varname> = "cval"
+<varname>C</varname> := "${C}append"</screen></para>
+ <para>In that example, <varname>A</varname> would contain <literal> test 123</literal>, <varname>B</varname> would contain <literal>456 bval</literal>, and <varname>C</varname> would be <literal>cvalappend</literal>.</para>
+ </section>
+ <section>
+ <title>Appending (+=) and prepending (=+)</title>
+ <para><screen><varname>B</varname> = "bval"
+<varname>B</varname> += "additionaldata"
+<varname>C</varname> = "cval"
+<varname>C</varname> =+ "test"</screen></para>
+ <para>In this example, <varname>B</varname> is now <literal>bval additionaldata</literal> and <varname>C</varname> is <literal>test cval</literal>.</para>
+ </section>
+ <section>
+ <title>Conditional metadata set</title>
+ <para>OVERRIDES is a <quote>:</quote> seperated variable containing each item you want to satisfy conditions. So, if you have a variable which is conditional on <quote>arm</quote>, and <quote>arm</quote> is in OVERRIDES, then the <quote>arm</quote> specific version of the variable is used rather than the non-conditional version. Example:</para>
+ <para><screen><varname>OVERRIDES</varname> = "architecture:os:machine"
+<varname>TEST</varname> = "defaultvalue"
+<varname>TEST_os</varname> = "osspecificvalue"
+<varname>TEST_condnotinoverrides</varname> = "othercondvalue"</screen></para>
+ <para>In this example, <varname>TEST</varname> would be <literal>osspecificvalue</literal>, due to the condition <quote>os</quote> being in <varname>OVERRIDES</varname>.</para>
+ </section>
+ <section>
+ <title>Conditional appending</title>
+ <para>BitBake also supports appending and prepending to variables based on whether something is in OVERRIDES. Example:</para>
+ <para><screen><varname>DEPENDS</varname> = "glibc ncurses"
+<varname>OVERRIDES</varname> = "machine:local"
+<varname>DEPENDS_append_machine</varname> = " libmad"</screen></para>
+ <para>In this example, <varname>DEPENDS</varname> is set to <literal>glibc ncurses libmad</literal>.</para>
+ </section>
+ <section>
+ <title>Inclusion</title>
+ <para>Next, there is the <literal>include</literal> directive, which causes BitBake to parse in whatever file you specify, and insert it at that location, which is not unlike <command>make</command>. However, if the path specified on the <literal>include</literal> line is a relative path, BitBake will locate the first one it can find within <envar>BBPATH</envar>.</para>
+ </section>
+ <section>
+ <title>Python variable expansion</title>
+ <para><screen><varname>DATE</varname> = "${@time.strftime('%Y%m%d',time.gmtime())}"</screen></para>
+ <para>This would result in the <varname>DATE</varname> variable containing today's date.</para>
+ </section>
+ <section>
+ <title>Defining executable metadata</title>
+ <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
+ <para><screen>do_mytask () {
+ echo "Hello, world!"
+}</screen></para>
+ <para>This is essentially identical to setting a variable, except that this variable happens to be executable shell code.</para>
+ <para><screen>python do_printdate () {
+ import time
+ print time.strftime('%Y%m%d', time.gmtime())
+}</screen></para>
+ <para>This is the similar to the previous, but flags it as python so that BitBake knows it is python code.</para>
+ </section>
+ <section>
+ <title>Defining python functions into the global python namespace</title>
+ <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
+ <para><screen>def get_depends(bb, d):
+ if bb.data.getVar('SOMECONDITION', d, 1):
+ return "dependencywithcond"
+ else:
+ return "dependency"
+
+<varname>SOMECONDITION</varname> = "1"
+<varname>DEPENDS</varname> = "${@get_depends(bb, d)}"</screen></para>
+ <para>This would result in <varname>DEPENDS</varname> containing <literal>dependencywithcond</literal>.</para>
+ </section>
+ <section>
+ <title>Inheritance</title>
+ <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
+ <para>The <literal>inherit</literal> directive is a means of specifying what classes of functionality your .bb requires. It is a rudamentary form of inheritence. For example, you can easily abstract out the tasks involved in building a package that uses autoconf and automake, and put that into a bbclass for your packages to make use of. A given bbclass is located by searching for classes/filename.oeclass in <envar>BBPATH</envar>, where filename is what you inherited.</para>
+ </section>
+ <section>
+ <title>Tasks</title>
+ <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
+ <para>In BitBake, each step that needs to be run for a given .bb is known as a task. There is a command <literal>addtask</literal> to add new tasks (must be a defined python executable metadata and must start with <quote>do_</quote>) and describe intertask dependencies.</para>
+ <para><screen>python do_printdate () {
+ import time
+ print time.strftime('%Y%m%d', time.gmtime())
+}
+
+addtask printdate before do_build</screen></para>
+ <para>This defines the necessary python function and adds it as a task which is now a dependency of do_build (the default task). If anyone executes the do_build task, that will result in do_printdate being run first.</para>
+ </section>
+ <section>
+ <title>Events</title>
+ <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
+ <para>BitBake also implements a means of registering event handlers. Events are triggered at certain points during operation, such as, the beginning of operation against a given .bb, the start of a given task, task failure, task success, et cetera. The intent was to make it easy to do things like email notifications on build failure.</para>
+ <para><emphasis>[Insert instructions on how to add event handlers here]</emphasis></para>
+ </section>
+ </section>
+ <section>
+ <title>Parsing</title>
+ <section>
+ <title>Configuration Files</title>
+ <para>The first of the classifications of metadata in BitBake is configuration metadata. This metadata is global, and therefore affects <emphasis>all</emphasis> packages and tasks which are executed. Currently, BitBake has hardcoded knowledge of a single configuration file. It expects to find 'conf/bitbake.conf' somewhere in the user specified <envar>BBPATH</envar>. That configuration file generally has include directives to pull in any other metadata (generally files specific to architecture, machine, <emphasis>local</emphasis> and so on.</para>
+ <para>Only variable definitions and include directives are allowed in .conf files.</para>
+ </section>
+ <section>
+ <title>Classes</title>
+ <para>BitBake classes are our rudamentary inheritence mechanism. As briefly mentioned in the metadata introduction, they're parsed when an <literal>inherit</literal> directive is encountered, and they are located in classes/ relative to the dirs in <envar>BBPATH</envar>.</para>
+ </section>
+ <section>
+ <title>.bb Files</title>
+ <para>A BitBake (.bb) file is a logical unit of tasks to be executed. Normally this is a package to be built. Inter-.bb dependencies are obeyed. The files themselves are located via the <varname>BBFILES</varname> variable, which is set to a space seperated list of .bb files, and does handle wildcards.</para>
+ </section>
+ </section>
+ </chapter>
+ <chapter>
+ <title>Commands</title>
+ <section>
+ <title>bbread</title>
+ <para>bbread is a command for displaying BitBake metadata. When run with no arguments, it has the core parse 'conf/bitbake.conf', as located in BBPATH, and displays that. If you supply a file on the commandline, such as a .bb, then it parses that afterwards, using the aforementioned configuration metadata.</para>
+ </section>
+ <section>
+ <title>bitbake</title>
+ <section>
+ <title>Introduction</title>
+ <para>bitbake is the primary command in the system. It facilitates executing tasks in a single .bb file, or executing a given task on a set of multiple .bb files, accounting for interdependencies amongst them.</para>
+ </section>
+ <section>
+ <title>Usage and Syntax</title>
+ <para>
+ <screen><prompt>$ </prompt>bitbake --help
+usage: bitbake [options] [package ...]
+
+Executes the specified task (default is 'build') for a given set of BitBake files.
+It expects that BBFILES is defined, which is a space seperated list of files to
+be executed. BBFILES does support wildcards.
+Default BBFILES are the .bb files in the current directory.
+
+options:
+ --version show program's version number and exit
+ -h, --help show this help message and exit
+ -bBUILDFILE, --buildfile=BUILDFILE
+ execute the task against this .bb file, rather than a
+ package from BBFILES.
+ -k, --continue continue as much as possible after an error. While the
+ target that failed, and those that depend on it, cannot
+ be remade, the other dependencies of these targets can
+ be processed all the same.
+ -f, --force force run of specified cmd, regardless of stamp status
+ -cCMD, --cmd=CMD Specify task to execute
+ -rFILE, --read=FILE read the specified file before bitbake.conf
+ -v, --verbose output more chit-chat to the terminal
+ -D, --debug Increase the debug level
+ -n, --dry-run don't execute, just go through the motions
+ -p, --parse-only quit after parsing the BB files (developers only)
+ -d, --disable-psyco disable using the psyco just-in-time compiler (not
+ recommended)
+ -s, --show-versions show current and preferred versions of all packages</screen>
+ </para>
+ <para>
+ <example>
+ <title>Executing a task against a single .bb</title>
+ <para>Executing tasks for a single file is relatively simple. You specify the file in question, and bitbake parses it and executes the specified task (or <quote>build</quote> by default). It obeys intertask dependencies when doing so.</para>
+ <para><quote>clean</quote> task:</para>
+ <para><screen><prompt>$ </prompt>bitbake -b blah_1.0.bb -c clean</screen></para>
+ <para><quote>build</quote> task:</para>
+ <para><screen><prompt>$ </prompt>bitbake -b blah_1.0.bb</screen></para>
+ </example>
+ </para>
+ <para>
+ <example>
+ <title>Executing tasks against a set of .bb files</title>
+ <para>There are a number of additional complexities introduced when one wants to manage multiple .bb files. Clearly there needs to be a way to tell bitbake what files are available, and of those, which we want to execute at this time. There also needs to be a way for each .bb to express its dependencies, both for build time and runtime. There must be a way for the user to express their preferences when multiple .bb's provide the same functionality, or when there are multiple versions of a .bb.</para>
+ <para>The next section, Metadata, outlines how one goes about specifying such things.</para>
+ <para>Note that the bitbake command, when not using --buildfile, accepts a <varname>PROVIDER</varname>, not a filename or anything else. By default, a .bb generally PROVIDES its packagename, packagename-version, and packagename-version-revision.</para>
+ <screen><prompt>$ </prompt>bitbake blah</screen>
+ <screen><prompt>$ </prompt>bitbake blah-1.0</screen>
+ <screen><prompt>$ </prompt>bitbake blah-1.0-r0</screen>
+ <screen><prompt>$ </prompt>bitbake -c clean blah</screen>
+ <screen><prompt>$ </prompt>bitbake virtual/whatever</screen>
+ <screen><prompt>$ </prompt>bitbake -c clean virtual/whatever</screen>
+ </example>
+ </para>
+ </section>
+ <section>
+ <title>Metadata</title>
+ <para>As you may have seen in the usage information, or in the information about .bb files, the BBFILES variable is how the bitbake tool locates its files. This variable is a space seperated list of files that are available, and supports wildcards.
+ <example>
+ <title>Setting BBFILES</title>
+ <programlisting><varname>BBFILES</varname> = "/path/to/bbfiles/*.bb"</programlisting>
+ </example></para>
+ <para>With regard to dependencies, it expects the .bb to define a <varname>DEPENDS</varname> variable, which contains a space seperated list of <quote>package names</quote>, which themselves are the <varname>PN</varname> variable. The <varname>PN</varname> variable is, in general, by default, set to a component of the .bb filename.</para>
+ <example>
+ <title>Depending on another .bb</title>
+ <para>a.bb:
+ <screen>PN = "package-a"
+ DEPENDS += "package-b"</screen>
+ </para>
+ <para>b.bb:
+ <screen>PN = "package-b"</screen>
+ </para>
+ </example>
+ <example>
+ <title>Using PROVIDES</title>
+ <para>This example shows the usage of the PROVIDES variable, which allows a given .bb to specify what functionality it provides.</para>
+ <para>package1.bb:
+ <screen>PROVIDES += "virtual/package"</screen>
+ </para>
+ <para>package2.bb:
+ <screen>DEPENDS += "virtual/package"</screen>
+ </para>
+ <para>package3.bb:
+ <screen>PROVIDES += "virtual/package"</screen>
+ </para>
+ <para>As you can see, here there are two different .bb's that provide the same functionality (virtual/package). Clearly, there needs to be a way for the person running bitbake to control which of those providers gets used. There is, indeed, such a way.</para>
+ <para>The following would go into a .conf file, to select package1:
+ <screen>PREFERRED_PROVIDER_virtual/package = "package1"</screen>
+ </para>
+ </example>
+ <example>
+ <title>Specifying version preference</title>
+ <para>When there are multiple <quote>versions</quote> of a given package, bitbake defaults to selecting the most recent version, unless otherwise specified. If the .bb in question has a <varname>DEFAULT_PREFERENCE</varname> set lower than the other .bb's (default is 0), then it will not be selected. This allows the person or persons maintaining the repository of .bb files to specify their preferences for the default selected version. In addition, the user can specify their preferences with regard to version.</para>
+ <para>If the first .bb is named <filename>a_1.1.bb</filename>, then the <varname>PN</varname> variable will be set to <quote>a</quote>, and the <varname>PV</varname> variable will be set to 1.1.</para>
+ <para>If we then have an <filename>a_1.2.bb</filename>, bitbake will choose 1.2 by default. However, if we define the following variable in a .conf that bitbake parses, we can change that.
+ <screen>PREFERRED_VERSION_a = "1.1"</screen>
+ </para>
+ </example>
+ <example>
+ <title>Using <quote>bbfile collections</quote></title>
+ <para>bbfile collections exist to allow the user to have multiple repositories of bbfiles that contain the same exact package. For example, one could easily use them to make one's own local copy of an upstream repository, but with custom modifications that one does not want upstream. Usage:</para>
+ <screen>BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
+BBFILE_COLLECTIONS = "upstream local"
+BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
+BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
+BBFILE_PRIORITY_upstream = "5"
+BBFILE_PRIORITY_local = "10"</screen>
+ </example>
+ </section>
+ </section>
+ </chapter>
+</book>
diff --git a/trunk/bitbake/lib/bb/__init__.py b/trunk/bitbake/lib/bb/__init__.py
new file mode 100644
index 000000000..07ad811f3
--- /dev/null
+++ b/trunk/bitbake/lib/bb/__init__.py
@@ -0,0 +1,1267 @@
+#!/usr/bin/python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake Build System Python Library
+
+Copyright (C) 2003 Holger Schurig
+Copyright (C) 2003, 2004 Chris Larson
+
+Based on Gentoo's portage.py.
+
+This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+"""
+
+__version__ = "1.3.0"
+
+__all__ = [
+
+ "debug",
+ "note",
+ "error",
+ "fatal",
+
+ "mkdirhier",
+ "movefile",
+
+ "tokenize",
+ "evaluate",
+ "flatten",
+ "relparse",
+ "ververify",
+ "isjustname",
+ "isspecific",
+ "pkgsplit",
+ "catpkgsplit",
+ "vercmp",
+ "pkgcmp",
+ "dep_parenreduce",
+ "dep_opconvert",
+ "digraph",
+
+# fetch
+ "decodeurl",
+ "encodeurl",
+
+# modules
+ "parse",
+ "data",
+ "event",
+ "build",
+ "fetch",
+ "make",
+ "manifest"
+ ]
+
+whitespace = '\t\n\x0b\x0c\r '
+lowercase = 'abcdefghijklmnopqrstuvwxyz'
+
+import sys, os, types, re, string
+
+#projectdir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
+projectdir = os.getcwd()
+
+debug_level = 0
+
+if "BBDEBUG" in os.environ:
+ level = int(os.environ["BBDEBUG"])
+ if level:
+ debug_level = level
+ else:
+ debug_level = 0
+
+class VarExpandError(Exception):
+ pass
+
+class MalformedUrl(Exception):
+ """Exception raised when encountering an invalid url"""
+
+
+#######################################################################
+#######################################################################
+#
+# SECTION: Debug
+#
+# PURPOSE: little functions to make yourself known
+#
+#######################################################################
+#######################################################################
+
+debug_prepend = ''
+
+
+def debug(lvl, *args):
+ if debug_level >= lvl:
+ print debug_prepend + 'DEBUG:', ''.join(args)
+
+def note(*args):
+ print debug_prepend + 'NOTE:', ''.join(args)
+
+def error(*args):
+ print debug_prepend + 'ERROR:', ''.join(args)
+
+def fatal(*args):
+ print debug_prepend + 'ERROR:', ''.join(args)
+ sys.exit(1)
+
+
+#######################################################################
+#######################################################################
+#
+# SECTION: File
+#
+# PURPOSE: Basic file and directory tree related functions
+#
+#######################################################################
+#######################################################################
+
+def mkdirhier(dir):
+ """Create a directory like 'mkdir -p', but does not complain if
+ directory already exists like os.makedirs
+ """
+
+ debug(3, "mkdirhier(%s)" % dir)
+ try:
+ os.makedirs(dir)
+ debug(2, "created " + dir)
+ except OSError, e:
+ if e.errno != 17: raise e
+
+
+#######################################################################
+
+import stat
+
+def movefile(src,dest,newmtime=None,sstat=None):
+ """Moves a file from src to dest, preserving all permissions and
+ attributes; mtime will be preserved even when moving across
+ filesystems. Returns true on success and false on failure. Move is
+ atomic.
+ """
+
+ #print "movefile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")"
+ try:
+ if not sstat:
+ sstat=os.lstat(src)
+ except Exception, e:
+ print "!!! Stating source file failed... movefile()"
+ print "!!!",e
+ return None
+
+ destexists=1
+ try:
+ dstat=os.lstat(dest)
+ except:
+ dstat=os.lstat(os.path.dirname(dest))
+ destexists=0
+
+ if destexists:
+ if stat.S_ISLNK(dstat[stat.ST_MODE]):
+ try:
+ os.unlink(dest)
+ destexists=0
+ except Exception, e:
+ pass
+
+ if stat.S_ISLNK(sstat[stat.ST_MODE]):
+ try:
+ target=os.readlink(src)
+ if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
+ os.unlink(dest)
+ os.symlink(target,dest)
+# os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ os.unlink(src)
+ return os.lstat(dest)
+ except Exception, e:
+ print "!!! failed to properly create symlink:"
+ print "!!!",dest,"->",target
+ print "!!!",e
+ return None
+
+ renamefailed=1
+ if sstat[stat.ST_DEV]==dstat[stat.ST_DEV]:
+ try:
+ ret=os.rename(src,dest)
+ renamefailed=0
+ except Exception, e:
+ import errno
+ if e[0]!=errno.EXDEV:
+ # Some random error.
+ print "!!! Failed to move",src,"to",dest
+ print "!!!",e
+ return None
+ # Invalid cross-device-link 'bind' mounted or actually Cross-Device
+
+ if renamefailed:
+ didcopy=0
+ if stat.S_ISREG(sstat[stat.ST_MODE]):
+ try: # For safety copy then move it over.
+ shutil.copyfile(src,dest+"#new")
+ os.rename(dest+"#new",dest)
+ didcopy=1
+ except Exception, e:
+ print '!!! copy',src,'->',dest,'failed.'
+ print "!!!",e
+ return None
+ else:
+ #we don't yet handle special, so we need to fall back to /bin/mv
+ a=getstatusoutput("/bin/mv -f "+"'"+src+"' '"+dest+"'")
+ if a[0]!=0:
+ print "!!! Failed to move special file:"
+ print "!!! '"+src+"' to '"+dest+"'"
+ print "!!!",a
+ return None # failure
+ try:
+ if didcopy:
+ missingos.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
+ os.unlink(src)
+ except Exception, e:
+ print "!!! Failed to chown/chmod/unlink in movefile()"
+ print "!!!",dest
+ print "!!!",e
+ return None
+
+ if newmtime:
+ os.utime(dest,(newmtime,newmtime))
+ else:
+ os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
+ newmtime=sstat[stat.ST_MTIME]
+ return newmtime
+
+
+
+#######################################################################
+#######################################################################
+#
+# SECTION: Download
+#
+# PURPOSE: Download via HTTP, FTP, CVS, BITKEEPER, handling of MD5-signatures
+# and mirrors
+#
+#######################################################################
+#######################################################################
+
+def decodeurl(url):
+ """Decodes an URL into the tokens (scheme, network location, path,
+ user, password, parameters).
+
+ >>> decodeurl("http://www.google.com/index.html")
+ ('http', 'www.google.com', '/index.html', '', '', {})
+
+ CVS url with username, host and cvsroot. The cvs module to check out is in the
+ parameters:
+
+ >>> decodeurl("cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg")
+ ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'})
+
+ Dito, but this time the username has a password part. And we also request a special tag
+ to check out.
+
+ >>> decodeurl("cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;module=familiar/dist/ipkg;tag=V0-99-81")
+ ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'})
+ """
+
+ m = re.compile('(?P<type>[^:]*)://((?P<user>.+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
+ if not m:
+ raise MalformedUrl(url)
+
+ type = m.group('type')
+ location = m.group('location')
+ if not location:
+ raise MalformedUrl(url)
+ user = m.group('user')
+ parm = m.group('parm')
+ m = re.compile('(?P<host>[^/;]+)(?P<path>/[^;]+)').match(location)
+ if m:
+ host = m.group('host')
+ path = m.group('path')
+ else:
+ host = ""
+ path = location
+ if user:
+ m = re.compile('(?P<user>[^:]+)(:?(?P<pswd>.*))').match(user)
+ if m:
+ user = m.group('user')
+ pswd = m.group('pswd')
+ else:
+ user = ''
+ pswd = ''
+
+ p = {}
+ if parm:
+ for s in parm.split(';'):
+ s1,s2 = s.split('=')
+ p[s1] = s2
+
+ return (type, host, path, user, pswd, p)
+
+#######################################################################
+
+def encodeurl(decoded):
+ """Encodes a URL from tokens (scheme, network location, path,
+ user, password, parameters).
+
+ >>> encodeurl(['http', 'www.google.com', '/index.html', '', '', {}])
+ 'http://www.google.com/index.html'
+
+ CVS with username, host and cvsroot. The cvs module to check out is in the
+ parameters:
+
+ >>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'}])
+ 'cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg'
+
+ Dito, but this time the username has a password part. And we also request a special tag
+ to check out.
+
+ >>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'}])
+ 'cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg'
+ """
+
+ (type, host, path, user, pswd, p) = decoded
+
+ if not type or not path:
+ fatal("invalid or missing parameters for url encoding")
+ url = '%s://' % type
+ if user:
+ url += "%s" % user
+ if pswd:
+ url += ":%s" % pswd
+ url += "@"
+ if host:
+ url += "%s" % host
+ url += "%s" % path
+ if p:
+ for parm in p.keys():
+ url += ";%s=%s" % (parm, p[parm])
+
+ return url
+
+#######################################################################
+
+def which(path, item, direction = 0):
+ """Useful function for locating a file in a PATH"""
+ found = ""
+ for p in (path or "").split(':'):
+ if os.path.exists(os.path.join(p, item)):
+ found = os.path.join(p, item)
+ if direction == 0:
+ break
+ return found
+
+#######################################################################
+
+
+
+
+#######################################################################
+#######################################################################
+#
+# SECTION: Dependency
+#
+# PURPOSE: Compare build & run dependencies
+#
+#######################################################################
+#######################################################################
+
+def tokenize(mystring):
+ """Breaks a string like 'foo? (bar) oni? (blah (blah))' into (possibly embedded) lists:
+
+ >>> tokenize("x")
+ ['x']
+ >>> tokenize("x y")
+ ['x', 'y']
+ >>> tokenize("(x y)")
+ [['x', 'y']]
+ >>> tokenize("(x y) b c")
+ [['x', 'y'], 'b', 'c']
+ >>> tokenize("foo? (bar) oni? (blah (blah))")
+ ['foo?', ['bar'], 'oni?', ['blah', ['blah']]]
+ >>> tokenize("sys-apps/linux-headers nls? (sys-devel/gettext)")
+ ['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']]
+ """
+
+ newtokens = []
+ curlist = newtokens
+ prevlists = []
+ level = 0
+ accum = ""
+ for x in mystring:
+ if x=="(":
+ if accum:
+ curlist.append(accum)
+ accum=""
+ prevlists.append(curlist)
+ curlist=[]
+ level=level+1
+ elif x==")":
+ if accum:
+ curlist.append(accum)
+ accum=""
+ if level==0:
+ print "!!! tokenizer: Unmatched left parenthesis in:\n'"+mystring+"'"
+ return None
+ newlist=curlist
+ curlist=prevlists.pop()
+ curlist.append(newlist)
+ level=level-1
+ elif x in whitespace:
+ if accum:
+ curlist.append(accum)
+ accum=""
+ else:
+ accum=accum+x
+ if accum:
+ curlist.append(accum)
+ if (level!=0):
+ print "!!! tokenizer: Exiting with unterminated parenthesis in:\n'"+mystring+"'"
+ return None
+ return newtokens
+
+
+#######################################################################
+
+def evaluate(tokens,mydefines,allon=0):
+ """Removes tokens based on whether conditional definitions exist or not.
+ Recognizes !
+
+ >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {})
+ ['sys-apps/linux-headers']
+
+ Negate the flag:
+
+ >>> evaluate(['sys-apps/linux-headers', '!nls?', ['sys-devel/gettext']], {})
+ ['sys-apps/linux-headers', ['sys-devel/gettext']]
+
+ Define 'nls':
+
+ >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {"nls":1})
+ ['sys-apps/linux-headers', ['sys-devel/gettext']]
+
+ Turn allon on:
+
+ >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}, True)
+ ['sys-apps/linux-headers', ['sys-devel/gettext']]
+ """
+
+ if tokens == None:
+ return None
+ mytokens = tokens + [] # this copies the list
+ pos = 0
+ while pos < len(mytokens):
+ if type(mytokens[pos]) == types.ListType:
+ evaluate(mytokens[pos], mydefines)
+ if not len(mytokens[pos]):
+ del mytokens[pos]
+ continue
+ elif mytokens[pos][-1] == "?":
+ cur = mytokens[pos][:-1]
+ del mytokens[pos]
+ if allon:
+ if cur[0] == "!":
+ del mytokens[pos]
+ else:
+ if cur[0] == "!":
+ if (cur[1:] in mydefines) and (pos < len(mytokens)):
+ del mytokens[pos]
+ continue
+ elif (cur not in mydefines) and (pos < len(mytokens)):
+ del mytokens[pos]
+ continue
+ pos = pos + 1
+ return mytokens
+
+
+#######################################################################
+
+def flatten(mytokens):
+ """Converts nested arrays into a flat arrays:
+
+ >>> flatten([1,[2,3]])
+ [1, 2, 3]
+ >>> flatten(['sys-apps/linux-headers', ['sys-devel/gettext']])
+ ['sys-apps/linux-headers', 'sys-devel/gettext']
+ """
+
+ newlist=[]
+ for x in mytokens:
+ if type(x)==types.ListType:
+ newlist.extend(flatten(x))
+ else:
+ newlist.append(x)
+ return newlist
+
+
+#######################################################################
+
+_package_weights_ = {"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} # dicts are unordered
+_package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list
+
+def relparse(myver):
+ """Parses the last elements of a version number into a triplet, that can
+ later be compared:
+
+ >>> relparse('1.2_pre3')
+ [1.2, -2, 3.0]
+ >>> relparse('1.2b')
+ [1.2, 98, 0]
+ >>> relparse('1.2')
+ [1.2, 0, 0]
+ """
+
+ number = 0
+ p1 = 0
+ p2 = 0
+ mynewver = myver.split('_')
+ if len(mynewver)==2:
+ # an _package_weights_
+ number = float(mynewver[0])
+ match = 0
+ for x in _package_ends_:
+ elen = len(x)
+ if mynewver[1][:elen] == x:
+ match = 1
+ p1 = _package_weights_[x]
+ try:
+ p2 = float(mynewver[1][elen:])
+ except:
+ p2 = 0
+ break
+ if not match:
+ # normal number or number with letter at end
+ divider = len(myver)-1
+ if myver[divider:] not in "1234567890":
+ # letter at end
+ p1 = ord(myver[divider:])
+ number = float(myver[0:divider])
+ else:
+ number = float(myver)
+ else:
+ # normal number or number with letter at end
+ divider = len(myver)-1
+ if myver[divider:] not in "1234567890":
+ #letter at end
+ p1 = ord(myver[divider:])
+ number = float(myver[0:divider])
+ else:
+ number = float(myver)
+ return [number,p1,p2]
+
+
+#######################################################################
+
+__ververify_cache__ = {}
+
+def ververify(myorigval,silent=1):
+ """Returns 1 if given a valid version string, els 0. Valid versions are in the format
+
+ <v1>.<v2>...<vx>[a-z,_{_package_weights_}[vy]]
+
+ >>> ververify('2.4.20')
+ 1
+ >>> ververify('2.4..20') # two dots
+ 0
+ >>> ververify('2.x.20') # 'x' is not numeric
+ 0
+ >>> ververify('2.4.20a')
+ 1
+ >>> ververify('2.4.20cvs') # only one trailing letter
+ 0
+ >>> ververify('1a')
+ 1
+ >>> ververify('test_a') # no version at all
+ 0
+ >>> ververify('2.4.20_beta1')
+ 1
+ >>> ververify('2.4.20_beta')
+ 1
+ >>> ververify('2.4.20_wrongext') # _wrongext is no valid trailer
+ 0
+ """
+
+ # Lookup the cache first
+ try:
+ return __ververify_cache__[myorigval]
+ except KeyError:
+ pass
+
+ if len(myorigval) == 0:
+ if not silent:
+ error("package version is empty")
+ __ververify_cache__[myorigval] = 0
+ return 0
+ myval = myorigval.split('.')
+ if len(myval)==0:
+ if not silent:
+ error("package name has empty version string")
+ __ververify_cache__[myorigval] = 0
+ return 0
+ # all but the last version must be a numeric
+ for x in myval[:-1]:
+ if not len(x):
+ if not silent:
+ error("package version has two points in a row")
+ __ververify_cache__[myorigval] = 0
+ return 0
+ try:
+ foo = int(x)
+ except:
+ if not silent:
+ error("package version contains non-numeric '"+x+"'")
+ __ververify_cache__[myorigval] = 0
+ return 0
+ if not len(myval[-1]):
+ if not silent:
+ error("package version has trailing dot")
+ __ververify_cache__[myorigval] = 0
+ return 0
+ try:
+ foo = int(myval[-1])
+ __ververify_cache__[myorigval] = 1
+ return 1
+ except:
+ pass
+
+ # ok, our last component is not a plain number or blank, let's continue
+ if myval[-1][-1] in lowercase:
+ try:
+ foo = int(myval[-1][:-1])
+ return 1
+ __ververify_cache__[myorigval] = 1
+ # 1a, 2.0b, etc.
+ except:
+ pass
+ # ok, maybe we have a 1_alpha or 1_beta2; let's see
+ ep=string.split(myval[-1],"_")
+ if len(ep)!= 2:
+ if not silent:
+ error("package version has more than one letter at then end")
+ __ververify_cache__[myorigval] = 0
+ return 0
+ try:
+ foo = string.atoi(ep[0])
+ except:
+ # this needs to be numeric, i.e. the "1" in "1_alpha"
+ if not silent:
+ error("package version must have numeric part before the '_'")
+ __ververify_cache__[myorigval] = 0
+ return 0
+
+ for mye in _package_ends_:
+ if ep[1][0:len(mye)] == mye:
+ if len(mye) == len(ep[1]):
+ # no trailing numeric is ok
+ __ververify_cache__[myorigval] = 1
+ return 1
+ else:
+ try:
+ foo = string.atoi(ep[1][len(mye):])
+ __ververify_cache__[myorigval] = 1
+ return 1
+ except:
+ # if no _package_weights_ work, *then* we return 0
+ pass
+ if not silent:
+ error("package version extension after '_' is invalid")
+ __ververify_cache__[myorigval] = 0
+ return 0
+
+
+def isjustname(mypkg):
+ myparts = string.split(mypkg,'-')
+ for x in myparts:
+ if ververify(x):
+ return 0
+ return 1
+
+
+_isspecific_cache_={}
+
+def isspecific(mypkg):
+ "now supports packages with no category"
+ try:
+ return __isspecific_cache__[mypkg]
+ except:
+ pass
+
+ mysplit = string.split(mypkg,"/")
+ if not isjustname(mysplit[-1]):
+ __isspecific_cache__[mypkg] = 1
+ return 1
+ __isspecific_cache__[mypkg] = 0
+ return 0
+
+
+#######################################################################
+
+__pkgsplit_cache__={}
+
+def pkgsplit(mypkg, silent=1):
+
+ """This function can be used as a package verification function. If
+ it is a valid name, pkgsplit will return a list containing:
+ [pkgname, pkgversion(norev), pkgrev ].
+
+ >>> pkgsplit('')
+ >>> pkgsplit('x')
+ >>> pkgsplit('x-')
+ >>> pkgsplit('-1')
+ >>> pkgsplit('glibc-1.2-8.9-r7')
+ >>> pkgsplit('glibc-2.2.5-r7')
+ ['glibc', '2.2.5', 'r7']
+ >>> pkgsplit('foo-1.2-1')
+ >>> pkgsplit('Mesa-3.0')
+ ['Mesa', '3.0', 'r0']
+ """
+
+ try:
+ return __pkgsplit_cache__[mypkg]
+ except KeyError:
+ pass
+
+ myparts = string.split(mypkg,'-')
+ if len(myparts) < 2:
+ if not silent:
+ error("package name without name or version part")
+ __pkgsplit_cache__[mypkg] = None
+ return None
+ for x in myparts:
+ if len(x) == 0:
+ if not silent:
+ error("package name with empty name or version part")
+ __pkgsplit_cache__[mypkg] = None
+ return None
+ # verify rev
+ revok = 0
+ myrev = myparts[-1]
+ ververify(myrev, silent)
+ if len(myrev) and myrev[0] == "r":
+ try:
+ string.atoi(myrev[1:])
+ revok = 1
+ except:
+ pass
+ if revok:
+ if ververify(myparts[-2]):
+ if len(myparts) == 2:
+ __pkgsplit_cache__[mypkg] = None
+ return None
+ else:
+ for x in myparts[:-2]:
+ if ververify(x):
+ __pkgsplit_cache__[mypkg]=None
+ return None
+ # names can't have versiony looking parts
+ myval=[string.join(myparts[:-2],"-"),myparts[-2],myparts[-1]]
+ __pkgsplit_cache__[mypkg]=myval
+ return myval
+ else:
+ __pkgsplit_cache__[mypkg] = None
+ return None
+
+ elif ververify(myparts[-1],silent):
+ if len(myparts)==1:
+ if not silent:
+ print "!!! Name error in",mypkg+": missing name part."
+ __pkgsplit_cache__[mypkg]=None
+ return None
+ else:
+ for x in myparts[:-1]:
+ if ververify(x):
+ if not silent: error("package name has multiple version parts")
+ __pkgsplit_cache__[mypkg] = None
+ return None
+ myval = [string.join(myparts[:-1],"-"), myparts[-1],"r0"]
+ __pkgsplit_cache__[mypkg] = myval
+ return myval
+ else:
+ __pkgsplit_cache__[mypkg] = None
+ return None
+
+
+#######################################################################
+
+__catpkgsplit_cache__ = {}
+
+def catpkgsplit(mydata,silent=1):
+ """returns [cat, pkgname, version, rev ]
+
+ >>> catpkgsplit('sys-libs/glibc-1.2-r7')
+ ['sys-libs', 'glibc', '1.2', 'r7']
+ >>> catpkgsplit('glibc-1.2-r7')
+ [None, 'glibc', '1.2', 'r7']
+ """
+
+ try:
+ return __catpkgsplit_cache__[mydata]
+ except KeyError:
+ pass
+
+ cat = os.path.basename(os.path.dirname(mydata))
+ mydata = os.path.join(cat, os.path.basename(mydata))
+ if mydata[-3:] == '.bb':
+ mydata = mydata[:-3]
+
+ mysplit = mydata.split("/")
+ p_split = None
+ splitlen = len(mysplit)
+ if splitlen == 1:
+ retval = [None]
+ p_split = pkgsplit(mydata,silent)
+ else:
+ retval = [mysplit[splitlen - 2]]
+ p_split = pkgsplit(mysplit[splitlen - 1],silent)
+ if not p_split:
+ __catpkgsplit_cache__[mydata] = None
+ return None
+ retval.extend(p_split)
+ __catpkgsplit_cache__[mydata] = retval
+ return retval
+
+
+#######################################################################
+
+__vercmp_cache__ = {}
+
+def vercmp(val1,val2):
+ """This takes two version strings and returns an integer to tell you whether
+ the versions are the same, val1>val2 or val2>val1.
+
+ >>> vercmp('1', '2')
+ -1.0
+ >>> vercmp('2', '1')
+ 1.0
+ >>> vercmp('1', '1.0')
+ 0
+ >>> vercmp('1', '1.1')
+ -1.0
+ >>> vercmp('1.1', '1_p2')
+ 1.0
+ """
+
+ # quick short-circuit
+ if val1 == val2:
+ return 0
+ valkey = val1+" "+val2
+
+ # cache lookup
+ try:
+ return __vercmp_cache__[valkey]
+ try:
+ return - __vercmp_cache__[val2+" "+val1]
+ except KeyError:
+ pass
+ except KeyError:
+ pass
+
+ # consider 1_p2 vc 1.1
+ # after expansion will become (1_p2,0) vc (1,1)
+ # then 1_p2 is compared with 1 before 0 is compared with 1
+ # to solve the bug we need to convert it to (1,0_p2)
+ # by splitting _prepart part and adding it back _after_expansion
+
+ val1_prepart = val2_prepart = ''
+ if val1.count('_'):
+ val1, val1_prepart = val1.split('_', 1)
+ if val2.count('_'):
+ val2, val2_prepart = val2.split('_', 1)
+
+ # replace '-' by '.'
+ # FIXME: Is it needed? can val1/2 contain '-'?
+
+ val1 = string.split(val1,'-')
+ if len(val1) == 2:
+ val1[0] = val1[0] +"."+ val1[1]
+ val2 = string.split(val2,'-')
+ if len(val2) == 2:
+ val2[0] = val2[0] +"."+ val2[1]
+
+ val1 = string.split(val1[0],'.')
+ val2 = string.split(val2[0],'.')
+
+ # add back decimal point so that .03 does not become "3" !
+ for x in range(1,len(val1)):
+ if val1[x][0] == '0' :
+ val1[x] = '.' + val1[x]
+ for x in range(1,len(val2)):
+ if val2[x][0] == '0' :
+ val2[x] = '.' + val2[x]
+
+ # extend varion numbers
+ if len(val2) < len(val1):
+ val2.extend(["0"]*(len(val1)-len(val2)))
+ elif len(val1) < len(val2):
+ val1.extend(["0"]*(len(val2)-len(val1)))
+
+ # add back _prepart tails
+ if val1_prepart:
+ val1[-1] += '_' + val1_prepart
+ if val2_prepart:
+ val2[-1] += '_' + val2_prepart
+ # The above code will extend version numbers out so they
+ # have the same number of digits.
+ for x in range(0,len(val1)):
+ cmp1 = relparse(val1[x])
+ cmp2 = relparse(val2[x])
+ for y in range(0,3):
+ myret = cmp1[y] - cmp2[y]
+ if myret != 0:
+ __vercmp_cache__[valkey] = myret
+ return myret
+ __vercmp_cache__[valkey] = 0
+ return 0
+
+
+#######################################################################
+
+def pkgcmp(pkg1,pkg2):
+ """ Compares two packages, which should have been split via
+ pkgsplit(). if the return value val is less than zero, then pkg2 is
+ newer than pkg1, zero if equal and positive if older.
+
+ >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r7'])
+ 0
+ >>> pkgcmp(['glibc', '2.2.5', 'r4'], ['glibc', '2.2.5', 'r7'])
+ -1
+ >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r2'])
+ 1
+ """
+
+ mycmp = vercmp(pkg1[1],pkg2[1])
+ if mycmp > 0:
+ return 1
+ if mycmp < 0:
+ return -1
+ r1=string.atoi(pkg1[2][1:])
+ r2=string.atoi(pkg2[2][1:])
+ if r1 > r2:
+ return 1
+ if r2 > r1:
+ return -1
+ return 0
+
+
+#######################################################################
+
+def dep_parenreduce(mysplit, mypos=0):
+ """Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists:
+
+ >>> dep_parenreduce([''])
+ ['']
+ >>> dep_parenreduce(['1', '2', '3'])
+ ['1', '2', '3']
+ >>> dep_parenreduce(['1', '(', '2', '3', ')', '4'])
+ ['1', ['2', '3'], '4']
+ """
+
+ while mypos < len(mysplit):
+ if mysplit[mypos] == "(":
+ firstpos = mypos
+ mypos = mypos + 1
+ while mypos < len(mysplit):
+ if mysplit[mypos] == ")":
+ mysplit[firstpos:mypos+1] = [mysplit[firstpos+1:mypos]]
+ mypos = firstpos
+ break
+ elif mysplit[mypos] == "(":
+ # recurse
+ mysplit = dep_parenreduce(mysplit,mypos)
+ mypos = mypos + 1
+ mypos = mypos + 1
+ return mysplit
+
+
+def dep_opconvert(mysplit, myuse):
+ "Does dependency operator conversion"
+
+ mypos = 0
+ newsplit = []
+ while mypos < len(mysplit):
+ if type(mysplit[mypos]) == types.ListType:
+ newsplit.append(dep_opconvert(mysplit[mypos],myuse))
+ mypos += 1
+ elif mysplit[mypos] == ")":
+ # mismatched paren, error
+ return None
+ elif mysplit[mypos]=="||":
+ if ((mypos+1)>=len(mysplit)) or (type(mysplit[mypos+1])!=types.ListType):
+ # || must be followed by paren'd list
+ return None
+ try:
+ mynew = dep_opconvert(mysplit[mypos+1],myuse)
+ except Exception, e:
+ error("unable to satisfy OR dependancy: " + string.join(mysplit," || "))
+ raise e
+ mynew[0:0] = ["||"]
+ newsplit.append(mynew)
+ mypos += 2
+ elif mysplit[mypos][-1] == "?":
+ # use clause, i.e "gnome? ( foo bar )"
+ # this is a quick and dirty hack so that repoman can enable all USE vars:
+ if (len(myuse) == 1) and (myuse[0] == "*"):
+ # enable it even if it's ! (for repoman) but kill it if it's
+ # an arch variable that isn't for this arch. XXX Sparc64?
+ if (mysplit[mypos][:-1] not in settings.usemask) or \
+ (mysplit[mypos][:-1]==settings["ARCH"]):
+ enabled=1
+ else:
+ enabled=0
+ else:
+ if mysplit[mypos][0] == "!":
+ myusevar = mysplit[mypos][1:-1]
+ enabled = not myusevar in myuse
+ #if myusevar in myuse:
+ # enabled = 0
+ #else:
+ # enabled = 1
+ else:
+ myusevar=mysplit[mypos][:-1]
+ enabled = myusevar in myuse
+ #if myusevar in myuse:
+ # enabled=1
+ #else:
+ # enabled=0
+ if (mypos +2 < len(mysplit)) and (mysplit[mypos+2] == ":"):
+ # colon mode
+ if enabled:
+ # choose the first option
+ if type(mysplit[mypos+1]) == types.ListType:
+ newsplit.append(dep_opconvert(mysplit[mypos+1],myuse))
+ else:
+ newsplit.append(mysplit[mypos+1])
+ else:
+ # choose the alternate option
+ if type(mysplit[mypos+1]) == types.ListType:
+ newsplit.append(dep_opconvert(mysplit[mypos+3],myuse))
+ else:
+ newsplit.append(mysplit[mypos+3])
+ mypos += 4
+ else:
+ # normal use mode
+ if enabled:
+ if type(mysplit[mypos+1]) == types.ListType:
+ newsplit.append(dep_opconvert(mysplit[mypos+1],myuse))
+ else:
+ newsplit.append(mysplit[mypos+1])
+ # otherwise, continue
+ mypos += 2
+ else:
+ # normal item
+ newsplit.append(mysplit[mypos])
+ mypos += 1
+ return newsplit
+
+class digraph:
+ """beautiful directed graph object"""
+
+ def __init__(self):
+ self.dict={}
+ #okeys = keys, in order they were added (to optimize firstzero() ordering)
+ self.okeys=[]
+ self.__callback_cache=[]
+
+ def __str__(self):
+ str = ""
+ for key in self.okeys:
+ str += "%s:\t%s\n" % (key, self.dict[key][1])
+ return str
+
+ def addnode(self,mykey,myparent):
+ if not mykey in self.dict:
+ self.okeys.append(mykey)
+ if myparent==None:
+ self.dict[mykey]=[0,[]]
+ else:
+ self.dict[mykey]=[0,[myparent]]
+ self.dict[myparent][0]=self.dict[myparent][0]+1
+ return
+ if myparent and (not myparent in self.dict[mykey][1]):
+ self.dict[mykey][1].append(myparent)
+ self.dict[myparent][0]=self.dict[myparent][0]+1
+
+ def delnode(self,mykey, ref = 1):
+ """Delete a node
+
+ If ref is 1, remove references to this node from other nodes.
+ If ref is 2, remove nodes that reference this node."""
+ if not mykey in self.dict:
+ return
+ for x in self.dict[mykey][1]:
+ self.dict[x][0]=self.dict[x][0]-1
+ del self.dict[mykey]
+ while 1:
+ try:
+ self.okeys.remove(mykey)
+ except ValueError:
+ break
+ if ref:
+ __kill = []
+ for k in self.okeys:
+ if mykey in self.dict[k][1]:
+ if ref == 1 or ref == 2:
+ self.dict[k][1].remove(mykey)
+ if ref == 2:
+ __kill.append(k)
+ for l in __kill:
+ self.delnode(l, ref)
+
+ def allnodes(self):
+ "returns all nodes in the dictionary"
+ return self.dict.keys()
+
+ def firstzero(self):
+ "returns first node with zero references, or NULL if no such node exists"
+ for x in self.okeys:
+ if self.dict[x][0]==0:
+ return x
+ return None
+
+ def firstnonzero(self):
+ "returns first node with nonzero references, or NULL if no such node exists"
+ for x in self.okeys:
+ if self.dict[x][0]!=0:
+ return x
+ return None
+
+
+ def allzeros(self):
+ "returns all nodes with zero references, or NULL if no such node exists"
+ zerolist = []
+ for x in self.dict.keys():
+ if self.dict[x][0]==0:
+ zerolist.append(x)
+ return zerolist
+
+ def hasallzeros(self):
+ "returns 0/1, Are all nodes zeros? 1 : 0"
+ zerolist = []
+ for x in self.dict.keys():
+ if self.dict[x][0]!=0:
+ return 0
+ return 1
+
+ def empty(self):
+ if len(self.dict)==0:
+ return 1
+ return 0
+
+ def hasnode(self,mynode):
+ return mynode in self.dict
+
+ def getparents(self, item):
+ if not self.hasnode(item):
+ return []
+ return self.dict[item][1]
+
+ def getchildren(self, item):
+ if not self.hasnode(item):
+ return []
+ children = [i for i in self.okeys if item in self.getparents(i)]
+ return children
+
+ def walkdown(self, item, callback, debug = None, usecache = False):
+ if not self.hasnode(item):
+ return 0
+
+ if usecache:
+ if self.__callback_cache.count(item):
+ if debug:
+ print "hit cache for item: %s" % item
+ return 1
+
+ parents = self.getparents(item)
+ children = self.getchildren(item)
+ for p in parents:
+ if p in children:
+# print "%s is both parent and child of %s" % (p, item)
+ if usecache:
+ self.__callback_cache.append(p)
+ ret = callback(self, p)
+ if ret == 0:
+ return 0
+ continue
+ if item == p:
+ print "eek, i'm my own parent!"
+ return 0
+ if debug:
+ print "item: %s, p: %s" % (item, p)
+ ret = self.walkdown(p, callback, debug, usecache)
+ if ret == 0:
+ return 0
+ if usecache:
+ self.__callback_cache.append(item)
+ return callback(self, item)
+
+ def walkup(self, item, callback):
+ if not self.hasnode(item):
+ return 0
+
+ parents = self.getparents(item)
+ children = self.getchildren(item)
+ for c in children:
+ if c in parents:
+ ret = callback(self, item)
+ if ret == 0:
+ return 0
+ continue
+ if item == c:
+ print "eek, i'm my own child!"
+ return 0
+ ret = self.walkup(c, callback)
+ if ret == 0:
+ return 0
+ return callback(self, item)
+
+ def copy(self):
+ mygraph=digraph()
+ for x in self.dict.keys():
+ mygraph.dict[x]=self.dict[x][:]
+ mygraph.okeys=self.okeys[:]
+ return mygraph
+
+#######################################################################
+#######################################################################
+#
+# SECTION: Config
+#
+# PURPOSE: Reading and handling of system/target-specific/local configuration
+# reading of package configuration
+#
+#######################################################################
+#######################################################################
+
+def reader(cfgfile, feeder):
+ """Generic configuration file reader that opens a file, reads the lines,
+ handles continuation lines, comments, empty lines and feed all read lines
+ into the function feeder(lineno, line).
+ """
+
+ f = open(cfgfile,'r')
+ lineno = 0
+ while 1:
+ lineno = lineno + 1
+ s = f.readline()
+ if not s: break
+ w = s.strip()
+ if not w: continue # skip empty lines
+ s = s.rstrip()
+ if s[0] == '#': continue # skip comments
+ while s[-1] == '\\':
+ s2 = f.readline()[:-1].strip()
+ s = s[:-1] + s2
+ feeder(lineno, s)
+
+if __name__ == "__main__":
+ import doctest, bb
+ doctest.testmod(bb)
diff --git a/trunk/bitbake/lib/bb/build.py b/trunk/bitbake/lib/bb/build.py
new file mode 100644
index 000000000..599b45d9d
--- /dev/null
+++ b/trunk/bitbake/lib/bb/build.py
@@ -0,0 +1,395 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake 'Build' implementation
+
+Core code for function execution and task handling in the
+BitBake build tools.
+
+Copyright (C) 2003, 2004 Chris Larson
+
+Based on Gentoo's portage.py.
+
+This program 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 program 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
+
+Based on functions from the base bb module, Copyright 2003 Holger Schurig
+"""
+
+from bb import debug, data, fetch, fatal, error, note, event, mkdirhier
+import bb, os
+
+# data holds flags and function name for a given task
+_task_data = data.init()
+
+# graph represents task interdependencies
+_task_graph = bb.digraph()
+
+# stack represents execution order, excepting dependencies
+_task_stack = []
+
+# events
+class FuncFailed(Exception):
+ """Executed function failed"""
+
+class EventException(Exception):
+ """Exception which is associated with an Event."""
+
+ def __init__(self, msg, event):
+ self.args = msg, event
+
+class TaskBase(event.Event):
+ """Base class for task events"""
+
+ def __init__(self, t, d ):
+ self._task = t
+ event.Event.__init__(self, d)
+
+ def getTask(self):
+ return self._task
+
+ def setTask(self, task):
+ self._task = task
+
+ task = property(getTask, setTask, None, "task property")
+
+class TaskStarted(TaskBase):
+ """Task execution started"""
+
+class TaskSucceeded(TaskBase):
+ """Task execution completed"""
+
+class TaskFailed(TaskBase):
+ """Task execution failed"""
+
+class InvalidTask(TaskBase):
+ """Invalid Task"""
+
+# functions
+
+def init(data):
+ global _task_data, _task_graph, _task_stack
+ _task_data = data.init()
+ _task_graph = bb.digraph()
+ _task_stack = []
+
+
+def exec_func(func, d, dirs = None):
+ """Execute an BB 'function'"""
+
+ body = data.getVar(func, d)
+ if not body:
+ return
+
+ if not dirs:
+ dirs = (data.getVarFlag(func, 'dirs', d) or "").split()
+ for adir in dirs:
+ adir = data.expand(adir, d)
+ mkdirhier(adir)
+
+ if len(dirs) > 0:
+ adir = dirs[-1]
+ else:
+ adir = data.getVar('B', d, 1)
+
+ adir = data.expand(adir, d)
+
+ try:
+ prevdir = os.getcwd()
+ except OSError:
+ prevdir = data.expand('${TOPDIR}', d)
+ if adir and os.access(adir, os.F_OK):
+ os.chdir(adir)
+
+ if data.getVarFlag(func, "python", d):
+ exec_func_python(func, d)
+ else:
+ exec_func_shell(func, d)
+
+ if os.path.exists(prevdir):
+ os.chdir(prevdir)
+
+def exec_func_python(func, d):
+ """Execute a python BB 'function'"""
+ import re, os
+
+ tmp = "def " + func + "():\n%s" % data.getVar(func, d)
+ comp = compile(tmp + '\n' + func + '()', bb.data.getVar('FILE', d, 1) + ':' + func, "exec")
+ prevdir = os.getcwd()
+ g = {} # globals
+ g['bb'] = bb
+ g['os'] = os
+ g['d'] = d
+ exec comp in g
+ if os.path.exists(prevdir):
+ os.chdir(prevdir)
+
+def exec_func_shell(func, d):
+ """Execute a shell BB 'function' Returns true if execution was successful.
+
+ For this, it creates a bash shell script in the tmp dectory, writes the local
+ data into it and finally executes. The output of the shell will end in a log file and stdout.
+
+ Note on directory behavior. The 'dirs' varflag should contain a list
+ of the directories you need created prior to execution. The last
+ item in the list is where we will chdir/cd to.
+ """
+ import sys
+
+ deps = data.getVarFlag(func, 'deps', d)
+ check = data.getVarFlag(func, 'check', d)
+ if check in globals():
+ if globals()[check](func, deps):
+ return
+
+ global logfile
+ t = data.getVar('T', d, 1)
+ if not t:
+ return 0
+ mkdirhier(t)
+ logfile = "%s/log.%s.%s" % (t, func, str(os.getpid()))
+ runfile = "%s/run.%s.%s" % (t, func, str(os.getpid()))
+
+ f = open(runfile, "w")
+ f.write("#!/bin/sh -e\n")
+ if bb.debug_level > 0: f.write("set -x\n")
+ data.emit_env(f, d)
+
+ f.write("cd %s\n" % os.getcwd())
+ if func: f.write("%s\n" % func)
+ f.close()
+ os.chmod(runfile, 0775)
+ if not func:
+ error("Function not specified")
+ raise FuncFailed()
+
+ # open logs
+ si = file('/dev/null', 'r')
+ try:
+ if bb.debug_level > 0:
+ so = os.popen("tee \"%s\"" % logfile, "w")
+ else:
+ so = file(logfile, 'w')
+ except OSError, e:
+ bb.error("opening log file: %s" % e)
+ pass
+
+ se = so
+
+ # dup the existing fds so we dont lose them
+ osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
+ oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
+ ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
+
+ # replace those fds with our own
+ os.dup2(si.fileno(), osi[1])
+ os.dup2(so.fileno(), oso[1])
+ os.dup2(se.fileno(), ose[1])
+
+ # execute function
+ prevdir = os.getcwd()
+ if data.getVarFlag(func, "fakeroot", d):
+ maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1)
+ else:
+ maybe_fakeroot = ''
+ ret = os.system('%ssh -e %s' % (maybe_fakeroot, runfile))
+ os.chdir(prevdir)
+
+ # restore the backups
+ os.dup2(osi[0], osi[1])
+ os.dup2(oso[0], oso[1])
+ os.dup2(ose[0], ose[1])
+
+ # close our logs
+ si.close()
+ so.close()
+ se.close()
+
+ # close the backup fds
+ os.close(osi[0])
+ os.close(oso[0])
+ os.close(ose[0])
+
+ if ret==0:
+ if bb.debug_level > 0:
+ os.remove(runfile)
+# os.remove(logfile)
+ return
+ else:
+ error("function %s failed" % func)
+ if data.getVar("BBINCLUDELOGS", d):
+ error("log data follows (%s)" % logfile)
+ f = open(logfile, "r")
+ while True:
+ l = f.readline()
+ if l == '':
+ break
+ l = l.rstrip()
+ print '| %s' % l
+ f.close()
+ else:
+ error("see log in %s" % logfile)
+ raise FuncFailed( logfile )
+
+
+def exec_task(task, d):
+ """Execute an BB 'task'
+
+ The primary difference between executing a task versus executing
+ a function is that a task exists in the task digraph, and therefore
+ has dependencies amongst other tasks."""
+
+ # check if the task is in the graph..
+ task_graph = data.getVar('_task_graph', d)
+ if not task_graph:
+ task_graph = bb.digraph()
+ data.setVar('_task_graph', task_graph, d)
+ task_cache = data.getVar('_task_cache', d)
+ if not task_cache:
+ task_cache = []
+ data.setVar('_task_cache', task_cache, d)
+ if not task_graph.hasnode(task):
+ raise EventException("Missing node in task graph", InvalidTask(task, d))
+
+ # check whether this task needs executing..
+ if not data.getVarFlag(task, 'force', d):
+ if stamp_is_current(task, d):
+ return 1
+
+ # follow digraph path up, then execute our way back down
+ def execute(graph, item):
+ if data.getVarFlag(item, 'task', d):
+ if item in task_cache:
+ return 1
+
+ if task != item:
+ # deeper than toplevel, exec w/ deps
+ exec_task(item, d)
+ return 1
+
+ try:
+ debug(1, "Executing task %s" % item)
+ old_overrides = data.getVar('OVERRIDES', d, 0)
+ localdata = data.createCopy(d)
+ data.setVar('OVERRIDES', 'task_%s:%s' % (item, old_overrides), localdata)
+ data.update_data(localdata)
+ event.fire(TaskStarted(item, localdata))
+ exec_func(item, localdata)
+ event.fire(TaskSucceeded(item, localdata))
+ task_cache.append(item)
+ data.setVar('_task_cache', task_cache, d)
+ except FuncFailed, reason:
+ note( "Task failed: %s" % reason )
+ failedevent = TaskFailed(item, d)
+ event.fire(failedevent)
+ raise EventException("Function failed in task: %s" % reason, failedevent)
+
+ # execute
+ task_graph.walkdown(task, execute)
+
+ # make stamp, or cause event and raise exception
+ if not data.getVarFlag(task, 'nostamp', d):
+ mkstamp(task, d)
+
+
+def stamp_is_current(task, d, checkdeps = 1):
+ """Check status of a given task's stamp. returns 0 if it is not current and needs updating."""
+ task_graph = data.getVar('_task_graph', d)
+ if not task_graph:
+ task_graph = bb.digraph()
+ data.setVar('_task_graph', task_graph, d)
+ stamp = data.getVar('STAMP', d)
+ if not stamp:
+ return 0
+ stampfile = "%s.%s" % (data.expand(stamp, d), task)
+ if not os.access(stampfile, os.F_OK):
+ return 0
+
+ if checkdeps == 0:
+ return 1
+
+ import stat
+ tasktime = os.stat(stampfile)[stat.ST_MTIME]
+
+ _deps = []
+ def checkStamp(graph, task):
+ # check for existance
+ if data.getVarFlag(task, 'nostamp', d):
+ return 1
+
+ if not stamp_is_current(task, d, 0):
+ return 0
+
+ depfile = "%s.%s" % (data.expand(stamp, d), task)
+ deptime = os.stat(depfile)[stat.ST_MTIME]
+ if deptime > tasktime:
+ return 0
+ return 1
+
+ return task_graph.walkdown(task, checkStamp)
+
+
+def md5_is_current(task):
+ """Check if a md5 file for a given task is current"""
+
+
+def mkstamp(task, d):
+ """Creates/updates a stamp for a given task"""
+ stamp = data.getVar('STAMP', d)
+ if not stamp:
+ return
+ stamp = "%s.%s" % (data.expand(stamp, d), task)
+ mkdirhier(os.path.dirname(stamp))
+ open(stamp, "w+")
+
+
+def add_task(task, deps, d):
+ task_graph = data.getVar('_task_graph', d)
+ if not task_graph:
+ task_graph = bb.digraph()
+ data.setVarFlag(task, 'task', 1, d)
+ task_graph.addnode(task, None)
+ for dep in deps:
+ if not task_graph.hasnode(dep):
+ task_graph.addnode(dep, None)
+ task_graph.addnode(task, dep)
+ # don't assume holding a reference
+ data.setVar('_task_graph', task_graph, d)
+
+
+def remove_task(task, kill, d):
+ """Remove an BB 'task'.
+
+ If kill is 1, also remove tasks that depend on this task."""
+
+ task_graph = data.getVar('_task_graph', d)
+ if not task_graph:
+ task_graph = bb.digraph()
+ if not task_graph.hasnode(task):
+ return
+
+ data.delVarFlag(task, 'task', d)
+ ref = 1
+ if kill == 1:
+ ref = 2
+ task_graph.delnode(task, ref)
+ data.setVar('_task_graph', task_graph, d)
+
+def task_exists(task, d):
+ task_graph = data.getVar('_task_graph', d)
+ if not task_graph:
+ task_graph = bb.digraph()
+ data.setVar('_task_graph', task_graph, d)
+ return task_graph.hasnode(task)
+
+def get_task_data():
+ return _task_data
diff --git a/trunk/bitbake/lib/bb/data.py b/trunk/bitbake/lib/bb/data.py
new file mode 100644
index 000000000..39ff2a7e3
--- /dev/null
+++ b/trunk/bitbake/lib/bb/data.py
@@ -0,0 +1,579 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake 'Data' implementations
+
+Functions for interacting with the data structure used by the
+BitBake build tools.
+
+Copyright (C) 2003, 2004 Chris Larson
+Copyright (C) 2005 Holger Hans Peter Freyther
+
+This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+
+Based on functions from the base bb module, Copyright 2003 Holger Schurig
+"""
+
+import sys, os, re, time, types
+if sys.argv[0][-5:] == "pydoc":
+ path = os.path.dirname(os.path.dirname(sys.argv[1]))
+else:
+ path = os.path.dirname(os.path.dirname(sys.argv[0]))
+sys.path.append(path)
+
+from bb import note, debug, data_smart
+
+_dict_type = data_smart.DataSmart
+_dict_p_type = data_smart.DataSmartPackage
+
+class DataDictFull(dict):
+ """
+ This implements our Package Data Storage Interface.
+ setDirty is a no op as all items are held in memory
+ """
+ def setDirty(self, bbfile, data):
+ """
+ No-Op we assume data was manipulated as some sort of
+ reference
+ """
+ if not bbfile in self:
+ raise Exception("File %s was not in dictionary before" % bbfile)
+
+ self[bbfile] = data
+
+class DataDictCache:
+ """
+ Databacked Dictionary implementation
+ """
+ def __init__(self, cache_dir):
+ self.cache_dir = cache_dir
+ self.files = []
+ self.dirty = {}
+
+ def has_key(self,key):
+ return key in self.files
+
+ def keys(self):
+ return self.files
+
+ def __setitem__(self, key, data):
+ """
+ Add the key to the list of known files and
+ place the data in the cache?
+ """
+ if key in self.files:
+ return
+
+ self.files.append(key)
+
+ def __getitem__(self, key):
+ if not key in self.files:
+ return None
+
+ # if it was dirty we will
+ if key in self.dirty:
+ return self.dirty[key]
+
+ # not cached yet
+ return _dict_p_type(self.cache_dir, key,False,None)
+
+ def setDirty(self, bbfile, data):
+ """
+ Only already added items can be declared dirty!!!
+ """
+
+ if not bbfile in self.files:
+ raise Exception("File %s was not in dictionary before" % bbfile)
+
+ self.dirty[bbfile] = data
+
+
+
+def init():
+ return _dict_type()
+
+def init_db(cache,name,clean,parent = None):
+ return _dict_p_type(cache,name,clean,parent)
+
+def init_db_mtime(cache,cache_bbfile):
+ return _dict_p_type.mtime(cache,cache_bbfile)
+
+def pkgdata(use_cache, cache):
+ """
+ Return some sort of dictionary to lookup parsed dictionaires
+ """
+ if use_cache:
+ return DataDictCache(cache)
+ return DataDictFull()
+
+def createCopy(source):
+ """Link the source set to the destination
+ If one does not find the value in the destination set,
+ search will go on to the source set to get the value.
+ Value from source are copy-on-write. i.e. any try to
+ modify one of them will end up putting the modified value
+ in the destination set.
+ """
+ return source.createCopy()
+
+def initVar(var, d):
+ """Non-destructive var init for data structure"""
+ d.initVar(var)
+
+
+def setVar(var, value, d):
+ """Set a variable to a given value
+
+ Example:
+ >>> d = init()
+ >>> setVar('TEST', 'testcontents', d)
+ >>> print getVar('TEST', d)
+ testcontents
+ """
+ d.setVar(var,value)
+
+
+def getVar(var, d, exp = 0):
+ """Gets the value of a variable
+
+ Example:
+ >>> d = init()
+ >>> setVar('TEST', 'testcontents', d)
+ >>> print getVar('TEST', d)
+ testcontents
+ """
+ return d.getVar(var,exp)
+
+def delVar(var, d):
+ """Removes a variable from the data set
+
+ Example:
+ >>> d = init()
+ >>> setVar('TEST', 'testcontents', d)
+ >>> print getVar('TEST', d)
+ testcontents
+ >>> delVar('TEST', d)
+ >>> print getVar('TEST', d)
+ None
+ """
+ d.delVar(var)
+
+def setVarFlag(var, flag, flagvalue, d):
+ """Set a flag for a given variable to a given value
+
+ Example:
+ >>> d = init()
+ >>> setVarFlag('TEST', 'python', 1, d)
+ >>> print getVarFlag('TEST', 'python', d)
+ 1
+ """
+ d.setVarFlag(var,flag,flagvalue)
+
+def getVarFlag(var, flag, d):
+ """Gets given flag from given var
+
+ Example:
+ >>> d = init()
+ >>> setVarFlag('TEST', 'python', 1, d)
+ >>> print getVarFlag('TEST', 'python', d)
+ 1
+ """
+ return d.getVarFlag(var,flag)
+
+def delVarFlag(var, flag, d):
+ """Removes a given flag from the variable's flags
+
+ Example:
+ >>> d = init()
+ >>> setVarFlag('TEST', 'testflag', 1, d)
+ >>> print getVarFlag('TEST', 'testflag', d)
+ 1
+ >>> delVarFlag('TEST', 'testflag', d)
+ >>> print getVarFlag('TEST', 'testflag', d)
+ None
+
+ """
+ d.delVarFlag(var,flag)
+
+def setVarFlags(var, flags, d):
+ """Set the flags for a given variable
+
+ Example:
+ >>> d = init()
+ >>> myflags = {}
+ >>> myflags['test'] = 'blah'
+ >>> setVarFlags('TEST', myflags, d)
+ >>> print getVarFlag('TEST', 'test', d)
+ blah
+ """
+ d.setVarFlags(var,flags)
+
+def getVarFlags(var, d):
+ """Gets a variable's flags
+
+ Example:
+ >>> d = init()
+ >>> setVarFlag('TEST', 'test', 'blah', d)
+ >>> print getVarFlags('TEST', d)['test']
+ blah
+ """
+ return d.getVarFlags(var)
+
+def delVarFlags(var, d):
+ """Removes a variable's flags
+
+ Example:
+ >>> data = init()
+ >>> setVarFlag('TEST', 'testflag', 1, data)
+ >>> print getVarFlag('TEST', 'testflag', data)
+ 1
+ >>> delVarFlags('TEST', data)
+ >>> print getVarFlags('TEST', data)
+ None
+
+ """
+ d.delVarFlags(var)
+
+def keys(d):
+ """Return a list of keys in d
+
+ Example:
+ >>> d = init()
+ >>> setVar('TEST', 1, d)
+ >>> setVar('MOO' , 2, d)
+ >>> setVarFlag('TEST', 'test', 1, d)
+ >>> keys(d)
+ ['TEST', 'MOO']
+ """
+ return d.keys()
+
+def getData(d):
+ """Returns the data object used"""
+ return d
+
+def setData(newData, d):
+ """Sets the data object to the supplied value"""
+ d = newData
+
+__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
+__expand_python_regexp__ = re.compile(r"\${@.+?}")
+
+def expand(s, d, varname = None):
+ """Variable expansion using the data store.
+
+ Example:
+ Standard expansion:
+ >>> d = init()
+ >>> setVar('A', 'sshd', d)
+ >>> print expand('/usr/bin/${A}', d)
+ /usr/bin/sshd
+
+ Python expansion:
+ >>> d = init()
+ >>> print expand('result: ${@37 * 72}', d)
+ result: 2664
+
+ Shell expansion:
+ >>> d = init()
+ >>> print expand('${TARGET_MOO}', d)
+ ${TARGET_MOO}
+ >>> setVar('TARGET_MOO', 'yupp', d)
+ >>> print expand('${TARGET_MOO}',d)
+ yupp
+ >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
+ >>> delVar('TARGET_MOO', d)
+ >>> print expand('${SRC_URI}', d)
+ http://somebug.${TARGET_MOO}
+ """
+ def var_sub(match):
+ key = match.group()[2:-1]
+ if varname and key:
+ if varname == key:
+ raise Exception("variable %s references itself!" % varname)
+ var = getVar(key, d, 1)
+ if var is not None:
+ return var
+ else:
+ return match.group()
+
+ def python_sub(match):
+ import bb
+ code = match.group()[3:-1]
+ locals()['d'] = d
+ s = eval(code)
+ if type(s) == types.IntType: s = str(s)
+ return s
+
+ if type(s) is not types.StringType: # sanity check
+ return s
+
+ while s.find('$') != -1:
+ olds = s
+ try:
+ s = __expand_var_regexp__.sub(var_sub, s)
+ s = __expand_python_regexp__.sub(python_sub, s)
+ if s == olds: break
+ if type(s) is not types.StringType: # sanity check
+ import bb
+ bb.error('expansion of %s returned non-string %s' % (olds, s))
+ except KeyboardInterrupt:
+ raise
+ except:
+ note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
+ raise
+ return s
+
+def expandKeys(alterdata, readdata = None):
+ if readdata == None:
+ readdata = alterdata
+
+ for key in keys(alterdata):
+ ekey = expand(key, readdata)
+ if key == ekey:
+ continue
+ val = getVar(key, alterdata)
+ if val is None:
+ continue
+# import copy
+# setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
+ setVar(ekey, val, alterdata)
+
+ for i in ('_append', '_prepend', '_delete'):
+ dest = getVarFlag(ekey, i, alterdata) or []
+ src = getVarFlag(key, i, readdata) or []
+ dest.extend(src)
+ setVarFlag(ekey, i, dest, alterdata)
+
+ delVar(key, alterdata)
+
+def expandData(alterdata, readdata = None):
+ """For each variable in alterdata, expand it, and update the var contents.
+ Replacements use data from readdata.
+
+ Example:
+ >>> a=init()
+ >>> b=init()
+ >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
+ >>> setVar("DL_DIR", "/path/to/whatever", b)
+ >>> expandData(a, b)
+ >>> print getVar("dlmsg", a)
+ dl_dir is /path/to/whatever
+ """
+ if readdata == None:
+ readdata = alterdata
+
+ for key in keys(alterdata):
+ val = getVar(key, alterdata)
+ if type(val) is not types.StringType:
+ continue
+ expanded = expand(val, readdata)
+# print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
+ if val != expanded:
+ setVar(key, expanded, alterdata)
+
+import os
+
+def inheritFromOS(d):
+ """Inherit variables from the environment."""
+# fakeroot needs to be able to set these
+ non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
+ for s in os.environ.keys():
+ if not s in non_inherit_vars:
+ try:
+ setVar(s, os.environ[s], d)
+ setVarFlag(s, 'matchesenv', '1', d)
+ except TypeError:
+ pass
+
+import sys
+
+def emit_var(var, o=sys.__stdout__, d = init(), all=False):
+ """Emit a variable to be sourced by a shell."""
+ if getVarFlag(var, "python", d):
+ return 0
+
+ try:
+ if all:
+ oval = getVar(var, d, 0)
+ val = getVar(var, d, 1)
+ except KeyboardInterrupt:
+ raise
+ except:
+ excname = str(sys.exc_info()[0])
+ if excname == "bb.build.FuncFailed":
+ raise
+ o.write('# expansion of %s threw %s\n' % (var, excname))
+ return 0
+
+ if all:
+ o.write('# %s=%s\n' % (var, oval))
+
+ if type(val) is not types.StringType:
+ return 0
+
+ if getVarFlag(var, 'matchesenv', d):
+ return 0
+
+ if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
+ return 0
+
+ val.rstrip()
+ if not val:
+ return 0
+
+ if getVarFlag(var, "func", d):
+# NOTE: should probably check for unbalanced {} within the var
+ o.write("%s() {\n%s\n}\n" % (var, val))
+ else:
+ if getVarFlag(var, "export", d):
+ o.write('export ')
+ else:
+ if not all:
+ return 0
+# if we're going to output this within doublequotes,
+# to a shell, we need to escape the quotes in the var
+ alter = re.sub('"', '\\"', val.strip())
+ o.write('%s="%s"\n' % (var, alter))
+ return 1
+
+
+def emit_env(o=sys.__stdout__, d = init(), all=False):
+ """Emits all items in the data store in a format such that it can be sourced by a shell."""
+
+ env = keys(d)
+
+ for e in env:
+ if getVarFlag(e, "func", d):
+ continue
+ emit_var(e, o, d, all) and o.write('\n')
+
+ for e in env:
+ if not getVarFlag(e, "func", d):
+ continue
+ emit_var(e, o, d) and o.write('\n')
+
+def update_data(d):
+ """Modifies the environment vars according to local overrides and commands.
+ Examples:
+ Appending to a variable:
+ >>> d = init()
+ >>> setVar('TEST', 'this is a', d)
+ >>> setVar('TEST_append', ' test', d)
+ >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
+ >>> update_data(d)
+ >>> print getVar('TEST', d)
+ this is a test of the emergency broadcast system.
+
+ Prepending to a variable:
+ >>> setVar('TEST', 'virtual/libc', d)
+ >>> setVar('TEST_prepend', 'virtual/tmake ', d)
+ >>> setVar('TEST_prepend', 'virtual/patcher ', d)
+ >>> update_data(d)
+ >>> print getVar('TEST', d)
+ virtual/patcher virtual/tmake virtual/libc
+
+ Overrides:
+ >>> setVar('TEST_arm', 'target', d)
+ >>> setVar('TEST_ramses', 'machine', d)
+ >>> setVar('TEST_local', 'local', d)
+ >>> setVar('OVERRIDES', 'arm', d)
+
+ >>> setVar('TEST', 'original', d)
+ >>> update_data(d)
+ >>> print getVar('TEST', d)
+ target
+
+ >>> setVar('OVERRIDES', 'arm:ramses:local', d)
+ >>> setVar('TEST', 'original', d)
+ >>> update_data(d)
+ >>> print getVar('TEST', d)
+ local
+ """
+
+ debug(2, "update_data()")
+
+# can't do delete env[...] while iterating over the dictionary, so remember them
+ dodel = []
+ overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
+
+ def applyOverrides(var, d):
+ if not overrides:
+ debug(1, "OVERRIDES not defined, nothing to do")
+ return
+ val = getVar(var, d)
+ for o in overrides:
+ if var.endswith("_" + o):
+ l = len(o)+1
+ name = var[:-l]
+ d[name] = d[var]
+
+ for s in keys(d):
+ applyOverrides(s, d)
+ sval = getVar(s, d) or ""
+
+# Handle line appends:
+ for (a, o) in getVarFlag(s, '_append', d) or []:
+ # maybe the OVERRIDE was not yet added so keep the append
+ if (o and o in overrides) or not o:
+ delVarFlag(s, '_append', d)
+ if o:
+ if not o in overrides:
+ continue
+ sval+=a
+ setVar(s, sval, d)
+
+# Handle line prepends
+ for (a, o) in getVarFlag(s, '_prepend', d) or []:
+ # maybe the OVERRIDE was not yet added so keep the append
+ if (o and o in overrides) or not o:
+ delVarFlag(s, '_prepend', d)
+ if o:
+ if not o in overrides:
+ continue
+ sval=a+sval
+ setVar(s, sval, d)
+
+# Handle line deletions
+ name = s + "_delete"
+ nameval = getVar(name, d)
+ if nameval:
+ sval = getVar(s, d)
+ if sval:
+ new = ''
+ pattern = nameval.replace('\n','').strip()
+ for line in sval.split('\n'):
+ if line.find(pattern) == -1:
+ new = new + '\n' + line
+ setVar(s, new, d)
+ dodel.append(name)
+
+# delete all environment vars no longer needed
+ for s in dodel:
+ delVar(s, d)
+
+def inherits_class(klass, d):
+ val = getVar('__inherit_cache', d) or ""
+ if os.path.join('classes', '%s.bbclass' % klass) in val.split():
+ return True
+ return False
+
+def _test():
+ """Start a doctest run on this module"""
+ import doctest
+ from bb import data
+ doctest.testmod(data)
+
+if __name__ == "__main__":
+ _test()
diff --git a/trunk/bitbake/lib/bb/data_smart.py b/trunk/bitbake/lib/bb/data_smart.py
new file mode 100644
index 000000000..e1ced4e1e
--- /dev/null
+++ b/trunk/bitbake/lib/bb/data_smart.py
@@ -0,0 +1,328 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake Smart Dictionary Implementation
+
+Functions for interacting with the data structure used by the
+BitBake build tools.
+
+Copyright (C) 2003, 2004 Chris Larson
+Copyright (C) 2004, 2005 Seb Frankengul
+Copyright (C) 2005 Holger Hans Peter Freyther
+Copyright (C) 2005 Uli Luckas
+Copyright (C) 2005 ROAD GmbH
+
+This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+
+Based on functions from the base bb module, Copyright 2003 Holger Schurig
+"""
+
+import copy, os, re, sys, time, types
+from bb import note, debug, fatal
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+ print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
+
+
+__setvar_keyword__ = ["_append","_prepend","_delete"]
+__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend|_delete)(_(?P<add>.*))?')
+__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
+__expand_python_regexp__ = re.compile(r"\${@.+?}")
+
+
+class DataSmart:
+ def __init__(self):
+ self.dict = {}
+
+ def expand(self,s, varname):
+ def var_sub(match):
+ key = match.group()[2:-1]
+ if varname and key:
+ if varname == key:
+ raise Exception("variable %s references itself!" % varname)
+ var = self.getVar(key, 1)
+ if var is not None:
+ return var
+ else:
+ return match.group()
+
+ def python_sub(match):
+ import bb
+ code = match.group()[3:-1]
+ locals()['d'] = self
+ s = eval(code)
+ if type(s) == types.IntType: s = str(s)
+ return s
+
+ if type(s) is not types.StringType: # sanity check
+ return s
+
+ while s.find('$') != -1:
+ olds = s
+ try:
+ s = __expand_var_regexp__.sub(var_sub, s)
+ s = __expand_python_regexp__.sub(python_sub, s)
+ if s == olds: break
+ if type(s) is not types.StringType: # sanity check
+ import bb
+ bb.error('expansion of %s returned non-string %s' % (olds, s))
+ except KeyboardInterrupt:
+ raise
+ except:
+ note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
+ raise
+ return s
+
+ def initVar(self, var):
+ if not var in self.dict:
+ self.dict[var] = {}
+
+ def pickle_prep(self, cfg):
+ if "_data" in self.dict:
+ if self.dict["_data"] == cfg:
+ self.dict["_data"] = "cfg";
+ else: # this is an unknown array for the moment
+ pass
+
+ def unpickle_prep(self, cfg):
+ if "_data" in self.dict:
+ if self.dict["_data"] == "cfg":
+ self.dict["_data"] = cfg;
+
+ def _findVar(self,var):
+ _dest = self.dict
+
+ while (_dest and var not in _dest):
+ if not "_data" in _dest:
+ _dest = None
+ break
+ _dest = _dest["_data"]
+
+ if _dest and var in _dest:
+ return _dest[var]
+ return None
+
+ def _copyVar(self,var,name):
+ local_var = self._findVar(var)
+ if local_var:
+ self.dict[name] = copy.copy(local_var)
+ else:
+ debug(1,"Warning, _copyVar %s to %s, %s does not exists" % (var,name,var))
+
+
+ def _makeShadowCopy(self, var):
+ if var in self.dict:
+ return
+
+ local_var = self._findVar(var)
+
+ if local_var:
+ self.dict[var] = copy.copy(local_var)
+ else:
+ self.initVar(var)
+
+ def setVar(self,var,value):
+ match = __setvar_regexp__.match(var)
+ if match and match.group("keyword") in __setvar_keyword__:
+ base = match.group('base')
+ keyword = match.group("keyword")
+ override = match.group('add')
+ l = self.getVarFlag(base, keyword) or []
+ if override == 'delete':
+ if l.count([value, None]):
+ del l[l.index([value, None])]
+ l.append([value, override])
+ self.setVarFlag(base, match.group("keyword"), l)
+ return
+
+ if not var in self.dict:
+ self._makeShadowCopy(var)
+ if self.getVarFlag(var, 'matchesenv'):
+ self.delVarFlag(var, 'matchesenv')
+ self.setVarFlag(var, 'export', 1)
+
+ # setting var
+ self.dict[var]["content"] = value
+
+ def getVar(self,var,exp):
+ value = self.getVarFlag(var,"content")
+
+ if exp and value:
+ return self.expand(value,var)
+ return value
+
+ def delVar(self,var):
+ self.dict[var] = {}
+
+ def setVarFlag(self,var,flag,flagvalue):
+ if not var in self.dict:
+ self._makeShadowCopy(var)
+ self.dict[var][flag] = flagvalue
+
+ def getVarFlag(self,var,flag):
+ local_var = self._findVar(var)
+ if local_var:
+ if flag in local_var:
+ return copy.copy(local_var[flag])
+ return None
+
+ def delVarFlag(self,var,flag):
+ local_var = self._findVar(var)
+ if not local_var:
+ return
+ if not var in self.dict:
+ self._makeShadowCopy(var)
+
+ if var in self.dict and flag in self.dict[var]:
+ del self.dict[var][flag]
+
+ def setVarFlags(self,var,flags):
+ if not var in self.dict:
+ self._makeShadowCopy(var)
+
+ for i in flags.keys():
+ if i == "content":
+ continue
+ self.dict[var][i] = flags[i]
+
+ def getVarFlags(self,var):
+ local_var = self._findVar(var)
+ flags = {}
+
+ if local_var:
+ for i in self.dict[var].keys():
+ if i == "content":
+ continue
+ flags[i] = self.dict[var][i]
+
+ if len(flags) == 0:
+ return None
+ return flags
+
+
+ def delVarFlags(self,var):
+ if not var in self.dict:
+ self._makeShadowCopy(var)
+
+ if var in self.dict:
+ content = None
+
+ # try to save the content
+ if "content" in self.dict[var]:
+ content = self.dict[var]["content"]
+ self.dict[var] = {}
+ self.dict[var]["content"] = content
+ else:
+ del self.dict[var]
+
+
+ def createCopy(self):
+ """
+ Create a copy of self by setting _data to self
+ """
+ # we really want this to be a DataSmart...
+ data = DataSmart()
+ data.dict["_data"] = self.dict
+
+ return data
+
+ # Dictionary Methods
+ def keys(self):
+ def _keys(d, mykey):
+ if "_data" in d:
+ _keys(d["_data"],mykey)
+
+ for key in d.keys():
+ if key != "_data":
+ mykey[key] = None
+ keytab = {}
+ _keys(self.dict,keytab)
+ return keytab.keys()
+
+ def __getitem__(self,item):
+ start = self.dict
+ while start:
+ if item in start:
+ return start[item]
+ elif "_data" in start:
+ start = start["_data"]
+ else:
+ start = None
+ return None
+
+ def __setitem__(self,var,data):
+ self._makeShadowCopy(var)
+ self.dict[var] = data
+
+
+class DataSmartPackage(DataSmart):
+ """
+ Persistent Data Storage
+ """
+ def sanitize_filename(bbfile):
+ return bbfile.replace( '/', '_' )
+ sanitize_filename = staticmethod(sanitize_filename)
+
+ def unpickle(self):
+ """
+ Restore the dict from memory
+ """
+ cache_bbfile = self.sanitize_filename(self.bbfile)
+ p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
+ self.dict = p.load()
+ funcstr = self.getVar('__functions__', 0)
+ if funcstr:
+ comp = compile(funcstr, "<pickled>", "exec")
+ exec comp in __builtins__
+
+ def linkDataSet(self,parent):
+ if not parent == None:
+ # assume parent is a DataSmartInstance
+ self.dict = copy.deepcopy(parent.dict)
+
+
+ def __init__(self,cache,name,clean,parent):
+ """
+ Construct a persistent data instance
+ """
+ #Initialize the dictionary
+ DataSmart.__init__(self)
+
+ self.cache = cache
+ self.bbfile = os.path.abspath( name )
+
+ # Either unpickle the data or do copy on write
+ if clean:
+ self.linkDataSet(parent)
+ else:
+ self.unpickle()
+
+ def commit(self, mtime):
+ """
+ Save the package to a permanent storage
+ """
+ cache_bbfile = self.sanitize_filename(self.bbfile)
+ p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
+ p.dump( self.dict )
+
+ def mtime(cache,bbfile):
+ cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
+ try:
+ return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
+ except OSError:
+ return 0
+ mtime = staticmethod(mtime)
diff --git a/trunk/bitbake/lib/bb/event.py b/trunk/bitbake/lib/bb/event.py
new file mode 100644
index 000000000..c4e88fa35
--- /dev/null
+++ b/trunk/bitbake/lib/bb/event.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake 'Event' implementation
+
+Classes and functions for manipulating 'events' in the
+BitBake build tools.
+
+Copyright (C) 2003, 2004 Chris Larson
+
+This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+"""
+
+import os, re
+import bb.data
+
+class Event:
+ """Base class for events"""
+ type = "Event"
+
+ def __init__(self, d = bb.data.init()):
+ self._data = d
+
+ def getData(self):
+ return self._data
+
+ def setData(self, data):
+ self._data = data
+
+ data = property(getData, setData, None, "data property")
+
+NotHandled = 0
+Handled = 1
+handlers = []
+
+def tmpHandler(event):
+ """Default handler for code events"""
+ return NotHandled
+
+def defaultTmpHandler():
+ tmp = "def tmpHandler(e):\n\t\"\"\"heh\"\"\"\n\treturn 0"
+ comp = compile(tmp, "tmpHandler(e)", "exec")
+ return comp
+
+def fire(event):
+ """Fire off an Event"""
+ for h in handlers:
+ if type(h).__name__ == "code":
+ exec(h)
+ if tmpHandler(event) == Handled:
+ return Handled
+ else:
+ if h(event) == Handled:
+ return Handled
+ return NotHandled
+
+def register(handler):
+ """Register an Event handler"""
+ if handler is not None:
+# handle string containing python code
+ if type(handler).__name__ == "str":
+ return registerCode(handler)
+# prevent duplicate registration
+ if not handler in handlers:
+ handlers.append(handler)
+
+def registerCode(handlerStr):
+ """Register a 'code' Event.
+ Deprecated interface; call register instead.
+
+ Expects to be passed python code as a string, which will
+ be passed in turn to compile() and then exec(). Note that
+ the code will be within a function, so should have had
+ appropriate tabbing put in place."""
+ tmp = "def tmpHandler(e):\n%s" % handlerStr
+ comp = compile(tmp, "tmpHandler(e)", "exec")
+# prevent duplicate registration
+ if not comp in handlers:
+ handlers.append(comp)
+
+def remove(handler):
+ """Remove an Event handler"""
+ for h in handlers:
+ if type(handler).__name__ == "str":
+ return removeCode(handler)
+
+ if handler is h:
+ handlers.remove(handler)
+
+def removeCode(handlerStr):
+ """Remove a 'code' Event handler
+ Deprecated interface; call remove instead."""
+ tmp = "def tmpHandler(e):\n%s" % handlerStr
+ comp = compile(tmp, "tmpHandler(e)", "exec")
+ handlers.remove(comp)
+
+def getName(e):
+ """Returns the name of a class or class instance"""
+ if getattr(e, "__name__", None) == None:
+ return e.__class__.__name__
+ else:
+ return e.__name__
+
+
+class PkgBase(Event):
+ """Base class for package events"""
+
+ def __init__(self, t, d = {}):
+ self._pkg = t
+ Event.__init__(self, d)
+
+ def getPkg(self):
+ return self._pkg
+
+ def setPkg(self, pkg):
+ self._pkg = pkg
+
+ pkg = property(getPkg, setPkg, None, "pkg property")
+
+
+class BuildBase(Event):
+ """Base class for bbmake run events"""
+
+ def __init__(self, n, p, c):
+ self._name = n
+ self._pkgs = p
+ Event.__init__(self, c)
+
+ def getPkgs(self):
+ return self._pkgs
+
+ def setPkgs(self, pkgs):
+ self._pkgs = pkgs
+
+ def getName(self):
+ return self._name
+
+ def setName(self, name):
+ self._name = name
+
+ def getCfg(self):
+ return self.data
+
+ def setCfg(self, cfg):
+ self.data = cfg
+
+ pkgs = property(getPkgs, setPkgs, None, "pkgs property")
+ name = property(getName, setName, None, "name property")
+ cfg = property(getCfg, setCfg, None, "cfg property")
+
+
+class DepBase(PkgBase):
+ """Base class for dependency events"""
+
+ def __init__(self, t, data, d):
+ self._dep = d
+ PkgBase.__init__(self, t, data)
+
+ def getDep(self):
+ return self._dep
+
+ def setDep(self, dep):
+ self._dep = dep
+
+ dep = property(getDep, setDep, None, "dep property")
+
+
+class PkgStarted(PkgBase):
+ """Package build started"""
+
+
+class PkgFailed(PkgBase):
+ """Package build failed"""
+
+
+class PkgSucceeded(PkgBase):
+ """Package build completed"""
+
+
+class BuildStarted(BuildBase):
+ """bbmake build run started"""
+
+
+class BuildCompleted(BuildBase):
+ """bbmake build run completed"""
+
+
+class UnsatisfiedDep(DepBase):
+ """Unsatisfied Dependency"""
+
+
+class RecursiveDep(DepBase):
+ """Recursive Dependency"""
+
+
+class MultipleProviders(PkgBase):
+ """Multiple Providers"""
+
diff --git a/trunk/bitbake/lib/bb/fetch.py b/trunk/bitbake/lib/bb/fetch.py
new file mode 100644
index 000000000..f773e97eb
--- /dev/null
+++ b/trunk/bitbake/lib/bb/fetch.py
@@ -0,0 +1,646 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake 'Fetch' implementations
+
+Classes for obtaining upstream sources for the
+BitBake build tools.
+
+Copyright (C) 2003, 2004 Chris Larson
+
+This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+
+Based on functions from the base bb module, Copyright 2003 Holger Schurig
+"""
+
+import os, re
+import bb
+from bb import data
+
+class FetchError(Exception):
+ """Exception raised when a download fails"""
+
+class NoMethodError(Exception):
+ """Exception raised when there is no method to obtain a supplied url or set of urls"""
+
+class MissingParameterError(Exception):
+ """Exception raised when a fetch method is missing a critical parameter in the url"""
+
+#decodeurl("cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;module=familiar/dist/ipkg;tag=V0-99-81")
+#('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'})
+
+def uri_replace(uri, uri_find, uri_replace, d):
+# bb.note("uri_replace: operating on %s" % uri)
+ if not uri or not uri_find or not uri_replace:
+ bb.debug(1, "uri_replace: passed an undefined value, not replacing")
+ uri_decoded = list(bb.decodeurl(uri))
+ uri_find_decoded = list(bb.decodeurl(uri_find))
+ uri_replace_decoded = list(bb.decodeurl(uri_replace))
+ result_decoded = ['','','','','',{}]
+ for i in uri_find_decoded:
+ loc = uri_find_decoded.index(i)
+ result_decoded[loc] = uri_decoded[loc]
+ import types
+ if type(i) == types.StringType:
+ import re
+ if (re.match(i, uri_decoded[loc])):
+ result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
+ if uri_find_decoded.index(i) == 2:
+ if d:
+ localfn = bb.fetch.localpath(uri, d)
+ if localfn:
+ result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(bb.fetch.localpath(uri, d))
+# bb.note("uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc]))
+ else:
+# bb.note("uri_replace: no match")
+ return uri
+# else:
+# for j in i.keys():
+# FIXME: apply replacements against options
+ return bb.encodeurl(result_decoded)
+
+methods = []
+
+def init(urls = [], d = None):
+ if d == None:
+ bb.debug(2,"BUG init called with None as data object!!!")
+ return
+
+ for m in methods:
+ m.urls = []
+
+ for u in urls:
+ for m in methods:
+ m.data = d
+ if m.supports(u, d):
+ m.urls.append(u)
+
+def go(d):
+ """Fetch all urls"""
+ for m in methods:
+ if m.urls:
+ m.go(d)
+
+def localpaths(d):
+ """Return a list of the local filenames, assuming successful fetch"""
+ local = []
+ for m in methods:
+ for u in m.urls:
+ local.append(m.localpath(u, d))
+ return local
+
+def localpath(url, d):
+ for m in methods:
+ if m.supports(url, d):
+ return m.localpath(url, d)
+ return url
+
+class Fetch(object):
+ """Base class for 'fetch'ing data"""
+
+ def __init__(self, urls = []):
+ self.urls = []
+ for url in urls:
+ if self.supports(bb.decodeurl(url), d) is 1:
+ self.urls.append(url)
+
+ def supports(url, d):
+ """Check to see if this fetch class supports a given url.
+ Expects supplied url in list form, as outputted by bb.decodeurl().
+ """
+ return 0
+ supports = staticmethod(supports)
+
+ def localpath(url, d):
+ """Return the local filename of a given url assuming a successful fetch.
+ """
+ return url
+ localpath = staticmethod(localpath)
+
+ def setUrls(self, urls):
+ self.__urls = urls
+
+ def getUrls(self):
+ return self.__urls
+
+ urls = property(getUrls, setUrls, None, "Urls property")
+
+ def setData(self, data):
+ self.__data = data
+
+ def getData(self):
+ return self.__data
+
+ data = property(getData, setData, None, "Data property")
+
+ def go(self, urls = []):
+ """Fetch urls"""
+ raise NoMethodError("Missing implementation for url")
+
+class Wget(Fetch):
+ """Class to fetch urls via 'wget'"""
+ def supports(url, d):
+ """Check to see if a given url can be fetched using wget.
+ Expects supplied url in list form, as outputted by bb.decodeurl().
+ """
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ return type in ['http','https','ftp']
+ supports = staticmethod(supports)
+
+ def localpath(url, d):
+# strip off parameters
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ if "localpath" in parm:
+# if user overrides local path, use it.
+ return parm["localpath"]
+ url = bb.encodeurl([type, host, path, user, pswd, {}])
+
+ return os.path.join(data.getVar("DL_DIR", d), os.path.basename(url))
+ localpath = staticmethod(localpath)
+
+ def go(self, d, urls = []):
+ """Fetch urls"""
+ def fetch_uri(uri, basename, dl, md5, d):
+ if os.path.exists(dl):
+# file exists, but we didnt complete it.. trying again..
+ fetchcmd = data.getVar("RESUMECOMMAND", d, 1)
+ else:
+ fetchcmd = data.getVar("FETCHCOMMAND", d, 1)
+
+ bb.note("fetch " + uri)
+ fetchcmd = fetchcmd.replace("${URI}", uri)
+ fetchcmd = fetchcmd.replace("${FILE}", basename)
+ bb.debug(2, "executing " + fetchcmd)
+ ret = os.system(fetchcmd)
+ if ret != 0:
+ return False
+
+ # check if sourceforge did send us to the mirror page
+ dl_dir = data.getVar("DL_DIR", d, True)
+ if not os.path.exists(dl):
+ os.system("rm %s*" % dl) # FIXME shell quote it
+ bb.debug(2,"sourceforge.net send us to the mirror on %s" % basename)
+ return False
+
+# supposedly complete.. write out md5sum
+ if bb.which(data.getVar('PATH', d), 'md5sum'):
+ try:
+ md5pipe = os.popen('md5sum ' + dl)
+ md5data = (md5pipe.readline().split() or [ "" ])[0]
+ md5pipe.close()
+ except OSError:
+ md5data = ""
+ md5out = file(md5, 'w')
+ md5out.write(md5data)
+ md5out.close()
+ else:
+ md5out = file(md5, 'w')
+ md5out.write("")
+ md5out.close()
+ return True
+
+ if not urls:
+ urls = self.urls
+
+ localdata = data.createCopy(d)
+ data.setVar('OVERRIDES', "wget:" + data.getVar('OVERRIDES', localdata), localdata)
+ data.update_data(localdata)
+
+ for uri in urls:
+ completed = 0
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(uri, localdata))
+ basename = os.path.basename(path)
+ dl = self.localpath(uri, d)
+ dl = data.expand(dl, localdata)
+ md5 = dl + '.md5'
+
+ if os.path.exists(md5):
+# complete, nothing to see here..
+ continue
+
+ premirrors = [ i.split() for i in (data.getVar('PREMIRRORS', localdata, 1) or "").split('\n') if i ]
+ for (find, replace) in premirrors:
+ newuri = uri_replace(uri, find, replace, d)
+ if newuri != uri:
+ if fetch_uri(newuri, basename, dl, md5, localdata):
+ completed = 1
+ break
+
+ if completed:
+ continue
+
+ if fetch_uri(uri, basename, dl, md5, localdata):
+ continue
+
+# try mirrors
+ mirrors = [ i.split() for i in (data.getVar('MIRRORS', localdata, 1) or "").split('\n') if i ]
+ for (find, replace) in mirrors:
+ newuri = uri_replace(uri, find, replace, d)
+ if newuri != uri:
+ if fetch_uri(newuri, basename, dl, md5, localdata):
+ completed = 1
+ break
+
+ if not completed:
+ raise FetchError(uri)
+
+ del localdata
+
+
+methods.append(Wget())
+
+class Cvs(Fetch):
+ """Class to fetch a module or modules from cvs repositories"""
+ def supports(url, d):
+ """Check to see if a given url can be fetched with cvs.
+ Expects supplied url in list form, as outputted by bb.decodeurl().
+ """
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ return type in ['cvs', 'pserver']
+ supports = staticmethod(supports)
+
+ def localpath(url, d):
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ if "localpath" in parm:
+# if user overrides local path, use it.
+ return parm["localpath"]
+
+ if not "module" in parm:
+ raise MissingParameterError("cvs method needs a 'module' parameter")
+ else:
+ module = parm["module"]
+ if 'tag' in parm:
+ tag = parm['tag']
+ else:
+ tag = ""
+ if 'date' in parm:
+ date = parm['date']
+ else:
+ if not tag:
+ date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
+ else:
+ date = ""
+
+ return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, tag, date), d))
+ localpath = staticmethod(localpath)
+
+ def go(self, d, urls = []):
+ """Fetch urls"""
+ if not urls:
+ urls = self.urls
+
+ localdata = data.createCopy(d)
+ data.setVar('OVERRIDES', "cvs:%s" % data.getVar('OVERRIDES', localdata), localdata)
+ data.update_data(localdata)
+
+ for loc in urls:
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata))
+ if not "module" in parm:
+ raise MissingParameterError("cvs method needs a 'module' parameter")
+ else:
+ module = parm["module"]
+
+ dlfile = self.localpath(loc, localdata)
+ dldir = data.getVar('DL_DIR', localdata, 1)
+# if local path contains the cvs
+# module, consider the dir above it to be the
+# download directory
+# pos = dlfile.find(module)
+# if pos:
+# dldir = dlfile[:pos]
+# else:
+# dldir = os.path.dirname(dlfile)
+
+# setup cvs options
+ options = []
+ if 'tag' in parm:
+ tag = parm['tag']
+ else:
+ tag = ""
+
+ if 'date' in parm:
+ date = parm['date']
+ else:
+ if not tag:
+ date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
+ else:
+ date = ""
+
+ if "method" in parm:
+ method = parm["method"]
+ else:
+ method = "pserver"
+
+ if "localdir" in parm:
+ localdir = parm["localdir"]
+ else:
+ localdir = module
+
+ cvs_rsh = None
+ if method == "ext":
+ if "rsh" in parm:
+ cvs_rsh = parm["rsh"]
+
+ tarfn = data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, tag, date), localdata)
+ data.setVar('TARFILES', dlfile, localdata)
+ data.setVar('TARFN', tarfn, localdata)
+
+ dl = os.path.join(dldir, tarfn)
+ if os.access(dl, os.R_OK):
+ bb.debug(1, "%s already exists, skipping cvs checkout." % tarfn)
+ continue
+
+ pn = data.getVar('PN', d, 1)
+ cvs_tarball_stash = None
+ if pn:
+ cvs_tarball_stash = data.getVar('CVS_TARBALL_STASH_%s' % pn, d, 1)
+ if cvs_tarball_stash == None:
+ cvs_tarball_stash = data.getVar('CVS_TARBALL_STASH', d, 1)
+ if cvs_tarball_stash:
+ fetchcmd = data.getVar("FETCHCOMMAND_wget", d, 1)
+ uri = cvs_tarball_stash + tarfn
+ bb.note("fetch " + uri)
+ fetchcmd = fetchcmd.replace("${URI}", uri)
+ ret = os.system(fetchcmd)
+ if ret == 0:
+ bb.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
+ continue
+
+ if date:
+ options.append("-D %s" % date)
+ if tag:
+ options.append("-r %s" % tag)
+
+ olddir = os.path.abspath(os.getcwd())
+ os.chdir(data.expand(dldir, localdata))
+
+# setup cvsroot
+ if method == "dir":
+ cvsroot = path
+ else:
+ cvsroot = ":" + method + ":" + user
+ if pswd:
+ cvsroot += ":" + pswd
+ cvsroot += "@" + host + ":" + path
+
+ data.setVar('CVSROOT', cvsroot, localdata)
+ data.setVar('CVSCOOPTS', " ".join(options), localdata)
+ data.setVar('CVSMODULE', module, localdata)
+ cvscmd = data.getVar('FETCHCOMMAND', localdata, 1)
+ cvsupdatecmd = data.getVar('UPDATECOMMAND', localdata, 1)
+
+ if cvs_rsh:
+ cvscmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvscmd)
+ cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd)
+
+# create module directory
+ bb.debug(2, "Fetch: checking for module directory")
+ pkg=data.expand('${PN}', d)
+ pkgdir=os.path.join(data.expand('${CVSDIR}', localdata), pkg)
+ moddir=os.path.join(pkgdir,localdir)
+ if os.access(os.path.join(moddir,'CVS'), os.R_OK):
+ bb.note("Update " + loc)
+# update sources there
+ os.chdir(moddir)
+ myret = os.system(cvsupdatecmd)
+ else:
+ bb.note("Fetch " + loc)
+# check out sources there
+ bb.mkdirhier(pkgdir)
+ os.chdir(pkgdir)
+ bb.debug(1, "Running %s" % cvscmd)
+ myret = os.system(cvscmd)
+
+ if myret != 0:
+ try:
+ os.rmdir(moddir)
+ except OSError:
+ pass
+ raise FetchError(module)
+
+ os.chdir(moddir)
+ os.chdir('..')
+# tar them up to a defined filename
+ myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(moddir)))
+ if myret != 0:
+ try:
+ os.unlink(tarfn)
+ except OSError:
+ pass
+ os.chdir(olddir)
+ del localdata
+
+methods.append(Cvs())
+
+class Bk(Fetch):
+ def supports(url, d):
+ """Check to see if a given url can be fetched via bitkeeper.
+ Expects supplied url in list form, as outputted by bb.decodeurl().
+ """
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ return type in ['bk']
+ supports = staticmethod(supports)
+
+methods.append(Bk())
+
+class Local(Fetch):
+ def supports(url, d):
+ """Check to see if a given url can be fetched in the local filesystem.
+ Expects supplied url in list form, as outputted by bb.decodeurl().
+ """
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ return type in ['file','patch']
+ supports = staticmethod(supports)
+
+ def localpath(url, d):
+ """Return the local filename of a given url assuming a successful fetch.
+ """
+ path = url.split("://")[1]
+ newpath = path
+ if path[0] != "/":
+ filespath = data.getVar('FILESPATH', d, 1)
+ if filespath:
+ newpath = bb.which(filespath, path)
+ if not newpath:
+ filesdir = data.getVar('FILESDIR', d, 1)
+ if filesdir:
+ newpath = os.path.join(filesdir, path)
+ return newpath
+ localpath = staticmethod(localpath)
+
+ def go(self, urls = []):
+ """Fetch urls (no-op for Local method)"""
+# no need to fetch local files, we'll deal with them in place.
+ return 1
+
+methods.append(Local())
+
+class Svn(Fetch):
+ """Class to fetch a module or modules from svn repositories"""
+ def supports(url, d):
+ """Check to see if a given url can be fetched with svn.
+ Expects supplied url in list form, as outputted by bb.decodeurl().
+ """
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ return type in ['svn']
+ supports = staticmethod(supports)
+
+ def localpath(url, d):
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
+ if "localpath" in parm:
+# if user overrides local path, use it.
+ return parm["localpath"]
+
+ if not "module" in parm:
+ raise MissingParameterError("svn method needs a 'module' parameter")
+ else:
+ module = parm["module"]
+ if 'rev' in parm:
+ revision = parm['rev']
+ else:
+ revision = ""
+
+ date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
+
+ return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, revision, date), d))
+ localpath = staticmethod(localpath)
+
+ def go(self, d, urls = []):
+ """Fetch urls"""
+ if not urls:
+ urls = self.urls
+
+ localdata = data.createCopy(d)
+ data.setVar('OVERRIDES', "svn:%s" % data.getVar('OVERRIDES', localdata), localdata)
+ data.update_data(localdata)
+
+ for loc in urls:
+ (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata))
+ if not "module" in parm:
+ raise MissingParameterError("svn method needs a 'module' parameter")
+ else:
+ module = parm["module"]
+
+ dlfile = self.localpath(loc, localdata)
+ dldir = data.getVar('DL_DIR', localdata, 1)
+# if local path contains the svn
+# module, consider the dir above it to be the
+# download directory
+# pos = dlfile.find(module)
+# if pos:
+# dldir = dlfile[:pos]
+# else:
+# dldir = os.path.dirname(dlfile)
+
+# setup svn options
+ options = []
+ if 'rev' in parm:
+ revision = parm['rev']
+ else:
+ revision = ""
+
+ date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
+
+ if "method" in parm:
+ method = parm["method"]
+ else:
+ method = "pserver"
+
+ if "proto" in parm:
+ proto = parm["proto"]
+ else:
+ proto = "svn"
+
+ svn_rsh = None
+ if method == "ext":
+ if "rsh" in parm:
+ svn_rsh = parm["rsh"]
+
+ tarfn = data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, revision, date), localdata)
+ data.setVar('TARFILES', dlfile, localdata)
+ data.setVar('TARFN', tarfn, localdata)
+
+ dl = os.path.join(dldir, tarfn)
+ if os.access(dl, os.R_OK):
+ bb.debug(1, "%s already exists, skipping svn checkout." % tarfn)
+ continue
+
+ svn_tarball_stash = data.getVar('CVS_TARBALL_STASH', d, 1)
+ if svn_tarball_stash:
+ fetchcmd = data.getVar("FETCHCOMMAND_wget", d, 1)
+ uri = svn_tarball_stash + tarfn
+ bb.note("fetch " + uri)
+ fetchcmd = fetchcmd.replace("${URI}", uri)
+ ret = os.system(fetchcmd)
+ if ret == 0:
+ bb.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
+ continue
+
+ olddir = os.path.abspath(os.getcwd())
+ os.chdir(data.expand(dldir, localdata))
+
+# setup svnroot
+# svnroot = ":" + method + ":" + user
+# if pswd:
+# svnroot += ":" + pswd
+ svnroot = host + path
+
+ data.setVar('SVNROOT', svnroot, localdata)
+ data.setVar('SVNCOOPTS', " ".join(options), localdata)
+ data.setVar('SVNMODULE', module, localdata)
+ svncmd = data.getVar('FETCHCOMMAND', localdata, 1)
+ svncmd = "svn co %s://%s/%s" % (proto, svnroot, module)
+
+ if revision:
+ svncmd = "svn co -r %s %s://%s/%s" % (revision, proto, svnroot, module)
+ if svn_rsh:
+ svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd)
+
+# create temp directory
+ bb.debug(2, "Fetch: creating temporary directory")
+ bb.mkdirhier(data.expand('${WORKDIR}', localdata))
+ data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvn.XXXXXX', localdata), localdata)
+ tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
+ tmpfile = tmppipe.readline().strip()
+ if not tmpfile:
+ bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
+ raise FetchError(module)
+
+# check out sources there
+ os.chdir(tmpfile)
+ bb.note("Fetch " + loc)
+ bb.debug(1, "Running %s" % svncmd)
+ myret = os.system(svncmd)
+ if myret != 0:
+ try:
+ os.rmdir(tmpfile)
+ except OSError:
+ pass
+ raise FetchError(module)
+
+ os.chdir(os.path.join(tmpfile, os.path.dirname(module)))
+# tar them up to a defined filename
+ myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(module)))
+ if myret != 0:
+ try:
+ os.unlink(tarfn)
+ except OSError:
+ pass
+# cleanup
+ os.system('rm -rf %s' % tmpfile)
+ os.chdir(olddir)
+ del localdata
+
+methods.append(Svn())
diff --git a/trunk/bitbake/lib/bb/make.py b/trunk/bitbake/lib/bb/make.py
new file mode 100644
index 000000000..3ecaf7522
--- /dev/null
+++ b/trunk/bitbake/lib/bb/make.py
@@ -0,0 +1,246 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake 'Make' implementations
+
+Functions for reading BB files, building a dependency graph and
+building a set of BB files while walking along the dependency graph.
+
+Copyright (C) 2003, 2004 Mickey Lauer
+Copyright (C) 2003, 2004 Phil Blundell
+Copyright (C) 2003, 2004 Chris Larson
+
+This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+
+This file is part of the BitBake build tools.
+"""
+
+from bb import debug, digraph, data, fetch, fatal, error, note, event, parse
+import copy, bb, re, sys, os, glob, sre_constants
+
+pkgdata = None
+cfg = data.init()
+cache = None
+digits = "0123456789"
+ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+mtime_cache = {}
+
+def get_bbfiles( path = os.getcwd() ):
+ """Get list of default .bb files by reading out the current directory"""
+ contents = os.listdir(path)
+ bbfiles = []
+ for f in contents:
+ (root, ext) = os.path.splitext(f)
+ if ext == ".bb":
+ bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
+ return bbfiles
+
+def find_bbfiles( path ):
+ """Find all the .bb files in a directory (uses find)"""
+ findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
+ try:
+ finddata = os.popen(findcmd)
+ except OSError:
+ return []
+ return finddata.readlines()
+
+def deps_clean(d):
+ depstr = data.getVar('__depends', d)
+ if depstr:
+ deps = depstr.split(" ")
+ for dep in deps:
+ (f,old_mtime_s) = dep.split("@")
+ old_mtime = int(old_mtime_s)
+ new_mtime = parse.cached_mtime(f)
+ if (new_mtime > old_mtime):
+ return False
+ return True
+
+def load_bbfile( bbfile ):
+ """Load and parse one .bb build file"""
+
+ if not cache in [None, '']:
+ # get the times
+ cache_mtime = data.init_db_mtime(cache, bbfile)
+ file_mtime = parse.cached_mtime(bbfile)
+
+ if file_mtime > cache_mtime:
+ #print " : '%s' dirty. reparsing..." % bbfile
+ pass
+ else:
+ #print " : '%s' clean. loading from cache..." % bbfile
+ cache_data = data.init_db( cache, bbfile, False )
+ if deps_clean(cache_data):
+ return cache_data, True
+
+ topdir = data.getVar('TOPDIR', cfg)
+ if not topdir:
+ topdir = os.path.abspath(os.getcwd())
+ # set topdir to here
+ data.setVar('TOPDIR', topdir, cfg)
+ bbfile = os.path.abspath(bbfile)
+ bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
+ # expand tmpdir to include this topdir
+ data.setVar('TMPDIR', data.getVar('TMPDIR', cfg, 1) or "", cfg)
+ # set topdir to location of .bb file
+ topdir = bbfile_loc
+ #data.setVar('TOPDIR', topdir, cfg)
+ # go there
+ oldpath = os.path.abspath(os.getcwd())
+ os.chdir(topdir)
+ bb = data.init_db(cache,bbfile, True, cfg)
+ try:
+ parse.handle(bbfile, bb) # read .bb data
+ if not cache in [None, '']:
+ bb.commit(parse.cached_mtime(bbfile)) # write cache
+ os.chdir(oldpath)
+ return bb, False
+ finally:
+ os.chdir(oldpath)
+
+def collect_bbfiles( progressCallback ):
+ """Collect all available .bb build files"""
+ collect_bbfiles.cb = progressCallback
+ parsed, cached, skipped, masked = 0, 0, 0, 0
+ global cache, pkgdata
+ cache = bb.data.getVar( "CACHE", cfg, 1 )
+ pkgdata = data.pkgdata( not cache in [None, ''], cache )
+
+ if not cache in [None, '']:
+ if collect_bbfiles.cb is not None:
+ print "NOTE: Using cache in '%s'" % cache
+ try:
+ os.stat( cache )
+ except OSError:
+ bb.mkdirhier( cache )
+ else:
+ if collect_bbfiles.cb is not None:
+ print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
+ files = (data.getVar( "BBFILES", cfg, 1 ) or "").split()
+ data.setVar("BBFILES", " ".join(files), cfg)
+
+ if not len(files):
+ files = get_bbfiles()
+
+ if not len(files):
+ bb.error("no files to build.")
+
+ newfiles = []
+ for f in files:
+ if os.path.isdir(f):
+ dirfiles = find_bbfiles(f)
+ if dirfiles:
+ newfiles += dirfiles
+ continue
+ newfiles += glob.glob(f) or [ f ]
+
+ bbmask = bb.data.getVar('BBMASK', cfg, 1) or ""
+ try:
+ bbmask_compiled = re.compile(bbmask)
+ except sre_constants.error:
+ bb.fatal("BBMASK is not a valid regular expression.")
+
+ for i in xrange( len( newfiles ) ):
+ f = newfiles[i]
+ if bbmask and bbmask_compiled.search(f):
+ bb.debug(1, "bbmake: skipping %s" % f)
+ masked += 1
+ continue
+ debug(1, "bbmake: parsing %s" % f)
+
+ # read a file's metadata
+ try:
+ bb_data, fromCache = load_bbfile(f)
+ if fromCache: cached += 1
+ else: parsed += 1
+ deps = None
+ if bb_data is not None:
+ # allow metadata files to add items to BBFILES
+ #data.update_data(pkgdata[f])
+ addbbfiles = data.getVar('BBFILES', bb_data) or None
+ if addbbfiles:
+ for aof in addbbfiles.split():
+ if not files.count(aof):
+ if not os.path.isabs(aof):
+ aof = os.path.join(os.path.dirname(f),aof)
+ files.append(aof)
+ for var in bb_data.keys():
+ if data.getVarFlag(var, "handler", bb_data) and data.getVar(var, bb_data):
+ event.register(data.getVar(var, bb_data))
+ pkgdata[f] = bb_data
+
+ # now inform the caller
+ if collect_bbfiles.cb is not None:
+ collect_bbfiles.cb( i + 1, len( newfiles ), f, bb_data, fromCache )
+
+ except IOError, e:
+ bb.error("opening %s: %s" % (f, e))
+ pass
+ except bb.parse.SkipPackage:
+ skipped += 1
+ pass
+ except KeyboardInterrupt:
+ raise
+ except Exception, e:
+ bb.error("%s while parsing %s" % (e, f))
+
+ if collect_bbfiles.cb is not None:
+ print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
+
+def explode_version(s):
+ import string
+ r = []
+ alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
+ numeric_regexp = re.compile('^(\d+)(.*)$')
+ while (s != ''):
+ if s[0] in digits:
+ m = numeric_regexp.match(s)
+ r.append(int(m.group(1)))
+ s = m.group(2)
+ continue
+ if s[0] in ascii_letters:
+ m = alpha_regexp.match(s)
+ r.append(m.group(1))
+ s = m.group(2)
+ continue
+ s = s[1:]
+ return r
+
+def vercmp_part(a, b):
+ va = explode_version(a)
+ vb = explode_version(b)
+ while True:
+ if va == []:
+ ca = None
+ else:
+ ca = va.pop(0)
+ if vb == []:
+ cb = None
+ else:
+ cb = vb.pop(0)
+ if ca == None and cb == None:
+ return 0
+ if ca > cb:
+ return 1
+ if ca < cb:
+ return -1
+
+def vercmp(ta, tb):
+ (va, ra) = ta
+ (vb, rb) = tb
+
+ r = vercmp_part(va, vb)
+ if (r == 0):
+ r = vercmp_part(ra, rb)
+ return r
diff --git a/trunk/bitbake/lib/bb/manifest.py b/trunk/bitbake/lib/bb/manifest.py
new file mode 100644
index 000000000..30bb45472
--- /dev/null
+++ b/trunk/bitbake/lib/bb/manifest.py
@@ -0,0 +1,144 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# Copyright (C) 2003, 2004 Chris Larson
+#
+# This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+
+import os, sys
+import bb, bb.data
+
+def getfields(line):
+ fields = {}
+ fieldmap = ( "pkg", "src", "dest", "type", "mode", "uid", "gid", "major", "minor", "start", "inc", "count" )
+ for f in xrange(len(fieldmap)):
+ fields[fieldmap[f]] = None
+
+ if not line:
+ return None
+
+ splitline = line.split()
+ if not len(splitline):
+ return None
+
+ try:
+ for f in xrange(len(fieldmap)):
+ if splitline[f] == '-':
+ continue
+ fields[fieldmap[f]] = splitline[f]
+ except IndexError:
+ pass
+ return fields
+
+def parse (mfile, d):
+ manifest = []
+ while 1:
+ line = mfile.readline()
+ if not line:
+ break
+ if line.startswith("#"):
+ continue
+ fields = getfields(line)
+ if not fields:
+ continue
+ manifest.append(fields)
+ return manifest
+
+def emit (func, manifest, d):
+#str = "%s () {\n" % func
+ str = ""
+ for line in manifest:
+ emittedline = emit_line(func, line, d)
+ if not emittedline:
+ continue
+ str += emittedline + "\n"
+# str += "}\n"
+ return str
+
+def mangle (func, line, d):
+ import copy
+ newline = copy.copy(line)
+ src = bb.data.expand(newline["src"], d)
+
+ if src:
+ if not os.path.isabs(src):
+ src = "${WORKDIR}/" + src
+
+ dest = newline["dest"]
+ if not dest:
+ return
+
+ if dest.startswith("/"):
+ dest = dest[1:]
+
+ if func is "do_install":
+ dest = "${D}/" + dest
+
+ elif func is "do_populate":
+ dest = "${WORKDIR}/install/" + newline["pkg"] + "/" + dest
+
+ elif func is "do_stage":
+ varmap = {}
+ varmap["${bindir}"] = "${STAGING_DIR}/${HOST_SYS}/bin"
+ varmap["${libdir}"] = "${STAGING_DIR}/${HOST_SYS}/lib"
+ varmap["${includedir}"] = "${STAGING_DIR}/${HOST_SYS}/include"
+ varmap["${datadir}"] = "${STAGING_DATADIR}"
+
+ matched = 0
+ for key in varmap.keys():
+ if dest.startswith(key):
+ dest = varmap[key] + "/" + dest[len(key):]
+ matched = 1
+ if not matched:
+ newline = None
+ return
+ else:
+ newline = None
+ return
+
+ newline["src"] = src
+ newline["dest"] = dest
+ return newline
+
+def emit_line (func, line, d):
+ import copy
+ newline = copy.deepcopy(line)
+ newline = mangle(func, newline, d)
+ if not newline:
+ return None
+
+ str = ""
+ type = newline["type"]
+ mode = newline["mode"]
+ src = newline["src"]
+ dest = newline["dest"]
+ if type is "d":
+ str = "install -d "
+ if mode:
+ str += "-m %s " % mode
+ str += dest
+ elif type is "f":
+ if not src:
+ return None
+ if dest.endswith("/"):
+ str = "install -d "
+ str += dest + "\n"
+ str += "install "
+ else:
+ str = "install -D "
+ if mode:
+ str += "-m %s " % mode
+ str += src + " " + dest
+ del newline
+ return str
diff --git a/trunk/bitbake/lib/bb/parse/BBHandler.py b/trunk/bitbake/lib/bb/parse/BBHandler.py
new file mode 100644
index 000000000..d38668505
--- /dev/null
+++ b/trunk/bitbake/lib/bb/parse/BBHandler.py
@@ -0,0 +1,378 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""class for handling .bb files
+
+ Reads a .bb file and obtains its metadata
+
+ Copyright (C) 2003, 2004 Chris Larson
+ Copyright (C) 2003, 2004 Phil Blundell
+
+ This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place, Suite 330, Boston, MA 02111-1307 USA."""
+
+import re, bb, os, sys
+import bb.fetch, bb.build
+from bb import debug, data, fetch, fatal
+
+from bb.parse.ConfHandler import include, localpath, obtain, init
+from bb.parse import ParseError
+
+__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
+__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
+__export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
+__addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
+__addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
+__def_regexp__ = re.compile( r"def\s+(\w+).*:" )
+__python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
+__word__ = re.compile(r"\S+")
+
+__infunc__ = ""
+__inpython__ = False
+__body__ = []
+__bbpath_found__ = 0
+__classname__ = ""
+classes = [ None, ]
+
+def supports(fn, d):
+ localfn = localpath(fn, d)
+ return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
+
+def inherit(files, d):
+ __inherit_cache = data.getVar('__inherit_cache', d) or ""
+ fn = ""
+ lineno = 0
+ for f in files:
+ file = data.expand(f, d)
+ if file[0] != "/" and file[-8:] != ".bbclass":
+ file = os.path.join('classes', '%s.bbclass' % file)
+
+ if not file in __inherit_cache.split():
+ debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
+ __inherit_cache += " %s" % file
+ include(fn, file, d)
+ data.setVar('__inherit_cache', __inherit_cache, d)
+
+
+def handle(fn, d, include = 0):
+ global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
+ __body__ = []
+ __bbpath_found__ = 0
+ __infunc__ = ""
+ __classname__ = ""
+ __residue__ = []
+
+ if include == 0:
+ debug(2, "BB " + fn + ": handle(data)")
+ else:
+ debug(2, "BB " + fn + ": handle(data, include)")
+
+ (root, ext) = os.path.splitext(os.path.basename(fn))
+ init(d)
+
+ if ext == ".bbclass":
+ __classname__ = root
+ classes.append(__classname__)
+
+ if include != 0:
+ oldfile = data.getVar('FILE', d)
+ else:
+ oldfile = None
+
+ fn = obtain(fn, d)
+ bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
+ if not os.path.isabs(fn):
+ f = None
+ for p in bbpath:
+ p = data.expand(p, d)
+ j = os.path.join(p, fn)
+ if os.access(j, os.R_OK):
+ abs_fn = j
+ f = open(j, 'r')
+ break
+ if f is None:
+ raise IOError("file not found")
+ else:
+ f = open(fn,'r')
+ abs_fn = fn
+
+ if ext != ".bbclass":
+ bbpath.insert(0, os.path.dirname(abs_fn))
+ data.setVar('BBPATH', ":".join(bbpath), d)
+
+ if include:
+ bb.parse.mark_dependency(d, abs_fn)
+
+ if ext != ".bbclass":
+ data.setVar('FILE', fn, d)
+ i = (data.getVar("INHERIT", d, 1) or "").split()
+ if not "base" in i and __classname__ != "base":
+ i[0:0] = ["base"]
+ inherit(i, d)
+
+ lineno = 0
+ while 1:
+ lineno = lineno + 1
+ s = f.readline()
+ if not s: break
+ s = s.rstrip()
+ feeder(lineno, s, fn, d)
+ if __inpython__:
+ # add a blank line to close out any python definition
+ feeder(lineno + 1, "", fn, d)
+ if ext == ".bbclass":
+ classes.remove(__classname__)
+ else:
+ if include == 0:
+ data.expandKeys(d)
+ data.update_data(d)
+ anonqueue = data.getVar("__anonqueue", d, 1) or []
+ for anon in anonqueue:
+ data.setVar("__anonfunc", anon["content"], d)
+ data.setVarFlags("__anonfunc", anon["flags"], d)
+ from bb import build
+ try:
+ t = data.getVar('T', d)
+ data.setVar('T', '${TMPDIR}/', d)
+ build.exec_func("__anonfunc", d)
+ data.delVar('T', d)
+ if t:
+ data.setVar('T', t, d)
+ except Exception, e:
+ bb.debug(1, "executing anonymous function: %s" % e)
+ raise
+ data.delVar("__anonqueue", d)
+ data.delVar("__anonfunc", d)
+ set_additional_vars(fn, d, include)
+ data.update_data(d)
+
+ for var in data.keys(d):
+ if data.getVarFlag(var, 'handler', d):
+ bb.event.register(data.getVar(var, d))
+ continue
+
+ if not data.getVarFlag(var, 'task', d):
+ continue
+
+ deps = data.getVarFlag(var, 'deps', d) or []
+ postdeps = data.getVarFlag(var, 'postdeps', d) or []
+ bb.build.add_task(var, deps, d)
+ for p in postdeps:
+ pdeps = data.getVarFlag(p, 'deps', d) or []
+ pdeps.append(var)
+ data.setVarFlag(p, 'deps', pdeps, d)
+ bb.build.add_task(p, pdeps, d)
+ bbpath.pop(0)
+ if oldfile:
+ bb.data.setVar("FILE", oldfile, d)
+ return d
+
+def feeder(lineno, s, fn, d):
+ global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, __bbpath_found__, classes, bb, __residue__
+ if __infunc__:
+ if s == '}':
+ __body__.append('')
+ data.setVar(__infunc__, '\n'.join(__body__), d)
+ data.setVarFlag(__infunc__, "func", 1, d)
+ if __infunc__ == "__anonymous":
+ anonqueue = bb.data.getVar("__anonqueue", d) or []
+ anonitem = {}
+ anonitem["content"] = bb.data.getVar("__anonymous", d)
+ anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
+ anonqueue.append(anonitem)
+ bb.data.setVar("__anonqueue", anonqueue, d)
+ bb.data.delVarFlags("__anonymous", d)
+ bb.data.delVar("__anonymous", d)
+ __infunc__ = ""
+ __body__ = []
+ else:
+ __body__.append(s)
+ return
+
+ if __inpython__:
+ m = __python_func_regexp__.match(s)
+ if m:
+ __body__.append(s)
+ return
+ else:
+ text = '\n'.join(__body__)
+ comp = compile(text, "<bb>", "exec")
+ exec comp in __builtins__
+ __body__ = []
+ __inpython__ = False
+ funcs = data.getVar('__functions__', d) or ""
+ data.setVar('__functions__', "%s\n%s" % (funcs, text), d)
+# fall through
+
+ if s == '' or s[0] == '#': return # skip comments and empty lines
+
+ if s[-1] == '\\':
+ __residue__.append(s[:-1])
+ return
+
+ s = "".join(__residue__) + s
+ __residue__ = []
+
+ m = __func_start_regexp__.match(s)
+ if m:
+ __infunc__ = m.group("func") or "__anonymous"
+ key = __infunc__
+ if data.getVar(key, d):
+# clean up old version of this piece of metadata, as its
+# flags could cause problems
+ data.setVarFlag(key, 'python', None, d)
+ data.setVarFlag(key, 'fakeroot', None, d)
+ if m.group("py") is not None:
+ data.setVarFlag(key, "python", "1", d)
+ else:
+ data.delVarFlag(key, "python", d)
+ if m.group("fr") is not None:
+ data.setVarFlag(key, "fakeroot", "1", d)
+ else:
+ data.delVarFlag(key, "fakeroot", d)
+ return
+
+ m = __def_regexp__.match(s)
+ if m:
+ __body__.append(s)
+ __inpython__ = True
+ return
+
+ m = __export_func_regexp__.match(s)
+ if m:
+ fns = m.group(1)
+ n = __word__.findall(fns)
+ for f in n:
+ allvars = []
+ allvars.append(f)
+ allvars.append(classes[-1] + "_" + f)
+
+ vars = [[ allvars[0], allvars[1] ]]
+ if len(classes) > 1 and classes[-2] is not None:
+ allvars.append(classes[-2] + "_" + f)
+ vars = []
+ vars.append([allvars[2], allvars[1]])
+ vars.append([allvars[0], allvars[2]])
+
+ for (var, calledvar) in vars:
+ if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
+ continue
+
+ if data.getVar(var, d):
+ data.setVarFlag(var, 'python', None, d)
+ data.setVarFlag(var, 'func', None, d)
+
+ for flag in [ "func", "python" ]:
+ if data.getVarFlag(calledvar, flag, d):
+ data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
+ for flag in [ "dirs" ]:
+ if data.getVarFlag(var, flag, d):
+ data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
+
+ if data.getVarFlag(calledvar, "python", d):
+ data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
+ else:
+ data.setVar(var, "\t" + calledvar + "\n", d)
+ data.setVarFlag(var, 'export_func', '1', d)
+
+ return
+
+ m = __addtask_regexp__.match(s)
+ if m:
+ func = m.group("func")
+ before = m.group("before")
+ after = m.group("after")
+ if func is None:
+ return
+ var = "do_" + func
+
+ data.setVarFlag(var, "task", 1, d)
+
+ if after is not None:
+# set up deps for function
+ data.setVarFlag(var, "deps", after.split(), d)
+ if before is not None:
+# set up things that depend on this func
+ data.setVarFlag(var, "postdeps", before.split(), d)
+ return
+
+ m = __addhandler_regexp__.match(s)
+ if m:
+ fns = m.group(1)
+ hs = __word__.findall(fns)
+ for h in hs:
+ data.setVarFlag(h, "handler", 1, d)
+ return
+
+ m = __inherit_regexp__.match(s)
+ if m:
+
+ files = m.group(1)
+ n = __word__.findall(files)
+ inherit(n, d)
+ return
+
+ from bb.parse import ConfHandler
+ return ConfHandler.feeder(lineno, s, fn, d)
+
+__pkgsplit_cache__={}
+def vars_from_file(mypkg, d):
+ if not mypkg:
+ return (None, None, None)
+ if mypkg in __pkgsplit_cache__:
+ return __pkgsplit_cache__[mypkg]
+
+ myfile = os.path.splitext(os.path.basename(mypkg))
+ parts = myfile[0].split('_')
+ __pkgsplit_cache__[mypkg] = parts
+ exp = 3 - len(parts)
+ tmplist = []
+ while exp != 0:
+ exp -= 1
+ tmplist.append(None)
+ parts.extend(tmplist)
+ return parts
+
+def set_additional_vars(file, d, include):
+ """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
+
+ debug(2,"BB %s: set_additional_vars" % file)
+
+ src_uri = data.getVar('SRC_URI', d)
+ if not src_uri:
+ return
+ src_uri = data.expand(src_uri, d)
+
+ a = data.getVar('A', d)
+ if a:
+ a = data.expand(a, d).split()
+ else:
+ a = []
+
+ from bb import fetch
+ try:
+ fetch.init(src_uri.split(), d)
+ except fetch.NoMethodError:
+ pass
+ except bb.MalformedUrl,e:
+ raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
+
+ a += fetch.localpaths(d)
+ del fetch
+ data.setVar('A', " ".join(a), d)
+
+
+# Add us to the handlers list
+from bb.parse import handlers
+handlers.append({'supports': supports, 'handle': handle, 'init': init})
+del handlers
diff --git a/trunk/bitbake/lib/bb/parse/ConfHandler.py b/trunk/bitbake/lib/bb/parse/ConfHandler.py
new file mode 100644
index 000000000..70451d649
--- /dev/null
+++ b/trunk/bitbake/lib/bb/parse/ConfHandler.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""class for handling configuration data files
+
+ Reads a .conf file and obtains its metadata
+
+ Copyright (C) 2003, 2004 Chris Larson
+ Copyright (C) 2003, 2004 Phil Blundell
+
+ This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place, Suite 330, Boston, MA 02111-1307 USA."""
+
+import re, bb.data, os, sys
+from bb import debug, fatal
+
+#__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
+__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}/]+)(\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?\s*((?P<colon>:=)|(?P<ques>\?=)|(?P<append>\+=)|(?P<prepend>=\+)|=)\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
+__include_regexp__ = re.compile( r"include\s+(.+)" )
+
+def init(data):
+ if not bb.data.getVar('TOPDIR', data):
+ bb.data.setVar('TOPDIR', os.getcwd(), data)
+ if not bb.data.getVar('BBPATH', data):
+ bb.data.setVar('BBPATH', os.path.join(sys.prefix, 'share', 'bitbake'), data)
+
+def supports(fn, d):
+ return localpath(fn, d)[-5:] == ".conf"
+
+def localpath(fn, d):
+ if os.path.exists(fn):
+ return fn
+
+ localfn = None
+ try:
+ localfn = bb.fetch.localpath(fn, d)
+ except bb.MalformedUrl:
+ pass
+
+ if not localfn:
+ localfn = fn
+ return localfn
+
+def obtain(fn, data = bb.data.init()):
+ import sys, bb
+ fn = bb.data.expand(fn, data)
+ localfn = bb.data.expand(localpath(fn, data), data)
+
+ if localfn != fn:
+ dldir = bb.data.getVar('DL_DIR', data, 1)
+ if not dldir:
+ debug(1, "obtain: DL_DIR not defined")
+ return localfn
+ bb.mkdirhier(dldir)
+ try:
+ bb.fetch.init([fn])
+ except bb.fetch.NoMethodError:
+ (type, value, traceback) = sys.exc_info()
+ debug(1, "obtain: no method: %s" % value)
+ return localfn
+
+ try:
+ bb.fetch.go(data)
+ except bb.fetch.MissingParameterError:
+ (type, value, traceback) = sys.exc_info()
+ debug(1, "obtain: missing parameters: %s" % value)
+ return localfn
+ except bb.fetch.FetchError:
+ (type, value, traceback) = sys.exc_info()
+ debug(1, "obtain: failed: %s" % value)
+ return localfn
+ return localfn
+
+
+def include(oldfn, fn, data = bb.data.init()):
+ if oldfn == fn: # prevent infinate recursion
+ return None
+
+ import bb
+ fn = bb.data.expand(fn, data)
+ oldfn = bb.data.expand(oldfn, data)
+
+ from bb.parse import handle
+ try:
+ ret = handle(fn, data, 1)
+ except IOError:
+ debug(2, "CONF file '%s' not found" % fn)
+
+def handle(fn, data = bb.data.init(), include = 0):
+ if include:
+ inc_string = "including"
+ else:
+ inc_string = "reading"
+ init(data)
+
+ if include == 0:
+ bb.data.inheritFromOS(data)
+ oldfile = None
+ else:
+ oldfile = bb.data.getVar('FILE', data)
+
+ fn = obtain(fn, data)
+ bbpath = []
+ if not os.path.isabs(fn):
+ f = None
+ vbbpath = bb.data.getVar("BBPATH", data)
+ if vbbpath:
+ bbpath += vbbpath.split(":")
+ for p in bbpath:
+ currname = os.path.join(bb.data.expand(p, data), fn)
+ if os.access(currname, os.R_OK):
+ f = open(currname, 'r')
+ abs_fn = currname
+ debug(1, "CONF %s %s" % (inc_string, currname))
+ break
+ if f is None:
+ raise IOError("file not found")
+ else:
+ f = open(fn,'r')
+ debug(1, "CONF %s %s" % (inc_string,fn))
+ abs_fn = fn
+
+ if include:
+ bb.parse.mark_dependency(data, abs_fn)
+
+ lineno = 0
+ bb.data.setVar('FILE', fn, data)
+ while 1:
+ lineno = lineno + 1
+ s = f.readline()
+ if not s: break
+ w = s.strip()
+ if not w: continue # skip empty lines
+ s = s.rstrip()
+ if s[0] == '#': continue # skip comments
+ while s[-1] == '\\':
+ s2 = f.readline()[:-1].strip()
+ lineno = lineno + 1
+ s = s[:-1] + s2
+ feeder(lineno, s, fn, data)
+
+ if oldfile:
+ bb.data.setVar('FILE', oldfile, data)
+ return data
+
+def feeder(lineno, s, fn, data = bb.data.init()):
+ m = __config_regexp__.match(s)
+ if m:
+ groupd = m.groupdict()
+ key = groupd["var"]
+ if "exp" in groupd and groupd["exp"] != None:
+ bb.data.setVarFlag(key, "export", 1, data)
+ if "ques" in groupd and groupd["ques"] != None:
+ val = bb.data.getVar(key, data)
+ if val == None:
+ val = groupd["value"]
+ elif "colon" in groupd and groupd["colon"] != None:
+ val = bb.data.expand(groupd["value"], data)
+ elif "append" in groupd and groupd["append"] != None:
+ val = "%s %s" % ((bb.data.getVar(key, data) or ""), groupd["value"])
+ elif "prepend" in groupd and groupd["prepend"] != None:
+ val = "%s %s" % (groupd["value"], (bb.data.getVar(key, data) or ""))
+ else:
+ val = groupd["value"]
+ if 'flag' in groupd and groupd['flag'] != None:
+# bb.note("setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val))
+ bb.data.setVarFlag(key, groupd['flag'], val, data)
+ else:
+ bb.data.setVar(key, val, data)
+ return
+
+ m = __include_regexp__.match(s)
+ if m:
+ s = bb.data.expand(m.group(1), data)
+# debug(2, "CONF %s:%d: including %s" % (fn, lineno, s))
+ include(fn, s, data)
+ return
+
+ raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s));
+
+# Add us to the handlers list
+from bb.parse import handlers
+handlers.append({'supports': supports, 'handle': handle, 'init': init})
+del handlers
diff --git a/trunk/bitbake/lib/bb/parse/__init__.py b/trunk/bitbake/lib/bb/parse/__init__.py
new file mode 100644
index 000000000..8877b6f40
--- /dev/null
+++ b/trunk/bitbake/lib/bb/parse/__init__.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake Parsers
+
+File parsers for the BitBake build tools.
+
+Copyright (C) 2003, 2004 Chris Larson
+Copyright (C) 2003, 2004 Phil Blundell
+
+This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+
+Based on functions from the base bb module, Copyright 2003 Holger Schurig
+"""
+__version__ = '1.0'
+
+__all__ = [ 'handlers', 'supports', 'handle', 'init', 'ConfHandler', 'BBHandler', 'ParseError' ]
+handlers = []
+
+class ParseError(Exception):
+ """Exception raised when parsing fails"""
+
+class SkipPackage(Exception):
+ """Exception raised to skip this package"""
+
+import ConfHandler
+ConfHandler.ParseError = ParseError
+import BBHandler
+BBHandler.ParseError = ParseError
+
+__mtime_cache = {}
+
+def cached_mtime(f):
+ import os
+ if not __mtime_cache.has_key(f):
+ __mtime_cache[f] = os.stat(f)[8]
+ return __mtime_cache[f]
+
+def mark_dependency(d, f):
+ import bb, os
+ if f.startswith('./'):
+ f = "%s/%s" % (os.getcwd(), f[2:])
+ deps = (bb.data.getVar('__depends', d) or "").split()
+ deps.append("%s@%s" % (f, cached_mtime(f)))
+ bb.data.setVar('__depends', " ".join(deps), d)
+
+def supports(fn, data):
+ """Returns true if we have a handler for this file, false otherwise"""
+ for h in handlers:
+ if h['supports'](fn, data):
+ return 1
+ return 0
+
+def handle(fn, data, include = 0):
+ """Call the handler that is appropriate for this file"""
+ for h in handlers:
+ if h['supports'](fn, data):
+ return h['handle'](fn, data, include)
+ raise ParseError("%s is not a BitBake file" % fn)
+
+def init(fn, data):
+ for h in handlers:
+ if h['supports'](fn):
+ return h['init'](data)
diff --git a/trunk/bitbake/lib/bb/shell.py b/trunk/bitbake/lib/bb/shell.py
new file mode 100644
index 000000000..5d5565455
--- /dev/null
+++ b/trunk/bitbake/lib/bb/shell.py
@@ -0,0 +1,764 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+##########################################################################
+#
+# Copyright (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>, Vanille Media
+#
+# This program 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; version 2 of the License.
+#
+# This program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+##########################################################################
+
+"""
+BitBake Shell
+
+IDEAS:
+ * list defined tasks per package
+ * list classes
+ * toggle force
+ * command to reparse just one (or more) bbfile(s)
+ * automatic check if reparsing is necessary (inotify?)
+ * frontend for bb file manipulation
+ * more shell-like features:
+ - shell lexer (shlex)
+ - output control, i.e. pipe output into grep, sort, etc.
+ - job control, i.e. bring running commands into background and foreground
+ - wildcards for commands, i.e. build *opie*
+ * start parsing in background right after startup
+ * print variable from package data
+ * ncurses interface
+ * read some initial commands from startup file (batch)
+
+MAYBE WORKING:
+ * poke doesn't work at all (outcommented atm.)
+
+PROBLEMS:
+ * force doesn't always work
+ * readline completion for commands with more than one parameters
+
+"""
+
+##########################################################################
+# Import and setup global variables
+##########################################################################
+
+try:
+ set
+except NameError:
+ from sets import Set as set
+import sys, os, imp, readline, socket, httplib, urllib, commands, popen2
+imp.load_source( "bitbake", os.path.dirname( sys.argv[0] )+"/bitbake" )
+from bb import data, parse, build, make, fatal
+
+__version__ = "0.5.0"
+__credits__ = """BitBake Shell Version %s (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
+Type 'help' for more information, press CTRL-D to exit.""" % __version__
+
+cmds = {}
+leave_mainloop = False
+last_exception = None
+cooker = None
+parsed = False
+debug = os.environ.get( "BBSHELL_DEBUG", "" )
+
+##########################################################################
+# Class BitBakeShellCommands
+##########################################################################
+
+class BitBakeShellCommands:
+ """This class contains the valid commands for the shell"""
+
+ def __init__( self, shell ):
+ """Register all the commands"""
+ self._shell = shell
+ for attr in BitBakeShellCommands.__dict__:
+ if not attr.startswith( "_" ):
+ if attr.endswith( "_" ):
+ command = attr[:-1].lower()
+ else:
+ command = attr[:].lower()
+ method = getattr( BitBakeShellCommands, attr )
+ debugOut( "registering command '%s'" % command )
+ # scan number of arguments
+ usage = getattr( method, "usage", "" )
+ if usage != "<...>":
+ numArgs = len( usage.split() )
+ else:
+ numArgs = -1
+ shell.registerCommand( command, method, numArgs, "%s %s" % ( command, usage ), method.__doc__ )
+
+ def _checkParsed( self ):
+ if not parsed:
+ print "SHELL: This command needs to parse bbfiles..."
+ self.parse( None )
+
+ def _findProvider( self, item ):
+ self._checkParsed()
+ preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, make.cfg, 1 )
+ if not preferred: preferred = item
+ try:
+ lv, lf, pv, pf = cooker.findBestProvider( preferred )
+ except KeyError:
+ if item in cooker.status.providers:
+ pf = cooker.status.providers[item][0]
+ else:
+ pf = None
+ return pf
+
+ def alias( self, params ):
+ """Register a new name for a command"""
+ new, old = params
+ if not old in cmds:
+ print "ERROR: Command '%s' not known" % old
+ else:
+ cmds[new] = cmds[old]
+ print "OK"
+ alias.usage = "<alias> <command>"
+
+ def buffer( self, params ):
+ """Dump specified output buffer"""
+ index = params[0]
+ print self._shell.myout.buffer( int( index ) )
+ buffer.usage = "<index>"
+
+ def buffers( self, params ):
+ """Show the available output buffers"""
+ commands = self._shell.myout.bufferedCommands()
+ if not commands:
+ print "SHELL: No buffered commands available yet. Start doing something."
+ else:
+ print "="*35, "Available Output Buffers", "="*27
+ for index, cmd in enumerate( commands ):
+ print "| %s %s" % ( str( index ).ljust( 3 ), cmd )
+ print "="*88
+
+ def build( self, params, cmd = "build" ):
+ """Build a providee"""
+ name = params[0]
+
+ oldcmd = make.options.cmd
+ make.options.cmd = cmd
+ cooker.build_cache = []
+ cooker.build_cache_fail = []
+
+ self._checkParsed()
+
+ try:
+ cooker.buildProvider( name )
+ except build.EventException, e:
+ print "ERROR: Couldn't build '%s'" % name
+ global last_exception
+ last_exception = e
+
+ make.options.cmd = oldcmd
+ build.usage = "<providee>"
+
+ def clean( self, params ):
+ """Clean a providee"""
+ self.build( params, "clean" )
+ clean.usage = "<providee>"
+
+ def compile( self, params ):
+ """Execute 'compile' on a providee"""
+ self.build( params, "compile" )
+ compile.usage = "<providee>"
+
+ def configure( self, params ):
+ """Execute 'configure' on a providee"""
+ self.build( params, "configure" )
+ configure.usage = "<providee>"
+
+ def edit( self, params ):
+ """Call $EDITOR on a providee"""
+ name = params[0]
+ bbfile = self._findProvider( name )
+ if bbfile is not None:
+ os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), bbfile ) )
+ else:
+ print "ERROR: Nothing provides '%s'" % name
+ edit.usage = "<providee>"
+
+ def environment( self, params ):
+ """Dump out the outer BitBake environment (see bbread)"""
+ data.emit_env(sys.__stdout__, make.cfg, True)
+
+ def exit_( self, params ):
+ """Leave the BitBake Shell"""
+ debugOut( "setting leave_mainloop to true" )
+ global leave_mainloop
+ leave_mainloop = True
+
+ def fetch( self, params ):
+ """Fetch a providee"""
+ self.build( params, "fetch" )
+ fetch.usage = "<providee>"
+
+ def fileBuild( self, params, cmd = "build" ):
+ """Parse and build a .bb file"""
+ name = params[0]
+ bf = completeFilePath( name )
+ print "SHELL: Calling '%s' on '%s'" % ( cmd, bf )
+
+ oldcmd = make.options.cmd
+ make.options.cmd = cmd
+ cooker.build_cache = []
+ cooker.build_cache_fail = []
+
+ try:
+ bbfile_data = parse.handle( bf, make.cfg )
+ except parse.ParseError:
+ print "ERROR: Unable to open or parse '%s'" % bf
+ else:
+ item = data.getVar('PN', bbfile_data, 1)
+ data.setVar( "_task_cache", [], bbfile_data ) # force
+ try:
+ cooker.tryBuildPackage( os.path.abspath( bf ), item, bbfile_data )
+ except build.EventException, e:
+ print "ERROR: Couldn't build '%s'" % name
+ global last_exception
+ last_exception = e
+
+ make.options.cmd = oldcmd
+ fileBuild.usage = "<bbfile>"
+
+ def fileClean( self, params ):
+ """Clean a .bb file"""
+ self.fileBuild( params, "clean" )
+ fileClean.usage = "<bbfile>"
+
+ def fileEdit( self, params ):
+ """Call $EDITOR on a .bb file"""
+ name = params[0]
+ os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), completeFilePath( name ) ) )
+ fileEdit.usage = "<bbfile>"
+
+ def fileRebuild( self, params ):
+ """Rebuild (clean & build) a .bb file"""
+ self.fileClean( params )
+ self.fileBuild( params )
+ fileRebuild.usage = "<bbfile>"
+
+ def force( self, params ):
+ """Toggle force task execution flag (see bitbake -f)"""
+ make.options.force = not make.options.force
+ print "SHELL: Force Flag is now '%s'" % repr( make.options.force )
+
+ def help( self, params ):
+ """Show a comprehensive list of commands and their purpose"""
+ print "="*30, "Available Commands", "="*30
+ allcmds = cmds.keys()
+ allcmds.sort()
+ for cmd in allcmds:
+ function,numparams,usage,helptext = cmds[cmd]
+ print "| %s | %s" % (usage.ljust(30), helptext)
+ print "="*78
+
+ def lastError( self, params ):
+ """Show the reason or log that was produced by the last BitBake event exception"""
+ if last_exception is None:
+ print "SHELL: No Errors yet (Phew)..."
+ else:
+ reason, event = last_exception.args
+ print "SHELL: Reason for the last error: '%s'" % reason
+ if ':' in reason:
+ msg, filename = reason.split( ':' )
+ filename = filename.strip()
+ print "SHELL: Dumping log file for last error:"
+ try:
+ print open( filename ).read()
+ except IOError:
+ print "ERROR: Couldn't open '%s'" % filename
+
+ def new( self, params ):
+ """Create a new .bb file and open the editor"""
+ dirname, filename = params
+ packages = '/'.join( data.getVar( "BBFILES", make.cfg, 1 ).split('/')[:-2] )
+ fulldirname = "%s/%s" % ( packages, dirname )
+
+ if not os.path.exists( fulldirname ):
+ print "SHELL: Creating '%s'" % fulldirname
+ os.mkdir( fulldirname )
+ if os.path.exists( fulldirname ) and os.path.isdir( fulldirname ):
+ if os.path.exists( "%s/%s" % ( fulldirname, filename ) ):
+ print "SHELL: ERROR: %s/%s already exists" % ( fulldirname, filename )
+ return False
+ print "SHELL: Creating '%s/%s'" % ( fulldirname, filename )
+ newpackage = open( "%s/%s" % ( fulldirname, filename ), "w" )
+ print >>newpackage,"""DESCRIPTION = ""
+SECTION = ""
+AUTHOR = ""
+HOMEPAGE = ""
+MAINTAINER = ""
+LICENSE = "GPL"
+PR = "r0"
+
+SRC_URI = ""
+
+#inherit base
+
+#do_configure() {
+#
+#}
+
+#do_compile() {
+#
+#}
+
+#do_stage() {
+#
+#}
+
+#do_install() {
+#
+#}
+"""
+ newpackage.close()
+ os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) )
+ new.usage = "<directory> <filename>"
+
+ def pasteBin( self, params ):
+ """Send a command + output buffer to http://pastebin.com"""
+ index = params[0]
+ contents = self._shell.myout.buffer( int( index ) )
+ status, error, location = sendToPastebin( contents )
+ if status == 302:
+ print "SHELL: Pasted to %s" % location
+ else:
+ print "ERROR: %s %s" % ( status, error )
+ pasteBin.usage = "<index>"
+
+ def pasteLog( self, params ):
+ """Send the last event exception error log (if there is one) to http://pastebin.com"""
+ if last_exception is None:
+ print "SHELL: No Errors yet (Phew)..."
+ else:
+ reason, event = last_exception.args
+ print "SHELL: Reason for the last error: '%s'" % reason
+ if ':' in reason:
+ msg, filename = reason.split( ':' )
+ filename = filename.strip()
+ print "SHELL: Pasting log file to pastebin..."
+
+ status, error, location = sendToPastebin( open( filename ).read() )
+
+ if status == 302:
+ print "SHELL: Pasted to %s" % location
+ else:
+ print "ERROR: %s %s" % ( status, error )
+
+ def patch( self, params ):
+ """Execute 'patch' command on a providee"""
+ self.build( params, "patch" )
+ patch.usage = "<providee>"
+
+ def parse( self, params ):
+ """(Re-)parse .bb files and calculate the dependency graph"""
+ cooker.status = cooker.ParsingStatus()
+ ignore = data.getVar("ASSUME_PROVIDED", make.cfg, 1) or ""
+ cooker.status.ignored_dependencies = set( ignore.split() )
+ cooker.handleCollections( data.getVar("BBFILE_COLLECTIONS", make.cfg, 1) )
+
+ make.collect_bbfiles( cooker.myProgressCallback )
+ cooker.buildDepgraph()
+ global parsed
+ parsed = True
+ print
+
+ def getvar( self, params ):
+ """Dump the contents of an outer BitBake environment variable"""
+ var = params[0]
+ value = data.getVar( var, make.cfg, 1 )
+ print value
+ getvar.usage = "<variable>"
+
+ def peek( self, params ):
+ """Dump contents of variable defined in providee's metadata"""
+ name, var = params
+ bbfile = self._findProvider( name )
+ if bbfile is not None:
+ value = make.pkgdata[bbfile].getVar( var, 1 )
+ print value
+ else:
+ print "ERROR: Nothing provides '%s'" % name
+ peek.usage = "<providee> <variable>"
+
+ def poke( self, params ):
+ """Set contents of variable defined in providee's metadata"""
+ name, var, value = params
+ bbfile = self._findProvider( name )
+ d = make.pkgdata[bbfile]
+ if bbfile is not None:
+ data.setVar( var, value, d )
+
+ # mark the change semi persistant
+ make.pkgdata.setDirty(bbfile, d)
+ print "OK"
+ else:
+ print "ERROR: Nothing provides '%s'" % name
+ poke.usage = "<providee> <variable> <value>"
+
+ def print_( self, params ):
+ """Dump all files or providers"""
+ what = params[0]
+ if what == "files":
+ self._checkParsed()
+ for key in make.pkgdata.keys(): print key
+ elif what == "providers":
+ self._checkParsed()
+ for key in cooker.status.providers.keys(): print key
+ else:
+ print "Usage: print %s" % self.print_.usage
+ print_.usage = "<files|providers>"
+
+ def python( self, params ):
+ """Enter the expert mode - an interactive BitBake Python Interpreter"""
+ sys.ps1 = "EXPERT BB>>> "
+ sys.ps2 = "EXPERT BB... "
+ import code
+ interpreter = code.InteractiveConsole( dict( globals() ) )
+ interpreter.interact( "SHELL: Expert Mode - BitBake Python %s\nType 'help' for more information, press CTRL-D to switch back to BBSHELL." % sys.version )
+
+ def showdata( self, params ):
+ """Execute 'showdata' on a providee"""
+ self.build( params, "showdata" )
+ showdata.usage = "<providee>"
+
+ def setVar( self, params ):
+ """Set an outer BitBake environment variable"""
+ var, value = params
+ data.setVar( var, value, make.cfg )
+ print "OK"
+ setVar.usage = "<variable> <value>"
+
+ def rebuild( self, params ):
+ """Clean and rebuild a .bb file or a providee"""
+ self.build( params, "clean" )
+ self.build( params, "build" )
+ rebuild.usage = "<providee>"
+
+ def shell( self, params ):
+ """Execute a shell command and dump the output"""
+ if params != "":
+ print commands.getoutput( " ".join( params ) )
+ shell.usage = "<...>"
+
+ def stage( self, params ):
+ """Execute 'stage' on a providee"""
+ self.build( params, "stage" )
+ stage.usage = "<providee>"
+
+ def status( self, params ):
+ """<just for testing>"""
+ print "-" * 78
+ print "build cache = '%s'" % cooker.build_cache
+ print "build cache fail = '%s'" % cooker.build_cache_fail
+ print "building list = '%s'" % cooker.building_list
+ print "build path = '%s'" % cooker.build_path
+ print "consider_msgs_cache = '%s'" % cooker.consider_msgs_cache
+ print "build stats = '%s'" % cooker.stats
+ if last_exception is not None: print "last_exception = '%s'" % repr( last_exception.args )
+ print "memory output contents = '%s'" % self._shell.myout._buffer
+
+ def test( self, params ):
+ """<just for testing>"""
+ print "testCommand called with '%s'" % params
+
+ def unpack( self, params ):
+ """Execute 'unpack' on a providee"""
+ self.build( params, "unpack" )
+ unpack.usage = "<providee>"
+
+ def which( self, params ):
+ """Computes the providers for a given providee"""
+ item = params[0]
+
+ self._checkParsed()
+
+ preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, make.cfg, 1 )
+ if not preferred: preferred = item
+
+ try:
+ lv, lf, pv, pf = cooker.findBestProvider( preferred )
+ except KeyError:
+ lv, lf, pv, pf = (None,)*4
+
+ try:
+ providers = cooker.status.providers[item]
+ except KeyError:
+ print "SHELL: ERROR: Nothing provides", preferred
+ else:
+ for provider in providers:
+ if provider == pf: provider = " (***) %s" % provider
+ else: provider = " %s" % provider
+ print provider
+ which.usage = "<providee>"
+
+##########################################################################
+# Common helper functions
+##########################################################################
+
+def completeFilePath( bbfile ):
+ """Get the complete bbfile path"""
+ if not make.pkgdata: return bbfile
+ for key in make.pkgdata.keys():
+ if key.endswith( bbfile ):
+ return key
+ return bbfile
+
+def sendToPastebin( content ):
+ """Send content to http://www.pastebin.com"""
+ mydata = {}
+ mydata["parent_pid"] = ""
+ mydata["format"] = "bash"
+ mydata["code2"] = content
+ mydata["paste"] = "Send"
+ mydata["poster"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" )
+ params = urllib.urlencode( mydata )
+ headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
+
+ conn = httplib.HTTPConnection( "pastebin.com:80" )
+ conn.request("POST", "/", params, headers )
+
+ response = conn.getresponse()
+ conn.close()
+
+ return response.status, response.reason, response.getheader( "location" ) or "unknown"
+
+def completer( text, state ):
+ """Return a possible readline completion"""
+ debugOut( "completer called with text='%s', state='%d'" % ( text, state ) )
+
+ if state == 0:
+ line = readline.get_line_buffer()
+ if " " in line:
+ line = line.split()
+ # we are in second (or more) argument
+ if line[0] in cmds and hasattr( cmds[line[0]][0], "usage" ): # known command and usage
+ u = getattr( cmds[line[0]][0], "usage" ).split()[0]
+ if u == "<variable>":
+ allmatches = make.cfg.keys()
+ elif u == "<bbfile>":
+ if make.pkgdata is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
+ else: allmatches = [ x.split("/")[-1] for x in make.pkgdata.keys() ]
+ elif u == "<providee>":
+ if make.pkgdata is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
+ else: allmatches = cooker.status.providers.iterkeys()
+ else: allmatches = [ "(No tab completion available for this command)" ]
+ else: allmatches = [ "(No tab completion available for this command)" ]
+ else:
+ # we are in first argument
+ allmatches = cmds.iterkeys()
+
+ completer.matches = [ x for x in allmatches if x[:len(text)] == text ]
+ #print "completer.matches = '%s'" % completer.matches
+ if len( completer.matches ) > state:
+ return completer.matches[state]
+ else:
+ return None
+
+def debugOut( text ):
+ if debug:
+ sys.stderr.write( "( %s )\n" % text )
+
+def columnize( alist, width = 80 ):
+ """
+ A word-wrap function that preserves existing line breaks
+ and most spaces in the text. Expects that existing line
+ breaks are posix newlines (\n).
+ """
+ return reduce(lambda line, word, width=width: '%s%s%s' %
+ (line,
+ ' \n'[(len(line[line.rfind('\n')+1:])
+ + len(word.split('\n',1)[0]
+ ) >= width)],
+ word),
+ alist
+ )
+
+##########################################################################
+# Class MemoryOutput
+##########################################################################
+
+class MemoryOutput:
+ """File-like output class buffering the output of the last 10 commands"""
+ def __init__( self, delegate ):
+ self.delegate = delegate
+ self._buffer = []
+ self.text = []
+ self._command = None
+
+ def startCommand( self, command ):
+ self._command = command
+ self.text = []
+ def endCommand( self ):
+ if self._command is not None:
+ if len( self._buffer ) == 10: del self._buffer[0]
+ self._buffer.append( ( self._command, self.text ) )
+ def removeLast( self ):
+ if self._buffer:
+ del self._buffer[ len( self._buffer ) - 1 ]
+ self.text = []
+ self._command = None
+ def lastBuffer( self ):
+ if self._buffer:
+ return self._buffer[ len( self._buffer ) -1 ][1]
+ def bufferedCommands( self ):
+ return [ cmd for cmd, output in self._buffer ]
+ def buffer( self, i ):
+ if i < len( self._buffer ):
+ return "BB>> %s\n%s" % ( self._buffer[i][0], "".join( self._buffer[i][1] ) )
+ else: return "ERROR: Invalid buffer number. Buffer needs to be in (0, %d)" % ( len( self._buffer ) - 1 )
+ def write( self, text ):
+ if self._command is not None and text != "BB>> ": self.text.append( text )
+ if self.delegate is not None: self.delegate.write( text )
+ def flush( self ):
+ return self.delegate.flush()
+ def fileno( self ):
+ return self.delegate.fileno()
+ def isatty( self ):
+ return self.delegate.isatty()
+
+##########################################################################
+# Class BitBakeShell
+##########################################################################
+
+class BitBakeShell:
+
+ def __init__( self ):
+ """Register commands and set up readline"""
+ self.commands = BitBakeShellCommands( self )
+ self.myout = MemoryOutput( sys.stdout )
+ self.historyfilename = os.path.expanduser( "~/.bbsh_history" )
+ self.startupfilename = os.path.expanduser( "~/.bbsh_startup" )
+
+ readline.set_completer( completer )
+ readline.set_completer_delims( " " )
+ readline.parse_and_bind("tab: complete")
+
+ try:
+ readline.read_history_file( self.historyfilename )
+ except IOError:
+ pass # It doesn't exist yet.
+
+ print __credits__
+
+ def cleanup( self ):
+ """Write readline history and clean up resources"""
+ debugOut( "writing command history" )
+ try:
+ readline.write_history_file( self.historyfilename )
+ except:
+ print "SHELL: Unable to save command history"
+
+ def registerCommand( self, command, function, numparams = 0, usage = "", helptext = "" ):
+ """Register a command"""
+ if usage == "": usage = command
+ if helptext == "": helptext = function.__doc__ or "<not yet documented>"
+ cmds[command] = ( function, numparams, usage, helptext )
+
+ def processCommand( self, command, params ):
+ """Process a command. Check number of params and print a usage string, if appropriate"""
+ debugOut( "processing command '%s'..." % command )
+ try:
+ function, numparams, usage, helptext = cmds[command]
+ except KeyError:
+ print "SHELL: ERROR: '%s' command is not a valid command." % command
+ self.myout.removeLast()
+ else:
+ if (numparams != -1) and (not len( params ) == numparams):
+ print "Usage: '%s'" % usage
+ return
+
+ result = function( self.commands, params )
+ debugOut( "result was '%s'" % result )
+
+ def processStartupFile( self ):
+ """Read and execute all commands found in $HOME/.bbsh_startup"""
+ if os.path.exists( self.startupfilename ):
+ startupfile = open( self.startupfilename, "r" )
+ # save_stdout = sys.stdout
+ # sys.stdout = open( "/dev/null", "w" )
+ numCommands = 0
+ for cmdline in startupfile.readlines():
+ cmdline = cmdline.strip()
+ debugOut( "processing startup line '%s'" % cmdline )
+ if not cmdline:
+ continue
+ if "|" in cmdline:
+ print >>save_stdout, "ERROR: ';' in startup file is not allowed. Ignoring line"
+ continue
+ allCommands = cmdline.split( ';' )
+ for command in allCommands:
+ if ' ' in command:
+ self.processCommand( command.split()[0], command.split()[1:] )
+ else:
+ self.processCommand( command, "" )
+ numCommands += 1
+ print "SHELL: Processed %d commands from '%s'" % ( numCommands, self.startupfilename )
+
+ def main( self ):
+ """The main command loop"""
+ while not leave_mainloop:
+ try:
+ sys.stdout = self.myout.delegate
+ cmdline = raw_input( "BB>> " )
+ sys.stdout = self.myout
+ if cmdline:
+ allCommands = cmdline.split( ';' )
+ for command in allCommands:
+ pipecmd = None
+ #
+ # special case for expert mode
+ if command == 'python':
+ sys.stdout = self.myout.delegate
+ self.processCommand( command, "" )
+ sys.stdout = self.myout
+ else:
+ self.myout.startCommand( command )
+ if '|' in command: # disable output
+ command, pipecmd = command.split( '|' )
+ delegate = self.myout.delegate
+ self.myout.delegate = None
+ if ' ' in command:
+ self.processCommand( command.split()[0], command.split()[1:] )
+ else:
+ self.processCommand( command, "" )
+ self.myout.endCommand()
+ if pipecmd is not None: # restore output
+ self.myout.delegate = delegate
+
+ pipe = popen2.Popen4( pipecmd )
+ pipe.tochild.write( "\n".join( self.myout.lastBuffer() ) )
+ pipe.tochild.close()
+ sys.stdout.write( pipe.fromchild.read() )
+ #
+ except EOFError:
+ print
+ return
+ except KeyboardInterrupt:
+ print
+
+##########################################################################
+# Start function - called from the BitBake command line utility
+##########################################################################
+
+def start( aCooker ):
+ global cooker
+ cooker = aCooker
+ bbshell = BitBakeShell()
+ bbshell.processStartupFile()
+ bbshell.main()
+ bbshell.cleanup()
+
+if __name__ == "__main__":
+ print "SHELL: Sorry, this program should only be called by BitBake."
diff --git a/trunk/bitbake/setup.py b/trunk/bitbake/setup.py
new file mode 100755
index 000000000..43a9aea66
--- /dev/null
+++ b/trunk/bitbake/setup.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# Copyright (C) 2003 Chris Larson
+#
+# This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+
+from distutils.core import setup
+import os, sys
+
+# bbdir = os.path.join(sys.prefix, 'share', 'bitbake')
+# docdir = os.path.join(sys.prefix, 'share', 'doc')
+bbdir = os.path.join('bitbake')
+docdir = os.path.join('doc')
+
+def clean_doc(type):
+ origpath = os.path.abspath(os.curdir)
+ os.chdir(os.path.join(origpath, 'doc', 'manual'))
+ make = os.environ.get('MAKE') or 'make'
+ os.system('%s clean-%s' % (make, type))
+
+def generate_doc(type):
+ origpath = os.path.abspath(os.curdir)
+ os.chdir(os.path.join(origpath, 'doc', 'manual'))
+ make = os.environ.get('MAKE') or 'make'
+ ret = os.system('%s %s' % (make, type))
+ if ret != 0:
+ print "ERROR: Unable to generate html documentation."
+ sys.exit(ret)
+ os.chdir(origpath)
+
+if 'bdist' in sys.argv[1:]:
+ generate_doc('html')
+
+sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'lib'))
+import bb
+import glob
+setup(name='bitbake',
+ version=bb.__version__,
+ license='GPL',
+ url='http://developer.berlios.de/projects/bitbake/',
+ description='BitBake build tool',
+ long_description='BitBake is a simple tool for the execution of tasks. It is derived from Portage, which is the package management system used by the Gentoo Linux distribution. It is most commonly used to build packages, as it can easily use its rudamentary inheritence to abstract common operations, such as fetching sources, unpacking them, patching them, compiling them, and so on. It is the basis of the OpenEmbedded project, which is being used for OpenZaurus, Familiar, and a number of other Linux distributions.',
+ author='Chris Larson',
+ author_email='clarson@elinux.org',
+ packages=['bb', 'bb.parse'],
+ package_dir={'bb': os.path.join('lib', 'bb')},
+ scripts=[os.path.join('bin', 'bitbake'),
+ os.path.join('bin', 'bbread'),
+ os.path.join('bin', 'bbimage')],
+ data_files=[(os.path.join(bbdir, 'conf'), [os.path.join('conf', 'bitbake.conf')]),
+ (os.path.join(bbdir, 'classes'), [os.path.join('classes', 'base.bbclass')]),
+ (os.path.join(docdir, 'bitbake-%s' % bb.__version__, 'html'), glob.glob(os.path.join('doc', 'manual', 'html', '*.html'))),
+ (os.path.join(docdir, 'bitbake-%s' % bb.__version__, 'pdf'), glob.glob(os.path.join('doc', 'manual', 'pdf', '*.pdf'))),],
+ )
+
+if 'bdist' in sys.argv[1:]:
+ clean_doc('html')
diff --git a/trunk/bitbake_qa/bin/bittest b/trunk/bitbake_qa/bin/bittest
new file mode 100755
index 000000000..d211c95b2
--- /dev/null
+++ b/trunk/bitbake_qa/bin/bittest
@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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, os, optparse
+
+sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+
+from bittest import *
+
+try:
+ import bb
+ import bb.data
+except:
+ print "Use PYTHONPATH to point to bitbake/lib"
+ sys.exit(0)
+
+__version__ = 0.2
+__all_tests__ = ["patch_checker",
+ "source_checker",
+ "doc_checker",
+ "content_checker"]
+
+def handle_options( args ):
+ """
+ Handle the options and return the handled options and the rest (not parsed)
+ """
+ parser = optparse.OptionParser( version = "BitTest Bitbake Testing Tool version %s" % __version__,
+ usage = """%prog [options] [test ...]
+Executes the specified tests or if none are given all tests. The result is printed
+on the cmd line
+""" )
+
+ parser.add_option( "-o", "--output", help = "print the output to the file",
+ action = "store", dest = "output", default = None )
+ parser.add_option( "-f", "--format", help = "print the output in the specified format",
+ action = "store", dest = "format", default = None )
+
+ options, args = parser.parse_args( args )
+ return options, args[1:]
+
+def _load_config(file):
+ """
+ load a config file into a bb.data instance
+ """
+ try:
+ return bb.parse.handle(os.path.join('conf', file), bb.data.init() )
+ except IOError, e:
+ return None
+
+def _get_instances(tests):
+ test_inst = {}
+
+ # create instances
+ for test in tests:
+ test_inst[test] = __import__(test).create_test()
+
+ return test_inst
+
+def generate_results(test_results):
+ for result in test_results:
+ test_output = TestOutputText(result, test_results[result])
+ test_output.print_result()
+
+def run_tests(data,test_config,test_options, tests, bbfiles = None):
+ if bbfiles == None:
+ bbfiles = fileparser.find_files(bb.data.getVar('BBFILES', test_config).split(' '))
+
+ bb.note("Collected %d BitBake files" % len(bbfiles) )
+
+ tmp_dir = os.path.join(os.getcwd(),'tmp')
+ src_dir = os.path.join(os.getcwd(),'tmp_sources')
+ bb.mkdirhier(tmp_dir)
+ bb.mkdirhier(src_dir)
+
+ # now run the tests for each test
+ test_results = {}
+ test_instances = _get_instances(tests)
+
+ for test in test_instances:
+ test_results[test] = TestResult(test_instances[test].test_name())
+
+ for bbfile in bbfiles:
+
+ # now we do it for each configuration...
+ for (arch,os1,distro,machines) in test_options:
+ test_data = bb.data.createCopy(data)
+ bb.data.setVar('TARGET_ARCH', arch, test_data)
+ bb.data.setVar('TARGET_OS', os1, test_data)
+ bb.data.setVar('DISTRO', distro, test_data)
+
+ # include the distro
+ bb.parse.handle(os.path.join('conf/distro',distro+'.conf'),test_data,1)
+
+ # now for each machine and we can finally run the tests
+ for machine in machines:
+ machine_data = bb.data.createCopy(test_data)
+ bb.data.setVar('MACHINE', machine, machine_data)
+
+ try:
+ bb.parse.handle(os.path.join('conf/machine',machine+'.conf'),machine_data,1)
+ except:
+ bb.note("Machine %s is not known" % machine)
+
+ try:
+ bb_data = bb.parse.handle(bbfile, bb.data.createCopy(machine_data))
+ except bb.parse.SkipPackage:
+ bb.note("Skipping Package %s" % bbfile)
+ continue
+ except Exception, e:
+ bb.note("Error on parsing: %s:%s" % (bbfile, e))
+
+ # run the testcases now
+ for test in test_instances:
+ test_run = bb.data.createCopy(bb_data)
+
+ # be sure these variables are set
+ bb.data.setVar('TMPDIR', tmp_dir, test_run)
+ bb.data.setVar('DL_DIR', src_dir, test_run)
+
+
+ bb.data.update_data(test_run)
+ print "Running test for %s with machine: %s and distro: %s" % (bb.data.getVar('PN', test_run, True), machine, distro)
+ test_results[test].insert_result(test_instances[test].test(bbfile, test_run))
+
+ return test_results
+
+
+
+def start_testing():
+ """
+ Start with testing:
+ We will parse the options to decide which tests should be executed.
+ Then we will parse the base configuration (bitbake.conf) and afterwards
+ our unit testing configuration.
+ We will go through every bbfile, parse it and for each setup we will call
+ the testing method
+ """
+
+ options, args = handle_options( sys.argv )
+
+ tests = []
+ if len(args) == 0:
+ tests = __all_tests__
+ else:
+ for mode in args:
+ if not mode in __all_tests__ and not mode == "example":
+ bb.note("Test %s does not exist" % mode)
+ else:
+ tests.append(mode)
+
+ if len(tests) == 0:
+ bb.note("No tests to run exiting")
+ sys.exit(0)
+
+ bb.note("Running the following tests: %s" % tests )
+
+ # Parse the default config
+ data = _load_config('bitbake.conf')
+ if data == None:
+ bb.error("Could not parse the bitbake.conf")
+ bb.data.inheritFromOS(data)
+
+ # Parse the test configuration
+ test_config = _load_config('testrun.conf')
+ if test_config == None:
+ bb.error("Could not parse the bittest configuration file")
+ test_options = parse_test_options(test_config)
+
+ # start running the test
+ results = run_tests(data, test_config, test_options, tests)
+ generate_results(results)
+
+
+
+if __name__ == "__main__":
+ start_testing()
diff --git a/trunk/bitbake_qa/classes/base.bbclass b/trunk/bitbake_qa/classes/base.bbclass
new file mode 100755
index 000000000..e813bb3fd
--- /dev/null
+++ b/trunk/bitbake_qa/classes/base.bbclass
@@ -0,0 +1,775 @@
+PATCHES_DIR="${S}"
+
+def base_dep_prepend(d):
+ import bb;
+ #
+ # Ideally this will check a flag so we will operate properly in
+ # the case where host == build == target, for now we don't work in
+ # that case though.
+ #
+ deps = ""
+
+ # INHIBIT_DEFAULT_DEPS doesn't apply to the patch command. Whether or not
+ # we need that built is the responsibility of the patch function / class, not
+ # the application.
+ patchdeps = bb.data.getVar("PATCH_DEPENDS", d, 1)
+ if patchdeps and not patchdeps in bb.data.getVar("PROVIDES", d, 1):
+ deps = patchdeps
+
+ if not bb.data.getVar('INHIBIT_DEFAULT_DEPS', d):
+ if (bb.data.getVar('HOST_SYS', d, 1) !=
+ bb.data.getVar('BUILD_SYS', d, 1)):
+ deps += " virtual/${TARGET_PREFIX}gcc virtual/libc "
+ return deps
+
+def base_read_file(filename):
+ import bb
+ try:
+ f = file( filename, "r" )
+ except IOError, reason:
+ raise bb.build.FuncFailed("can't read from file '%s' (%s)", (filename,reason))
+ else:
+ return f.read().strip()
+ return None
+
+def base_conditional(variable, checkvalue, truevalue, falsevalue, d):
+ import bb
+ if bb.data.getVar(variable,d,1) == checkvalue:
+ return truevalue
+ else:
+ return falsevalue
+
+DEPENDS_prepend="${@base_dep_prepend(d)} "
+
+def base_set_filespath(path, d):
+ import os, bb
+ filespath = []
+ for p in path:
+ overrides = bb.data.getVar("OVERRIDES", d, 1) or ""
+ overrides = overrides + ":"
+ for o in overrides.split(":"):
+ filespath.append(os.path.join(p, o))
+ bb.data.setVar("FILESPATH", ":".join(filespath), d)
+
+FILESPATH = "${@base_set_filespath([ "${FILE_DIRNAME}/${PF}", "${FILE_DIRNAME}/${P}", "${FILE_DIRNAME}/${PN}", "${FILE_DIRNAME}/files", "${FILE_DIRNAME}" ], d)}"
+
+def oe_filter(f, str, d):
+ from re import match
+ return " ".join(filter(lambda x: match(f, x, 0), str.split()))
+
+def oe_filter_out(f, str, d):
+ from re import match
+ return " ".join(filter(lambda x: not match(f, x, 0), str.split()))
+
+die() {
+ oefatal "$*"
+}
+
+oenote() {
+ echo "NOTE:" "$*"
+}
+
+oewarn() {
+ echo "WARNING:" "$*"
+}
+
+oefatal() {
+ echo "FATAL:" "$*"
+ exit 1
+}
+
+oedebug() {
+ test $# -ge 2 || {
+ echo "Usage: oedebug level \"message\""
+ exit 1
+ }
+
+ test ${OEDEBUG:-0} -ge $1 && {
+ shift
+ echo "DEBUG:" $*
+ }
+}
+
+oe_runmake() {
+ if [ x"$MAKE" = x ]; then MAKE=make; fi
+ oenote ${MAKE} ${EXTRA_OEMAKE} "$@"
+ ${MAKE} ${EXTRA_OEMAKE} "$@" || die "oe_runmake failed"
+}
+
+oe_soinstall() {
+ # Purpose: Install shared library file and
+ # create the necessary links
+ # Example:
+ #
+ # oe_
+ #
+ #oenote installing shared library $1 to $2
+ #
+ libname=`basename $1`
+ install -m 755 $1 $2/$libname
+ sonamelink=`${HOST_PREFIX}readelf -d $1 |grep 'Library soname:' |sed -e 's/.*\[\(.*\)\].*/\1/'`
+ solink=`echo $libname | sed -e 's/\.so\..*/.so/'`
+ ln -sf $libname $2/$sonamelink
+ ln -sf $libname $2/$solink
+}
+
+oe_libinstall() {
+ # Purpose: Install a library, in all its forms
+ # Example
+ #
+ # oe_libinstall libltdl ${STAGING_LIBDIR}/
+ # oe_libinstall -C src/libblah libblah ${D}/${libdir}/
+ dir=""
+ libtool=""
+ silent=""
+ require_static=""
+ require_shared=""
+ while [ "$#" -gt 0 ]; do
+ case "$1" in
+ -C)
+ shift
+ dir="$1"
+ ;;
+ -s)
+ silent=1
+ ;;
+ -a)
+ require_static=1
+ ;;
+ -so)
+ require_shared=1
+ ;;
+ -*)
+ oefatal "oe_libinstall: unknown option: $1"
+ ;;
+ *)
+ break;
+ ;;
+ esac
+ shift
+ done
+
+ libname="$1"
+ shift
+ destpath="$1"
+ if [ -z "$destpath" ]; then
+ oefatal "oe_libinstall: no destination path specified"
+ fi
+
+ __runcmd () {
+ if [ -z "$silent" ]; then
+ echo >&2 "oe_libinstall: $*"
+ fi
+ $*
+ }
+
+ if [ -z "$dir" ]; then
+ dir=`pwd`
+ fi
+ if [ -d "$dir/.libs" ]; then
+ dir=$dir/.libs
+ fi
+ olddir=`pwd`
+ __runcmd cd $dir
+
+ lafile=$libname.la
+ if [ -f "$lafile" ]; then
+ # libtool archive
+ eval `cat $lafile|grep "^library_names="`
+ libtool=1
+ else
+ library_names="$libname.so* $libname.dll.a"
+ fi
+
+ __runcmd install -d $destpath/
+ dota=$libname.a
+ if [ -f "$dota" -o -n "$require_static" ]; then
+ __runcmd install -m 0644 $dota $destpath/
+ fi
+ dotlai=$libname.lai
+ if [ -f "$dotlai" -o -n "$libtool" ]; then
+ __runcmd install -m 0644 $dotlai $destpath/$libname.la
+ fi
+
+ for name in $library_names; do
+ files=`eval echo $name`
+ for f in $files; do
+ if [ ! -e "$f" ]; then
+ if [ -n "$libtool" ]; then
+ oefatal "oe_libinstall: $dir/$f not found."
+ fi
+ elif [ -L "$f" ]; then
+ __runcmd cp --no-dereference "$f" $destpath/
+ elif [ ! -L "$f" ]; then
+ libfile="$f"
+ __runcmd install -m 0755 $libfile $destpath/
+ fi
+ done
+ done
+
+ if [ -z "$libfile" ]; then
+ if [ -n "$require_shared" ]; then
+ oefatal "oe_libinstall: unable to locate shared library"
+ fi
+ elif [ -z "$libtool" ]; then
+ # special case hack for non-libtool .so.#.#.# links
+ baselibfile=`basename "$libfile"`
+ if (echo $baselibfile | grep -qE '^lib.*\.so\.[0-9.]*$'); then
+ sonamelink=`${HOST_PREFIX}readelf -d $libfile |grep 'Library soname:' |sed -e 's/.*\[\(.*\)\].*/\1/'`
+ solink=`echo $baselibfile | sed -e 's/\.so\..*/.so/'`
+ if [ -n "$sonamelink" -a x"$baselibfile" != x"$sonamelink" ]; then
+ __runcmd ln -sf $baselibfile $destpath/$sonamelink
+ fi
+ __runcmd ln -sf $baselibfile $destpath/$solink
+ fi
+ fi
+
+ __runcmd cd "$olddir"
+}
+
+oe_machinstall() {
+ # Purpose: Install machine dependent files, if available
+ # If not available, check if there is a default
+ # If no default, just touch the destination
+ # Example:
+ # $1 $2 $3 $4
+ # oe_machinstall -m 0644 fstab ${D}/etc/fstab
+ #
+ # TODO: Check argument number?
+ #
+ filename=`basename $3`
+ dirname=`dirname $3`
+
+ for o in `echo ${OVERRIDES} | tr ':' ' '`; do
+ if [ -e $dirname/$o/$filename ]; then
+ oenote $dirname/$o/$filename present, installing to $4
+ install $1 $2 $dirname/$o/$filename $4
+ return
+ fi
+ done
+# oenote overrides specific file NOT present, trying default=$3...
+ if [ -e $3 ]; then
+ oenote $3 present, installing to $4
+ install $1 $2 $3 $4
+ else
+ oenote $3 NOT present, touching empty $4
+ touch $4
+ fi
+}
+
+addtask showdata
+do_showdata[nostamp] = "1"
+python do_showdata() {
+ import sys
+ # emit variables and shell functions
+ bb.data.emit_env(sys.__stdout__, d, True)
+ # emit the metadata which isnt valid shell
+ for e in d.keys():
+ if bb.data.getVarFlag(e, 'python', d):
+ sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, bb.data.getVar(e, d, 1)))
+}
+
+addtask listtasks
+do_listtasks[nostamp] = "1"
+python do_listtasks() {
+ import sys
+ # emit variables and shell functions
+ #bb.data.emit_env(sys.__stdout__, d)
+ # emit the metadata which isnt valid shell
+ for e in d.keys():
+ if bb.data.getVarFlag(e, 'task', d):
+ sys.__stdout__.write("%s\n" % e)
+}
+
+addtask clean
+do_clean[dirs] = "${TOPDIR}"
+do_clean[nostamp] = "1"
+do_clean[bbdepcmd] = ""
+python base_do_clean() {
+ """clear the build and temp directories"""
+ dir = bb.data.expand("${WORKDIR}", d)
+ if dir == '//': raise bb.build.FuncFailed("wrong DATADIR")
+ bb.note("removing " + dir)
+ os.system('rm -rf ' + dir)
+
+ dir = "%s.*" % bb.data.expand(bb.data.getVar('STAMP', d), d)
+ bb.note("removing " + dir)
+ os.system('rm -f '+ dir)
+}
+
+addtask mrproper
+do_mrproper[dirs] = "${TOPDIR}"
+do_mrproper[nostamp] = "1"
+do_mrproper[bbdepcmd] = ""
+python base_do_mrproper() {
+ """clear downloaded sources, build and temp directories"""
+ dir = bb.data.expand("${DL_DIR}", d)
+ if dir == '/': bb.build.FuncFailed("wrong DATADIR")
+ bb.debug(2, "removing " + dir)
+ os.system('rm -rf ' + dir)
+ bb.build.exec_task('do_clean', d)
+}
+
+addtask fetch
+do_fetch[dirs] = "${DL_DIR}"
+do_fetch[nostamp] = "1"
+python base_do_fetch() {
+ import sys
+
+ localdata = bb.data.createCopy(d)
+ bb.data.update_data(localdata)
+
+ src_uri = bb.data.getVar('SRC_URI', localdata, 1)
+ if not src_uri:
+ return 1
+
+ try:
+ bb.fetch.init(localdata,src_uri.split())
+ except bb.fetch.NoMethodError:
+ (type, value, traceback) = sys.exc_info()
+ raise bb.build.FuncFailed("No method: %s" % value)
+
+ try:
+ bb.fetch.go(localdata)
+ except bb.fetch.MissingParameterError:
+ (type, value, traceback) = sys.exc_info()
+ raise bb.build.FuncFailed("Missing parameters: %s" % value)
+ except bb.fetch.FetchError:
+ (type, value, traceback) = sys.exc_info()
+ raise bb.build.FuncFailed("Fetch failed: %s" % value)
+}
+
+def oe_unpack_file(file, data, url = None):
+ import bb, os
+ if not url:
+ url = "file://%s" % file
+ dots = file.split(".")
+ if dots[-1] in ['gz', 'bz2', 'Z']:
+ efile = os.path.join(bb.data.getVar('WORKDIR', data, 1),os.path.basename('.'.join(dots[0:-1])))
+ else:
+ efile = file
+ cmd = None
+ if file.endswith('.tar'):
+ cmd = 'tar x --no-same-owner -f %s' % file
+ elif file.endswith('.tgz') or file.endswith('.tar.gz'):
+ cmd = 'tar xz --no-same-owner -f %s' % file
+ elif file.endswith('.tbz') or file.endswith('.tar.bz2'):
+ cmd = 'bzip2 -dc %s | tar x --no-same-owner -f -' % file
+ elif file.endswith('.gz') or file.endswith('.Z') or file.endswith('.z'):
+ cmd = 'gzip -dc %s > %s' % (file, efile)
+ elif file.endswith('.bz2'):
+ cmd = 'bzip2 -dc %s > %s' % (file, efile)
+ elif file.endswith('.zip'):
+ cmd = 'unzip -q %s' % file
+ elif os.path.isdir(file):
+ filesdir = os.path.realpath(bb.data.getVar("FILESDIR", data, 1))
+ destdir = "."
+ if file[0:len(filesdir)] == filesdir:
+ destdir = file[len(filesdir):file.rfind('/')]
+ destdir = destdir.strip('/')
+ if len(destdir) < 1:
+ destdir = "."
+ elif not os.access("%s/%s" % (os.getcwd(), destdir), os.F_OK):
+ os.makedirs("%s/%s" % (os.getcwd(), destdir))
+ cmd = 'cp -a %s %s/%s/' % (file, os.getcwd(), destdir)
+ else:
+ (type, host, path, user, pswd, parm) = bb.decodeurl(url)
+ if not 'patch' in parm:
+ # The "destdir" handling was specifically done for FILESPATH
+ # items. So, only do so for file:// entries.
+ if type == "file":
+ destdir = bb.decodeurl(url)[1] or "."
+ else:
+ destdir = "."
+ bb.mkdirhier("%s/%s" % (os.getcwd(), destdir))
+ cmd = 'cp %s %s/%s/' % (file, os.getcwd(), destdir)
+ if not cmd:
+ return True
+ cmd = "PATH=\"%s\" %s" % (bb.data.getVar('PATH', data, 1), cmd)
+ bb.note("Unpacking %s to %s/" % (file, os.getcwd()))
+ ret = os.system(cmd)
+ return ret == 0
+
+addtask unpack after do_fetch
+do_unpack[dirs] = "${WORKDIR}"
+python base_do_unpack() {
+ import re, os
+
+ localdata = bb.data.createCopy(d)
+ bb.data.update_data(localdata)
+
+ src_uri = bb.data.getVar('SRC_URI', localdata)
+ if not src_uri:
+ return
+ src_uri = bb.data.expand(src_uri, localdata)
+ for url in src_uri.split():
+ try:
+ local = bb.data.expand(bb.fetch.localpath(url, localdata), localdata)
+ except bb.MalformedUrl, e:
+ raise FuncFailed('Unable to generate local path for malformed uri: %s' % e)
+ # dont need any parameters for extraction, strip them off
+ local = re.sub(';.*$', '', local)
+ local = os.path.realpath(local)
+ ret = oe_unpack_file(local, localdata, url)
+ if not ret:
+ raise bb.build.FuncFailed()
+}
+
+addtask patch after do_unpack
+do_patch[dirs] = "${WORKDIR}"
+python base_do_patch() {
+ import re
+ import bb.fetch
+
+ src_uri = (bb.data.getVar('SRC_URI', d, 1) or '').split()
+ if not src_uri:
+ return
+
+ patchcleancmd = bb.data.getVar('PATCHCLEANCMD', d, 1)
+ if patchcleancmd:
+ bb.data.setVar("do_patchcleancmd", patchcleancmd, d)
+ bb.data.setVarFlag("do_patchcleancmd", "func", 1, d)
+ bb.build.exec_func("do_patchcleancmd", d)
+
+ workdir = bb.data.getVar('WORKDIR', d, 1)
+ for url in src_uri:
+
+ (type, host, path, user, pswd, parm) = bb.decodeurl(url)
+ if not "patch" in parm:
+ continue
+
+ bb.fetch.init([url])
+ url = bb.encodeurl((type, host, path, user, pswd, []))
+ local = os.path.join('/', bb.fetch.localpath(url, d))
+
+ # did it need to be unpacked?
+ dots = os.path.basename(local).split(".")
+ if dots[-1] in ['gz', 'bz2', 'Z']:
+ unpacked = os.path.join(bb.data.getVar('WORKDIR', d),'.'.join(dots[0:-1]))
+ else:
+ unpacked = local
+ unpacked = bb.data.expand(unpacked, d)
+
+ if "pnum" in parm:
+ pnum = parm["pnum"]
+ else:
+ pnum = "1"
+
+ if "pname" in parm:
+ pname = parm["pname"]
+ else:
+ pname = os.path.basename(unpacked)
+
+ bb.note("Applying patch '%s'" % pname)
+ bb.data.setVar("do_patchcmd", bb.data.getVar("PATCHCMD", d, 1) % (pnum, pname, unpacked), d)
+ bb.data.setVarFlag("do_patchcmd", "func", 1, d)
+ bb.data.setVarFlag("do_patchcmd", "dirs", "${WORKDIR} ${S}", d)
+ bb.build.exec_func("do_patchcmd", d)
+}
+
+
+addhandler base_eventhandler
+python base_eventhandler() {
+ from bb import note, error, data
+ from bb.event import Handled, NotHandled, getName
+ import os
+
+ messages = {}
+ messages["Completed"] = "completed"
+ messages["Succeeded"] = "completed"
+ messages["Started"] = "started"
+ messages["Failed"] = "failed"
+
+ name = getName(e)
+ msg = ""
+ if name.startswith("Pkg"):
+ msg += "package %s: " % data.getVar("P", e.data, 1)
+ msg += messages.get(name[3:]) or name[3:]
+ elif name.startswith("Task"):
+ msg += "package %s: task %s: " % (data.getVar("PF", e.data, 1), e.task)
+ msg += messages.get(name[4:]) or name[4:]
+ elif name.startswith("Build"):
+ msg += "build %s: " % e.name
+ msg += messages.get(name[5:]) or name[5:]
+ elif name == "UnsatisfiedDep":
+ msg += "package %s: dependency %s %s" % (e.pkg, e.dep, name[:-3].lower())
+ note(msg)
+
+ if name.startswith("BuildStarted"):
+ statusvars = ['TARGET_ARCH', 'TARGET_OS', 'MACHINE', 'DISTRO',
+ 'TARGET_FPU']
+ statuslines = ["%-13s = \"%s\"" % (i, bb.data.getVar(i, e.data, 1) or '') for i in statusvars]
+ statusmsg = "\nOE Build Configuration:\n%s\n" % '\n'.join(statuslines)
+ print statusmsg
+
+ needed_vars = [ "TARGET_ARCH", "TARGET_OS" ]
+ pesteruser = []
+ for v in needed_vars:
+ val = bb.data.getVar(v, e.data, 1)
+ if not val or val == 'INVALID':
+ pesteruser.append(v)
+ if pesteruser:
+ bb.fatal('The following variable(s) were not set: %s\nPlease set them directly, or choose a MACHINE or DISTRO that sets them.' % ', '.join(pesteruser))
+
+ if not data in e.__dict__:
+ return NotHandled
+
+ log = data.getVar("EVENTLOG", e.data, 1)
+ if log:
+ logfile = file(log, "a")
+ logfile.write("%s\n" % msg)
+ logfile.close()
+
+ return NotHandled
+}
+
+addtask configure after do_unpack do_patch
+do_configure[dirs] = "${S} ${B}"
+do_configure[bbdepcmd] = "do_populate_staging"
+base_do_configure() {
+ :
+}
+
+addtask compile after do_configure
+do_compile[dirs] = "${S} ${B}"
+do_compile[bbdepcmd] = "do_populate_staging"
+base_do_compile() {
+ if [ -e Makefile -o -e makefile ]; then
+ oe_runmake || die "make failed"
+ else
+ oenote "nothing to compile"
+ fi
+}
+
+
+addtask stage after do_compile
+base_do_stage () {
+ :
+}
+
+do_populate_staging[dirs] = "${STAGING_DIR}/${TARGET_SYS}/bin ${STAGING_DIR}/${TARGET_SYS}/lib \
+ ${STAGING_DIR}/${TARGET_SYS}/include \
+ ${STAGING_DIR}/${BUILD_SYS}/bin ${STAGING_DIR}/${BUILD_SYS}/lib \
+ ${STAGING_DIR}/${BUILD_SYS}/include \
+ ${STAGING_DATADIR} \
+ ${S} ${B}"
+
+addtask populate_staging after do_compile
+
+#python do_populate_staging () {
+# if not bb.data.getVar('manifest', d):
+# bb.build.exec_func('do_emit_manifest', d)
+# if bb.data.getVar('do_stage', d):
+# bb.build.exec_func('do_stage', d)
+# else:
+# bb.build.exec_func('manifest_do_populate_staging', d)
+#}
+
+python do_populate_staging () {
+ if bb.data.getVar('manifest_do_populate_staging', d):
+ bb.build.exec_func('manifest_do_populate_staging', d)
+ else:
+ bb.build.exec_func('do_stage', d)
+}
+
+#addtask install
+addtask install after do_compile
+do_install[dirs] = "${S} ${B}"
+
+base_do_install() {
+ :
+}
+
+#addtask populate_pkgs after do_compile
+#python do_populate_pkgs () {
+# if not bb.data.getVar('manifest', d):
+# bb.build.exec_func('do_emit_manifest', d)
+# bb.build.exec_func('manifest_do_populate_pkgs', d)
+# bb.build.exec_func('package_do_shlibs', d)
+#}
+
+base_do_package() {
+ :
+}
+
+addtask build after do_populate_staging
+do_build = ""
+do_build[func] = "1"
+
+# Functions that update metadata based on files outputted
+# during the build process.
+
+SHLIBS = ""
+RDEPENDS_prepend = " ${SHLIBS}"
+
+python read_manifest () {
+ import sys
+ mfn = bb.data.getVar("MANIFEST", d, 1)
+ if os.access(mfn, os.R_OK):
+ # we have a manifest, so emit do_stage and do_populate_pkgs,
+ # and stuff some additional bits of data into the metadata store
+ mfile = file(mfn, "r")
+ manifest = bb.manifest.parse(mfile, d)
+ if not manifest:
+ return
+
+ bb.data.setVar('manifest', manifest, d)
+}
+
+python parse_manifest () {
+ manifest = bb.data.getVar("manifest", d)
+ if not manifest:
+ return
+ for func in ("do_populate_staging", "do_populate_pkgs"):
+ value = bb.manifest.emit(func, manifest, d)
+ if value:
+ bb.data.setVar("manifest_" + func, value, d)
+ bb.data.delVarFlag("manifest_" + func, "python", d)
+ bb.data.delVarFlag("manifest_" + func, "fakeroot", d)
+ bb.data.setVarFlag("manifest_" + func, "func", 1, d)
+ packages = []
+ for l in manifest:
+ if "pkg" in l and l["pkg"] is not None:
+ packages.append(l["pkg"])
+ bb.data.setVar("PACKAGES", " ".join(packages), d)
+}
+
+def explode_deps(s):
+ r = []
+ l = s.split()
+ flag = False
+ for i in l:
+ if i[0] == '(':
+ flag = True
+ j = []
+ if flag:
+ j.append(i)
+ if i.endswith(')'):
+ flag = False
+ r[-1] += ' ' + ' '.join(j)
+ else:
+ r.append(i)
+ return r
+
+python read_shlibdeps () {
+ packages = (bb.data.getVar('PACKAGES', d, 1) or "").split()
+ for pkg in packages:
+ rdepends = explode_deps(bb.data.getVar('RDEPENDS_' + pkg, d, 0) or bb.data.getVar('RDEPENDS', d, 0) or "")
+ shlibsfile = bb.data.expand("${WORKDIR}/install/" + pkg + ".shlibdeps", d)
+ if os.access(shlibsfile, os.R_OK):
+ fd = file(shlibsfile)
+ lines = fd.readlines()
+ fd.close()
+ for l in lines:
+ rdepends.append(l.rstrip())
+ pcfile = bb.data.expand("${WORKDIR}/install/" + pkg + ".pcdeps", d)
+ if os.access(pcfile, os.R_OK):
+ fd = file(pcfile)
+ lines = fd.readlines()
+ fd.close()
+ for l in lines:
+ rdepends.append(l.rstrip())
+ bb.data.setVar('RDEPENDS_' + pkg, " " + " ".join(rdepends), d)
+}
+
+python read_subpackage_metadata () {
+ import re
+
+ def decode(str):
+ import codecs
+ c = codecs.getdecoder("string_escape")
+ return c(str)[0]
+
+ data_file = bb.data.expand("${WORKDIR}/install/${PN}.package", d)
+ if os.access(data_file, os.R_OK):
+ f = file(data_file, 'r')
+ lines = f.readlines()
+ f.close()
+ r = re.compile("([^:]+):\s*(.*)")
+ for l in lines:
+ m = r.match(l)
+ if m:
+ bb.data.setVar(m.group(1), decode(m.group(2)), d)
+}
+
+python __anonymous () {
+ import exceptions
+ need_host = bb.data.getVar('COMPATIBLE_HOST', d, 1)
+ if need_host:
+ import re
+ this_host = bb.data.getVar('HOST_SYS', d, 1)
+ if not re.match(need_host, this_host):
+ raise bb.parse.SkipPackage("incompatible with host %s" % this_host)
+
+ pn = bb.data.getVar('PN', d, 1)
+
+ cvsdate = bb.data.getVar('CVSDATE_%s' % pn, d, 1)
+ if cvsdate != None:
+ bb.data.setVar('CVSDATE', cvsdate, d)
+
+ use_nls = bb.data.getVar('USE_NLS_%s' % pn, d, 1)
+ if use_nls != None:
+ bb.data.setVar('USE_NLS', use_nls, d)
+
+ try:
+ bb.build.exec_func('read_manifest', d)
+ bb.build.exec_func('parse_manifest', d)
+ except exceptions.KeyboardInterrupt:
+ raise
+ except Exception, e:
+ bb.error("anonymous function: %s" % e)
+ pass
+}
+
+python () {
+ import bb, os
+ mach_arch = bb.data.getVar('MACHINE_ARCH', d, 1)
+ old_arch = bb.data.getVar('PACKAGE_ARCH', d, 1)
+ if (old_arch == mach_arch):
+ # Nothing to do
+ return
+ if (bb.data.getVar('SRC_URI_OVERRIDES_PACKAGE_ARCH', d, 1) == '0'):
+ return
+ paths = []
+ for p in [ "${FILE_DIRNAME}/${PF}", "${FILE_DIRNAME}/${P}", "${FILE_DIRNAME}/${PN}", "${FILE_DIRNAME}/files", "${FILE_DIRNAME}" ]:
+ paths.append(bb.data.expand(os.path.join(p, mach_arch), d))
+ for s in bb.data.getVar('SRC_URI', d, 1).split():
+ local = bb.data.expand(bb.fetch.localpath(s, d), d)
+ for mp in paths:
+ if local.startswith(mp):
+# bb.note("overriding PACKAGE_ARCH from %s to %s" % (old_arch, mach_arch))
+ bb.data.setVar('PACKAGE_ARCH', mach_arch, d)
+ return
+}
+
+
+addtask emit_manifest
+python do_emit_manifest () {
+# FIXME: emit a manifest here
+# 1) adjust PATH to hit the wrapper scripts
+ wrappers = bb.which(bb.data.getVar("BBPATH", d, 1), 'build/install', 0)
+ path = (bb.data.getVar('PATH', d, 1) or '').split(':')
+ path.insert(0, os.path.dirname(wrappers))
+ bb.data.setVar('PATH', ':'.join(path), d)
+# 2) exec_func("do_install", d)
+ bb.build.exec_func('do_install', d)
+# 3) read in data collected by the wrappers
+ bb.build.exec_func('read_manifest', d)
+# 4) mangle the manifest we just generated, get paths back into
+# our variable form
+# 5) write it back out
+# 6) re-parse it to ensure the generated functions are proper
+ bb.build.exec_func('parse_manifest', d)
+}
+
+EXPORT_FUNCTIONS do_clean do_mrproper do_fetch do_unpack do_configure do_compile do_install do_package do_patch do_populate_pkgs do_stage
+
+MIRRORS[func] = "0"
+MIRRORS () {
+${DEBIAN_MIRROR}/main http://snapshot.debian.net/archive/pool
+${DEBIAN_MIRROR} ftp://ftp.de.debian.org/debian/pool
+${GNU_MIRROR} ftp://mirrors.kernel.org/gnu
+ftp://ftp.kernel.org/pub http://www.kernel.org/pub
+ftp://ftp.kernel.org/pub ftp://ftp.de.kernel.org/pub
+}
+
diff --git a/trunk/bitbake_qa/conf/bitbake.conf b/trunk/bitbake_qa/conf/bitbake.conf
new file mode 100644
index 000000000..aa1427131
--- /dev/null
+++ b/trunk/bitbake_qa/conf/bitbake.conf
@@ -0,0 +1,379 @@
+##################################################################
+# Standard target filesystem paths.
+##################################################################
+
+# Path prefixes
+export base_prefix = ""
+export prefix = "/usr"
+export exec_prefix = "${prefix}"
+
+# Base paths
+export base_bindir = "${base_prefix}/bin"
+export base_sbindir = "${base_prefix}/sbin"
+export base_libdir = "${base_prefix}/lib"
+
+# Architecture independent paths
+export datadir = "${prefix}/share"
+export sysconfdir = "/etc"
+export sharedstatedir = "${prefix}/com"
+export localstatedir = "/var"
+export infodir = "${datadir}/info"
+export mandir = "${datadir}/man"
+export docdir = "${datadir}/doc"
+export servicedir = "/srv"
+
+# Architecture dependent paths
+export bindir = "${exec_prefix}/bin"
+export sbindir = "${exec_prefix}/sbin"
+export libexecdir = "${exec_prefix}/libexec"
+export libdir = "${exec_prefix}/lib"
+export includedir = "${exec_prefix}/include"
+export oldincludedir = "${exec_prefix}/include"
+
+##################################################################
+# Architecture-dependent build variables.
+##################################################################
+
+BUILD_ARCH = "${@os.uname()[4]}"
+BUILD_OS = "${@os.uname()[0].lower()}"
+BUILD_VENDOR = ""
+BUILD_SYS = "${BUILD_ARCH}${BUILD_VENDOR}-${BUILD_OS}"
+BUILD_PREFIX = ""
+BUILD_CC_ARCH = ""
+
+HOST_ARCH = "${TARGET_ARCH}"
+HOST_OS = "${TARGET_OS}"
+HOST_VENDOR = "${TARGET_VENDOR}"
+HOST_SYS = "${HOST_ARCH}${HOST_VENDOR}-${HOST_OS}"
+HOST_PREFIX = "${TARGET_PREFIX}"
+HOST_CC_ARCH = "${TARGET_CC_ARCH}"
+
+TARGET_ARCH = "INVALID"
+TARGET_OS = "INVALID"
+TARGET_VENDOR = "${BUILD_VENDOR}"
+TARGET_SYS = "${TARGET_ARCH}${TARGET_VENDOR}-${TARGET_OS}"
+TARGET_PREFIX = "${TARGET_SYS}-"
+TARGET_CC_ARCH = ""
+
+PACKAGE_ARCH = "${HOST_ARCH}"
+MACHINE_ARCH = "${@[bb.data.getVar('HOST_ARCH', d, 1), bb.data.getVar('MACHINE', d, 1)][bool(bb.data.getVar('MACHINE', d, 1))]}"
+
+##################################################################
+# Date/time variables.
+##################################################################
+
+DATE := "${@time.strftime('%Y%m%d',time.gmtime())}"
+TIME := "${@time.strftime('%H%M%S',time.gmtime())}"
+DATETIME = "${DATE}${TIME}"
+
+##################################################################
+# Package default variables.
+##################################################################
+
+PN = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[0] or 'defaultpkgname'}"
+PV = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[1] or '1.0'}"
+PR = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[2] or 'r0'}"
+PF = "${PN}-${PV}-${PR}"
+P = "${PN}-${PV}"
+
+# Package info.
+
+SECTION = "base"
+PRIORITY = "optional"
+DESCRIPTION = "Version ${PV}-${PR} of package ${PN}"
+LICENSE = "unknown"
+MAINTAINER = "OpenEmbedded Team <oe@handhelds.org>"
+HOMEPAGE = "unknown"
+
+# Package dependencies and provides.
+
+DEPENDS = ""
+RDEPENDS = ""
+PROVIDES = ""
+PROVIDES_prepend = "${P} ${PF} ${PN} "
+RPROVIDES = ""
+
+PACKAGES = "${PN} ${PN}-doc ${PN}-dev ${PN}-locale"
+FILES = ""
+FILES_${PN} = "${bindir} ${sbindir} ${libexecdir} ${libdir}/lib*.so.* \
+ ${sysconfdir} ${sharedstatedir} ${localstatedir} \
+ /bin /sbin /lib/*.so* ${datadir}/${PN} ${libdir}/${PN} \
+ ${datadir}/pixmaps ${datadir}/applications \
+ ${datadir}/idl ${datadir}/omf ${datadir}/sounds \
+ ${libdir}/bonobo/servers"
+SECTION_${PN}-doc = "doc"
+FILES_${PN}-doc = "${docdir} ${mandir} ${infodir} ${datadir}/gtk-doc \
+ ${datadir}/gnome/help"
+SECTION_${PN}-dev = "devel"
+FILES_${PN}-dev = "${includedir} ${libdir}/lib*.so ${libdir}/*.la \
+ ${libdir}/*.a ${libdir}/*.o ${libdir}/pkgconfig \
+ /lib/*.a /lib/*.o ${datadir}/aclocal"
+FILES_${PN}-locale = "${datadir}/locale"
+
+# File manifest
+
+export MANIFEST = "${FILESDIR}/manifest"
+
+FILE_DIRNAME = "${@os.path.dirname(bb.data.getVar('FILE', d))}"
+FILESPATH = "${FILE_DIRNAME}/${PF}:${FILE_DIRNAME}/${P}:${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/files:${FILE_DIRNAME}"
+FILESDIR = "${@bb.which(bb.data.getVar('FILESPATH', d, 1), '.')}"
+
+##################################################################
+# General work and output directories for the build system.
+##################################################################
+
+TMPDIR = "${TOPDIR}/tmp"
+CACHE = "${TMPDIR}/cache"
+DL_DIR = "${TMPDIR}/downloads"
+CVSDIR = "${DL_DIR}/cvs"
+
+STAMP = "${TMPDIR}/stamps/${PF}"
+WORKDIR = "${TMPDIR}/work/${PF}"
+T = "${WORKDIR}/temp"
+D = "${WORKDIR}/image"
+S = "${WORKDIR}/${P}"
+B = "${S}"
+
+STAGING_DIR = "${TMPDIR}/staging"
+STAGING_BINDIR = "${STAGING_DIR}/${BUILD_SYS}/bin"
+STAGING_LIBDIR = "${STAGING_DIR}/${HOST_SYS}/lib"
+STAGING_INCDIR = "${STAGING_DIR}/${HOST_SYS}/include"
+STAGING_DATADIR = "${STAGING_DIR}/${HOST_SYS}/share"
+
+DEPLOY_DIR = "${TMPDIR}/deploy"
+DEPLOY_DIR_TAR = "${DEPLOY_DIR}/tar"
+DEPLOY_DIR_IPK = "${DEPLOY_DIR}/ipk"
+DEPLOY_DIR_RPM = "${DEPLOY_DIR}/rpm"
+
+##################################################################
+# Kernel info.
+##################################################################
+
+OLDEST_KERNEL = "2.4.0"
+STAGING_KERNEL_DIR = "${STAGING_DIR}/${HOST_SYS}/kernel"
+
+##################################################################
+# Specific image creation and rootfs population info.
+##################################################################
+
+DEPLOY_DIR_IMAGE = "${DEPLOY_DIR}/images"
+IMAGE_ROOTFS = "${TMPDIR}/rootfs"
+IMAGE_BASENAME = "rootfs"
+IMAGE_NAME = "${IMAGE_BASENAME}-${MACHINE}-${DATETIME}"
+IMAGE_CMD = ""
+IMAGE_CMD_jffs2 = "mkfs.jffs2 --root=${IMAGE_ROOTFS} --faketime \
+ --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 \
+ ${EXTRA_IMAGECMD}"
+IMAGE_CMD_cramfs = "mkcramfs ${IMAGE_ROOTFS} ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.cramfs ${EXTRA_IMAGECMD}"
+IMAGE_CMD_ext2 = "genext2fs -b ${IMAGE_ROOTFS_SIZE} -d ${IMAGE_ROOTFS} ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ext2 ${EXTRA_IMAGECMD}"
+IMAGE_CMD_ext2.gz = "mkdir ${DEPLOY_DIR_IMAGE}/tmp.gz; genext2fs -b ${IMAGE_ROOTFS_SIZE} -d ${IMAGE_ROOTFS} ${DEPLOY_DIR_IMAGE}/tmp.gz/${IMAGE_NAME}.rootfs.ext2 ${EXTRA_IMAGECMD}; gzip -f -9 ${DEPLOY_DIR_IMAGE}/tmp.gz/${IMAGE_NAME}.rootfs.ext2; mv ${DEPLOY_DIR_IMAGE}/tmp.gz/${IMAGE_NAME}.rootfs.ext2.gz ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ext2.gz; rmdir ${DEPLOY_DIR_IMAGE}/tmp.gz"
+IMAGE_CMD_squashfs = "mksquashfs ${IMAGE_ROOTFS} ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.squashfs ${EXTRA_IMAGECMD} -noappend"
+IMAGE_CMD_tar = "cd ${IMAGE_ROOTFS} && tar -jcvf ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.tar.bz2 ."
+EXTRA_IMAGECMD = ""
+EXTRA_IMAGECMD_jffs2 = "--pad --little-endian --eraseblock=0x40000"
+EXTRA_IMAGECMD_squashfs = "-le -b 16384"
+IMAGE_FSTYPE = "jffs2"
+IMAGE_FSTYPES = "${IMAGE_FSTYPE}"
+IMAGE_ROOTFS_SIZE_ext2 = "65536"
+IMAGE_ROOTFS_SIZE_ext2.gz = "65536"
+
+IMAGE_DEPENDS = ""
+IMAGE_DEPENDS_jffs2 = "mtd-utils-native"
+IMAGE_DEPENDS_cramfs = "cramfs-native"
+IMAGE_DEPENDS_ext2 = "genext2fs-native"
+IMAGE_DEPENDS_ext2.gz = "genext2fs-native"
+IMAGE_DEPENDS_squashfs = "squashfs-tools-native"
+EXTRA_IMAGEDEPENDS = ""
+
+##################################################################
+# Toolchain info.
+##################################################################
+
+CROSS_DIR = "${TMPDIR}/cross"
+CROSS_DATADIR = "${CROSS_DIR}/share"
+export PATH_prepend = "${STAGING_BINDIR}/${HOST_SYS}:${STAGING_BINDIR}:${CROSS_DIR}/bin:"
+
+##################################################################
+# Build utility info.
+##################################################################
+
+CCACHE = "${@bb.which(bb.data.getVar('PATH', d), 'ccache') and 'ccache '}"
+
+export CC = "${CCACHE}${HOST_PREFIX}gcc ${HOST_CC_ARCH}"
+export CXX = "${CCACHE}${HOST_PREFIX}g++ ${HOST_CC_ARCH}"
+export F77 = "${CCACHE}${HOST_PREFIX}g77 ${HOST_CC_ARCH}"
+export CPP = "${HOST_PREFIX}gcc -E"
+export LD = "${HOST_PREFIX}ld"
+export CCLD = "${CC}"
+export AR = "${HOST_PREFIX}ar"
+export AS = "${HOST_PREFIX}as"
+export RANLIB = "${HOST_PREFIX}ranlib"
+export STRIP = "${HOST_PREFIX}strip"
+
+export BUILD_CC = "${CCACHE}${BUILD_PREFIX}gcc ${BUILD_CC_ARCH}"
+export BUILD_CXX = "${CCACHE}${BUILD_PREFIX}g++ ${BUILD_CC_ARCH}"
+export BUILD_F77 = "${CCACHE}${BUILD_PREFIX}g77 ${BUILD_CC_ARCH}"
+export BUILD_CPP = "${BUILD_PREFIX}cpp"
+export BUILD_LD = "${BUILD_PREFIX}ld"
+export BUILD_CCLD = "${BUILD_PREFIX}gcc"
+export BUILD_AR = "${BUILD_PREFIX}ar"
+export BUILD_RANLIB = "${BUILD_PREFIX}ranlib"
+export BUILD_STRIP = "${BUILD_PREFIX}strip"
+
+export MAKE = "make"
+EXTRA_OEMAKE = "-e MAKEFLAGS="
+
+##################################################################
+# Build flags and options.
+##################################################################
+
+export BUILD_CPPFLAGS = "-I${STAGING_DIR}/${BUILD_SYS}/include"
+export CPPFLAGS = "${TARGET_CPPFLAGS}"
+export TARGET_CPPFLAGS = "-I${STAGING_DIR}/${TARGET_SYS}/include"
+
+export BUILD_CFLAGS = "${BUILD_CPPFLAGS} ${BUILD_OPTIMIZATION}"
+export CFLAGS = "${TARGET_CFLAGS}"
+export TARGET_CFLAGS = "${TARGET_CPPFLAGS} ${SELECTED_OPTIMIZATION}"
+
+export BUILD_CXXFLAGS = "${BUILD_CFLAGS} -fpermissive"
+export CXXFLAGS = "${TARGET_CXXFLAGS}"
+export TARGET_CXXFLAGS = "${TARGET_CFLAGS} -fpermissive"
+
+export BUILD_LDFLAGS = "-L${STAGING_DIR}/${BUILD_SYS}/lib \
+ -Wl,-rpath-link,${STAGING_DIR}/${BUILD_SYS}/lib \
+ -Wl,-rpath,${STAGING_DIR}/${BUILD_SYS}/lib -Wl,-O1"
+export LDFLAGS = "${TARGET_LDFLAGS}"
+export TARGET_LDFLAGS = "-L${STAGING_DIR}/${TARGET_SYS}/lib \
+ -Wl,-rpath-link,${STAGING_DIR}/${TARGET_SYS}/lib \
+ -Wl,-O1"
+
+# Which flags to leave by strip-flags() in bin/build/oebuild.sh ?
+ALLOWED_FLAGS = "-O -mcpu -march -pipe"
+
+# Pass parallel make options to the compile task only
+EXTRA_OEMAKE_prepend_task_do_compile = "${PARALLEL_MAKE} "
+
+##################################################################
+# Optimization flags.
+##################################################################
+
+FULL_OPTIMIZATION = "-fexpensive-optimizations -fomit-frame-pointer -frename-registers -O2"
+DEBUG_OPTIMIZATION = "-O -g"
+SELECTED_OPTIMIZATION = "${@bb.data.getVar(['FULL_OPTIMIZATION', 'DEBUG_OPTIMIZATION'][bb.data.getVar('DEBUG_BUILD', d, 1) == '1'], d, 1)}"
+BUILD_OPTIMIZATION = "-O2"
+
+##################################################################
+# Bootstrap stuff.
+##################################################################
+
+BOOTSTRAP_EXTRA_DEPENDS = ""
+BOOTSTRAP_EXTRA_RDEPENDS = ""
+BOOTSTRAP_EXTRA_RRECOMMENDS = ""
+
+##################################################################
+# Palmtop stuff.
+##################################################################
+
+export QTDIR = "${STAGING_DIR}/${HOST_SYS}/qt2"
+export QPEDIR = "${STAGING_DIR}/${HOST_SYS}"
+export OPIEDIR = "${STAGING_DIR}/${HOST_SYS}"
+export palmtopdir = "/opt/QtPalmtop"
+export palmqtdir = "/opt/QtPalmtop"
+
+##################################################################
+# Download locations and utilities.
+##################################################################
+
+GNU_MIRROR = "ftp://ftp.gnu.org/gnu"
+DEBIAN_MIRROR = "ftp://ftp.debian.org/debian/pool"
+SOURCEFORGE_MIRROR = "http://aleron.dl.sourceforge.net/sourceforge"
+GPE_MIRROR = "http://ftp.handhelds.org/pub/projects/gpe/source"
+XLIBS_MIRROR = "http://xlibs.freedesktop.org/release"
+GNOME_MIRROR = "http://ftp.gnome.org/pub/GNOME/sources"
+HANDHELDS_CVS = "cvs://anoncvs:anoncvs@cvs.handhelds.org/cvs"
+
+# You can use the mirror of your country to get faster downloads by putting
+# export DEBIAN_MIRROR = "ftp://ftp.de.debian.org/debian/pool"
+# export SOURCEFORGE_MIRROR = "http://belnet.dl.sourceforge.net/sourceforge"
+# into your local.conf
+
+FETCHCOMMAND = ""
+FETCHCOMMAND_wget = "/usr/bin/env wget --timeout=30 -t 3 --passive-ftp -P ${DL_DIR} ${URI}"
+FETCHCOMMAND_cvs = "/usr/bin/env cvs -d${CVSROOT} co ${CVSCOOPTS} ${CVSMODULE}"
+RESUMECOMMAND = ""
+RESUMECOMMAND_wget = "/usr/bin/env wget -c --timeout=30 -t 3 --passive-ftp -P ${DL_DIR} ${URI}"
+UPDATECOMMAND = ""
+UPDATECOMMAND_cvs = "/usr/bin/env cvs update -d -P ${CVSCOOPTS}"
+CVSDATE = "${DATE}"
+
+SRC_URI = "file://${FILE}"
+
+##################################################################
+# Miscellaneous utilities.
+##################################################################
+
+MKTEMPDIRCMD = "mktemp -d -q ${TMPBASE}"
+MKTEMPCMD = "mktemp -q ${TMPBASE}"
+
+# Program to be used to patch sources, use 'inherit patcher' to overwrite this:
+
+PATCHCLEANCMD = 'if [ -n "`quilt applied`" ]; then quilt pop -a -R -f || exit 1; fi'
+PATCHCMD = "pnum='%s'; name='%s'; patch='%s'; mkdir -p patches; quilt upgrade >/dev/null 2>&1; quilt import -f -p $pnum -n $name $patch; chmod u+w patches/$name; quilt push"
+PATCH_DEPENDS = "quilt-native"
+
+# GNU patch tries to be intellgent about checking out read-only files from
+# a RCS, which freaks out those special folks with active Perforce clients
+# the following makes patch ignore RCS:
+
+export PATCH_GET=0
+
+# Program to be used to build ipkg packages
+
+IPKGBUILDCMD = "ipkg-build -o 0 -g 0"
+
+##################################################################
+# Not sure about the rest of this yet.
+##################################################################
+
+# slot - currently unused by OE. portage remnants
+SLOT = "0"
+
+# Other
+
+export PKG_CONFIG_PATH = "${STAGING_DATADIR}/pkgconfig"
+export PKG_CONFIG_DISABLE_UNINSTALLED = "yes"
+
+export QMAKE_MKSPEC_PATH = "${STAGING_DIR}/${BUILD_SYS}/share/qmake"
+export STAGING_SIPDIR = "${STAGING_DIR}/${BUILD_SYS}/share/sip"
+export STAGING_IDLDIR = "${STAGING_DATADIR}/idl"
+
+# default test results for autoconf
+# possible candidate for moving into autotools.oeclass -CL
+export CONFIG_SITE = "${@bb.which(bb.data.getVar('BBPATH', d, 1), 'site/%s-%s' % (bb.data.getVar('HOST_ARCH', d, 1), bb.data.getVar('HOST_OS', d, 1)))}"
+
+# library package naming
+AUTO_LIBNAME_PKGS = "${PACKAGES}"
+
+###
+### Config file processing
+###
+
+# This means that an envionment variable named '<foo>_arm' overrides an
+# environment variable '<foo>' (when ${TARGET_ARCH} is arm). And the same: an
+# environment variable '<foo>_ramses' overrides both '<foo>' and '<foo>_arm
+# when ${MACHINE} is 'ramses'. And finally '<foo>_local' overrides anything.
+#
+OVERRIDES = "local:${MACHINE}:${DISTRO}:${TARGET_OS}:${TARGET_ARCH}"
+
+##################################################################
+# Include the rest of the config files.
+##################################################################
+
+include conf/site.conf
+include conf/auto.conf
+include conf/local.conf
+include conf/documentation.conf
+include conf/build/${BUILD_SYS}.conf
+include conf/target/${TARGET_SYS}.conf
+include conf/machine/${MACHINE}.conf
+include conf/distro/${DISTRO}.conf
diff --git a/trunk/bitbake_qa/conf/testrun.conf.sample b/trunk/bitbake_qa/conf/testrun.conf.sample
new file mode 100644
index 000000000..65bc9a179
--- /dev/null
+++ b/trunk/bitbake_qa/conf/testrun.conf.sample
@@ -0,0 +1,9 @@
+# Point to the OpenEmbedded packages
+BBFILES := "/home/ich/programming/oe/openembedded_data/packages/*/*.bb"
+
+# Configurations to run tests for
+# Each configurations consists out of a three tuple
+# (TARGET_ARCH,TARGET_OS,DISTRO,[MACHINE1.MACHINE2])
+TEST_CONFIGS = "(arm,linux,familiar-0.9.0,[h3600.h3900]) (arm,linux,openzaurus-3.5.3,[collie.corgie])"
+
+
diff --git a/trunk/bitbake_qa/content_checker/__init__.py b/trunk/bitbake_qa/content_checker/__init__.py
new file mode 100644
index 000000000..4304075ba
--- /dev/null
+++ b/trunk/bitbake_qa/content_checker/__init__.py
@@ -0,0 +1,40 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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 content_checker
+
+__all__ = [ "create_test" ]
+
+def create_test():
+ return content_checker.TestCase()
diff --git a/trunk/bitbake_qa/content_checker/content_checker.py b/trunk/bitbake_qa/content_checker/content_checker.py
new file mode 100644
index 000000000..e37235f1f
--- /dev/null
+++ b/trunk/bitbake_qa/content_checker/content_checker.py
@@ -0,0 +1,67 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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.
+
+from bittest import TestItem
+from bb import data
+
+# quite simple without regexps
+bad_signs = {
+ 'SRC_URI' : '?' # SRC_URI should not contain URLs like http://foo.foo?file=foo.tar.gz
+ }
+
+class TestCase:
+ """
+ Check if keys contain weird expressions that are considered
+ error prone.
+ """
+
+ def __init__(self):
+ pass
+
+ def test(self, file_name, file_data):
+ """
+ Go through bad_signs and do reports
+ """
+ results = []
+
+ for sign in bad_signs.keys():
+ value = data.getVar(sign, file_data, True)
+ if not value == None:
+ if bad_signs[sign] in value:
+ results.append( TestItem(file_name,False,"BAD sign found for %s." % sign))
+
+ return results
+
+ def test_name(self):
+ return "Content Checker Tool"
diff --git a/trunk/bitbake_qa/doc/README b/trunk/bitbake_qa/doc/README
new file mode 100644
index 000000000..1f8921e6a
--- /dev/null
+++ b/trunk/bitbake_qa/doc/README
@@ -0,0 +1,29 @@
+Bitbake QA will hold Quality Assurance Resources:
+ The primary user will be OpenEmbedded but it is useful
+for any other user bitbake as well.
+
+layout of the bitbake_qa module:
+conf/
+ It contains example configurations used to run tests
+with specified parameters (for overrides)
+
+doc/
+ This directory
+
+module_name/
+ QA modules doing the actual tests
+
+
+I hope to offer the following tests soon:
+
+source_checker - It will check if the sources can still be fetched
+ and generates reports
+
+patch_checker - It will check if the patches still applies
+
+doc_checker - It will check if all variables have a documentation
+
+content_checker - It will check for common misusage in variables
+
+tinderbox_resources - It will contain resources to run a tinderbox server
+ and client.
diff --git a/trunk/bitbake_qa/doc_checker/__init__.py b/trunk/bitbake_qa/doc_checker/__init__.py
new file mode 100644
index 000000000..24cbe845c
--- /dev/null
+++ b/trunk/bitbake_qa/doc_checker/__init__.py
@@ -0,0 +1,40 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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 doc_checker
+
+__all__ = [ "create_test" ]
+
+def create_test():
+ return doc_checker.TestCase()
diff --git a/trunk/bitbake_qa/doc_checker/doc_checker.py b/trunk/bitbake_qa/doc_checker/doc_checker.py
new file mode 100644
index 000000000..18650cdc5
--- /dev/null
+++ b/trunk/bitbake_qa/doc_checker/doc_checker.py
@@ -0,0 +1,74 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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.
+
+from bittest import TestItem
+
+import bb
+
+
+# black list of KEYs that are not needed to have a documentation
+_black_list = []
+
+class TestCase:
+ """
+ Check if variables carry a documentation. For each concrete bbfile
+ (which includes bbclasses) we will check if all keys are named.
+ """
+
+ def __init__(self):
+ """
+ Construct the test case...
+ """
+ pass
+
+ def test(self, file_name, file_data):
+ """
+ Now we will run the tests
+ """
+
+ results = []
+
+ #
+ # The big plot. We will go through every key of file_data
+ # and check if there is a doc Flag
+ #
+ for key in bb.data.keys(file_data):
+ flag = bb.data.getVarFlag(key,"doc", file_data)
+ if flag == None:
+ results.append( TestItem(file_name,False,"Attribute named '%s' lacks documentation." % key))
+
+ return results
+
+ def test_name(self):
+ return "Documentation Checker Tool"
diff --git a/trunk/bitbake_qa/example/__init__.py b/trunk/bitbake_qa/example/__init__.py
new file mode 100644
index 000000000..661b31fff
--- /dev/null
+++ b/trunk/bitbake_qa/example/__init__.py
@@ -0,0 +1,41 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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 example
+
+__all__ = [
+ "create_test"
+]
+def create_test():
+ return example.TestCase()
diff --git a/trunk/bitbake_qa/example/example.py b/trunk/bitbake_qa/example/example.py
new file mode 100644
index 000000000..d91cba5ca
--- /dev/null
+++ b/trunk/bitbake_qa/example/example.py
@@ -0,0 +1,59 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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.
+
+from bittest import TestItem
+
+class TestCase:
+ """
+ A simple test case
+ """
+
+ def __init__(self):
+ """
+ Construct and initialize the test case
+ """
+
+ def test(self,file_name, file_data):
+ """
+ Now run the test for file_name and the corresponding data.
+ You can use whatever you want
+ """
+
+ return TestItem(file_name,False,"The Test Failed")
+
+ def test_name(self):
+ """
+ Retutnr a name for the test
+ """
+ return "Example Test"
diff --git a/trunk/bitbake_qa/lib/bittest/__init__.py b/trunk/bitbake_qa/lib/bittest/__init__.py
new file mode 100644
index 000000000..c3f50fb9f
--- /dev/null
+++ b/trunk/bitbake_qa/lib/bittest/__init__.py
@@ -0,0 +1,14 @@
+from testresult import TestItem, TestResult
+from testoutput_text import TestOutputText
+from config import parse_test_options
+
+__all__ = [
+ "TestResult",
+ "TestItem",
+ "TestOutputText",
+
+# fileparser.py
+ "fileparser",
+# config.py
+ "parse_test_options"
+]
diff --git a/trunk/bitbake_qa/lib/bittest/config.py b/trunk/bitbake_qa/lib/bittest/config.py
new file mode 100644
index 000000000..ea1dfc37d
--- /dev/null
+++ b/trunk/bitbake_qa/lib/bittest/config.py
@@ -0,0 +1,79 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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.
+
+"""
+Config Utility to parse bitttest/doctest related configuration resources
+"""
+
+__version__ = 0.2
+
+import bb
+
+def __build_array(string):
+ """
+ Build an array out of the string [abc.def]
+ """
+ ar = []
+ tmp = string.split('.')
+
+ for item in tmp:
+ ar.append( item.strip().strip('[').strip(']').strip() )
+
+ return ar
+
+def parse_test_options(cfg):
+ """
+ Parse the test options from the TEST_CONFIGS key normally found in the
+ testrun.conf
+ """
+
+ config = []
+ data = bb.data.getVar('TEST_CONFIGS', cfg)
+ data = data.split(' ')
+
+ for tuple in data:
+ # Lame ass splitting
+ g = tuple.split(',')
+ # Split the tuple by hand
+ a = g[0].strip().strip('(').strip()
+ b = g[1].strip()
+ c = g[2].strip()
+
+ # [a.b]
+ d = __build_array(g[3].strip(')').strip())
+
+ # now append
+ config.append( (a,b,c,d) )
+
+ return config
diff --git a/trunk/bitbake_qa/lib/bittest/fileparser.py b/trunk/bitbake_qa/lib/bittest/fileparser.py
new file mode 100644
index 000000000..bc575a21b
--- /dev/null
+++ b/trunk/bitbake_qa/lib/bittest/fileparser.py
@@ -0,0 +1,52 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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 os, glob
+from bb import make
+
+__version__ = "0.0"
+
+
+def find_files(files):
+ lst = []
+
+ for file in files:
+ if os.path.isdir(file):
+ d_files = bb.make.find_bbfiles(f)
+ if d_files:
+ lst += d_files
+ else:
+ lst += glob.glob(file) or [ file ]
+
+ return lst
diff --git a/trunk/bitbake_qa/lib/bittest/testoutput_text.py b/trunk/bitbake_qa/lib/bittest/testoutput_text.py
new file mode 100644
index 000000000..11aac1962
--- /dev/null
+++ b/trunk/bitbake_qa/lib/bittest/testoutput_text.py
@@ -0,0 +1,52 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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.
+
+__version__ = "0.0"
+
+import os, sys
+
+class TestOutputText:
+ """
+ Output the Test Result as Text
+ """
+
+ def __init__(self,test_config,test_result):
+ self.test_config = test_config
+ self.test_result = test_result
+
+ def print_result(self):
+ print "Test results for %s:" % self.test_config
+ print "\tNumber of ran tests: %d" % len(self.test_result)
+ for test in self.test_result:
+ print "Tested file: %s Test Result: %s Test Comment:%s" % (test.tested_file(),test.test_result(),test.test_comment())
diff --git a/trunk/bitbake_qa/lib/bittest/testresult.py b/trunk/bitbake_qa/lib/bittest/testresult.py
new file mode 100644
index 000000000..8b9d074cd
--- /dev/null
+++ b/trunk/bitbake_qa/lib/bittest/testresult.py
@@ -0,0 +1,116 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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 types
+
+__version__ = "0.0"
+
+
+class TestItem:
+ """
+ A TestItem contains of the following:
+ (
+ tested_file [String],
+ test_result [True,False],
+ test_comment [String]
+ )
+ """
+ def __init__(self,tested_file,test_result,test_comment):
+ self._tested_file = tested_file
+ self._test_result = test_result
+ self._test_comment = test_comment
+
+ def tested_file(self):
+ return self._tested_file
+
+ def test_result(self):
+ return self._test_result
+
+ def test_comment(self):
+ return self._test_comment
+
+class TestResult:
+ """
+ This class holds the testresults
+ """
+
+ def __init__(self, name):
+ """
+ name is the test name
+ """
+ self._test_name = name
+ self._results = []
+
+ def test_name(self):
+ return self._test_name
+
+ def insert_result(self, item):
+ """
+ Insert item into the list of results. We will not
+ enter item if item is None.
+ If item is of type list we will add every element in the
+ list to the list of test results
+ """
+ if item == None:
+ return
+
+ if type(item) == types.ListType:
+ self._results.extend(item)
+ else:
+ self._results.append(item)
+
+ def __iter__(self):
+ return self._results.__iter__()
+
+ def __getitem__(self,index):
+ return self._results[index]
+
+ def count(self):
+ return self._results.count()
+
+ def __len__(self):
+ return self._results.__len__()
+
+
+def _test():
+ """
+ Test the quite simple Test Data Types
+ """
+ import doctest
+
+
+if __name__ == "__main__":
+ _test()
+
+
diff --git a/trunk/bitbake_qa/patch_checker/__init__.py b/trunk/bitbake_qa/patch_checker/__init__.py
new file mode 100644
index 000000000..efa466514
--- /dev/null
+++ b/trunk/bitbake_qa/patch_checker/__init__.py
@@ -0,0 +1,42 @@
+#ifndef SOURCE_CHECKER/SOURCE_CHECKER.PY
+#define SOURCE_CHECKER/SOURCE_CHECKER.PY
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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 patch_checker
+
+__all__ = ["create_test"]
+
+def create_test():
+ return patch_checker.TestCase()
diff --git a/trunk/bitbake_qa/patch_checker/patch_checker.py b/trunk/bitbake_qa/patch_checker/patch_checker.py
new file mode 100644
index 000000000..34cfa347c
--- /dev/null
+++ b/trunk/bitbake_qa/patch_checker/patch_checker.py
@@ -0,0 +1,82 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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.
+
+from bittest import TestItem
+import bb, sys
+
+
+class TestCase:
+ def __init__(self):
+ pass
+
+ def test_name(self):
+ return "Patch Checker"
+
+ def test(self,file, data):
+ """
+ Run the Test now... some duplication of the base.bbclass
+ """
+
+ error = None
+
+ try:
+ bb.build.exec_func('do_unpack', data)
+ bb.build.exec_func('do_patch', data)
+
+ try:
+ bb.build.exec_func('do_clean', data)
+ except:
+ pass
+ except bb.build.FuncFailed:
+ error = """Function failed
+Distro: %s
+Machine: %s
+OS: %s
+ARCH: %s
+FPU: %s
+""" % (bb.data.getVar('DISTRO',data),bb.data.getVar('MACHINE',data),bb.data.getVar('TARGET_OS',data, True),bb.data.getVar('TARGET_ARCH',data, True),bb.data.getVar('TARGET_FPU',data, True))
+ except bb.build.EventException:
+ (type,value,traceback) = sys.exc_info()
+ e = value.event
+ error = """EventException %s
+Distro: %s
+Machine: %s
+OS: %s
+ARCH: %s
+FPU: %s
+""" % (bb.event.getName(e),bb.data.getVar('DISTRO',data),bb.data.getVar('MACHINE',data),bb.data.getVar('TARGET_OS',data, True),bb.data.getVar('TARGET_ARCH',data, True),bb.data.getVar('TARGET_FPU',data))
+
+
+
+ return TestItem(file,error == None, error)
diff --git a/trunk/bitbake_qa/source_checker/__init__.py b/trunk/bitbake_qa/source_checker/__init__.py
new file mode 100644
index 000000000..ef8c8b5e0
--- /dev/null
+++ b/trunk/bitbake_qa/source_checker/__init__.py
@@ -0,0 +1,40 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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 source_checker
+
+__all__ = [ "create_test" ]
+
+def create_test():
+ return source_checker.TestCase()
diff --git a/trunk/bitbake_qa/source_checker/source_checker.py b/trunk/bitbake_qa/source_checker/source_checker.py
new file mode 100644
index 000000000..5dfc7ceab
--- /dev/null
+++ b/trunk/bitbake_qa/source_checker/source_checker.py
@@ -0,0 +1,80 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+#
+# Copyright (C) 2005 Holger Hans Peter Freyther
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name Holger Hans Peter Freyther nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# 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.
+
+from bittest import TestItem
+import bb
+import os, sys
+
+class TestCase:
+ def __init__(self):
+ pass
+
+ def test_name(self):
+ return "Source Checker"
+
+ def generate_error(file, error):
+ (type,value,traceback) = sys.exc_info()
+ return TestItem(file,False,error % (value,type,traceback))
+ generate_error = staticmethod(generate_error)
+
+ def test(self,file, data):
+ # we run the tests
+
+ src_uri = bb.data.getVar('SRC_URI', data, 1)
+
+ if not src_uri:
+ return TestItem(file,True,"NO SRC_URI")
+
+ try:
+ bb.fetch.init(src_uri.split(), data)
+ except bb.fetch.NoMethodError:
+ return TestCase.generate_error(file,"""No Method Exception %s
+Type: %s
+Traceback: %s
+""")
+ try:
+ bb.fetch.go(data)
+ except bb.fetch.MissingParameterError:
+ return TestCase.generate_error(file,"""Missing Parameter Error %s
+Type: %s
+Traceback: %s
+""")
+ except bb.fetch.FetchError:
+ return TestCase.generate_error(file,"""Fetch Error %s
+Type: %s
+Traceback: %s
+""")
+
+ return TestItem(file,True,"")
+