#!/usr/bin/env python3
import os.path
import shlex
import sys
try:
from setuptools import setup, Extension
except ImportError:
from distutils.core import setup, Extension
try:
from distutils import sysconfig
except ImportError:
import sysconfig
# C++ is only supported on Python 3.6 and newer
TEST_CXX = (sys.version_info >= (3, 6))
SRC_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), '..'))
# Windows uses MSVC compiler
MSVC = (os.name == "nt")
COMMON_FLAGS = [
'-I' + SRC_DIR,
]
if not MSVC:
# C compiler flags for GCC and clang
COMMON_FLAGS.extend((
# Treat warnings as error
'-Werror',
# Enable all warnings
'-Wall', '-Wextra',
# Extra warnings
'-Wconversion',
# Formatting checks
'-Wformat',
'-Wformat-nonliteral',
'-Wformat-security',
))
CFLAGS = COMMON_FLAGS
else:
# C compiler flags for MSVC
COMMON_FLAGS.extend((
# Treat all compiler warnings as compiler errors
'/WX',
))
# Python 3.11 and older emits C4100 "unreferenced parameter" warnings
# on Py_UNUSED() parameters. Py_UNUSED() was modified in Python 3.12
# to support MSVC.
if sys.version_info >= (3, 12):
COMMON_FLAGS.extend((
# Display warnings level 1 to 4
'/W4',
))
CFLAGS = list(COMMON_FLAGS)
CXXFLAGS = list(COMMON_FLAGS)
if not MSVC:
C_VERSIONS = ('c99', 'c11')
else:
# MSVC doesn't support /std:c99 flag
C_VERSIONS = ('c11',)
if not MSVC:
CXX_VERSIONS = [
('test_pythoncapi_compat_cpp03ext', ['-std=c++03']),
('test_pythoncapi_compat_cpp11ext', ['-std=c++11']),
('test_pythoncapi_compat_cpp14ext', ['-std=c++14']),
('test_pythoncapi_compat_cpp17ext', ['-std=c++17']),
('test_pythoncapi_compat_cpp20ext', ['-std=c++20']),
]
else:
# MSVC doesn't support /std:c++11
CXX_VERSIONS = [
('test_pythoncapi_compat_cppext', None),
('test_pythoncapi_compat_cpp14ext', ['/std:c++14', '/Zc:__cplusplus']),
]
def main():
# gh-105776: When "gcc -std=11" is used as the C++ compiler, -std=c11
# option emits a C++ compiler warning. Remove "-std11" option from the
# CC command.
cmd = (sysconfig.get_config_var('CC') or '')
if cmd:
cmd = shlex.split(cmd)
cmd = [arg for arg in cmd if not arg.startswith('-std=')]
if (sys.version_info >= (3, 8)):
cmd = shlex.join(cmd)
elif (sys.version_info >= (3, 3)):
cmd = ' '.join(shlex.quote(arg) for arg in cmd)
else:
# Python 2.7
import pipes
cmd = ' '.join(pipes.quote(arg) for arg in cmd)
# CC env var overrides sysconfig CC variable in setuptools
os.environ['CC'] = cmd
# C extension
extensions = []
for std in C_VERSIONS:
if not MSVC:
cflags = CFLAGS + ['-std=%s' % std]
else:
cflags = CFLAGS + ['/std:%s' % std]
c_ext = Extension(
'test_pythoncapi_compat_cext_%s' % std,
sources=['test_pythoncapi_compat_cext.c'],
extra_compile_args=cflags)
extensions.append(c_ext)
if TEST_CXX:
# C++ extension
for name, std_flags in CXX_VERSIONS:
flags = list(CXXFLAGS)
if std_flags is not None:
flags.extend(std_flags)
cpp_ext = Extension(
name,
sources=['test_pythoncapi_compat_cppext.cpp'],
extra_compile_args=flags,
language='c++')
extensions.append(cpp_ext)
setup(name="test_pythoncapi_compat",
ext_modules=extensions)
if __name__ == "__main__":
main()