Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions easybuild/easyblocks/s/systemd_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
##
# Copyright 2021-2025 Vrije Universiteit Brussel
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# https://github.com/easybuilders/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for installing a wrapper module file for systemd

@author: Mikael Öhman (Chalmers University of Technology)
"""
import os
import re

from easybuild.framework.easyblock import EasyBlock
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.filetools import mkdir, symlink
from easybuild.tools.run import run_shell_cmd
from easybuild.tools.systemtools import get_shared_lib_ext


def get_sys_lib_dirs():
res = run_shell_cmd('gcc -print-search-dirs', hidden=True, in_dry_run=True)
match = re.search(r"^libraries:\s*=(.*)$", res.output, re.MULTILINE)
if match:
return [p for p in match.group(1).split(":") if p]
return []


def get_sys_include_dirs():
cmd = "LC_ALL=C gcc -E -Wp,-v -xc /dev/null"
res = run_shell_cmd(cmd, hidden=True, in_dry_run=True)
sys_include_dirs = []
for match in re.finditer(r'^\s(/[^\0\n]*)+', res.output, re.MULTILINE):
sys_include_dirs.extend(match.groups())
return sys_include_dirs


def get_sys_pc_dirs():
res = run_shell_cmd('pkg-config --variable pc_path pkgconf', hidden=True, in_dry_run=True)
return res.output.strip().split(':')


class EB_systemd_wrapper(EasyBlock):
"""
Find path to installation files of systemd and udev in the host system.
"""

def __init__(self, *args, **kwargs):
"""Locate the installation files of systemd in the host system"""
super().__init__(*args, **kwargs)

shlib_ext = get_shared_lib_ext()
systemd_lib_patterns = [f'libsystemd.{shlib_ext}', f'libudev.{shlib_ext}']
systemd_include_patterns = ['systemd', 'libudev.h']
systemd_pc_patterns = ['systemd.pc', 'udev.pc']

self.systemd = dict()

# Check lib paths for systemd libraries
sys_lib_dirs = get_sys_lib_dirs()
self.log.info('Found the following lib directories in host system: %s', ', '.join(sys_lib_dirs))

self.systemd['libs'] = dict()
for systemd_lib_pattern in systemd_lib_patterns:
for sys_lib_dir in sys_lib_dirs:
file = os.path.join(sys_lib_dir, systemd_lib_pattern)
if os.path.exists(file):
self.systemd['libs'][systemd_lib_pattern] = file
break
else:
self.systemd['libs'][systemd_lib_pattern] = None

# Check system include paths for systemd headers
sys_include_dirs = get_sys_include_dirs()
self.log.info('Found the following include directories in host system: %s', ', '.join(sys_include_dirs))

self.systemd['includes'] = dict()
for systemd_include_pattern in systemd_include_patterns:
for sys_include_dir in sys_include_dirs:
file = os.path.join(sys_include_dir, systemd_include_pattern)
if os.path.exists(file):
self.systemd['includes'][systemd_include_pattern] = file
break
else:
self.systemd['includes'][systemd_include_pattern] = None

# Check pkgconfig paths
sys_pc_dirs = get_sys_pc_dirs()
self.log.info("Found the following pkgconfig directories in host system: %s", ', '.join(sys_pc_dirs))

self.systemd['pcs'] = dict()
for systemd_pc_pattern in systemd_pc_patterns:
for sys_pc_dir in sys_pc_dirs:
file = os.path.join(sys_pc_dir, systemd_pc_pattern)
if os.path.exists(file):
self.systemd['pcs'][systemd_pc_pattern] = file
break
else:
self.systemd['pcs'][systemd_pc_pattern] = None

def fetch_step(self, *args, **kwargs):
"""Nothing to fetch"""

def extract_step(self):
"""No sources to extract"""

def configure_step(self):
"""No configure step"""

def build_step(self):
"""No configure step"""

def install_step(self):
"""Symlink OS systemd installation"""
lib_dir = os.path.join(self.installdir, 'lib')
mkdir(lib_dir, parents=True)
for pattern, file in self.systemd['libs'].items():
if file is not None:
symlink(file, os.path.join(lib_dir, os.path.basename(file)))
else:
raise EasyBuildError('Could not find library: %s', pattern)

include_dir = os.path.join(self.installdir, 'include')
mkdir(include_dir, parents=True)
for pattern, file in self.systemd['includes'].items():
if file is not None:
symlink(file, os.path.join(include_dir, os.path.basename(file)))
else:
raise EasyBuildError('Could not find include: %s', pattern)

pc_dir = os.path.join(self.installdir, 'share', 'pkgconfig')
mkdir(pc_dir, parents=True)
for pattern, file in self.systemd['pcs'].items():
if file is not None:
symlink(file, os.path.join(pc_dir, os.path.basename(file)))
else:
raise EasyBuildError('Could not find pkgconfig files: %s', pattern)

def sanity_check_step(self):
"""Custom sanity check for systemd wrapper."""
shlib_ext = get_shared_lib_ext()
custom_paths = {
'files': [f'lib/libsystemd.{shlib_ext}', f'lib/libudev.{shlib_ext}', 'include/libudev.h',
'share/pkgconfig/systemd.pc', 'share/pkgconfig/udev.pc'],
'dirs': ['include/systemd'],
}
return super().sanity_check_step(custom_paths=custom_paths, custom_commands=[])