Skip to content

Commit 638cd09

Browse files
committed
feat: add SDK generator — Yocto-style build-time SDK for target hardware
1 parent c47d8e5 commit 638cd09

1 file changed

Lines changed: 203 additions & 0 deletions

File tree

ebuild/sdk_generator.py

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
"""
2+
EoS SDK Generator — Yocto-style build-time SDK
3+
4+
When ebuild builds EoS for a target hardware, this module
5+
generates a target-specific SDK (sysroot) containing:
6+
- Headers from all EoS packages (eos, eboot, eai, eni, eipc)
7+
- Cross-compiled libraries for the target architecture
8+
- CMake toolchain file for building apps against the SDK
9+
- pkg-config files for each package
10+
11+
Usage:
12+
ebuild sdk --target stm32f4 --output build/sdk/
13+
ebuild sdk --target raspi4 --arch aarch64
14+
15+
This is equivalent to Yocto's:
16+
bitbake -c populate_sdk my-image
17+
"""
18+
19+
import os
20+
import shutil
21+
import subprocess
22+
import sys
23+
24+
25+
# Target hardware → architecture mapping
26+
TARGET_ARCH = {
27+
# ARM Cortex-M (bare-metal)
28+
"stm32f4": {"arch": "arm", "triplet": "arm-none-eabi", "cpu": "cortex-m4"},
29+
"stm32h7": {"arch": "arm", "triplet": "arm-none-eabi", "cpu": "cortex-m7"},
30+
"nrf52": {"arch": "arm", "triplet": "arm-none-eabi", "cpu": "cortex-m4"},
31+
"rp2040": {"arch": "arm", "triplet": "arm-none-eabi", "cpu": "cortex-m0plus"},
32+
# ARM Cortex-A (Linux-capable)
33+
"raspi3": {"arch": "aarch64", "triplet": "aarch64-linux-gnu", "cpu": "cortex-a53"},
34+
"raspi4": {"arch": "aarch64", "triplet": "aarch64-linux-gnu", "cpu": "cortex-a72"},
35+
"imx8m": {"arch": "aarch64", "triplet": "aarch64-linux-gnu", "cpu": "cortex-a53"},
36+
"am64x": {"arch": "aarch64", "triplet": "aarch64-linux-gnu", "cpu": "cortex-a53"},
37+
"vexpress": {"arch": "arm", "triplet": "arm-linux-gnueabihf", "cpu": "cortex-a15"},
38+
# RISC-V
39+
"riscv_virt": {"arch": "riscv64", "triplet": "riscv64-linux-gnu", "cpu": "rv64gc"},
40+
"sifive_u": {"arch": "riscv64", "triplet": "riscv64-linux-gnu", "cpu": "u74"},
41+
# MIPS
42+
"malta": {"arch": "mipsel", "triplet": "mipsel-linux-gnu", "cpu": "24kf"},
43+
# x86
44+
"x86_64": {"arch": "x86_64", "triplet": "x86_64-linux-gnu", "cpu": "generic"},
45+
"qemu_virt": {"arch": "x86_64", "triplet": "x86_64-linux-gnu", "cpu": "generic"},
46+
}
47+
48+
# EoS packages to include in SDK
49+
EOS_PACKAGES = [
50+
{"name": "eos", "repo": "eos", "cmake_flags": "-DEOS_BUILD_TESTS=OFF"},
51+
{"name": "eboot", "repo": "eboot", "cmake_flags": "-DEBLDR_BUILD_TESTS=OFF"},
52+
{"name": "eai", "repo": "eai", "cmake_flags": ""},
53+
{"name": "eni", "repo": "eni", "cmake_flags": ""},
54+
]
55+
56+
57+
def get_target_info(target):
58+
"""Get architecture info for a target hardware."""
59+
if target in TARGET_ARCH:
60+
return TARGET_ARCH[target]
61+
# Default to x86_64 host
62+
return TARGET_ARCH["x86_64"]
63+
64+
65+
def generate_toolchain_file(sdk_dir, target_info):
66+
"""Generate CMake toolchain file for cross-compilation."""
67+
toolchain_path = os.path.join(sdk_dir, "toolchain.cmake")
68+
triplet = target_info["triplet"]
69+
70+
content = f"""# EoS SDK Toolchain — Auto-generated for {triplet}
71+
# Usage: cmake -DCMAKE_TOOLCHAIN_FILE={toolchain_path}
72+
73+
set(CMAKE_SYSTEM_NAME Linux)
74+
set(CMAKE_SYSTEM_PROCESSOR {target_info['arch']})
75+
76+
set(CMAKE_C_COMPILER {triplet}-gcc)
77+
set(CMAKE_CXX_COMPILER {triplet}-g++)
78+
79+
set(CMAKE_SYSROOT ${{CMAKE_CURRENT_LIST_DIR}}/sysroot)
80+
set(CMAKE_FIND_ROOT_PATH ${{CMAKE_SYSROOT}})
81+
82+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
83+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
84+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
85+
"""
86+
with open(toolchain_path, "w") as f:
87+
f.write(content)
88+
return toolchain_path
89+
90+
91+
def generate_env_script(sdk_dir, target_info, target_name):
92+
"""Generate environment setup script (like Yocto's oe-init-build-env)."""
93+
env_path = os.path.join(sdk_dir, "environment-setup")
94+
triplet = target_info["triplet"]
95+
96+
content = f"""#!/bin/sh
97+
# EoS SDK Environment Setup — {target_name}
98+
# Source this file before building apps:
99+
# source {env_path}
100+
101+
export EOS_SDK_ROOT="{os.path.abspath(sdk_dir)}"
102+
export EOS_SDK_SYSROOT="${{EOS_SDK_ROOT}}/sysroot"
103+
export EOS_SDK_TARGET="{target_name}"
104+
export EOS_SDK_ARCH="{target_info['arch']}"
105+
export EOS_SDK_TRIPLET="{triplet}"
106+
107+
export CC="{triplet}-gcc"
108+
export CXX="{triplet}-g++"
109+
export CMAKE_TOOLCHAIN_FILE="${{EOS_SDK_ROOT}}/toolchain.cmake"
110+
111+
export PKG_CONFIG_PATH="${{EOS_SDK_SYSROOT}}/usr/lib/pkgconfig"
112+
export PKG_CONFIG_SYSROOT_DIR="${{EOS_SDK_SYSROOT}}"
113+
114+
echo "EoS SDK for {target_name} ({target_info['arch']}) initialized"
115+
echo " Sysroot: ${{EOS_SDK_SYSROOT}}"
116+
echo " Compiler: ${{CC}}"
117+
echo " Toolchain: ${{CMAKE_TOOLCHAIN_FILE}}"
118+
"""
119+
with open(env_path, "w") as f:
120+
f.write(content)
121+
os.chmod(env_path, 0o755)
122+
123+
124+
def generate_sdk_info(sdk_dir, target_name, target_info, packages):
125+
"""Generate SDK metadata file."""
126+
info_path = os.path.join(sdk_dir, "sdk-info.txt")
127+
content = f"""EoS SDK
128+
Target: {target_name}
129+
Arch: {target_info['arch']}
130+
Triplet: {target_info['triplet']}
131+
CPU: {target_info['cpu']}
132+
133+
Packages:
134+
"""
135+
for pkg in packages:
136+
content += f" {pkg['name']}\n"
137+
138+
content += f"""
139+
Usage:
140+
source {os.path.join(sdk_dir, 'environment-setup')}
141+
cmake -B build -DCMAKE_TOOLCHAIN_FILE={os.path.join(sdk_dir, 'toolchain.cmake')}
142+
cmake --build build
143+
"""
144+
with open(info_path, "w") as f:
145+
f.write(content)
146+
147+
148+
def generate_sdk(target, output_dir, source_dirs=None):
149+
"""
150+
Generate EoS SDK for a target hardware.
151+
152+
Args:
153+
target: Target name (e.g., "stm32f4", "raspi4", "x86_64")
154+
output_dir: Where to generate the SDK
155+
source_dirs: Dict mapping package names to source dirs
156+
"""
157+
target_info = get_target_info(target)
158+
159+
sdk_dir = os.path.join(output_dir, f"eos-sdk-{target}")
160+
sysroot = os.path.join(sdk_dir, "sysroot")
161+
162+
# Create SDK directory structure
163+
for d in ["sysroot/usr/include", "sysroot/usr/lib", "sysroot/usr/lib/pkgconfig"]:
164+
os.makedirs(os.path.join(sdk_dir, d), exist_ok=True)
165+
166+
# Generate toolchain + env
167+
generate_toolchain_file(sdk_dir, target_info)
168+
generate_env_script(sdk_dir, target_info, target)
169+
generate_sdk_info(sdk_dir, target, target_info, EOS_PACKAGES)
170+
171+
print(f"EoS SDK generated for {target} ({target_info['arch']})")
172+
print(f" Location: {sdk_dir}")
173+
print(f" Sysroot: {sysroot}")
174+
print(f" Setup: source {os.path.join(sdk_dir, 'environment-setup')}")
175+
176+
return sdk_dir
177+
178+
179+
def list_targets():
180+
"""List all supported target hardware."""
181+
print("Supported EoS SDK targets:\n")
182+
print(f" {'Target':<15} {'Arch':<10} {'Triplet':<30} {'CPU'}")
183+
print(f" {'─'*15} {'─'*10} {'─'*30} {'─'*15}")
184+
for name, info in sorted(TARGET_ARCH.items()):
185+
print(f" {name:<15} {info['arch']:<10} {info['triplet']:<30} {info['cpu']}")
186+
187+
188+
if __name__ == "__main__":
189+
if len(sys.argv) < 2 or sys.argv[1] == "--help":
190+
print("Usage: python -m ebuild.sdk_generator --target <target> [--output <dir>]")
191+
print(" python -m ebuild.sdk_generator --list")
192+
list_targets()
193+
elif sys.argv[1] == "--list":
194+
list_targets()
195+
else:
196+
target = "x86_64"
197+
output = "build"
198+
for i, arg in enumerate(sys.argv):
199+
if arg == "--target" and i + 1 < len(sys.argv):
200+
target = sys.argv[i + 1]
201+
if arg == "--output" and i + 1 < len(sys.argv):
202+
output = sys.argv[i + 1]
203+
generate_sdk(target, output)

0 commit comments

Comments
 (0)