colinux64/bin/comake/tools.py
2025-02-13 19:09:34 -07:00

309 lines
11 KiB
Python
Executable File

import os, tempfile, shutil
class TargetNotBuildError(Exception):
pass
class Tool(object):
EMPTY = False
def make(self, target, reporter):
raise TargetNotBuildError()
def cache(self, target):
return ''
def rebuild_needed(self, target):
return False
class ToolRunInfo(object):
def __init__(self, target, reporter, options):
self.target = target
self.reporter = reporter
self.options = options
class Empty(Tool):
EMPTY = True
def make(self, target, reporter):
return 0
class MakefileKbuild(Tool):
def _content(self, target):
from StringIO import StringIO
import os
from comake.defaults import file_id_allocator
global colinux_file_id
parameters = [os.path.dirname(target.pathname)]
compiler_defines = target.options.get('compiler_defines', {})
defines = compiler_defines.items()
defines.sort()
for key, value in defines:
if key == 'COLINUX_FILE_ID':
continue
if value is not None:
parameters.append('-D%s=%s' % (key, value))
continue
parameters.append('-D%s' % (key, ))
# Output-type coded in extension (lib-m or colinux-objs)
libm = target.get_ext()[1:]
output_file = StringIO()
print >>output_file, "include $(KBUILD_EXTMOD)/Makefile.include"
print >>output_file, "EXTRA_CFLAGS += -I$(COLINUX_BASE)/%s" % ' '.join(parameters)
for names in target.inputs:
name = os.path.basename(names.pathname)
if not name in [ 'file_ids.c', 'colinux.mod.c', 'colinux.c' ]:
full_name = os.path.join(parameters[0], name)
colinux_file_id = file_id_allocator.allocate(full_name)
oname = os.path.splitext(name)[0]+'.o'
print >>output_file, "%s += %s" % (libm, oname)
print >>output_file, "CFLAGS_%s = -DCOLINUX_FILE_ID=%d" % (oname, colinux_file_id)
return output_file.getvalue()
def make(self, target, reporter):
output_file = open(target.pathname, 'wb')
output_file.write(self._content(target))
def rebuild_needed(self, target):
return open(target.pathname, 'rb').read() != self._content(target)
class Copy(Tool):
def make(self, target, reporter):
input_pathnames = []
for tinput in target.get_actual_inputs():
if tinput.get_ext() in ['.c', '.cpp']:
actual_compile = True
input_pathnames.append(tinput.pathname)
if len(input_pathnames) != 1:
raise TargetNotBuildError()
pathnames = input_pathnames[0], target.pathname
reporter.print_text("Copying '%s' to '%s'" % pathnames)
shutil.copy(*pathnames)
class Executer(Tool):
def get_cross_build_tool(self, tool, tool_run_inf):
compiler_path = tool
cross_compilation_prefix = tool_run_inf.options.get('cross_compilation_prefix', None)
if cross_compilation_prefix:
compiler_path = cross_compilation_prefix + compiler_path
return compiler_path
def system(self, command_line, tool_run_inf):
tool_run_inf.reporter.print_text(command_line)
exit_status = os.system(command_line)
return exit_status
def make(self, target, reporter):
tool_run_inf = ToolRunInfo(target, reporter, target.options)
self.prepare_command(tool_run_inf)
try:
command_line = self.get_command_line(tool_run_inf)
exit_status = self.system(command_line, tool_run_inf)
finally:
self.cleanup(tool_run_inf)
if exit_status != 0:
raise TargetNotBuildError()
def cache(self, target):
tool_run_inf = ToolRunInfo(target, None, target.options)
return self.get_command_line(tool_run_inf)
def prepare_command(self, tool_run_inf):
pass
def get_command_line(self, tool_run_inf):
return ''
def cleanup(self, tool_run_inf):
pass
class Compiler(Executer):
def get_command_line(self, tool_run_inf):
from sys import platform
darwin = (platform == "darwin")
actual_compile = False
count_archives = 0
compiler_def_type = tool_run_inf.options.get('compiler_def_type', [])
if not compiler_def_type:
compiler_def_type = 'gcc'
compiler_path = self.get_cross_build_tool(compiler_def_type, tool_run_inf)
input_pathnames = []
for tinput in tool_run_inf.target.get_actual_inputs():
if tinput.get_ext() in ['.c', '.cpp']:
actual_compile = True
elif tinput.get_ext() in ['.a']:
count_archives += 1
elif tinput.get_ext() in ['.h']:
continue
input_pathnames.append(tinput.pathname)
parameters = []
parameters.append(compiler_path)
if actual_compile:
compiler_includes = tool_run_inf.options.get('compiler_includes', [])
parameters += ["-I" + path for path in compiler_includes]
compiler_flags = tool_run_inf.options.get('compiler_flags', [])
parameters += compiler_flags
compiler_optimization = tool_run_inf.options.get('compiler_optimization', "-O2")
parameters += [compiler_optimization]
compiler_defines = tool_run_inf.options.get('compiler_defines', {})
defines = compiler_defines.items()
defines.sort()
for key, value in defines:
if value is not None:
parameters.append('-D%s=%s' % (key, value))
continue
parameters.append('-D%s' % (key, ))
parameters.append('-c')
else:
linker_flags = tool_run_inf.options.get('linker_flags', [])
parameters += linker_flags
compiler_strip = tool_run_inf.options.get('compiler_strip', False)
if compiler_strip:
parameters.append('-Wl,--strip-debug')
if count_archives > 1 and not darwin:
parameters.append('-Wl,--start-group')
parameters.extend(input_pathnames)
compiler_lib_paths = tool_run_inf.options.get('compiler_lib_paths', [])
compiler_libs = tool_run_inf.options.get('compiler_libs', [])
parameters += ["-L" + path for path in compiler_lib_paths]
parameters += ["-l" + path for path in compiler_libs]
if not actual_compile:
parameters += tool_run_inf.options.get('linker_add', [])
if count_archives > 1 and not darwin:
parameters.append('-Wl,--end-group')
parameters.append('-o')
parameters.append(tool_run_inf.target.pathname)
command_line = ' '.join(parameters)
return command_line
class Linker(Executer):
def get_command_line(self, tool_run_inf):
actual_compile = False
link_path = self.get_cross_build_tool('ld', tool_run_inf)
input_pathnames = []
for tinput in tool_run_inf.target.get_actual_inputs():
input_pathnames.append(tinput.pathname)
parameters = []
parameters.append(link_path)
if tool_run_inf.target.get_ext() == '.o':
parameters.append('-r')
parameters.extend(input_pathnames)
parameters += tool_run_inf.options.get('linker_add', [])
parameters.append('-o')
parameters.append(tool_run_inf.target.pathname)
command_line = ' '.join(parameters)
return command_line
class Archiver(Executer):
def __init__(self, flat=True):
self.flat = flat
def get_command_line(self, tool_run_inf):
ar = self.get_cross_build_tool('ar', tool_run_inf)
parameters = []
parameters.append(ar)
parameters.append('cr')
parameters.append(tool_run_inf.target.pathname)
parameters.extend(tool_run_inf.ready_inputs)
command_line = ' '.join(parameters)
return command_line
def cache(self, target):
tool_run_inf = ToolRunInfo(target, None, target.options)
cmdline = self.get_cross_build_tool('ar', tool_run_inf)
cmdline += ' '.join([target.pathname for target in tool_run_inf.target.get_actual_inputs()])
return cmdline
def prepare_command(self, tool_run_inf):
tool_run_inf.flat_mode = False
ready_inputs = []
tool_run_inf.ready_inputs = ready_inputs
tool_run_inf.temp_dir = None
tool_run_inf.temp_dir_extract = None
tool_run_inf.temp_inputs = []
ar = self.get_cross_build_tool('ar', tool_run_inf)
input_pathnames = []
for tinput in tool_run_inf.target.get_actual_inputs():
if tinput.get_ext() == '.a':
if self.flat:
tool_run_inf.flat_mode = True
else:
ready_inputs.append(tinput.pathname)
else:
ready_inputs.append(tinput.pathname)
if tool_run_inf.flat_mode:
temp_dir = tempfile.mkdtemp()
temp_dir_extract = tempfile.mkdtemp()
tool_run_inf.temp_dir = temp_dir
tool_run_inf.temp_dir_extract = temp_dir_extract
file_index = 0
for tinput in tool_run_inf.target.get_actual_inputs():
if tinput.get_ext() == '.a':
cwd = os.getcwd()
real_path = os.path.realpath(tinput.pathname)
try:
os.chdir(temp_dir_extract)
self.system('ar x %s' % (real_path, ), tool_run_inf)
finally:
os.chdir(cwd)
for pathname in os.listdir(temp_dir_extract):
if pathname == '__.SYMDEF SORTED':
continue
fullname = os.path.join(temp_dir_extract, pathname)
destname = os.path.join(temp_dir, ("%d-" % (file_index, )) + pathname)
os.rename(fullname, destname)
tool_run_inf.ready_inputs.append(destname)
tool_run_inf.temp_inputs.append(destname)
file_index += 1
def cleanup(self, tool_run_inf):
if tool_run_inf.temp_dir:
for pathname in tool_run_inf.temp_inputs:
os.unlink(pathname)
name = os.path.join(tool_run_inf.temp_dir, '__.SYMDEF SORTED')
if os.path.exists(name):
os.unlink(name)
name = os.path.join(tool_run_inf.temp_dir_extract, '__.SYMDEF SORTED')
if os.path.exists(name):
os.unlink(name)
os.rmdir(tool_run_inf.temp_dir)
os.rmdir(tool_run_inf.temp_dir_extract)
class Script(Executer):
def __init__(self, func):
self.func = func
def get_command_line(self, tool_run_inf):
return self.func(self, tool_run_inf)
exported_tools = [
Compiler,
Linker,
Empty,
Script,
Tool,
Executer,
Copy,
MakefileKbuild,
]