Skip to content

Commit

Permalink
Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
zacikpa committed Aug 12, 2024
1 parent ef66d41 commit b39b95c
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 63 deletions.
67 changes: 9 additions & 58 deletions python/src/libcpuid/_ffi_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,22 @@
Module for compiling the C FFI.
"""

import subprocess
import os
import sys
from cffi import FFI

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

class FFIBuildException(Exception):
"""Generic exception for errors occuring during the CFFI build."""


def find_header():
"""
Obtains libcpuid header file location via pkg-config.
"""
try:
cflags = (
subprocess.check_output(["pkg-config", "libcpuid", "--cflags-only-I"])
.decode()
.strip()
.split()
)
except subprocess.CalledProcessError as e:
if e.returncode == 127:
raise FFIBuildException(
"The pkg-config command is necessary to build python-libcpuid."
) from e
if e.returncode == 1:
raise FFIBuildException(
"The libcpuid C library (devel) was not found."
) from e
raise FFIBuildException("Error looking for the libcpuid library") from e

# Find an existing libcpuid header file
header_path = None # pylint: disable=invalid-name
for cflag in cflags:
header_candidate = os.path.join(cflag[2:], "libcpuid.h")
if os.path.isfile(header_candidate):
header_path = header_candidate
break
if header_path is None:
raise FFIBuildException("Could not find header file of the libcpuid library.")
return header_path


def preprocess_header(header_path):
"""
Preprocesses the header file (python-cffi only accepts preprocessed C definitions).
"""
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

from _ffi_build_utils import ( # pylint: disable=import-error, wrong-import-position
find_header_file,
preprocess_header,
eval_sizeofs,
)

header = find_header()

header = eval_sizeofs(preprocess_header(find_header_file()))
ffibuilder = FFI()
ffibuilder.cdef(preprocess_header(header))
ffibuilder.cdef(header)
ffibuilder.set_source_pkgconfig(
"libcpuid._libcpuid_cffi", ["libcpuid"], "#include <libcpuid.h>"
)
8 changes: 3 additions & 5 deletions python/src/libcpuid/_ffi_build_rtd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
Script for compiling the C FFI for the live documentation.
"""

import subprocess
import sys
import os
from cffi import FFI
from ._ffi_build_utils import preprocess_header, eval_sizeofs

if __name__ == "__main__":
header = sys.argv[1]
header_path = sys.argv[1]
install_dir = sys.argv[2]
library_dir = os.path.join(os.getcwd(), install_dir, "lib")
ffibuilder = FFI()
ffibuilder.cdef(
subprocess.check_output(["gcc", "-U __GNUC__", "-E", header]).decode()
)
ffibuilder.cdef(eval_sizeofs(preprocess_header(header_path)))
ffibuilder.set_source(
"python.src.libcpuid._libcpuid_cffi",
"#include <libcpuid.h>",
Expand Down
107 changes: 107 additions & 0 deletions python/src/libcpuid/_ffi_build_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""
Utility functions for building the FFI.
"""

import subprocess
import os
import re
import tempfile


class FFIBuildException(Exception):
"""Generic exception for errors occuring during the CFFI build."""


def _get_include_flags():
"""
Obtains libcpuid include flags via pkg-config.
"""
try:
cflags = (
subprocess.check_output(["pkg-config", "libcpuid", "--cflags-only-I"])
.decode()
.strip()
.split()
)
return cflags
except subprocess.CalledProcessError as e:
if e.returncode == 127:
raise FFIBuildException(
"The pkg-config command is necessary to build python-libcpuid."
) from e
if e.returncode == 1:
raise FFIBuildException(
"The libcpuid C library (devel) was not found."
) from e
raise FFIBuildException("Error looking for the libcpuid library") from e


def find_header_file():
"""
Obtains libcpuid header file location via pkg-config.
"""
header_path = None # pylint: disable=invalid-name
for cflag in _get_include_flags():
header_candidate = os.path.join(cflag[2:], "libcpuid.h")
if os.path.isfile(header_candidate):
header_path = header_candidate
break
if header_path is None:
raise FFIBuildException("Could not find header file of the libcpuid library.")
return header_path


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("%d", {sizeof});
return 0;
}}
"""


def eval_sizeofs(header):
"""
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 = os.path.join(tmp_dir, "sizeof.c")
executable_path = os.path.join(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, *_get_include_flags(), "-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

0 comments on commit b39b95c

Please sign in to comment.