feat: basically finish pkgconfig generation

This commit is contained in:
2026-08-03 14:22:56 +08:00
parent 02526784a2
commit 8c0775d784
11 changed files with 246 additions and 36 deletions
@@ -65,9 +65,9 @@ class CMakeProperties:
"bad target name component in CMake. consider manually specifying it"
)
if self.artifact_dll == "":
raise ValueError("bad artifact dll file name")
raise ValueError("bad artifact dll file name in CMake")
if self.artifact_lib == "":
raise ValueError("bad artifact lib file name")
raise ValueError("bad artifact lib file name in CMake")
if self.version.prerelease is not None or self.version.build is not None:
raise ValueError(
"unsupported semantic version components (prerelease or build) in CMake"
@@ -1,21 +1,90 @@
"""Renderer for pkg-config package files.
Generates the ``<pkg>.pc`` file consumed by the ``pkg-config`` tool so that the
distributed Rust FFI library can be located and linked by downstream build
systems. The data fed to the template is carried by
:class:`PkgConfigProperties`, and :class:`PkgConfigRender` performs the
rendering on top of :class:`renders.common.BaseRender`.
"""
from dataclasses import dataclass
from typing import Any
from . import common
from semver import Version
@dataclass(frozen=True)
class PkgConfigProperties:
pass
"""Inputs required to render the pkg-config ``.pc`` file.
A frozen dataclass validated in :meth:`__post_init__`; once constructed, an
instance is guaranteed to hold only values that are safe to substitute into
the ``.pc`` template.
"""
name: str
"""Human-readable name of the library or package.
This is purely descriptive; the ``pkg-config`` tool itself resolves
packages by the file name of the ``.pc`` file, not by this field.
"""
description: str
"""Brief description of the package."""
artifact: str
"""Name of the build artifact.
``pkg-config`` uses this value to determine which dynamic library to link.
For an artifact named ``XXX``, it looks for ``libXXX.so`` on Linux and
``XXX.lib`` or ``libXXX.dll.a`` on Windows.
"""
version: Version
"""Version of the library. Must not carry a prerelease or build component."""
def __post_init__(self) -> None:
"""Validate the fields after construction.
:raises ValueError: if the name or description is blank, or the
version carries a prerelease or build component (unsupported in
pkg-config).
"""
if self.name == "":
raise ValueError("unexpected blank name of pkg-config")
if self.description == "":
raise ValueError("unexpected blank description of pkg-config")
if self.version.prerelease is not None or self.version.build is not None:
raise ValueError(
"unsupported semantic version components (prerelease or build) in pkg-config"
)
class PkgConfigRender:
"""Renderer that turns :class:`PkgConfigProperties` into a ``.pc`` file.
Wraps a :class:`renders.common.BaseRender` and exposes :meth:`render` to
emit the package configuration file.
"""
__render: common.BaseRender
__properties: PkgConfigProperties
def __init__(self, properties: PkgConfigProperties) -> None:
"""Create the renderer with its Jinja2 backend and bound properties.
:param properties: Validated inputs reused by :meth:`render`.
"""
self.__render = common.BaseRender()
self.__properties = properties
def render(self) -> str:
payload: dict[str, Any] = {}
"""Render the ``<pkg>.pc`` file.
:returns: The rendered ``.pc`` content as a string.
"""
payload: dict[str, Any] = {
"name": self.__properties.name,
"description": self.__properties.description,
"artifact": self.__properties.artifact,
}
return self.__render.render("XXX.pc.jinja", payload)