External Dependency Management in Karabo¶
The Karabo Framework depends on a large number of third party packages. The karabo C++ library dependencies are managed using the conan open source package manager. This automatically provides things like Python, boost, AMQP, etc.
Because building these dependencies has become a time consuming and sensitive process, they are now being managed by an automated system. Together with the CI (continuous integration) features of GitLab, the dependencies are automatically built and cached whenever one or more of those dependencies changes.
Installing the Dependencies into a Clean Source Tree¶
After cloning the framework from git, or doing a clean rebuild, the external
dependencies should first be installed. This is handled automatically by the
auto_build_all.sh
script.
The already-built dependencies will be downloaded from the public conan repository when available. If pre-built binaries are not available, then the source code will be download and compiled locally according to the script in the conanfile.py of the dependency package.
Mechanism for Determining Correct Dependencies to Install¶
The conan package manager enables building the karabo framework with a deterministic build environment. All of the build options, compiler and host system settings are used to compute a package ID for the dependency. The package ID is a unique identifier that conan uses to determine package compatibility with a host system and other dependencies.
If you are interested in a more detailed explanation of how this works, you can read more about it at blog.conan.io:
Adding/Removing/Updating a Dependency¶
To add, remove, or update a dependency in Karabo, create a new feature branch and make your changes. Build and install the dependency (or dependencies) that you are currently concerned with.
Building all of Karabo is explained in Build from sources. But if you only want to know how to build a single extern. Here is the command:
cd extern
./build.sh <platform-directory> externPackageName
<platform-directory>
is usually something like GNU-Linux-x86
.
It’s the directory where all built externs are staged before
being copied into a karabo build directory.
Note that dependencies which include executable binaries (programs or shared
libraries) will need to have their RUNPATH
metadata set so that runtime
linking works appropriately. This is handled by the extern/relocate_deps.sh
script, and should be made there when adding/removing/updating dependencies.
In order to test the built result, you can create a feature branch with name
format of deps-mr-<package>
and push it to the framework repository. The
CI runner will pick up this branch and create the a new dependency package at
http://exflctrl01.desy.de/karabo/karaboDevelopmentDeps
Once the dependency package is created, you can try verify it by clean building the framework locally using this package:
./auto_build_all.sh Clean-All
./auto_build_all.sh Debug --pyDevelop
This will build the framework using the updated dependency packages created from your feature branch. Once finished, you can try to use the framework to verify if the new/updated pakcage plays nicely with the framework.
Once you are reasonably sure that everything works, open a merge request for the branch. After the merge request is approved and merged into the master branch, add a tag to the merge commit:
git log # to find the commit hash for the merge commit
git tag deps-<name> <commit hash> # See below for naming convention
git push origin --tags
This will cause an automated build to begin and rebuild the dependencies. If this build fails, then shame on you. You should be more careful when working with the dependencies. You’ll need to fix the problem with a new merge request and tag. It’s not the end of the world, of course, but it might cause grief for anyone who performs a clean rebuild before you’ve fixed the master branch.
The Naming Convention for Dependency tags¶
All dependency tags need to begin with “deps-“. This is hardcoded into the build infrastructure. The rest is only defined by convention.
The basic format is: deps-<action>-<package>
<action>
is one of the following: add, update, remove
<package>
is the principle package which is being changed. The fact that
multiple packages are perhaps being modified is not terribly important. It is
also a good idea to add a little bit of version information after the package
name for disambiguation. As the number of “deps-” tags grows, some packages will
likely appear more than once (eg. deps-update-boostNNN or deps-update-numpy)
Current collection of dependencies¶
Karabo is currently shipped with the a tree dependencies that enables development directly from the distributed platform:
library | version | license | Karabo depends | KaraboGUI depends |
---|---|---|---|---|
aioredis | 1.3.1 | MIT | yes | no |
aiormq | 3.3.1 | Apache-2.0 | yes | no |
AMQP-CPP | 4.3.12 | Apache-2.0 | yes | no |
atomicwrites | 1.4.0 | MIT | yes | yes |
attrs | 20.3.0 | MIT | yes | yes |
backcall | 0.2.0 | BSD-3 | yes | yes |
backports-abc | 0.4 | PSFL | no | no |
backports.ssl-match | 3.5.0.1 | PSFL | no | no |
boost | 1.82.0 | Boost License | yes | no |
bzip2 | 1.0.8 | BSD | yes | yes |
certifi | 2018.4.16 | MPL2.0 | no | no |
chardet | 3.0.4 | LGPL | yes | no |
colorama | 0.4.4 | BSD | yes | yes |
conan | 1.57.0 | MIT | yes | no |
coverage | 4.5.1 | Apache-2.0 | no | no |
cppunit | 1.14.0 | LGPL | no | no |
cycler | 0.10.0 | BSD-3 | no | yes |
cython | 0.29.24 | Apache-2.0 | no | no |
daemontools-encore | 1.10-karabo3 | MIT | no | no |
dateutil | 2.8.1 | apache/BSD | no | yes |
decorator | 4.4.2 | BSDv2 | yes | yes |
dill | 0.2.5 | BSD-3 | yes | yes |
eulexistdb | 0.21.1 | Apache-2.0 | no | no |
eulxml | 1.1.3 | Apache-2.0 | no | no |
eXistDB | 2.2 | LGPL | no | no |
flake8 | 3.8.4 | MIT | no | no |
flaky | 3.7.0 | Apache-2.0 | no | no |
freetype | 2.5.2 | FTL/GPLv2 | no | yes |
gmock | 1.7.0 | BSD | no | no |
httplib2 | 0.9.1 | MIT | yes | yes |
idna | 2.7 | PSFL | yes | no |
importlib-metadata | 3.3.0 | apache | yes | no |
iniconfig [pyt] | 1.1.1 | MIT | yes | yes |
ipcluster-tools | 0.0.11 | BSD-3 | yes | no |
ipykernel | 4.3.1 | BSD-3-Clause | yes | yes |
ipyparallel | 5.1.1 | BSD-3-Clause | yes | no |
ipython | 7.19.0 | BSD-3-Clause | yes | yes |
ipython-genutils | 0.2.0 | BSD-3-Clause | yes | yes |
jedi | 0.17.2 | MIT | yes | yes |
jpeg | 9a | Ack | yes | yes |
Jinja2 | 2.7.2 | BSD | no | no |
jsonschema | 2.3.0 | MIT | yes | yes |
jupyter-client | 6.1.6 | BSD | yes | no |
jupyter-core | 4.6.3 | BSD | yes | no |
lapack | 3.6.0 | BSD | yes | no |
libev-git | 4.33dev | BSD/GPLv2 | yes | no |
libpng | 1.6.8 | libpng (MIT like) | yes | yes |
libxml2 | 2.9.10 | MIT | yes | yes |
libxslt | 1.1.34 | MIT | yes | yes |
libzmq | 4.2.5 | LGPLv3 | yes | yes |
log4cpp | 1.1.3 | LGPLv2.1 | yes | no |
lxml | 3.6.4 | BSD | yes | no |
MarkupSafe | 0.18 | BSD | no | no |
matplotlib | 2.1.1 | PSFL | no | no |
more-itertools | 8.6.0 | MIT | yes | no |
msgpack | 0.5.6 | APL2 | no | no |
msgpack-numpy | 0.4.3 | BSD | no | no |
multidict | 1.5.0 | Apache-2.0 | yes | no |
nbformat | 4.1.0 | BSD | yes | yes |
nose | 1.3.0 | LGPL | no | no |
notebook | 4.2.2 | BSD | yes | yes |
nss | ? | MPL | yes | no |
numpy | 1.22.4 | BSD | yes | yes |
openmq | 5.0.1 | EPL/GPLv2 | yes | yes |
packaging | 20.8 | apache/BSD | yes | no |
pamqp | 2.3.0 | BSD-3-Clause | yes | no |
parse | 1.6.3 | BSD | no | no |
parso | 0.7.1 | MIT | no | no |
patchelf | 0.8 | GPLv3 | no | no |
pexpect | 4.8.0 | ISC license (BSD like) | yes | yes |
pg8000 | 1.21.2 | BSD | yes | no |
pickleshare | 0.7.5 | MIT | yes | yes |
Pillow | 10.0.0 | PIL (MIT like) | no | yes |
Pint | 0.17 | BSD-3-Clause | yes | yes |
pip | 7.1 | MIT | yes | yes |
pkgconfig | 1.2.2 | MIT | yes | yes |
pluggy | 0.13.1 | MIT | yes | no |
ply | 3.11 | BSD | yes | no |
prompt-toolkit | 3.0.10 | BSD-3-Clause | yes | yes |
ptyprocess | 0.7.0 | ISCL | yes | no |
psutil | 4.3.1 | BSD | no | no |
pugixml | 1.2 | MIT | yes | no |
py | 1.10.0 | MIT | yes | no |
pybind11 | 2.6.1 | MIT | yes | no |
pycodestyle | 2.6.0 | MIT | no | no |
pyelftools | 0.24 | Public Domain | no | no |
pyflakes | 2.2.0 | MIT | no | no |
Pygments | 2.7.4 | BSD | yes | yes |
pyparsing | 2.4.7 | MIT | no | yes |
pyqt | 5.9.2 | GPLv3/Commercial | no | yes |
pyqtgraph | 0.11.0 | MIT | no | yes |
pytest | 6.2.1 | MIT | no | no |
pytest-runner | 2.11.1 | MIT | no | no |
pytz | 2020.5 | MIT | no | yes |
PyYAML | 3.12 | MIT | no | no |
pyzmq | 22.3.0 | LGPL+BSD | yes | yes |
qtconsole | 4.2.1 | BSD | yes | yes |
qt | 5.9.7 | GPLv3/Commercial | no | yes |
qtpy | 1.9 | MIT | no | yes |
redisclient | 1.0.2dev | MIT | yes | no |
requests | 2.19.1 | APLv2 | no | no |
scikit-learn | 0.14.1 | BSD | no | no |
scipy | 1.7.3 | BSD | no | no |
setuptools | 39.1.0 | MIT | yes | yes |
setuptools-scm | 1.15.6 | MIT | yes | yes |
simplegeneric | 0.8.1 | ZPLv2.1 (BSD plus trademark) | yes | yes |
six | 1.15.0 | MIT | yes | yes |
tiff | 4.4.1 | libtiff license (BSD like) | no | no |
tornado | 6.0.4 | APLv2 | yes | no |
toml | 0.10.2 | MIT | yes | no |
traitlets | 5.0.5 | BSD | yes | yes |
traits | 4.6.0 | BSD | yes | yes |
tzlocal | 1.1.1 | MIT | yes | yes |
urllib3 | 1.23 | MIT | yes | no |
wcwidth | 0.2.5 | MIT | yes | yes |
wheel | 0.24.0 | MIT | yes | yes |
yarl | 1.6.3 | Apache-2.0 | yes | no |
zipp | 1.0.0 | MIT | yes | no |
In order to disentangle the dependencies’ structure, it is convenient to split the structure as follow: The graph below represents the karabo libraries (please note that the graph below represents the goal of a refactoring that is in progress):
Here are the dependencies of the karabo-cpp
python module:
Here are the dependencies of the karabo.common
python module:
Here are the dependencies of the karabo.native
python sub-module:
Here are the dependencies of the karabo.project_db
python sub-module:
Here are the dependencies of the karabo.middlelayer
python sub-module, for the sake of clarity,
the ipython
, numpy
and jupyter_client
modules are not expanded in their dependencies:
Here are the dependencies of the karabogui
python sub-module, for the sake of clarity,
the ipython
, numpy
and jupyter_client
modules are not expanded in their dependencies:
“karabogui” -> “karabo.common” “karabogui” -> “karabo.native” “karabogui” -> “pyqt” “pyqt” -> “qt5” “karabogui” -> “qtconsole” “karabogui” -> “matplotlib” “karabogui” -> “ipython” “matplotlib” -> “numpy” “matplotlib” -> “six” “matplotlib” -> “python-dateutil” “matplotlib” -> “pytz” “matplotlib” -> “cycler” “matplotlib” -> “pyparsing” “qtconsole” -> “jupyter_client” “qtconsole” -> “traitlets” “qtconsole” -> “pygments” “qtconsole” -> “jupyter_core” “qtconsole” -> “ipykernel” “karabogui” -> “pyzmq” “karabogui” -> “pyqtgraph” “pyqtgraph” -> “numpy ” “cycler” -> “six” “karabogui” -> “requests”
Here are the dependencies of the ipython
, numpy
and jupyter_client
:
Here are the dependencies that are not needed by framework, but might be needed during development:
Remarks on miniconda3 Windows CI¶
Our release process for Windows is now done on a shared Windows 10 runner. This runner was configured manually by means of installing miniconda3, plink and cwrsync on our home folder (C:Usersxkarabo) and are all added on xkarabo path. Currently the GitLab CI logs in as a system user, so we have to manually add these environment variables each time the job is executed (see .gitlab-ci.yaml). Also, cwrsync’s ssh tool needs the HOME variable set to be %USERPROFILE%.
Also, for the Windows CI as we don’t have an easy-to-use tool like sshpass we have created an RSA key and added it to our linux server (exflctrl01). The key on Windows is located on %USERPROFILE%.sshwin-cwrsync.
Code used for building the recipe¶
Our building process has three steps:
The first step for the release is to create (solve) the environment based on our environment.devenv.file. This environment is used to generate our recipe’s meta.yaml based on a template called meta_base.yaml using a very well known code generator called cogapp. After this file is generated, we can delegate the build process to conda-build. When successful, we will have our package inside <conda_directory>/conda-bld/<platform>/.
After the karabogui package is built, we also need to populate our mirror channel based on the package’s dependencies. For this we developed a script called create_mirror_channels.py which decides which packages to download using the conda-mirror tool. The advantage to have a mirror is that the deployment is much faster and we have the safety of having our internal channel.
Possible Issues¶
Differently from our Linux CI, the Windows CI is not started fresh at each run, so it’s possible that some issues arise during the release process. We try to mitigate most of them by some cleaning process on ci/miniconda/build.cmd.
Some errors that were met were:
Not a conda environment: <environment path>¶
The environment got corrupted somehow. Fix it by removing it manually:
conda remove -n <environment_name> –all –yes
or
conda env remove -n <environment_name> –all
Package conflicts on test phase¶
Usually it’s an error like the following
Found conflicts! Looking for incompatible packages. This can take several minutes. Press CTRL-C to abort. failed
Package libtiff conflicts for: pyqtgraph==0.11.0=py_1 -> pyqt -> qt=5.6 -> libtiff=4.0 karabogui==2.7.0a5=py36_0 -> pillow==6.2.1=py36h5fcff3f_1 -> libtiff[version=’>=4.1.0,<5.0a0’] karabogui==2.7.0a5=py36_0 -> libtiff==4.1.0=h21b02b4_1 libtiff==4.1.0=h21b02b4_1 Package pygments conflicts for: karabogui==2.7.0a5=py36_0 -> pygments[version=‘2.4.2|2.5.0’,build=py_0] karabogui==2.7.0a5=py36_0 -> ipython==7.2.0=py36h39e3cac_1000 -> pygments qtconsole==4.6.0=py_0 -> pygments ipykernel==5.1.3=py36h5ca1d4c_0 -> ipython[version=’>=5.0’] -> pygments ipython==7.2.0=py36h39e3cac_1000 -> jedi[version=’>=0.10’]]
Either this means:
- An actual conflicting of dependencies
- One of the packages are not available on the desired platform
- A dirty conda build cache
On our scenario, as we always solve the environment before the build (in order to decide which packages we use), the first two options are not viable. By cleaning the conda build cache it usually works:
conda build purge-all
If it doesn’t, try cleaning everything in conda:
conda clean –all –yes
If it doesn’t, it might be a bug generated by an update on the conda package. Try downgrading it:
conda install -n base conda=<lower_version>
Remarks on Licensing¶
For the Karabo Framework, excluding the GUI, we plan to use a Mozilla Public License version 2.0 , which foresees as weak form of copy-left.
for more information: https://www.mozilla.org/en-US/MPL/2.0/FAQ/
The GUI would be released initially as GPLv3, which is required by the PyQt5 library the GUI uses. A future more permissive license is possible, but would require factoring out the GPLv3 dependency, which we do not deem necessary as of now.
A note on the General Public License¶
Licensing the framework with stricter copy-left licenses like the General Public License (GPL) is not possible due to conflicts between the software license of some of the dependencies used. The OpenMQ C library is dual licensed with the Eclipse Public License version 2.0 (EPL-2.0) and the GPL version 2.0 (GPL-2.0). GPL-2.0 is in conflict with the Apache Software License version 2 (Apache-2.0) that is used by multiple libraries and this precludes the use of GPL-2.0 and the strict definition of the GPL included in OpenMQ precludes the use of other GPL versions.
For more information regarding the EPL-2.0 dual licensing: https://www.eclipse.org/legal/epl-2.0/faq.php
License for the Karabo GUI¶
The Karabo GUI depends from a library that has a strong copyleft license. The PyQT5 graphical user interface library is licensed under GPLv3 or Commercial. This limits the licenses usable for the Karabo GUI to GPLv3.
The Karabo GUI is however currently using an abstraction layer that will allow the use of a less strictly licensed library and if the need arises or we wish to, the Karabo GUI code could be relicensed using a more permissive license.
A note regarding Karabo Plugins (Devices)¶
The Mozilla Public License (MPL) extends to all files containing code licensed under the MPL. As a consequence of this, all code using plugins can be licensed and released with a license of the choice of the authors as long as the distribution of such code and binaries complies with the license of Karabo and its dependencies.
A Note on Copyright¶
The European XFEL GmbH is the copyright owner of the code. All contributions must include this copyright notice.