diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2dc991277439943ef15a88043ae7726cc426edd5..2881eaa9664b7a58efe44aa18bd7879b3cd5c021 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -39,15 +39,15 @@ Configure with gcc:
     <<: *main_tests
     stage: Configures
     script:
-        - cd $HOME/$CI_PIPELINE_ID/build.gcc
-        - ../configure --prefix=$HOME/$CI_PIPELINE_ID/build.gcc --with-debug --static-modules CC=gcc
+        - cd $HOME/$CI_PIPELINE_ID/
+        - scripts/validate.bash --compiler=clang --debug --static-modules --step=configure
 
 Configure with clang:
     <<: *main_tests
     stage: Configures
     script:
-        - cd $HOME/$CI_PIPELINE_ID/build.clang
-        - ../configure --prefix=$HOME/$CI_PIPELINE_ID/build.clang --with-debug --static-modules CC=clang
+        - cd $HOME/$CI_PIPELINE_ID/
+        - scripts/validate.bash --compiler=clang --debug --static-modules --step=configure
 
 #################################################
 ### Builds ######################################
@@ -57,14 +57,12 @@ Build with gcc:
     <<: *main_tests
     stage: Builds
     script:
-        - cd $HOME/$CI_PIPELINE_ID/build.gcc
-        - make -j4
-        - make install
+        - cd $HOME/$CI_PIPELINE_ID/
+        - scripts/validate.bash --compiler=gcc --step=build
 
 Build with clang:
     <<: *main_tests
     stage: Builds
     script:
         - cd $HOME/$CI_PIPELINE_ID/build.clang
-        - make -j4
-        - make install
+        - scripts/validate.bash --compiler=clang --step=build
diff --git a/scripts/astyle.sh b/scripts/astyle.sh
index 0a4a45c565660898d023d54c4bab3e9fec5fb02d..1ec4735fcb2d4ad9eb216551d7a6920c2fa9c9d1 100755
--- a/scripts/astyle.sh
+++ b/scripts/astyle.sh
@@ -16,8 +16,8 @@ OPTIONS='
   --quiet'
 
 
-find . -iname '*.c' -exec astyle $OPTIONS {} \;
-find . -iname '*.h' -exec astyle $OPTIONS {} \;
-find . -iname '*.hpp' -exec astyle $OPTIONS {} \;
-find . -iname '*.cpp' -exec astyle $OPTIONS {} \;
-find . -iname '*.orig' -exec rm {} \;
+find . -iname '*.c'     -exec astyle $OPTIONS {} \;
+find . -iname '*.h'     -exec astyle $OPTIONS {} \;
+find . -iname '*.hpp'   -exec astyle $OPTIONS {} \;
+find . -iname '*.cpp'   -exec astyle $OPTIONS {} \;
+find . -iname '*.orig'  -exec rm {} \;
diff --git a/scripts/karafont.sh b/scripts/karafont.sh
index 751ac6dec967b53807820c5e02aa7d9da4dc08ac..6536333786d3f40d3ce6ae10f48a24e8d53e2e03 100755
--- a/scripts/karafont.sh
+++ b/scripts/karafont.sh
@@ -1,49 +1,46 @@
 #!/bin/sh
 
-
 BASE=/home/kara
 
 # Extract all fonts from the MKV file ($1)
