How to Write a Build Config¶
This page walks through the process of writing a build script.
Config File¶
Here’s a simple config without any steps.
1#!/usr/bin/env python3
2
3from fab.build_config import BuildConfig
4
5with BuildConfig(project_label='<project label>') as state:
6 pass
If we want to run the build script from the command line, we give it executable permission with the command chmod +x build_it.py. We also add the shebang directive on line 1, telling our computer it’s a Python script.
Pick a project label. Fab creates a project workspace with this name (see Project Workspace).
Source Code¶
Let’s tell Fab where our source code is.
We use the find_source_files()
step for this.
We can point this step to a source folder, which is a valid way to use this step.
However, because Fab can sometimes create artefacts alongside the source [1],
we usually copy the source into the project workspace first using a grab
step.
A grab step will copy files from a folder or remote repo into a folder called “source” within the project workspace.
1#!/usr/bin/env python3
2
3from fab.build_config import BuildConfig
4from fab.steps.find_source_files import find_source_files
5from fab.steps.grab import GrabFolder
6
7if __name__ == '__main__':
8
9 with BuildConfig(project_label='<project label') as state:
10 grab_folder(state, src='<path to source folder>')
11 find_source_files(state)
Note
Fab tries to minimise user input by providing sensible defaults. In this case, the user doesn’t have to specify where the code goes. The grab and find_source_files steps already know what to do by default. Sensible defaults can be overridden.
Please see the documentation for find_source_files()
for more information,
including how to exclude certain source code from the build. More grab steps can be found in the grab
module.
After the find_source_files step, there will be a collection called "all_source"
, in the artefact store.
Preprocess¶
Next we want to preprocess our source code. Preprocessing resolves any #include and #ifdef directives in the code, which must happen before we analyse it.
Steps generally create and find artefacts in the Artefact Store, arranged into named collections.
The preprocess_fortran()
automatically looks for Fortran source code in a collection named ‘all_source’,
which is the default output from the preceding :funcfind_source_files step.
It filters just the (uppercase) .F90
files.
Note
Uppercase .F90
are preprocessed into lowercase .f90
.
The Fortran preprocessor will read the FPP environment variable to determine which tool to call.
1#!/usr/bin/env python3
2import logging
3
4from fab.build_config import BuildConfig
5from fab.steps.find_source_files import find_source_files
6from fab.steps.preprocess import preprocess_fortran
7
8logger = logging.getLogger('fab')
9
10if __name__ == '__main__':
11
12 with BuildConfig(project_label='<project label') as state:
13 grab_folder(state, src='<path to source folder>')
14 find_source_files(state)
15 preprocess_fortran(state)
Preprocessed files are created in the ‘build_output’ folder, inside the project workspace.
After the fortran_preprocessor step, there will be a collection called "preprocessed_fortran"
, in the artefact store.
Analyse¶
We must analyse()
the source code to determine which Fortran files to compile,
and in which order.
The Analyse step looks for source to analyse in several collections:
.f90
found in the source.F90
we pre-processed into.f90
preprocessed c
1#!/usr/bin/env python3
2import logging
3
4from fab.steps.analyse import analyse
5from fab.build_config import BuildConfig
6from fab.steps.find_source_files import find_source_files
7from fab.steps.grab import GrabFolder
8from fab.steps.preprocess import preprocess_fortran
9
10logger = logging.getLogger('fab')
11
12if __name__ == '__main__':
13
14 with BuildConfig(project_label='<project label') as state:
15 grab_folder(state, src='<path to source folder>')
16 find_source_files(state)
17 preprocess_fortran(state)
18 analyse(state, root_symbol='<program>')
Here we tell the analyser which Root Symbol we want to build into an executable.
Alternatively, we can use the find_programs
flag for Fab to discover and build all programs.
After the Analyse step, there will be a collection called "build_trees"
, in the artefact store.
Compile and Link¶
The compile_fortran()
step compiles files in the "build_trees"
collection.
The link_exe()
step then creates the executable.
1#!/usr/bin/env python3
2import logging
3
4from fab.steps.analyse import analyse
5from fab.build_config import BuildConfig
6from fab.steps.compile_fortran import compile_fortran
7from fab.steps.find_source_files import find_source_files
8from fab.steps.grab import GrabFolder
9from fab.steps.link import link_exe
10from fab.steps.preprocess import preprocess_fortran
11
12logger = logging.getLogger('fab')
13
14if __name__ == '__main__':
15
16 with BuildConfig(project_label='<project label') as state:
17 grab_folder(state, src='<path to source folder>')
18 find_source_files(state)
19 preprocess_fortran(state)
20 analyse(state, root_symbol='<program>')
21 compile_fortran(state)
22 link_exe(state)
After the link_exe()
step, the executable name can be found in a collection called "executables"
.
Flags¶
Preprocess, compile and link steps usually need configuration to specify command-line arguments to the underlying tool, such as symbol definitions, include paths, optimisation flags, etc. See also Advanced Flags.
C Code¶
Fab comes with C processing steps.
The preprocess_c()
and compile_c()
Steps
behave like their Fortran equivalents.
However, it currently requires a preceding step called the c_pragma_injector()
.
Fab needs to inject pragmas into C code before it is preprocessed in order to know which dependencies
are for user code, and which are for system code to be ignored.
See also Advanced C Code
Further Reading¶
More advanced config topics are discussed in Advanced Configuration.
You can see more complicated configs in Fab’s example run configs.