File build.py of Package failed_python-rencode
#!/usr/bin/env python3
"""
Minimal build helper for rencode that sanitizes compiler flags which
are invalid on non-x86 architectures (like riscv64). The upstream
build script sometimes picks up -march=native and x86-specific
options (-msse, -msse2, -mfma, -mfpmath=sse) from the environment
(CFLAGS) or from automatic feature detection. On RISC-V these cause
gcc to fail:
gcc: error: ‘-march=native’: ISA string must begin with rv32 or rv64
gcc: error: unrecognized command-line option ‘-msse’
We perform the smallest possible change: filter out the offending
flags from the environment and from extension extra_compile_args
before invoking setuptools to build the extension in-place.
"""
from __future__ import annotations
import os
import platform
import shlex
import sys
from pathlib import Path
# Flags that are known to be invalid on RISC-V / non-x86 targets.
# We treat '-msse*' and similar as prefixes.
_OFFENDING_PREFIXES = (
"-msse",
"-mfma",
"-mfpmath",
)
_OFFENDING_EXACT = (
"-march=native",
)
def _sanitize_flag_tokens(tokens):
"""Return a new list of tokens with offending flags removed."""
out = []
for t in tokens:
if t in _OFFENDING_EXACT:
continue
skip = False
for p in _OFFENDING_PREFIXES:
if t.startswith(p):
skip = True
break
if skip:
continue
out.append(t)
return out
def sanitize_env_flags():
"""
Sanitize CFLAGS and similar environment variables in-place so that
distutils/setuptools won't pass invalid flags to the compiler.
"""
# List of env vars that commonly influence compilation.
for var in ("CFLAGS", "CPPFLAGS", "CXXFLAGS", "LDFLAGS"):
val = os.environ.get(var)
if not val:
continue
try:
# split honoring quoted parts
tokens = shlex.split(val)
except Exception:
# Fallback: simple whitespace split
tokens = val.split()
new_tokens = _sanitize_flag_tokens(tokens)
if new_tokens != tokens:
os.environ[var] = " ".join(new_tokens)
def build():
# If we are on a RISC-V target (or similar non-x86), aggressively
# sanitize flags. Also sanitize unconditionally to avoid picking up
# -msse etc. from the build environment when cross-building.
machine = platform.machine() or ""
# sanitize always; it's safe to drop x86-only flags on x86 as they are
# often redundant when optimization is requested in other ways.
sanitize_env_flags()
# Now invoke setuptools to build the extension in-place.
from setuptools import setup, Extension
try:
from Cython.Build import cythonize
have_cython = True
except Exception:
have_cython = False
src_dir = Path(__file__).parent.resolve() / "rencode"
pyx = src_dir / "_rencode.pyx"
c_file = src_dir / "_rencode.c"
if have_cython and pyx.exists():
sources = [str(pyx)]
cythonize_kwargs = dict(language_level=3)
elif c_file.exists():
sources = [str(c_file)]
cythonize_kwargs = None
else:
# If neither .pyx nor .c exists, fallback to a very small metadata-only
# setup so the build system can continue (this is unlikely).
sources = []
cythonize_kwargs = None
ext_modules = []
if sources:
ext = Extension(
"rencode._rencode",
sources=sources,
extra_compile_args=[], # do not add architecture-specific flags here
)
if cythonize_kwargs is not None:
ext_modules = cythonize([ext], **cythonize_kwargs)
else:
ext_modules = [ext]
# Minimal metadata — keep it small to avoid altering packaging behaviour.
setup(
name="rencode",
version="1.0.8",
description="rencode encoder/decoder (sanitized build)",
packages=["rencode"],
ext_modules=ext_modules,
script_args=["build_ext", "--inplace"],
)
if __name__ == "__main__":
build()