GN only works in the monorepo layout.
-#. Obtain a `gn binary <https://gn.googlesource.com/gn/#getting-started>`_.
+#. Obtain a gn binary. If gn is not already on your PATH, run
+ `llvm/utils/gn/get.py` to download a prebuilt gn binary if you're on a 64-bit
+ X86 system running Linux, macOS, or Windows, or `build gn yourself
+ <https://gn.googlesource.com/gn/#getting-started>`_ if you're on a different
+ platform or don't want to trust prebuilt binaries.
#. In the root of the monorepo, run `llvm/utils/gn/gn.py gen out/gn`.
`out/gn` is the build directory, it can have any name, and you can have as
--- /dev/null
+#!/usr/bin/env python
+"""Downloads a prebuilt gn binary to a place where gn.py can find it."""
+
+from __future__ import print_function
+
+import os
+import urllib2
+import sys
+import tempfile
+import zipfile
+
+
+def download_url(url, output_file):
+ """Download url into output_file."""
+ print('downloading %s ...' % url, end='')
+ sys.stdout.flush()
+ output_file.write(urllib2.urlopen(url).read())
+ print(' done')
+
+
+def download_and_unpack(url, output_dir, gn):
+ """Download an archive from url and extract gn from it into output_dir."""
+ with tempfile.TemporaryFile() as f:
+ download_url(url, f)
+ f.seek(0)
+ zipfile.ZipFile(f).extract(gn, path=output_dir)
+
+
+def set_executable_bit(path):
+ mode = os.stat(path).st_mode
+ mode |= (mode & 0o444) >> 2 # Copy R bits to X.
+ os.chmod(path, mode) # No-op on Windows.
+
+
+def get_platform():
+ if os.uname()[4] != 'x86_64':
+ return None
+ if sys.platform.startswith('linux'):
+ return 'linux-amd64'
+ if sys.platform == 'darwin':
+ return 'mac-amd64'
+ if sys.platform == 'win32':
+ return 'windows-amd64'
+
+
+def main():
+ platform = get_platform()
+ if not platform:
+ print('no prebuilt binary for', sys.platform)
+ return 1
+
+ dirname = os.path.join(os.path.dirname(__file__), 'bin', platform)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
+ url = 'https://chrome-infra-packages.appspot.com/dl/gn/gn/%s/+/latest'
+ gn = 'gn' + ('.exe' if sys.platform == 'win32' else '')
+ download_and_unpack(url % platform, dirname, gn)
+ set_executable_bit(os.path.join(dirname, gn))
+
+
+if __name__ == '__main__':
+ sys.exit(main())
ROOT_DIR = os.path.join(THIS_DIR, '..', '..', '..')
+def get_platform():
+ if os.uname()[4] != 'x86_64':
+ return None
+ if sys.platform.startswith('linux'):
+ return 'linux-amd64'
+ if sys.platform == 'darwin':
+ return 'mac-amd64'
+ if sys.platform == 'win32':
+ return 'windows-amd64'
+
+
+def print_no_gn(mention_get):
+ print('gn binary not found in PATH')
+ if mention_get:
+ print('run llvm/utils/gn/get.py to download a binary and try again, or')
+ print('follow https://gn.googlesource.com/gn/#getting-started')
+ return 1
+
+
def main():
- # Find real gn executable. For now, just assume it's on PATH.
- # FIXME: Probably need to append '.exe' on Windows.
+ # Find real gn executable.
gn = 'gn'
+ if subprocess.call([gn, '--version'], stdout=open(os.devnull, 'w'),
+ stderr=subprocess.STDOUT) != 0:
+ # Not on path. See if get.py downloaded a prebuilt binary and run that
+ # if it's there, or suggest to run get.py if it isn't.
+ platform = get_platform()
+ if not platform:
+ return print_no_gn(mention_get=False)
+ gn = os.path.join(os.path.dirname(__file__), 'bin', platform, 'gn')
+ if not os.path.exists(gn + ('.exe' if platform == 'windows' else '')):
+ return print_no_gn(mention_get=True)
# Compute --dotfile= and --root= args to add.
extra_args = []