Wednesday 21 October 2009

muddle: Cross-compiling V8

So, I'm transferring a native (Intel) build of various things to a cross-compiled build for the ARM (specifically, for my beagleboard).

Today's tasks were sqlite (which was harder than I expected) and V8, Google's open source JavaScript engine.


V8 is built using scons, which it turns out is not particularly well aimed at the cross compilation fans amongst us.

It turns out that you can set environment variables (such as CC) to tell scons which compiler to use, but of course you need to know all the calls to the toolchain it is going to make, in order to catch them all. The easiest way to do that seems to be to run scons -n (i.e., tell me what commands you'll obey, but don't actually do them), which does work, but means that if you update the scons build environment, and coincidentally the script mutates to use new parts of the toolchain, they won't be covered. Which is rather awful.

Note

I'm rather hoping I've missed something here, and there's actually a better way of doing this. Although any way that includes editing the scons script supplied by the original package won't count as "better".

Anyway, it turns out that the muddle way to build V8 is fairly simple - a small bit of muddle code, and a simple helper Makefile.

First, the muddle code:

# Make sure our host has scons available
aptget.simple(builder, 'platform_host_tools', role, ['scons'])

# Set up the cross compilation environment variables
# - we retrieve the environment that will be applied to all packages
# and add the environment variables to it
label = label_from_string('package:*{*}/*')
env = builder.invocation.get_environment_for(label)
env.set("MUDDLE_CROSS_COMPILE", "/opt/codesourcery/arm-2008q3/bin/arm-none-linux-gnueabi-")
env.set("MUDDLE_ARCH", "arm")

# For reasons to do with the particular system I'm building, the V8
# sources get checked out into 'src/platform/v8'. There's nothing
# special about revision '3108' - it's just today's revision
muddled.checkouts.twolevel.absolute(builder,
        co_dir="platform",
        co_name="v8",
        repo_url="svn+http://v8.googlecode.com/svn/trunk",
        rev="3106")

# I then have an out-of-tree Makefile to build V8 in our context,
# in 'src/helpers/v8'
make.medium(builder,
            name = "v8",          # package name
            roles = [role],
            checkout = 'helpers',
            makefileName = os.path.join("v8","Makefile.muddle"))

# And we can't build the package until we've checked its files out
muddled.pkg.package_depends_on_checkout(builder.invocation.ruleset,
                                        "v8",     # this package
                                        role,     # in this role
                                        "v8",     # depends on this checkout
                                        None)

It looks as if I'm going to standardise on the cross compilation environment variable names as given, and I'm using the technique often enough that the rather clumsy mechanism for setting them will probably get streamlined fairly soon.

The only other thing that is needed, then, is the Makefile, src/helpers/v8/Makefile.muddle.

Note

We started out calling the helpers directory builders (because it has stuff used to build other things), but I find it irritating having to discriminate between src/builds and src/builders, so I'm trying out the new name to see if it works.

The original of this makefile was not cross-platform. I believe this version should work in that situation as well.

# Muddle makefile to control v8 builds

V8_SRC=$(shell $(MUDDLE) query dir "checkout:v8{*}/*")

ifneq ($(MUDDLE_ARCH),)
        FLAGS=arch=$(MUDDLE_ARCH)
        ENV=CXX=$(MUDDLE_CROSS_COMPILE)g++ CC=$(MUDDLE_CROSS_COMPILE)gcc
else
        FLAGS=
        ENV=
endif

SCONS_CMD=scons -C . -f $(V8_SRC)/SConstruct -Y $(V8_SRC)

all:
        (cd $(MUDDLE_OBJ_OBJ); $(ENV) $(SCONS_CMD) $(FLAGS) library=shared mode=release)
        (cd $(MUDDLE_OBJ_OBJ); $(ENV) $(SCONS_CMD) $(FLAGS) library=shared mode=debug)

config:
        -rm -rf $(MUDDLE_OBJ)
        -mkdir -p $(MUDDLE_OBJ_OBJ)

install:
        -mkdir -p $(MUDDLE_OBJ_INCLUDE)/v8
        -mkdir -p $(MUDDLE_OBJ_LIB)
        -mkdir -p $(MUDDLE_INSTALL)/usr/lib

        install -m 0644 $(V8_SRC)/include/v8.h       $(MUDDLE_OBJ_INCLUDE)/v8/v8.h
        install -m 0644 $(V8_SRC)/include/v8-debug.h $(MUDDLE_OBJ_INCLUDE)/v8/v8-debug.h
        install -m 0755 $(MUDDLE_OBJ_OBJ)/libv8.so   $(MUDDLE_OBJ_LIB)/libv8.so
        install -m 0755 $(MUDDLE_OBJ_OBJ)/libv8_g.so $(MUDDLE_OBJ_LIB)/libv8_g.so
        install -m 0755 $(MUDDLE_OBJ_OBJ)/libv8.so   $(MUDDLE_INSTALL)/usr/lib/libv8.so
        install -m 0755 $(MUDDLE_OBJ_OBJ)/libv8_g.so $(MUDDLE_INSTALL)/usr/lib/libv8_g.so
        echo INSTALL=$(MUDDLE_INSTALL)

clean:
        (cd $(MUDDLE_OBJ_OBJ); $(SCONS_CMD) --clean)

distclean:
        -rm -rf $(MUDDLE_OBJ)

The scons switches used are:

  • -C <directory> -- cd to this directory before building
  • -f <path> -- the given <path> is the scons build script
  • -Y <directory> -- look for import files in the given directory (the scons documentation talks about this as specifying the repository path, but that sounds like a use of the same term for a different purpose)

The disposal of the various resultant files within the muddle build tree matches the Intel build.

There are some caveats; notably that I've checked that the build produces ARM files, but haven't yet had a chance to test them, and the Makefile could clearly do with some tidying up -- for a start, it's clearly very clumsy to do cd <somewhere>; scons -C . instead of just doing scons -C <somewhere>.

No comments:

Post a Comment