Skip to content

Commit 3aef78b

Browse files
author
Kilynho
committed
feat: Improve compilation error diagnosis and kernel config
Enhancements to compile.py: 1. Auto-configuration: - Automatically runs 'make defconfig' if kernel is not configured - Checks for .config existence before compilation - Prevents compilation failures due to missing configuration 2. Error classification: - Categorizes errors: config, code, dependency, unknown - 'config': Symbols undeclared due to CONFIG_* flags - 'code': Real syntax/type errors in source - 'dependency': Missing headers/files - Helps distinguish autofix bugs from environment issues 3. Enhanced reporting: - Shows error classification in summary - Labels each failed file with error type - Provides context for troubleshooting Results with current dataset: - 2 errors classified as 'config' (envp_init, rd_load_image) - 1 error classified as 'unknown' (section conflict) - 0 errors due to autofix bugs These improvements help users understand that compilation failures are environment/config issues, not bugs in the autofix system.
1 parent d13a429 commit 3aef78b

File tree

1 file changed

+127
-5
lines changed

1 file changed

+127
-5
lines changed

compile.py

Lines changed: 127 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ class CompilationResult:
2222
"""Representa el resultado de compilar un archivo."""
2323

2424
def __init__(self, file_path: str, success: bool, duration: float,
25-
stdout: str = "", stderr: str = "", error_message: str = ""):
25+
stdout: str = "", stderr: str = "", error_message: str = "",
26+
error_type: str = ""):
2627
self.file_path = file_path
2728
self.success = success
2829
self.duration = duration
2930
self.stdout = stdout
3031
self.stderr = stderr
3132
self.error_message = error_message
33+
self.error_type = error_type # 'config', 'code', 'dependency', 'unknown'
3234

3335
def to_dict(self) -> dict:
3436
"""Convierte el resultado a un diccionario para JSON."""
@@ -38,10 +40,99 @@ def to_dict(self) -> dict:
3840
"duration": self.duration,
3941
"stdout": self.stdout,
4042
"stderr": self.stderr,
41-
"error_message": self.error_message
43+
"error_message": self.error_message,
44+
"error_type": self.error_type
4245
}
4346

4447

48+
def ensure_kernel_configured(kernel_root: Path) -> bool:
49+
"""
50+
Verifica que el kernel esté configurado y lo configura si es necesario.
51+
52+
Args:
53+
kernel_root: Directorio raíz del kernel
54+
55+
Returns:
56+
True si el kernel está configurado correctamente
57+
"""
58+
config_file = kernel_root / ".config"
59+
60+
# Si ya existe .config, asumir que está configurado
61+
if config_file.exists():
62+
return True
63+
64+
print("[COMPILE] Kernel not configured. Running 'make defconfig'...")
65+
try:
66+
result = subprocess.run(
67+
['make', 'defconfig'],
68+
cwd=str(kernel_root),
69+
capture_output=True,
70+
text=True,
71+
timeout=60
72+
)
73+
74+
if result.returncode == 0 and config_file.exists():
75+
print("[COMPILE] ✓ Kernel configured successfully")
76+
return True
77+
else:
78+
print(f"[COMPILE] ✗ Failed to configure kernel: {result.stderr[:200]}")
79+
return False
80+
81+
except Exception as e:
82+
print(f"[COMPILE] ✗ Exception while configuring kernel: {e}")
83+
return False
84+
85+
86+
def classify_compilation_error(error_msg: str, stderr: str) -> str:
87+
"""
88+
Clasifica el tipo de error de compilación para ayudar al diagnóstico.
89+
90+
Returns:
91+
Clasificación del error: 'config', 'code', 'dependency', 'unknown'
92+
"""
93+
error_lower = (error_msg + "\n" + stderr).lower()
94+
95+
# Errores de configuración del kernel (CONFIG_* no definido)
96+
config_indicators = [
97+
'undeclared',
98+
'not declared in this scope',
99+
'was not declared',
100+
'implicit declaration',
101+
'redefinition', # A veces por #ifdef CONFIG_
102+
]
103+
104+
# Errores de dependencia/header faltante
105+
dependency_indicators = [
106+
'no such file or directory',
107+
'cannot find',
108+
'#include',
109+
]
110+
111+
# Errores de código real (sintaxis, tipos, etc.)
112+
code_indicators = [
113+
'syntax error',
114+
'expected',
115+
'conflicting types',
116+
'incompatible',
117+
'invalid',
118+
]
119+
120+
# Clasificar
121+
for indicator in dependency_indicators:
122+
if indicator in error_lower:
123+
return 'dependency'
124+
125+
for indicator in config_indicators:
126+
if indicator in error_lower:
127+
return 'config'
128+
129+
for indicator in code_indicators:
130+
if indicator in error_lower:
131+
return 'code'
132+
133+
return 'unknown'
134+
135+
45136
def compile_single_file(file_path: Path, kernel_root: Path) -> CompilationResult:
46137
"""
47138
Compila un archivo individual del kernel Linux usando el sistema de build del kernel.
@@ -74,6 +165,7 @@ def compile_single_file(file_path: Path, kernel_root: Path) -> CompilationResult
74165

75166
success = result.returncode == 0
76167
error_msg = ""
168+
error_type = ""
77169

78170
if not success:
79171
# Extraer mensaje de error más relevante
@@ -84,14 +176,18 @@ def compile_single_file(file_path: Path, kernel_root: Path) -> CompilationResult
84176
error_msg = '\n'.join(error_msgs[:5]) # Primeros 5 errores
85177
else:
86178
error_msg = result.stderr[:500] # Primeros 500 chars si no hay errores explícitos
179+
180+
# Clasificar el tipo de error
181+
error_type = classify_compilation_error(error_msg, result.stderr)
87182

88183
return CompilationResult(
89184
file_path=str(file_path),
90185
success=success,
91186
duration=duration,
92187
stdout=result.stdout,
93188
stderr=result.stderr,
94-
error_message=error_msg
189+
error_message=error_msg,
190+
error_type=error_type
95191
)
96192

97193
except subprocess.TimeoutExpired:
@@ -156,6 +252,11 @@ def compile_modified_files(files: List[Path], kernel_root: Path,
156252
"""
157253
results = []
158254

