Skip to content

Commit

Permalink
Merge pull request pypa/distutils#228 from pypa/feature/cpp-support
Browse files Browse the repository at this point in the history
Distutils C++ support
  • Loading branch information
jaraco committed Aug 2, 2024
2 parents 127371a + 8307b56 commit fc76caa
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 35 deletions.
23 changes: 19 additions & 4 deletions distutils/cygwinccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,18 @@ def __init__(self, verbose=False, dry_run=False, force=False):
self.cxx = os.environ.get('CXX', 'g++')

self.linker_dll = self.cc
self.linker_dll_cxx = self.cxx
shared_option = "-shared"

self.set_executables(
compiler=f'{self.cc} -mcygwin -O -Wall',
compiler_so=f'{self.cc} -mcygwin -mdll -O -Wall',
compiler_cxx=f'{self.cxx} -mcygwin -O -Wall',
compiler_so_cxx=f'{self.cxx} -mcygwin -mdll -O -Wall',
linker_exe=f'{self.cc} -mcygwin',
linker_so=(f'{self.linker_dll} -mcygwin {shared_option}'),
linker_so=f'{self.linker_dll} -mcygwin {shared_option}',
linker_exe_cxx=f'{self.cxx} -mcygwin',
linker_so_cxx=f'{self.linker_dll_cxx} -mcygwin {shared_option}',
)

# Include the appropriate MSVC runtime library if Python was built
Expand Down Expand Up @@ -138,9 +142,17 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
raise CompileError(msg)
else: # for other files use the C-compiler
try:
self.spawn(
self.compiler_so + cc_args + [src, '-o', obj] + extra_postargs
)
if self.detect_language(src) == 'c++':
self.spawn(
self.compiler_so_cxx
+ cc_args
+ [src, '-o', obj]
+ extra_postargs
)
else:
self.spawn(
self.compiler_so + cc_args + [src, '-o', obj] + extra_postargs
)
except DistutilsExecError as msg:
raise CompileError(msg)

Expand Down Expand Up @@ -276,9 +288,12 @@ def __init__(self, verbose=False, dry_run=False, force=False):
self.set_executables(
compiler=f'{self.cc} -O -Wall',
compiler_so=f'{self.cc} -shared -O -Wall',
compiler_so_cxx=f'{self.cxx} -shared -O -Wall',
compiler_cxx=f'{self.cxx} -O -Wall',
linker_exe=f'{self.cc}',
linker_so=f'{self.linker_dll} {shared_option}',
linker_exe_cxx=f'{self.cxx}',
linker_so_cxx=f'{self.linker_dll_cxx} {shared_option}',
)

def runtime_library_dir_option(self, dir):
Expand Down
69 changes: 44 additions & 25 deletions distutils/sysconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def _customize_macos():
)


