modemd: package Python scripts for compiled deployment

Python scripts without a .py extension are never cached as bytecode by
CPython — every invocation re-parses the source.  Packaging as a wheel
pre-compiles all modules to .pyc and installs thin import stubs as the
executables, matching the approach used by bin/show and statd.

Restructure the modemd Python scripts into a proper Python package
(src/modemd/modemd/): each script becomes a module with a main() entry
point.  pyproject.toml declares 11 entry points; the Buildroot
MODEMD_BUILD_PYTHON hook builds a wheel via PEP 517, then pyinstaller.py
installs compiled stubs to /usr/libexec/modemd/ and pre-compiled .pyc
modules to site-packages.

/sbin/modemd is now a symlink to the compiled stub.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-06-07 20:51:01 +02:00
parent f78f161dbe
commit 1168c6c8e2
13 changed files with 111 additions and 45 deletions
+23 -12
View File
@@ -10,13 +10,34 @@ MODEMD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/modemd
MODEMD_LICENSE = BSD-3-Clause
MODEMD_LICENSE_FILES = LICENSE
MODEMD_REDISTRIBUTE = NO
MODEMD_DEPENDENCIES = modem-manager jansson python3
MODEMD_DEPENDENCIES = modem-manager jansson python3 \
host-python3 host-python-pypa-build host-python-installer \
host-python-poetry-core
define MODEMD_BUILD_CMDS
$(TARGET_CC) $(TARGET_CFLAGS) $(TARGET_LDFLAGS) \
$(MODEMD_DIR)/modem-command.c -o $(MODEMD_DIR)/modem-command -ljansson
endef
define MODEMD_BUILD_PYTHON
cd $(MODEMD_SITE) && \
$(PKG_PYTHON_PEP517_ENV) $(HOST_DIR)/bin/python3 $(PKG_PYTHON_PEP517_BUILD_CMD) -o $(@D)/dist
mkdir -p $(TARGET_DIR)/usr/libexec/modemd
rm -f $(TARGET_DIR)/usr/libexec/modemd/modemd \
$(TARGET_DIR)/usr/libexec/modemd/modem-* \
$(TARGET_DIR)/usr/libexec/modemd/sim-setup
cd $(@D) && \
$(HOST_DIR)/bin/python3 $(TOPDIR)/support/scripts/pyinstaller.py \
dist/*.whl \
--interpreter=/usr/bin/python3 \
--script-kind=posix \
--purelib=$(TARGET_DIR)/usr/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages \
--headers=$(TARGET_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \
--scripts=$(TARGET_DIR)/usr/libexec/modemd \
--data=$(TARGET_DIR)
endef
MODEMD_POST_INSTALL_TARGET_HOOKS += MODEMD_BUILD_PYTHON
define MODEMD_INSTALL_TARGET_CMDS
mkdir -p $(TARGET_DIR)/usr/libexec/modemd
mkdir -p $(TARGET_DIR)/lib/udev/rules.d
@@ -27,18 +48,8 @@ define MODEMD_INSTALL_TARGET_CMDS
install -m 644 $(MODEMD_DIR)/qmi-wwan-ids.rules $(TARGET_DIR)/lib/udev/rules.d/91-qmi-wwan-ids.rules
install -m 644 $(MODEMD_DIR)/77-mm-dell-port-types.rules $(TARGET_DIR)/etc/udev/rules.d/77-mm-dell-port-types.rules
install -D -m 644 $(MODEMD_DIR)/modemd.modules-load $(TARGET_DIR)/etc/modules-load.d/modemd.conf
install -m 755 $(MODEMD_DIR)/modem-udev $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modemd $(TARGET_DIR)/sbin/modemd
install -m 755 $(MODEMD_DIR)/modem-command $(TARGET_DIR)/sbin/modem-command
install -m 755 $(MODEMD_DIR)/modem-info $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modem-rpc $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modem-sms $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modem-scan-networks $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modem-update-firmware $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modem-ussd $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modem-carrier $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/modem-power $(TARGET_DIR)/usr/libexec/modemd/
install -m 755 $(MODEMD_DIR)/sim-setup $(TARGET_DIR)/usr/libexec/modemd/
ln -sf /usr/libexec/modemd/modemd $(TARGET_DIR)/sbin/modemd
endef
$(eval $(generic-package))
+6 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import threading
import subprocess
import argparse
@@ -1625,7 +1623,8 @@ def sighandler(signum, frame):
fatal("Exiting on signal %d" % signum)
if __name__ == "__main__":
def main():
global debug
syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_DAEMON)
if os.geteuid() != 0:
@@ -1692,3 +1691,7 @@ if __name__ == "__main__":
[th.join() for th in threads]
fatal("Abnormal exit")
if __name__ == "__main__":
main()
+5 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import subprocess
import argparse
import json
@@ -272,7 +270,7 @@ def runlist(index, manf, model):
sys.exit(0)
if __name__ == "__main__":
def main():
parser = argparse.ArgumentParser(prog='modem-carrier')
parser.add_argument("-i", "--index", default=0, help="Modem index")
parser.add_argument("-m", "--manf", default=0, help="Modem manufacturer")
@@ -312,3 +310,7 @@ if __name__ == "__main__":
runget(index, manf, model)
sys.exit(0)
if __name__ == "__main__":
main()
+5 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import subprocess
import argparse
import syslog
@@ -531,7 +529,7 @@ def print_all():
print(data)
if __name__ == "__main__":
def main():
parser = argparse.ArgumentParser(prog='modem-info')
parser.add_argument("-i", "--index", default=0, help="Modem index")
args = parser.parse_args()
@@ -545,3 +543,7 @@ if __name__ == "__main__":
print_modem(int(args.index))
else:
print_all()
if __name__ == "__main__":
main()
+5 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import subprocess
import argparse
import json
@@ -65,7 +63,7 @@ def reset(index, info):
return True
if __name__ == "__main__":
def main():
parser = argparse.ArgumentParser(prog='modem-power')
parser.add_argument("-i", "--index", default=0, help="Modem index")
args = parser.parse_args()
@@ -84,3 +82,7 @@ if __name__ == "__main__":
fatal("Unable to power-cycle modem")
sys.exit(0)
if __name__ == "__main__":
main()
+5 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import argparse
import json
import sys
@@ -21,7 +19,7 @@ def sendrpc(index, rpc):
os.unlink(path)
if __name__ == "__main__":
def main():
parser = argparse.ArgumentParser(prog='modem-rpc')
parser.add_argument("-i", "--index", default=0, help="Modem index")
parser.add_argument("-r", "--rpc", default=0, help="RPC command")
@@ -48,3 +46,7 @@ if __name__ == "__main__":
}
sendrpc(index, rpc)
if __name__ == "__main__":
main()
+6 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import argparse
import subprocess
import json
@@ -65,7 +63,8 @@ def scan(mpath):
return True
if __name__ == "__main__":
def main():
global index
parser = argparse.ArgumentParser(prog='modem-scan-networks')
parser.add_argument("-i", "--index", default=0, help="Modem index")
args = parser.parse_args()
@@ -77,3 +76,7 @@ if __name__ == "__main__":
print("Scanning networks on modem%d, please stand by ..." % index)
if not scan(m["path"]):
print("Operation failed.", file=sys.stderr)
if __name__ == "__main__":
main()
+5 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import subprocess
import json
import fcntl
@@ -254,7 +252,7 @@ def read_setup():
return setup
if __name__ == "__main__":
def main():
setup = read_setup()
if setup is None:
sys.exit(0)
@@ -263,3 +261,7 @@ if __name__ == "__main__":
fatal("Unable set up SIMs")
sys.exit(0)
if __name__ == "__main__":
main()
+5 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
from datetime import datetime
import argparse
import locale
@@ -106,7 +104,7 @@ def listlocale():
return ", ".join(locales)
if __name__ == "__main__":
def main():
parser = argparse.ArgumentParser(prog='modem-sms')
parser.add_argument("-d", action="store_true", help="Delete SMS")
parser.add_argument("-s", action="store_true", help="Send SMS")
@@ -140,3 +138,7 @@ if __name__ == "__main__":
delete(index)
else:
show(index)
if __name__ == "__main__":
main()
+6 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import shutil
import errno
import time
@@ -283,7 +281,8 @@ def apply():
return True
if __name__ == "__main__":
def main():
global debug
with open("/proc/cmdline", 'r') as fd:
cmdline = fd.read()
if "debug" in cmdline:
@@ -314,3 +313,7 @@ if __name__ == "__main__":
dbg("ended")
sys.exit(rc)
if __name__ == "__main__":
main()
+6 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import subprocess
import argparse
import urllib.parse
@@ -347,7 +345,8 @@ def download(url, checksum):
return True
if __name__ == "__main__":
def main():
global debug, index
syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_DAEMON)
parser = argparse.ArgumentParser(prog='modem-firmware-update')
@@ -387,3 +386,7 @@ if __name__ == "__main__":
fatal("Firmware update failed")
rmdir(tempdir)
if __name__ == "__main__":
main()
+6 -3
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python3
import argparse
import subprocess
import sys
@@ -49,7 +47,8 @@ def ussd(index, code):
return True
if __name__ == "__main__":
def main():
global verbose
parser = argparse.ArgumentParser(prog='modem-ussd')
parser.add_argument("-i", "--index", default=0, help="Modem index")
parser.add_argument("-c", "--code", default=None, help="USSD codec")
@@ -70,3 +69,7 @@ if __name__ == "__main__":
sys.exit(0)
sys.exit(1)
if __name__ == "__main__":
main()
+28
View File
@@ -0,0 +1,28 @@
[tool.poetry]
name = "modemd"
version = "1.0"
description = "Infix modem daemon and utilities"
license = "BSD-3-Clause"
packages = [
{ include = "modemd" }
]
authors = [
"KernelKit developers"
]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
modemd = "modemd:main"
modem-info = "modemd.info:main"
modem-carrier = "modemd.carrier:main"
modem-rpc = "modemd.rpc:main"
modem-sms = "modemd.sms:main"
modem-scan-networks = "modemd.scan_networks:main"
modem-update-firmware = "modemd.update_firmware:main"
modem-ussd = "modemd.ussd:main"
modem-power = "modemd.power:main"
modem-udev = "modemd.udev:main"
sim-setup = "modemd.sim_setup:main"