edm¶
edm stands for EVerest dependency manager. It helps you orchestrating the dependencies between the different EVerest repositories.
Note
The EDM tool was developed at a time when the EVerest source code was organized in many different repositories. Since 2026, EVerest has essentially changed to a (quasi-)mono-repository layout. Manual installation of EDM is usually not necessary to work with recent versions of EVerest.
Dependency Manager for EVerest¶
Install and Quick Start¶
To install the edm dependency manager for EVerest you have to perform the following steps.
Please make sure you are running a sufficiently recent version of Python3 (>=3.6) and that you are able to install Python packages from source. See the python3 command below for upgrading the required packages. Refer to the Python Installing Packages documentation for indepth guidance if any problems arise. You may want to create and activate a virtual environment using venv
python3 -m venv venv
source venv/bin/activate
before executing the commands below.
python3 -m pip install --upgrade pip setuptools wheel jstyleson jsonschema
Python packages needed to run edm¶
The following Python3 packages are needed to run edm. If you install edm using this guide they will be installed automatically.
Python >= 3.6
Jinja2 >= 3.0
PyYAML >= 5.4
Installing edm¶
Now you can clone this repository and install edm:
git clone https://github.com/EVerest/EVerest.git
cd EVerest/applications/dependency_manager
python3 -m pip install . --break-system-packages
or in short
python3 -m pip install git+https://github.com/EVerest/EVerest.git@main#subdirectory=applications/dependency_manager --break-system-packages
Note
Alternatively, you can also install edm in a python virtual environment.
Make sure edm is available in your PATH after the installation. You can verify
this by running edm --version.
Next you could run
edm init --workspace ~/checkout/everest-workspace
This creates a workspace in the ~/checkout/everest-workspace
directory from the most recent release of EVerest. If you want the most recent
main you can use:
edm init main --workspace ~/checkout/everest-workspace
The workspace will have the following structure containing all current dependencies for EVerest:
everest-workspace/
├── everest-cmake
├── EVerest
├── everest-dev-environment
├── everest-framework
├── everest-sqlite
├── everest-utils
├── Josev
├── libcbv2g
├── libevse-security
├── libfsm
├── libiso15118
├── liblog
├── libnfc-nci
├── libocpp
├── libslac
├── libtimer
└── workspace-config.yaml
The workspace-config.yaml contains a copy of the config that was used to create
this workspace.
Enabling CPM_SOURCE_CACHE and setting PATH¶
The EVerest dependency manager uses
CPM
for its CMake integration. This means you can and should set the
CPM_SOURCE_CACHE environment variable. This makes sure that dependencies
that you do not manage in the workspace are not re-downloaded multiple times.
For detailed information and other useful environment variables please
refer to the CPM Documentation.
Also set the PATH variable:
export CPM_SOURCE_CACHE=$HOME/.cache/CPM
export PATH=$PATH:/home/$(whoami)/.local/bin
Building EVerest¶
Make sure you have installed ev-cli first. You can now use the following commands to build the repository EVerest:
cd ~/checkout/everest-workspace/EVerest
mkdir build
cd build
cmake ..
make -j$(nproc) install
Setting up and updating a workspace¶
For letting edm do the work of setting up an initial EVerest workspace, do this:
edm init --workspace ~/checkout/everest-workspace
If you are currently in the everest-workspace directory the following command has the same effect:
edm init
For using a dedicated release version, you can do this:
edm init 2023.7.0
In this example, version 2023.7.0 is pulled from the server. This will only work if your previous code is not in a “dirty” state.
Using the edm CMake module and dependencies.yaml¶
To use edm from CMake you have to add the following line to the top-level CMakeLists.txt file in the respective source repository:
find_package(EDM REQUIRED)
To define dependencies you can now add a dependencies.yaml file to your source repository. It should look like this:
---
sigslot:
git: https://github.com/palacaze/sigslot
git_tag: v1.2.3
cmake_condition: "EVEREST_DEPENDENCY_ENABLED_SIGSLOT"
options:
- "SIGSLOT_COMPILE_EXAMPLES OFF"
- "SIGSLOT_COMPILE_TESTS OFF"
pugixml:
git: https://github.com/zeux/pugixml
git_tag: v1.15
cmake_condition: "EVEREST_DEPENDENCY_ENABLED_PUGIXML"
If you want to conditionally include some dependencies, e.g. for testing, you can do this in the following way:
catch2:
git: https://github.com/catchorg/Catch2.git
git_tag: v3.4.0
cmake_condition: "BUILD_TESTING"
Here cmake_condition can be any string that CMake can use in an if() block.
Please be aware that any variables you use here must be defined before a call to
evc_setup_edm() is made in your CMakeLists.txt
Additionally you can set the EVEREST_MODIFY_DEPENDENCIES environment variable
to a file containing modifications to the projects dependencies.yaml files when
running cmake:
EVEREST_MODIFY_DEPENDENCIES=../dependencies_modified.yaml cmake -S . -B build
The dependencies_modified.yaml file can contain something along these lines:
nlohmann_json:
git: null # this makes edm look for nlohmann_json via find_package
libfmt:
rename: fmt # if find_package needs a different dependency name you can rename it
git: null
catch2:
git_tag: v1.2.3 # select a different git tag for a build
Selective package builds¶
EVerest is built and installed in five packages. EVEREST_PACKAGES selects the ones
built from the tree; packages that are needed but not listed are taken from an installed
prefix with find_package().
Package |
Contents |
|---|---|
|
log, timer, util, sqlite, evse_security, tls |
|
libiso15118 and the cbv2g EXI codec libraries |
|
libocpp |
|
the framework libraries, code generation and the interface definitions; this is what out-of-tree module projects build against |
|
the in-tree modules, applications and configurations (no CMake package) |
The default builds all five. Only libocpp and what it needs, for example:
cmake -S . -B build -DEVEREST_PACKAGES="base;ocpp"
From an external project’s dependencies.yaml:
everest-core:
git: https://github.com/EVerest/EVerest.git
git_tag: 2026.10.0
options:
- "EVEREST_PACKAGES base;ocpp"
With DISABLE_EDM=ON the packages can also be built and installed one after the other into
the same prefix:
cmake -S . -B b1 -DDISABLE_EDM=ON -DEVEREST_PACKAGES=base -DCMAKE_INSTALL_PREFIX=/opt/everest
cmake -S . -B b2 -DDISABLE_EDM=ON -DEVEREST_PACKAGES="iso15118;ocpp" \
-DCMAKE_PREFIX_PATH=/opt/everest -DCMAKE_INSTALL_PREFIX=/opt/everest
cmake -S . -B b3 -DDISABLE_EDM=ON -DEVEREST_PACKAGES=core \
-DCMAKE_PREFIX_PATH=/opt/everest -DCMAKE_INSTALL_PREFIX=/opt/everest
cmake -S . -B b4 -DDISABLE_EDM=ON -DEVEREST_PACKAGES=runtime \
-DCMAKE_PREFIX_PATH=/opt/everest -DCMAKE_INSTALL_PREFIX=/opt/everest
With EDM, cmake --install installs what is needed to run EVerest (the manager, modules,
libraries and configurations) but no CMake packages and no development files such as the generated
headers. To build against EVerest with find_package(), install it from a build with
DISABLE_EDM=ON; EDM projects add EVerest as a dependency instead.
Tests are built with BUILD_TESTING=ON for every package built from the tree.
EVEREST_TEST_PACKAGES (default: all five) narrows that to selected packages, for example
-DBUILD_TESTING=ON -DEVEREST_TEST_PACKAGES="core;runtime".
Framework thread pool scaling policy¶
The framework message handler uses a dynamically scaling thread pool for operation messages such as variable updates, commands, errors, GetConfig and ModuleReady messages. Its scaling policy can be selected at CMake configure time.
CMake options:
Option |
Default |
Description |
|---|---|---|
|
|
Selects the policy. Supported values are |
|
|
Minimum worker count of the pool. These workers are always running. |
|
|
Maximum worker count of the pool, independent of the CPU core count. The pool grows so that a handler blocked waiting for another message still lets that message be handled; such threads do not run in parallel, so the core count is not the right bound. Must not be below the minimum. It must exceed the number of handlers that may block on each other at the same time; a maximum equal to the minimum disables growth, so any such handler waits forever. |
|
|
Maximum queued task wait time, in milliseconds, before the |
|
|
Back-off, in milliseconds, before the |
|
|
Queue size threshold at which the |
|
(empty) |
Header to include when the policy is |
|
(empty) |
Fully-qualified C++ policy type to use when the policy is |
|
(empty) |
Additional include directory for the custom policy header. |
Two conditions the pool cannot resolve itself are logged by the module as warnings: a handler thread that cannot be started (the pool keeps retrying; after five seconds of failures the module exits like a crash), and a message that has waited more than a second with every handler thread busy, which means the maximum is too low for the handlers that wait for each other.
The built-in policies are:
Policy |
Behavior |
|---|---|
|
Default. Adds a worker whenever a submitted task would otherwise wait for a busy worker, so below the maximum no task is ever left queued behind blocked workers. No supervisor thread; the pool size follows the number of outstanding handlers and surplus workers retire after the idle timeout. |
|
Adds workers when queued work has waited longer than the framework latency threshold, checked by a supervisor thread that sleeps while the pool is idle. |
|
Adds workers only when the queue depth significantly exceeds the current worker count. |
|
Adds workers once the queue size reaches the configured
|
Example: selecting the latency policy for a full EVerest build
cmake -S . -B build \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_POLICY=latency \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_LATENCY_THRESHOLD_MS=50 \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_LATENCY_TICK_MS=5
cmake --build build
Example: selecting fixed-size scaling
cmake -S . -B build \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_POLICY=fixed_size \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_FIXED_SIZE_THRESHOLD=3
cmake --build build
Example: using a custom policy
cmake -S . -B build \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_POLICY=custom \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_POLICY_CUSTOM_HEADER=my_policy.hpp \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_POLICY_CUSTOM_TYPE=my_project::MyPolicy \
-DEVEREST_FRAMEWORK_THREAD_POOL_SCALING_POLICY_CUSTOM_INCLUDE_DIR=/path/to/include
cmake --build build
A custom policy must provide the same interface as the built-in policies:
struct MyPolicy {
static constexpr std::optional<std::chrono::milliseconds> supervisor_tick =
std::nullopt;
static bool should_grow(
std::size_t current_workers,
std::size_t queue_size,
std::optional<std::chrono::steady_clock::time_point> oldest_arrival);
};
should_grow is evaluated on a submission below the thread limit only if the
submitted task may wait, that is, if the queue is now longer than the number of
workers waiting at it or about to; a task that an idle worker takes at once
never grows the pool, so queue_size is at least 1 whenever the policy is
asked. A policy with a supervisor_tick additionally gets a supervisor thread
that re-evaluates should_grow for tasks that queue behind busy workers,
backing off one tick after each evaluation. It sleeps while the queue is empty
and, at the thread limit, until a worker retires. If the policy also provides
static std::chrono::steady_clock::time_point next_check(
std::chrono::steady_clock::time_point oldest_arrival);
the supervisor sleeps until that time instead of waking every tick.
next_check must return a time no later than the first time should_grow
can become true for a queue whose oldest task arrived at oldest_arrival
(an earlier time is harmless: the supervisor then retries every tick), and it
must be non-decreasing in oldest_arrival. LatencyScaling provides it.
Create a workspace config from an existing directory tree¶
Suppose you already have a directory tree that you want to save into a config file. You can do this with the following command:
edm --create-config custom-config.yaml
This is a short form of:
edm --create-config custom-config.yaml --include-remotes https://github.com/EVerest/*
and only includes repositories from the EVerest namespace. You can add as many remotes to this list as you want.
For example, if you only want to include certain repositories you can use the following command.
edm --create-config custom-config.yaml --include-remotes https://github.com/EVerest/everest* https://github.com/EVerest/ext-switchev-iso15118.git
If you want to include all repositories, including external dependencies, in the config you can use the following command:
edm --create-config custom-config.yaml --external-in-config
Git information at a glance¶
You can get a list of all git repositories in the current directory and their state using the following command:
edm --git-info --git-fetch
If you want to know the state of all repositories in a workspace you can use the following command:
edm --workspace ~/checkout/everest-workspace --git-info --git-fetch
This creates output that is similar to the following example:
[edm]: Git info for "~/checkout/everest-workspace":
[edm]: Using git-fetch to update remote information. This might take a few seconds.
[edm]: "everest-dev-environment" @ branch: main [remote: origin/main] [behind 6] [clean]
[edm]: "everest-framework" @ branch: main [remote: origin/main] [dirty]
[edm]: "everest-deploy-devkit" @ branch: main [remote: origin/main] [clean]
[edm]: "libtimer" @ branch: main [remote: origin/main] [dirty]
[edm]: 2/4 repositories are dirty.
Further information can be seen as shell output by calling edm with parameter -h or –help.
Authors: Kai-Uwe Hermann, Stefan Wahren, Andreas Heinrich, Manuel Ziegler