WKern
Loading...
Searching...
No Matches
configure.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3
13
14import os
15import sys
16import subprocess
17import atexit
18from pathlib import Path
19from concurrent.futures import ThreadPoolExecutor
20import time
21
22# === ANSI Color Constants ===
23BLUE = "\033[0;34m"
24RED = "\033[0;31m"
25GREEN = "\033[0;32m"
26YELLOW = "\033[0;33m"
27MAGENTA = "\033[0;35m"
28CYAN = "\033[0;36m"
29CLEAR = "\033[0m"
30
31# === Temporary Files to Clean on Exit ===
32tmp_files = ["tmp.c", "tmp.asm", "tmp.o", "disk.img"]
33atexit.register(lambda: [os.remove(f) for f in tmp_files if os.path.exists(f)])
34
35
37def yes(): print(f"\033[30;42m YES \033[0m")
38
39
41def no(): print(f"\033[30;41m NO \033[0m")
42
43
49def run_check(desc, cmd, fatal=True):
50 print(desc)
51 result = subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
52 if result.returncode == 0:
53 yes()
54 else:
55 no()
56 if fatal:
57 sys.exit(1)
58
59
63def check_tool(tool):
64 result = subprocess.run(f"{tool} --version", shell=True,
65 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
66 status = f"\033[30;42m YES \033[0m" if result.returncode == 0 else f"\033[30;41m NO \033[0m"
67 print(f"{BLUE}Checking for {tool}{CLEAR} -> {status}")
68 if result.returncode != 0:
69 sys.exit(1)
70
71
75def check_cc_flag(flag):
76 with open("tmp.c", "w") as f:
77 f.write("int main() { return 0; }")
78 result = subprocess.run(f"i686-elf-gcc {flag} -c tmp.c -o /dev/null", shell=True,
79 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
80 status = f"\033[30;42m YES \033[0m" if result.returncode == 0 else f"\033[30;41m NO \033[0m"
81 print(f"{MAGENTA}Checking CC Flag \"{flag}\"{CLEAR} -> {status}")
82 if result.returncode != 0:
83 sys.exit(1)
84
85
89def check_ld_flag(flag):
90 with open("tmp.c", "w") as f:
91 f.write("int main() { return 0; }")
92 subprocess.run("i686-elf-gcc -c tmp.c -o tmp.o", shell=True, check=True)
93 result = subprocess.run(f"i686-elf-ld {flag} -o /dev/null tmp.o", shell=True,
94 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
95 status = f"\033[30;42m YES \033[0m" if result.returncode == 0 else f"\033[30;41m NO \033[0m"
96 print(f"{RED}Checking LD Flag \"{flag}\"{CLEAR} -> {status}")
97 if result.returncode != 0:
98 sys.exit(1)
99
100# === Main Entrypoint ===
101if __name__ == "__main__":
102 start_time = time.time()
103 reconfigure = len(sys.argv) > 1 and sys.argv[1] == "--reconfigure"
104
105 # Check if already configured
106 if Path("didconf").exists() and not reconfigure:
107 print(f"{RED}Already configured. Run with --reconfigure to force.{CLEAR}")
108 sys.exit(0)
109 elif reconfigure:
110 Path("didconf").unlink(missing_ok=True)
111
112 # Tool Check
113 print(f"{CYAN}Checking for required tools{CLEAR}\n")
114 tools = ["make", "nasm", "i686-elf-gcc", "i686-elf-ld", "i686-elf-grub-mkrescue", "qemu-system-i386"]
115 with ThreadPoolExecutor() as exec:
116 exec.map(check_tool, tools)
117
118 # mkfs.msdos test
119 print(f"\n{CYAN}Checking if mkfs.msdos works{CLEAR}")
120 subprocess.run("dd if=/dev/zero of=disk.img bs=1M count=64", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
121 run_check("", "mkfs.msdos disk.img -F 16")
122
123 # NASM test
124 print(f"{CYAN}Checking if NASM works{CLEAR}")
125 with open("tmp.asm", "w") as f:
126 f.write("_start:\n\tmov eax, 0x00\n\tmov ebx, 0x00\n\tret\n")
127 run_check("", "nasm tmp.asm -o /dev/null")
128
129 # Compiler flags
130 print(f"\n{CYAN}Checking compiler flags{CLEAR}\n")
131 cc_flags = ["-ffreestanding", "-nostdlib", "-fno-pie", "-m32", "-O2", "-fno-omit-frame-pointer", "-std=c99", "-g"]
132 with ThreadPoolExecutor() as exec:
133 exec.map(check_cc_flag, cc_flags)
134
135 # Linker flags
136 print(f"\n{CYAN}Checking linker flags{CLEAR}\n")
137 ld_flags = ["-melf_i386", "-n", "--oformat=elf32-i386"]
138 with ThreadPoolExecutor() as exec:
139 exec.map(check_ld_flag, ld_flags)
140
141 # Mark configuration done
142 Path("didconf").write_text("Y")
143
144 # Create `objs/` directory structure
145 if not Path("./objs").exists():
146 print(f"{YELLOW}Creating build directory{CLEAR}")
147 for subdir in Path("src").rglob("*"):
148 if subdir.is_dir():
149 (Path("objs") / subdir).mkdir(parents=True, exist_ok=True)
150
151 # Clone SLRE regex engine if not present
152 if not Path("./src/slre").exists():
153 subprocess.run("git clone --depth 1 https://github.com/Wdboyes13/slre src/slre", shell=True, check=True)
154
155 end_time = time.time()
156 elapsed = end_time - start_time
157 print(f"\n\033[36mFinished in {elapsed:.2f} seconds\033[0m")
158 print(f"{GREEN}Configured - run `./build.py` to start build{CLEAR}")
check_tool(tool)
Checks if a given tool is available in PATH.
Definition configure.py:63
check_cc_flag(flag)
Checks if a compiler flag is accepted by i686-elf-gcc.
Definition configure.py:75
yes()
Prints a "YES" message in green.
Definition configure.py:37
check_ld_flag(flag)
Checks if a linker flag is accepted by i686-elf-ld.
Definition configure.py:89
run_check(desc, cmd, fatal=True)
Runs a shell command and checks its success.
Definition configure.py:49
no()
Prints a "NO" message in red.
Definition configure.py:41