Index: llvm/utils/gn/.gitignore =================================================================== --- /dev/null +++ llvm/utils/gn/.gitignore @@ -0,0 +1 @@ +bin Index: llvm/utils/gn/README.rst =================================================================== --- llvm/utils/gn/README.rst +++ llvm/utils/gn/README.rst @@ -42,7 +42,11 @@ GN only works in the monorepo layout. -#. Obtain a `gn binary `_. +#. 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 + Linux, macOS, or Windows, or `build gn yourself + `_ 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 Index: llvm/utils/gn/get.py =================================================================== --- /dev/null +++ llvm/utils/gn/get.py @@ -0,0 +1,63 @@ +#!/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()) Index: llvm/utils/gn/gn.py =================================================================== --- llvm/utils/gn/gn.py +++ llvm/utils/gn/gn.py @@ -15,10 +15,38 @@ 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 = []