-function extract_fonts {
-  STA=0
-  IDX=0
-  while [ $STA -eq 0 ]
-  do
-    IDX=$[ $IDX + 1 ]
-    mkvextract "$1" attachments "$IDX:/tmp/fontfile$IDX.ttf" 2>/dev/null >/dev/null
-    STA=$?
-  done
-  return $IDX
+function extract_fonts ()
+{
+    STA=0
+    IDX=0
+    while [ $STA -eq 0 ] ; do
+        IDX=$[ $IDX + 1 ]
+        mkvextract "$1" attachments "$IDX:/tmp/fontfile$IDX.ttf" 2>/dev/null >/dev/null
+        STA=$?
+    done
+    return $IDX
 }
 
-
 # Update attachments with the right type MIME, $1 is the MKV file, $2 is the id of the attachments
-function update_attachments {
-  mkvpropedit "$1" --attachment-mime-type application/x-truetype-font --update-attachment "$2" 2>/dev/null >/dev/null
+function update_attachments ()
+{
+    mkvpropedit "$1" --attachment-mime-type application/x-truetype-font --update-attachment "$2" 2>/dev/null >/dev/null
 }
 
-function update_kara_main {
-  [ -z "$1" ] && return 1
+function update_kara_main ()
+{
+    [ -z "$1" ] && return 1
 
-  # Get if there are fonts as attachments in the MKV
-  FILE=$(mkvinfo -t "$1" | grep -iE 'ttf|otf' 2>/dev/null | grep -oE '[^ ]+$')
-  STA=$?
+    # Get if there are fonts as attachments in the MKV
+    FILE=$(mkvinfo -t "$1" | grep -iE 'ttf|otf' 2>/dev/null | grep -oE '[^ ]+$')
+    STA=$?
 
-  ! [ $STA -eq 0 ] && return 1
+    ! [ $STA -eq 0 ] && return 1
 
-  extract_fonts "$1"
-  COUNT=$[ $? - 1 ]
-  while [ $COUNT -gt 0 ]
-  do
-    update_attachments "$1" "$COUNT"
-    COUNT=$[ $COUNT - 1 ]
-  done
-  echo "$1"
+    extract_fonts "$1"
+    COUNT=$[ $? - 1 ]
+    while [ $COUNT -gt 0 ] ; do
+        update_attachments "$1" "$COUNT"
+        COUNT=$[ $COUNT - 1 ]
+    done
+    echo "$1"
 }
 
-
-if [ -z "$1" ]
-then
+if [ -z "$1" ] ; then
   find $BASE -type f -name '*.mkv' -exec "$0" "{}" \;
 else
   update_kara_main "$1"
diff --git a/scripts/validate.bash b/scripts/validate.bash
new file mode 100644
index 0000000000000000000000000000000000000000..10a24401d210a813029790c5831ae8f07908bcc3
--- /dev/null
+++ b/scripts/validate.bash
@@ -0,0 +1,129 @@
+#!/bin/bash
+
+### GLOBAL VARIABLES #########################################################
+INFORMATION_COLOR="$(printf "\\033[0;32m")"
+DEFAULT_COLOR="$(printf "\\033[0;39m")"
+IMPORTANT_COLOR="$(printf "\\033[1;31m")"
+WARNING_COLOR="$(printf "\\033[4;33m")"
+
+LKT_DEBUG=""                # Whether or not to build in debug mode
+LKT_STATIC_MODULES=""       # Build modules inside liblektor.so or not
+LKT_COMPILER=""             # The compiler to use, the basename
+LKT_STEP=""                 # Steps: configure, build, etc
+LKT_DIR="$PWD"              # The project directory
+LKT_CONFIGURE_OPTIONS=""    # Options to pass to the configure command
+LKT_CORE_NUMBER=4           # Number of cores to use with make
+
+### Utility functions ########################################################
+function die ()
+{
+    printf "$IMPORTANT_COLOR$@$DEFAULT_COLOR\n" >/dev/stderr
+    exit 1
+}
+
+function check_cd ()
+{
+    [ $# -ne 1 ] && die "Invalid number of argument '$#' for cd command"
+    cd $1        || die "Can't go to folder $1"
+}
+
+function check_configure ()
+{
+    $LKT_DIR/configure $* || die "Failed to configure with $LKT_COMPILER"
+}
+
+function check_make ()
+{
+    make $* || die "Failed to make with compiler $LKT_COMPILER"
+}
+
+if ! [ -f $PWD/scripts/validate.sh ] ; then
+    die This script should be run from the root of the project
+fi
+
+### CONFIGURE ################################################################
+# Globals:                                                                   #
+# - LKT_DIR                 Project root directory                           #
+# - LKT_COMPILER            The compiler used to build                       #
+# - LKT_CONFIGURE_OPTIONS   Options to pass to the configure command         #
+function do_configure ()
+{
+    check_cd $LKT_DIR
+    mkdir {build,install}.$LKT_COMPILER
+    check_cd build.$LKT_COMPILER
+    check_configure                                                           \
+        --prefix=$LKT_DIR/install.$LKT_COMPILER                               \
+        $LKT_CONFIGURE_OPTIONS
+    check_cd $LKT_DIR
+}
+
+### BUILD THE PROJECT ########################################################
+# Globals:                                                                   #
+# - LKT_DIR                 Project root directory                           #
+# - LKT_COMPILER            The compiler used to build                       #
+function do_build ()
+{
+    check_cd $LKT_DIR/build.$LKT_COMPILER
+    check_make -j$LKT_CORE_NUMBER
+    check_make install
+    check_cd $LKT_DIR
+}
+
+### PERFORM THE STEPS ########################################################
+# Globals:                                                                   #
+# - LKT_STEP                Steps to perform                                 #
+function do_steps ()
+{
+    local _build=""
+    local _configure=""
+    for step in $LKT_STEP ; do
+        case "$step" in
+            build)      do_build;;
+            configure)  do_configure;;
+        esac
+    done
+}
+
+### PROCESS ARGS #############################################################
+# Globals:                                                                   #
+# - LKT_DEBUG               Whether or not to build in debug mode            #
+# - LKT_STATIC_MODULES      Build lektor modules inside liblektor.so         #
+# - LKT_CONFIGURE_OPTIONS   Options to pass to the configure command         #
+function process_args ()
+{
+    if [ "x$LKT_DEBUG" = "xyes" ] ; then
+        LKT_CONFIGURE_OPTIONS="$LKT_CONFIGURE_OPTIONS --with-debug"
+    fi
+    if [ "x$LKT_STATIC_MODULES" = "xyes" ] ; then
+        LKT_CONFIGURE_OPTIONS="$LKT_CONFIGURE_OPTIONS --with-static-modules"
+    fi
+    LKT_CONFIGURE_OPTIONS="$LKT_CONFIGURE_OPTIONS CC=$LKT_COMPILER"
+}
+
+### PARSE ARGS ###############################################################
+for arg in $* ; do
+    case "$arg" in
+        --help|-h)
+            help
+            exit 0
+            ;;
+        --debug)
+            LKT_DEBUG="yes"
+            ;;
+        --build=*)
+            LKT_COMPILER=$(echo "A$arg" | sed -e 's/A--build='//g)
+            ;;
+        --static-modules)
+            LKT_STATIC_MODULES="yes"
+            ;;
+        --step=*)
+            LKT_STEP=$(echo "A$arg" | sed -e 's/A--step=//g' -e 's/,/ /g')
+            ;;
+        *)
+            die "Unknown argument $arg"
+            ;;
+    esac
+done
+
+process_args
+do_steps