Skip to content

Commit b12901e

Browse files
committed
Fully functional build/install tools
1 parent a4ffd1c commit b12901e

File tree

5 files changed

+334
-5
lines changed

5 files changed

+334
-5
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
__pycache__/
2+
build/
3+
out/
4+
install/
25

6+
python*.*
7+
*.zip
8+
*.tar.gz

build.py

Lines changed: 175 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
1+
#!/usr/bin/env python3
2+
13
import subprocess
24
import sys
35
import os
6+
import shutil
7+
import json
8+
import time
49

5-
def run(*command):
10+
def run(*command, cwd=None):
611
print(command)
712
try:
8-
result = subprocess.run(command)
13+
result = subprocess.run(command, cwd=cwd)
914
except OSError:
1015
return 127, []
11-
return result.returncode, result.stdout.decode('utf-8').strip().split('\n')
16+
return result.returncode, "" # TODO
17+
18+
def read_properties(fname):
19+
data = {}
20+
with open(fname, 'r') as f:
21+
for line in f:
22+
fields = [x.strip() for x in line.split('=')]
23+
data[fields[0]] = fields[1]
24+
return data
1225

1326
def check_git():
1427
rcode, stdout = run('git', '--version')
@@ -20,18 +33,175 @@ def check_python():
2033
return 1
2134
else:
2235
if os.path.exists('python/.git'):
23-
return 0
36+
return 2
2437
else:
2538
return 1
39+
else:
40+
return 0
41+
42+
def check_ndk(ndk_dir, min_ver, checking_sub=False):
43+
if not os.path.exists(ndk_dir):
44+
return 1
45+
if os.path.exists(ndk_dir + '/source.properties'):
46+
info = read_properties(ndk_dir + '/source.properties')
47+
if not 'Pkg.Revision' in info:
48+
return 1
49+
vn = [int(x) for x in info['Pkg.Revision'].split('.')]
50+
for i in range(len(vn)):
51+
if i >= len(min_ver):
52+
print('versions equal')
53+
return 0
54+
elif vn[i] > min_ver[i]:
55+
print('later version')
56+
return 0
57+
elif vn[i] < min_ver[i]:
58+
print('earlier version')
59+
return 1
60+
print('versions equal')
61+
return 0
2662
else:
2763
return 1
2864

65+
def trymkdir(dir):
66+
if not os.path.exists(dir):
67+
os.mkdir(dir)
68+
return 0
69+
elif not os.path.isdir(dir):
70+
print("'%s' exists and is a file. Please move or delete it." % dir)
71+
return 1
72+
else:
73+
return 0
74+
75+
def copy(src, dest):
76+
print("%s -> %s" % (src, dest))
77+
shutil.copy(src, dest)
78+
2979
def main():
3080
print("Building Python for Android 24 64-bit ARM (aarch64-linux-android)")
3181
print("Checking/installing dependencies")
3282

83+
# TODO arguments
84+
py_version='v3.9.2'
85+
ndk_dir=os.getenv('HOME') + '/Android/Sdk/ndk/22.0.7026061'
86+
ndk_min_ver=(22,)
87+
make_jobs=6
88+
target='aarch64-linux-android'
89+
android_ver='24'
90+
shell='/usr/bin/bash'
91+
make='/usr/bin/make'
92+
tar='/usr/bin/tar'
93+
force_build=False
94+
3395
if not check_git:
3496
print("Could not find Git. Is it in your PATH?")
3597
sys.exit(1)
3698