def customize_compiler(compiler): # noqa: C901
def customize_compiler(compiler):
"""Do any platform-specific customization of a CCompiler instance.
Mainly needed on Unix, so we can plug in the information that
Expand All @@ -304,6 +304,7 @@ def customize_compiler(compiler): # noqa: C901
cflags,
ccshared,
ldshared,
ldcxxshared,
shlib_suffix,
ar,
ar_flags,
Expand All @@ -313,50 +314,57 @@ def customize_compiler(compiler): # noqa: C901
'CFLAGS',
'CCSHARED',
'LDSHARED',
'LDCXXSHARED',
'SHLIB_SUFFIX',
'AR',
'ARFLAGS',
)

cxxflags = cflags

if 'CC' in os.environ:
newcc = os.environ['CC']
if 'LDSHARED' not in os.environ and ldshared.startswith(cc):
# If CC is overridden, use that as the default
# command for LDSHARED as well
ldshared = newcc + ldshared[len(cc) :]
cc = newcc
if 'CXX' in os.environ:
cxx = os.environ['CXX']
if 'LDSHARED' in os.environ:
ldshared = os.environ['LDSHARED']
if 'CPP' in os.environ:
cpp = os.environ['CPP']
else:
cpp = cc + " -E" # not always
if 'LDFLAGS' in os.environ:
ldshared = ldshared + ' ' + os.environ['LDFLAGS']
if 'CFLAGS' in os.environ:
cflags = cflags + ' ' + os.environ['CFLAGS']
ldshared = ldshared + ' ' + os.environ['CFLAGS']
if 'CPPFLAGS' in os.environ:
cpp = cpp + ' ' + os.environ['CPPFLAGS']
cflags = cflags + ' ' + os.environ['CPPFLAGS']
ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
if 'AR' in os.environ:
ar = os.environ['AR']
if 'ARFLAGS' in os.environ:
archiver = ar + ' ' + os.environ['ARFLAGS']
else:
archiver = ar + ' ' + ar_flags
cxx = os.environ.get('CXX', cxx)
ldshared = os.environ.get('LDSHARED', ldshared)
ldcxxshared = os.environ.get('LDCXXSHARED', ldcxxshared)
cpp = os.environ.get(
'CPP',
cc + " -E", # not always
)

ldshared = _add_flags(ldshared, 'LD')
ldcxxshared = _add_flags(ldcxxshared, 'LD')
cflags = _add_flags(cflags, 'C')
ldshared = _add_flags(ldshared, 'C')
cxxflags = os.environ.get('CXXFLAGS', cxxflags)
ldcxxshared = _add_flags(ldcxxshared, 'CXX')
cpp = _add_flags(cpp, 'CPP')
cflags = _add_flags(cflags, 'CPP')
cxxflags = _add_flags(cxxflags, 'CPP')
ldshared = _add_flags(ldshared, 'CPP')
ldcxxshared = _add_flags(ldcxxshared, 'CPP')

ar = os.environ.get('AR', ar)

archiver = ar + ' ' + os.environ.get('ARFLAGS', ar_flags)
cc_cmd = cc + ' ' + cflags
cxx_cmd = cxx + ' ' + cxxflags

compiler.set_executables(
preprocessor=cpp,
compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared,
compiler_cxx=cxx,
compiler_cxx=cxx_cmd,
compiler_so_cxx=cxx_cmd + ' ' + ccshared,
linker_so=ldshared,
linker_so_cxx=ldcxxshared,
linker_exe=cc,
linker_exe_cxx=cxx,
archiver=archiver,
)

Expand Down Expand Up @@ -561,3 +569,14 @@ def get_config_var(name):

warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
return get_config_vars().get(name)


@pass_none
def _add_flags(value: str, type: str) -> str:
"""
Add any flags from the environment for the given type.
type is the prefix to FLAGS in the environment key (e.g. "C" for "CFLAGS").
"""
flags = os.environ.get(f'{type}FLAGS')
return f'{value} {flags}' if flags else value
7 changes: 5 additions & 2 deletions distutils/tests/test_sysconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ def test_customize_compiler(self):
assert comp.exes['compiler_so'] == (
'env_cc --sc-cflags --env-cflags --env-cppflags --sc-ccshared'
)
assert comp.exes['compiler_cxx'] == 'env_cxx --env-cxx-flags'
assert (
comp.exes['compiler_cxx']
== 'env_cxx --env-cxx-flags --sc-cflags --env-cppflags'
)
assert comp.exes['linker_exe'] == 'env_cc'
assert comp.exes['linker_so'] == (
'env_ldshared --env-ldflags --env-cflags --env-cppflags'
Expand Down Expand Up @@ -162,7 +165,7 @@ def test_customize_compiler(self):
assert comp.exes['preprocessor'] == 'sc_cc -E'
assert comp.exes['compiler'] == 'sc_cc --sc-cflags'
assert comp.exes['compiler_so'] == 'sc_cc --sc-cflags --sc-ccshared'
assert comp.exes['compiler_cxx'] == 'sc_cxx'
assert comp.exes['compiler_cxx'] == 'sc_cxx --sc-cflags'
assert comp.exes['linker_exe'] == 'sc_cc'
assert comp.exes['linker_so'] == 'sc_ldshared'
assert comp.shared_lib_extension == 'sc_shutil_suffix'
Expand Down
6 changes: 5 additions & 1 deletion distutils/tests/test_unixccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,13 @@ def test_cc_overrides_ldshared_for_cxx_correctly(self):
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'
return 'gcc-4.2'
elif v == 'CC':
return 'gcc-4.2'
return ''

def gcvs(*args, _orig=sysconfig.get_config_vars):
if args:
Expand Down
21 changes: 18 additions & 3 deletions distutils/unixccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,12 @@ class UnixCCompiler(CCompiler):
'preprocessor': None,
'compiler': ["cc"],
'compiler_so': ["cc"],
'compiler_cxx': ["cc"],
'compiler_cxx': ["c++"],
'compiler_so_cxx': ["c++"],
'linker_so': ["cc", "-shared"],
'linker_so_cxx': ["c++", "-shared"],
'linker_exe': ["cc"],
'linker_exe_cxx': ["c++", "-shared"],
'archiver': ["ar", "-cr"],
'ranlib': None,
}
Expand Down Expand Up @@ -187,8 +190,14 @@ def preprocess(

def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
compiler_so = compiler_fixup(self.compiler_so, cc_args + extra_postargs)
compiler_so_cxx = compiler_fixup(self.compiler_so_cxx, cc_args + extra_postargs)
try:
self.spawn(compiler_so + cc_args + [src, '-o', obj] + extra_postargs)
if self.detect_language(src) == 'c++':
self.spawn(
compiler_so_cxx + cc_args + [src, '-o', obj] + extra_postargs
)
else:
self.spawn(compiler_so + cc_args + [src, '-o', obj] + extra_postargs)
except DistutilsExecError as msg:
raise CompileError(msg)

Expand Down Expand Up @@ -256,7 +265,13 @@ def link(
# building an executable or linker_so (with shared options)
# when building a shared library.
building_exe = target_desc == CCompiler.EXECUTABLE
linker = (self.linker_exe if building_exe else self.linker_so)[:]
linker = (
self.linker_exe
if building_exe
else (
self.linker_so_cxx if target_lang == "c++" else self.linker_so
)
)[:]

if target_lang == "c++" and self.compiler_cxx:
env, linker_ne = _split_env(linker)
Expand Down

0 comments on commit fc76caa

Please sign in to comment.