Wednesday, 29 September 2010

muddle and its directories - part 4 - building

Building a package

Whilst it is possible for a package to be built from more than one checkout, this is relatively uncommon, and it is quite usual for a package to correspond directly to a checkout. As it does in this case.

If one tries to build a package that doesn't exist, one will be told so:

$ m3 build cpio
Building package:cpio{x86}/postinstalled
There is no rule to build label package:cpio{x86}/postinstalled

It's simple to find out what packages there are:

$ m3 query packages
pkg_cpio

So let's build it:

$ m3 build pkg_cpio
Building package:pkg_cpio{x86}/postinstalled
> Building package:pkg_cpio{x86}/preconfig
> Make directory /home/tibs/sw/m3/example/obj/pkg_cpio/x86
> Make directory /home/tibs/sw/m3/example/install/x86
> Make directory /home/tibs/sw/m3/example/.muddle/tags/package/pkg_cpio
> Building package:pkg_cpio{x86}/configured
> make  -f Makefile config
Nothing to do
> Building package:pkg_cpio{x86}/built
> make  -f Makefile
cc -o /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world hello_world.c
> Building package:pkg_cpio{x86}/installed
> make  -f Makefile install
if [ ! -d /home/tibs/sw/m3/example/install/x86/bin ]; then mkdir /home/tibs/sw/m3/example/install/x86/bin; fi
install -m 0755 /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world /home/tibs/sw/m3/example/install/x86/bin/hello_world
install -m 0644 hello_world.c /home/tibs/sw/m3/example/install/x86/hello_world.c
> Building package:pkg_cpio{x86}/postinstalled

We now have two new directories:

$ ls -AFt
install/  obj/  src/  .muddle/

The src/ directory has not changed.

The .muddle/ directory has gained some new tags in .muddle/tags/package/pkg_cpio/, reflecting the new state of the build:

.muddle/
|-- Description
|-- RootRepository
`-- tags/
    |-- checkout/
    |   |-- builds/
    |   |   `-- checked_out
    |   `-- cpio_co/
    |       `-- checked_out
    `-- package/
        `-- pkg_cpio/
            |-- x86-built
            |-- x86-configured
            |-- x86-installed
            |-- x86-postinstalled
            `-- x86-preconfig

The obj/ directory contains the results of building packages. Thus we have a new directory called obj/pkg_cpio/x86.

obj/
`-- pkg_cpio/
    `-- x86/
        `-- hello_world*

Specifically, within obj/ there is a directory named after each package, within which there is a directory named after each role for that package. For convenience, the makefile can use the environment variable $(MUDDLE_OBJ) to refer to <root_dir>/obj/pkg_cpio/x86 (<root_dir> indicates the absolute path to the top-level build directory).

There would normally be more use of subdirectories such as $(MUDDLE_OBJ)/bin in a "real" build, and muddle provides some other environment variables to help with these.

The install/ contains the results of installing packages. Each {role} gets a separate directory in install/:

install/
`-- x86/
    |-- bin/
    |   `-- hello_world*
    `-- hello_world.c

Again, the makefile can use the environment variable $(MUDDLE_INSTALL) to refer to this role-specific directory.

As an aside, using the MUDDLE environment variables in this way means that if two packages (e.g., package:a{b}/* versus package:c{d}/*, or even package:a{b}/* versus package:a{d}/*) both use the same checkout, and thus the same makefile, the results of building the two packages will still end up in different, predictable directories.

It is possible to find out the entire environment muddle passes to a makefile with the makeenv query:

$ m3 query makeenv package:pkg_cpio{x86}/built
MUDDLE=/home/tibs/sw/m3/muddle3_labels/muddle/muddled/__main__.py
MUDDLE_INCLUDE_DIRS=
MUDDLE_INSTALL=/home/tibs/sw/m3/example/install/x86
MUDDLE_INSTRUCT=/home/tibs/sw/m3/muddle3_labels/muddle/muddled/__main__.py instruct pkg_cpio{x86}
MUDDLE_KIND=package
MUDDLE_LABEL=package:pkg_cpio{x86}/built
MUDDLE_LD_LIBRARY_PATH=
MUDDLE_LIB_DIRS=
MUDDLE_NAME=pkg_cpio
MUDDLE_OBJ=/home/tibs/sw/m3/example/obj/pkg_cpio/x86
MUDDLE_OBJ_INCLUDE=/home/tibs/sw/m3/example/obj/pkg_cpio/x86/include
MUDDLE_OBJ_LIB=/home/tibs/sw/m3/example/obj/pkg_cpio/x86/lib
MUDDLE_OBJ_OBJ=/home/tibs/sw/m3/example/obj/pkg_cpio/x86/obj
MUDDLE_PKGCONFIG_DIRS=
MUDDLE_PKGCONFIG_DIRS_AS_PATH=
MUDDLE_ROLE=x86
MUDDLE_ROOT=/home/tibs/sw/m3/example
MUDDLE_SRC=/home/tibs/sw/m3/example/src/cpio_co
MUDDLE_TAG=built
MUDDLE_TARGET_LOCATION=/
MUDDLE_UNINSTRUCT=/home/tibs/sw/m3/muddle3_labels/muddle/muddled/__main__.py instruct pkg_cpio{x86}

Builds specifying cross-compilation toolchains and other options may have much longer environments passed down.

Deployment

Deployment is the process of copying the files for the various roles from the install/ directories to the deploy/ directories.

Deployment is commonly the stage that prepares the "blob" that will be put onto the final device (if one is building an embedded device), and perhaps also aggregates the tools for doing so.

In this build, we are producing a CPIO archive.

(CPIO is a very old Unix archive format. For our purposes ("us" being muddle), its advantage is that it is possible to flag files within the archive with particular permission bits, to request creationg of device nodes, and other thing that would require superuser privileges if done "live" in the build tree.)

In this build we only have a single deployment target, so we don't need to specify its name.

$ m3 deploy
Building deployment:cpio_dep/deployed
> Building deployment:cpio_dep/deployed
> Make directory /home/tibs/sw/m3/example/deploy/cpio_dep
Collecting package:*{x86}/*  for deployment to / ..
h = ---Roots---
/ -> [ / (fs /home/tibs/sw/m3/example/install/x86) mode = 40755 uid = 7007 gid = 7007 kids = /bin /hello_world.c]
---Map---
/bin/hello_world -> [ /bin/hello_world (fs /home/tibs/sw/m3/example/install/x86/bin/hello_world) mode = 100755 uid = 7007 gid = 7007 kids = ]
/ -> [ / (fs /home/tibs/sw/m3/example/install/x86) mode = 40755 uid = 7007 gid = 7007 kids = /bin /hello_world.c]
/bin -> [ /bin (fs /home/tibs/sw/m3/example/install/x86/bin) mode = 40755 uid = 7007 gid = 7007 kids = /bin/hello_world]
/hello_world.c -> [ /hello_world.c (fs /home/tibs/sw/m3/example/install/x86/hello_world.c) mode = 100644 uid = 7007 gid = 7007 kids = ]
---

base = /
Scanning instructions for role x86, domain None ..
> Writing /home/tibs/sw/m3/example/deploy/cpio_dep/my_archive.cpio ..
> Packing / ..
> Packing /bin ..
> Packing /bin/hello_world ..
> Packing /hello_world.c ..
> Packing TRAILER!!! ..
> Make directory /home/tibs/sw/m3/example/.muddle/tags/deployment/cpio_dep

That leaves us with a new deploy/ directory:

$ ls -AFt
deploy/  install/  obj/  src/  .muddle/

containing our CPIO archive:

deploy/
`-- cpio_dep/
    `-- my_archive.cpio

and the appropriate tag has been set in the .muddle/ directory tree:

.muddle/tags/deployment/
`-- cpio_dep/
    `-- deployed

Rebuilding things

muddle provides a convenience command to rebuild a package:

$ m3 rebuild pkg_cpio
Killing package:pkg_cpio{x86}/built
Clearing tags: package:pkg_cpio{x86}/built package:pkg_cpio{x86}/installed package:pkg_cpio{x86}/postinstalled package:pkg_cpio{x86}/built
Building package:pkg_cpio{x86}/postinstalled
> Building package:pkg_cpio{x86}/built
> make  -f Makefile
cc -o /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world hello_world.c
> Building package:pkg_cpio{x86}/installed
> make  -f Makefile install
if [ ! -d /home/tibs/sw/m3/example/install/x86/bin ]; then mkdir /home/tibs/sw/m3/example/install/x86/bin; fi
install -m 0755 /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world /home/tibs/sw/m3/example/install/x86/bin/hello_world
install -m 0644 hello_world.c /home/tibs/sw/m3/example/install/x86/hello_world.c
> Building package:pkg_cpio{x86}/postinstalled

As you can see, this "kills" (deletes) the tags saying that the package has been built, installed and postinstalled, and then rebuilds the /postinstalled tag. This does not, however, do anything about things that depend on this package.

It is frequently more useful to use the distrebuild command, which is a conflation of the distclean and build commands:

$ m3 distrebuild pkg_cpio
Building: package:pkg_cpio{x86}/distclean ..
> Building package:pkg_cpio{x86}/distclean[T]
> make  -f Makefile distclean
rm -f /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world
Distclean is just a clean
Killing: package:pkg_cpio{x86}/preconfig ..
Clearing tags: package:pkg_cpio{x86}/preconfig package:pkg_cpio{x86}/configured package:pkg_cpio{x86}/preconfig package:pkg_cpio{x86}/installed package:pkg_cpio{x86}/postinstalled package:pkg_cpio{x86}/built
Building package:pkg_cpio{x86}/postinstalled
> Building package:pkg_cpio{x86}/preconfig
> Building package:pkg_cpio{x86}/configured
> make  -f Makefile config
Nothing to do
> Building package:pkg_cpio{x86}/built
> make  -f Makefile
cc -o /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world hello_world.c
> Building package:pkg_cpio{x86}/installed
> make  -f Makefile install
if [ ! -d /home/tibs/sw/m3/example/install/x86/bin ]; then mkdir /home/tibs/sw/m3/example/install/x86/bin; fi
install -m 0755 /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world /home/tibs/sw/m3/example/install/x86/bin/hello_world
install -m 0644 hello_world.c /home/tibs/sw/m3/example/install/x86/hello_world.c
> Building package:pkg_cpio{x86}/postinstalled

The distclean also removes the tags for any packages that depended upon this package (not very obvious in this case where we only had one, of course).

(Beware - it unsets the state of other packages, but not the deployment.)

You can also, quite legally, do the same thing by direct manipulation of the tag files in the .muddle/ directories:

$ rm .muddle/tags/package/pkg_cpio/*
$ m3 build pkg_cpio
Building package:pkg_cpio{x86}/postinstalled
> Building package:pkg_cpio{x86}/preconfig
> Building package:pkg_cpio{x86}/configured
> make  -f Makefile config
Nothing to do
> Building package:pkg_cpio{x86}/built
> make  -f Makefile
cc -o /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world hello_world.c
> Building package:pkg_cpio{x86}/installed
> make  -f Makefile install
if [ ! -d /home/tibs/sw/m3/example/install/x86/bin ]; then mkdir /home/tibs/sw/m3/example/install/x86/bin; fi
install -m 0755 /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world /home/tibs/sw/m3/example/install/x86/bin/hello_world
install -m 0644 hello_world.c /home/tibs/sw/m3/example/install/x86/hello_world.c
> Building package:pkg_cpio{x86}/postinstalled

That is, muddle doesn't care if you remove the tags directly, instead of via the command line tool.

You can even do things like:

$ rm .muddle/tags/checkout/builds/checked_out
$ m3 checkout _all
> svn checkout  http://muddle.googlecode.com/svn/trunk/muddle/examples/cpio/builds builds
Checked out revision 459.

This is quite deliberate. Whilst the muddle command line tool provides a variery of useful shorthand commands (such as "distclean", "distrebuild" and "redeploy"), it is quite possible and even sensible to exert finer control over a build by deleting (or, indeed, "touch"ing) tag files in the .muddle directory.

Do what I say, not what I do

Please note that although I have been explicitly requesting indiviual builds, rebuilds, deployments and so on above, this is not necessarily the normal way of using muddle. The muddle command line tool is carefully designed so that it normally does "the right thing", according to which directory you are in.

So, if one is at the top level of the build, and has checked out everything, it is more colloquial just to give the muddle command with no arguments than to be overly specific.

This is perhaps most easily shown by, well, showing it.

We can revert to the just checked out state quite easily, by just removing everything except the .muddle/ and src/ directories:

$ ls -AF
deploy/  install/  .muddle/  obj/  src/
$ rm -rf deploy/ install/ obj/
$ rm -rf .muddle/tags/package/ .muddle/tags/deployment/

Once we're back to the stage just after init, we can just do:

$ m3
Building deployment:cpio_dep/deployed
> Building package:pkg_cpio{x86}/preconfig
...
> Building package:pkg_cpio{x86}/configured
...
> Building package:pkg_cpio{x86}/built
...
> Building package:pkg_cpio{x86}/installed
...
> Building package:pkg_cpio{x86}/postinstalled
> Building deployment:cpio_dep/deployed
...
> Writing /home/tibs/sw/m3/example/deploy/cpio_dep/my_archive.cpio ..
...
> Make directory /home/tibs/sw/m3/example/.muddle/tags/deployment/cpio_dep

(I've shortened the log above, because by now it should be all too familiar.)

Contrariwise, if we clean it all up again:

$ rm -rf deploy/ install/ obj/
$ rm -rf .muddle/tags/package/ .muddle/tags/deployment/

and go into a particular checkout directory:

$ pushd src/cpio_co
$ m3
Killing package:pkg_cpio{x86}/built
Clearing tags: package:pkg_cpio{x86}/built package:pkg_cpio{x86}/installed package:pkg_cpio{x86}/postinstalled package:pkg_cpio{x86}/built
Building package:pkg_cpio{x86}/*
> Building package:pkg_cpio{x86}/distclean[T]
> Make directory /home/tibs/sw/m3/example/obj/pkg_cpio/x86
> Make directory /home/tibs/sw/m3/example/install/x86
> make  -f Makefile distclean
rm -f /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world
Distclean is just a clean
> Building package:pkg_cpio{x86}/clean[T]
> make  -f Makefile clean
rm -f /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world
> Building package:pkg_cpio{x86}/preconfig
> Make directory /home/tibs/sw/m3/example/.muddle/tags/package/pkg_cpio
> Building package:pkg_cpio{x86}/configured
> make  -f Makefile config
Nothing to do
> Building package:pkg_cpio{x86}/built
> make  -f Makefile
cc -o /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world hello_world.c
> Building package:pkg_cpio{x86}/installed
> make  -f Makefile install
if [ ! -d /home/tibs/sw/m3/example/install/x86/bin ]; then mkdir /home/tibs/sw/m3/example/install/x86/bin; fi
install -m 0755 /home/tibs/sw/m3/example/obj/pkg_cpio/x86/hello_world /home/tibs/sw/m3/example/install/x86/bin/hello_world
install -m 0644 hello_world.c /home/tibs/sw/m3/example/install/x86/hello_world.c
> Building package:pkg_cpio{x86}/postinstalled
$ popd

That is, muddle only rebuilds the packages that depend on this checkout. See muddle help build and its friends for more information on this.

People who like to cd around the filesystem a lot will probably find this intuitive. Those of us who prefer to sit at the top-level and work from there (not necessarily any more sensible, of course) are more likely just to do:

$ m3 distrebuild pkg_cpio

(yes, this has identical effect, and no, by now I'm not going to include the listing yet again).

Note

As an aside, if you want to preserve the source of a build, then (if there aren't any domains) it is sufficient to do:

$ tar -zcvf build.tgz .muddle/Description .muddle/RootRepository .muddle/tags/checkout src

Issue 125 suggests adding a muddle command to make this convenient (including in the with-domains case).

No comments:

Post a Comment