37-
99+
res = check_python()
100+
if res == 1:
101+
print("'python' is already a file or directory. Please delete or move it.")
102+
sys.exit(1)
103+
elif res == 2:
104+
print("'python' Git clone found")
105+
else:
106+
rval = run('git', 'clone', '-n', 'https://github.com/python/cpython')[0]
107+
if rval != 0:
108+
print("Clone failed!")
109+
sys.exit(2)
110+
111+
print("Checkout version '%s'" % py_version)
112+
rval = run('git', '-C', 'python/', 'checkout', py_version)[0]
113+
if rval != 0:
114+
print("Checkout failed!")
115+
sys.exit(2)
116+
117+
print("Checking NDK")
118+
if check_ndk(ndk_dir, ndk_min_ver) != 0:
119+
print("NDK not found. Please install NDK version %s or later and specify --ndk-dir" % ('.'.join(min_ver)))
120+
sys.exit(1)
121+
122+
print("Setting up build environment")
123+
if trymkdir('build') != 0:
124+
sys.exit(1)
125+
with open('build/config.site', 'w') as f:
126+
f.write('ac_cv_file__dev_ptmx=no\n')
127+
f.write('ac_cv_file__dev_ptc=no\n')
128+
129+
arguments=[shell, '../python/configure']
130+
131+
toolchain = ndk_dir + '/toolchains/llvm/prebuilt/linux-x86_64'
132+
arguments.append('--srcdir=../python')
133+
arguments.append('--prefix=' + os.path.realpath('out/'))
134+
arguments.append('--build=x86_64-pc-linux-gnu')
135+
arguments.append('--host=' + target)
136+
arguments.append('--disable-ipv6')
137+
arguments.append('CONFIG_SITE=config.site')
138+
arguments.append('TOOLCHAIN=' + toolchain)
139+
arguments.append('TARGET=' + target)
140+
arguments.append('API=' + android_ver)
141+
arguments.append('AR=' + toolchain + '/bin/llvm-ar')
142+
arguments.append('CC=' + toolchain + '/bin/' + target + android_ver + '-clang')
143+
arguments.append('AS=' + toolchain + '/bin/' + target + android_ver + '-clang')
144+
arguments.append('CXX=' + toolchain + '/bin/' + target + android_ver + '-clang++')
145+
arguments.append('LD=' + toolchain + '/bin/ld')
146+
arguments.append('RANLIB=' + toolchain + '/bin/llvm-ranlib')
147+
arguments.append('STRIP=' + toolchain + '/bin/llvm-strip')
148+
arguments.append('READELF=' + toolchain + '/bin/llvm-readelf')
149+
arguments.append('LD_LIBRARY_PATH=' + toolchain + '/sysroot/usr/lib/' + target + \
150+
':' + toolchain + '/sysroot/usr/lib' + target + '/' + android_ver)
151+
152+
if not os.path.exists('out/bin') or force_build:
153+
rval = run(*arguments, cwd='build/')[0]
154+
if rval != 0:
155+
print("configure failed (%d)" % rval)
156+
sys.exit(2)
157+
158+
rval = run(make, 'clean', cwd='build/')[0]
159+
if rval != 0:
160+
print("clean failed (%d)" % rval)
161+
sys.exit(2)
162+
163+
rval = run(make, '-j' + str(make_jobs), cwd='build/')[0]
164+
if rval != 0:
165+
print("compilation failed (%d)" % rval)
166+
sys.exit(2)
167+
168+
rval = run(make, 'install', cwd='build/')[0]
169+
if rval != 0:
170+
print("install failed (%d)" % rval)
171+
sys.exit(2)
172+
173+
pyver_numbers = py_version[1:].split('.')
174+
python_executable = 'python' + '.'.join(pyver_numbers[0:2])
175+
176+
print("Building install archive")
177+
if trymkdir('install') != 0:
178+
sys.exit(2)
179+
180+
copy('out/bin/' + python_executable, 'install/' + python_executable)
181+
install_archive = 'install/' + python_executable + '.tar.gz'
182+
if os.path.exists(install_archive):
183+
os.remove(install_archive)
184+
run(tar, '-C', 'out/lib', '-cvzf', install_archive, 'python3.9/')
185+
186+
build_time = time.localtime()
187+
188+
install_info = {
189+
'version': py_version[1:],
190+
'python': python_executable,
191+
'build-tool-version': '1.0.0',
192+
'build-date': time.strftime('%Y-%m-%d %H:%M', build_time)
193+
}
194+
195+
with open('install/install.txt', 'w') as f:
196+
json.dump(install_info, f)
197+
198+
# copy install scripts
199+
copy('install-tools/install.py', 'install/install.py')
200+
copy('install-tools/install.sh', 'install/install.sh')
201+
copy('install-tools/README.txt', 'install/README.txt')
202+
203+
output_name = 'android-python-%s-%s' % (time.strftime('%Y%m%d_%H%M', build_time))
204+
shutil.make_archive(output_name, 'zip', 'install')
205+
206+
if __name__ == '__main__':
207+
main()

