File size: 2,769 Bytes
26bead7
 
 
 
 
 
 
 
 
 
 
 
cc7a977
26bead7
cc7a977
 
26bead7
 
 
 
cc7a977
26bead7
 
 
 
 
 
 
 
 
cc7a977
26bead7
 
 
 
 
 
 
 
 
 
 
 
 
 
cc7a977
26bead7
 
 
cc7a977
26bead7
cc7a977
26bead7
 
 
 
 
cc7a977
26bead7
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"""Compilation and tests module for the AI Python C Extensions Generator application."""

import os
import subprocess
import sys
from logging import getLogger


_logger = getLogger(__name__)


# Define a function to write outputs to a file with a given filename.
def write_file(data, path):
    """Write data to a file with the specified filename."""
    path.parent.mkdir(parents=True, exist_ok=True)
    with open(path, "w") as file:
        file.write(data)


# Extension compilation function.
def build_extension(compile_path):
    """Compile the C extension using 'setup.py' and return the compilation output."""
    # Set default COMSPEC to cmd.exe on Windows to avoid issues with some C compilers.
    if sys.platform == "win32":
        _logger.info('PATCHING COMSPEC FOR WINDOWS COMPILATION COMPATIBILITY...')
        preset_comspec = os.environ.get("COMSPEC")
        os.environ["COMSPEC"] = "C:\\Windows\\System32\\cmd.exe"
    try:
        _logger.info('STARTING COMPILATION PROCESS...')
        compile_cmd = ["python", "setup.py", "build_ext", "--inplace"]
        compile_result = subprocess.run(compile_cmd, env=os.environ, cwd=compile_path,
                                        check=True, text=True, capture_output=True)
    except subprocess.CalledProcessError as ex:
        _logger.error(f"COMPILATION FAILED WITH ERROR:\n{ex.stdout}\n{ex.stderr}")
        raise Exception(f"An error occurred while building:\n{ex.stdout}\n{ex.stderr}")
    finally:
        # Restore original COMSPEC on Windows.
        if sys.platform == "win32":
            _logger.info('RESTORING ORIGINAL COMSPEC...')
            os.environ["COMSPEC"] = preset_comspec
    _logger.info('COMPILATION COMPLETED SUCCESSFULLY.')
    return compile_result.stdout


# Extension compilation function.
def compile_extension(c_code, setup_code, module_name, compile_path):
    """Build the C extension from the provided codes."""
    try:  # Write the provided codes to their respective files.
        _logger.info('WRITING GENERATED C CODE TO FILE...')
        write_file(c_code, compile_path / f"{module_name}.c")
        _logger.info('WRITING GENERATED SETUP CODE TO FILE...')
        write_file(setup_code, compile_path / "setup.py")
    except Exception as ex:
        _logger.error(f"ERROR WHILE WRITING FILES:\n{ex}")
        return f"An error occurred while writing files:\n{ex}"
    try:  # Build the extension and capture the output.
        _logger.info('BUILDING THE EXTENSION...')
        build_output = build_extension(compile_path)
    except Exception as ex:  # If build fails, return the error message.
        _logger.error(f"ERROR WHILE BUILDING EXTENSION:\n{ex}")
        return str(ex)
    _logger.info('EXTENSION BUILT SUCCESSFULLY.')
    return build_output