Metadata-Version: 2.4
Name: liblinks_and_nodes
Version: 2.8.1
Summary: Python packaging wrapper for the links_and_nodes C/C++ library and Python bindings
Author-email: Florian Schmidt <florian.schmidt@dlr.de>
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://gitlab.com/links_and_nodes/links_and_nodes
Project-URL: Repository, https://gitlab.com/links_and_nodes/links_and_nodes
Classifier: Development Status :: 5 - Production/Stable
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: COPYING
Requires-Dist: numpy
Requires-Dist: libstring_util<1.4.0,>=1.3.0
Requires-Dist: cmeel-boost<1.91,>=1.90
Provides-Extra: manager
Requires-Dist: PyGObject<4.0,>=3.5; extra == "manager"
Dynamic: license-file

[![Build Status](https://rmc-jenkins.robotic.dlr.de/jenkins/job/common/job/links_and_nodes/job/master/33/badge/icon)](https://rmc-jenkins.robotic.dlr.de/jenkins/job/common/job/links_and_nodes/job/master/33/)

# links_and_nodes
links_and_nodes GPLv3 release.
library is released under the terms of LGPLv3.

all tested with debian buster & stretch

## how to build

if you are at DLR-RMC, please read [README.RMC.md](README.RMC) for RMC-specific build instructions.

otherwise first check whether there is a premade build script for your distribution:

    ls scripts/build_*

if so, try running it with the option `-h` first.

it will leave an `ln_env.sh` script in your `INSTALL_PREFIX`-folder which you can source in your shell-init
scripts to "activate" that LN-install. as the help-output shows, the `INSTALL_PREFIX` is given as argument
to the `scripts/build_*` script.

example:
```
 $ sudo scripts/build_ubuntu22.04.sh /usr/local
```
then add to your `~/.bashrc`:
```
source /usr/local/ln_env.sh
```

see the following instructions if you cannot use any of these build scripts.

### dependencies
to build the library, daemon and python binding:

- compiler requirement:

  LN requires a C compiler with C99/GNU99 support. The build system compiles
  the C library as GNU99. On Linux systems with futex support, libln's shm v3
  synchronization also relies on GCC/Clang-compatible atomic intrinsics. The
  distro build scripts install GCC/G++, which satisfies this requirement on all
  supported Linux platforms.

- common for debian and ubuntu systems:

```shell
 $ sudo apt-get update
 $ sudo apt-get install scons libtool autoconf libprocps-dev coreutils dash file g++ git gzip libacl1 libncurses5-dev libselinux1 libtomcrypt-dev libtommath-dev locales make patch sed tar wget
```

- additions for debian stretch, buster
```shell
 $ sudo apt-get install python-sphinx libboost-python-dev python-numpy iproute2
```
- additions for debian bullseye
```shell
 $ sudo apt-get install python3-sphinx python3-dev libboost-python-dev python3-yaml python3-numpy
```

- additions for ubuntu 18.04
add the "universe" repository to your /etc/apt/sources.list, it might look like this: `deb http://de.archive.ubuntu.com/ubuntu bionic main universe`
```shell
 $ sudo apt-get update
 $ sudo apt-get install sphinx-doc sphinx-common python-dev libboost-python-dev
```
- additions for ubuntu 20.04
add the "universe" repository to your /etc/apt/sources.list, it might look like this: `deb http://de.archive.ubuntu.com/ubuntu focal main universe`
```shell
 $ sudo apt-get update
 $ sudo apt-get install sphinx-doc sphinx-common python-dev libboost-python1.67-dev 
```

- arch linux (2020-03-25)
```shell
 $ sudo pacman -S scons libtool autoconf procps-ng coreutils dash file gcc git gzip acl boost ncurses libtomcrypt libtommath make patch sed tar wget python2-numpy python-sphinx
```

### libstring_util

you can get libstring_util from
  https://gitlab.com/links_and_nodes/libstring_util
or
  https://rmc-github.robotic.dlr.de/common/libstring_util

```shell
 $ cd /path/to
 $ git clone .../libstring_util.git
 $ cd libstring_util
 $ autoreconf -if
 $ mkdir build; cd build
 $ ../configure --prefix=/usr/local
 $ make
 $ sudo make install
```

### links_and_nodes

```shell
 $ cd /path/to
 $ git clone --recursive .../links_and_nodes.git
 $ cd links_and_nodes
 $ scons --prefix=/usr/local
 $ sudo scons --prefix=/usr/local install
```
this will build the library, python binding and the daemon and install them
to /usr/local.
you can specify a different target with the option `--prefix=/home/user/my_local`.
but be careful to always specify an absolute path as prefix!

depending on which install-prefix and python version you chose, you might want to add this to
your e.g. ~/.bashrc file:
```shell
export LN_PREFIX=/usr/local
export PATH=$LN_PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$LN_PREFIX/lib:$LD_LIBRARY_PATH
# for debian and related:
export PYTHONPATH=$LN_PREFIX/lib/python3/dist-packages:$PYTHONPATH
# for suse, ARCH:
export PYTHONPATH=$LN_PREFIX/lib/python3/site-packages:$PYTHONPATH
# cmake cfg for libln
export CMAKE_PREFIX_PATH=$LN_PREFIX/lib/cmake/:$CMAKE_PREFIX_PATH
```
(not needed if you install to --prefix=/usr)

## optional runtime dependencies
to start the ln_manager gui:
- debian, ubuntu18.04, ubuntu20.04
```shell
 $ sudo apt-get install openssh-client python-gi gir1.2-gtk-3.0 gir1.2-vte-2.91
```
- arch
```shell
 $ sudo pacman -S openssh python2-gobject gtk3 vte3
```

to start notebooks (pygtksvnb):
- newer debian's
```shell
 $ sudo apt-get install gir1.2-gtksource-4 python-matplotlib
```
- debian stretch
```shell
 $ sudo apt-get install gir1.2-gtksource-3 python-matplotlib
```
- ubuntu18.04
```shell
 $ sudo apt-get install gir1.2-gtksource-3.0 python-matplotlib
```
- ubuntu20.04
```shell
 $ sudo apt-get install gir1.2-gtksource-4
 $ wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O get-pip.py
 $ python get-pip.py --force-reinstall
 $ python -m pip install pyparsing matplotlib
```
- arch
```shell
 $ sudo pacman -S gtksourceview4 python-matplotlib
```

TODO: currently no working Gtk3 OpenGL widget found for pyscopes!


## how to test your installation
to test the python binding:
```shell
 $ python -c "import links_and_nodes as ln; print 'ok'"
 ok
```

to test the ln_manager:
```shell
 $ ln_manager --help
 2015-11-05 13:50:29.73 info    Manager:           $Id: Manager.py 20622 2013-10-01 13:12:52Z schm_fl $
 
 usage: ln_manager [-h] [-i instance_name] [-p PORT] [--log-level LEVEL] -c configuration_file
        -h                  show this usage info and exit
 ...
```

to test notebooks:
```shell
 $ python -m pyutils.pygtksvnb.notebook
```


## further reading
please read the incomplete $LN_documentation/links_and_nodes.md, have a
look at those example ln-clients below examples/ and maybe
grep for things of interest in my personal test cases
libln/tests.

the official API documentation is currently here:
- C-API: libln/include/ln/ln.h
- C++-API: libln/include/ln/cppwrapper.h
- python-API: python/links_and_nodes/_ln.cpp
  (have a look at the last function BOOST_PYTHON_MODULE() in that file)
  and python/links_and_nodes/ln_wrappers.py
- ln-config-file options: python/links_and_nodes_manager/SystemConfiguration.py

## license issues
all of links and nodes but the ln-library is released with a GPLv3
license. the ln-library is released with a LGPLv3 license - by that you
can dynamically link libln.so into your non-GPL compatible binaries
(needed header files use a non-copyleft BSD license).


## Python packaging

You can install `liblinks_and_nodes` from PyPI using `pip install liblinks-and-nodes`.

The package ships a Python wrapper (`python_pkg/`) that builds the C/C++ library
via SCons during `pip install` and installs the compiled `.so`, public headers,
and bundled data into `site-packages/liblinks_and_nodes/{lib,include,share}`.


### Quick start

```bash
# Install the package (builds C/C++ library via SCons on-the-fly)
# You can pass -vv to activate verbose mode
uv pip install .

# Or install from PyPI
pip install liblinks-and-nodes

# Locate the installed library, headers and share directory
python -m liblinks_and_nodes lib
python -m liblinks_and_nodes include
python -m liblinks_and_nodes share

# Or programmatically
python -c "import liblinks_and_nodes; print(liblinks_and_nodes.list_library_files())"
```


### Manager extra

Pre-built CI wheels always include the manager and `ln_daemon`. If you are
installing from PyPI or CI artifacts, the manager is already included —
no extra flags needed.

To also build the `ln_daemon` binary and the `links_and_nodes_manager` GUI package
when installing from source:

```bash
pip install '.[manager]' -C with-manager=true
# Or with uv:
# Full package, with ln manager, ln daemon and file sync
uv pip install  ".[manager]" -vv  -C with-manager=true
```

PyGObject (gi) must be installed via your system package manager:
- Debian/Ubuntu: `apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0`
- Fedora: `dnf install python3-gobject gtk3`
- Arch: `pacman -S python-gobject gtk3`


### Testing the packaging locally

All commands below use [`uv`](https://github.com/astral-sh/uv) (install via
`curl -LsSf https://astral.sh/uv/install.sh | sh`).


#### Full manylinux wheel build (matches CI)

Requires Docker. Reads `[tool.cibuildwheel]` from `pyproject.toml`.
The CI pipeline passes `with-manager=true` through `CIBW_CONFIG_SETTINGS`,
so the resulting wheels are always "full" (include manager + ln_daemon).

```bash
# Build all Python versions (3.10–3.14), full wheels (include manager + daemon)
CIBW_CONFIG_SETTINGS="with-manager=true" \
    uvx --python 3.12 cibuildwheel --platform linux

# Or a single version
CIBW_BUILD="cp312-manylinux_x86_64" \
    CIBW_CONFIG_SETTINGS="with-manager=true" \
    uvx --python 3.12 cibuildwheel --platform linux
```

Note: you can set `CIBW_BUILD_VERBOSITY=3` for debugging

To build base-only wheels (no manager/daemon), omit `CIBW_CONFIG_SETTINGS`.

Wheels land in `wheelhouse/`.


#### Quick smoke test (no Docker)

```bash
# Build a platform-specific "full" wheel (matches CI, includes manager + daemon)
uvx --from build pyproject-build --wheel --outdir dist/ \
    --config-setting with-manager=true

# Or base-only (no manager/daemon):
# uvx --from build pyproject-build --wheel --outdir dist/

# Install into a fresh uv-managed venv
uv venv /tmp/test_venv
uv pip install --python /tmp/test_venv/bin/python dist/*.whl

# Smoke-check the installed package
/tmp/test_venv/bin/python -m liblinks_and_nodes lib
/tmp/test_venv/bin/python -m liblinks_and_nodes include
/tmp/test_venv/bin/python -c "import links_and_nodes; print('import OK')"
```


#### Test sdist round-trip

The sdist is identical regardless of whether the final build includes the
manager or not — the flag is only needed at install time.

```bash
uvx --from build pyproject-build --sdist --outdir dist/
tar xzf dist/liblinks_and_nodes-*.tar.gz -C /tmp/

# Base install (default):
uv pip install --python /tmp/test_venv/bin/python /tmp/liblinks_and_nodes-*/

# Full install (with manager + daemon):
uv pip install --python /tmp/test_venv/bin/python \
    --config-settings with-manager=true /tmp/liblinks_and_nodes-*/
```


#### Verify wheel content

```bash
unzip -l wheelhouse/*.whl | grep -E '\.so|liblinks_and_nodes|links_and_nodes/'
```


#### Upload to PyPI (wheels + sdist)

The following produces **all** artifacts (manylinux wheels for every Python
version **plus** a source distribution) in a single `dist/` directory, then
uploads them with `twine`.

##### 1. Build manylinux wheels

Requires Docker. Reads `[tool.cibuildwheel]` from `pyproject.toml`.
Wheels are "full" (include manager + daemon) to match CI output.

```bash
CIBW_CONFIG_SETTINGS="with-manager=true" \
    uvx --python 3.12 cibuildwheel --platform linux --output-dir dist/
```

##### 2. Build the source distribution

```bash
uvx --from build pyproject-build --sdist --outdir dist/
```

##### 3. Check the artifacts

```bash
ls -lh dist/
# Expect: one .whl per Python version (cp310, cp311, cp312, cp313, cp314)
#         one .tar.gz (source distribution)
```

##### 4. Upload to TestPyPI (dry run, uses a separate token)

```bash
export TWINE_USERNAME="__token__"
export TWINE_PASSWORD="pypi-<your-testpypi-token>"

uv tool run --from twine twine upload --repository testpypi dist/*
```

Visit <https://test.pypi.org/project/liblinks-and-nodes/> to verify the listing.

##### 5. Upload to production PyPI

```bash
export TWINE_USERNAME="__token__"
export TWINE_PASSWORD="pypi-<your-production-token>"

uv tool run --from twine twine upload dist/*
```

> **Token setup:** Generate API tokens at
> <https://pypi.org/manage/account/token/> (production) and
> <https://test.pypi.org/manage/account/token/> (TestPyPI).
> Never hardcode tokens — always use environment variables or a `.netrc` file.


#### CI wheel builds

The GitLab CI pipeline (`.gitlab-ci.yml`) automatically builds manylinux_2_28
wheels and an sdist when a **tag** is pushed.  Wheel jobs run in parallel
(one per Python version 3.10–3.14) inside Docker-in-Docker using
`cibuildwheel`.  The `package` stage collects all artifacts into `dist/`
for download.

To trigger a wheel build locally on the default branch, use:

```bash
# Requires Docker
CIBW_CONFIG_SETTINGS="with-manager=true" \
    uvx --python 3.12 cibuildwheel --platform linux
```

The resulting wheels are "full" (include manager + daemon) and "thin":
only `libln.so` and Python packages are
vendored.  External shared-library dependencies (`libboost_python*.so` from
`cmeel-boost`, `libstring_util.so` from `libstring_util`) are excluded from
the wheel and provided by their own PyPI wheels at install time.

For manylinux wheels with daemon support, `auditwheel` may bundle system
libraries that are not on the manylinux allowlist, such as `libprocps` and
its runtime dependency chain.  The wheel build copies the corresponding RPM
license/notice files and source-package references into
`liblinks_and_nodes/share/third_party_licenses/`.
