summaryrefslogtreecommitdiff
path: root/setuptools/tests/test_build_ext.py
blob: 3177a2cdd6bf5d82c6049e13e6611fa4fa148ec3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import os
import sys
import distutils.command.build_ext as orig
from distutils.sysconfig import get_config_var

from jaraco import path

from setuptools.command.build_ext import build_ext, get_abi3_suffix
from setuptools.dist import Distribution
from setuptools.extension import Extension

from . import environment
from .textwrap import DALS


IS_PYPY = '__pypy__' in sys.builtin_module_names


class TestBuildExt:
    def test_get_ext_filename(self):
        """
        Setuptools needs to give back the same
        result as distutils, even if the fullname
        is not in ext_map.
        """
        dist = Distribution()
        cmd = build_ext(dist)
        cmd.ext_map['foo/bar'] = ''
        res = cmd.get_ext_filename('foo')
        wanted = orig.build_ext.get_ext_filename(cmd, 'foo')
        assert res == wanted

    def test_abi3_filename(self):
        """
        Filename needs to be loadable by several versions
        of Python 3 if 'is_abi3' is truthy on Extension()
        """
        print(get_abi3_suffix())

        extension = Extension('spam.eggs', ['eggs.c'], py_limited_api=True)
        dist = Distribution(dict(ext_modules=[extension]))
        cmd = build_ext(dist)
        cmd.finalize_options()
        assert 'spam.eggs' in cmd.ext_map
        res = cmd.get_ext_filename('spam.eggs')

        if not get_abi3_suffix():
            assert res.endswith(get_config_var('EXT_SUFFIX'))
        elif sys.platform == 'win32':
            assert res.endswith('eggs.pyd')
        else:
            assert 'abi3' in res

    def test_ext_suffix_override(self):
        """
        SETUPTOOLS_EXT_SUFFIX variable always overrides
        default extension options.
        """
        dist = Distribution()
        cmd = build_ext(dist)
        cmd.ext_map['for_abi3'] = ext = Extension(
            'for_abi3',
            ['s.c'],
            # Override shouldn't affect abi3 modules
            py_limited_api=True,
        )
        # Mock value needed to pass tests
        ext._links_to_dynamic = False

        if not IS_PYPY:
            expect = cmd.get_ext_filename('for_abi3')
        else:
            # PyPy builds do not use ABI3 tag, so they will
            # also get the overridden suffix.
            expect = 'for_abi3.test-suffix'

        try:
            os.environ['SETUPTOOLS_EXT_SUFFIX'] = '.test-suffix'
            res = cmd.get_ext_filename('normal')
            assert 'normal.test-suffix' == res
            res = cmd.get_ext_filename('for_abi3')
            assert expect == res
        finally:
            del os.environ['SETUPTOOLS_EXT_SUFFIX']


def test_build_ext_config_handling(tmpdir_cwd):
    files = {
        'setup.py': DALS(
            """
            from setuptools import Extension, setup
            setup(
                name='foo',
                version='0.0.0',
                ext_modules=[Extension('foo', ['foo.c'])],
            )
            """),
        'foo.c': DALS(
            """
            #include "Python.h"

            #if PY_MAJOR_VERSION >= 3

            static struct PyModuleDef moduledef = {
                    PyModuleDef_HEAD_INIT,
                    "foo",
                    NULL,
                    0,
                    NULL,
                    NULL,
                    NULL,
                    NULL,
                    NULL
            };

            #define INITERROR return NULL

            PyMODINIT_FUNC PyInit_foo(void)

            #else

            #define INITERROR return

            void initfoo(void)

            #endif
            {
            #if PY_MAJOR_VERSION >= 3
                PyObject *module = PyModule_Create(&moduledef);
            #else
                PyObject *module = Py_InitModule("extension", NULL);
            #endif
                if (module == NULL)
                    INITERROR;
            #if PY_MAJOR_VERSION >= 3
                return module;
            #endif
            }
            """),
        'setup.cfg': DALS(
            """
            [build]
            build_base = foo_build
            """),
    }
    path.build(files)
    code, output = environment.run_setup_py(
        cmd=['build'], data_stream=(0, 2),
    )
    assert code == 0, '\nSTDOUT:\n%s\nSTDERR:\n%s' % output