This document provides an introduction in how the source code of libelektra is organized and how and where to add functionality.
Make sure to read DESIGN together with this document.
After you downloaded and unpacked Elektra you should see some folders. The most important are:
- src: This directory contains the source of the libraries, tools and plugins.
- doc: General documentation for the project and the core library.
- examples: Examples on how to use the core library.
- tests: Contains the testing framework for the source (src).
libelektra is the ANSI/ISO C99-Core which coordinates the interactions between the user and the plugins.
The plugins have all kinds of dependencies. It is the responsibility of the plugins to find and check them using CMake. The same guidelines apply to all code in the repository including the plugins.
libloader
is responsible for loading the backend modules. It works on
various operating systems by using libltdl
. This code is optimized
for static linking and win32.
kdb is the commandline-tool to access and initialize the Elektra database.
You are only allowed to break a guideline if there is a good reason to do so. When you do, document the fact as comment next to the code.
Of course, all rules of good software engineering apply: Use meaningful names and keep the software both testable and reusable.
The purpose of the guidelines is to have a consistent style, not to teach programming.
If you see code that breaks guidelines do not hesitate to fix them. At least put a TODO marker to make the places visible.
If you see inconsistency within the rules do not hesitate to talk about it with the intent to add a new rule here.
See DESIGN document too, they complement each other.
Code is not only for the computer, but it should be readable for humans, too. Up-to-date code comments are essential to make code understandable for others. Thus please use following techniques (in order of preference):
-
Comment functions with
/**/
and Doxygen, see below. -
You should also add assertions to state what should be true at a specific position in the code. Their syntax is checked and they are automatically verified at run-time. So they are not only useful for people reading the code but also for tools. Assertions in Elektra are used by:
#include <kdbassert.h>
ELEKTRA_ASSERT (condition, "formatted text to be printed when assert fails", ...)
Note: Do not use assert for user-APIs, always handle arguments of user-APIs like untrusted input.
-
If the "comment" might be useful to be printed during execution, use logging:
#include <kdblogger.h>
ELEKTRA_LOG ("formatted text to be printed according to log filters", ...)
Read HERE for how to enable the logger.
-
Otherwise comment within source with
//
or with/**/
for multi-line comments.
-
Limits
- Functions should not exceed 100 lines.
- Files should not exceed 1000 lines.
- A line should not be longer than 140 characters.
Split up when those limits are reached. Rationale: Readability with split windows.
-
Indentation
- Use tabs for indentation.
- One tab equals 8 spaces.
-
Blocks
- Use blocks even for single line statements.
- Curly braces go on a line on their own on the previous indentation level.
- Avoid multiple variable declarations at one place.
- Declare Variables as late as possible, preferable within blocks.
-
Naming
- Use camelCase for functions and variables.
- Start types with upper-case, everything else with lower-case.
- Prefix names with
elektra
for internal usage. External API either starts withks
,key
orkdb
.
-
Whitespaces
- Use space before and after equal when assigning a value.
- Use space before round parenthesis (
(
). - Use space before and after
*
from Pointers. - Use space after
,
of every function argument.
The reformat script can ensure most code style rules, but it is obviously not capable of ensuring everything (e.g. naming conventions). So do not give this responsibility out of hands entirely.
- The compiler shall not emit any warning (or error).
- Use goto only for error situations.
- Use
const
as much as possible. - Use
static
methods if they should not be externally visible. - C-Files have extension
.c
, Header files.h
. - Use internal functions: prefer to use
elektraMalloc
,elektraFree
.
Example: src/libs/elektra/kdb.c
To guarantee consistent formatting we use clang-format
(version 6.0
or version 7.0
) to format all C and C++ code in the repository. Since our build servers also check the style for every pull request you might want to make sure you reformat your C/C++ code changes with this tool.
To find out which version of clang-format
a certain build server uses please check:
- the Debian sid Docker image,
- the Travis configuration file , and
- the Cirrus configuration file
and search for the relevant packages (clang-format
, llvm
). Currently we use
- clang-format
6.0
in the Debian sid image on the Jenkins build server, - clang-format
7.0
in the Travis configuration file , and - clang-format
7.0
in the Cirrus macOS build jobs
.
On macOS you can install clang-format
using Homebrew either directly:
brew install clang-format
or by installing the whole LLVM infrastructure:
brew install llvm
. Please note, that both of these commands will install current versions of clang-format
that might format code a little bit differently than Clang-Format 6.0
in certain edge cases. If you want you can also install Clang-Format 7.0
using LLVM 7.0
:
brew install llvm@7
.
In Debian the package for Clang-Format 6.0
is called clang-format-6.0
:
apt-get install clang-format-6.0
.
For the basic use cases you can use clang-format
directly. To do that, just call the tool using the option -i
and specify the name of the files you want to reformat. For example, if you want to reformat the file src/bindings/cpp/include/kdb.hpp
you can use the following command:
# On some systems such as Debian the `cmake-format` executable also contains
# the version number. For those systems, please replace `clang-format`,
# with `clang-format-6.0` or `clang-format-7` in the command below.
clang-format -i src/bindings/cpp/include/kdb.hpp
. While this works fine, if you want to format only a small number of file, formatting multiple files can be quite tedious. For that purpose you can use the script reformat-source
that reformats all C and C++ code in Elektra’s code base
scripts/reformat-source # This script will probably take some seconds to execute
.
If you work on Elektra’s code base regularly you might want to integrate the formatting step directly in your development setup. ClangFormat’s homepage includes a list of integrations for various tools that should help you to do that. Even if this webpage does not list any integrations for your favorite editor or IDE, you can usually add support for external tools such as clang-format
to advanced editors or IDEs pretty easily.
While TextMate supports clang-format
for the current file directly via the keyboard shortcut ctrl+⇧+H, the editor does not automatically reformat the file on save. To do that
- open the bundle editor (“Bundles” → “Edit Bundles”),
- navigate to the “Reformat Code” item of the C bundle (“C” → “Menu Actions” → “Reformat Code”),
- insert
callback.document.will-save
into the field “Semantic Class”, and - change the menu option for the field “Save” to “Nothing”
. After that change TextMate will reformat C and C++ code with clang-format
every time you save a file.
- Everything as in C if not noted otherwise.
- Do not use goto at all, use RAII instead.
- Do not use raw pointers, use smart pointers instead.
- C++-Files have extension
.cpp
, Header files.hpp
. - Do not use
static
, but anonymous namespaces. - Write everything within namespaces and do not prefix names.
- Oriented towards more safe and modern usage.
Example: src/bindings/cpp/include/kdb.hpp
We use a similar style for CMake as we do for other code:
- The length of a functions should not exceed 100 lines.
- The length of a file should not exceed 1000 lines.
- A line should not be longer than 140 characters.
- Use tabs for indentation.
- One tab equals 8 spaces.
- Declare variables as late as possible, preferable within blocks.
- Add a space character before round parenthesis (
(
). - Use lower case for command names (e.g.
set
instead ofSET
)
We use cmake-format
to reformat code according to the guidelines given above. Since
cmake-format
currently does not support tabs, we use the standard command unexpand
to fix this issue. For example, to reformat the
file CMakeLists.txt
in the root folder of the repository we use the following command:
# This command uses `sponge`, which is part of the [moreutils](https://joeyh.name/code/moreutils/) package.
cmake-format CMakeLists.txt | unexpand | sponge CMakeLists.txt
.
Since cmake-format
is written in Python you usually install it via Python’s package manager pip
:
# Install cmake format `0.4.5` with support for YAML config files
pip install cmake-format[yaml]==0.4.5
. Please make sure, that you install the correct version (0.4.5
) of cmake format:
cmake-format --version
#> 0.4.5
, since otherwise the formatted code might look quite different.
We also use the moreutils in our CMake formatting script, which you can install on macOS using Homebrew:
brew install moreutils
and on Debian using apt-get
:
apt-get install moreutils
.
If you want to reformat the whole codebase you can use the script reformat-cmake
:
scripts/reformat-cmake # Running this script for the whole code base takes some time.
. To reformat specific files add a list of file paths after the command:
# The command below reformats the file `cmake/CMakeLists.txt`.
scripts/reformat-cmake cmake/CMakeLists.txt
.
If you work on CMake code quite often you probably want to integrate cmake format into your development workflow. The homepage of cmake format list some integration options.
While TextMate does not support cmake format directly, you can quickly create a command that applies cmake-format
every time you save a CMake file yourself. The steps below show one option to do that.
-
Open the “Bundle Editor”: Press ^ + ⌥ + ⌘ + B
-
Create a new command:
- Press ⌘ + N
- Select “Command”
- Press the button “Create”
-
Configure your new command
-
Use “Reformat Document” or a similar text as “Name”
-
Enter
source.cmake
in the field “Scope Selector” -
Use ^ + ⇧ + H as “Key Equivalent”
-
Copy the text
callback.document.will-save
into the field “Semantic Class” -
Select “Document” as “Input”
-
Select “Replace Document” in the dropdown menu for the option “Output”
-
Select “Line Interpolation” in the menu “Caret Placement”
-
Copy the following code into the text field:
#!/bin/bash set -o pipefail if ! "${TM_CMAKE_FORMAT:-cmake-format}" - | ${TM_CMAKE_FORMAT_FILTER:-tee}; then . "$TM_SUPPORT_PATH/lib/bash_init.sh" exit_show_tool_tip fi
-
Save your new command: ⌘ + S
-
Store the value
unexpand
in the variableTM_CMAKE_FORMAT_FILTER
. To do that save the text
TM_CMAKE_FORMAT_FILTER = "unexpand"
in a file called
.tm_properties
in the root of Elektra’s repository. -
Please follow Google Java Style Guide for Java and Groovy (used by Jenkins) files.
Most notably use:
- 2 spaces for indentation
- Variable and function names in lowerCamelCase
- K & R style brackets
- File Ending is
.md
or integrated within Doxygen comments - Only use
#
characters at the left side of headers/titles - Use fences for code/examples
- Prefer fences which indicate the used language for better syntax highlighting
- Fences with sh are for the shell recorder syntax
README.md
and tutorials should be written exclusively with shell recorder syntax so that we know that the code in the tutorial produces output as expected- Please use title-case for headings in the general documentation.
- For man pages please use only capital letters for subheadings and only small letters for the main header. We use this header style to match the look and feel of man pages for Unix tools such as
ls
ormkdir
.
We use prettier
to format the documentation according to the guidelines given above.
Under certain exceptional circumstances you might want to prevent prettier
from formatting certain parts of a Markdown file. To do
that you can
- enclose the Markdown code in
<!-- prettier-ignore-start -->
and<!-- prettier-ignore-end -->
tags, or - use
<!-- prettier-ignore -->
to disable formatting till the end of a file
.
On macOS you can install prettier
using Homebrew:
brew install prettier
.
To install prettier
using Node’s package manager npm you can use the command below
npm install --global prettier@1.17.1
.
You can format all Markdown files in the repository using the script reformat-markdown
:
scripts/reformat-markdown
. To format only some files, please specify a list of filenames after the command:
scripts/reformat-markdown doc/CODING.md # Reformat this file
.
The homepage of Prettier lists various options to integrate the tool into your workflow.
To reformat a Markdown document in TextMate every time you save it, please follow the steps listed below.
-
Open the “Bundle Editor”: Press ^ + ⌥ + ⌘ + B
-
Create a new command:
- Press ⌘ + N
- Select “Command”
- Press the button “Create”
-
Configure your new command
-
Use “Reformat Document” or a similar text as “Name”
-
Enter
text.html.markdown
in the field “Scope Selector” -
Use ^ + ⇧ + H as “Key Equivalent”
-
Copy the text
callback.document.will-save
into the field “Semantic Class” -
Select “Document” as “Input”
-
Select “Replace Input” in the dropdown menu for the option “Output”
-
Select “Line Interpolation” in the menu “Caret Placement”
-
Copy the following code into the text field:
#!/bin/bash if ! "${TM_PRETTIER:-prettier}" --stdin --stdin-filepath "${TM_FILEPATH}" then . "$TM_SUPPORT_PATH/lib/bash_init.sh" exit_show_tool_tip fi
-
Save your new command: ⌘ + S
-
- Please only use POSIX functionality.
We use shfmt
to format Shell files in the repository.
You can install shfmt
on macOS using Homebrew:
brew install shfmt
.
shfmt’s GitHub release page offers binaries for various operating systems. For example, to install the binary for the current user on Linux you can use the following command:
mkdir -p "$HOME/bin" && cd "$HOME/bin" && \
curl -L "https://github.com/mvdan/sh/releases/download/v2.6.4/shfmt_v2.6.4_linux_amd64" -o shfmt && \
chmod u+x shfmt
. Please note that you have to make sure, that your PATH
includes $HOME/bin
, if you use the command above:
export PATH=$PATH:"$HOME/bin"
.
We provide the script reformat-shfmt
that formats the whole codebase with shfmt
:
scripts/reformat-shfmt
. You can also reformat specific files by listing filenames after the script:
scripts/reformat-shfmt scripts/reformat-shfmt # Reformat the source of `reformat-shfmt`
.
The GitHub project page of shfmt
offers some options to integrate the tool into your development workflow here.
The steps below show you how to create a TextMate command that formats a documents with shfmt
every time you save it.
-
Open the “Bundle Editor”: Press ^ + ⌥ + ⌘ + B
-
Create a new command:
- Press ⌘ + N
- Select “Command”
- Press the button “Create”
-
Configure your new command
-
Use “Reformat Document” or a similar text as “Name”
-
Enter
source.shell
in the field “Scope Selector” -
Use ^ + ⇧ + H as “Key Equivalent”
-
Copy the text
callback.document.will-save
into the field “Semantic Class” -
Select “Document” as “Input”
-
Select “Replace Input” in the dropdown menu for the option “Output”
-
Select “Line Interpolation” in the menu “Caret Placement”
-
Copy the following code into the text field:
#!/bin/bash if ! "${TM_SHFMT_FORMAT:-shfmt}" -s -sr; then . "$TM_SUPPORT_PATH/lib/bash_init.sh" exit_show_tool_tip fi
-
Save your new command: ⌘ + S
-
doxygen
is used to document the API and to build the html and pdf output.
We also support the import of Markdown pages. Doxygen 1.8.8 or later
is required for this feature (Anyways you can find the
API Doc online).
Links between Markdown files will be converted with the
Markdown Link Converter.
Markdown pages are used in the pdf, therefore watch which characters you use and
provide a proper encoding!
- use
@
to start Doxygen tags - Do not duplicate information available in git in Doxygen comments.
- Use
@copydoc
,@copybrief
and@copydetails
intensively (except for file headers).
Files should start with:
/**
* @file
*
* @brief <short statement about the content of the file>
*
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*/
Note:
@
file
has no parameters.@
brief
should contain a short statement about the content of the file and is needed so that your file gets listed at https://doc.libelektra.org/api/latest/html/files.html
The duplication of the filename, author and date is not needed, because this information is tracked using git and doc/AUTHORS.md already.