Skip to content

Commit 0712502

Browse files
committed
[tools] Add scripts and hooks
1 parent 2843aa5 commit 0712502

File tree

5 files changed

+526
-0
lines changed

5 files changed

+526
-0
lines changed

DEPS

+13
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,16 @@ deps = {
1818
'dep_type': 'cipd',
1919
},
2020
}
21+
22+
hooks = [
23+
{
24+
'name': 'Download engine artifacts',
25+
'pattern': '.',
26+
'action': ['python3', 'src/tools/download_engine.py'],
27+
},
28+
{
29+
'name': 'Generate Tizen sysroots',
30+
'pattern': '.',
31+
'action': ['python3', 'src/tools/generate_sysroot.py', '-q'],
32+
}
33+
]

tools/check_symbols.py

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved.
3+
# Use of this source code is governed by a BSD-style license that can be
4+
# found in the LICENSE file.
5+
6+
import argparse
7+
import os
8+
import subprocess
9+
import sys
10+
11+
12+
class Symbol:
13+
14+
def __init__(self, addr, type, name):
15+
self.addr = addr
16+
self.type = type
17+
self.name = name
18+
19+
def __str__(self):
20+
return '{} {} {}'.format(self.addr, self.type, self.name)
21+
22+
@staticmethod
23+
def parse(line):
24+
return Symbol(line[:8].strip(), line[9], line[11:].strip())
25+
26+
27+
def check_symbol(sofile, allowlist):
28+
if not os.access(sofile, os.R_OK):
29+
sys.exit('{} is not a valid file.'.format(sofile))
30+
if not os.access(allowlist, os.R_OK):
31+
sys.exit('{} is not a valid file.'.format(allowlist))
32+
33+
try:
34+
symbols_raw = subprocess.check_output(
35+
['nm', '-gDC', sofile]).decode('utf-8').splitlines()
36+
symbols = [Symbol.parse(line) for line in symbols_raw]
37+
except subprocess.CalledProcessError as error:
38+
sys.exit('nm failed: {}'.format(error))
39+
40+
with open(allowlist, 'r') as file:
41+
allowlist = [line.strip() for line in file.readlines()]
42+
43+
not_allowed = []
44+
for symbol in symbols:
45+
if symbol.addr:
46+
continue
47+
if symbol.name.startswith('FlutterEngine'):
48+
continue
49+
if symbol.name in allowlist:
50+
continue
51+
not_allowed.append(symbol)
52+
53+
if not_allowed:
54+
print('Symbols not allowed ({}):'.format(sofile))
55+
for symbol in not_allowed:
56+
print(symbol)
57+
sys.exit(1)
58+
59+
60+
def main():
61+
parser = argparse.ArgumentParser()
62+
parser.add_argument('--allowlist', type=str, required=True,
63+
help='Path to the allowlist file')
64+
parser.add_argument('sofile', type=str, nargs='+',
65+
help='Path to the .so file')
66+
args = parser.parse_args()
67+
68+
for sofile in args.sofile:
69+
check_symbol(sofile, args.allowlist)
70+
71+
72+
# Execute only if run as a script.
73+
if __name__ == '__main__':
74+
main()

tools/download_engine.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved.
3+
# Use of this source code is governed by a BSD-style license that can be
4+
# found in the LICENSE file.
5+
6+
import requests
7+
import shutil
8+
import sys
9+
import urllib.request
10+
from io import BytesIO
11+
from pathlib import Path
12+
from zipfile import ZipFile
13+
14+
15+
# Downloads the latest engine artifacts for use by the linker.
16+
def main():
17+
engine_dir = Path(__file__).parent.parent / 'engine'
18+
github_url = 'https://github.com/flutter-tizen/engine/releases'
19+
20+
stamp = ''
21+
stamp_file = engine_dir / 'engine.stamp'
22+
if stamp_file.is_file():
23+
stamp = stamp_file.read_text().strip()
24+
25+
version = ''
26+
# The GitHub REST API cannot be used in the company network due to an
27+
# "API rate limit exceeded" error. The following is a workaround.
28+
request = requests.get('{}/latest'.format(github_url))
29+
redirected_url = request.url
30+
if '/tag/' in redirected_url:
31+
version = redirected_url.split('/tag/')[-1]
32+
33+
if not version:
34+
sys.exit('Latest tag not found.')
35+
if version == stamp:
36+
print('Already downloaded latest version.')
37+
sys.exit()
38+
39+
if engine_dir.is_dir():
40+
shutil.rmtree(engine_dir)
41+
engine_dir.mkdir()
42+
43+
names = ['tizen-arm-release.zip',
44+
'tizen-arm64-release.zip', 'tizen-x86-debug.zip']
45+
for filename in names:
46+
arch = filename.split('-')[1]
47+
print('Downloading libflutter_engine.so for {}...'.format(arch))
48+
49+
download_path = engine_dir / arch
50+
download_url = '{}/download/{}/{}'.format(github_url, version, filename)
51+
with urllib.request.urlopen(download_url) as response:
52+
with ZipFile(BytesIO(response.read())) as file:
53+
file.extractall(download_path)
54+
55+
for file in download_path.iterdir():
56+
if file.name != 'libflutter_engine.so':
57+
file.unlink()
58+
59+
stamp_file.write_text(version)
60+
61+
62+
# Execute only if run as a script.
63+
if __name__ == '__main__':
64+
main()

