# Language Bindings

## Introduction

In this section, we will explain the how to write a language binding for Elektra.

### High-level API

Writing bindings for the high-level API is described in a [different document](highlevel-bindings.md), since it is a bit
less straightforward and needs additional considerations.

## TODO

1. which parts of Elektra bindings make sense (application, plugin, tools, ...)
2. how to integrate bindings into CMake (if possible and useful)
3. which parts of the bindings can and should differ for every language. This includes:
   1. iterators
   2. conversion to native types (strings, int, ...)
   3. operator overloading (if available)
   4. other programming language integrations (streams, hash-codes, identity, ...)
   5. returned errors from kdb functions (what this issue here is about)

## CMake Integration

### Building

To add the subdirectory containing our binding to the build, we have to modify `src/bindings/CMakeLists.txt`.

```cmake
check_binding_included ("our_binding" IS_INCLUDED)
if (IS_INCLUDED)
    add_subdirectory (our_binding_directory)
endif ()
```

At first we want to make sure that the build tools and compilers we need for the binding are installed. We can use `find_program (BUILD_TOOL_EXECUTABLE build_tool)` to find our `build_tool` program. The result of the search will be stored in `BUILD_TOOL_EXECUTABLE`, so now we can use an if block to include the bindings in the build, if the program exists or exclude it, if it doesn't. To do that, we use `add_binding` which adds ours to the list of bindings that will be built. For more provided functions, [see here](../../scripts/cmake/Modules/LibAddBinding.cmake).

If, for example, our bindings only support linking against a dynamic library we can express that, by using the `BUILD_*` variables in if blocks or by passing `ONLY_SHARED` to `add_binding`. You can read more in the [compile doc](../COMPILE.md).

```cmake
if (BUILD_TOOL_EXECUTABLE)
    add_binding (our_binding ONLY_SHARED)
else ()
    exclude_binding (our_binding, "build_tool not found")
    return ()
endif ()
```

Elektra uses out-of-source builds, so we have to copy all the needed files over to the build directory. The ${CMAKE_CURRENT_SOURCE_DIR} variable refers to the source directory, while ${CMAKE_CURRENT_BINARY_DIR} refers to the build directory. The copy is as simple as

```cmake
# Inside the previous if block
file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
```

However for some files we may want to use some CMakes variables. Say we're writing a build script for our project and want to include the version number and the directory that `libelektra.so` resides in, so our build tool can find and link against it. We create our script named `build.script.in`. It looks like this

```
version = "@KDB_VERSION@"
link-search-path = "@CMAKE_BINARY_DIR@/lib"
```

Back in our CMake script, we tell CMake to replace the variables with their associated values.

```cmake
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/build.script.in" "${CMAKE_CURRENT_BINARY_DIR}/build.script" @ONLY)
```

Note how we leave off the `.in` ending on the target file.

Since we're building a foreign language project, it will most likely have its own build tool or compiler. So we have to tell CMake how to invoke it, in order to build the project. First we specify what file we expect to be generated by that command. In this example it's a `.lib` file that is generated in some target directory. We then call our build tool using the variable `BUILD_TOOL_EXECUTABLE` we created earlier with the `build` subcommand and the `--release` option. We can also specify one or multiple files that this command depends on, such that CMake can make sure they are built or generated before.
Finally, we add a custom target that depends on the `.lib` file. To built this target, CMake will invoke our custom command and build the specified file.

```cmake
add_custom_command (OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/target/release/libelektra.lib"
            COMMAND ${BUILD_TOOL_EXECUTABLE} build --release
            WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
            DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/build.script" "${CMAKE_CURRENT_BINARY_DIR}/other-dependency.file")
add_custom_target (our_binding ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/target/release/libelektra.lib")
```

We can then explicitly include the bindings using `cmake -DBINDINGS="our_binding" ..` in the build directory and follow the further steps for [compilation](../COMPILE.md).

### Testing

To invoke our tests through CMake, we have to follow similar steps as in the build. We add a test by specifying a command that runs our tests. In our case, we're calling the same program for testing as in the building step.

```cmake
add_test (NAME test_our_binding COMMAND ${BUILD_TOOL_EXECUTABLE} test WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
```

We may have to specify an additonal environment variable to tell the test command, where `libelektra.so` resides, so that the dynamic linker can find it.

```cmake
set_property (TEST test_our_binding PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib")
```

Now our bindings can be tested through `ctest` alongside all other tests.

See the [Java binding](../../src/bindings/jna/CMakeLists.txt) for examples.

## Error Handling

Since v0.9.0, Elektra has a new error code system. You might want to take a look in the [design decision](../decisions/error_codes.md)
first to understand the concept of the error codes. These codes are hierarchically structured
and are therefore perfectly suitable for inheritance if the language supports it.

Some error codes like the `Permanent Errors` are generalizations and used for developers who want to catch
all specific types of errors (e.g., it does not matter if it is a Resource or Installation Error but
the developer wants to check for both). Such errors should not be able to "instantiate" or emitted
back to Elektra as we want to force developers to take a more specific category. In case of
Java for example the `Permanent Error` is an abstract class. Which errors are instantiable or not can be seen in
the [error-categorization guideline](../dev/error-categorization.md) in the respective title saying either `abstract` or `concrete`.
Here is an example of how Java has implemented it:

```java
public abstract class PermanentException extends Exception {...}
    public class ResourceException extends PermanentException {...}
        public class MemoryAllocationException extends ResourceException {...}
    public class InstallationException extends PermanentException {...}
...
```

All error codes as well as the hierarchy itself is depicted in the [design decision](../decisions/error_codes.md).

If you have a language which does not support inheritance this way like GoLang, you can still use the
error code itself since the hierarchy is integrated in it. For example you can check if the code starts with
`C01...` to catch all `Permanent Errors`.

### Error Message

In Elektra every error has a predefined format. You can take a look at the [related design decision](../decisions/error_message_format.md)
to see how it looks like.

Every Exception/Error struct/etc. should have separate accessors to individual parts of the message.
These include:

1. Module (getModule())
2. Error Code (getErrorCode())
3. Reason (getReason())
4. Configfile (getConfigFile())
5. Mountpoint (getMountpoint())
6. Debuginformation (text looks like "At: file:line") (getDebugInformation())

In case of an error at least the following part has to be returned:

```
Sorry, module getModule() issued error getErrorCode():
getReason()
```

Please also keep the wording identical for consistency.
Take a look how the Java Binding implemented it in the
[KDBException](../../src/bindings/jna/libelektra4j/src/main/java/org/libelektra/exception/KDBException.java)
