Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_unix.py414 linesDownload Raw Back to tests
1"""Tests for distutils.unixccompiler."""2 3import os4import sys5import unittest.mock as mock6from distutils import sysconfig7from distutils.compat import consolidate_linker_args8from distutils.errors import DistutilsPlatformError9from distutils.tests import support10from distutils.tests.compat.py39 import EnvironmentVarGuard11from distutils.util import _clear_cached_macosx_ver12 13import pytest14 15from .. import unix16 17 18@pytest.fixture(autouse=True)19def save_values(monkeypatch):20    monkeypatch.setattr(sys, 'platform', sys.platform)21    monkeypatch.setattr(sysconfig, 'get_config_var', sysconfig.get_config_var)22    monkeypatch.setattr(sysconfig, 'get_config_vars', sysconfig.get_config_vars)23 24 25@pytest.fixture(autouse=True)26def compiler_wrapper(request):27    class CompilerWrapper(unix.Compiler):28        def rpath_foo(self):29            return self.runtime_library_dir_option('/foo')30 31    request.instance.cc = CompilerWrapper()32 33 34class TestUnixCCompiler(support.TempdirManager):35    @pytest.mark.skipif('platform.system == "Windows"')36    def test_runtime_libdir_option(self):  # noqa: C90137        # Issue #5900; GitHub Issue #3738        #39        # Ensure RUNPATH is added to extension modules with RPATH if40        # GNU ld is used41 42        # darwin43        sys.platform = 'darwin'44        darwin_ver_var = 'MACOSX_DEPLOYMENT_TARGET'45        darwin_rpath_flag = '-Wl,-rpath,/foo'46        darwin_lib_flag = '-L/foo'47 48        # (macOS version from syscfg, macOS version from env var) -> flag49        # Version value of None generates two tests: as None and as empty string50        # Expected flag value of None means an mismatch exception is expected51        darwin_test_cases = [52            ((None, None), darwin_lib_flag),53            ((None, '11'), darwin_rpath_flag),54            (('10', None), darwin_lib_flag),55            (('10.3', None), darwin_lib_flag),56            (('10.3.1', None), darwin_lib_flag),57            (('10.5', None), darwin_rpath_flag),58            (('10.5.1', None), darwin_rpath_flag),59            (('10.3', '10.3'), darwin_lib_flag),60            (('10.3', '10.5'), darwin_rpath_flag),61            (('10.5', '10.3'), darwin_lib_flag),62            (('10.5', '11'), darwin_rpath_flag),63            (('10.4', '10'), None),64        ]65 66        def make_darwin_gcv(syscfg_macosx_ver):67            def gcv(var):68                if var == darwin_ver_var:69                    return syscfg_macosx_ver70                return "xxx"71 72            return gcv73 74        def do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag):75            env = os.environ76            msg = f"macOS version = (sysconfig={syscfg_macosx_ver!r}, env={env_macosx_ver!r})"77 78            # Save79            old_gcv = sysconfig.get_config_var80            old_env_macosx_ver = env.get(darwin_ver_var)81 82            # Setup environment83            _clear_cached_macosx_ver()84            sysconfig.get_config_var = make_darwin_gcv(syscfg_macosx_ver)85            if env_macosx_ver is not None:86                env[darwin_ver_var] = env_macosx_ver87            elif darwin_ver_var in env:88                env.pop(darwin_ver_var)89 90            # Run the test91            if expected_flag is not None:92                assert self.cc.rpath_foo() == expected_flag, msg93            else:94                with pytest.raises(95                    DistutilsPlatformError, match=darwin_ver_var + r' mismatch'96                ):97                    self.cc.rpath_foo()98 99            # Restore100            if old_env_macosx_ver is not None:101                env[darwin_ver_var] = old_env_macosx_ver102            elif darwin_ver_var in env:103                env.pop(darwin_ver_var)104            sysconfig.get_config_var = old_gcv105            _clear_cached_macosx_ver()106 107        for macosx_vers, expected_flag in darwin_test_cases:108            syscfg_macosx_ver, env_macosx_ver = macosx_vers109            do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag)110            # Bonus test cases with None interpreted as empty string111            if syscfg_macosx_ver is None:112                do_darwin_test("", env_macosx_ver, expected_flag)113            if env_macosx_ver is None:114                do_darwin_test(syscfg_macosx_ver, "", expected_flag)115            if syscfg_macosx_ver is None and env_macosx_ver is None:116                do_darwin_test("", "", expected_flag)117 118        old_gcv = sysconfig.get_config_var119 120        # hp-ux121        sys.platform = 'hp-ux'122 123        def gcv(v):124            return 'xxx'125 126        sysconfig.get_config_var = gcv127        assert self.cc.rpath_foo() == ['+s', '-L/foo']128 129        def gcv(v):130            return 'gcc'131 132        sysconfig.get_config_var = gcv133        assert self.cc.rpath_foo() == ['-Wl,+s', '-L/foo']134 135        def gcv(v):136            return 'g++'137 138        sysconfig.get_config_var = gcv139        assert self.cc.rpath_foo() == ['-Wl,+s', '-L/foo']140 141        sysconfig.get_config_var = old_gcv142 143        # GCC GNULD144        sys.platform = 'bar'145 146        def gcv(v):147            if v == 'CC':148                return 'gcc'149            elif v == 'GNULD':150                return 'yes'151 152        sysconfig.get_config_var = gcv153        assert self.cc.rpath_foo() == consolidate_linker_args([154            '-Wl,--enable-new-dtags',155            '-Wl,-rpath,/foo',156        ])157 158        def gcv(v):159            if v == 'CC':160                return 'gcc -pthread -B /bar'161            elif v == 'GNULD':162                return 'yes'163 164        sysconfig.get_config_var = gcv165        assert self.cc.rpath_foo() == consolidate_linker_args([166            '-Wl,--enable-new-dtags',167            '-Wl,-rpath,/foo',168        ])169 170        # GCC non-GNULD171        sys.platform = 'bar'172 173        def gcv(v):174            if v == 'CC':175                return 'gcc'176            elif v == 'GNULD':177                return 'no'178 179        sysconfig.get_config_var = gcv180        assert self.cc.rpath_foo() == '-Wl,-R/foo'181 182        # GCC GNULD with fully qualified configuration prefix183        # see #7617184        sys.platform = 'bar'185 186        def gcv(v):187            if v == 'CC':188                return 'x86_64-pc-linux-gnu-gcc-4.4.2'189            elif v == 'GNULD':190                return 'yes'191 192        sysconfig.get_config_var = gcv193        assert self.cc.rpath_foo() == consolidate_linker_args([194            '-Wl,--enable-new-dtags',195            '-Wl,-rpath,/foo',196        ])197 198        # non-GCC GNULD199        sys.platform = 'bar'200 201        def gcv(v):202            if v == 'CC':203                return 'cc'204            elif v == 'GNULD':205                return 'yes'206 207        sysconfig.get_config_var = gcv208        assert self.cc.rpath_foo() == consolidate_linker_args([209            '-Wl,--enable-new-dtags',210            '-Wl,-rpath,/foo',211        ])212 213        # non-GCC non-GNULD214        sys.platform = 'bar'215 216        def gcv(v):217            if v == 'CC':218                return 'cc'219            elif v == 'GNULD':220                return 'no'221 222        sysconfig.get_config_var = gcv223        assert self.cc.rpath_foo() == '-Wl,-R/foo'224 225    @pytest.mark.skipif('platform.system == "Windows"')226    def test_cc_overrides_ldshared(self):227        # Issue #18080:228        # ensure that setting CC env variable also changes default linker229        def gcv(v):230            if v == 'LDSHARED':231                return 'gcc-4.2 -bundle -undefined dynamic_lookup '232            return 'gcc-4.2'233 234        def gcvs(*args, _orig=sysconfig.get_config_vars):235            if args:236                return list(map(sysconfig.get_config_var, args))237            return _orig()238 239        sysconfig.get_config_var = gcv240        sysconfig.get_config_vars = gcvs241        with EnvironmentVarGuard() as env:242            env['CC'] = 'my_cc'243            del env['LDSHARED']244            sysconfig.customize_compiler(self.cc)245        assert self.cc.linker_so[0] == 'my_cc'246 247    @pytest.mark.skipif('platform.system == "Windows"')248    def test_cxx_commands_used_are_correct(self):249        def gcv(v):250            if v == 'LDSHARED':251                return 'ccache gcc-4.2 -bundle -undefined dynamic_lookup'252            elif v == 'LDCXXSHARED':253                return 'ccache g++-4.2 -bundle -undefined dynamic_lookup'254            elif v == 'CXX':255                return 'ccache g++-4.2'256            elif v == 'CC':257                return 'ccache gcc-4.2'258            return ''259 260        def gcvs(*args, _orig=sysconfig.get_config_vars):261            if args:262                return list(map(sysconfig.get_config_var, args))263            return _orig()  # pragma: no cover264 265        sysconfig.get_config_var = gcv266        sysconfig.get_config_vars = gcvs267        with (268            mock.patch.object(self.cc, 'spawn', return_value=None) as mock_spawn,269            mock.patch.object(self.cc, '_need_link', return_value=True),270            mock.patch.object(self.cc, 'mkpath', return_value=None),271            EnvironmentVarGuard() as env,272        ):273            # override environment overrides in case they're specified by CI274            del env['CXX']275            del env['LDCXXSHARED']276 277            sysconfig.customize_compiler(self.cc)278            assert self.cc.linker_so_cxx[0:2] == ['ccache', 'g++-4.2']279            assert self.cc.linker_exe_cxx[0:2] == ['ccache', 'g++-4.2']280            self.cc.link(None, [], 'a.out', target_lang='c++')281            call_args = mock_spawn.call_args[0][0]282            expected = ['ccache', 'g++-4.2', '-bundle', '-undefined', 'dynamic_lookup']283            assert call_args[:5] == expected284 285            self.cc.link_executable([], 'a.out', target_lang='c++')286            call_args = mock_spawn.call_args[0][0]287            expected = ['ccache', 'g++-4.2', '-o', self.cc.executable_filename('a.out')]288            assert call_args[:4] == expected289 290            env['LDCXXSHARED'] = 'wrapper g++-4.2 -bundle -undefined dynamic_lookup'291            env['CXX'] = 'wrapper g++-4.2'292            sysconfig.customize_compiler(self.cc)293            assert self.cc.linker_so_cxx[0:2] == ['wrapper', 'g++-4.2']294            assert self.cc.linker_exe_cxx[0:2] == ['wrapper', 'g++-4.2']295            self.cc.link(None, [], 'a.out', target_lang='c++')296            call_args = mock_spawn.call_args[0][0]297            expected = ['wrapper', 'g++-4.2', '-bundle', '-undefined', 'dynamic_lookup']298            assert call_args[:5] == expected299 300            self.cc.link_executable([], 'a.out', target_lang='c++')301            call_args = mock_spawn.call_args[0][0]302            expected = [303                'wrapper',304                'g++-4.2',305                '-o',306                self.cc.executable_filename('a.out'),307            ]308            assert call_args[:4] == expected309 310    @pytest.mark.skipif('platform.system == "Windows"')311    @pytest.mark.usefixtures('disable_macos_customization')312    def test_cc_overrides_ldshared_for_cxx_correctly(self):313        """314        Ensure that setting CC env variable also changes default linker315        correctly when building C++ extensions.316 317        pypa/distutils#126318        """319 320        def gcv(v):321            if v == 'LDSHARED':322                return 'gcc-4.2 -bundle -undefined dynamic_lookup '323            elif v == 'LDCXXSHARED':324                return 'g++-4.2 -bundle -undefined dynamic_lookup '325            elif v == 'CXX':326                return 'g++-4.2'327            elif v == 'CC':328                return 'gcc-4.2'329            return ''330 331        def gcvs(*args, _orig=sysconfig.get_config_vars):332            if args:333                return list(map(sysconfig.get_config_var, args))334            return _orig()335 336        sysconfig.get_config_var = gcv337        sysconfig.get_config_vars = gcvs338        with (339            mock.patch.object(self.cc, 'spawn', return_value=None) as mock_spawn,340            mock.patch.object(self.cc, '_need_link', return_value=True),341            mock.patch.object(self.cc, 'mkpath', return_value=None),342            EnvironmentVarGuard() as env,343        ):344            env['CC'] = 'ccache my_cc'345            env['CXX'] = 'my_cxx'346            del env['LDSHARED']347            sysconfig.customize_compiler(self.cc)348            assert self.cc.linker_so[0:2] == ['ccache', 'my_cc']349            self.cc.link(None, [], 'a.out', target_lang='c++')350            call_args = mock_spawn.call_args[0][0]351            expected = ['my_cxx', '-bundle', '-undefined', 'dynamic_lookup']352            assert call_args[:4] == expected353 354    @pytest.mark.skipif('platform.system == "Windows"')355    def test_explicit_ldshared(self):356        # Issue #18080:357        # ensure that setting CC env variable does not change358        #   explicit LDSHARED setting for linker359        def gcv(v):360            if v == 'LDSHARED':361                return 'gcc-4.2 -bundle -undefined dynamic_lookup '362            return 'gcc-4.2'363 364        def gcvs(*args, _orig=sysconfig.get_config_vars):365            if args:366                return list(map(sysconfig.get_config_var, args))367            return _orig()368 369        sysconfig.get_config_var = gcv370        sysconfig.get_config_vars = gcvs371        with EnvironmentVarGuard() as env:372            env['CC'] = 'my_cc'373            env['LDSHARED'] = 'my_ld -bundle -dynamic'374            sysconfig.customize_compiler(self.cc)375        assert self.cc.linker_so[0] == 'my_ld'376 377    def test_has_function(self):378        # Issue https://github.com/pypa/distutils/issues/64:379        # ensure that setting output_dir does not raise380        # FileNotFoundError: [Errno 2] No such file or directory: 'a.out'381        self.cc.output_dir = 'scratch'382        os.chdir(self.mkdtemp())383        self.cc.has_function('abort')384 385    def test_find_library_file(self, monkeypatch):386        compiler = unix.Compiler()387        compiler._library_root = lambda dir: dir388        monkeypatch.setattr(os.path, 'exists', lambda d: 'existing' in d)389 390        libname = 'libabc.dylib' if sys.platform != 'cygwin' else 'cygabc.dll'391        dirs = ('/foo/bar/missing', '/foo/bar/existing')392        assert (393            compiler.find_library_file(dirs, 'abc').replace('\\', '/')394            == f'/foo/bar/existing/{libname}'395        )396        assert (397            compiler.find_library_file(reversed(dirs), 'abc').replace('\\', '/')398            == f'/foo/bar/existing/{libname}'399        )400 401        monkeypatch.setattr(402            os.path,403            'exists',404            lambda d: 'existing' in d and '.a' in d and '.dll.a' not in d,405        )406        assert (407            compiler.find_library_file(dirs, 'abc').replace('\\', '/')408            == '/foo/bar/existing/libabc.a'409        )410        assert (411            compiler.find_library_file(reversed(dirs), 'abc').replace('\\', '/')412            == '/foo/bar/existing/libabc.a'413        )414 
codekingpro/portable-devtools · Team Ai