1# Copyright 2018 The Chromium Authors. All rights reserved. 2# Use of this source code is governed under the Apache License, Version 2.0 3# that can be found in the LICENSE file. 4"""Recipe for building GN.""" 5 6from recipe_engine.recipe_api import Property 7 8DEPS = [ 9 'recipe_engine/buildbucket', 10 'recipe_engine/cipd', 11 'recipe_engine/context', 12 'recipe_engine/file', 13 'recipe_engine/json', 14 'recipe_engine/path', 15 'recipe_engine/platform', 16 'recipe_engine/properties', 17 'recipe_engine/python', 18 'recipe_engine/raw_io', 19 'recipe_engine/step', 20 'macos_sdk', 21 'windows_sdk', 22] 23 24PROPERTIES = { 25 'repository': Property(kind=str, default='https://gn.googlesource.com/gn'), 26} 27 28 29def RunSteps(api, repository): 30 src_dir = api.path['start_dir'].join('gn') 31 32 with api.step.nest('git'), api.context(infra_steps=True): 33 api.step('init', ['git', 'init', src_dir]) 34 35 with api.context(cwd=src_dir): 36 build_input = api.buildbucket.build_input 37 ref = ( 38 build_input.gitiles_commit.id 39 if build_input.gitiles_commit else 'refs/heads/master') 40 # Fetch tags so `git describe` works. 41 api.step('fetch', ['git', 'fetch', '--tags', repository, ref]) 42 api.step('checkout', ['git', 'checkout', 'FETCH_HEAD']) 43 for change in build_input.gerrit_changes: 44 api.step('fetch %s/%s' % (change.change, change.patchset), [ 45 'git', 'fetch', repository, 46 'refs/changes/%s/%s/%s' % 47 (str(change.change)[-2:], change.change, change.patchset) 48 ]) 49 api.step('cherry-pick %s/%s' % (change.change, change.patchset), 50 ['git', 'cherry-pick', 'FETCH_HEAD']) 51 52 with api.context(infra_steps=True): 53 cipd_dir = api.path['start_dir'].join('cipd') 54 pkgs = api.cipd.EnsureFile() 55 pkgs.add_package('infra/ninja/${platform}', 'version:1.8.2') 56 if api.platform.is_linux or api.platform.is_mac: 57 pkgs.add_package('fuchsia/clang/${platform}', 58 'git_revision:b920a7f65b13237dc4d5b2b836b29a954fff440a') 59 if api.platform.is_linux: 60 pkgs.add_package('fuchsia/sysroot/${platform}', 61 'git_revision:a28dfa20af063e5ca00634024c85732e20220419', 62 'sysroot') 63 api.cipd.ensure(cipd_dir, pkgs) 64 65 # The order is important since release build will get uploaded to CIPD. 66 configs = [ 67 { 68 'name': 'debug', 69 'args': ['-d'] 70 }, 71 { 72 'name': 'release', 73 'args': ['--use-lto', '--use-icf'] 74 }, 75 ] 76 77 with api.macos_sdk(), api.windows_sdk(): 78 if api.platform.is_linux: 79 sysroot = '--sysroot=%s' % cipd_dir.join('sysroot') 80 env = { 81 'CC': cipd_dir.join('bin', 'clang'), 82 'CXX': cipd_dir.join('bin', 'clang++'), 83 'AR': cipd_dir.join('bin', 'llvm-ar'), 84 'CFLAGS': sysroot, 85 'LDFLAGS': sysroot, 86 } 87 elif api.platform.is_mac: 88 sysroot = '--sysroot=%s' % api.step( 89 'xcrun', ['xcrun', '--show-sdk-path'], 90 stdout=api.raw_io.output(name='sdk-path', add_output_log=True), 91 step_test_data= 92 lambda: api.raw_io.test_api.stream_output('/some/xcode/path') 93 ).stdout.strip() 94 stdlib = '-nostdlib++ %s' % cipd_dir.join('lib', 'libc++.a') 95 env = { 96 'CC': cipd_dir.join('bin', 'clang'), 97 'CXX': cipd_dir.join('bin', 'clang++'), 98 'AR': cipd_dir.join('bin', 'llvm-ar'), 99 'CFLAGS': sysroot, 100 'LDFLAGS': '%s %s' % (sysroot, stdlib), 101 } 102 else: 103 env = {} 104 105 for config in configs: 106 with api.step.nest(config['name']): 107 with api.step.nest('build'), api.context(env=env, cwd=src_dir): 108 api.python( 109 'generate', src_dir.join('build', 'gen.py'), args=config['args']) 110 111 # Windows requires the environment modifications when building too. 112 api.step('ninja', [cipd_dir.join('ninja'), '-C', src_dir.join('out')]) 113 114 api.step('test', [src_dir.join('out', 'gn_unittests')]) 115 116 if build_input.gerrit_changes: 117 return 118 119 cipd_pkg_name = 'gn/gn/${platform}' 120 gn = 'gn' + ('.exe' if api.platform.is_win else '') 121 122 pkg_def = api.cipd.PackageDefinition( 123 package_name=cipd_pkg_name, 124 package_root=src_dir.join('out'), 125 install_mode='copy') 126 pkg_def.add_file(src_dir.join('out', gn)) 127 pkg_def.add_version_file('.versions/%s.cipd_version' % gn) 128 129 cipd_pkg_file = api.path['cleanup'].join('gn.cipd') 130 131 api.cipd.build_from_pkg( 132 pkg_def=pkg_def, 133 output_package=cipd_pkg_file, 134 ) 135 136 if api.buildbucket.builder_id.project == 'infra-internal': 137 with api.context(cwd=src_dir): 138 revision = api.step( 139 'rev-parse', ['git', 'rev-parse', 'HEAD'], 140 stdout=api.raw_io.output()).stdout.strip() 141 142 cipd_pin = api.cipd.search(cipd_pkg_name, 'git_revision:' + revision) 143 if cipd_pin: 144 api.step('Package is up-to-date', cmd=None) 145 return 146 147 api.cipd.register( 148 package_name=cipd_pkg_name, 149 package_path=cipd_pkg_file, 150 refs=['latest'], 151 tags={ 152 'git_repository': repository, 153 'git_revision': revision, 154 }, 155 ) 156 157 158def GenTests(api): 159 for platform in ('linux', 'mac', 'win'): 160 yield (api.test('ci_' + platform) + api.platform.name(platform) + 161 api.buildbucket.ci_build( 162 project='gn', 163 git_repo='gn.googlesource.com/gn', 164 )) 165 166 yield (api.test('cq_' + platform) + api.platform.name(platform) + 167 api.buildbucket.try_build( 168 project='gn', 169 git_repo='gn.googlesource.com/gn', 170 )) 171 172 yield (api.test('cipd_exists') + api.buildbucket.ci_build( 173 project='infra-internal', 174 git_repo='gn.googlesource.com/gn', 175 revision='a' * 40, 176 ) + api.step_data('rev-parse', api.raw_io.stream_output('a' * 40)) + 177 api.step_data('cipd search gn/gn/${platform} git_revision:' + 'a' * 40, 178 api.cipd.example_search('gn/gn/linux-amd64', 179 ['git_revision:' + 'a' * 40]))) 180 181 yield (api.test('cipd_register') + api.buildbucket.ci_build( 182 project='infra-internal', 183 git_repo='gn.googlesource.com/gn', 184 revision='a' * 40, 185 ) + api.step_data('rev-parse', api.raw_io.stream_output('a' * 40)) + 186 api.step_data('cipd search gn/gn/${platform} git_revision:' + 'a' * 40, 187 api.cipd.example_search('gn/gn/linux-amd64', []))) 188