tools/generate_sysroot.py

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved.
3+
# Use of this source code is governed by a BSD-style license that can be
4+
# found in the LICENSE file.
5+
6+
import argparse
7+
import os
8+
import re
9+
import shutil
10+
import subprocess
11+
import sys
12+
import urllib.parse
13+
import urllib.request
14+
from pathlib import Path
15+
16+
17+
base_packages = [
18+
'gcc',
19+
'glibc',
20+
'glibc-devel',
21+
'libgcc',
22+
'libstdc++',
23+
'libstdc++-devel',
24+
'linux-glibc-devel',
25+
]
26+
27+
unified_packages = [
28+
'atk-devel',
29+
'at-spi2-atk-devel',
30+
'capi-appfw-application',
31+
'capi-appfw-application-devel',
32+
'capi-appfw-app-common',
33+
'capi-appfw-app-common-devel',
34+
'capi-appfw-app-control',
35+
'capi-appfw-app-control-devel',
36+
'capi-base-common',
37+
'capi-base-common-devel',
38+
'capi-base-utils',
39+
'capi-base-utils-devel',
40+
'capi-system-info',
41+
'capi-system-info-devel',
42+
'capi-system-system-settings',
43+
'capi-system-system-settings-devel',
44+
'capi-ui-efl-util',
45+
'capi-ui-efl-util-devel',
46+
'cbhm',
47+
'cbhm-devel',
48+
'coregl',
49+
'coregl-devel',
50+
'ecore-con-devel',
51+
'ecore-core',
52+
'ecore-core-devel',
53+
'ecore-evas',
54+
'ecore-evas-devel',
55+
'ecore-file-devel',
56+
'ecore-imf',
57+
'ecore-imf-devel',
58+
'ecore-imf-evas',
59+
'ecore-imf-evas-devel',
60+
'ecore-input',
61+
'ecore-input-devel',
62+
'ecore-wayland',
63+
'ecore-wayland-devel',
64+
'ecore-wl2',
65+
'ecore-wl2-devel',
66+
'edje-devel',
67+
'eet',
68+
'eet-devel',
69+
'efl-devel',
70+
'efl-extension',
71+
'efl-extension-devel',
72+
'efreet-devel',
73+
'eina',
74+
'eina-devel',
75+
'eina-tools',
76+
'elementary',
77+
'elementary-devel',
78+
'emile-devel',
79+
'eo-devel',
80+
'ethumb-devel',
81+
'evas',
82+
'evas-devel',
83+
'glib2-devel',
84+
'jsoncpp',
85+
'jsoncpp-devel',
86+
'libatk',
87+
'libatk-bridge-2_0-0',
88+
'libfeedback',
89+
'libfeedback-devel',
90+
'libdlog',
91+
'libdlog-devel',
92+
'libglib',
93+
'libgobject',
94+
'libtbm',
95+
'libtbm-devel',
96+
'libtdm-client',
97+
'libtdm-client-devel',
98+
'libtdm-devel',
99+
'libwayland-client',
100+
'libwayland-cursor',
101+
'libwayland-egl',
102+
'libwayland-extension-client',
103+
'libxkbcommon',
104+
'libxkbcommon-devel',
105+
'tzsh',
106+
'tzsh-devel',
107+
'vulkan-headers',
108+
'vulkan-loader',
109+
'vulkan-loader-devel',
110+
'wayland-extension-client-devel',
111+
'wayland-devel',
112+
]
113+
114+
# Only available for Tizen 6.5 and above.
115+
dali_packages = [
116+
'dali2',
117+
'dali2-adaptor',
118+
'dali2-adaptor-devel',
119+
'dali2-devel',
120+
'dali2-toolkit',
121+
'dali2-toolkit-devel',
122+
]
123+
124+
125+
def generate_sysroot(sysroot: Path, api_version: float, arch: str, quiet=False):
126+
if arch == 'arm':
127+
tizen_arch = 'armv7l'
128+
elif arch == 'arm64':
129+
tizen_arch = 'aarch64'
130+
elif arch == 'x86':
131+
tizen_arch = 'i686'
132+
else:
133+
sys.exit('Unknown arch: ' + arch)
134+
135+
base_repo = 'http://download.tizen.org/snapshots/tizen/{}-base/latest/repos/standard/packages'.format(
136+
api_version)
137+
unified_repo = 'http://download.tizen.org/snapshots/tizen/{}-unified/latest/repos/standard/packages'.format(
138+
api_version)
139+
140+
# Retrieve html documents.
141+
documents = {}
142+
for url in ['{}/{}'.format(base_repo, tizen_arch),
143+
'{}/{}'.format(base_repo, 'noarch'),
144+
'{}/{}'.format(unified_repo, tizen_arch),
145+
'{}/{}'.format(unified_repo, 'noarch')]:
146+
request = urllib.request.Request(url)
147+
with urllib.request.urlopen(request) as response:
148+
documents[url] = response.read().decode('utf-8')
149+
150+
# Download packages.
151+
download_path = sysroot / '.rpms'
152+
download_path.mkdir(exist_ok=True)
153+
existing_rpms = [f for f in download_path.iterdir() if f.suffix == '.rpm']
154+
155+
packages = base_packages + unified_packages
156+
if api_version >= 6.5:
157+
packages += dali_packages
158+
159+
for package in packages:
160+
quoted = urllib.parse.quote(package)
161+
pattern = re.escape(quoted) + '-\\d+\\.[\\d_\\.]+-[\\d\\.]+\\..+\\.rpm'
162+
163+
if any([re.match(pattern, rpm.name) for rpm in existing_rpms]):
164+
continue
165+
166+
for parent, doc in documents.items():
167+
match = re.search('<a href="({})">.+?</a>'.format(pattern), doc)
168+
if match:
169+
rpm_url = '{}/{}'.format(parent, match.group(1))
170+
break
171+
172+
if match:
173+
if not quiet:
174+
print('Downloading ' + rpm_url)
175+
urllib.request.urlretrieve(rpm_url, download_path / match.group(1))
176+
else:
177+
sys.exit('Could not find a package named ' + package)
178+
179+
# Extract files.
180+
for rpm in [f for f in download_path.iterdir() if f.suffix == '.rpm']:
181+
command = 'rpm2cpio {} | cpio -idum --quiet'.format(rpm)
182+
subprocess.run(command, shell=True, cwd=sysroot, check=True)
183+
184+
# Create symbolic links.
185+
asm = sysroot / 'usr' / 'include' / 'asm'
186+
if not asm.exists():
187+
os.symlink('asm-' + arch, asm)
188+
pkgconfig = sysroot / 'usr' / 'lib' / 'pkgconfig'
189+
if arch == 'arm64' and not pkgconfig.exists():
190+
os.symlink('../lib64/pkgconfig', pkgconfig)
191+
192+
# Copy objects required by the linker, such as crtbeginS.o and libgcc.a.
193+
if arch == 'arm64':
194+
libpath = sysroot / 'usr' / 'lib64'
195+
else:
196+
libpath = sysroot / 'usr' / 'lib'
197+
subprocess.run('cp gcc/*/*/*.o gcc/*/*/*.a .',
198+
shell=True, cwd=libpath, check=True)
199+
200+
201+
def main():
202+
# Check dependencies.
203+
for dep in ['rpm2cpio', 'cpio', 'git']:
204+
if not shutil.which(dep):
205+
sys.exit('{} is not installed. To install, run:\n'
206+
' sudo apt install {}'.format(dep, dep))
207+
208+
# Parse arguments.
209+
parser = argparse.ArgumentParser(description='Tizen sysroot generator')
210+
parser.add_argument('-o', '--out', metavar='PATH', type=str,
211+
help='Path to the output directory')
212+
parser.add_argument('-f', '--force', action='store_true',
213+
help='Force re-downloading of packages')
214+
parser.add_argument('-q', '--quiet', action='store_true',
215+
help='Suppress log output')
216+
parser.add_argument('--api-version', metavar='VER', default=5.5, type=float,
217+
help='Target API version (defaults to 5.5)')
218+
args = parser.parse_args()
219+
220+
if args.out:
221+
outpath = Path(args.out)
222+
else:
223+
outpath = Path(__file__).parent.parent / 'sysroot'
224+
outpath.mkdir(exist_ok=True)
225+
226+
for arch in ['arm', 'arm64', 'x86']:
227+
sysroot = outpath / arch
228+
if args.force and sysroot.is_dir():
229+
shutil.rmtree(sysroot)
230+
sysroot.mkdir(exist_ok=True)
231+
232+
if not args.quiet:
233+
print('Generating sysroot for {}...'.format(arch))
234+
generate_sysroot(sysroot.resolve(), args.api_version, arch, args.quiet)
235+
236+
237+
# Execute only if run as a script.
238+
if __name__ == '__main__':
239+
main()

0 commit comments

Comments
 (0)