From 285becfa4c25e803e809ded615ea5981d1d0dbcf Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 28 Jan 2019 19:54:41 +0000 Subject: [PATCH] gn build: Add get.py script to download prebuilt gn, make gn.py run downloaded gn if gn is not on PATH Prebuilts are available for x86_64 Linux, macOS, Windows. The script always pulls the latest GN version. Differential Revision: https://reviews.llvm.org/D57256 llvm-svn: 352420 --- llvm/utils/gn/.gitignore | 1 + llvm/utils/gn/README.rst | 6 +++- llvm/utils/gn/get.py | 63 ++++++++++++++++++++++++++++++++++++++++ llvm/utils/gn/gn.py | 32 ++++++++++++++++++-- 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 llvm/utils/gn/.gitignore create mode 100644 llvm/utils/gn/get.py diff --git a/llvm/utils/gn/.gitignore b/llvm/utils/gn/.gitignore new file mode 100644 index 000000000000..ba077a4031ad --- /dev/null +++ b/llvm/utils/gn/.gitignore @@ -0,0 +1 @@ +bin diff --git a/llvm/utils/gn/README.rst b/llvm/utils/gn/README.rst index 4d8051ff602d..3c40846689c2 100644 --- a/llvm/utils/gn/README.rst +++ b/llvm/utils/gn/README.rst @@ -42,7 +42,11 @@ Quick start 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 a 64-bit + X86 system running 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 diff --git a/llvm/utils/gn/get.py b/llvm/utils/gn/get.py new file mode 100644 index 000000000000..defeac98f2c1 --- /dev/null +++ b/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()) diff --git a/llvm/utils/gn/gn.py b/llvm/utils/gn/gn.py index f80873b3be80..f523e6443ea7 100755 --- a/llvm/utils/gn/gn.py +++ b/llvm/utils/gn/gn.py @@ -15,10 +15,38 @@ THIS_DIR = os.path.dirname(__file__) 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 = []