Skip to content

Commit aa24d90

Browse files
committed
Create toolchain generation script
1 parent c57756c commit aa24d90

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
arm**/**
2+
dist/

compress.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tar -c -I 'xz -9 -T0' -f dist/arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi.tar.xz arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi
2+
3+
tar -c -I 'xz -9 -T0' -f dist/arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi
4+
5+
tar -c -I 'xz -9 -T0' -f dist/arm-gnu-toolchain-14.2.rel1-aarch64-arm-none-eabi.tar.xz arm-gnu-toolchain-14.2.rel1-aarch64-arm-none-eabi
6+
7+
tar -c -I 'xz -9 -T0' -f dist/arm-gnu-toolchain-14.2.rel1-darwin-x86_64-arm-none-eabi.tar.xz arm-gnu-toolchain-14.2.rel1-darwin-x86_64-arm-none-eabi
8+
9+
tar -c -I 'xz -9 -T0' -f dist/arm-gnu-toolchain-14.2.rel1-darwin-arm64-arm-none-eabi.tar.xz arm-gnu-toolchain-14.2.rel1-darwin-arm64-arm-none-eabi

generate_toolchain.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
"""
2+
This script generates the ARM-GCC toolchain from the official ARM website
3+
"""
4+
5+
from urllib.request import urlopen
6+
from traceback import print_exc
7+
import os
8+
import sys
9+
import zipfile
10+
import tarfile
11+
import shutil
12+
13+
BASE_URL = "https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/"
14+
15+
16+
ALL_TOOLCHAINS = [
17+
"arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi.zip",
18+
"arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz",
19+
"arm-gnu-toolchain-14.2.rel1-aarch64-arm-none-eabi.tar.xz",
20+
"arm-gnu-toolchain-14.2.rel1-darwin-x86_64-arm-none-eabi.tar.xz",
21+
"arm-gnu-toolchain-14.2.rel1-darwin-arm64-arm-none-eabi.tar.xz",
22+
]
23+
24+
ALL_ARCHS = [
25+
"v6-m", # Cortex M0+
26+
"v7e-m+fp", # Cortex M4
27+
"v7e-m+dp", # Cortex M7
28+
"v8-m.main+fp" # Cortex M33
29+
]
30+
31+
32+
def download_file(url, target):
33+
if os.path.exists(target):
34+
print(f"File {target} already exists. Skipping download.")
35+
return
36+
print(f"Downloading {url} into {target}")
37+
try:
38+
with urlopen(url) as remote, open(target, "wb") as f:
39+
40+
headers = dict(remote.info())
41+
expected_size = int(headers.get("Content-Length", 0))
42+
43+
if not expected_size:
44+
print("URL has no Content-Length header")
45+
46+
mb_expected = expected_size / 1048576
47+
block_size = (expected_size + 49) // 50
48+
blocks_downloaded = 0
49+
file_size_downloaded = 0
50+
51+
while True:
52+
buffer = remote.read(block_size)
53+
if not buffer:
54+
break
55+
file_size_downloaded += len(buffer)
56+
blocks_downloaded += 1
57+
f.write(buffer)
58+
59+
mb_downloaded = file_size_downloaded / 1048576
60+
61+
progress_bar = " [ " + "━" * blocks_downloaded + " " * (50 - blocks_downloaded) + " ]"
62+
progress_bar += f" {mb_downloaded:.1f}/{mb_expected:.1f} MiB"
63+
print(progress_bar, end="\r")
64+
print()
65+
except Exception:
66+
print_exc()
67+
sys.exit("Failed to download files")
68+
69+
70+
def extract_tar_xz(path: str, name: str):
71+
if os.path.exists(name):
72+
print(f"Folder {name} Already Exists. Skipping extract tar.")
73+
return
74+
print(f"Extracting {path}")
75+
with tarfile.open(path, "r:xz") as tf:
76+
tf.extractall(".", filter="data")
77+
print("Done extracting tar.")
78+
79+
80+
def extract_zip(path: str, name: str):
81+
if os.path.exists(name):
82+
print(f"Folder {name} Already Exists. Skipping unzip.")
83+
return
84+
print(f"Unzipping {path}")
85+
with zipfile.ZipFile(path, "r") as zf:
86+
zf.extractall(name)
87+
print("Done unzipping.")
88+
89+
90+
def delete_if_exist(path):
91+
if os.path.isdir(path):
92+
shutil.rmtree(path)
93+
elif os.path.isfile(path):
94+
os.remove(path)
95+
else:
96+
pass # does not exist
97+
98+
99+
def delete_unused_folders(parent, folders_to_keep):
100+
for name in os.listdir(parent):
101+
if name not in folders_to_keep:
102+
delete_if_exist(os.path.join(parent, name))
103+
104+
# only keep the hard float / no float option
105+
for folder in folders_to_keep:
106+
delete_if_exist(os.path.join(parent, folder, "softfp"))
107+
108+
109+
def main():
110+
if not os.path.isdir("dist"):
111+
os.mkdir("dist")
112+
113+
for toolchain in ALL_TOOLCHAINS:
114+
download_file(url=BASE_URL+toolchain, target=toolchain)
115+
if toolchain.endswith(".zip"):
116+
toolchain_dir = toolchain.removesuffix(".zip")
117+
extract_zip(toolchain, toolchain_dir)
118+
119+
delete_if_exist(os.path.join(toolchain_dir, "libexec/gcc/arm-none-eabi/14.2.1/f951.exe"))
120+
delete_if_exist(os.path.join(toolchain_dir, "libexec/gcc/arm-none-eabi/14.2.1/lto1.exe"))
121+
delete_if_exist(os.path.join(toolchain_dir, "bin/arm-none-eabi-lto-dump.exe"))
122+
123+
elif toolchain.endswith(".tar.xz"):
124+
toolchain_dir = toolchain.removesuffix(".tar.xz")
125+
extract_tar_xz(toolchain, toolchain_dir)
126+
127+
delete_if_exist(os.path.join(toolchain_dir, "libexec/gcc/arm-none-eabi/14.2.1/f951"))
128+
delete_if_exist(os.path.join(toolchain_dir, "libexec/gcc/arm-none-eabi/14.2.1/lto1"))
129+
delete_if_exist(os.path.join(toolchain_dir, "bin/arm-none-eabi-lto-dump"))
130+
131+
else:
132+
raise ValueError("unexpected format")
133+
134+
thumb_path = os.path.join(toolchain_dir, "lib/gcc/arm-none-eabi/14.2.1/thumb")
135+
delete_unused_folders(thumb_path, ALL_ARCHS)
136+
thumb_path = os.path.join(toolchain_dir, "arm-none-eabi/lib/thumb")
137+
delete_unused_folders(thumb_path, ALL_ARCHS)
138+
139+
delete_if_exist(os.path.join(toolchain_dir, "lib/gcc/arm-none-eabi/14.2.1/arm"))
140+
delete_if_exist(os.path.join(toolchain_dir, "arm-none-eabi/lib/arm"))
141+
142+
# compress to archive
143+
with tarfile.open(os.path.join("dist", toolchain_dir + ".tar.xz"), "w:xz") as tar:
144+
tar.add(toolchain_dir)
145+
146+
147+
if __name__ == "__main__":
148+
main()

0 commit comments

Comments
 (0)