ninja.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #!/usr/bin/env python3
  2. # Copyright 2022 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """This script is a wrapper around the ninja binary that is pulled to
  6. third_party as part of gclient sync. It will automatically find the ninja
  7. binary when run inside a gclient source tree, so users can just type
  8. "ninja" on the command line."""
  9. import os
  10. import subprocess
  11. import sys
  12. import gclient_paths
  13. DEPOT_TOOLS_ROOT = os.path.abspath(os.path.dirname(__file__))
  14. def fallbackToLegacyNinja(ninja_args):
  15. print(
  16. 'depot_tools/ninja.py: Fallback to a deprecated legacy ninja binary. '
  17. 'Note that this ninja binary will be removed soon.\n'
  18. 'Please install ninja to your project using DEPS. '
  19. 'If your project does not have DEPS, Please install ninja in your PATH.\n'
  20. 'See also https://crbug.com/1340825',
  21. file=sys.stderr)
  22. exe_name = ''
  23. if sys.platform == 'linux':
  24. exe_name = 'ninja-linux64'
  25. elif sys.platform == 'darwin':
  26. exe_name = 'ninja-mac'
  27. elif sys.platform in ['win32', 'cygwin']:
  28. exe_name = 'ninja.exe'
  29. else:
  30. print('depot_tools/ninja.py: %s is not supported platform' % sys.platform)
  31. return 1
  32. ninja_path = os.path.join(DEPOT_TOOLS_ROOT, exe_name)
  33. return subprocess.call([ninja_path] + ninja_args)
  34. def findNinjaInPath():
  35. env_path = os.getenv('PATH')
  36. if not env_path:
  37. return
  38. exe = 'ninja'
  39. if sys.platform in ['win32', 'cygwin']:
  40. exe += '.exe'
  41. for bin_dir in env_path.split(os.pathsep):
  42. if bin_dir.rstrip(os.sep).endswith('depot_tools'):
  43. # skip depot_tools to avoid calling ninja.py infitely.
  44. continue
  45. ninja_path = os.path.join(bin_dir, exe)
  46. if os.path.isfile(ninja_path):
  47. return ninja_path
  48. def fallback(ninja_args):
  49. # Try to find ninja in PATH.
  50. ninja_path = findNinjaInPath()
  51. if ninja_path:
  52. return subprocess.call([ninja_path] + ninja_args)
  53. # TODO(crbug.com/1340825): remove raw binaries from depot_tools.
  54. return fallbackToLegacyNinja(ninja_args)
  55. def main(args):
  56. # On Windows the ninja.bat script passes along the arguments enclosed in
  57. # double quotes. This prevents multiple levels of parsing of the special '^'
  58. # characters needed when compiling a single file. When this case is detected,
  59. # we need to split the argument. This means that arguments containing actual
  60. # spaces are not supported by ninja.bat, but that is not a real limitation.
  61. if (sys.platform.startswith('win') and len(args) == 2):
  62. args = args[:1] + args[1].split(' ')
  63. # Get gclient root + src.
  64. primary_solution_path = gclient_paths.GetPrimarySolutionPath()
  65. gclient_root_path = gclient_paths.FindGclientRoot(os.getcwd())
  66. for base_path in [primary_solution_path, gclient_root_path]:
  67. if not base_path:
  68. continue
  69. ninja_path = os.path.join(base_path, 'third_party', 'ninja',
  70. 'ninja' + gclient_paths.GetExeSuffix())
  71. if os.path.isfile(ninja_path):
  72. return subprocess.call([ninja_path] + args[1:])
  73. return fallback(args[1:])
  74. if __name__ == '__main__':
  75. try:
  76. sys.exit(main(sys.argv))
  77. except KeyboardInterrupt:
  78. sys.exit(1)