Skip to content

Commit 9af1d93

Browse files
tsullivanjoelgriffithkibanamachine
authored
[Build Chromium] Improve git checkout (#83225) (#87009)
* [Build Chromium] Document steps for local build, improve checkout commit e817796d107d554504870cdb8e6dd10db1079a1e Merge: 19e6b300260 61b4e052fdd Author: Timothy Sullivan <tsullivan@elastic.co> Date: Thu Nov 12 13:25:09 2020 -0700 Merge branch 'chore/build_chromium/improvements' of github.com:tsullivan/kibana into chore/build_chromium/improvements commit 19e6b300260822418cea4dc594bdfdf621a331e0 Author: Timothy Sullivan <tsullivan@elastic.co> Date: Thu Nov 12 13:23:01 2020 -0700 fixes commit 9de24ec298792a46e88207f41c9f6aff1997dbf1 Author: Timothy Sullivan <tsullivan@elastic.co> Date: Thu Nov 12 13:22:52 2020 -0700 add instructions to build local commit 872c0f68e0077ad50c541b605a87253befd1a891 Author: Timothy Sullivan <tsullivan@elastic.co> Date: Thu Nov 12 11:58:25 2020 -0700 simplify commit 8dae9484efcdc483ad20ceab32cae4e97735ab1c Author: Timothy Sullivan <tsullivan@elastic.co> Date: Thu Nov 12 10:28:18 2020 -0700 fixes commit 492f5cfe25e2c7ccffce55a8733383a30aae1cb6 Author: Timothy Sullivan <tsullivan@elastic.co> Date: Wed Nov 11 20:15:43 2020 -0700 --wip-- [skip ci] commit acba359b121f7be8e6c353f90e938bc5d88658a1 Author: Timothy Sullivan <tsullivan@elastic.co> Date: Wed Nov 11 15:47:50 2020 -0700 [Build Chromium] Improve git checkout commit 61b4e052fdd04456fe23956ad8ce99c8e771c01e Author: Timothy Sullivan <tsullivan@elastic.co> Date: Wed Nov 11 20:15:43 2020 -0700 --wip-- [skip ci] commit 58300c9deeca15cce838b3956c55c2994f99f530 Author: Timothy Sullivan <tsullivan@elastic.co> Date: Wed Nov 11 15:47:50 2020 -0700 [Build Chromium] Improve git checkout * Apply suggestions from code review Co-authored-by: Joel Griffith <joel@joelgriffith.net> Co-authored-by: Joel Griffith <joel@joelgriffith.net> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Joel Griffith <joel@joelgriffith.net> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
1 parent 8a08bc2 commit 9af1d93

File tree

4 files changed

+200
-92
lines changed

4 files changed

+200
-92
lines changed

x-pack/build_chromium/README.md

Lines changed: 85 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,105 @@
11
# Chromium build
22

3-
We ship our own headless build of Chromium which is significantly smaller than the standard binaries shipped by Google. The scripts in this folder can be used to initialize the build environments and run the build on Mac, Windows, and Linux.
3+
We ship our own headless build of Chromium which is significantly smaller than
4+
the standard binaries shipped by Google. The scripts in this folder can be used
5+
to accept a commit hash from the Chromium repository, and initialize the build
6+
environments and run the build on Mac, Windows, and Linux.
47

5-
The official Chromium build process is poorly documented, and seems to have breaking changes fairly regularly. The build pre-requisites, and the build flags change over time, so it is likely that the scripts in this directory will be out of date by the time we have to do another Chromium build.
6-
7-
This document is an attempt to note all of the gotchas we've come across while building, so that the next time we have to tinker here, we'll have a good starting point.
8-
9-
# Before you begin
10-
You'll need access to our GCP account, which is where we have two machines provisioned for the Linux and Windows builds. Mac builds can be achieved locally, and are a great place to start to gain familiarity.
8+
## Before you begin
9+
If you wish to use a remote VM to build, you'll need access to our GCP account,
10+
which is where we have two machines provisioned for the Linux and Windows
11+
builds. Mac builds can be achieved locally, and are a great place to start to
12+
gain familiarity.
1113

1214
1. Login to our GCP instance [here using your okta credentials](https://console.cloud.google.com/).
1315
2. Click the "Compute Engine" tab.
1416
3. Ensure that `chromium-build-linux` and `chromium-build-windows-12-beefy` are there.
1517
4. If #3 fails, you'll have to spin up new instances. Generally, these need `n1-standard-8` types or 8 vCPUs/30 GB memory.
1618
5. Ensure that there's enough room left on the disk. `ncdu` is a good linux util to verify what's claming space.
1719

20+
## Usage
21+
22+
```
23+
# Create a dedicated working directory for this directory of Python scripts.
24+
mkdir ~/chromium && cd ~/chromium
25+
# Copy the scripts from the Kibana repo to use them conveniently in the working directory
26+
cp -r ~/path/to/kibana/x-pack/build_chromium .
27+
# Install the OS packages, configure the environment, download the chromium source
28+
python ./build_chromium/init.sh [arch_name]
29+
30+
# Run the build script with the path to the chromium src directory, the git commit id
31+
python ./build_chromium/build.py <commit_id>
32+
33+
# You can add an architecture flag for ARM
34+
python ./build_chromium/build.py <commit_id> arm64
35+
```
36+
37+
## Getting the Commit ID
38+
Getting `<commit_id>` can be tricky. The best technique seems to be:
39+
1. Create a temporary working directory and intialize yarn
40+
2. `yarn add puppeteer # install latest puppeter`
41+
3. Look through puppeteer's node module files to find the "chromium revision" (a custom versioning convention for Chromium).
42+
4. Use `https://crrev.com` and look up the revision and find the git commit info.
43+
44+
The official Chromium build process is poorly documented, and seems to have
45+
breaking changes fairly regularly. The build pre-requisites, and the build
46+
flags change over time, so it is likely that the scripts in this directory will
47+
be out of date by the time we have to do another Chromium build.
48+
49+
This document is an attempt to note all of the gotchas we've come across while
50+
building, so that the next time we have to tinker here, we'll have a good
51+
starting point.
52+
1853
## Build args
1954

20-
Chromium is built via a build tool called "ninja". The build can be configured by specifying build flags either in an "args.gn" file or via commandline args. We have an "args.gn" file per platform:
55+
A good how-to on building Chromium from source is
56+
[here](https://chromium.googlesource.com/chromium/src/+/master/docs/get_the_code.md).
57+
58+
There are documents for each OS that will explain how to customize arguments
59+
for the build using the `gn` tool. Those instructions do not apply for the
60+
Kibana Chromium build. Our `build.py` script ensure the correct `args.gn`
61+
file gets used for build arguments.
2162

22-
- mac: darwin/args.gn
23-
- linux 64bit: linux-x64/args.gn
63+
We have an `args.gn` file per platform:
64+
65+
- mac: `darwin/args.gn`
66+
- linux 64bit: `linux-x64/args.gn`
67+
- windows: `windows/args.gn`
2468
- ARM 64bit: linux-aarch64/args.gn
25-
- windows: windows/args.gn
2669

27-
The various build flags are not well documented. Some are documented [here](https://www.chromium.org/developers/gn-build-configuration). Some, such as `enable_basic_printing = false`, I only found by poking through 3rd party build scripts.
70+
To get a list of the build arguments that are enabled, install `depot_tools` and run
71+
`gn args out/headless --list`. It prints out all of the flags and their
72+
settings, including the defaults.
73+
74+
The various build flags are not well documented. Some are documented
75+
[here](https://www.chromium.org/developers/gn-build-configuration).
2876

29-
As of this writing, there is an officially supported headless Chromium build args file for Linux: `build/args/headless.gn`. This does not work on Windows or Mac, so we have taken that as our starting point, and modified it until the Windows / Mac builds succeeded.
77+
As of this writing, there is an officially supported headless Chromium build
78+
args file for Linux: `build/args/headless.gn`. This does not work on Windows or
79+
Mac, so we have taken that as our starting point, and modified it until the
80+
Windows / Mac builds succeeded.
3081

3182
**NOTE:** Please, make sure you consult @elastic/kibana-security before you change, remove or add any of the build flags.
3283

84+
## Building locally
85+
86+
You can skip the step of running `<os_name>/init.sh` for your OS if you already
87+
have your environment set up, and the chromium source cloned.
88+
89+
To get the Chromium code, refer to the [documentation](https://chromium.googlesource.com/chromium/src/+/master/docs/get_the_code.md).
90+
Install `depot_tools` as suggested, since it comes with useful scripts. Use the
91+
`fetch` command to clone the chromium repository. To set up and run the build,
92+
use the Kibana `build.py` script (in this directory).
93+
94+
It's recommended that you create a working directory for the chromium source
95+
code and all the build tools, and run the commands from there:
96+
```
97+
mkdir ~/chromium && cd ~/chromium
98+
cp -r ~/path/to/kibana/x-pack/build_chromium .
99+
python ./build_chromium/init.sh [arch_name]
100+
python ./build_chromium/build.py <commit_id>
101+
```
102+
33103
## VMs
34104

35105
I ran Linux and Windows VMs in GCP with the following specs:
@@ -57,7 +127,8 @@ The more cores the better, as the build makes effective use of each. For Linux,
57127

58128
## Initializing each VM / environment
59129

60-
You only need to initialize each environment once. NOTE: on Mac OS you'll need to install XCode and accept the license agreement.
130+
In a VM, you'll want to use the init scripts to to initialize each environment.
131+
On Mac OS you'll need to install XCode and accept the license agreement.
61132

62133
Create the build folder:
63134

@@ -86,16 +157,6 @@ In windows, at least, you will need to do a number of extra steps:
86157

87158
## Building
88159

89-
Find the sha of the Chromium commit you wish to build. Most likely, you want to build the Chromium revision that is tied to the version of puppeteer that we're using.
90-
91-
Find the Chromium revision (run in kibana's working directory):
92-
93-
- `cat node_modules/puppeteer-core/package.json | grep chromium_revision`
94-
- Take the revision number from that, and tack it to the end of this URL: https://crrev.com
95-
- (For example, puppeteer@1.19.0 has rev (674921): https://crrev.com/674921)
96-
- Grab the SHA from there
97-
- (For example, rev 674921 has sha 312d84c8ce62810976feda0d3457108a6dfff9e6)
98-
99160
Note: In Linux, you should run the build command in tmux so that if your ssh session disconnects, the build can keep going. To do this, just type `tmux` into your terminal to hop into a tmux session. If you get disconnected, you can hop back in like so:
100161

101162
- SSH into the server

x-pack/build_chromium/build.py

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,80 @@
1-
import subprocess, os, sys, platform, zipfile, hashlib, shutil
2-
from build_util import runcmd, mkdir, md5_file, script_dir, root_dir, configure_environment
1+
import os, subprocess, sys, platform, zipfile, hashlib, shutil
2+
from os import path
3+
from build_util import (
4+
runcmd,
5+
runcmdsilent,
6+
mkdir,
7+
md5_file,
8+
configure_environment,
9+
)
310

411
# This file builds Chromium headless on Windows, Mac, and Linux.
512

613
# Verify that we have an argument, and if not print instructions
714
if (len(sys.argv) < 2):
815
print('Usage:')
9-
print('python build.py {chromium_version}')
16+
print('python build.py {chromium_version} [arch_name]')
1017
print('Example:')
1118
print('python build.py 68.0.3440.106')
1219
print('python build.py 4747cc23ae334a57a35ed3c8e6adcdbc8a50d479')
20+
print('python build.py 4747cc23ae334a57a35ed3c8e6adcdbc8a50d479 arm64 # build for ARM architecture')
21+
print
1322
sys.exit(1)
1423

24+
src_path = path.abspath(path.join(os.curdir, 'chromium', 'src'))
25+
build_path = path.abspath(path.join(src_path, '..', '..'))
26+
build_chromium_path = path.abspath(path.dirname(__file__))
27+
argsgn_file = path.join(build_chromium_path, platform.system().lower(), 'args.gn')
28+
1529
# The version of Chromium we wish to build. This can be any valid git
1630
# commit, tag, or branch, so: 68.0.3440.106 or
1731
# 4747cc23ae334a57a35ed3c8e6adcdbc8a50d479
1832
source_version = sys.argv[1]
33+
base_version = source_version[:7].strip('.')
1934

2035
# Set to "arm" to build for ARM on Linux
2136
arch_name = sys.argv[2] if len(sys.argv) >= 3 else 'x64'
2237

23-
print('Building Chromium ' + source_version + ' for ' + arch_name)
24-
25-
# Set the environment variables required by the build tools
26-
print('Configuring the build environment')
27-
configure_environment()
28-
29-
# Sync the codebase to the correct version, syncing master first
30-
# to ensure that we actually have all the versions we may refer to
31-
print('Syncing source code')
32-
33-
os.chdir(os.path.join(root_dir, 'chromium/src'))
34-
35-
runcmd('git checkout master')
36-
runcmd('git fetch origin')
37-
runcmd('gclient sync --with_branch_heads --with_tags --jobs 16')
38-
runcmd('git checkout ' + source_version)
39-
runcmd('gclient sync --with_branch_heads --with_tags --jobs 16')
40-
runcmd('gclient runhooks')
38+
if arch_name != 'x64' and arch_name != 'arm64':
39+
raise Exception('Unexpected architecture: ' + arch_name)
40+
41+
print('Building Chromium ' + source_version + ' for ' + arch_name + ' from ' + src_path)
42+
print('src path: ' + src_path)
43+
print('depot_tools path: ' + path.join(build_path, 'depot_tools'))
44+
print('build_chromium_path: ' + build_chromium_path)
45+
print('args.gn file: ' + argsgn_file)
46+
print
47+
48+
# Sync the codebase to the correct version
49+
print('Setting local tracking branch')
50+
print(' > cd ' + src_path)
51+
os.chdir(src_path)
52+
53+
checked_out = runcmdsilent('git checkout build-' + base_version)
54+
if checked_out != 0:
55+
print('Syncing remote version')
56+
runcmd('git fetch origin ' + source_version)
57+
print('Creating a new branch for tracking the source version')
58+
runcmd('git checkout -b build-' + base_version + ' ' + source_version)
59+
60+
depot_tools_path = os.path.join(build_path, 'depot_tools')
61+
path_value = depot_tools_path + os.pathsep + os.environ['PATH']
62+
print('Updating PATH for depot_tools: ' + path_value)
63+
os.environ['PATH'] = path_value
64+
print('Updating all modules')
65+
runcmd('gclient sync')
4166

4267
# Copy build args/{Linux | Darwin | Windows}.gn from the root of our directory to out/headless/args.gn,
43-
platform_build_args = os.path.join(script_dir, platform.system().lower(), 'args.gn')
68+
argsgn_destination = path.abspath('out/headless/args.gn')
4469
print('Generating platform-specific args')
45-
print('Copying build args: ' + platform_build_args + ' to out/headless/args.gn')
4670
mkdir('out/headless')
47-
shutil.copyfile(platform_build_args, 'out/headless/args.gn')
71+
print(' > cp ' + argsgn_file + ' ' + argsgn_destination)
72+
shutil.copyfile(argsgn_file, argsgn_destination)
4873

4974
print('Adding target_cpu to args')
5075

5176
f = open('out/headless/args.gn', 'a')
52-
f.write('\rtarget_cpu = "' + arch_name + '"')
77+
f.write('\rtarget_cpu = "' + arch_name + '"\r')
5378
f.close()
5479

5580
runcmd('gn gen out/headless')
@@ -67,37 +92,38 @@
6792

6893
# Create the zip and generate the md5 hash using filenames like:
6994
# chromium-4747cc2-linux_x64.zip
70-
base_filename = 'out/headless/chromium-' + source_version[:7].strip('.') + '-' + platform.system().lower() + '_' + arch_name
95+
base_filename = 'out/headless/chromium-' + base_version + '-' + platform.system().lower() + '_' + arch_name
7196
zip_filename = base_filename + '.zip'
7297
md5_filename = base_filename + '.md5'
7398

74-
print('Creating ' + zip_filename)
99+
print('Creating ' + path.join(src_path, zip_filename))
75100
archive = zipfile.ZipFile(zip_filename, mode='w', compression=zipfile.ZIP_DEFLATED)
76101

77102
def archive_file(name):
78103
"""A little helper function to write individual files to the zip file"""
79-
from_path = os.path.join('out/headless', name)
80-
to_path = os.path.join('headless_shell-' + platform.system().lower() + '_' + arch_name, name)
104+
from_path = path.join('out/headless', name)
105+
to_path = path.join('headless_shell-' + platform.system().lower() + '_' + arch_name, name)
81106
archive.write(from_path, to_path)
107+
return to_path
82108

83109
# Each platform has slightly different requirements for what dependencies
84110
# must be bundled with the Chromium executable.
85111
if platform.system() == 'Linux':
86112
archive_file('headless_shell')
87-
archive_file(os.path.join('swiftshader', 'libEGL.so'))
88-
archive_file(os.path.join('swiftshader', 'libGLESv2.so'))
113+
archive_file(path.join('swiftshader', 'libEGL.so'))
114+
archive_file(path.join('swiftshader', 'libGLESv2.so'))
89115

90116
if arch_name == 'arm64':
91-
archive_file(os.path.join('swiftshader', 'libEGL.so'))
117+
archive_file(path.join('swiftshader', 'libEGL.so'))
92118

93119
elif platform.system() == 'Windows':
94120
archive_file('headless_shell.exe')
95121
archive_file('dbghelp.dll')
96122
archive_file('icudtl.dat')
97-
archive_file(os.path.join('swiftshader', 'libEGL.dll'))
98-
archive_file(os.path.join('swiftshader', 'libEGL.dll.lib'))
99-
archive_file(os.path.join('swiftshader', 'libGLESv2.dll'))
100-
archive_file(os.path.join('swiftshader', 'libGLESv2.dll.lib'))
123+
archive_file(path.join('swiftshader', 'libEGL.dll'))
124+
archive_file(path.join('swiftshader', 'libEGL.dll.lib'))
125+
archive_file(path.join('swiftshader', 'libGLESv2.dll'))
126+
archive_file(path.join('swiftshader', 'libGLESv2.dll.lib'))
101127

102128
elif platform.system() == 'Darwin':
103129
archive_file('headless_shell')
@@ -107,6 +133,6 @@ def archive_file(name):
107133

108134
archive.close()
109135

110-
print('Creating ' + md5_filename)
136+
print('Creating ' + path.join(src_path, md5_filename))
111137
with open (md5_filename, 'w') as f:
112138
f.write(md5_file(zip_filename))
Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,45 @@
1-
import os, hashlib
1+
import os, hashlib, platform, sys
22

33
# This file contains various utility functions used by the init and build scripts
44

5-
# Compute the root build and script directory as relative to this file
6-
script_dir = os.path.realpath(os.path.join(__file__, '..'))
7-
root_dir = os.path.realpath(os.path.join(script_dir, '..'))
5+
def runcmdsilent(cmd):
6+
"""Executes a string command in the shell"""
7+
print(' > ' + cmd)
8+
return os.system(cmd)
89

910
def runcmd(cmd):
1011
"""Executes a string command in the shell"""
11-
print(cmd)
12+
print(' > ' + cmd)
1213
result = os.system(cmd)
1314
if result != 0:
1415
raise Exception(cmd + ' returned ' + str(result))
1516

1617
def mkdir(dir):
18+
print(' > mkdir -p ' + dir)
1719
"""Makes a directory if it doesn't exist"""
1820
if not os.path.exists(dir):
19-
print('mkdir -p ' + dir)
2021
return os.makedirs(dir)
2122

2223
def md5_file(filename):
2324
"""Builds a hex md5 hash of the given file"""
2425
md5 = hashlib.md5()
25-
with open(filename, 'rb') as f:
26-
for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
26+
with open(filename, 'rb') as f:
27+
for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
2728
md5.update(chunk)
2829
return md5.hexdigest()
2930

30-
def configure_environment():
31-
"""Configures temporary environment variables required by Chromium's build"""
32-
depot_tools_path = os.path.join(root_dir, 'depot_tools')
33-
os.environ['PATH'] = depot_tools_path + os.pathsep + os.environ['PATH']
31+
def configure_environment(arch_name, build_path, src_path):
32+
"""Runs install scripts for deps, and configures temporary environment variables required by Chromium's build"""
33+
34+
if platform.system() == 'Linux':
35+
if arch_name:
36+
print('Running sysroot install script...')
37+
sysroot_cmd = src_path + '/build/linux/sysroot_scripts/install-sysroot.py --arch=' + arch_name
38+
runcmd(sysroot_cmd)
39+
print('Running install-build-deps...')
40+
runcmd(src_path + '/build/install-build-deps.sh')
41+
42+
depot_tools_path = os.path.join(build_path, 'depot_tools')
43+
full_path = depot_tools_path + os.pathsep + os.environ['PATH']
44+
print('Updating PATH for depot_tools: ' + full_path)
45+
os.environ['PATH'] = full_path

0 commit comments

Comments
 (0)