contact Me

Use the form on the right to contact me.

You are welcome, to contact me regarding the topics of this page, my open source projects, or my work. Please use the contact form and leave a valid email address for me to respond to.

Thank you.

Egidestr. 9
44892 Bochum
Germany

/brain/dump

Random thoughts, bright ideas and interesting experiments. In short the ramblings of a fulltime nerd.

 

Building Vala projects with CMake

Jakob Westhoff

Recently I wrote an application in Vala. Vala is a great language positioned around the GObject system, which is used a lot in the GTK/Gnome world. Vala is a very feature rich object-oriented high-level language, which incorporates modern language concepts known from C# or current versions of Java. In contrast to Java and C# Vala programs do not need any memory consuming runtime to be executed. They are compiled to plain C code, which is then compiled using your favorite compiler chain into good old machine-code. Most likely this will be GCC. To be able to build my Vala project I wanted to use CMake, which I like much better than the autotools. This blogpost gives a practical demonstration on how to integrate Vala with CMake to build your Vala based projects.

CMake as an Autotools alternative

CMake is an alternative as a build system to the widely known Autotools. It is much younger than the Autotools, which exist quite a while by now. However it gets quite some attention as, more and more established projects like KDE for example migrate their build systems over to CMake.

As I never really liked the Autotools syntax, I decided to go with CMake whenever I was in need for a build system centered around compiled languages. As I am mostly writing code for interpreted language namely PHP I don't have a need for these systems that often.

CMake provides all necessary functionality to check for package dependencies, find libraries and compiler executables, execute common compile tasks and link everything together into the executable or library you want to create.

Unfortunately all these features are targeted at building C/C++ projects. Luckily for us Vala code can be compiled straight to plain C code. Therefore all these already available nifty features can be used as soon as we can persuade CMake to compile our .vala files into .c files, before further processing them. This is where some CMake macro magic comes into place.

Vala macros for CMake

Different Vala specific things need to be taken care of, that are not part of the default CMake system.

First there is the need to ensure the Vala compiler valac is available on the system and more important the correct version is available. This is more important with Vala than with other languages, as Vala is a young and quickly evolving language, which often introduces new language features from one version to the another.

Second some action needs to be taken, to compile the .vala files into their .c equivalent, before these C language files are given to the usual CMake processing chain.

To accomplish both of these tasks I wrote some CMake macros to do the job. I have published them on github to allow everybody to easily fork them and/or provide patches for them. A detailed README, as well as a lot of inline documentation is available. At this point I want thank a fellow PHP-Usergroupie Florian Sowade, who came up with this idea of processing, as well as providing me with the initial draft version of the macros.

Installing the macros

To use the Vala macros in your own project you need to copy the macro files to an arbitrary folder in your projects directory and reference them in your CMakeLists.txt file.

Assuming the macros are stored under cmake/vala in your projects folder you need to add the following information to your base CMakeLists.txt:

list(APPEND CMAKE_MODULE_PATH 
    ${CMAKE_SOURCE_DIR}/cmake/vala
)

After the new module path as been added you can simply include the provided modules or use the provided find routines.

Using the FindVala macro

The find module for vala works like any other Find specific module in CMake. You can simple call it using the usual find_package function. Default parameters like REQUIRED and QUIETLY are supported.

find_package(VALA REQUIRED)

After a call to the find function the following variables will be set:

VALA_FOUND : Whether the vala compiler has been found or not

VALA_EXECUTABLE : Full path to the valac executable if it has been found

VALA_VERSION : Version number of the available valac

To ensure that a certain minimum Vala version is available on the system you can either use CMakes integrated version-compare conditions inside an if function, or use the the provided ensure_vala_version macro. Lets say you need at least Vala version 0.7.8 the following invocation would to the trick:

# Load the version module
include(ValaVersion)

# Check for the version
ensure_vala_version("0.7.8" MINIMUM)

Instead of supplying MINIMUM you could as well specify MAXIMUM or EXACT.

Precompiling Vala files to C code

As already mentioned CMake does know how to work with C and C++ files, but has no understanding of Vala source files. Therefore the .vala files need to be compiled to .c files before they can be further mangled by CMake.

The macro vala_precompile creates C files from your .vala sources for further CMake processing.

The first parameter provided is a variable, which will be filled with a list of C files outputted by the vala compiler. This list can than be used in conjunction with functions like add_executable or others to create the necessary compile rules with CMake.

The initial variable is followed by a list of .vala files to be compiled. Please take care to add every vala file belonging to the currently compiled project or library as Vala will otherwise not be able to resolve all dependencies.

The following sections may be specified afterwards to provide certain options to the vala compiler:

PACKAGES : A list of vala packages/libraries to be used during the compile cycle. The package names are exactly the same, as they would be passed to the valac "--pkg=" option.

OPTIONS : A list of optional options to be passed to the valac executable. This can be used to pass "--thread" for example to enable multi-threading support.

CUSTOM_VAPIS : A list of custom vapi files to be included for compilation. This can be useful to include freshly created vala libraries without having to install them in the system.

GENERATE_VAPI : Pass all the needed flags to the compiler to create an internal vapi for the compiled library. The provided name will be used for this and a \.vapi file will be created.

GENERATE_HEADER : Let the compiler generate a header file for the compiled code. There will be a header file as well as an internal header file being generated called \.h and \_internal.h

The following call is a simple example to the vala_precompile macro showing an example to every of the optional sections:

vala_precompile(VALA_C
    source1.vala
    source2.vala
    source3.vala
PACKAGES
    gtk+-2.0
    gio-1.0
    posix
OPTIONS
    --thread
CUSTOM_VAPIS
    some_vapi.vapi
GENERATE_VAPI
    myvapi
GENERATE_HEADER
    myheader
)

Most important is the variable VALA_C which will contain all the generated c file names after the call. The most likely to be used function with this information is add_executable to have CMake create an executable out of the provided sources.

An example CMake project

To get a better understanding of how all the shown macros work together in providing an easy way to build Vala projects, a really simple example project is presented here.

The example project consists of two Vala source files source_one.vala and source_two.vala, which will be build to create one executable called vala_cmake_demo. Furthermore the project has a dependency on GTK.

As with every CMake based project we start by creating a CMakeLists.txt.

First the project gets a name and the language it is written in is selected. Because we use Vala the language CMake needs to handle is C, as we are precompiling all our Vala sources to C before having CMake really process them.

project("our-first-vala-cmake-project" C)

To ensure all the functionality which is used in the script is available it is recommended to check for a certain cmake version, which can be done by a simple CMake macro:

cmake_minimum_required(VERSION 2.6)

The next step is to add the path to the needed Vala macros to CMakes module path:

list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/vala)

The command above assumes the macros have been installed in the directory cmake/vala under your current source directory. CMake is now able to include and load the macros needed to do all the Vala preprocessing. Therefore the next step is to do just that, include the macros:

include(ValaPrecompile)
include(ValaVersion)

So far we have prepared the project by setting all kinds of environmental and initial configuration. The next step is to ensure the Vala compiler is installed and a certain version is available:

find_package(Vala)
ensure_vala_version("0.7.8" MINIMUM)

At this point it is ensured the correct Vala version is available on the system. However another check is needed before the project source files can be configured. As stated in the introduction to this section the example project assumes to have a dependency on GTK. To check for this library CMake provides all the necessary utilities and find macros, which simply need to be called:

find_package(PkgConfig)
pkg_check_modules(GTK REQUIRED gtk+-2.0)
add_definitions(${GTK_CFLAGS} ${GTK_CFLAGS_OTHER})
link_libraries(${GTK_LIBRARIES})
link_directories(${GTK_LIBRARY_DIRS})

The CMake documentation is quite detailed about all the used macros. In short the commands first use pkg-config to locate the GTK library and include paths. Finally the acquired information is added to the paths and definitions to be used during the compile process.

The generation of the C files from the mentioned Vala sources is next. As described the vala_precompile macro takes care of that:

vala_precompile(VALA_C
    "source_one.vala"
    "source_two.vala"
PACKAGES 
    gtk+-2.0
)

The VALA_C variable will contain the list of generated C files after this call. Therefore making CMake to create an executable using the C compiler is easily done with the add_executable function:

add_executable("vala_cmake_demo" ${VALA_C})

All this put together in a directory structure together with our source files creates a simple but yet working Vala based CMake project. A simple call to cmake ./ && make builds the projects and creates the executable we need. One could add further CMake commands to be able to install the necessary files using make install, but this does not fit into this article.

Further reading

I hope you got a certain understanding of how things work in CMake using the Vala CMake macros. If you need more examples you might want to take a look at the Pdf Presenter Console repository, which makes heavy use of the presented build process.

Furthermore the CMake documentation does provide a lot of information about all different kinds of functionality which may be used inside of CMake.