Contents
Zeek’s compilation process is managed through CMake, which provides a cross-platform solution for generating native makefiles and IDE workspaces.
Since the Zeek source code is organized into many self-contained components, each of which has its own git repository, a given component has to not only drive its own build/install process via CMake, but also cooperate with other components to build/install the full Zeek distribution. The organizational term that CMake uses for a component is a "project" and most of Zeek’s CMake projects follow a similar structure.
The top-level CMakeLists.txt in each CMake project typically dedicates sections to accomplish specific tasks.
Things that change/extend CMake functionality are found here, commonly including:
* Enforcement of minimum CMake version * Enforcement of out-of-source builds * Addition of an ``uninstall`` target * Supplemental CMake modules
The supplemental CMake modules are typically located in the project’s cmake subdirectory and contains scripts (maintained by Zeek developers) with macros/functions that the project can rely on (e.g. FindFoo.cmake for finding if package Foo is installed).
The cmake subdirectory in any of the Zeek projects is actually its own repository that’s included in the project as a git submodule. This organization decreases the burden of maintaining separate CMake scripts per Zeek project since many of them share similar CMake code.
This first section is mostly just for organizing and determining the values of parameters that will either be used by the compiler or change a major configuration setting of the component.
The purpose of this section is straightforward — it contains the logic to check whether the component’s dependencies are satisfied for the given system’s configuration.
If the dependency is required, a custom FindRequiredPackage() macro is usually used as a convenient way to gather up all the missing dependencies to report to the user instead of aborting immediately on the first missing one.
If the dependency is optional, the standard find_package() macro and logic suffice.
Whether required or optional, if the dependency can be built from existing Zeek CMake project sources located in a subdirectory, then we first use the add_subdirectory() macro on that project which effectively encapsulates its build/install process within the current project.
Also, if the dependency can be built from source and it is required to be used during the build of the component that depends on it (e.g. Zeek’s dependency on BinPAC), then the sub-project is responsible for setting the required CMake variables that the super-project uses (e.g. library and binary paths) such that the build can complete without having to actually install the dependency.
This is the case where project A depends on project B, but the sources for B include the sources for A (e.g. Broctl depends on Zeek, but Zeek may include the Broctl sources).
The way to account for this case is to modify the FindB.cmake script within A’s sources to check for certain CMake variables that B sets, thus indicating that we don’t have to look in the standard places for an installation of B because we’re already part of its build process.
Platform-specific setting and other sanity-checking is usually done here, with the goal usually being to generate a config.h file.
Sometimes if a CMake project is large enough, the CMake logic is divided hierarchically according to directory structure and that’s simply accounted for with the add_subdirectory() macro.
This section may also have logic regarding Super-Project Dependencies simply because most of the super-project’s CMake logic has been seen by now which means that the depending sub-project can reliably tap into side effects caused by the super-project.
The CMake scripting for package configuration mostly involves gathering package metadata into the required formats. The only other key feature worth mentioning is that the packages are configured to include built-in pre/post-install scripts. One purpose of these scripts is to alert users of possibly modified configuration files which differ from the version that the package is about to install (this is a Mac specific feature, RPMs already have a robust means of handling config file changes). Another purpose, is to enforce a sticky bit on directories (/var/opt/bro/*) that Broctl may install (on Linux systems) as world-writable for runtime data.
Example for Zeek:
git clone --recursive https://github.com/zeek/zeek cd zeek make dist
When it makes sense, a configure shell script is provided to emulate the functionality of an Autotools-based build system. The main benefits are that it will be familiar to users and also that it provides an easy way to view configuration options, a feature lacking in CMake.
Simply put, the configure wrapper script passes options given to it along to CMake with the appropriate syntax. An important point is that while the CMake projects are written to work recursively and cooperate with each other, the configure scripts have no knowledge of each other. This means that if a super-project wants to be able to access configuration options exclusive to a sub-project, the super-project’s configure script needs to explicitly accept those options.
See here for instructions on creating a new git repository.
Now, in your local working-copy of the intended super-project, create a topic branch and add a git submodule by executing this in the top-level directory:
git submodule add <new repository's public URL> <relative-dst-path>
Then, use the CMake recipe outlined above and look at the existing Zeek CMake projects to determine what modifications are necessary. When everything is working, follow the standard process for merging changes into the git repositories.
© 2014 The Bro Project.