# Setting Up Your Project

This chapter will walk you through the basics of setting up a MakeKit project. It will assume a C language project, the finer details of which are covered in . However, the steps here remain the same for any sort of project.

## Directory Layout

All MakeKit rules are placed in `MakeKitBuild`. You can opt to use a single such file in the top level directory of your project, or split your build logic into smaller `MakeKitBuild` files in each subdirectory of your project, or some intermediate arrangement. A typical project opting for multiple small files might look like the following:

### `project-name/`

- `MakeKitBuild`

- `default.conf`

- `include/`

  - `MakeKitBuild`

  - `project-name.h`

- `src/`

  - `MakeKitBuild`

  - `project-name.c`

- `doc/`

  - `MakeKitBuild`

  - `readme.txt`

## Build Files

Once you've decided where to place your `MakeKitBuild` files, you'll need to put something in them. Each file is an ordinary POSIX shell script, but it should adhere to a particular structure which MakeKit expects. The following shows what the top-level `MakeKitBuild` might look like for our example project layout:

    SUBDIRS="include src doc"
    MODULES="core compiler"
    PROJECT_NAME="project-name"

    defaults()
    {
        PREFIX=/opt/project-name
    }

    option()
    {
        mk_option \
            OPTION="config-file" \
            VAR="CONFIG_FILE" \
            PARAM="path" \
            DEFAULT="${MK_SYSCONFDIR}/project-name.conf" \
            HELP="Configuration file path"
    }

    configure()
    {
        mk_msg "configuration file: $CONFIG_FILE"
    }

    make()
    {
        mk_stage SOURCE="default.conf" DEST="$CONFIG_FILE"
    }

The `SUBDIRS` variable specifies a list of subdirectories where MakeKit should look for further `MakeKitBuild` files. This line can be omitted if there are no subdirectories to specify.

The `MODULES` variable specifies which MakeKit modules you will be using. Each module adds additional functionality on top of the core build engine. For example, the `compiler` module gives you access to functions for configure and building C language programs and libraries.

The `PROJECT_NAME` variable specified the name of the project. If unspecified, the name of the directory of the `MakeKitBuild` file is used instead.

The `defaults` function allows you to set default values for options that are usually specified by the user when configuring the project to be built, such as the installation prefix.

The `option` function is where you can define configuration options for your project which can be passed on the command line. Each option is declared with with `mk_option` function, which specifies the option name as passed on the command line (`OPTION`), the shell variable to store the setting in (`VAR`), a one-word description of the parameter that should be passed to the option (`PARAM`), a default value to use if the option isn't specified (`DEFAULT`), and a help message descriping the option (`HELP`). This particular example allows customizing the location of a configuration file.

The `configure` function is where you can perform any configuration for your project. Typical operations performed here include processing any options which were specified and testing that the system meets any prerequisites for building. Messages are usually printed to the user summarizing what is being done.

The `make` function is the meat of your build system. This is where you should define the build rules for your project that produce its actual end products. The example above installs a default configuration file into the location that was specified with the `config-file` parameter.

All of these elements are optional. It is not unusual for subdirectories that act only as organizational elements to contain a `MakeKitBuild` with only a `SUBDIRS` line.

Your build files will be processed as follows, starting from the top-level `MakeKitBuild`:

- The `option` function will be run if present.
- The `configure` function will be run if present.
- For each directory in `SUBDIRS`, the `MakeKitBuild` file in that directory will be recursively processed according to this list.
- The `make` function will be run if present

If you wish for the `make` function of a directory to be run before (or in the middle) of processing subdirectories, you may put `.` in `SUBDIRS`.

## Installing MakeKit

Once your build files are in place, you're ready to install a copy of MakeKit into your project directory. This step makes your build system self-contained and ready to distribute to other people. Simply run the following in your shell:

    $ makekit init

This will install a copy of MakeKit into the `mk` subdirectory, and create an executable `configure` script which can be run to configure your project.

You can see additional options to the `makekit init` command by specifying the `-h` option:

    $ makekit init -h
    makekit init -- install MakeKit files into current directory

    Usage: makekit init [ options ]

    Options:

      -h,--help         Show this help
      -s                Symlink files instead of copying them
      -f                Overwrite existing files

## Configuring

Once MakeKit has been installed, you are ready to run `configure` to generate a `Makefile` for your project. You should always configure from a directory other than your project directory to avoid cluttering it with generated files. This also allows you to have multiple build areas with different settings (e.g. debug versus release).

For example, the following sequence of commands demonstrates creating a build area called `build` and the result of running `configure` from within it.

    $ mkdir build
    $ cd build
    $ ../configure
               [makekit] initializing
              [platform] build operating system: linux
              [platform] build distribution: ubuntu
              [platform] build distribution version: 10.10
              [platform] build processor architecture: x86
              [platform] build instruction set architectures: x86_32
              [platform] host operating system: linux
              [platform] host distribution: ubuntu
              [platform] host distribution version: 10.10
              [platform] host processor architecture: x86
              [platform] host instruction set architectures: x86_32
                  [path] prefix: /opt/project-name
                  [path] exec prefix: /opt/project-name
                  [path] library dir (x86_32): /opt/project-name/lib
                  [path] include dir: /opt/project-name/include
                  [path] binary dir: /opt/project-name/bin
                  [path] system binary dir: /opt/project-name/sbin
                  [path] system config dir: /opt/project-name/etc
                  [path] local state dir: /opt/project-name/var
                  [path] data root dir: /opt/project-name/share
                  [path] data dir: /opt/project-name/share/project-name
                  [path] documenation dir: /opt/project-name/share/doc/project-name
                  [path] HTML documentation dir: /opt/project-name/share/doc/project-name/html
                  [path] manpage dir: /opt/project-name/share/man
              [compiler] default C compiler: gcc
              [compiler] default C preprocessor flags:
              [compiler] default C compiler flags: -O2 -g
              [compiler] default linker flags: -O2 -g
              [compiler] C compiler (build/x86_32): gcc -m32
              [compiler] C preprocessor flags (build/x86_32):
              [compiler] C compiler flags (build/x86_32): -O2 -g
              [compiler] linker flags (build/x86_32): -O2 -g
              [compiler] C compiler (host/x86_32): gcc -m32
              [compiler] C preprocessor flags (host/x86_32):
              [compiler] C compiler flags (host/x86_32): -O2 -g
              [compiler] linker flags (host/x86_32): -O2 -g
          [project-name] configuration file: /opt/project-name/etc/project-name.conf

