_spawn_patch.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. # Copyright 2016 gRPC authors.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Patches the spawn() command for windows compilers.
  15. Windows has an 8191 character command line limit, but some compilers
  16. support an @command_file directive where command_file is a file
  17. containing the full command line.
  18. """
  19. from distutils import ccompiler
  20. import os
  21. import os.path
  22. import shutil
  23. import sys
  24. import tempfile
  25. MAX_COMMAND_LENGTH = 8191
  26. _classic_spawn = ccompiler.CCompiler.spawn
  27. def _commandfile_spawn(self, command):
  28. command_length = sum([len(arg) for arg in command])
  29. if os.name == 'nt' and command_length > MAX_COMMAND_LENGTH:
  30. # Even if this command doesn't support the @command_file, it will
  31. # fail as is so we try blindly
  32. print('Command line length exceeded, using command file')
  33. print(' '.join(command))
  34. temporary_directory = tempfile.mkdtemp()
  35. command_filename = os.path.abspath(
  36. os.path.join(temporary_directory, 'command'))
  37. with open(command_filename, 'w') as command_file:
  38. escaped_args = [
  39. '"' + arg.replace('\\', '\\\\') + '"' for arg in command[1:]
  40. ]
  41. command_file.write(' '.join(escaped_args))
  42. modified_command = command[:1] + ['@{}'.format(command_filename)]
  43. try:
  44. _classic_spawn(self, modified_command)
  45. finally:
  46. shutil.rmtree(temporary_directory)
  47. else:
  48. _classic_spawn(self, command)
  49. def monkeypatch_spawn():
  50. """Monkeypatching is dumb, but it's either that or we become maintainers of
  51. something much, much bigger."""
  52. ccompiler.CCompiler.spawn = _commandfile_spawn