Skip to content
Snippets Groups Projects
Commit b2362798 authored by Masood Malekghassemi's avatar Masood Malekghassemi
Browse files

Patch `spawn` for Python 'unix' compilers instead

Before we patched the link command, now we just patch `spawn` as an
updatable catch-all solution to ARG_MAX limitations on bash for MSYS and
MinGW and friends.
parent 24ae8eaa
No related branches found
No related tags found
No related merge requests found
...@@ -62,8 +62,8 @@ import commands ...@@ -62,8 +62,8 @@ import commands
import grpc_core_dependencies import grpc_core_dependencies
import grpc_version import grpc_version
# TODO(atash) make this conditional on being on a mingw32 build if 'win32' in sys.platform:
_unixccompiler_patch.monkeypatch_unix_compiler() _unixccompiler_patch.monkeypatch_unix_compiler()
LICENSE = '3-clause BSD' LICENSE = '3-clause BSD'
......
...@@ -38,84 +38,36 @@ import shutil ...@@ -38,84 +38,36 @@ import shutil
import sys import sys
import tempfile import tempfile
def _unix_commandfile_spawn(self, command):
"""Wrapper around distutils.util.spawn that attempts to use command files.
def _unix_piecemeal_link( Meant to replace the CCompiler method `spawn` on UnixCCompiler and its
self, target_desc, objects, output_filename, output_dir=None, derivatives (e.g. the MinGW32 compiler).
libraries=None, library_dirs=None, runtime_library_dirs=None,
export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None,
build_temp=None, target_lang=None):
"""`link` externalized method taken almost verbatim from UnixCCompiler.
Modifies the link command for unix-like compilers by using a command file so Some commands like `gcc` (and friends like `clang`) support command files to
that long command line argument strings don't break the command shell's work around shell command length limits.
ARG_MAX character limit.
""" """
objects, output_dir = self._fix_object_args(objects, output_dir) command_base = os.path.basename(command[0].strip())
libraries, library_dirs, runtime_library_dirs = self._fix_lib_args( if command_base == 'ccache':
libraries, library_dirs, runtime_library_dirs) command_base = command[:2]
# filter out standard library paths, which are not explicitely needed command_args = command[2:]
# for linking elif command_base.startswith('ccache') or command_base in ['gcc', 'clang', 'clang++', 'g++']:
library_dirs = [dir for dir in library_dirs command_base = command[:1]
if not dir in ('/lib', '/lib64', '/usr/lib', '/usr/lib64')] command_args = command[1:]
runtime_library_dirs = [dir for dir in runtime_library_dirs
if not dir in ('/lib', '/lib64', '/usr/lib', '/usr/lib64')]
lib_opts = ccompiler.gen_lib_options(self, library_dirs, runtime_library_dirs,
libraries)
if (not (isinstance(output_dir, str) or isinstance(output_dir, bytes))
and output_dir is not None):
raise TypeError("'output_dir' must be a string or None")
if output_dir is not None:
output_filename = os.path.join(output_dir, output_filename)
if self._need_link(objects, output_filename):
ld_args = (objects + self.objects +
lib_opts + ['-o', output_filename])
if debug:
ld_args[:0] = ['-g']
if extra_preargs:
ld_args[:0] = extra_preargs
if extra_postargs:
ld_args.extend(extra_postargs)
self.mkpath(os.path.dirname(output_filename))
try:
if target_desc == ccompiler.CCompiler.EXECUTABLE:
linker = self.linker_exe[:]
else:
linker = self.linker_so[:]
if target_lang == "c++" and self.compiler_cxx:
# skip over environment variable settings if /usr/bin/env
# is used to set up the linker's environment.
# This is needed on OSX. Note: this assumes that the
# normal and C++ compiler have the same environment
# settings.
i = 0
if os.path.basename(linker[0]) == "env":
i = 1
while '=' in linker[i]:
i = i + 1
linker[i] = self.compiler_cxx[i]
if sys.platform == 'darwin':
import _osx_support
linker = _osx_support.compiler_fixup(linker, ld_args)
temporary_directory = tempfile.mkdtemp()
command_filename = os.path.abspath(
os.path.join(temporary_directory, 'command'))
with open(command_filename, 'w') as command_file:
escaped_ld_args = [arg.replace('\\', '\\\\') for arg in ld_args]
command_file.write(' '.join(escaped_ld_args))
self.spawn(linker + ['@{}'.format(command_filename)])
except errors.DistutilsExecError:
raise ccompiler.LinkError
else: else:
log.debug("skipping %s (up-to-date)", output_filename) return ccompiler.CCompiler.spawn(self, command)
temporary_directory = tempfile.mkdtemp()
command_filename = os.path.abspath(os.path.join(temporary_directory, 'command'))
with open(command_filename, 'w') as command_file:
escaped_args = [arg.replace('\\', '\\\\') for arg in command_args]
command_file.write(' '.join(escaped_args))
modified_command = command_base + ['@{}'.format(command_filename)]
result = ccompiler.CCompiler.spawn(self, modified_command)
shutil.rmtree(temporary_directory)
return result
# TODO(atash) try replacing this monkeypatch of the compiler harness' link
# operation with a monkeypatch of the distutils `spawn` that applies
# command-argument-file hacks where it can. Might be cleaner.
def monkeypatch_unix_compiler(): def monkeypatch_unix_compiler():
"""Monkeypatching is dumb, but it's either that or we become maintainers of """Monkeypatching is dumb, but it's either that or we become maintainers of
something much, much bigger.""" something much, much bigger."""
unixccompiler.UnixCCompiler.link = _unix_piecemeal_link unixccompiler.UnixCCompiler.spawn = _unix_commandfile_spawn
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment