about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-4a52a71956a8d46fcb7294ac71734504bb09bcc2.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests')
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_base.py83
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_cygwin.py76
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_mingw.py48
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_msvc.py136
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_unix.py350
5 files changed, 693 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_base.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_base.py
new file mode 100644
index 00000000..a762e2b6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_base.py
@@ -0,0 +1,83 @@
+import platform
+import sysconfig
+import textwrap
+
+import pytest
+
+from .. import base
+
+pytestmark = pytest.mark.usefixtures('suppress_path_mangle')
+
+
+@pytest.fixture
+def c_file(tmp_path):
+    c_file = tmp_path / 'foo.c'
+    gen_headers = ('Python.h',)
+    is_windows = platform.system() == "Windows"
+    plat_headers = ('windows.h',) * is_windows
+    all_headers = gen_headers + plat_headers
+    headers = '\n'.join(f'#include <{header}>\n' for header in all_headers)
+    payload = (
+        textwrap.dedent(
+            """
+        #headers
+        void PyInit_foo(void) {}
+        """
+        )
+        .lstrip()
+        .replace('#headers', headers)
+    )
+    c_file.write_text(payload, encoding='utf-8')
+    return c_file
+
+
+def test_set_include_dirs(c_file):
+    """
+    Extensions should build even if set_include_dirs is invoked.
+    In particular, compiler-specific paths should not be overridden.
+    """
+    compiler = base.new_compiler()
+    python = sysconfig.get_paths()['include']
+    compiler.set_include_dirs([python])
+    compiler.compile([c_file])
+
+    # do it again, setting include dirs after any initialization
+    compiler.set_include_dirs([python])
+    compiler.compile([c_file])
+
+
+def test_has_function_prototype():
+    # Issue https://github.com/pypa/setuptools/issues/3648
+    # Test prototype-generating behavior.
+
+    compiler = base.new_compiler()
+
+    # Every C implementation should have these.
+    assert compiler.has_function('abort')
+    assert compiler.has_function('exit')
+    with pytest.deprecated_call(match='includes is deprecated'):
+        # abort() is a valid expression with the <stdlib.h> prototype.
+        assert compiler.has_function('abort', includes=['stdlib.h'])
+    with pytest.deprecated_call(match='includes is deprecated'):
+        # But exit() is not valid with the actual prototype in scope.
+        assert not compiler.has_function('exit', includes=['stdlib.h'])
+    # And setuptools_does_not_exist is not declared or defined at all.
+    assert not compiler.has_function('setuptools_does_not_exist')
+    with pytest.deprecated_call(match='includes is deprecated'):
+        assert not compiler.has_function(
+            'setuptools_does_not_exist', includes=['stdio.h']
+        )
+
+
+def test_include_dirs_after_multiple_compile_calls(c_file):
+    """
+    Calling compile multiple times should not change the include dirs
+    (regression test for setuptools issue #3591).
+    """
+    compiler = base.new_compiler()
+    python = sysconfig.get_paths()['include']
+    compiler.set_include_dirs([python])
+    compiler.compile([c_file])
+    assert compiler.include_dirs == [python]
+    compiler.compile([c_file])
+    assert compiler.include_dirs == [python]
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_cygwin.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_cygwin.py
new file mode 100644
index 00000000..9adf6b8e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_cygwin.py
@@ -0,0 +1,76 @@
+"""Tests for distutils.cygwinccompiler."""
+
+import os
+import sys
+from distutils import sysconfig
+from distutils.tests import support
+
+import pytest
+
+from .. import cygwin
+
+
+@pytest.fixture(autouse=True)
+def stuff(request, monkeypatch, distutils_managed_tempdir):
+    self = request.instance
+    self.python_h = os.path.join(self.mkdtemp(), 'python.h')
+    monkeypatch.setattr(sysconfig, 'get_config_h_filename', self._get_config_h_filename)
+    monkeypatch.setattr(sys, 'version', sys.version)
+
+
+class TestCygwinCCompiler(support.TempdirManager):
+    def _get_config_h_filename(self):
+        return self.python_h
+
+    @pytest.mark.skipif('sys.platform != "cygwin"')
+    @pytest.mark.skipif('not os.path.exists("/usr/lib/libbash.dll.a")')
+    def test_find_library_file(self):
+        from distutils.cygwinccompiler import CygwinCCompiler
+
+        compiler = CygwinCCompiler()
+        link_name = "bash"
+        linkable_file = compiler.find_library_file(["/usr/lib"], link_name)
+        assert linkable_file is not None
+        assert os.path.exists(linkable_file)
+        assert linkable_file == f"/usr/lib/lib{link_name:s}.dll.a"
+
+    @pytest.mark.skipif('sys.platform != "cygwin"')
+    def test_runtime_library_dir_option(self):
+        from distutils.cygwinccompiler import CygwinCCompiler
+
+        compiler = CygwinCCompiler()
+        assert compiler.runtime_library_dir_option('/foo') == []
+
+    def test_check_config_h(self):
+        # check_config_h looks for "GCC" in sys.version first
+        # returns CONFIG_H_OK if found
+        sys.version = (
+            '2.6.1 (r261:67515, Dec  6 2008, 16:42:21) \n[GCC '
+            '4.0.1 (Apple Computer, Inc. build 5370)]'
+        )
+
+        assert cygwin.check_config_h()[0] == cygwin.CONFIG_H_OK
+
+        # then it tries to see if it can find "__GNUC__" in pyconfig.h
+        sys.version = 'something without the *CC word'
+
+        # if the file doesn't exist it returns  CONFIG_H_UNCERTAIN
+        assert cygwin.check_config_h()[0] == cygwin.CONFIG_H_UNCERTAIN
+
+        # if it exists but does not contain __GNUC__, it returns CONFIG_H_NOTOK
+        self.write_file(self.python_h, 'xxx')
+        assert cygwin.check_config_h()[0] == cygwin.CONFIG_H_NOTOK
+
+        # and CONFIG_H_OK if __GNUC__ is found
+        self.write_file(self.python_h, 'xxx __GNUC__ xxx')
+        assert cygwin.check_config_h()[0] == cygwin.CONFIG_H_OK
+
+    def test_get_msvcr(self):
+        assert cygwin.get_msvcr() == []
+
+    @pytest.mark.skipif('sys.platform != "cygwin"')
+    def test_dll_libraries_not_none(self):
+        from distutils.cygwinccompiler import CygwinCCompiler
+
+        compiler = CygwinCCompiler()
+        assert compiler.dll_libraries is not None
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_mingw.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_mingw.py
new file mode 100644
index 00000000..dc45687a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_mingw.py
@@ -0,0 +1,48 @@
+from distutils import sysconfig
+from distutils.errors import DistutilsPlatformError
+from distutils.util import is_mingw, split_quoted
+
+import pytest
+
+from .. import cygwin, errors
+
+
+class TestMinGW32Compiler:
+    @pytest.mark.skipif(not is_mingw(), reason='not on mingw')
+    def test_compiler_type(self):
+        compiler = cygwin.MinGW32Compiler()
+        assert compiler.compiler_type == 'mingw32'
+
+    @pytest.mark.skipif(not is_mingw(), reason='not on mingw')
+    def test_set_executables(self, monkeypatch):
+        monkeypatch.setenv('CC', 'cc')
+        monkeypatch.setenv('CXX', 'c++')
+
+        compiler = cygwin.MinGW32Compiler()
+
+        assert compiler.compiler == split_quoted('cc -O -Wall')
+        assert compiler.compiler_so == split_quoted('cc -shared -O -Wall')
+        assert compiler.compiler_cxx == split_quoted('c++ -O -Wall')
+        assert compiler.linker_exe == split_quoted('cc')
+        assert compiler.linker_so == split_quoted('cc -shared')
+
+    @pytest.mark.skipif(not is_mingw(), reason='not on mingw')
+    def test_runtime_library_dir_option(self):
+        compiler = cygwin.MinGW32Compiler()
+        with pytest.raises(DistutilsPlatformError):
+            compiler.runtime_library_dir_option('/usr/lib')
+
+    @pytest.mark.skipif(not is_mingw(), reason='not on mingw')
+    def test_cygwincc_error(self, monkeypatch):
+        monkeypatch.setattr(cygwin, 'is_cygwincc', lambda _: True)
+
+        with pytest.raises(errors.Error):
+            cygwin.MinGW32Compiler()
+
+    @pytest.mark.skipif('sys.platform == "cygwin"')
+    def test_customize_compiler_with_msvc_python(self):
+        # In case we have an MSVC Python build, but still want to use
+        # MinGW32Compiler, then customize_compiler() shouldn't fail at least.
+        # https://github.com/pypa/setuptools/issues/4456
+        compiler = cygwin.MinGW32Compiler()
+        sysconfig.customize_compiler(compiler)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_msvc.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_msvc.py
new file mode 100644
index 00000000..eca83199
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_msvc.py
@@ -0,0 +1,136 @@
+import os
+import sys
+import sysconfig
+import threading
+import unittest.mock as mock
+from distutils.errors import DistutilsPlatformError
+from distutils.tests import support
+from distutils.util import get_platform
+
+import pytest
+
+from .. import msvc
+
+needs_winreg = pytest.mark.skipif('not hasattr(msvc, "winreg")')
+
+
+class Testmsvccompiler(support.TempdirManager):
+    def test_no_compiler(self, monkeypatch):
+        # makes sure query_vcvarsall raises
+        # a DistutilsPlatformError if the compiler
+        # is not found
+        def _find_vcvarsall(plat_spec):
+            return None, None
+
+        monkeypatch.setattr(msvc, '_find_vcvarsall', _find_vcvarsall)
+
+        with pytest.raises(DistutilsPlatformError):
+            msvc._get_vc_env(
+                'wont find this version',
+            )
+
+    @pytest.mark.skipif(
+        not sysconfig.get_platform().startswith("win"),
+        reason="Only run test for non-mingw Windows platforms",
+    )
+    @pytest.mark.parametrize(
+        "plat_name, expected",
+        [
+            ("win-arm64", "win-arm64"),
+            ("win-amd64", "win-amd64"),
+            (None, get_platform()),
+        ],
+    )
+    def test_cross_platform_compilation_paths(self, monkeypatch, plat_name, expected):
+        """
+        Ensure a specified target platform is passed to _get_vcvars_spec.
+        """
+        compiler = msvc.Compiler()
+
+        def _get_vcvars_spec(host_platform, platform):
+            assert platform == expected
+
+        monkeypatch.setattr(msvc, '_get_vcvars_spec', _get_vcvars_spec)
+        compiler.initialize(plat_name)
+
+    @needs_winreg
+    def test_get_vc_env_unicode(self):
+        test_var = 'ṰḖṤṪ┅ṼẨṜ'
+        test_value = '₃⁴₅'
+
+        # Ensure we don't early exit from _get_vc_env
+        old_distutils_use_sdk = os.environ.pop('DISTUTILS_USE_SDK', None)
+        os.environ[test_var] = test_value
+        try:
+            env = msvc._get_vc_env('x86')
+            assert test_var.lower() in env
+            assert test_value == env[test_var.lower()]
+        finally:
+            os.environ.pop(test_var)
+            if old_distutils_use_sdk:
+                os.environ['DISTUTILS_USE_SDK'] = old_distutils_use_sdk
+
+    @needs_winreg
+    @pytest.mark.parametrize('ver', (2015, 2017))
+    def test_get_vc(self, ver):
+        # This function cannot be mocked, so pass if VC is found
+        # and skip otherwise.
+        lookup = getattr(msvc, f'_find_vc{ver}')
+        expected_version = {2015: 14, 2017: 15}[ver]
+        version, path = lookup()
+        if not version:
+            pytest.skip(f"VS {ver} is not installed")
+        assert version >= expected_version
+        assert os.path.isdir(path)
+
+
+class CheckThread(threading.Thread):
+    exc_info = None
+
+    def run(self):
+        try:
+            super().run()
+        except Exception:
+            self.exc_info = sys.exc_info()
+
+    def __bool__(self):
+        return not self.exc_info
+
+
+class TestSpawn:
+    def test_concurrent_safe(self):
+        """
+        Concurrent calls to spawn should have consistent results.
+        """
+        compiler = msvc.Compiler()
+        compiler._paths = "expected"
+        inner_cmd = 'import os; assert os.environ["PATH"] == "expected"'
+        command = [sys.executable, '-c', inner_cmd]
+
+        threads = [
+            CheckThread(target=compiler.spawn, args=[command]) for n in range(100)
+        ]
+        for thread in threads:
+            thread.start()
+        for thread in threads:
+            thread.join()
+        assert all(threads)
+
+    def test_concurrent_safe_fallback(self):
+        """
+        If CCompiler.spawn has been monkey-patched without support
+        for an env, it should still execute.
+        """
+        from distutils import ccompiler
+
+        compiler = msvc.Compiler()
+        compiler._paths = "expected"
+
+        def CCompiler_spawn(self, cmd):
+            "A spawn without an env argument."
+            assert os.environ["PATH"] == "expected"
+
+        with mock.patch.object(ccompiler.CCompiler, 'spawn', CCompiler_spawn):
+            compiler.spawn(["n/a"])
+
+        assert os.environ.get("PATH") != "expected"
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_unix.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_unix.py
new file mode 100644
index 00000000..f4e28984
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/compilers/C/tests/test_unix.py
@@ -0,0 +1,350 @@
+"""Tests for distutils.unixccompiler."""
+
+import os
+import sys
+import unittest.mock as mock
+from distutils import sysconfig
+from distutils.compat import consolidate_linker_args
+from distutils.errors import DistutilsPlatformError
+from distutils.tests import support
+from distutils.tests.compat.py39 import EnvironmentVarGuard
+from distutils.util import _clear_cached_macosx_ver
+
+import pytest
+
+from .. import unix
+
+
+@pytest.fixture(autouse=True)
+def save_values(monkeypatch):
+    monkeypatch.setattr(sys, 'platform', sys.platform)
+    monkeypatch.setattr(sysconfig, 'get_config_var', sysconfig.get_config_var)
+    monkeypatch.setattr(sysconfig, 'get_config_vars', sysconfig.get_config_vars)
+
+
+@pytest.fixture(autouse=True)
+def compiler_wrapper(request):
+    class CompilerWrapper(unix.Compiler):
+        def rpath_foo(self):
+            return self.runtime_library_dir_option('/foo')
+
+    request.instance.cc = CompilerWrapper()
+
+
+class TestUnixCCompiler(support.TempdirManager):
+    @pytest.mark.skipif('platform.system == "Windows"')
+    def test_runtime_libdir_option(self):  # noqa: C901
+        # Issue #5900; GitHub Issue #37
+        #
+        # Ensure RUNPATH is added to extension modules with RPATH if
+        # GNU ld is used
+
+        # darwin
+        sys.platform = 'darwin'
+        darwin_ver_var = 'MACOSX_DEPLOYMENT_TARGET'
+        darwin_rpath_flag = '-Wl,-rpath,/foo'
+        darwin_lib_flag = '-L/foo'
+
+        # (macOS version from syscfg, macOS version from env var) -> flag
+        # Version value of None generates two tests: as None and as empty string
+        # Expected flag value of None means an mismatch exception is expected
+        darwin_test_cases = [
+            ((None, None), darwin_lib_flag),
+            ((None, '11'), darwin_rpath_flag),
+            (('10', None), darwin_lib_flag),
+            (('10.3', None), darwin_lib_flag),
+            (('10.3.1', None), darwin_lib_flag),
+            (('10.5', None), darwin_rpath_flag),
+            (('10.5.1', None), darwin_rpath_flag),
+            (('10.3', '10.3'), darwin_lib_flag),
+            (('10.3', '10.5'), darwin_rpath_flag),
+            (('10.5', '10.3'), darwin_lib_flag),
+            (('10.5', '11'), darwin_rpath_flag),
+            (('10.4', '10'), None),
+        ]
+
+        def make_darwin_gcv(syscfg_macosx_ver):
+            def gcv(var):
+                if var == darwin_ver_var:
+                    return syscfg_macosx_ver
+                return "xxx"
+
+            return gcv
+
+        def do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag):
+            env = os.environ
+            msg = f"macOS version = (sysconfig={syscfg_macosx_ver!r}, env={env_macosx_ver!r})"
+
+            # Save
+            old_gcv = sysconfig.get_config_var
+            old_env_macosx_ver = env.get(darwin_ver_var)
+
+            # Setup environment
+            _clear_cached_macosx_ver()
+            sysconfig.get_config_var = make_darwin_gcv(syscfg_macosx_ver)
+            if env_macosx_ver is not None:
+                env[darwin_ver_var] = env_macosx_ver
+            elif darwin_ver_var in env:
+                env.pop(darwin_ver_var)
+
+            # Run the test
+            if expected_flag is not None:
+                assert self.cc.rpath_foo() == expected_flag, msg
+            else:
+                with pytest.raises(
+                    DistutilsPlatformError, match=darwin_ver_var + r' mismatch'
+                ):
+                    self.cc.rpath_foo()
+
+            # Restore
+            if old_env_macosx_ver is not None:
+                env[darwin_ver_var] = old_env_macosx_ver
+            elif darwin_ver_var in env:
+                env.pop(darwin_ver_var)
+            sysconfig.get_config_var = old_gcv
+            _clear_cached_macosx_ver()
+
+        for macosx_vers, expected_flag in darwin_test_cases:
+            syscfg_macosx_ver, env_macosx_ver = macosx_vers
+            do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag)
+            # Bonus test cases with None interpreted as empty string
+            if syscfg_macosx_ver is None:
+                do_darwin_test("", env_macosx_ver, expected_flag)
+            if env_macosx_ver is None:
+                do_darwin_test(syscfg_macosx_ver, "", expected_flag)
+            if syscfg_macosx_ver is None and env_macosx_ver is None:
+                do_darwin_test("", "", expected_flag)
+
+        old_gcv = sysconfig.get_config_var
+
+        # hp-ux
+        sys.platform = 'hp-ux'
+
+        def gcv(v):
+            return 'xxx'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == ['+s', '-L/foo']
+
+        def gcv(v):
+            return 'gcc'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == ['-Wl,+s', '-L/foo']
+
+        def gcv(v):
+            return 'g++'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == ['-Wl,+s', '-L/foo']
+
+        sysconfig.get_config_var = old_gcv
+
+        # GCC GNULD
+        sys.platform = 'bar'
+
+        def gcv(v):
+            if v == 'CC':
+                return 'gcc'
+            elif v == 'GNULD':
+                return 'yes'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == consolidate_linker_args([
+            '-Wl,--enable-new-dtags',
+            '-Wl,-rpath,/foo',
+        ])
+
+        def gcv(v):
+            if v == 'CC':
+                return 'gcc -pthread -B /bar'
+            elif v == 'GNULD':
+                return 'yes'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == consolidate_linker_args([
+            '-Wl,--enable-new-dtags',
+            '-Wl,-rpath,/foo',
+        ])
+
+        # GCC non-GNULD
+        sys.platform = 'bar'
+
+        def gcv(v):
+            if v == 'CC':
+                return 'gcc'
+            elif v == 'GNULD':
+                return 'no'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == '-Wl,-R/foo'
+
+        # GCC GNULD with fully qualified configuration prefix
+        # see #7617
+        sys.platform = 'bar'
+
+        def gcv(v):
+            if v == 'CC':
+                return 'x86_64-pc-linux-gnu-gcc-4.4.2'
+            elif v == 'GNULD':
+                return 'yes'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == consolidate_linker_args([
+            '-Wl,--enable-new-dtags',
+            '-Wl,-rpath,/foo',
+        ])
+
+        # non-GCC GNULD
+        sys.platform = 'bar'
+
+        def gcv(v):
+            if v == 'CC':
+                return 'cc'
+            elif v == 'GNULD':
+                return 'yes'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == consolidate_linker_args([
+            '-Wl,--enable-new-dtags',
+            '-Wl,-rpath,/foo',
+        ])
+
+        # non-GCC non-GNULD
+        sys.platform = 'bar'
+
+        def gcv(v):
+            if v == 'CC':
+                return 'cc'
+            elif v == 'GNULD':
+                return 'no'
+
+        sysconfig.get_config_var = gcv
+        assert self.cc.rpath_foo() == '-Wl,-R/foo'
+
+    @pytest.mark.skipif('platform.system == "Windows"')
+    def test_cc_overrides_ldshared(self):
+        # Issue #18080:
+        # ensure that setting CC env variable also changes default linker
+        def gcv(v):
+            if v == 'LDSHARED':
+                return 'gcc-4.2 -bundle -undefined dynamic_lookup '
+            return 'gcc-4.2'
+
+        def gcvs(*args, _orig=sysconfig.get_config_vars):
+            if args:
+                return list(map(sysconfig.get_config_var, args))
+            return _orig()
+
+        sysconfig.get_config_var = gcv
+        sysconfig.get_config_vars = gcvs
+        with EnvironmentVarGuard() as env:
+            env['CC'] = 'my_cc'
+            del env['LDSHARED']
+            sysconfig.customize_compiler(self.cc)
+        assert self.cc.linker_so[0] == 'my_cc'
+
+    @pytest.mark.skipif('platform.system == "Windows"')
+    @pytest.mark.usefixtures('disable_macos_customization')
+    def test_cc_overrides_ldshared_for_cxx_correctly(self):
+        """
+        Ensure that setting CC env variable also changes default linker
+        correctly when building C++ extensions.
+
+        pypa/distutils#126
+        """
+
+        def gcv(v):
+            if v == 'LDSHARED':
+                return 'gcc-4.2 -bundle -undefined dynamic_lookup '
+            elif v == 'LDCXXSHARED':
+                return 'g++-4.2 -bundle -undefined dynamic_lookup '
+            elif v == 'CXX':
+                return 'g++-4.2'
+            elif v == 'CC':
+                return 'gcc-4.2'
+            return ''
+
+        def gcvs(*args, _orig=sysconfig.get_config_vars):
+            if args:
+                return list(map(sysconfig.get_config_var, args))
+            return _orig()
+
+        sysconfig.get_config_var = gcv
+        sysconfig.get_config_vars = gcvs
+        with (
+            mock.patch.object(self.cc, 'spawn', return_value=None) as mock_spawn,
+            mock.patch.object(self.cc, '_need_link', return_value=True),
+            mock.patch.object(self.cc, 'mkpath', return_value=None),
+            EnvironmentVarGuard() as env,
+        ):
+            env['CC'] = 'ccache my_cc'
+            env['CXX'] = 'my_cxx'
+            del env['LDSHARED']
+            sysconfig.customize_compiler(self.cc)
+            assert self.cc.linker_so[0:2] == ['ccache', 'my_cc']
+            self.cc.link(None, [], 'a.out', target_lang='c++')
+            call_args = mock_spawn.call_args[0][0]
+            expected = ['my_cxx', '-bundle', '-undefined', 'dynamic_lookup']
+            assert call_args[:4] == expected
+
+    @pytest.mark.skipif('platform.system == "Windows"')
+    def test_explicit_ldshared(self):
+        # Issue #18080:
+        # ensure that setting CC env variable does not change
+        #   explicit LDSHARED setting for linker
+        def gcv(v):
+            if v == 'LDSHARED':
+                return 'gcc-4.2 -bundle -undefined dynamic_lookup '
+            return 'gcc-4.2'
+
+        def gcvs(*args, _orig=sysconfig.get_config_vars):
+            if args:
+                return list(map(sysconfig.get_config_var, args))
+            return _orig()
+
+        sysconfig.get_config_var = gcv
+        sysconfig.get_config_vars = gcvs
+        with EnvironmentVarGuard() as env:
+            env['CC'] = 'my_cc'
+            env['LDSHARED'] = 'my_ld -bundle -dynamic'
+            sysconfig.customize_compiler(self.cc)
+        assert self.cc.linker_so[0] == 'my_ld'
+
+    def test_has_function(self):
+        # Issue https://github.com/pypa/distutils/issues/64:
+        # ensure that setting output_dir does not raise
+        # FileNotFoundError: [Errno 2] No such file or directory: 'a.out'
+        self.cc.output_dir = 'scratch'
+        os.chdir(self.mkdtemp())
+        self.cc.has_function('abort')
+
+    def test_find_library_file(self, monkeypatch):
+        compiler = unix.Compiler()
+        compiler._library_root = lambda dir: dir
+        monkeypatch.setattr(os.path, 'exists', lambda d: 'existing' in d)
+
+        libname = 'libabc.dylib' if sys.platform != 'cygwin' else 'cygabc.dll'
+        dirs = ('/foo/bar/missing', '/foo/bar/existing')
+        assert (
+            compiler.find_library_file(dirs, 'abc').replace('\\', '/')
+            == f'/foo/bar/existing/{libname}'
+        )
+        assert (
+            compiler.find_library_file(reversed(dirs), 'abc').replace('\\', '/')
+            == f'/foo/bar/existing/{libname}'
+        )
+
+        monkeypatch.setattr(
+            os.path,
+            'exists',
+            lambda d: 'existing' in d and '.a' in d and '.dll.a' not in d,
+        )
+        assert (
+            compiler.find_library_file(dirs, 'abc').replace('\\', '/')
+            == '/foo/bar/existing/libabc.a'
+        )
+        assert (
+            compiler.find_library_file(reversed(dirs), 'abc').replace('\\', '/')
+            == '/foo/bar/existing/libabc.a'
+        )