Skip to content

Commit

Permalink
Refactor binding build
Browse files Browse the repository at this point in the history
  • Loading branch information
zacikpa committed Aug 29, 2024
1 parent 3950650 commit 304a9f4
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 156 deletions.
9 changes: 3 additions & 6 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@ build:
pre_install:
- libtoolize
- autoreconf --install
- mkdir ./install
- ./configure --prefix=`pwd`/install
- ldconfig -p
- ./configure
- make
- make install
- pip install cffi
- python ./python/src/libcpuid/_ffi_build_rtd.py ./libcpuid/libcpuid.h ./install

- python python/src/libcpuid/ffi_build.py
sphinx:
configuration: python/docs/conf.py

Expand Down
114 changes: 100 additions & 14 deletions python/src/libcpuid/_ffi_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,109 @@
"""

import os
import sys
import subprocess
import tempfile
import re
from pathlib import Path
from cffi import FFI

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from _ffi_build_utils import ( # pylint: disable=import-error, wrong-import-position
get_include_flags,
find_header_file,
preprocess_header,
eval_sizeofs,
class FFIBuildException(Exception):
"""Generic exception for errors occuring during the CFFI build."""


def preprocess_header(header_path):
"""
Preprocesses the header file (python-cffi only accepts preprocessed C definitions)
at the given path and returns it as a string.
"""
try:
return subprocess.check_output(
["gcc", "-U __GNUC__", "-E", header_path]
).decode()
except subprocess.CalledProcessError as e:
if e.returncode == 127:
raise FFIBuildException(
"The gcc compiler is necessary to build python-libcpuid."
) from e
raise FFIBuildException(
f"Error preprocessing the libcpuid header file: {e.stderr}"
) from e


def _get_sizeof_eval_source(sizeof):
return f"""
#include <libcpuid.h>
#include <stdio.h>
int main() {{
printf("%ld", {sizeof});
return 0;
}}
"""


def eval_sizeofs(header, cflags):
"""
Evaluates each sizeof found in the given C header and replaces all
occurences of the sizeof with its computed value.
"""
sizeofs = set(re.findall(r"sizeof\([^\)]*\)", header))
tmp_dir = tempfile.mkdtemp()
c_program_path = Path(tmp_dir, "sizeof.c")
executable_path = Path(tmp_dir, "sizeof")

for sizeof in sizeofs:
with open(c_program_path, "w", encoding="UTF-8") as c_program_file:
c_program_file.write(_get_sizeof_eval_source(sizeof))
subprocess.check_call(["gcc", c_program_path, *cflags, "-o", executable_path])
size = subprocess.check_output([executable_path]).decode()
header = header.replace(sizeof, size)

os.remove(c_program_path)
os.remove(executable_path)
os.rmdir(tmp_dir)
return header


LIBCPUID_DIR = str(Path(*(Path(os.path.abspath(__file__)).parts[:-4])))
LIBCPUID_INCLUDE_DIR = str(Path(LIBCPUID_DIR, "libcpuid"))
LIBCPUID_LIBRARY_DIR = str(Path(LIBCPUID_DIR, "libcpuid", ".libs"))
LIBCPUID_MAIN_HEADER_FILENAME = "libcpuid.h"
LIBCPUID_MAIN_HEADER_PATH = str(
Path(LIBCPUID_INCLUDE_DIR, LIBCPUID_MAIN_HEADER_FILENAME)
)
LIBCPUID_LIBRARY_NAME = "cpuid"

PREPROCESSED_HEADER = preprocess_header(LIBCPUID_MAIN_HEADER_PATH)
eval_sizeof_cflags = [
f"-I{LIBCPUID_INCLUDE_DIR}",
f"-L{LIBCPUID_LIBRARY_DIR}",
f"-l{LIBCPUID_LIBRARY_NAME}",
]
if __name__ == "__main__":
eval_sizeof_cflags.append(f"-Wl,-rpath={LIBCPUID_LIBRARY_DIR}")

NO_SIZEOF_HEADER = eval_sizeofs(PREPROCESSED_HEADER, eval_sizeof_cflags)

include_flags = get_include_flags()
preprocessed_header = preprocess_header(find_header_file(include_flags))
no_sizeof_header = eval_sizeofs(preprocessed_header, include_flags)
ffibuilder = FFI()
ffibuilder.cdef(no_sizeof_header)
ffibuilder.set_source_pkgconfig(
"libcpuid._libcpuid_cffi", ["libcpuid"], "#include <libcpuid.h>"
)
ffibuilder.cdef(NO_SIZEOF_HEADER)


if __name__ == "__main__":
ffibuilder.set_source(
"libcpuid._libcpuid_cffi",
f"#include <{LIBCPUID_MAIN_HEADER_FILENAME}>",
libraries=[LIBCPUID_LIBRARY_NAME],
include_dirs=[LIBCPUID_INCLUDE_DIR],
library_dirs=[LIBCPUID_LIBRARY_DIR],
extra_link_args=[f"-Wl,-rpath={LIBCPUID_LIBRARY_DIR}"],
)
else:
ffibuilder.set_source(
"libcpuid._libcpuid_cffi",
f"#include <{LIBCPUID_MAIN_HEADER_FILENAME}>",
libraries=[LIBCPUID_LIBRARY_NAME],
include_dirs=[LIBCPUID_INCLUDE_DIR],
library_dirs=[LIBCPUID_LIBRARY_DIR],
)
31 changes: 0 additions & 31 deletions python/src/libcpuid/_ffi_build_rtd.py

This file was deleted.

105 changes: 0 additions & 105 deletions python/src/libcpuid/_ffi_build_utils.py

This file was deleted.

0 comments on commit 304a9f4

Please sign in to comment.