Skip to content

mpashton/fbuild

 
 

Repository files navigation

Fbuild Build System v0.2

Overview

Fbuild is a build system designed for configuring and compiling both small and large projects. It has extensive feature list:

  • Linux, Apple, and Windows support
  • Supports compiling C, C++, O'Caml, Java, Scala, GHC, and Felix
  • Extensive configuration detection for the C and C++ standard library, posix, and more
  • Parallel compilation
  • Cross compiling
  • Digest-based tracking of file changes
  • Full Python scriptability
  • Easy to extend
  • Pretty output
  • ... and it is quite fast too

Download and Installation

Fbuild is hosted and developed on Github. It requires Python 3. To download the current Fbuild version, you visit the Fbuild website. Or, if you have access to the curl program, you can just run this command:

$ curl -L https://github.com/erickt/fbuild/tarball/v0.2 | tar -zx

To download the development version, run this git command:

$ git clone git://github.com/erickt/fbuild.git

To install, run:

$ python3 setup.py install

Introduction

Fbuild has extensive support for advanced build systems, but this doesn't complicate simple projects. Here is the classic "Hello World" example, written in a C file named helloworld.c:

#include <stdio.h>
int main() {
    printf("hello world!\n");
    return 0;
}

Along side of it we will create a Python 3 file named fbuildroot.py, which will drive the compilation. We'll step through each line in a moment:

import fbuild.builders.c

def build(ctx):
    builder = fbuild.builders.c.guess_static(ctx)
    exe = builder.build_exe('helloworld', ['helloworld.c'])

    ctx.logger.log(' * running ' + exe)
    ctx.execute([exe])

As you can see, it is pretty compact Python script. To compile, if you installed Fbuild, simply run fbuild in the same directory as the fbuildroot.py. Otherwise, you can run fbuild-light out of the Fbuild distribution, which doesn't require installation. This is what you'll see:

$ fbuild  # or $FBUILD_DIR/fbuild-light
determining platform     : {'bsd', 'darwin', 'macosx', 'posix'}
looking for program gcc   : ok /usr/bin/gcc
checking gcc              : ok
looking for program ar    : ok /usr/bin/ar
looking for program ranlib : ok /usr/bin/ranlib
checking if gcc can make objects : ok
checking if gcc can make libraries : ok
checking if gcc can make exes      : ok
checking if gcc can link lib to exe : ok
 * gcc                              : helloworld.c -> build/helloworld.o
 * gcc                              : build/helloworld.o -> build/helloworld
 * running build/helloworld
hello world!

Broken down, Fbuild did:

  • automatically determined that I'm on a Apple machine
  • configured gcc for our c builder
  • tested that the c builder worked
  • compiled our code
  • and finally, ran the program

Now lets go through the fbuildroot.py:

...
def main(ctx):
    ...

Fbuild is written as a Python library with the fbuild script as a simple driver in order start up and stop the build. The default entry point is a function called build. If you run fbuild without any arguments or with fbuild build it will call this function. You can also create your own entry points with the fbuild.target module, which is described further on.

import fbuild.builders.c
...
builder = fbuild.builders.c.guess_static(ctx)
...

Next we have to make a c builder. Since pretty much each platform has it's own C compiler, Fbuild provides a mechanism to guess the platform's preferred one. fbuild.builders.c.guess_static creates a C builder that is capable of creating static libraries. You can also use fbuild.builders.c.guess_shared if you want to create dynamically loadable libraries. In this case though, we're just creating an executable so it doesn't matter which function we use.

exe = builder.build_exe('helloworld', ['helloworld.c'])

Now that we've got a builder, we can compile our binary. The first argument is the name of the executable, and the second is a list of input sources. There's a large amount of other options available. The most important are:

argument description
includes a list of directories to add to the include search path
libs a list of libraries to link in
libpaths a list of directories to add to the library search path
external_libs a list of libraries Fbuild should not track modification
macros a list of string macros
debug a boolean to enable debug builds
optimize a boolean to enable optimized builds
cflags a list of arbitrary arguments to pass to the compiler
lflags a list of arbitrary arguments to pass to the linker

These arguments can also be passed to fbuild.builders.c.guess_static if you want them to apply to everything built by the builder.

ctx.logger.log(' * running ' + exe)
ctx.execute([exe])

Finally, we'll execute the command we just compiled. We use the ctx.logger.log so that the message will be logged into the Fbuild log file, normally found in build/fbuild.log. To run the command we use ctx.execute, which is a wrapper around the system call execv, and also writes the command's output to the log file.

In comparison, this is an equivalent Makefile, written to use gcc:

exe = helloworld
srcs = helloworld.c
objs = $(srcs:%.c=%.o)

all: helloworld
    ./helloworld

helloworld: $(objs)
    gcc -o $@ $<

%.o: %.c
    gcc -c -o $@ $<

As you can see, Fbuild's driver script is about half the size and does so much more.

Unit Tests

To run the unit tests:

$ cd tests
$ python3 run_tests.py

Help

If you run into any problems, don't hesitate to ask a question on the fbuild mailing list. Or, you can usually find me in the #felix channel on irc.freenode.net.

About

A cross platform, high performant caching build system

Resources

License

Stars

Watchers

Forks

Packages

No packages published