255+
# Verificar/configurar el kernel antes de compilar
256+
if not ensure_kernel_configured(kernel_root):
257+
print("[COMPILE] ✗ Cannot compile without kernel configuration")
258+
return results
259+
159260
print(f"[COMPILE] Compilando {len(files)} archivos...")
160261

161262
for i, file_path in enumerate(files, 1):
@@ -224,13 +325,20 @@ def summarize_results(results: List[CompilationResult]) -> Dict:
224325
total_duration = sum(r.duration for r in results)
225326
avg_duration = total_duration / total if total > 0 else 0
226327

328+
# Clasificar errores por tipo
329+
error_types = {}
330+
for r in results:
331+
if not r.success and r.error_type:
332+
error_types[r.error_type] = error_types.get(r.error_type, 0) + 1
333+
227334
return {
228335
"total": total,
229336
"successful": successful,
230337
"failed": failed,
231338
"success_rate": (successful / total * 100) if total > 0 else 0,
232339
"total_duration": total_duration,
233-
"avg_duration": avg_duration
340+
"avg_duration": avg_duration,
341+
"error_types": error_types
234342
}
235343

236344

@@ -253,11 +361,25 @@ def print_summary(results: List[CompilationResult]):
253361
print(f"Tiempo promedio: {summary['avg_duration']:.2f}s")
254362
print("="*60)
255363

364+
# Mostrar clasificación de errores si hay fallos
365+
if summary.get('error_types'):
366+
print("\nClasificación de errores:")
367+
error_labels = {
368+
'config': 'Config/Context (símbolos no declarados por CONFIG_*)',
369+
'dependency': 'Dependencies (headers/archivos faltantes)',
370+
'code': 'Código (sintaxis, tipos, etc.)',
371+
'unknown': 'Desconocido'
372+
}
373+
for error_type, count in summary['error_types'].items():
374+
label = error_labels.get(error_type, error_type)
375+
print(f" • {label}: {count}")
376+
256377
if summary['failed'] > 0:
257378
print("\nArchivos con errores de compilación:")
258379
for result in results:
259380
if not result.success:
260-
print(f" ✗ {Path(result.file_path).name}")
381+
error_type_label = f" [{result.error_type}]" if result.error_type else ""
382+
print(f" ✗ {Path(result.file_path).name}{error_type_label}")
261383
if result.error_message:
262384
# Mostrar primera línea de error
263385
first_line = result.error_message.split('\n')[0]

0 commit comments

Comments
 (0)