You can see the full set of options to `configure` by passing `--help`:

    $ ../configure --help
    Usage: makekit configure [ option | @settings_file ] ...
    Options:
      --sourcedir=path            Source directory [.]
      --objectdir=path            Intermediate file directory [object]
      --stagedir=path             Staging directory [stage]
      --rundir=path               Build tool install directory [run]
      --show-vars=yes|no          Always show options as variable names in help
                                  output [no]
      --help=yes|no               Show this help [yes]

    Options (platform):
      --build-os=value            Build operating system [linux]
      --build-arch=value          Build CPU architecture [x86]
      --build-isas=value          Build instruction set architectures [x86_32]
      --build-distro=value        Build operating system distribution [ubuntu]
      --build-distro-version=value
                                  Build operating system distribution version
                                  [10.10]
      --build-distro-archetype=value
                                  Build operating system distribution archetype
                                  [debian]
      --host-os=value             Host operating system [linux]
      --host-arch=value           Host CPU architecture [x86]
      --host-isas=value           Host instruction set architectures [x86_32]
      --host-distro=value         Host operating system distribution [ubuntu]
      --host-distro-version=value Host operating system distribution version [10.10]
      --host-distro-archetype=value
                                  Host operating system distribution archetype
                                  [debian]

    Options (core):
      --fail-on-warn=yes|no       Fail on warnings [no]
      --debug=yes|no              Build in debug mode [no]

    Options (path):
      --prefix=path               Architecture-independent installation prefix
                                  [/opt/project-name]
      --exec-prefix=path          Architecture-dependent installation prefix
                                  [/opt/project-name]
      --libdir=path               Library directory (x86_32) [/opt/project-name/lib]
      --includedir=path           Header file directory [/opt/project-name/include]
      --bindir=path               User executable directory [/opt/project-name/bin]
      --sbindir=path              System executable directory
                                  [/opt/project-name/sbin]
      --libexecdir=path           Program executable directory
                                  [/opt/project-name/libexec]
      --sysconfdir=path           System configuration directory
                                  [/opt/project-name/etc]
      --localstatedir=path        Local state directory [/opt/project-name/var]
      --datarootdir=path          Root data directory [/opt/project-name/share]
      --datadir=path              Data directory
                                  [/opt/project-name/share/project-name]
      --docdir=path               Documentation directory
                                  [/opt/project-name/share/doc/project-name]
      --htmldir=path              HTML documentation directory
                                  [/opt/project-name/share/doc/project-name/html]
      --mandir=path               UNIX man page directory
                                  [/opt/project-name/share/man]

    Options (compiler):
      CC=program                  Default C compiler [gcc]
      CPPFLAGS=flags              Default C preprocessor flags []
      CFLAGS=flags                Default C compiler flags [-O2 -g]
      LDFLAGS=flags               Default linker flags [-O2 -g]
      BUILD_X86_32_CC=program     C compiler (build/x86_32) [gcc -m32]
      BUILD_X86_32_CPPFLAGS=flags C preprocessor flags (build/x86_32) []
      BUILD_X86_32_CFLAGS=flags   C compiler flags (build/x86_32) [-O2 -g]
      BUILD_X86_32_LDFLAGS=flags  Linker flags (build/x86_32) [-O2 -g]
      HOST_X86_32_CC=program      C compiler (host/x86_32) [gcc -m32]
      HOST_X86_32_CPPFLAGS=flags  C preprocessor flags (host/x86_32) []
      HOST_X86_32_CFLAGS=flags    C compiler flags (host/x86_32) [-O2 -g]
      HOST_X86_32_LDFLAGS=flags   Linker flags (host/x86_32) [-O2 -g]

    Options (project-name):
      --config-file=path          Configuration file path
                                  [/opt/project-name/etc/project-name.conf]

Note that this includes options for MakeKit itself, all modules which were used (either directly or indirectly), and finally options from the project.

## Building

At this point, the project is ready to be built by running `make`. When complete, all end products will have been placed in the `stage` directory, which has an internal structure mirroring the UNIX root filesystem. From here, the products can be copied into place or packaged up using your favorite packaging format. MakeKit also generates the following set of convenience targets to aid in your workflow:

`make subdir`

  Builds products only from subdir and any of its transitive subdirectories. For example, `make `doc`` or `make `src``.

`make clean`

  Removes all built intermediate products while leaving end products (anything in `stage`) untouched.

`make SUBDIR=subdir clean`

  Removes all built intermediate products only from subdir and any of its transitive subdirectories.

`make scrub`

  Removes everything that `make clean` removes, plus all end products in the `stage` directory.

`make nuke`

  Completely removes all generated files from the build area, including all intermediate and end products and anything generated by running `configure`.

`make install`

  Installs all end products built so far into their final locations on the filesystem. You will generally need root permissions to do this.

`make DESTDIR=dest install`

  Installs all end products built so far into dest rather than `/`. This might be useful for creating a package or binary tarball. Of course, you could just tar up `stage` directly...