install-tools/README.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Android-Python for the REV Control Hub
2+
Copyright (C) 2021 Aidan Yaklin
3+
This project is licensed under the MIT license. See <url> for more details.
4+
5+
HOW TO USE
6+
* Connect your REV hub to your computer with ADB (Wifi or USB should work, as long
7+
as it's connected.)
8+
* Make sure that ADB (the Android Debugger) is in your PATH. This tool comes with
9+
Android Studio and is usually located in
10+
<user home folder>/Android/Sdk/platform-tools or
11+
<user home folder>/AppData/Local/Android/Sdk/platform-tools.
12+
* Open up a terminal/command line and run
13+
python install.py
14+
Double-clicking install.py in Windows *might* also work, but this hasn't been tested.
15+
* When prompted, type 'yes' to confirm the installation.
16+
* Once the installation is finished, test it by opening an ADB shell with 'adb shell'
17+
and running python. You should be able to import most built-in libraries without
18+
any issues.

install-tools/install.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import os
2+
import sys
3+
import subprocess
4+
import json
5+
6+
def run(*command, cwd=None):
7+
print(command)
8+
try:
9+
result = subprocess.run(command, cwd=cwd, stdout=subprocess.PIPE)
10+
return result.returncode, result.stdout.decode('utf-8').strip()
11+
except OSError:
12+
return 127, []
13+
14+
def main():
15+
r, stdout = run('adb', 'devices')
16+
if r != 0:
17+
print("Failed to run adb. Make sure it is in your PATH?")
18+
print("hint: adb is in <Android SDK dir>/platform-tools/")
19+
sys.exit(1)
20+
if len(stdout.split('\n')) < 2:
21+
print("No devices found. Make sure you are connected to your REV hub over")
22+
print("USB or WiFi.")
23+
sys.exit(0)
24+
25+
if not os.path.exists('install.txt'):
26+
print("Could not find 'install.txt'. Did you mean to run build.py instead?")
27+
print("This file should only be used inside an install archive directory.")
28+
sys.exit(1)
29+
30+
with open('install.txt', 'r') as f:
31+
install_info = json.load(f)
32+
33+
python = install_info['python']
34+
version = install_info['version']
35+
36+
print("This tool will install Python v%s onto your REV Control Hub. This requires" % version)
37+
print("uploading files into the hub's system folders.")
38+
print()
39+
print("-- USE AT YOUR OWN RISK! However, if this 'bricks' your Control Hub, you should")
40+
print("be able to re-install the Control Hub OS with the REV Hardware Client.")
41+
print()
42+
print("-- If you are using Blocks or OnBot Java, consider backing up the files on your")
43+
print("Control Hub before continuing.")
44+
print()
45+
print("Type 'yes' to continue: ", end="")
46+
resp = input()
47+
if resp != 'yes':
48+
print("Nope!")
49+
sys.exit(0)
50+
51+
print("Rooting REV hub...")
52+
r, stdout = run('adb', 'root')
53+
if r != 0:
54+
print("Root failed")
55+
sys.exit(1)
56+
57+
r, stdout = run('adb', 'remount')
58+
if r != 0:
59+
print("Remount failed")
60+
sys.exit(1)
61+
62+
print("Uploading python...")
63+
version_maj = version.split('.')[0]
64+
r, stdout = run('adb', 'push', python, '/system/bin/')
65+
if r != 0:
66+
print("Upload failed")
67+
sys.exit(1)
68+
69+
print("Uploading python libraries...")
70+
r, stdout = run('adb', 'push', python + '.tar.gz', '/data/local/tmp')
71+
if r != 0:
72+
print("Upload failed")
73+
sys.exit(1)
74+
75+
print("Uploading install script...")
76+
r, stdout = run('adb', 'push', 'install.sh', '/data/local/tmp')
77+
if r != 0:
78+
print("Upload failed")
79+
sys.exit(1)
80+
81+
print("Running install script...")
82+
r, stdout = run('adb', 'shell', 'chmod', '755', '/data/local/tmp/install.sh')
83+
if r != 0:
84+
print("chmod failed")
85+
sys.exit(1)
86+
r, stdout = run('adb', 'shell', '/data/local/tmp/install.sh', python[len('python'):])
87+
88+
if r != 0:
89+
print("Installation failed!")
90+
print("There are still temporary files in /data/local/tmp. Make sure to")
91+
print("delete them (in the Android Studio Device File Explorer).")
92+
sys.exit(1)

install-tools/install.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/system/bin/sh
2+
# Tool to extract and set up Android Python on the target system
3+
# DO NOT RUN THIS ON YOUR COMPUTER; IT WILL NOT WORK
4+
5+
echo $(uname -m)
6+
echo $(whoami)
7+
py_prefix=python$1 # avoid nasty input errors deleting/overwriting /system/lib/
8+
echo $py_prefix
9+
10+
# Make sure we're in the right directory
11+
cd /data/local/tmp
12+
13+
# We need to move the executable out of the way first, since it's only called 'python3.9'
14+
# Otherwise, this file would conflict with the directory created when we extract
15+
# the libraries
16+
echo "Installing executable"
17+
mv ${py_prefix} /system/bin
18+
# create symlinks
19+
maj_version=$(echo ${py_prefix} | sed -r 's/(python[0-9]+)\..*/\1/')
20+
ln -s /system/bin/${py_prefix} /system/bin/${maj_version} # pythonX -> pythonX.Y
21+
ln -s /system/bin/${py_prefix} /system/bin/python # python -> pythonX.Y
22+
23+
echo "Extracting archive"
24+
tar -xzf ${py_prefix}.tar.gz # Should create a directory ${py_prefix}/
25+
if [ $? != 0 ]; then
26+
echo "Failed to extract archive"
27+
exit 1
28+
fi
29+
30+
if [ -e /system/lib/${py_prefix} ]; then
31+
echo "Removing old Python installation"
32+
rm -r /system/lib/${py_prefix}
33+
fi
34+
35+
# mv probably has to move the extracted files to a different filesystem
36+
# this requires a copy-delete and is much slower than just renaming
37+
echo "Installing python libraries"
38+
mv ${py_prefix} /system/lib
39+
40+
rm ${py_prefix}.tar.gz
41+
42+
echo "Install completed successfully!"
43+
echo "Run 'python' in an ADB shell to make sure everything works."

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy