From 9ce381a88bf18a5932c37ab4e9fc14dbc2f4a792 Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 16 Jun 2015 03:17:50 -0400 Subject: remove outdated note --- mconfig.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mconfig.py b/mconfig.py index 8bfea5a..fd64147 100644 --- a/mconfig.py +++ b/mconfig.py @@ -1,4 +1,3 @@ -# TODO: get rid of 'need'. Use a function that memoizes the object instead. import re, argparse, sys, os, string, shlex, subprocess, glob from collections import OrderedDict, namedtuple import curses.ascii -- cgit v1.2.3 From 5558f3331394ea0a9cad2aec1ca469e6a0406038 Mon Sep 17 00:00:00 2001 From: comex Date: Sat, 20 Jun 2015 03:21:49 -0400 Subject: We are actually emitting makefiles and building now (with make and ninja); some things remain for MVP though, like detecting makefile change, rebuilding in case of rule changes, helper functions... --- configure | 26 ++++++ mconfig.py | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 286 insertions(+), 31 deletions(-) create mode 100755 configure diff --git a/configure b/configure new file mode 100755 index 0000000..39163cb --- /dev/null +++ b/configure @@ -0,0 +1,26 @@ +#!/usr/bin/env python2.7 +import mconfig +settings = mconfig.settings_root +settings.package_unix_name.value = 'substitute' + +c = settings.host_machine().c_tools() + +c.cc.required() + +mconfig.parse_args() +settings.cflags = ['-I%s/lib' % (settings.src,)] + settings.cflags + +emitter = settings.emitter +mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, + 'dylib', + '(out)/libsubstitute.dylib', + [ + '(src)/lib/darwin/find-syms.c', + '(src)/lib/darwin/inject.c', + '(src)/lib/darwin/interpose.c', + ] +) +# todo use wrapper +emitter.add_command(['all'], [settings.out + '/libsubstitute.dylib'], [], phony=True) +emitter.set_default_rule('all') +mconfig.emit() diff --git a/mconfig.py b/mconfig.py index fd64147..3b3a6df 100644 --- a/mconfig.py +++ b/mconfig.py @@ -73,12 +73,14 @@ class memoize(object): raise class Pending(object): - def __str__(self): - return 'Pending', + def __repr__(self): + return 'Pending(%x%s)' % (id(self), ('; value=%r' % (self.value,)) if hasattr(self, 'value') else '') def resolve(self): return self.value # xxx py3 def __getattr__(self, attr): + if attr is 'value': + raise AttributeError return PendingAttribute(self, attr) class PendingOption(Pending, namedtuple('PendingOption', 'opt')): @@ -90,6 +92,8 @@ class PendingOption(Pending, namedtuple('PendingOption', 'opt')): class PendingAttribute(Pending, namedtuple('PendingAttribute', 'base attr')): def resolve(self): return getattr(self.base, self.attr) + def __repr__(self): + return 'PendingAttribute(attr=%s, base=%r)' % (self.attr, self.base) class SettingsGroup(object): def __init__(self, group_parent=None, inherit_parent=None, name=None): @@ -163,7 +167,9 @@ class SettingsGroup(object): def add_setting_option(self, name, optname, optdesc, default, **kwargs): def f(value): self[name] = value - default = Expansion(default, self) if isinstance(default, str) else default + if isinstance(default, str): + old = default + default = lambda: expand(old, self) opt = Option(optname, optdesc, f, default, **kwargs) self[name] = PendingOption(opt) @@ -228,20 +234,14 @@ class Option(object): if self.on_set is not None: self.on_set(value) -class Expansion(object): - def __init__(self, fmt, base): - assert isinstance(fmt, str) - self.fmt = fmt - self.deps = list(map(base.relative_lookup, re.findall('\((.*?)\)', fmt))) - def __repr__(self): - return 'Expansion(%r)' % (self.fmt,) - def __call__(self): - deps = self.deps[:] - def get_dep(m): - dep = deps.pop(0) - if isinstance(dep, Pending): - dep = dep.resolve() - return re.sub('\((.*?)\)', get_dep, self.fmt) +def expand(fmt, base): + def get_dep(m): + dep = base.relative_lookup(m.group(1)) + if isinstance(dep, Pending): + dep = dep.resolve() + print dep + return dep + return re.sub('\((.*?)\)', get_dep, fmt) def installation_dirs_group(sg): section = OptSection('Fine tuning of the installation directories:') @@ -298,6 +298,7 @@ def _print_help(include_unused=False): parser.print_help() def parse_args(): + will_need(pre_parse_args_will_need) default_opt_section.move_to_end() parser = _make_argparse(include_unused=True, include_env=False) args, argv = parser.parse_known_args() @@ -340,7 +341,7 @@ def parse_args(): will_need(post_parse_args_will_need) # -- toolchains -- -class Triple(namedtuple('Triple', 'triple arch forgot1 os forgot2')): +class Triple(namedtuple('Triple', 'triple arch vendor os abi')): def __new__(self, triple): if isinstance(triple, Triple): return triple @@ -349,10 +350,10 @@ class Triple(namedtuple('Triple', 'triple arch forgot1 os forgot2')): numbits = len(bits) if numbits > 4: raise Exception('strange triple %r' % (triple,)) - if numbits != 4: + if numbits in (2, 3) and bits[1] not in ('unknown', 'none', 'pc'): + # assume the vendor was left out bits.insert(1, None) return super(Triple, self).__new__(self, triple, *((bits.pop(0) if bits else None) for i in range(4))) - #def __repr__(self): def __str__(self): return self.triple @@ -385,6 +386,10 @@ class Machine(object): self._is_cross = self.triple != self.settings.build_machine().triple return self._is_cross + def is_darwin(self): + return (self.triple.os is not None and 'darwin' in self.triple.os) or \ + (self.triple.triple == '' and os.path.exists('/System/Library/Frameworks')) + # Get a list of appropriate toolchains. def toolchains(self): # memoized tcs = [] @@ -395,9 +400,9 @@ class Machine(object): #memoize def c_tools(self): - return CTools(self, self.toolchains()) + return CTools(self.settings, self, self.toolchains()) -class UnixTool(object): +class CLITool(object): def __init__(self, name, defaults, env, machine, toolchains, dont_suffix_env=False): self.name = name self.defaults = defaults @@ -413,7 +418,7 @@ class UnixTool(object): self.argv = memoize(self.argv) def __repr__(self): - return 'UnixTool(name=%r, defaults=%r, env=%r)' % (self.name, self.defaults, self.env) + return 'CLITool(name=%r, defaults=%r, env=%r)' % (self.name, self.defaults, self.env) def optional(self): self.argv_opt.need() @@ -462,9 +467,6 @@ class UnixToolchain(object): failure_notes.append('detected cross compilation, so searched for %s-%s' % (self.machine.triple.triple, tool.name)) return tool.locate_in_paths(prefix, self.settings.tool_search_paths) - def get_tool_search_paths(self): - return None # just use the default - # Reads a binary or XML plist (on OS X) def read_plist(gunk): import plistlib @@ -573,11 +575,10 @@ class XcodeToolchain(object): return None return argv -# Just a collection of common tools. +# Just a collection of common tools, plus flag options class CTools(object): - def __init__(self, machine, toolchains): + def __init__(self, settings, machine, toolchains): tools = [ - # TODO figure out ld ('cc', ['cc', 'gcc', 'clang'], 'CC'), ('cxx', ['c++', 'g++', 'clang++'], 'CXX'), ('ar',), @@ -595,9 +596,15 @@ class CTools(object): name, defaults, env = spec[0], [spec[0]], spec[0].upper() else: name, defaults, env = spec - tool = UnixTool(name, defaults, env, machine, toolchains) + tool = CLITool(name, defaults, env, machine, toolchains) setattr(self, name, tool) + section = OptSection('Compiler/linker flags:') + self.cflags_opt = settings.add_setting_option('cflags', 'CFLAGS=', 'Flags for $CC', [], section=section, type=shlex.split) + self.cxxflags_opt = settings.add_setting_option('cxxflags', 'CXXFLAGS=', 'Flags for $CXX', [], section=section, type=shlex.split) + self.ldflags_opt = settings.add_setting_option('ldflags', 'LDFLAGS=', 'Flags for $CC/$CXX when linking', [], section=section, type=shlex.split) + self.cppflags_opt = settings.add_setting_option('cppflags', 'CPPFLAGS=', 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=section, type=shlex.split) + # A nicer - but optional - way of doing multiple tests that will print all the # errors in one go and exit cleanly @@ -612,6 +619,215 @@ def will_need(tests): log('(%d failure%s.)\n' % (failures, 's' if failures != 1 else '')) sys.exit(1) +class Emitter(object): + def pre_output(self): + assert not hasattr(self, 'did_output') + self.did_output = True + def set_default_rule(self, rule): + self.default_rule = rule + +# In the future it may be desirable to use make variables and nontrivial ninja rules for efficiency. + +class MakefileEmitter(Emitter): + def __init__(self, settings): + self.settings = settings + self.makefile_bits = [] + + def add_all_and_clean(self): + if hasattr(self, 'default_rule'): + if self.default_rule != 'all': + self.add_command(['all'], [self.default_rule], [], phony=True) + else: + log('Warning: %r: no default rule\n' % (self,)) + self.makefile_bits.append('clean:\n\trm -rf %s\n' % (self.filename_rel_and_escape(self.settings.out))) + + @staticmethod + def filename_escape(fn): + if re.search('[\n\0]', fn): + raise ValueError("your awful filename %r can't be encoded in make (probably)" % (fn,)) + return re.sub(r'([ :\$\\])', r'\\\1', fn) + def filename_rel_and_escape(self, fn): + fn = os.path.relpath(fn, os.path.dirname(self.settings.emit_fn)) + return self.filename_escape(fn) + # depfile = ('makefile', filename) or ('msvc',) + def add_command(self, outs, ins, argvs, phony=False, depfile=None): + bit = '' + outs = ' '.join(map(self.filename_rel_and_escape, outs)) + ins = ' '.join(map(self.filename_rel_and_escape, ins)) + if phony: + bit += '.PHONY: %s\n' % (outs,) + bit += '%s:%s%s\n' % (outs, ' ' if ins else '', ins) + for argv in argvs: + bit += '\t' + argv_to_shell(argv) + '\n' + if depfile is not None: + if depfile[0] != 'makefile': + raise ValueError("don't support depfile of type %r" % (depfile[0],)) + bit += '-include %s\n' % (self.filename_rel_and_escape(depfile[1]),) + if 'all' in outs: + self.makefile_bits.insert(0, bit) + else: + self.makefile_bits.append(bit) + + def output(self): + self.pre_output() + self.add_all_and_clean() + return '\n'.join(self.makefile_bits) + + def default_outfile(self): + return 'Makefile' + +class NinjaEmitter(Emitter): + def __init__(self, settings): + self.settings = settings + self.ninja_bits = [] + self.ruleno = 0 + @staticmethod + def filename_escape(fn): + if re.search('[\n\0]', fn): + raise ValueError("your awful filename %r can't be encoded in ninja (probably)" % (fn,)) + return re.sub(r'([ :\$])', r'$\1', fn) + def add_command(self, outs, ins, argvs, phony=False, depfile=None): + bit = '' + if phony: + if len(argvs) == 0: + self.ninja_bits.append('build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, ins)))) + return + outs2 = ['__phony_' + out for out in outs] + bit += 'build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, outs2))) + outs = outs2 + rule_name = 'rule_%d' % (self.ruleno,) + self.ruleno += 1 + bit += 'rule %s\n' % (rule_name,) + bit += ' command = %s\n' % (' && $\n '.join(map(argv_to_shell, argvs))) + if depfile: + if depfile[0] not in ('makefile', 'msvc'): + raise ValueError("don't support depfile of type %r" % (depfile[0],)) + bit += ' deps = %s\n' % ({'makefile': 'gcc', 'msvc': 'msvc'}[depfile[0]],) + bit += ' depfile = %s\n' % (self.filename_escape(depfile[1]),) + bit += 'build %s: %s' % (' '.join(map(self.filename_escape, outs),), rule_name) + if ins: + bit += ' | %s' % (' '.join(map(self.filename_escape, ins),)) + bit += '\n' + self.ninja_bits.append(bit) + + def add_default(self): + if hasattr(self, 'default_rule'): + self.ninja_bits.append('default %s\n' % (self.default_rule,)) + else: + log('Warning: %r: no default rule\n' % (self,)) + + def output(self): + self.pre_output() + self.add_default() + return '\n'.join(self.ninja_bits) + + def default_outfile(self): + return 'build.ninja' + + +def add_emitter_option(): + def on_set_generate(val): + if val not in emitters: + raise DependencyNotFoundException('Unknown build script type: %s (options: %s)' % (val, ' '.join(emitters.keys()))) + settings_root.emitter = emitters[val](settings_root) + Option( + '--generate', + 'The type of build script to generate. Options: %s (default makefile)' % (', '.join(emitters.keys()),), + on_set_generate, default='makefile', section=output_section) + settings_root.add_setting_option('emit_fn', '--outfile', 'Output file. Default: depends on type', section=output_section, default=lambda: settings_root.emitter.default_outfile()) + +# TODO +def emit(): + output = settings_root.emitter.output() + fn = settings_root.emit_fn + log('Writing %s\n' % (fn,)) + fp = open(fn, 'w') + fp.write(output) + fp.close() + +# see cc_to_use_cb +def default_cc_to_use(filename): + root, ext = os.path.splitext(filename) + return ext in ('cc', 'cpp', 'cxx', 'mm') + +# emitter: the emitter to add rules to +# machine: machine +# settings: settings object; will inspect {c,cxx,cpp,ld}flags +# sources: list of source files +# headers: *optional* list of header files that will be used in the future to +# generate IDE projects - unused for makefile/ninja due to +# depfiles +# objs: list of .o files or other things to add to the link +# link_out: optional linker output +# link_type: 'exec', 'dylib', 'staticlib', 'obj'; default exec +# info_cb: (filename) -> a dict with any of these keys: +# 'is_cxx': True ($CXX) or False ($CC); ignored in IDE native mode +# 'cc': override cc altogther; ignored in IDE native mode +# 'cflags': *override* cflags; never ignored +# 'obj_fn': ... +# 'extra_deps': dependencies +# force_cli: don't use IDEs' native C/C++ compilation mechanism +# expand: call expand on filenames +def build_c_objs(emitter, machine, settings, sources, headers=[], info_cb=None, force_cli=False, expand=True): + if expand: + headers = [expand(header, settings) for header in headers] + tools = machine.c_tools() + any_was_cxx = False + obj_fns = [] + _expand = globals()['expand'] + for fn in sources: + if expand: + fn = _expand(fn, settings) + info = {} if info_cb is None else info_cb(fn) + obj_fn = info['obj_fn'] if 'obj_fn' in info else guess_obj_fn(fn, settings) + is_cxx = info.get('is_cxx', False) + cflags = info['cflags'] if 'cflags' in info else (settings.cxxflags if is_cxx else settings.cflags) + cc = info['cc'] if 'cc' in info else (tools.cxx if is_cxx else tools.cc).argv() + extra_deps = info.get('extra_deps', []) + any_was_cxx = any_was_cxx or is_cxx + dep_fn = os.path.splitext(obj_fn)[0] + '.d' + + mkdir_cmd = ['mkdir', '-p', os.path.dirname(obj_fn)] + cmd = cc + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] + + emitter.add_command([obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn)) + obj_fns.append(obj_fn) + + return obj_fns, any_was_cxx + +def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[]): + if expand: + _expand = globals()['expand'] + link_out = _expand(link_out, settings) + objs = [_expand(obj, settings) for obj in objs] + tools = machine.c_tools() + assert link_type in ('exec', 'dylib', 'staticlib', 'obj') + if link_type in ('exec', 'dylib'): + assert link_with_cxx in (False, True) + cc_for_link = (tools.cxx if link_with_cxx else tools.cc).argv() + if link_type == 'dylib': + typeflag = ['-dynamiclib'] if machine.is_darwin() else ['-shared'] + else: + typeflag = [] + cmd = cc_for_link + typeflag + settings.ldflags + ['-o', link_out] + objs + elif link_type == 'staticlib': + cmd = tools.ar() + ['rcs'] + objs + elif link_type == 'obj': + cmd = tools.cc() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs + mkdir_cmd = ['mkdir', '-p', os.path.dirname(link_out)] + emitter.add_command([link_out], objs + extra_deps, [mkdir_cmd, cmd]) + +def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], info_cb=None, force_cli=False, expand=True, extra_deps=[]): + more_objs, link_with_cxx = build_c_objs(emitter, machine, settings, sources, headers, info_cb, force_cli, expand) + link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps) + +def guess_obj_fn(fn, settings): + rel = os.path.relpath(fn, settings.src) + if not rel.startswith('../'): + rel = os.path.splitext(rel)[0] + '.o' + return os.path.join(settings.out, rel) + raise ValueError("can't guess .o filename for %r, as it's not in settings.src" % (fn,)) + # -- init code -- @@ -623,18 +839,31 @@ all_options = [] all_options_by_name = {} all_opt_sections = [] default_opt_section = OptSection('Uncategorized options:') +pre_parse_args_will_need = [] post_parse_args_will_need = [] settings_root = SettingsGroup(name='root') settings_root.package_unix_name = Pending() installation_dirs_group(settings_root.new_child('idirs')) +output_section = OptSection('Output options:') + triple_options_section = OptSection('System types:') -settings_root.build_machine = memoize(lambda: Machine('build', settings_root, 'the machine doing the build', '')) +settings_root.build_machine = memoize(lambda: Machine('build', settings_root, 'the machine doing the build', lambda: Triple(''))) settings_root.host_machine = memoize(lambda: settings_root.build_machine() and Machine('host', settings_root, 'the machine that will run the compiled program', lambda: settings_root.build_machine().triple)) # ...'the machine that the program will itself compile programs for', settings_root.tool_search_paths = os.environ['PATH'].split(':') +settings_root.src = os.path.dirname(sys.argv[0]) +settings_root.out = os.path.join(os.getcwd(), 'out') + +emitters = { + 'makefile': MakefileEmitter, + 'ninja': NinjaEmitter, +} + +pre_parse_args_will_need.append(add_emitter_option) + # -- -- cgit v1.2.3 From 9adbc0e6f54c9aba9fdae4c0387f9e9ec75a3bc5 Mon Sep 17 00:00:00 2001 From: comex Date: Sun, 21 Jun 2015 11:46:09 -0400 Subject: improve expand() and add support to add_command --- configure | 8 +++-- mconfig.py | 103 +++++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/configure b/configure index 39163cb..6526965 100755 --- a/configure +++ b/configure @@ -20,7 +20,9 @@ mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, '(src)/lib/darwin/interpose.c', ] ) -# todo use wrapper -emitter.add_command(['all'], [settings.out + '/libsubstitute.dylib'], [], phony=True) + +settings.test = 'foo baz' +emitter.add_command(settings, ['all'], ['(out)/libsubstitute.dylib'], [], phony=True) emitter.set_default_rule('all') -mconfig.emit() + +mconfig.finish_and_emit() diff --git a/mconfig.py b/mconfig.py index 3b3a6df..014ea23 100644 --- a/mconfig.py +++ b/mconfig.py @@ -1,4 +1,4 @@ -import re, argparse, sys, os, string, shlex, subprocess, glob +import re, argparse, sys, os, string, shlex, subprocess, glob, parser from collections import OrderedDict, namedtuple import curses.ascii @@ -160,10 +160,6 @@ class SettingsGroup(object): s += '}' return s - def relative_lookup(self, name): - name = re.sub('^\.\.', 'group_parent.', name) - return eval('self.' + name) - def add_setting_option(self, name, optname, optdesc, default, **kwargs): def f(value): self[name] = value @@ -234,14 +230,61 @@ class Option(object): if self.on_set is not None: self.on_set(value) -def expand(fmt, base): - def get_dep(m): - dep = base.relative_lookup(m.group(1)) - if isinstance(dep, Pending): - dep = dep.resolve() - print dep - return dep - return re.sub('\((.*?)\)', get_dep, fmt) +def parse_expander(fmt): + bits = [] + z = 0 + while True: + y = fmt.find('(', z) + if y == -1: + bits.append(fmt[z:]) + break + bits.append(fmt[z:y]) + should_shlex_result = False + if fmt[y+1:y+2] == '*': + should_shlex_result = True + y += 1 + try: + parser.expr(fmt[y+1:]) + except SyntaxError as e: + offset = e.offset + if offset == 0 or fmt[y+1+offset-1] != ')': + raise + bits.append((compile(fmt[y+1:y+1+offset-1], '', 'eval'), should_shlex_result)) + z = y+1+offset + return bits + +def eval_expand_bit(bit, settings): + dep = eval(bit, settings.vals, settings.__dict__) + if isinstance(dep, Pending): + dep = dep.resolve() + return dep + +def expand(fmt, settings): + bits = parse_expander(fmt) + return ''.join((bit if isinstance(bit, basestring) else eval_expand_bit(bit[0], settings)) for bit in bits) + +def expand_argv(argv, settings): + if isinstance(argv, basestring): + bits = parse_expander(argv) + shell = ''.join(bit if isinstance(bit, basestring) else '(!)' for bit in bits) + codes = [bit for bit in bits if not isinstance(bit, basestring)] + argv = shlex.split(shell) + out_argv = [] + for arg in argv: + first = True + out_argv.append('') + for bit in arg.split('(!)'): + if not first: + code, should_shlex_result = codes.pop(0) + res = eval_expand_bit(code, settings) + res = shlex.split(res) if should_shlex_result else [res] + out_argv[-1] += res[0] + out_argv.extend(res[1:]) + first = False + out_argv[-1] += bit + return out_argv + else: + return [expand(arg, settings) for arg in argv] def installation_dirs_group(sg): section = OptSection('Fine tuning of the installation directories:') @@ -259,7 +302,7 @@ def installation_dirs_group(sg): ('share', '--datadir', '', '(datarootdir)'), ('locale', '--localedir', '', '(datarootdir)/locale'), ('man', '--mandir', '', '(datarootdir)/man'), - ('doc', '--docdir', '', '(datarootdir)/doc/(..package_unix_name)'), + ('doc', '--docdir', '', '(datarootdir)/doc/(group_parent.package_unix_name)'), ('html', '--htmldir', '', '(doc)'), ('pdf', '--pdfdir', '', '(doc)'), ]: @@ -625,6 +668,18 @@ class Emitter(object): self.did_output = True def set_default_rule(self, rule): self.default_rule = rule + def add_command(self, settings, outs, ins, argvs, *args, **kwargs): + outs = [expand(x, settings) for x in outs] + ins = [expand(x, settings) for x in ins] + argvs = [expand_argv(x, settings) for x in argvs] + return self.add_command_raw(outs, ins, argvs, *args, **kwargs) + def emit(self, fn): + output = self.output() + log('Writing %s\n' % (fn,)) + fp = open(fn, 'w') + fp.write(output) + fp.close() + # In the future it may be desirable to use make variables and nontrivial ninja rules for efficiency. @@ -636,7 +691,7 @@ class MakefileEmitter(Emitter): def add_all_and_clean(self): if hasattr(self, 'default_rule'): if self.default_rule != 'all': - self.add_command(['all'], [self.default_rule], [], phony=True) + self.add_command_raw(['all'], [self.default_rule], [], phony=True) else: log('Warning: %r: no default rule\n' % (self,)) self.makefile_bits.append('clean:\n\trm -rf %s\n' % (self.filename_rel_and_escape(self.settings.out))) @@ -650,7 +705,7 @@ class MakefileEmitter(Emitter): fn = os.path.relpath(fn, os.path.dirname(self.settings.emit_fn)) return self.filename_escape(fn) # depfile = ('makefile', filename) or ('msvc',) - def add_command(self, outs, ins, argvs, phony=False, depfile=None): + def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): bit = '' outs = ' '.join(map(self.filename_rel_and_escape, outs)) ins = ' '.join(map(self.filename_rel_and_escape, ins)) @@ -686,7 +741,7 @@ class NinjaEmitter(Emitter): if re.search('[\n\0]', fn): raise ValueError("your awful filename %r can't be encoded in ninja (probably)" % (fn,)) return re.sub(r'([ :\$])', r'$\1', fn) - def add_command(self, outs, ins, argvs, phony=False, depfile=None): + def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): bit = '' if phony: if len(argvs) == 0: @@ -736,14 +791,8 @@ def add_emitter_option(): on_set_generate, default='makefile', section=output_section) settings_root.add_setting_option('emit_fn', '--outfile', 'Output file. Default: depends on type', section=output_section, default=lambda: settings_root.emitter.default_outfile()) -# TODO -def emit(): - output = settings_root.emitter.output() - fn = settings_root.emit_fn - log('Writing %s\n' % (fn,)) - fp = open(fn, 'w') - fp.write(output) - fp.close() +def finish_and_emit(): + settings_root.emitter.emit(settings_root.emit_fn) # see cc_to_use_cb def default_cc_to_use(filename): @@ -790,7 +839,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], info_cb=None, mkdir_cmd = ['mkdir', '-p', os.path.dirname(obj_fn)] cmd = cc + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] - emitter.add_command([obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn)) + emitter.add_command_raw([obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn)) obj_fns.append(obj_fn) return obj_fns, any_was_cxx @@ -815,7 +864,7 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with elif link_type == 'obj': cmd = tools.cc() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs mkdir_cmd = ['mkdir', '-p', os.path.dirname(link_out)] - emitter.add_command([link_out], objs + extra_deps, [mkdir_cmd, cmd]) + emitter.add_command_raw([link_out], objs + extra_deps, [mkdir_cmd, cmd]) def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], info_cb=None, force_cli=False, expand=True, extra_deps=[]): more_objs, link_with_cxx = build_c_objs(emitter, machine, settings, sources, headers, info_cb, force_cli, expand) -- cgit v1.2.3 From 88666c94eda8af35974889d275248daf451a0005 Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 23 Jun 2015 20:46:07 -0400 Subject: build_c_objs improvements --- configure | 7 +++++-- mconfig.py | 53 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/configure b/configure index 6526965..c1b9be1 100755 --- a/configure +++ b/configure @@ -18,10 +18,13 @@ mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, '(src)/lib/darwin/find-syms.c', '(src)/lib/darwin/inject.c', '(src)/lib/darwin/interpose.c', - ] + ], + #settings_cb=lambda fn: settings.specialize(override_is_cxx=True) + + ) -settings.test = 'foo baz' +#settings.test = 'foo baz' emitter.add_command(settings, ['all'], ['(out)/libsubstitute.dylib'], [], phony=True) emitter.set_default_rule('all') diff --git a/mconfig.py b/mconfig.py index 014ea23..72942bf 100644 --- a/mconfig.py +++ b/mconfig.py @@ -113,7 +113,7 @@ class SettingsGroup(object): if inherit_parent is not None: ret = SettingsGroup.get_meat(inherit_parent, attr, exctype) if isinstance(ret, SettingsGroup): - ret = self[attr] = ret.new_inheritor(name='%s.%s' % (object.__getattribute__(self, 'name'), attr)) + ret = self[attr] = ret.specialize(name='%s.%s' % (object.__getattribute__(self, 'name'), attr)) return ret raise exctype(attr) else: @@ -141,6 +141,11 @@ class SettingsGroup(object): return self.__getattribute__(attr) def __setitem__(self, attr, val): self.vals[attr] = val + def get(self, attr, default=None): + try: + return self[attr] + except AttributeError: + return default def __iter__(self): return self.vals.__iter__() @@ -169,8 +174,11 @@ class SettingsGroup(object): opt = Option(optname, optdesc, f, default, **kwargs) self[name] = PendingOption(opt) - def new_inheritor(self, *args, **kwargs): - return SettingsGroup(inherit_parent=self, *args, **kwargs) + def specialize(self, name=None, **kwargs): + sg = SettingsGroup(inherit_parent=self, name=name) + for key, val in kwargs.items(): + sg[key] = val + return sg def new_child(self, name, *args, **kwargs): sg = SettingsGroup(group_parent=self, name='%s.%s' % (self.name, name), *args, **kwargs) @@ -794,8 +802,7 @@ def add_emitter_option(): def finish_and_emit(): settings_root.emitter.emit(settings_root.emit_fn) -# see cc_to_use_cb -def default_cc_to_use(filename): +def default_is_cxx(filename): root, ext = os.path.splitext(filename) return ext in ('cc', 'cpp', 'cxx', 'mm') @@ -809,15 +816,15 @@ def default_cc_to_use(filename): # objs: list of .o files or other things to add to the link # link_out: optional linker output # link_type: 'exec', 'dylib', 'staticlib', 'obj'; default exec -# info_cb: (filename) -> a dict with any of these keys: -# 'is_cxx': True ($CXX) or False ($CC); ignored in IDE native mode -# 'cc': override cc altogther; ignored in IDE native mode -# 'cflags': *override* cflags; never ignored -# 'obj_fn': ... -# 'extra_deps': dependencies +# settings_cb: (filename) -> None or a settings object to override the default +# the following keys are accepted: +# override_cxx: True ($CXX) or False ($CC); ignored in IDE native mode +# override_cc: override cc altogther; ignored in IDE native mode +# override_obj_fn: the .o file +# extra_deps: dependencies # force_cli: don't use IDEs' native C/C++ compilation mechanism # expand: call expand on filenames -def build_c_objs(emitter, machine, settings, sources, headers=[], info_cb=None, force_cli=False, expand=True): +def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=None, force_cli=False, expand=True): if expand: headers = [expand(header, settings) for header in headers] tools = machine.c_tools() @@ -827,12 +834,18 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], info_cb=None, for fn in sources: if expand: fn = _expand(fn, settings) - info = {} if info_cb is None else info_cb(fn) - obj_fn = info['obj_fn'] if 'obj_fn' in info else guess_obj_fn(fn, settings) - is_cxx = info.get('is_cxx', False) - cflags = info['cflags'] if 'cflags' in info else (settings.cxxflags if is_cxx else settings.cflags) - cc = info['cc'] if 'cc' in info else (tools.cxx if is_cxx else tools.cc).argv() - extra_deps = info.get('extra_deps', []) + my_settings = settings + if settings_cb is not None: + s = settings_cb(fn) + if s is not None: + my_settings = s + obj_fn = my_settings.get('override_obj_fn') or guess_obj_fn(fn, settings) + is_cxx = my_settings.get('override_is_cxx') + if is_cxx is None: + is_cxx = default_is_cxx(fn) + cflags = my_settings.cxxflags if is_cxx else my_settings.cflags + cc = my_settings.get('override_cc') or (tools.cxx if is_cxx else tools.cc).argv() + extra_deps = my_settings.get('extra_deps', []) any_was_cxx = any_was_cxx or is_cxx dep_fn = os.path.splitext(obj_fn)[0] + '.d' @@ -866,8 +879,8 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with mkdir_cmd = ['mkdir', '-p', os.path.dirname(link_out)] emitter.add_command_raw([link_out], objs + extra_deps, [mkdir_cmd, cmd]) -def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], info_cb=None, force_cli=False, expand=True, extra_deps=[]): - more_objs, link_with_cxx = build_c_objs(emitter, machine, settings, sources, headers, info_cb, force_cli, expand) +def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[]): + more_objs, link_with_cxx = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps) def guess_obj_fn(fn, settings): -- cgit v1.2.3 From ddcbd946b512c3f06db8596cb3052b9f7ca545a6 Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 25 Jun 2015 21:33:07 -0400 Subject: ... --- configure | 47 +++++++++++++- mconfig.py | 211 ++++++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 198 insertions(+), 60 deletions(-) diff --git a/configure b/configure index c1b9be1..4eecda0 100755 --- a/configure +++ b/configure @@ -7,23 +7,64 @@ c = settings.host_machine().c_tools() c.cc.required() +asm_archs = [ + ('x86_64', []), + ('i386', []), + ('arm', ['-marm']), + ('arm64', []), # XXX +] + +machs = [] +for name, cflags in asm_archs: + mach = mconfig.Machine('asm-' + name, settings, 'for cross-compiling the inject baton', name + '-apple-darwin10') + machs.append(mach) + mach.c_tools().cc.required() + + mconfig.parse_args() settings.cflags = ['-I%s/lib' % (settings.src,)] + settings.cflags +settings.debug_info = True emitter = settings.emitter -mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, + +balco = lambda *args, **kwargs: mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, *args, **kwargs) + +# Note: the order of darwin-inject-asm.o is significant. Per man page, ld is +# guaranteed to link objects in order, which is necessary because +# darwin-inject-asm.S does not itself ensure there is at least 0x4000 bytes of +# executable stuff after inject_page_start (so that arm can remap into arm64). +# By putting it at the beginning, we can just reuse the space for the rest of +# the library rather than having to pad with zeroes. +# (This only matters on 32-bit ARM, and the text segment is currently 0xa000 +# bytes there, more than enough.) + +balco( 'dylib', '(out)/libsubstitute.dylib', [ + '(src)/generated/darwin-inject-asm.S', '(src)/lib/darwin/find-syms.c', '(src)/lib/darwin/inject.c', '(src)/lib/darwin/interpose.c', + '(src)/lib/darwin/objc-asm.S', + '(src)/lib/darwin/objc.c', + '(src)/lib/darwin/read.c', + '(src)/lib/darwin/substrate-compat.c', + '(src)/lib/darwin/execmem.c', + '(src)/lib/cbit/vec.c', + '(src)/lib/jump-dis.c', + '(src)/lib/transform-dis.c', + '(src)/lib/hook-functions.c', + '(src)/lib/strerror.c', ], #settings_cb=lambda fn: settings.specialize(override_is_cxx=True) - - ) +#for name, arch_flag, opts in [ +#]: +#compile_c_objs(emitter, settings.host_machine(), + + #settings.test = 'foo baz' emitter.add_command(settings, ['all'], ['(out)/libsubstitute.dylib'], [], phony=True) emitter.set_default_rule('all') diff --git a/mconfig.py b/mconfig.py index 72942bf..973f748 100644 --- a/mconfig.py +++ b/mconfig.py @@ -1,4 +1,4 @@ -import re, argparse, sys, os, string, shlex, subprocess, glob, parser +import re, argparse, sys, os, string, shlex, subprocess, glob, parser, hashlib, json from collections import OrderedDict, namedtuple import curses.ascii @@ -9,6 +9,9 @@ def log(x): sys.stdout.write(x) config_log.write(x) +def to_upper_and_underscore(s): + return s.upper().replace('-', '_') + def argv_to_shell(argv): quoteds = [] for arg in argv: @@ -51,6 +54,7 @@ def run_command(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs): config_log.write(so.rstrip()) config_log.write('\n stderr:\n') config_log.write(se.rstrip()) + config_log.write('\n-----------\n') return so, se, p.returncode class DependencyNotFoundException(Exception): @@ -414,6 +418,8 @@ class Machine(object): self.settings = settings def on_set(val): self.triple = val + if isinstance(triple_default, basestring): + triple_help += '; default: %r' % (triple_default,) self.triple_option = Option('--' + name, help=triple_help, default=triple_default, on_set=on_set, type=Triple, section=triple_options_section) self.triple = PendingOption(self.triple_option) @@ -454,18 +460,18 @@ class Machine(object): return CTools(self.settings, self, self.toolchains()) class CLITool(object): - def __init__(self, name, defaults, env, machine, toolchains, dont_suffix_env=False): + def __init__(self, name, defaults, env, machine, toolchains, dont_suffix_env=False, section=None): self.name = name self.defaults = defaults self.env = env self.toolchains = toolchains self.needed = False if machine.name != 'host' and not dont_suffix_env: - env = '%s_FOR_%s' % (env, machine.name.upper()) + env = '%s_FOR_%s' % (env, to_upper_and_underscore(machine.name)) def on_set(val): if val is not None: self.argv_from_opt = shlex.split(val) - self.argv_opt = Option(env + '=', help='Default: %r' % (defaults,), on_set=on_set, show=False) + self.argv_opt = Option(env + '=', help='Default: %r' % (defaults,), on_set=on_set, show=False, section=section) self.argv = memoize(self.argv) def __repr__(self): @@ -534,49 +540,66 @@ def read_plist(gunk): class XcodeToolchain(object): def __init__(self, machine, settings): self.machine = machine - prefix = machine.name if machine.name != 'host' else '' + prefix = (machine.name + '-') if machine.name != 'host' else '' + section = OptSection('Xcode SDK options (%s):' % (machine.name,)) name = '--%sxcode-sdk' % (prefix,) - self.sdk_opt = Option(name, help='Use Xcode SDK - `xcodebuild -showsdks` lists; typical values: macosx, iphoneos, iphonesimulator, watchos, watchsimulator', on_set=self.on_set_sdk) - self.got_sdk = False + self.sdk_opt = Option(name, help='Use Xcode SDK - `xcodebuild -showsdks` lists; typical values: macosx, iphoneos, iphonesimulator, watchos, watchsimulator', on_set=None, section=section) name = '--%sxcode-archs' % (prefix,) - self.sdk_opt = Option(name, help='Comma-separated list of -arch settings for use with an Xcode toolchain', on_set=self.on_set_arch) - self.got_arch = False - - def on_set_sdk(self, val): - using_default = val is None - self.using_default_sdk = using_default - if using_default: - if self.machine != settings_root.build_machine(): - # assume some other kind of cross compilation - return - val = 'macosx' + self.arch_opt = Option(name, help='Comma-separated list of -arch settings for use with an Xcode toolchain', on_set=self.on_set_arch, section=section) + self.ok = False + + def on_set_arch(self, arch): + self.sdk = self.sdk_opt.value + some_explicit_xcode_request = bool(self.sdk or arch) + tarch = arch + if not arch and self.machine.triple.arch is not None: + tarch = self.machine.triple.arch + if tarch == 'arm': + log("Warning: treating 'arm' in triple %r as '-arch armv7'; you can specify a triple like 'armv7-apple-darwin10', or override with %r" % (self.machine.triple.triple, self.arch_opt.name)) + tarch = 'armv7' + elif tarch == 'armv8': # XXX is this right? + tarch = 'arm64' + if not self.sdk: + is_armish = tarch is not None and tarch.startswith('arm') + self.sdk = 'iphoneos' if is_armish else 'macosx' # this is used for arch and also serves as a check - sdk_platform_path, _, code = run_command(['/usr/bin/xcrun', '--sdk', val, '--show-sdk-platform-path']) + sdk_platform_path, _, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, '--show-sdk-platform-path']) if code == 127: log('* Failed to run /usr/bin/xcrun\n') - if not using_default: + if some_explicit_xcode_request: raise DependencyNotFoundException return elif code: - log('* Xcode SDK %r not found\n' % (val,)) - if not using_default: + log('* Xcode SDK %r not found\n' % (self.sdk,)) + if some_explicit_xcode_request: raise DependencyNotFoundException return self.sdk_platform_path = sdk_platform_path.rstrip() log('Xcode SDK platform path: %r\n' % (self.sdk_platform_path,)) - self.got_sdk = True - - def on_set_arch(self, val): - if not self.got_sdk: + self.archs = self.get_archs(arch, tarch) + if self.archs is None: + log("%s default Xcode SDK for %r because %s; pass %s=arch1,arch2 to override\n" % ( + "Can't use" if some_explicit_xcode_request else "Not using", + self.machine.name, + ("triple architecture %r doesn't seem to be valid" % (tarch,)) if tarch is not None else "I couldn't guess a list of architectures from the SDK", + self.arch_opt.name, + )) + if some_explicit_xcode_request: + raise DependencyNotFoundException return - self.archs = self.get_archs(val) - log('Using architectures: %s\n' % (repr(self.archs) if self.archs != [] else '(native)')) - self.got_arch = True + log('Using architectures for %r: %s\n' % (self.machine.name, repr(self.archs) if self.archs != [] else '(native)')) + self.ok = True - def get_archs(self, val): - if val is not None: + def get_archs(self, arch, tarch): + if arch: return re.sub('\s', '', val).split(',') + if tarch: + # we need to validate it + sod, sed, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, 'ld', '-arch', tarch]) + if 'unsupported arch' in sed: + return None + triple = self.machine.triple # try to divine appropriate architectures # this may fail with future versions of Xcode, but at least we tried if self.sdk_platform_path.endswith('MacOSX.platform'): @@ -608,17 +631,15 @@ class XcodeToolchain(object): log('(Failed to divine architectures from %r for some reason...)\n' % (spec,)) # give up - log("%s default Xcode SDK because I can't figure out a reasonable list of architectures; pass %s=arch1,arch2 to override\n" % ( - "Not using" if self.using_default_sdk else "Can't use", - self.arch_opt.name, - )) - if self.using_default_sdk: - raise DependencyNotFoundException + return None + + def arch_flags(self): + return [flag for arch in self.archs for flag in ('-arch', arch)] def find_tool(self, tool, failure_notes): - if not self.got_arch: + if not self.ok: return None - argv = ['/usr/bin/xcrun', tool.name] + argv = ['/usr/bin/xcrun', '--sdk', self.sdk, tool.name] + self.arch_flags() sod, sed, code = run_command(argv + ['--asdf']) if code != 0: if sed.startswith('xcrun: error: unable to find utility'): @@ -629,6 +650,9 @@ class XcodeToolchain(object): # Just a collection of common tools, plus flag options class CTools(object): def __init__(self, settings, machine, toolchains): + flags_section = OptSection('Compiler/linker flags (%s):' % (machine.name,)) + tools_section = OptSection('Tool overrides (%s):' % (machine.name,)) + tools = [ ('cc', ['cc', 'gcc', 'clang'], 'CC'), ('cxx', ['c++', 'g++', 'clang++'], 'CXX'), @@ -641,20 +665,24 @@ class CTools(object): ('objcopy', ['objcopy', 'gobjcopy'], 'OBJCOPY'), # OS X ('lipo',), + ('dsymutil',), ] for spec in tools: if len(spec) == 1: name, defaults, env = spec[0], [spec[0]], spec[0].upper() else: name, defaults, env = spec - tool = CLITool(name, defaults, env, machine, toolchains) + tool = CLITool(name, defaults, env, machine, toolchains, section=tools_section) setattr(self, name, tool) - section = OptSection('Compiler/linker flags:') - self.cflags_opt = settings.add_setting_option('cflags', 'CFLAGS=', 'Flags for $CC', [], section=section, type=shlex.split) - self.cxxflags_opt = settings.add_setting_option('cxxflags', 'CXXFLAGS=', 'Flags for $CXX', [], section=section, type=shlex.split) - self.ldflags_opt = settings.add_setting_option('ldflags', 'LDFLAGS=', 'Flags for $CC/$CXX when linking', [], section=section, type=shlex.split) - self.cppflags_opt = settings.add_setting_option('cppflags', 'CPPFLAGS=', 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=section, type=shlex.split) + suff = '' + if machine.name != 'host': + suff = '_FOR_' + to_upper_and_underscore(machine.name) + suff += '=' + self.cflags_opt = settings.add_setting_option('cflags', 'CFLAGS'+suff, 'Flags for $CC', [], section=flags_section, type=shlex.split) + self.cxxflags_opt = settings.add_setting_option('cxxflags', 'CXXFLAGS'+suff, 'Flags for $CXX', [], section=flags_section, type=shlex.split) + self.ldflags_opt = settings.add_setting_option('ldflags', 'LDFLAGS'+suff, 'Flags for $CC/$CXX when linking', [], section=flags_section, type=shlex.split) + self.cppflags_opt = settings.add_setting_option('cppflags', 'CPPFLAGS'+suff, 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=flags_section, type=shlex.split) # A nicer - but optional - way of doing multiple tests that will print all the @@ -670,18 +698,56 @@ def will_need(tests): log('(%d failure%s.)\n' % (failures, 's' if failures != 1 else '')) sys.exit(1) +def within_dirtree(tree, fn): + return not os.path.relpath(fn, tree).startswith('..'+os.path.sep) + +real_out = memoize(lambda: os.path.realpath(settings_root.out)) +def clean_files(fns, settings): + ro = real_out() + for fn in fns: + if not os.path.exists(fn) or os.path.isdir(fn): + continue + if not settings.allow_autoclean_outside_out and within_dirtree(ro, os.path.realpath(fn)): + log('* Would clean %r as previous build leftover, but it isn\'t in settings.out (%r) so keeping it for safety.\n' % (fn, ro)) + continue + config_log.write('Removing %r\n' % (fn,)) + os.remove(fn) + +def list_mconfig_scripts(settings): + real_src = os.path.realpath(settings.src) + res = [] + for mod in sys.modules.values(): + if hasattr(mod, '__file__') and within_dirtree(real_src, os.path.realpath(mod.__file__)): + res.append(mod.__file__) + return res + class Emitter(object): + def __init__(self, settings): + self.add_deps_on_config_scripts = settings.add_deps_on_config_scripts + self.settings = settings def pre_output(self): assert not hasattr(self, 'did_output') self.did_output = True def set_default_rule(self, rule): self.default_rule = rule def add_command(self, settings, outs, ins, argvs, *args, **kwargs): - outs = [expand(x, settings) for x in outs] - ins = [expand(x, settings) for x in ins] - argvs = [expand_argv(x, settings) for x in argvs] + if kwargs.get('expand', True): + outs = [expand(x, settings) for x in outs] + ins = [expand(x, settings) for x in ins] + argvs = [expand_argv(x, settings) for x in argvs] + if 'expand' in kwargs: + del kwargs['expand'] + if self.add_deps_on_config_scripts: + ins.append('int-mconfig-scripts-phony') + if settings.enable_rule_hashing: + sha = hashlib.sha1(json.dumps((outs, ins, argvs))).hexdigest() + if sha not in prev_rule_hashes: + clean_files(outs, settings) + cur_rule_hashes.add(sha) return self.add_command_raw(outs, ins, argvs, *args, **kwargs) def emit(self, fn): + if self.add_deps_on_config_scripts: + self.add_command(self.settings, ['int-mconfig-scripts-phony'], list_mconfig_scripts(self.settings), [], phony=True) output = self.output() log('Writing %s\n' % (fn,)) fp = open(fn, 'w') @@ -693,7 +759,7 @@ class Emitter(object): class MakefileEmitter(Emitter): def __init__(self, settings): - self.settings = settings + Emitter.__init__(self, settings) self.makefile_bits = [] def add_all_and_clean(self): @@ -741,7 +807,7 @@ class MakefileEmitter(Emitter): class NinjaEmitter(Emitter): def __init__(self, settings): - self.settings = settings + Emitter.__init__(self, settings) self.ninja_bits = [] self.ruleno = 0 @staticmethod @@ -801,6 +867,27 @@ def add_emitter_option(): def finish_and_emit(): settings_root.emitter.emit(settings_root.emit_fn) + if settings_root.enable_rule_hashing: + emit_rule_hashes() + +def check_rule_hashes(): + if not settings_root.enable_rule_hashing: + return + global prev_rule_hashes, cur_rule_hashes + cur_rule_hashes = set() + rule_path = os.path.join(settings_root.out, 'mconfig-hashes.txt') + try: + fp = open(rule_path) + except IOError: + prev_rule_hashes = set() + return + prev_rule_hashes = set(json.load(fp)) + fp.close() + +def emit_rule_hashes(): + rule_path = os.path.join(settings_root.out, 'mconfig-hashes.txt') + with open(rule_path, 'w') as fp: + json.dump(list(cur_rule_hashes), fp) def default_is_cxx(filename): root, ext = os.path.splitext(filename) @@ -843,6 +930,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No is_cxx = my_settings.get('override_is_cxx') if is_cxx is None: is_cxx = default_is_cxx(fn) + dbg = ['-g'] if my_settings.debug_info else [] cflags = my_settings.cxxflags if is_cxx else my_settings.cflags cc = my_settings.get('override_cc') or (tools.cxx if is_cxx else tools.cc).argv() extra_deps = my_settings.get('extra_deps', []) @@ -850,9 +938,9 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No dep_fn = os.path.splitext(obj_fn)[0] + '.d' mkdir_cmd = ['mkdir', '-p', os.path.dirname(obj_fn)] - cmd = cc + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] + cmd = cc + dbg + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] - emitter.add_command_raw([obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn)) + emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn), expand=False) obj_fns.append(obj_fn) return obj_fns, any_was_cxx @@ -871,13 +959,15 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with typeflag = ['-dynamiclib'] if machine.is_darwin() else ['-shared'] else: typeflag = [] - cmd = cc_for_link + typeflag + settings.ldflags + ['-o', link_out] + objs + cmds = [cc_for_link + typeflag + settings.ldflags + ['-o', link_out] + objs] + if machine.is_darwin() and settings.debug_info: + cmds.append(tools.dsymutil.argv() + [link_out]) elif link_type == 'staticlib': - cmd = tools.ar() + ['rcs'] + objs + cmds = [tools.ar.argv() + ['rcs'] + objs] elif link_type == 'obj': - cmd = tools.cc() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs - mkdir_cmd = ['mkdir', '-p', os.path.dirname(link_out)] - emitter.add_command_raw([link_out], objs + extra_deps, [mkdir_cmd, cmd]) + cmds = [tools.cc.argv() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs] + cmds.append(['mkdir', '-p', os.path.dirname(link_out)]) + emitter.add_command(settings, [link_out], objs + extra_deps, cmds, expand=False) def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[]): more_objs, link_with_cxx = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) @@ -920,6 +1010,13 @@ settings_root.tool_search_paths = os.environ['PATH'].split(':') settings_root.src = os.path.dirname(sys.argv[0]) settings_root.out = os.path.join(os.getcwd(), 'out') +settings_root.debug_info = False + +settings_root.enable_rule_hashing = True +settings_root.allow_autoclean_outside_out = False +post_parse_args_will_need.append(check_rule_hashes) +settings_root.add_deps_on_config_scripts = True + emitters = { 'makefile': MakefileEmitter, 'ninja': NinjaEmitter, -- cgit v1.2.3 From abee6770e6383b7da373c4d8600c3a0e64165987 Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 25 Jun 2015 21:39:30 -0400 Subject: fixes - now three ways to specify an arch for xcode, yayer --- configure | 1 + mconfig.py | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 4eecda0..93682e0 100755 --- a/configure +++ b/configure @@ -6,6 +6,7 @@ settings.package_unix_name.value = 'substitute' c = settings.host_machine().c_tools() c.cc.required() +c.dsymutil.required() asm_archs = [ ('x86_64', []), diff --git a/mconfig.py b/mconfig.py index 973f748..91b5b05 100644 --- a/mconfig.py +++ b/mconfig.py @@ -234,6 +234,9 @@ class Option(object): self.show = True def set(self, value): + if not self.show: + # If you didn't mention the option in help, you don't get no stinking value. This is for ignored options only. + return if value is None: value = self.default if callable(value): # Pending @@ -417,7 +420,7 @@ class Machine(object): self.name = name self.settings = settings def on_set(val): - self.triple = val + self.triple = Triple(val) if isinstance(triple_default, basestring): triple_help += '; default: %r' % (triple_default,) self.triple_option = Option('--' + name, help=triple_help, default=triple_default, on_set=on_set, type=Triple, section=triple_options_section) @@ -466,6 +469,7 @@ class CLITool(object): self.env = env self.toolchains = toolchains self.needed = False + self.machine = machine if machine.name != 'host' and not dont_suffix_env: env = '%s_FOR_%s' % (env, to_upper_and_underscore(machine.name)) def on_set(val): @@ -484,7 +488,9 @@ class CLITool(object): self.optional() post_parse_args_will_need.append(lambda: self.argv()) - def argv(self): # memoized + def argv(self): # mem + if not self.argv_opt.show: + raise Exception("You asked for argv but didn't call required() or optional() before parsing args: %r" % (self,)) # If the user specified it explicitly, don't question. if hasattr(self, 'argv_from_opt'): log('Using %s from command line: %s\n' % (self.name, argv_to_shell(self.argv_from_opt))) @@ -494,7 +500,10 @@ class CLITool(object): for tc in self.toolchains: argv = tc.find_tool(self, failure_notes) if argv is not None: - log('Found %s: %s\n' % (self.name, argv_to_shell(argv))) + log('Found %s%s: %s\n' % ( + self.name, + (' for %r' % (self.machine.name,) if self.machine is not None else ''), + argv_to_shell(argv))) return argv log('** Failed to locate %s\n' % (self.name,)) @@ -555,7 +564,7 @@ class XcodeToolchain(object): if not arch and self.machine.triple.arch is not None: tarch = self.machine.triple.arch if tarch == 'arm': - log("Warning: treating 'arm' in triple %r as '-arch armv7'; you can specify a triple like 'armv7-apple-darwin10', or override with %r" % (self.machine.triple.triple, self.arch_opt.name)) + #log("Warning: treating 'arm' in triple %r as '-arch armv7'; you can specify a triple like 'armv7-apple-darwin10', or override with %r\n" % (self.machine.triple.triple, self.arch_opt.name)) tarch = 'armv7' elif tarch == 'armv8': # XXX is this right? tarch = 'arm64' @@ -599,6 +608,7 @@ class XcodeToolchain(object): sod, sed, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, 'ld', '-arch', tarch]) if 'unsupported arch' in sed: return None + return [tarch] triple = self.machine.triple # try to divine appropriate architectures # this may fail with future versions of Xcode, but at least we tried -- cgit v1.2.3 From 516ff7d23cdd9f779cb1b414d02b63d465f8162c Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 25 Jun 2015 22:26:14 -0400 Subject: fixed auto-regen... --- configure | 7 +++++- mconfig.py | 73 +++++++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/configure b/configure index 93682e0..5e1ad3d 100755 --- a/configure +++ b/configure @@ -30,6 +30,11 @@ emitter = settings.emitter balco = lambda *args, **kwargs: mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, *args, **kwargs) +def cb(fn): + if fn.endswith('/objc.c'): + return settings.specialize(obj_ldflag_sets=[('-lobjc',)]) + return settings + # Note: the order of darwin-inject-asm.o is significant. Per man page, ld is # guaranteed to link objects in order, which is necessary because # darwin-inject-asm.S does not itself ensure there is at least 0x4000 bytes of @@ -58,7 +63,7 @@ balco( '(src)/lib/hook-functions.c', '(src)/lib/strerror.c', ], - #settings_cb=lambda fn: settings.specialize(override_is_cxx=True) + settings_cb=cb ) #for name, arch_flag, opts in [ diff --git a/mconfig.py b/mconfig.py index 91b5b05..97c92f2 100644 --- a/mconfig.py +++ b/mconfig.py @@ -602,7 +602,7 @@ class XcodeToolchain(object): def get_archs(self, arch, tarch): if arch: - return re.sub('\s', '', val).split(',') + return re.sub('\s', '', arch).split(',') if tarch: # we need to validate it sod, sed, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, 'ld', '-arch', tarch]) @@ -717,8 +717,8 @@ def clean_files(fns, settings): for fn in fns: if not os.path.exists(fn) or os.path.isdir(fn): continue - if not settings.allow_autoclean_outside_out and within_dirtree(ro, os.path.realpath(fn)): - log('* Would clean %r as previous build leftover, but it isn\'t in settings.out (%r) so keeping it for safety.\n' % (fn, ro)) + if not settings.allow_autoclean_outside_out and not within_dirtree(ro, os.path.realpath(fn)): + log("* Would clean %r as previous build leftover, but it isn't in settings.out (%r) so keeping it for safety.\n" % (fn, ro)) continue config_log.write('Removing %r\n' % (fn,)) os.remove(fn) @@ -731,9 +731,13 @@ def list_mconfig_scripts(settings): res.append(mod.__file__) return res +def write_file_loudly(fn, data): + log('Writing %s\n' % (fn,)) + with open(fn, 'w') as fp: + fp.write(data) + class Emitter(object): def __init__(self, settings): - self.add_deps_on_config_scripts = settings.add_deps_on_config_scripts self.settings = settings def pre_output(self): assert not hasattr(self, 'did_output') @@ -747,22 +751,17 @@ class Emitter(object): argvs = [expand_argv(x, settings) for x in argvs] if 'expand' in kwargs: del kwargs['expand'] - if self.add_deps_on_config_scripts: - ins.append('int-mconfig-scripts-phony') if settings.enable_rule_hashing: sha = hashlib.sha1(json.dumps((outs, ins, argvs))).hexdigest() if sha not in prev_rule_hashes: clean_files(outs, settings) cur_rule_hashes.add(sha) return self.add_command_raw(outs, ins, argvs, *args, **kwargs) - def emit(self, fn): - if self.add_deps_on_config_scripts: - self.add_command(self.settings, ['int-mconfig-scripts-phony'], list_mconfig_scripts(self.settings), [], phony=True) + def emit(self, fn=None): + if fn is None: + fn = self.settings.emit_fn output = self.output() - log('Writing %s\n' % (fn,)) - fp = open(fn, 'w') - fp.write(output) - fp.close() + write_file_loudly(fn, output) # In the future it may be desirable to use make variables and nontrivial ninja rules for efficiency. @@ -770,7 +769,11 @@ class Emitter(object): class MakefileEmitter(Emitter): def __init__(self, settings): Emitter.__init__(self, settings) - self.makefile_bits = [] + self.banner = '# Generated by mconfig.py' + self.makefile_bits = [self.banner] + self.main_mk = settings.get('main_mk') + if self.main_mk is None: + self.main_mk = lambda: os.path.join(os.path.dirname(settings.emit_fn), 'main.mk') def add_all_and_clean(self): if hasattr(self, 'default_rule'): @@ -812,6 +815,27 @@ class MakefileEmitter(Emitter): self.add_all_and_clean() return '\n'.join(self.makefile_bits) + def emit(self): + makefile = self.settings.emit_fn + main_mk = self.main_mk() + self.add_command_raw([makefile], list_mconfig_scripts(self.settings), [['./config.status']]) + Emitter.emit(self, main_mk) + # Write the stub + # TODO is there something better than shell? + # TODO avoid deleting partial output? + stub = ''' +%(banner)s +_ := $(shell "$(MAKE_COMMAND)" -f %(main_mk_arg)s %(makefile_arg)s) +include %(main_mk)s +'''.lstrip() \ + % { + 'makefile_arg': argv_to_shell([makefile]), + 'main_mk_arg': argv_to_shell([main_mk]), + 'main_mk': self.filename_rel_and_escape(main_mk), + 'banner': self.banner, + } + write_file_loudly(makefile, stub) + def default_outfile(self): return 'Makefile' @@ -876,7 +900,7 @@ def add_emitter_option(): settings_root.add_setting_option('emit_fn', '--outfile', 'Output file. Default: depends on type', section=output_section, default=lambda: settings_root.emitter.default_outfile()) def finish_and_emit(): - settings_root.emitter.emit(settings_root.emit_fn) + settings_root.emitter.emit() if settings_root.enable_rule_hashing: emit_rule_hashes() @@ -927,6 +951,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No tools = machine.c_tools() any_was_cxx = False obj_fns = [] + ldflag_sets = set() _expand = globals()['expand'] for fn in sources: if expand: @@ -951,11 +976,14 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No cmd = cc + dbg + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn), expand=False) + + for lset in my_settings.get('obj_ldflag_sets', ()): + ldflag_sets.add(tuple(lset)) obj_fns.append(obj_fn) - return obj_fns, any_was_cxx + return obj_fns, any_was_cxx, ldflag_sets -def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[]): +def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): if expand: _expand = globals()['expand'] link_out = _expand(link_out, settings) @@ -969,19 +997,20 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with typeflag = ['-dynamiclib'] if machine.is_darwin() else ['-shared'] else: typeflag = [] - cmds = [cc_for_link + typeflag + settings.ldflags + ['-o', link_out] + objs] + cmds = [cc_for_link + typeflag + settings.ldflags + extra_ldflags + ['-o', link_out] + objs] if machine.is_darwin() and settings.debug_info: cmds.append(tools.dsymutil.argv() + [link_out]) elif link_type == 'staticlib': cmds = [tools.ar.argv() + ['rcs'] + objs] elif link_type == 'obj': cmds = [tools.cc.argv() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs] - cmds.append(['mkdir', '-p', os.path.dirname(link_out)]) + cmds.insert(0, ['mkdir', '-p', os.path.dirname(link_out)]) emitter.add_command(settings, [link_out], objs + extra_deps, cmds, expand=False) -def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[]): - more_objs, link_with_cxx = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) - link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps) +def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): + more_objs, link_with_cxx, ldflag_sets = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) + extra_ldflags = [flag for lset in ldflag_sets for flag in lset] + extra_ldflags + link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps, extra_ldflags) def guess_obj_fn(fn, settings): rel = os.path.relpath(fn, settings.src) -- cgit v1.2.3 From d8fadac422bf7695406d69aeb2961702e3bf35ea Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 25 Jun 2015 22:26:28 -0400 Subject: rename Makefile to avoid issues - will be replaced soon --- Makefile | 207 ----------------------------------------------------------- Makefile.old | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 207 deletions(-) delete mode 100644 Makefile create mode 100644 Makefile.old diff --git a/Makefile b/Makefile deleted file mode 100644 index a9e18f6..0000000 --- a/Makefile +++ /dev/null @@ -1,207 +0,0 @@ -# I really want to rewrite this with some configure script written in a real -# language, that supports cross compilation properly, etc. In fact, making a -# good generic configure framework is on my todo list; but since that's a lot -# of work, have fun with this hacky Makefile. -CC := clang -CXX := clang++ -ARCH := -arch x86_64 -XCFLAGS := -g -O3 -Wall -Wextra -Werror -Ilib $(ARCH) -LIB_LDFLAGS := -lobjc -dynamiclib -fvisibility=hidden -install_name /usr/lib/libsubstitute.0.dylib -dead_strip -IOS_APP_LDFLAGS := -framework UIKit -framework Foundation -dead_strip -IS_IOS := $(findstring -arch arm,$(CC) $(CFLAGS) $(XCFLAGS)) -ifneq (,$(IS_IOS)) -# I don't know anything in particular that would break this on older versions, -# but I don't have any good way to test it and don't really care. So ensure it -# doesn't get run on them. -XCFLAGS := $(XCFLAGS) -miphoneos-version-min=7.0 -endif -override CC := $(CC) $(XCFLAGS) $(CFLAGS) -override CXX := $(CXX) $(XCFLAGS) $(CFLAGS) -fno-exceptions -fno-asynchronous-unwind-tables - -# These are only required to rebuild the generated disassemblers. -IMAON2 := /Users/comex/c/imaon2 -GEN_JS := node --harmony --harmony_arrow_functions $(IMAON2)/tables/gen.js - -all: \ - out/libsubstitute.dylib - -$(shell mkdir -p out generated) - -GENERATED_DIS_HEADERS := generated/generic-dis-arm.inc.h generated/generic-dis-thumb.inc.h generated/generic-dis-thumb2.inc.h generated/generic-dis-arm64.inc.h -define do_prefix -generated/generic-dis-$(1).inc.h: - $(GEN_JS) --gen-hook-disassembler $(2) --dis-pattern='P(XXX)' $(IMAON2)/out/out-$(3).json > $$@ || rm -f $$@ -generateds: generated/generic-dis-$(1).inc.h -endef -$(eval $(call do_prefix,thumb2,-n _thumb2,ARM)) -$(eval $(call do_prefix,thumb,-n _thumb,ARM)) -$(eval $(call do_prefix,arm,-n _arm,ARM)) -$(eval $(call do_prefix,arm64,,AArch64)) - -HEADERS := lib/*.h lib/*/*.h generated/manual-mach.inc.h - -out/%.o: lib/%.c Makefile $(HEADERS) - @mkdir -p $(dir $@) - $(CC) -fvisibility=hidden -std=c11 -c -o $@ $< -out/%.o: generated/%.S Makefile $(HEADERS) - $(CC) -fvisibility=hidden -c -o $@ $< -out/%.o: lib/%.S Makefile $(HEADERS) - @mkdir -p $(dir $@) - $(CC) -fvisibility=hidden -c -o $@ $< -out/jump-dis.o: $(GENERATED_DIS_HEADERS) -out/transform-dis.o: $(GENERATED_DIS_HEADERS) - -# Note: the order of darwin-inject-asm.o is significant. Per man page, ld is -# guaranteed to link objects in order, which is necessary because -# darwin-inject-asm.S does not itself ensure there is at least 0x4000 bytes of -# executable stuff after inject_page_start (so that arm can remap into arm64). -# By putting it at the beginning, we can just reuse the space for the rest of -# the library rather than having to pad with zeroes. -# (This only matters on 32-bit ARM, and the text segment is currently 0xa000 -# bytes there, more than enough.) - -LIB_OBJS := \ - out/darwin-inject-asm.o \ - out/darwin/find-syms.o \ - out/darwin/inject.o \ - out/darwin/interpose.o \ - out/darwin/objc-asm.o \ - out/darwin/objc.o \ - out/darwin/read.o \ - out/darwin/substrate-compat.o \ - out/darwin/execmem.o \ - out/cbit/vec.o \ - out/jump-dis.o \ - out/transform-dis.o \ - out/hook-functions.o \ - out/strerror.o - -out/libsubstitute.dylib: $(LIB_OBJS) - $(CC) -o $@ $(LIB_OBJS) $(LIB_LDFLAGS) - dsymutil $@ - -# The result of this is also checked into generated, just in case someone is -# trying to build with some Linux compiler that doesn't support all the -# architectures or something - meh. -# Did you know? With -Oz + -marm, Apple clang-600.0.56 actually generated -# wrong code for the ARM version. It works with -Os and with newer clang. -IACLANG := clang -Os -fno-stack-protector -dynamiclib -nostartfiles -nodefaultlibs -isysroot /dev/null -Ilib -fPIC -define define_iar -out/inject-asm-raw-$(1).o: lib/darwin/inject-asm-raw.c Makefile lib/darwin/manual-syscall.h lib/darwin/inject-asm-raw.order - $(IACLANG) -arch $(2) -Wl,-order_file,lib/darwin/inject-asm-raw.order -o $$@ $$< -endef -$(eval $(call define_iar,x86_64,x86_64)) -$(eval $(call define_iar,i386,i386)) -$(eval $(call define_iar,arm,armv7 -marm)) -$(eval $(call define_iar,arm64,arm64)) - -IAR_BINS := out/inject-asm-raw-x86_64.bin out/inject-asm-raw-i386.bin out/inject-asm-raw-arm.bin out/inject-asm-raw-arm64.bin -out/darwin-inject-asm.S: $(IAR_BINS) Makefile script/gen-inject-asm.sh - ./script/gen-inject-asm.sh > $@ || rm -f $@ -generateds: out/darwin-inject-asm.S -out/darwin-inject-asm.S: out/darwin-inject-asm.S - cp $< generated/ - -generateds: generated/manual-mach.inc.h -generated/manual-mach.inc.h: ./script/gen-manual-mach.sh - ./script/gen-manual-mach.sh - -out/%.bin: out/%.o Makefile - segedit -extract __TEXT __text $@ $< - -define define_test -out/test-$(1): test/test-$(2).[cm]* $(HEADERS) $(GENERATED) Makefile out/libsubstitute.dylib - $(3) -o $$@ $$< -Ilib -Isubstrate -Lout -dead_strip -lsubstitute - install_name_tool -change /usr/lib/libsubstitute.0.dylib '@executable_path/libsubstitute.dylib' $$@ -ifneq (,$(IS_IOS)) - ldid -Sent.plist $$@ -endif -tests: out/test-$(1) -endef -$(eval $(call define_test,td-simple-arm,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-arm.inc.h"' -Dxdis=dis_arm -DFORCE_TARGET_arm)) -$(eval $(call define_test,td-simple-thumb,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-thumb.inc.h"' -Dxdis=dis_thumb -DFORCE_TARGET_arm)) -$(eval $(call define_test,td-simple-thumb2,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-thumb2.inc.h"' -Dxdis=dis_thumb2 -DFORCE_TARGET_arm)) -$(eval $(call define_test,td-simple-arm64,td-simple,$(CC) -std=c11 -DHDR='"arm64/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_arm64)) -$(eval $(call define_test,td-simple-i386,td-simple,$(CC) -std=c11 -DHDR='"x86/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_i386)) -$(eval $(call define_test,td-simple-x86-64,td-simple,$(CC) -std=c11 -DHDR='"x86/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_x86_64)) -$(eval $(call define_test,dis-arm,dis,$(CC) -std=c11 -DFORCE_TARGET_arm)) -$(eval $(call define_test,dis-arm64,dis,$(CC) -std=c11 -DFORCE_TARGET_arm64)) -$(eval $(call define_test,jump-dis-arm,jump-dis,$(CC) -std=c11 -DFORCE_TARGET_arm -O0 out/cbit/vec.o)) -$(eval $(call define_test,jump-dis-arm64,jump-dis,$(CC) -std=c11 -DFORCE_TARGET_arm64 -O0 out/cbit/vec.o)) -$(eval $(call define_test,transform-dis-arm,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_arm -O0)) -$(eval $(call define_test,transform-dis-arm64,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_arm64 -O0)) -$(eval $(call define_test,transform-dis-i386,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_i386 -O0)) -$(eval $(call define_test,transform-dis-x86_64,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_x86_64 -O0)) -$(eval $(call define_test,find-syms,find-syms,$(CC) -std=c89)) -$(eval $(call define_test,find-syms-cpp,find-syms,$(CXX) -x c++ -std=c++98)) -$(eval $(call define_test,substrate,substrate,$(CXX) -std=c++98)) -$(eval $(call define_test,imp-forwarding,imp-forwarding,$(CC) -std=c11 -framework Foundation -lobjc)) -$(eval $(call define_test,objc-hook,objc-hook,$(CC) -std=c11 -framework Foundation -lsubstitute)) -$(eval $(call define_test,interpose,interpose,$(CC) -std=c11 -lsubstitute)) -$(eval $(call define_test,inject,inject,$(CC) -std=c11 -lsubstitute out/darwin/inject.o out/darwin/read.o)) -$(eval $(call define_test,pc-patch,pc-patch,$(CC) -std=c11 out/darwin/execmem.o)) -$(eval $(call define_test,execmem,execmem,$(CC) -std=c11 out/darwin/execmem.o -segprot __TEST rwx rx)) -$(eval $(call define_test,hook-functions,hook-functions,$(CC) -std=c11 -lsubstitute -segprot __TEST rwx rx)) -$(eval $(call define_test,posixspawn-hook,posixspawn-hook,$(CC) -std=c11)) -$(eval $(call define_test,htab,htab,$(CC) -std=c11)) -$(eval $(call define_test,vec,vec,$(CXX) -std=c++98 out/cbit/vec.o)) - -out/injected-test-dylib.dylib: test/injected-test-dylib.c Makefile - $(CC) -std=c11 -dynamiclib -o $@ $< -tests: out/injected-test-dylib.dylib - -# These are just random sequences of instructions which you can compile to .bin -# for testing. - -out/insns-arm.o: test/insns-arm.S Makefile - clang -arch armv7 -c -o $@ $< -out/insns-thumb2.o: test/insns-arm.S Makefile - clang -arch armv7 -DTHUMB2 -c -o $@ $< - -out/insns-libz-arm.o: test/insns-libz-arm.S Makefile - clang -arch armv7 -c -o $@ $< -out/insns-libz-thumb2.o: test/insns-libz-arm.S Makefile - clang -arch armv7 -c -o $@ $< -DTHUMB2 - -define transform-dis-cases -out/transform-dis-cases-$(arch).o: test/transform-dis-cases-$(arch).S Makefile - clang -arch $(arch) -c -o $$@ $$< -endef -$(foreach arch,i386 x86_64 armv7 arm64,$(eval $(transform-dis-cases))) - -# iOS bootstrap... -ifneq (,$(IS_IOS)) -SD_OBJS := out/safety-dance/main.o out/safety-dance/AutoGrid.o -out/safety-dance/%.o: darwin-bootstrap/safety-dance/%.m darwin-bootstrap/safety-dance/*.h Makefile - @mkdir -p $(dir $@) - $(CC) -c -o $@ $< -fobjc-arc -Wno-unused-parameter -out/safety-dance/SafetyDance.app/SafetyDance: $(SD_OBJS) Makefile - @mkdir -p $(dir $@) - $(CC) -o $@ $(SD_OBJS) $(IOS_APP_LDFLAGS) - ldid -S $@ -out/safety-dance/SafetyDance.app/Info.plist: darwin-bootstrap/safety-dance/Info.plist Makefile - @mkdir -p $(dir $@) - plutil -convert binary1 -o $@ $< - cp darwin-bootstrap/safety-dance/white.png out/safety-dance/SafetyDance.app/Default.png - cp darwin-bootstrap/safety-dance/white.png out/safety-dance/SafetyDance.app/Default@2x.png -safety-dance: out/safety-dance/SafetyDance.app/SafetyDance out/safety-dance/SafetyDance.app/Info.plist -all: safety-dance - -out/posixspawn-hook.dylib: darwin-bootstrap/posixspawn-hook.c out/libsubstitute.dylib - $(CC) -dynamiclib -o $@ $< -Lout -lsubstitute -out/bundle-loader.dylib: darwin-bootstrap/bundle-loader.c darwin-bootstrap/substituted-messages.h out/libsubstitute.dylib - $(CC) -dynamiclib -o $@ $< -Lout -out/unrestrict: darwin-bootstrap/unrestrict.c darwin-bootstrap/ib-log.h out/libsubstitute.dylib - $(CC) -o $@ $< -Lout -lsubstitute - ldid -Sent.plist $@ -out/inject-into-launchd: darwin-bootstrap/inject-into-launchd.c darwin-bootstrap/ib-log.h out/libsubstitute.dylib - $(CC) -o $@ $< -Lout -lsubstitute -framework IOKit -framework CoreFoundation - ldid -Sent.plist $@ -out/substituted: darwin-bootstrap/substituted* - $(CC) -o $@ darwin-bootstrap/substituted{.c,-plist-loader.m} -framework Foundation -framework CoreFoundation -lbsm -fobjc-arc -all: out/posixspawn-hook.dylib out/bundle-loader.dylib out/unrestrict out/inject-into-launchd out/substituted -endif - - -clean: - rm -rf out diff --git a/Makefile.old b/Makefile.old new file mode 100644 index 0000000..a9e18f6 --- /dev/null +++ b/Makefile.old @@ -0,0 +1,207 @@ +# I really want to rewrite this with some configure script written in a real +# language, that supports cross compilation properly, etc. In fact, making a +# good generic configure framework is on my todo list; but since that's a lot +# of work, have fun with this hacky Makefile. +CC := clang +CXX := clang++ +ARCH := -arch x86_64 +XCFLAGS := -g -O3 -Wall -Wextra -Werror -Ilib $(ARCH) +LIB_LDFLAGS := -lobjc -dynamiclib -fvisibility=hidden -install_name /usr/lib/libsubstitute.0.dylib -dead_strip +IOS_APP_LDFLAGS := -framework UIKit -framework Foundation -dead_strip +IS_IOS := $(findstring -arch arm,$(CC) $(CFLAGS) $(XCFLAGS)) +ifneq (,$(IS_IOS)) +# I don't know anything in particular that would break this on older versions, +# but I don't have any good way to test it and don't really care. So ensure it +# doesn't get run on them. +XCFLAGS := $(XCFLAGS) -miphoneos-version-min=7.0 +endif +override CC := $(CC) $(XCFLAGS) $(CFLAGS) +override CXX := $(CXX) $(XCFLAGS) $(CFLAGS) -fno-exceptions -fno-asynchronous-unwind-tables + +# These are only required to rebuild the generated disassemblers. +IMAON2 := /Users/comex/c/imaon2 +GEN_JS := node --harmony --harmony_arrow_functions $(IMAON2)/tables/gen.js + +all: \ + out/libsubstitute.dylib + +$(shell mkdir -p out generated) + +GENERATED_DIS_HEADERS := generated/generic-dis-arm.inc.h generated/generic-dis-thumb.inc.h generated/generic-dis-thumb2.inc.h generated/generic-dis-arm64.inc.h +define do_prefix +generated/generic-dis-$(1).inc.h: + $(GEN_JS) --gen-hook-disassembler $(2) --dis-pattern='P(XXX)' $(IMAON2)/out/out-$(3).json > $$@ || rm -f $$@ +generateds: generated/generic-dis-$(1).inc.h +endef +$(eval $(call do_prefix,thumb2,-n _thumb2,ARM)) +$(eval $(call do_prefix,thumb,-n _thumb,ARM)) +$(eval $(call do_prefix,arm,-n _arm,ARM)) +$(eval $(call do_prefix,arm64,,AArch64)) + +HEADERS := lib/*.h lib/*/*.h generated/manual-mach.inc.h + +out/%.o: lib/%.c Makefile $(HEADERS) + @mkdir -p $(dir $@) + $(CC) -fvisibility=hidden -std=c11 -c -o $@ $< +out/%.o: generated/%.S Makefile $(HEADERS) + $(CC) -fvisibility=hidden -c -o $@ $< +out/%.o: lib/%.S Makefile $(HEADERS) + @mkdir -p $(dir $@) + $(CC) -fvisibility=hidden -c -o $@ $< +out/jump-dis.o: $(GENERATED_DIS_HEADERS) +out/transform-dis.o: $(GENERATED_DIS_HEADERS) + +# Note: the order of darwin-inject-asm.o is significant. Per man page, ld is +# guaranteed to link objects in order, which is necessary because +# darwin-inject-asm.S does not itself ensure there is at least 0x4000 bytes of +# executable stuff after inject_page_start (so that arm can remap into arm64). +# By putting it at the beginning, we can just reuse the space for the rest of +# the library rather than having to pad with zeroes. +# (This only matters on 32-bit ARM, and the text segment is currently 0xa000 +# bytes there, more than enough.) + +LIB_OBJS := \ + out/darwin-inject-asm.o \ + out/darwin/find-syms.o \ + out/darwin/inject.o \ + out/darwin/interpose.o \ + out/darwin/objc-asm.o \ + out/darwin/objc.o \ + out/darwin/read.o \ + out/darwin/substrate-compat.o \ + out/darwin/execmem.o \ + out/cbit/vec.o \ + out/jump-dis.o \ + out/transform-dis.o \ + out/hook-functions.o \ + out/strerror.o + +out/libsubstitute.dylib: $(LIB_OBJS) + $(CC) -o $@ $(LIB_OBJS) $(LIB_LDFLAGS) + dsymutil $@ + +# The result of this is also checked into generated, just in case someone is +# trying to build with some Linux compiler that doesn't support all the +# architectures or something - meh. +# Did you know? With -Oz + -marm, Apple clang-600.0.56 actually generated +# wrong code for the ARM version. It works with -Os and with newer clang. +IACLANG := clang -Os -fno-stack-protector -dynamiclib -nostartfiles -nodefaultlibs -isysroot /dev/null -Ilib -fPIC +define define_iar +out/inject-asm-raw-$(1).o: lib/darwin/inject-asm-raw.c Makefile lib/darwin/manual-syscall.h lib/darwin/inject-asm-raw.order + $(IACLANG) -arch $(2) -Wl,-order_file,lib/darwin/inject-asm-raw.order -o $$@ $$< +endef +$(eval $(call define_iar,x86_64,x86_64)) +$(eval $(call define_iar,i386,i386)) +$(eval $(call define_iar,arm,armv7 -marm)) +$(eval $(call define_iar,arm64,arm64)) + +IAR_BINS := out/inject-asm-raw-x86_64.bin out/inject-asm-raw-i386.bin out/inject-asm-raw-arm.bin out/inject-asm-raw-arm64.bin +out/darwin-inject-asm.S: $(IAR_BINS) Makefile script/gen-inject-asm.sh + ./script/gen-inject-asm.sh > $@ || rm -f $@ +generateds: out/darwin-inject-asm.S +out/darwin-inject-asm.S: out/darwin-inject-asm.S + cp $< generated/ + +generateds: generated/manual-mach.inc.h +generated/manual-mach.inc.h: ./script/gen-manual-mach.sh + ./script/gen-manual-mach.sh + +out/%.bin: out/%.o Makefile + segedit -extract __TEXT __text $@ $< + +define define_test +out/test-$(1): test/test-$(2).[cm]* $(HEADERS) $(GENERATED) Makefile out/libsubstitute.dylib + $(3) -o $$@ $$< -Ilib -Isubstrate -Lout -dead_strip -lsubstitute + install_name_tool -change /usr/lib/libsubstitute.0.dylib '@executable_path/libsubstitute.dylib' $$@ +ifneq (,$(IS_IOS)) + ldid -Sent.plist $$@ +endif +tests: out/test-$(1) +endef +$(eval $(call define_test,td-simple-arm,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-arm.inc.h"' -Dxdis=dis_arm -DFORCE_TARGET_arm)) +$(eval $(call define_test,td-simple-thumb,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-thumb.inc.h"' -Dxdis=dis_thumb -DFORCE_TARGET_arm)) +$(eval $(call define_test,td-simple-thumb2,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-thumb2.inc.h"' -Dxdis=dis_thumb2 -DFORCE_TARGET_arm)) +$(eval $(call define_test,td-simple-arm64,td-simple,$(CC) -std=c11 -DHDR='"arm64/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_arm64)) +$(eval $(call define_test,td-simple-i386,td-simple,$(CC) -std=c11 -DHDR='"x86/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_i386)) +$(eval $(call define_test,td-simple-x86-64,td-simple,$(CC) -std=c11 -DHDR='"x86/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_x86_64)) +$(eval $(call define_test,dis-arm,dis,$(CC) -std=c11 -DFORCE_TARGET_arm)) +$(eval $(call define_test,dis-arm64,dis,$(CC) -std=c11 -DFORCE_TARGET_arm64)) +$(eval $(call define_test,jump-dis-arm,jump-dis,$(CC) -std=c11 -DFORCE_TARGET_arm -O0 out/cbit/vec.o)) +$(eval $(call define_test,jump-dis-arm64,jump-dis,$(CC) -std=c11 -DFORCE_TARGET_arm64 -O0 out/cbit/vec.o)) +$(eval $(call define_test,transform-dis-arm,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_arm -O0)) +$(eval $(call define_test,transform-dis-arm64,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_arm64 -O0)) +$(eval $(call define_test,transform-dis-i386,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_i386 -O0)) +$(eval $(call define_test,transform-dis-x86_64,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_x86_64 -O0)) +$(eval $(call define_test,find-syms,find-syms,$(CC) -std=c89)) +$(eval $(call define_test,find-syms-cpp,find-syms,$(CXX) -x c++ -std=c++98)) +$(eval $(call define_test,substrate,substrate,$(CXX) -std=c++98)) +$(eval $(call define_test,imp-forwarding,imp-forwarding,$(CC) -std=c11 -framework Foundation -lobjc)) +$(eval $(call define_test,objc-hook,objc-hook,$(CC) -std=c11 -framework Foundation -lsubstitute)) +$(eval $(call define_test,interpose,interpose,$(CC) -std=c11 -lsubstitute)) +$(eval $(call define_test,inject,inject,$(CC) -std=c11 -lsubstitute out/darwin/inject.o out/darwin/read.o)) +$(eval $(call define_test,pc-patch,pc-patch,$(CC) -std=c11 out/darwin/execmem.o)) +$(eval $(call define_test,execmem,execmem,$(CC) -std=c11 out/darwin/execmem.o -segprot __TEST rwx rx)) +$(eval $(call define_test,hook-functions,hook-functions,$(CC) -std=c11 -lsubstitute -segprot __TEST rwx rx)) +$(eval $(call define_test,posixspawn-hook,posixspawn-hook,$(CC) -std=c11)) +$(eval $(call define_test,htab,htab,$(CC) -std=c11)) +$(eval $(call define_test,vec,vec,$(CXX) -std=c++98 out/cbit/vec.o)) + +out/injected-test-dylib.dylib: test/injected-test-dylib.c Makefile + $(CC) -std=c11 -dynamiclib -o $@ $< +tests: out/injected-test-dylib.dylib + +# These are just random sequences of instructions which you can compile to .bin +# for testing. + +out/insns-arm.o: test/insns-arm.S Makefile + clang -arch armv7 -c -o $@ $< +out/insns-thumb2.o: test/insns-arm.S Makefile + clang -arch armv7 -DTHUMB2 -c -o $@ $< + +out/insns-libz-arm.o: test/insns-libz-arm.S Makefile + clang -arch armv7 -c -o $@ $< +out/insns-libz-thumb2.o: test/insns-libz-arm.S Makefile + clang -arch armv7 -c -o $@ $< -DTHUMB2 + +define transform-dis-cases +out/transform-dis-cases-$(arch).o: test/transform-dis-cases-$(arch).S Makefile + clang -arch $(arch) -c -o $$@ $$< +endef +$(foreach arch,i386 x86_64 armv7 arm64,$(eval $(transform-dis-cases))) + +# iOS bootstrap... +ifneq (,$(IS_IOS)) +SD_OBJS := out/safety-dance/main.o out/safety-dance/AutoGrid.o +out/safety-dance/%.o: darwin-bootstrap/safety-dance/%.m darwin-bootstrap/safety-dance/*.h Makefile + @mkdir -p $(dir $@) + $(CC) -c -o $@ $< -fobjc-arc -Wno-unused-parameter +out/safety-dance/SafetyDance.app/SafetyDance: $(SD_OBJS) Makefile + @mkdir -p $(dir $@) + $(CC) -o $@ $(SD_OBJS) $(IOS_APP_LDFLAGS) + ldid -S $@ +out/safety-dance/SafetyDance.app/Info.plist: darwin-bootstrap/safety-dance/Info.plist Makefile + @mkdir -p $(dir $@) + plutil -convert binary1 -o $@ $< + cp darwin-bootstrap/safety-dance/white.png out/safety-dance/SafetyDance.app/Default.png + cp darwin-bootstrap/safety-dance/white.png out/safety-dance/SafetyDance.app/Default@2x.png +safety-dance: out/safety-dance/SafetyDance.app/SafetyDance out/safety-dance/SafetyDance.app/Info.plist +all: safety-dance + +out/posixspawn-hook.dylib: darwin-bootstrap/posixspawn-hook.c out/libsubstitute.dylib + $(CC) -dynamiclib -o $@ $< -Lout -lsubstitute +out/bundle-loader.dylib: darwin-bootstrap/bundle-loader.c darwin-bootstrap/substituted-messages.h out/libsubstitute.dylib + $(CC) -dynamiclib -o $@ $< -Lout +out/unrestrict: darwin-bootstrap/unrestrict.c darwin-bootstrap/ib-log.h out/libsubstitute.dylib + $(CC) -o $@ $< -Lout -lsubstitute + ldid -Sent.plist $@ +out/inject-into-launchd: darwin-bootstrap/inject-into-launchd.c darwin-bootstrap/ib-log.h out/libsubstitute.dylib + $(CC) -o $@ $< -Lout -lsubstitute -framework IOKit -framework CoreFoundation + ldid -Sent.plist $@ +out/substituted: darwin-bootstrap/substituted* + $(CC) -o $@ darwin-bootstrap/substituted{.c,-plist-loader.m} -framework Foundation -framework CoreFoundation -lbsm -fobjc-arc +all: out/posixspawn-hook.dylib out/bundle-loader.dylib out/unrestrict out/inject-into-launchd out/substituted +endif + + +clean: + rm -rf out -- cgit v1.2.3 From 8f9a9156ee4872968f23dca8ca99c74223895af1 Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 25 Jun 2015 22:34:58 -0400 Subject: ok, actually works - for make. will need to look up what Ninja does wrt the file changing at some point - will it do the hashing thing for me? --- mconfig.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/mconfig.py b/mconfig.py index 97c92f2..81ce73d 100644 --- a/mconfig.py +++ b/mconfig.py @@ -728,13 +728,21 @@ def list_mconfig_scripts(settings): res = [] for mod in sys.modules.values(): if hasattr(mod, '__file__') and within_dirtree(real_src, os.path.realpath(mod.__file__)): - res.append(mod.__file__) + fn = mod.__file__ + if (fn.endswith('.pyc') or fn.endswith('.pyo')) and os.path.exists(fn[:-1]): + fn = fn[:-1] + res.append(fn) return res -def write_file_loudly(fn, data): +def write_file_loudly(fn, data, perm=None): log('Writing %s\n' % (fn,)) with open(fn, 'w') as fp: fp.write(data) + if perm is not None: + try: + os.chmod(fn, perm) + except Exception as e: + log('chmod: %r' % (e,)) class Emitter(object): def __init__(self, settings): @@ -818,14 +826,15 @@ class MakefileEmitter(Emitter): def emit(self): makefile = self.settings.emit_fn main_mk = self.main_mk() - self.add_command_raw([makefile], list_mconfig_scripts(self.settings), [['./config.status']]) + cs_argvs = [['echo', 'Running config.status...'], ['./config.status']] + self.add_command_raw([makefile], list_mconfig_scripts(self.settings), cs_argvs) Emitter.emit(self, main_mk) # Write the stub # TODO is there something better than shell? # TODO avoid deleting partial output? stub = ''' %(banner)s -_ := $(shell "$(MAKE_COMMAND)" -f %(main_mk_arg)s %(makefile_arg)s) +_ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) include %(main_mk)s '''.lstrip() \ % { @@ -899,10 +908,14 @@ def add_emitter_option(): on_set_generate, default='makefile', section=output_section) settings_root.add_setting_option('emit_fn', '--outfile', 'Output file. Default: depends on type', section=output_section, default=lambda: settings_root.emitter.default_outfile()) +def config_status(): + return '#!/bin/sh\n' + argv_to_shell(sys.argv) + '\n' + def finish_and_emit(): settings_root.emitter.emit() if settings_root.enable_rule_hashing: emit_rule_hashes() + write_file_loudly('config.status', config_status(), 0o755) def check_rule_hashes(): if not settings_root.enable_rule_hashing: -- cgit v1.2.3 From 9445968444341bc8456db2b9c72db26df0abc0a5 Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 25 Jun 2015 22:52:43 -0400 Subject: py3k fixes --- mconfig.py | 54 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/mconfig.py b/mconfig.py index 81ce73d..2624c33 100644 --- a/mconfig.py +++ b/mconfig.py @@ -2,6 +2,13 @@ import re, argparse, sys, os, string, shlex, subprocess, glob, parser, hashlib, from collections import OrderedDict, namedtuple import curses.ascii +# Py3 stuff... +is_py3 = sys.hexversion >= 0x3000000 +if is_py3: + basestring = str +def dirname(fn): + return os.path.dirname(fn) or '.' + def indentify(s, indent=' '): return s.replace('\n', '\n' + indent) @@ -46,7 +53,7 @@ def run_command(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs): except OSError: config_log.write(' OSError\n') return '', '', 127 - so, se = p.communicate() + so, se = [o.decode('utf-8') for o in p.communicate()] if p.returncode != 0: config_log.write(' failed with status %d\n' % (p.returncode,)) config_log.write('-----------\n') @@ -73,7 +80,8 @@ class memoize(object): try: self.result = self.f() return self.result - except DependencyNotFoundException as self.threw: + except DependencyNotFoundException as threw: + self.threw = threw raise class Pending(object): @@ -82,10 +90,13 @@ class Pending(object): def resolve(self): return self.value # xxx py3 - def __getattr__(self, attr): - if attr is 'value': - raise AttributeError - return PendingAttribute(self, attr) + def __getattribute__(self, attr): + try: + return object.__getattribute__(self, attr) + except AttributeError: + if attr is 'value': + raise AttributeError + return PendingAttribute(self, attr) class PendingOption(Pending, namedtuple('PendingOption', 'opt')): def resolve(self): @@ -591,7 +602,7 @@ class XcodeToolchain(object): log("%s default Xcode SDK for %r because %s; pass %s=arch1,arch2 to override\n" % ( "Can't use" if some_explicit_xcode_request else "Not using", self.machine.name, - ("triple architecture %r doesn't seem to be valid" % (tarch,)) if tarch is not None else "I couldn't guess a list of architectures from the SDK", + ("triple architecture %r doesn't seem to be valid" % (tarch,)) if tarch else "I couldn't guess a list of architectures from the SDK", self.arch_opt.name, )) if some_explicit_xcode_request: @@ -728,9 +739,16 @@ def list_mconfig_scripts(settings): res = [] for mod in sys.modules.values(): if hasattr(mod, '__file__') and within_dirtree(real_src, os.path.realpath(mod.__file__)): - fn = mod.__file__ - if (fn.endswith('.pyc') or fn.endswith('.pyo')) and os.path.exists(fn[:-1]): - fn = fn[:-1] + if is_py3: + fn = mod.__loader__.path + else: + fn = mod.__file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): + if os.path.exists(fn[:-1]): + fn = fn[:-1] + else: + # who knows? + continue res.append(fn) return res @@ -760,7 +778,7 @@ class Emitter(object): if 'expand' in kwargs: del kwargs['expand'] if settings.enable_rule_hashing: - sha = hashlib.sha1(json.dumps((outs, ins, argvs))).hexdigest() + sha = hashlib.sha1(json.dumps((outs, ins, argvs)).encode('utf-8')).hexdigest() if sha not in prev_rule_hashes: clean_files(outs, settings) cur_rule_hashes.add(sha) @@ -781,7 +799,7 @@ class MakefileEmitter(Emitter): self.makefile_bits = [self.banner] self.main_mk = settings.get('main_mk') if self.main_mk is None: - self.main_mk = lambda: os.path.join(os.path.dirname(settings.emit_fn), 'main.mk') + self.main_mk = lambda: os.path.join(dirname(settings.emit_fn), 'main.mk') def add_all_and_clean(self): if hasattr(self, 'default_rule'): @@ -797,7 +815,7 @@ class MakefileEmitter(Emitter): raise ValueError("your awful filename %r can't be encoded in make (probably)" % (fn,)) return re.sub(r'([ :\$\\])', r'\\\1', fn) def filename_rel_and_escape(self, fn): - fn = os.path.relpath(fn, os.path.dirname(self.settings.emit_fn)) + fn = os.path.relpath(fn, dirname(self.settings.emit_fn)) return self.filename_escape(fn) # depfile = ('makefile', filename) or ('msvc',) def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): @@ -909,7 +927,7 @@ def add_emitter_option(): settings_root.add_setting_option('emit_fn', '--outfile', 'Output file. Default: depends on type', section=output_section, default=lambda: settings_root.emitter.default_outfile()) def config_status(): - return '#!/bin/sh\n' + argv_to_shell(sys.argv) + '\n' + return '#!/bin/sh\n' + argv_to_shell([sys.executable] + sys.argv) + '\n' def finish_and_emit(): settings_root.emitter.emit() @@ -985,7 +1003,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No any_was_cxx = any_was_cxx or is_cxx dep_fn = os.path.splitext(obj_fn)[0] + '.d' - mkdir_cmd = ['mkdir', '-p', os.path.dirname(obj_fn)] + mkdir_cmd = ['mkdir', '-p', dirname(obj_fn)] cmd = cc + dbg + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn), expand=False) @@ -1017,7 +1035,7 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with cmds = [tools.ar.argv() + ['rcs'] + objs] elif link_type == 'obj': cmds = [tools.cc.argv() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs] - cmds.insert(0, ['mkdir', '-p', os.path.dirname(link_out)]) + cmds.insert(0, ['mkdir', '-p', dirname(link_out)]) emitter.add_command(settings, [link_out], objs + extra_deps, cmds, expand=False) def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): @@ -1027,7 +1045,7 @@ def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sourc def guess_obj_fn(fn, settings): rel = os.path.relpath(fn, settings.src) - if not rel.startswith('../'): + if not rel.startswith('..'+os.path.sep): rel = os.path.splitext(rel)[0] + '.o' return os.path.join(settings.out, rel) raise ValueError("can't guess .o filename for %r, as it's not in settings.src" % (fn,)) @@ -1059,7 +1077,7 @@ settings_root.host_machine = memoize(lambda: settings_root.build_machine() and M settings_root.tool_search_paths = os.environ['PATH'].split(':') -settings_root.src = os.path.dirname(sys.argv[0]) +settings_root.src = dirname(sys.argv[0]) settings_root.out = os.path.join(os.getcwd(), 'out') settings_root.debug_info = False -- cgit v1.2.3 From a94bed159dce83dc0522298fe717070f27ff7c09 Mon Sep 17 00:00:00 2001 From: comex Date: Mon, 29 Jun 2015 20:01:58 +0100 Subject: move mconfig.py --- configure | 4 +- mconfig.py | 1098 ----------------------------------------------------- script/mconfig.py | 1098 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1101 insertions(+), 1099 deletions(-) delete mode 100644 mconfig.py create mode 100644 script/mconfig.py diff --git a/configure b/configure index 5e1ad3d..218b2cf 100755 --- a/configure +++ b/configure @@ -1,4 +1,6 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python +import sys, os +sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'script')) import mconfig settings = mconfig.settings_root settings.package_unix_name.value = 'substitute' diff --git a/mconfig.py b/mconfig.py deleted file mode 100644 index 2624c33..0000000 --- a/mconfig.py +++ /dev/null @@ -1,1098 +0,0 @@ -import re, argparse, sys, os, string, shlex, subprocess, glob, parser, hashlib, json -from collections import OrderedDict, namedtuple -import curses.ascii - -# Py3 stuff... -is_py3 = sys.hexversion >= 0x3000000 -if is_py3: - basestring = str -def dirname(fn): - return os.path.dirname(fn) or '.' - -def indentify(s, indent=' '): - return s.replace('\n', '\n' + indent) - -def log(x): - sys.stdout.write(x) - config_log.write(x) - -def to_upper_and_underscore(s): - return s.upper().replace('-', '_') - -def argv_to_shell(argv): - quoteds = [] - for arg in argv: - if re.match('^[a-zA-Z0-9_\.@/+=-]+$', arg): - quoteds.append(arg) - else: - quoted = '' - for c in arg: - if c == '\n': - quoted += r'\n' - elif c in r'$`\"': - quoted += '\\' + c - elif not curses.ascii.isprint(c): - quoted += r'\x%02x' % ord(c) - else: - quoted += c - quoteds.append('"' + quoted + '"') - return ' '.join(quoteds) - - -def init_config_log(): - global config_log - config_log = open('config.log', 'w') - config_log.write(argv_to_shell(sys.argv) + '\n') - -# a wrapper for subprocess that logs results -# returns (stdout, stderr, status) [even if Popen fails] -def run_command(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs): - config_log.write('Running command %s...\n' % (argv_to_shell(cmd),)) - try: - p = subprocess.Popen(cmd, stdout=stdout, stderr=stderr, **kwargs) - except OSError: - config_log.write(' OSError\n') - return '', '', 127 - so, se = [o.decode('utf-8') for o in p.communicate()] - if p.returncode != 0: - config_log.write(' failed with status %d\n' % (p.returncode,)) - config_log.write('-----------\n') - config_log.write(' stdout:\n') - config_log.write(so.rstrip()) - config_log.write('\n stderr:\n') - config_log.write(se.rstrip()) - config_log.write('\n-----------\n') - return so, se, p.returncode - -class DependencyNotFoundException(Exception): - pass - -# it must take no arguments, and throw DependencyNotFoundException on failure -class memoize(object): - def __init__(self, f): - self.f = f - def __call__(self): - if hasattr(self, 'threw'): - raise self.threw - elif hasattr(self, 'result'): - return self.result - else: - try: - self.result = self.f() - return self.result - except DependencyNotFoundException as threw: - self.threw = threw - raise - -class Pending(object): - def __repr__(self): - return 'Pending(%x%s)' % (id(self), ('; value=%r' % (self.value,)) if hasattr(self, 'value') else '') - def resolve(self): - return self.value - # xxx py3 - def __getattribute__(self, attr): - try: - return object.__getattribute__(self, attr) - except AttributeError: - if attr is 'value': - raise AttributeError - return PendingAttribute(self, attr) - -class PendingOption(Pending, namedtuple('PendingOption', 'opt')): - def resolve(self): - return self.opt.value - def __repr__(self): - return 'PendingOption(%s)' % (self.opt.name,) - -class PendingAttribute(Pending, namedtuple('PendingAttribute', 'base attr')): - def resolve(self): - return getattr(self.base, self.attr) - def __repr__(self): - return 'PendingAttribute(attr=%s, base=%r)' % (self.attr, self.base) - -class SettingsGroup(object): - def __init__(self, group_parent=None, inherit_parent=None, name=None): - object.__setattr__(self, 'group_parent', group_parent) - object.__setattr__(self, 'inherit_parent', inherit_parent) - object.__setattr__(self, 'vals', OrderedDict()) - if name is None: - name = '<0x%x>' % (id(self),) - object.__setattr__(self, 'name', name) - @staticmethod - def get_meat(self, attr, exctype=KeyError): - allow_pending = not did_parse_args - try: - obj = object.__getattribute__(self, 'vals')[attr] - except KeyError: - inherit_parent = object.__getattribute__(self, 'inherit_parent') - if inherit_parent is not None: - ret = SettingsGroup.get_meat(inherit_parent, attr, exctype) - if isinstance(ret, SettingsGroup): - ret = self[attr] = ret.specialize(name='%s.%s' % (object.__getattribute__(self, 'name'), attr)) - return ret - raise exctype(attr) - else: - if isinstance(obj, Pending): - try: - return obj.resolve() - except: - if not allow_pending: - raise Exception("setting %r is pending; you need to set it" % (attr,)) - return obj - return obj - def __getattribute__(self, attr): - try: - return object.__getattribute__(self, attr) - except AttributeError: - return SettingsGroup.get_meat(self, attr, AttributeError) - def __setattr__(self, attr, val): - try: - object.__getattribute__(self, attr) - except: - self[attr] = val - else: - object.__setattribute__(self, attr, val) - def __getitem__(self, attr): - return self.__getattribute__(attr) - def __setitem__(self, attr, val): - self.vals[attr] = val - def get(self, attr, default=None): - try: - return self[attr] - except AttributeError: - return default - - def __iter__(self): - return self.vals.__iter__() - def items(self): - return self.vals.items() - - def __str__(self): - s = 'SettingsGroup %s {\n' % (self.name,) - o = self - while True: - for attr, val in o.vals.items(): - s += ' %s: %s\n' % (attr, indentify(str(val))) - if o.inherit_parent is None: - break - o = o.inherit_parent - s += ' [inherited from %s:]\n' % (o.name,) - s += '}' - return s - - def add_setting_option(self, name, optname, optdesc, default, **kwargs): - def f(value): - self[name] = value - if isinstance(default, str): - old = default - default = lambda: expand(old, self) - opt = Option(optname, optdesc, f, default, **kwargs) - self[name] = PendingOption(opt) - - def specialize(self, name=None, **kwargs): - sg = SettingsGroup(inherit_parent=self, name=name) - for key, val in kwargs.items(): - sg[key] = val - return sg - - def new_child(self, name, *args, **kwargs): - sg = SettingsGroup(group_parent=self, name='%s.%s' % (self.name, name), *args, **kwargs) - self[name] = sg - return sg - -class OptSection(object): - def __init__(self, desc): - self.desc = desc - self.opts = [] - all_opt_sections.append(self) - def move_to_end(self): - all_opt_sections.remove(self) - all_opt_sections.append(self) - -class Option(object): - def __init__(self, name, help, on_set, default=None, bool=False, show=True, section=None, metavar=None, type=str, **kwargs): - if name.startswith('--'): - self.is_env = False - assert set(kwargs).issubset({'nargs', 'choices', 'required', 'metavar'}) - elif name.endswith('='): - self.is_env = True - assert len(kwargs) == 0 - assert bool is False - else: - raise ValueError("name %r should be '--opt' or 'ENV='" % (name,)) - self.name = name - self.help = help - self.default = default - self.on_set = on_set - self.show = show - self.type = type - if metavar is None: - metavar = '...' - self.metavar = metavar - self.bool = bool - self.section = section if section is not None else default_opt_section - self.section.opts.append(self) - self.argparse_kw = kwargs.copy() - all_options.append(self) - if name in all_options_by_name: - raise KeyError('trying to create Option with duplicate name %r; old is:\n%r' % (name, all_options_by_name[name])) - all_options_by_name[name] = self - def __repr__(self): - value = repr(self.value) if hasattr(self, 'value') else '' - return 'Option(name=%r, help=%r, value=%s, default=%r)' % (self.name, self.help, value, self.default) - - def need(self): - self.show = True - - def set(self, value): - if not self.show: - # If you didn't mention the option in help, you don't get no stinking value. This is for ignored options only. - return - if value is None: - value = self.default - if callable(value): # Pending - value = value() - self.value = value - if self.on_set is not None: - self.on_set(value) - -def parse_expander(fmt): - bits = [] - z = 0 - while True: - y = fmt.find('(', z) - if y == -1: - bits.append(fmt[z:]) - break - bits.append(fmt[z:y]) - should_shlex_result = False - if fmt[y+1:y+2] == '*': - should_shlex_result = True - y += 1 - try: - parser.expr(fmt[y+1:]) - except SyntaxError as e: - offset = e.offset - if offset == 0 or fmt[y+1+offset-1] != ')': - raise - bits.append((compile(fmt[y+1:y+1+offset-1], '', 'eval'), should_shlex_result)) - z = y+1+offset - return bits - -def eval_expand_bit(bit, settings): - dep = eval(bit, settings.vals, settings.__dict__) - if isinstance(dep, Pending): - dep = dep.resolve() - return dep - -def expand(fmt, settings): - bits = parse_expander(fmt) - return ''.join((bit if isinstance(bit, basestring) else eval_expand_bit(bit[0], settings)) for bit in bits) - -def expand_argv(argv, settings): - if isinstance(argv, basestring): - bits = parse_expander(argv) - shell = ''.join(bit if isinstance(bit, basestring) else '(!)' for bit in bits) - codes = [bit for bit in bits if not isinstance(bit, basestring)] - argv = shlex.split(shell) - out_argv = [] - for arg in argv: - first = True - out_argv.append('') - for bit in arg.split('(!)'): - if not first: - code, should_shlex_result = codes.pop(0) - res = eval_expand_bit(code, settings) - res = shlex.split(res) if should_shlex_result else [res] - out_argv[-1] += res[0] - out_argv.extend(res[1:]) - first = False - out_argv[-1] += bit - return out_argv - else: - return [expand(arg, settings) for arg in argv] - -def installation_dirs_group(sg): - section = OptSection('Fine tuning of the installation directories:') - for name, optname, optdesc, default in [ - ('prefix', '--prefix', '', '/usr/local'), - ('exec_prefix', '--exec-prefix', '', '(prefix)'), - ('bin', '--bindir', '', '(exec_prefix)/bin'), - ('sbin', '--sbindir', '', '(exec_prefix)/sbin'), - ('libexec', '--libexecdir', '', '(exec_prefix)/libexec'), - ('etc', '--sysconfdir', '', '(prefix)/etc'), - ('var', '--localstatedir', '', '(prefix)/var'), - ('lib', '--libdir', '', '(prefix)/lib'), - ('include', '--includedir', '', '(prefix)/include'), - ('datarootdir', '--datarootdir', '', '(prefix)/share'), - ('share', '--datadir', '', '(datarootdir)'), - ('locale', '--localedir', '', '(datarootdir)/locale'), - ('man', '--mandir', '', '(datarootdir)/man'), - ('doc', '--docdir', '', '(datarootdir)/doc/(group_parent.package_unix_name)'), - ('html', '--htmldir', '', '(doc)'), - ('pdf', '--pdfdir', '', '(doc)'), - ]: - sg.add_setting_option(name, optname, optdesc, default, section=section, show=False) - for ignored in ['--sharedstatedir', '--oldincludedir', '--infodir', '--dvidir', '--psdir']: - Option(ignored, 'Ignored autotools compatibility setting', None, section=section, show=False) - -def _make_argparse(include_unused, include_env): - parser = argparse.ArgumentParser( - add_help=False, - usage='configure [OPTION]... [VAR=VALUE]...', - prefix_chars=('-' + string.ascii_letters if include_env else '-'), - ) - parser.add_argument('--help', action='store_true', help='Show this help', dest='__help') - parser.add_argument('--help-all', action='store_true', help='Show this help, including unused options', dest='__help_all') - for sect in all_opt_sections: - def include(opt): - return (include_unused or opt.show) and (include_env or not opt.is_env) - if not any(map(include, sect.opts)): - continue - ag = parser.add_argument_group(description=sect.desc) - for opt in sect.opts: - if not include(opt): - continue - ag.add_argument(opt.name, - action='store_true' if opt.bool else 'store', - dest=opt.name[2:], - help=opt.help, - type=opt.type, - metavar=opt.metavar, - **opt.argparse_kw) - return parser - -def _print_help(include_unused=False): - parser = _make_argparse(include_unused, include_env=True) - parser.print_help() - -def parse_args(): - will_need(pre_parse_args_will_need) - default_opt_section.move_to_end() - parser = _make_argparse(include_unused=True, include_env=False) - args, argv = parser.parse_known_args() - if args.__help or args.__help_all: - _print_help(include_unused=args.__help_all) - sys.exit(0) - unrecognized_env = [] - def do_env_arg(arg): - m = re.match('([^- ]+)=(.*)', arg) - if not m: - return True # keep for unrecognized - if m.group(1) + '=' not in all_options_by_name: - unrecognized_env.append(arg) - else: - os.environ[m.group(1)] = m.group(2) - return False - unrecognized_argv = list(filter(do_env_arg, argv)) - if unrecognized_argv: - print ('unrecognized arguments: %s' % (argv_to_shell(unrecognized_argv),)) - if unrecognized_env: - print ('unrecognized environment: %s' % (argv_to_shell(unrecognized_env),)) - if unrecognized_argv or unrecognized_env: - _print_help() - sys.exit(0) - - for opt in all_options: - try: - if opt.is_env: - name = opt.name[:-1] - opt.set(opt.type(os.environ[name]) if name in os.environ else None) - else: - opt.set(getattr(args, opt.name[2:])) - except DependencyNotFoundException as e: - def f(): raise e - post_parse_args_will_need.append(f) - #print args._unrecognized_args - - global did_parse_args - did_parse_args = True - will_need(post_parse_args_will_need) - -# -- toolchains -- -class Triple(namedtuple('Triple', 'triple arch vendor os abi')): - def __new__(self, triple): - if isinstance(triple, Triple): - return triple - else: - bits = triple.split('-') - numbits = len(bits) - if numbits > 4: - raise Exception('strange triple %r' % (triple,)) - if numbits in (2, 3) and bits[1] not in ('unknown', 'none', 'pc'): - # assume the vendor was left out - bits.insert(1, None) - return super(Triple, self).__new__(self, triple, *((bits.pop(0) if bits else None) for i in range(4))) - def __str__(self): - return self.triple - -class Machine(object): - def __init__(self, name, settings, triple_help, triple_default): - self.name = name - self.settings = settings - def on_set(val): - self.triple = Triple(val) - if isinstance(triple_default, basestring): - triple_help += '; default: %r' % (triple_default,) - self.triple_option = Option('--' + name, help=triple_help, default=triple_default, on_set=on_set, type=Triple, section=triple_options_section) - self.triple = PendingOption(self.triple_option) - - self.toolchains = memoize(self.toolchains) - self.c_tools = memoize(self.c_tools) - - def __eq__(self, other): - return self.triple == other.triple - def __ne__(self, other): - return self.triple != other.triple - def __repr__(self): - return 'Machine(name=%r, triple=%s)' % (self.name, repr(self.triple) if hasattr(self, 'triple') else '') - - def is_cross(self): - # This is only really meaningful in GNU land, as it decides whether to - # prepend the triple (hopefully other targets are sane enough not to - # have a special separate "cross compilation mode" that skips - # configuration checks, but...). Declared here because it may be - # useful to override. - if not hasattr(self, '_is_cross'): - self._is_cross = self.triple != self.settings.build_machine().triple - return self._is_cross - - def is_darwin(self): - return (self.triple.os is not None and 'darwin' in self.triple.os) or \ - (self.triple.triple == '' and os.path.exists('/System/Library/Frameworks')) - - # Get a list of appropriate toolchains. - def toolchains(self): # memoized - tcs = [] - if os.path.exists('/usr/bin/xcrun'): - tcs.append(XcodeToolchain(self, self.settings)) - tcs.append(UnixToolchain(self, self.settings)) - return tcs - - #memoize - def c_tools(self): - return CTools(self.settings, self, self.toolchains()) - -class CLITool(object): - def __init__(self, name, defaults, env, machine, toolchains, dont_suffix_env=False, section=None): - self.name = name - self.defaults = defaults - self.env = env - self.toolchains = toolchains - self.needed = False - self.machine = machine - if machine.name != 'host' and not dont_suffix_env: - env = '%s_FOR_%s' % (env, to_upper_and_underscore(machine.name)) - def on_set(val): - if val is not None: - self.argv_from_opt = shlex.split(val) - self.argv_opt = Option(env + '=', help='Default: %r' % (defaults,), on_set=on_set, show=False, section=section) - self.argv = memoize(self.argv) - - def __repr__(self): - return 'CLITool(name=%r, defaults=%r, env=%r)' % (self.name, self.defaults, self.env) - - def optional(self): - self.argv_opt.need() - - def required(self): - self.optional() - post_parse_args_will_need.append(lambda: self.argv()) - - def argv(self): # mem - if not self.argv_opt.show: - raise Exception("You asked for argv but didn't call required() or optional() before parsing args: %r" % (self,)) - # If the user specified it explicitly, don't question. - if hasattr(self, 'argv_from_opt'): - log('Using %s from command line: %s\n' % (self.name, argv_to_shell(self.argv_from_opt))) - return self.argv_from_opt - - failure_notes = [] - for tc in self.toolchains: - argv = tc.find_tool(self, failure_notes) - if argv is not None: - log('Found %s%s: %s\n' % ( - self.name, - (' for %r' % (self.machine.name,) if self.machine is not None else ''), - argv_to_shell(argv))) - return argv - - log('** Failed to locate %s\n' % (self.name,)) - for n in failure_notes: - log(' note: %s\n' % indentify(n, ' ')) - raise DependencyNotFoundException - - def locate_in_paths(self, prefix, paths): - for path in paths: - for default in self.defaults: - default = prefix + default - filename = os.path.join(path, default) - if os.path.exists(filename): - return [filename] - return None - - -class UnixToolchain(object): - def __init__(self, machine, settings): - self.machine = machine - self.settings = settings - - def find_tool(self, tool, failure_notes): - prefix = '' - if self.machine.is_cross(): - prefix = self.machine.triple.triple + '-' - failure_notes.append('detected cross compilation, so searched for %s-%s' % (self.machine.triple.triple, tool.name)) - return tool.locate_in_paths(prefix, self.settings.tool_search_paths) - -# Reads a binary or XML plist (on OS X) -def read_plist(gunk): - import plistlib - if sys.version_info >= (3, 0): - return plistlib.loads(gunk) # it can do it out of the box - else: - if gunk.startswith('bplist'): - p = subprocess.Popen('plutil -convert xml1 - -o -'.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE) - gunk, _ = p.communicate(gunk) - assert p.returncode == 0 - - return plistlib.readPlistFromString(gunk) - -class XcodeToolchain(object): - def __init__(self, machine, settings): - self.machine = machine - prefix = (machine.name + '-') if machine.name != 'host' else '' - section = OptSection('Xcode SDK options (%s):' % (machine.name,)) - name = '--%sxcode-sdk' % (prefix,) - self.sdk_opt = Option(name, help='Use Xcode SDK - `xcodebuild -showsdks` lists; typical values: macosx, iphoneos, iphonesimulator, watchos, watchsimulator', on_set=None, section=section) - name = '--%sxcode-archs' % (prefix,) - self.arch_opt = Option(name, help='Comma-separated list of -arch settings for use with an Xcode toolchain', on_set=self.on_set_arch, section=section) - self.ok = False - - def on_set_arch(self, arch): - self.sdk = self.sdk_opt.value - some_explicit_xcode_request = bool(self.sdk or arch) - tarch = arch - if not arch and self.machine.triple.arch is not None: - tarch = self.machine.triple.arch - if tarch == 'arm': - #log("Warning: treating 'arm' in triple %r as '-arch armv7'; you can specify a triple like 'armv7-apple-darwin10', or override with %r\n" % (self.machine.triple.triple, self.arch_opt.name)) - tarch = 'armv7' - elif tarch == 'armv8': # XXX is this right? - tarch = 'arm64' - if not self.sdk: - is_armish = tarch is not None and tarch.startswith('arm') - self.sdk = 'iphoneos' if is_armish else 'macosx' - # this is used for arch and also serves as a check - sdk_platform_path, _, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, '--show-sdk-platform-path']) - if code == 127: - log('* Failed to run /usr/bin/xcrun\n') - if some_explicit_xcode_request: - raise DependencyNotFoundException - return - elif code: - log('* Xcode SDK %r not found\n' % (self.sdk,)) - if some_explicit_xcode_request: - raise DependencyNotFoundException - return - self.sdk_platform_path = sdk_platform_path.rstrip() - log('Xcode SDK platform path: %r\n' % (self.sdk_platform_path,)) - - self.archs = self.get_archs(arch, tarch) - if self.archs is None: - log("%s default Xcode SDK for %r because %s; pass %s=arch1,arch2 to override\n" % ( - "Can't use" if some_explicit_xcode_request else "Not using", - self.machine.name, - ("triple architecture %r doesn't seem to be valid" % (tarch,)) if tarch else "I couldn't guess a list of architectures from the SDK", - self.arch_opt.name, - )) - if some_explicit_xcode_request: - raise DependencyNotFoundException - return - log('Using architectures for %r: %s\n' % (self.machine.name, repr(self.archs) if self.archs != [] else '(native)')) - self.ok = True - - def get_archs(self, arch, tarch): - if arch: - return re.sub('\s', '', arch).split(',') - if tarch: - # we need to validate it - sod, sed, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, 'ld', '-arch', tarch]) - if 'unsupported arch' in sed: - return None - return [tarch] - triple = self.machine.triple - # try to divine appropriate architectures - # this may fail with future versions of Xcode, but at least we tried - if self.sdk_platform_path.endswith('MacOSX.platform'): - # Assume you just wanted to build natively - return [] - xcspecs = glob.glob('%s/Developer/Library/Xcode/Specifications/*Architectures.xcspec' % (self.sdk_platform_path,)) + \ - glob.glob('%s/Developer/Library/Xcode/PrivatePlugIns/*/Contents/Resources/Device.xcspec' % (self.sdk_platform_path,)) - for spec in xcspecs: - def f(): - try: - pl = read_plist(open(spec, 'rb').read()) - except: - raise - return - if not isinstance(pl, list): - return - for item in pl: - if not isinstance(item, dict): - return - if item.get('ArchitectureSetting') != 'ARCHS_STANDARD': - return - archs = item.get('RealArchitectures') - if not isinstance(archs, list) and not all(isinstance(arch, basestring) for arch in archs): - return - return archs - archs = f() - if archs is not None: - return archs - log('(Failed to divine architectures from %r for some reason...)\n' % (spec,)) - - # give up - return None - - def arch_flags(self): - return [flag for arch in self.archs for flag in ('-arch', arch)] - - def find_tool(self, tool, failure_notes): - if not self.ok: - return None - argv = ['/usr/bin/xcrun', '--sdk', self.sdk, tool.name] + self.arch_flags() - sod, sed, code = run_command(argv + ['--asdf']) - if code != 0: - if sed.startswith('xcrun: error: unable to find utility'): - failure_notes.append(sed) - return None - return argv - -# Just a collection of common tools, plus flag options -class CTools(object): - def __init__(self, settings, machine, toolchains): - flags_section = OptSection('Compiler/linker flags (%s):' % (machine.name,)) - tools_section = OptSection('Tool overrides (%s):' % (machine.name,)) - - tools = [ - ('cc', ['cc', 'gcc', 'clang'], 'CC'), - ('cxx', ['c++', 'g++', 'clang++'], 'CXX'), - ('ar',), - ('nm',), - ('ranlib',), - ('strip',), - # GNU - ('objdump', ['objdump', 'gobjdump'], 'OBJDUMP'), - ('objcopy', ['objcopy', 'gobjcopy'], 'OBJCOPY'), - # OS X - ('lipo',), - ('dsymutil',), - ] - for spec in tools: - if len(spec) == 1: - name, defaults, env = spec[0], [spec[0]], spec[0].upper() - else: - name, defaults, env = spec - tool = CLITool(name, defaults, env, machine, toolchains, section=tools_section) - setattr(self, name, tool) - - suff = '' - if machine.name != 'host': - suff = '_FOR_' + to_upper_and_underscore(machine.name) - suff += '=' - self.cflags_opt = settings.add_setting_option('cflags', 'CFLAGS'+suff, 'Flags for $CC', [], section=flags_section, type=shlex.split) - self.cxxflags_opt = settings.add_setting_option('cxxflags', 'CXXFLAGS'+suff, 'Flags for $CXX', [], section=flags_section, type=shlex.split) - self.ldflags_opt = settings.add_setting_option('ldflags', 'LDFLAGS'+suff, 'Flags for $CC/$CXX when linking', [], section=flags_section, type=shlex.split) - self.cppflags_opt = settings.add_setting_option('cppflags', 'CPPFLAGS'+suff, 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=flags_section, type=shlex.split) - - -# A nicer - but optional - way of doing multiple tests that will print all the -# errors in one go and exit cleanly -def will_need(tests): - failures = 0 - for test in tests: - try: - test() - except DependencyNotFoundException: - failures += 1 - if failures > 0: - log('(%d failure%s.)\n' % (failures, 's' if failures != 1 else '')) - sys.exit(1) - -def within_dirtree(tree, fn): - return not os.path.relpath(fn, tree).startswith('..'+os.path.sep) - -real_out = memoize(lambda: os.path.realpath(settings_root.out)) -def clean_files(fns, settings): - ro = real_out() - for fn in fns: - if not os.path.exists(fn) or os.path.isdir(fn): - continue - if not settings.allow_autoclean_outside_out and not within_dirtree(ro, os.path.realpath(fn)): - log("* Would clean %r as previous build leftover, but it isn't in settings.out (%r) so keeping it for safety.\n" % (fn, ro)) - continue - config_log.write('Removing %r\n' % (fn,)) - os.remove(fn) - -def list_mconfig_scripts(settings): - real_src = os.path.realpath(settings.src) - res = [] - for mod in sys.modules.values(): - if hasattr(mod, '__file__') and within_dirtree(real_src, os.path.realpath(mod.__file__)): - if is_py3: - fn = mod.__loader__.path - else: - fn = mod.__file__ - if fn.endswith('.pyc') or fn.endswith('.pyo'): - if os.path.exists(fn[:-1]): - fn = fn[:-1] - else: - # who knows? - continue - res.append(fn) - return res - -def write_file_loudly(fn, data, perm=None): - log('Writing %s\n' % (fn,)) - with open(fn, 'w') as fp: - fp.write(data) - if perm is not None: - try: - os.chmod(fn, perm) - except Exception as e: - log('chmod: %r' % (e,)) - -class Emitter(object): - def __init__(self, settings): - self.settings = settings - def pre_output(self): - assert not hasattr(self, 'did_output') - self.did_output = True - def set_default_rule(self, rule): - self.default_rule = rule - def add_command(self, settings, outs, ins, argvs, *args, **kwargs): - if kwargs.get('expand', True): - outs = [expand(x, settings) for x in outs] - ins = [expand(x, settings) for x in ins] - argvs = [expand_argv(x, settings) for x in argvs] - if 'expand' in kwargs: - del kwargs['expand'] - if settings.enable_rule_hashing: - sha = hashlib.sha1(json.dumps((outs, ins, argvs)).encode('utf-8')).hexdigest() - if sha not in prev_rule_hashes: - clean_files(outs, settings) - cur_rule_hashes.add(sha) - return self.add_command_raw(outs, ins, argvs, *args, **kwargs) - def emit(self, fn=None): - if fn is None: - fn = self.settings.emit_fn - output = self.output() - write_file_loudly(fn, output) - - -# In the future it may be desirable to use make variables and nontrivial ninja rules for efficiency. - -class MakefileEmitter(Emitter): - def __init__(self, settings): - Emitter.__init__(self, settings) - self.banner = '# Generated by mconfig.py' - self.makefile_bits = [self.banner] - self.main_mk = settings.get('main_mk') - if self.main_mk is None: - self.main_mk = lambda: os.path.join(dirname(settings.emit_fn), 'main.mk') - - def add_all_and_clean(self): - if hasattr(self, 'default_rule'): - if self.default_rule != 'all': - self.add_command_raw(['all'], [self.default_rule], [], phony=True) - else: - log('Warning: %r: no default rule\n' % (self,)) - self.makefile_bits.append('clean:\n\trm -rf %s\n' % (self.filename_rel_and_escape(self.settings.out))) - - @staticmethod - def filename_escape(fn): - if re.search('[\n\0]', fn): - raise ValueError("your awful filename %r can't be encoded in make (probably)" % (fn,)) - return re.sub(r'([ :\$\\])', r'\\\1', fn) - def filename_rel_and_escape(self, fn): - fn = os.path.relpath(fn, dirname(self.settings.emit_fn)) - return self.filename_escape(fn) - # depfile = ('makefile', filename) or ('msvc',) - def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): - bit = '' - outs = ' '.join(map(self.filename_rel_and_escape, outs)) - ins = ' '.join(map(self.filename_rel_and_escape, ins)) - if phony: - bit += '.PHONY: %s\n' % (outs,) - bit += '%s:%s%s\n' % (outs, ' ' if ins else '', ins) - for argv in argvs: - bit += '\t' + argv_to_shell(argv) + '\n' - if depfile is not None: - if depfile[0] != 'makefile': - raise ValueError("don't support depfile of type %r" % (depfile[0],)) - bit += '-include %s\n' % (self.filename_rel_and_escape(depfile[1]),) - if 'all' in outs: - self.makefile_bits.insert(0, bit) - else: - self.makefile_bits.append(bit) - - def output(self): - self.pre_output() - self.add_all_and_clean() - return '\n'.join(self.makefile_bits) - - def emit(self): - makefile = self.settings.emit_fn - main_mk = self.main_mk() - cs_argvs = [['echo', 'Running config.status...'], ['./config.status']] - self.add_command_raw([makefile], list_mconfig_scripts(self.settings), cs_argvs) - Emitter.emit(self, main_mk) - # Write the stub - # TODO is there something better than shell? - # TODO avoid deleting partial output? - stub = ''' -%(banner)s -_ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) -include %(main_mk)s -'''.lstrip() \ - % { - 'makefile_arg': argv_to_shell([makefile]), - 'main_mk_arg': argv_to_shell([main_mk]), - 'main_mk': self.filename_rel_and_escape(main_mk), - 'banner': self.banner, - } - write_file_loudly(makefile, stub) - - def default_outfile(self): - return 'Makefile' - -class NinjaEmitter(Emitter): - def __init__(self, settings): - Emitter.__init__(self, settings) - self.ninja_bits = [] - self.ruleno = 0 - @staticmethod - def filename_escape(fn): - if re.search('[\n\0]', fn): - raise ValueError("your awful filename %r can't be encoded in ninja (probably)" % (fn,)) - return re.sub(r'([ :\$])', r'$\1', fn) - def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): - bit = '' - if phony: - if len(argvs) == 0: - self.ninja_bits.append('build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, ins)))) - return - outs2 = ['__phony_' + out for out in outs] - bit += 'build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, outs2))) - outs = outs2 - rule_name = 'rule_%d' % (self.ruleno,) - self.ruleno += 1 - bit += 'rule %s\n' % (rule_name,) - bit += ' command = %s\n' % (' && $\n '.join(map(argv_to_shell, argvs))) - if depfile: - if depfile[0] not in ('makefile', 'msvc'): - raise ValueError("don't support depfile of type %r" % (depfile[0],)) - bit += ' deps = %s\n' % ({'makefile': 'gcc', 'msvc': 'msvc'}[depfile[0]],) - bit += ' depfile = %s\n' % (self.filename_escape(depfile[1]),) - bit += 'build %s: %s' % (' '.join(map(self.filename_escape, outs),), rule_name) - if ins: - bit += ' | %s' % (' '.join(map(self.filename_escape, ins),)) - bit += '\n' - self.ninja_bits.append(bit) - - def add_default(self): - if hasattr(self, 'default_rule'): - self.ninja_bits.append('default %s\n' % (self.default_rule,)) - else: - log('Warning: %r: no default rule\n' % (self,)) - - def output(self): - self.pre_output() - self.add_default() - return '\n'.join(self.ninja_bits) - - def default_outfile(self): - return 'build.ninja' - - -def add_emitter_option(): - def on_set_generate(val): - if val not in emitters: - raise DependencyNotFoundException('Unknown build script type: %s (options: %s)' % (val, ' '.join(emitters.keys()))) - settings_root.emitter = emitters[val](settings_root) - Option( - '--generate', - 'The type of build script to generate. Options: %s (default makefile)' % (', '.join(emitters.keys()),), - on_set_generate, default='makefile', section=output_section) - settings_root.add_setting_option('emit_fn', '--outfile', 'Output file. Default: depends on type', section=output_section, default=lambda: settings_root.emitter.default_outfile()) - -def config_status(): - return '#!/bin/sh\n' + argv_to_shell([sys.executable] + sys.argv) + '\n' - -def finish_and_emit(): - settings_root.emitter.emit() - if settings_root.enable_rule_hashing: - emit_rule_hashes() - write_file_loudly('config.status', config_status(), 0o755) - -def check_rule_hashes(): - if not settings_root.enable_rule_hashing: - return - global prev_rule_hashes, cur_rule_hashes - cur_rule_hashes = set() - rule_path = os.path.join(settings_root.out, 'mconfig-hashes.txt') - try: - fp = open(rule_path) - except IOError: - prev_rule_hashes = set() - return - prev_rule_hashes = set(json.load(fp)) - fp.close() - -def emit_rule_hashes(): - rule_path = os.path.join(settings_root.out, 'mconfig-hashes.txt') - with open(rule_path, 'w') as fp: - json.dump(list(cur_rule_hashes), fp) - -def default_is_cxx(filename): - root, ext = os.path.splitext(filename) - return ext in ('cc', 'cpp', 'cxx', 'mm') - -# emitter: the emitter to add rules to -# machine: machine -# settings: settings object; will inspect {c,cxx,cpp,ld}flags -# sources: list of source files -# headers: *optional* list of header files that will be used in the future to -# generate IDE projects - unused for makefile/ninja due to -# depfiles -# objs: list of .o files or other things to add to the link -# link_out: optional linker output -# link_type: 'exec', 'dylib', 'staticlib', 'obj'; default exec -# settings_cb: (filename) -> None or a settings object to override the default -# the following keys are accepted: -# override_cxx: True ($CXX) or False ($CC); ignored in IDE native mode -# override_cc: override cc altogther; ignored in IDE native mode -# override_obj_fn: the .o file -# extra_deps: dependencies -# force_cli: don't use IDEs' native C/C++ compilation mechanism -# expand: call expand on filenames -def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=None, force_cli=False, expand=True): - if expand: - headers = [expand(header, settings) for header in headers] - tools = machine.c_tools() - any_was_cxx = False - obj_fns = [] - ldflag_sets = set() - _expand = globals()['expand'] - for fn in sources: - if expand: - fn = _expand(fn, settings) - my_settings = settings - if settings_cb is not None: - s = settings_cb(fn) - if s is not None: - my_settings = s - obj_fn = my_settings.get('override_obj_fn') or guess_obj_fn(fn, settings) - is_cxx = my_settings.get('override_is_cxx') - if is_cxx is None: - is_cxx = default_is_cxx(fn) - dbg = ['-g'] if my_settings.debug_info else [] - cflags = my_settings.cxxflags if is_cxx else my_settings.cflags - cc = my_settings.get('override_cc') or (tools.cxx if is_cxx else tools.cc).argv() - extra_deps = my_settings.get('extra_deps', []) - any_was_cxx = any_was_cxx or is_cxx - dep_fn = os.path.splitext(obj_fn)[0] + '.d' - - mkdir_cmd = ['mkdir', '-p', dirname(obj_fn)] - cmd = cc + dbg + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] - - emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn), expand=False) - - for lset in my_settings.get('obj_ldflag_sets', ()): - ldflag_sets.add(tuple(lset)) - obj_fns.append(obj_fn) - - return obj_fns, any_was_cxx, ldflag_sets - -def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): - if expand: - _expand = globals()['expand'] - link_out = _expand(link_out, settings) - objs = [_expand(obj, settings) for obj in objs] - tools = machine.c_tools() - assert link_type in ('exec', 'dylib', 'staticlib', 'obj') - if link_type in ('exec', 'dylib'): - assert link_with_cxx in (False, True) - cc_for_link = (tools.cxx if link_with_cxx else tools.cc).argv() - if link_type == 'dylib': - typeflag = ['-dynamiclib'] if machine.is_darwin() else ['-shared'] - else: - typeflag = [] - cmds = [cc_for_link + typeflag + settings.ldflags + extra_ldflags + ['-o', link_out] + objs] - if machine.is_darwin() and settings.debug_info: - cmds.append(tools.dsymutil.argv() + [link_out]) - elif link_type == 'staticlib': - cmds = [tools.ar.argv() + ['rcs'] + objs] - elif link_type == 'obj': - cmds = [tools.cc.argv() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs] - cmds.insert(0, ['mkdir', '-p', dirname(link_out)]) - emitter.add_command(settings, [link_out], objs + extra_deps, cmds, expand=False) - -def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): - more_objs, link_with_cxx, ldflag_sets = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) - extra_ldflags = [flag for lset in ldflag_sets for flag in lset] + extra_ldflags - link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps, extra_ldflags) - -def guess_obj_fn(fn, settings): - rel = os.path.relpath(fn, settings.src) - if not rel.startswith('..'+os.path.sep): - rel = os.path.splitext(rel)[0] + '.o' - return os.path.join(settings.out, rel) - raise ValueError("can't guess .o filename for %r, as it's not in settings.src" % (fn,)) - -# -- init code -- - - -init_config_log() - -did_parse_args = False - -all_options = [] -all_options_by_name = {} -all_opt_sections = [] -default_opt_section = OptSection('Uncategorized options:') -pre_parse_args_will_need = [] -post_parse_args_will_need = [] - -settings_root = SettingsGroup(name='root') -settings_root.package_unix_name = Pending() -installation_dirs_group(settings_root.new_child('idirs')) - -output_section = OptSection('Output options:') - -triple_options_section = OptSection('System types:') -settings_root.build_machine = memoize(lambda: Machine('build', settings_root, 'the machine doing the build', lambda: Triple(''))) -settings_root.host_machine = memoize(lambda: settings_root.build_machine() and Machine('host', settings_root, 'the machine that will run the compiled program', lambda: settings_root.build_machine().triple)) -# ...'the machine that the program will itself compile programs for', - -settings_root.tool_search_paths = os.environ['PATH'].split(':') - -settings_root.src = dirname(sys.argv[0]) -settings_root.out = os.path.join(os.getcwd(), 'out') - -settings_root.debug_info = False - -settings_root.enable_rule_hashing = True -settings_root.allow_autoclean_outside_out = False -post_parse_args_will_need.append(check_rule_hashes) -settings_root.add_deps_on_config_scripts = True - -emitters = { - 'makefile': MakefileEmitter, - 'ninja': NinjaEmitter, -} - -pre_parse_args_will_need.append(add_emitter_option) - -# -- - diff --git a/script/mconfig.py b/script/mconfig.py new file mode 100644 index 0000000..2624c33 --- /dev/null +++ b/script/mconfig.py @@ -0,0 +1,1098 @@ +import re, argparse, sys, os, string, shlex, subprocess, glob, parser, hashlib, json +from collections import OrderedDict, namedtuple +import curses.ascii + +# Py3 stuff... +is_py3 = sys.hexversion >= 0x3000000 +if is_py3: + basestring = str +def dirname(fn): + return os.path.dirname(fn) or '.' + +def indentify(s, indent=' '): + return s.replace('\n', '\n' + indent) + +def log(x): + sys.stdout.write(x) + config_log.write(x) + +def to_upper_and_underscore(s): + return s.upper().replace('-', '_') + +def argv_to_shell(argv): + quoteds = [] + for arg in argv: + if re.match('^[a-zA-Z0-9_\.@/+=-]+$', arg): + quoteds.append(arg) + else: + quoted = '' + for c in arg: + if c == '\n': + quoted += r'\n' + elif c in r'$`\"': + quoted += '\\' + c + elif not curses.ascii.isprint(c): + quoted += r'\x%02x' % ord(c) + else: + quoted += c + quoteds.append('"' + quoted + '"') + return ' '.join(quoteds) + + +def init_config_log(): + global config_log + config_log = open('config.log', 'w') + config_log.write(argv_to_shell(sys.argv) + '\n') + +# a wrapper for subprocess that logs results +# returns (stdout, stderr, status) [even if Popen fails] +def run_command(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs): + config_log.write('Running command %s...\n' % (argv_to_shell(cmd),)) + try: + p = subprocess.Popen(cmd, stdout=stdout, stderr=stderr, **kwargs) + except OSError: + config_log.write(' OSError\n') + return '', '', 127 + so, se = [o.decode('utf-8') for o in p.communicate()] + if p.returncode != 0: + config_log.write(' failed with status %d\n' % (p.returncode,)) + config_log.write('-----------\n') + config_log.write(' stdout:\n') + config_log.write(so.rstrip()) + config_log.write('\n stderr:\n') + config_log.write(se.rstrip()) + config_log.write('\n-----------\n') + return so, se, p.returncode + +class DependencyNotFoundException(Exception): + pass + +# it must take no arguments, and throw DependencyNotFoundException on failure +class memoize(object): + def __init__(self, f): + self.f = f + def __call__(self): + if hasattr(self, 'threw'): + raise self.threw + elif hasattr(self, 'result'): + return self.result + else: + try: + self.result = self.f() + return self.result + except DependencyNotFoundException as threw: + self.threw = threw + raise + +class Pending(object): + def __repr__(self): + return 'Pending(%x%s)' % (id(self), ('; value=%r' % (self.value,)) if hasattr(self, 'value') else '') + def resolve(self): + return self.value + # xxx py3 + def __getattribute__(self, attr): + try: + return object.__getattribute__(self, attr) + except AttributeError: + if attr is 'value': + raise AttributeError + return PendingAttribute(self, attr) + +class PendingOption(Pending, namedtuple('PendingOption', 'opt')): + def resolve(self): + return self.opt.value + def __repr__(self): + return 'PendingOption(%s)' % (self.opt.name,) + +class PendingAttribute(Pending, namedtuple('PendingAttribute', 'base attr')): + def resolve(self): + return getattr(self.base, self.attr) + def __repr__(self): + return 'PendingAttribute(attr=%s, base=%r)' % (self.attr, self.base) + +class SettingsGroup(object): + def __init__(self, group_parent=None, inherit_parent=None, name=None): + object.__setattr__(self, 'group_parent', group_parent) + object.__setattr__(self, 'inherit_parent', inherit_parent) + object.__setattr__(self, 'vals', OrderedDict()) + if name is None: + name = '<0x%x>' % (id(self),) + object.__setattr__(self, 'name', name) + @staticmethod + def get_meat(self, attr, exctype=KeyError): + allow_pending = not did_parse_args + try: + obj = object.__getattribute__(self, 'vals')[attr] + except KeyError: + inherit_parent = object.__getattribute__(self, 'inherit_parent') + if inherit_parent is not None: + ret = SettingsGroup.get_meat(inherit_parent, attr, exctype) + if isinstance(ret, SettingsGroup): + ret = self[attr] = ret.specialize(name='%s.%s' % (object.__getattribute__(self, 'name'), attr)) + return ret + raise exctype(attr) + else: + if isinstance(obj, Pending): + try: + return obj.resolve() + except: + if not allow_pending: + raise Exception("setting %r is pending; you need to set it" % (attr,)) + return obj + return obj + def __getattribute__(self, attr): + try: + return object.__getattribute__(self, attr) + except AttributeError: + return SettingsGroup.get_meat(self, attr, AttributeError) + def __setattr__(self, attr, val): + try: + object.__getattribute__(self, attr) + except: + self[attr] = val + else: + object.__setattribute__(self, attr, val) + def __getitem__(self, attr): + return self.__getattribute__(attr) + def __setitem__(self, attr, val): + self.vals[attr] = val + def get(self, attr, default=None): + try: + return self[attr] + except AttributeError: + return default + + def __iter__(self): + return self.vals.__iter__() + def items(self): + return self.vals.items() + + def __str__(self): + s = 'SettingsGroup %s {\n' % (self.name,) + o = self + while True: + for attr, val in o.vals.items(): + s += ' %s: %s\n' % (attr, indentify(str(val))) + if o.inherit_parent is None: + break + o = o.inherit_parent + s += ' [inherited from %s:]\n' % (o.name,) + s += '}' + return s + + def add_setting_option(self, name, optname, optdesc, default, **kwargs): + def f(value): + self[name] = value + if isinstance(default, str): + old = default + default = lambda: expand(old, self) + opt = Option(optname, optdesc, f, default, **kwargs) + self[name] = PendingOption(opt) + + def specialize(self, name=None, **kwargs): + sg = SettingsGroup(inherit_parent=self, name=name) + for key, val in kwargs.items(): + sg[key] = val + return sg + + def new_child(self, name, *args, **kwargs): + sg = SettingsGroup(group_parent=self, name='%s.%s' % (self.name, name), *args, **kwargs) + self[name] = sg + return sg + +class OptSection(object): + def __init__(self, desc): + self.desc = desc + self.opts = [] + all_opt_sections.append(self) + def move_to_end(self): + all_opt_sections.remove(self) + all_opt_sections.append(self) + +class Option(object): + def __init__(self, name, help, on_set, default=None, bool=False, show=True, section=None, metavar=None, type=str, **kwargs): + if name.startswith('--'): + self.is_env = False + assert set(kwargs).issubset({'nargs', 'choices', 'required', 'metavar'}) + elif name.endswith('='): + self.is_env = True + assert len(kwargs) == 0 + assert bool is False + else: + raise ValueError("name %r should be '--opt' or 'ENV='" % (name,)) + self.name = name + self.help = help + self.default = default + self.on_set = on_set + self.show = show + self.type = type + if metavar is None: + metavar = '...' + self.metavar = metavar + self.bool = bool + self.section = section if section is not None else default_opt_section + self.section.opts.append(self) + self.argparse_kw = kwargs.copy() + all_options.append(self) + if name in all_options_by_name: + raise KeyError('trying to create Option with duplicate name %r; old is:\n%r' % (name, all_options_by_name[name])) + all_options_by_name[name] = self + def __repr__(self): + value = repr(self.value) if hasattr(self, 'value') else '' + return 'Option(name=%r, help=%r, value=%s, default=%r)' % (self.name, self.help, value, self.default) + + def need(self): + self.show = True + + def set(self, value): + if not self.show: + # If you didn't mention the option in help, you don't get no stinking value. This is for ignored options only. + return + if value is None: + value = self.default + if callable(value): # Pending + value = value() + self.value = value + if self.on_set is not None: + self.on_set(value) + +def parse_expander(fmt): + bits = [] + z = 0 + while True: + y = fmt.find('(', z) + if y == -1: + bits.append(fmt[z:]) + break + bits.append(fmt[z:y]) + should_shlex_result = False + if fmt[y+1:y+2] == '*': + should_shlex_result = True + y += 1 + try: + parser.expr(fmt[y+1:]) + except SyntaxError as e: + offset = e.offset + if offset == 0 or fmt[y+1+offset-1] != ')': + raise + bits.append((compile(fmt[y+1:y+1+offset-1], '', 'eval'), should_shlex_result)) + z = y+1+offset + return bits + +def eval_expand_bit(bit, settings): + dep = eval(bit, settings.vals, settings.__dict__) + if isinstance(dep, Pending): + dep = dep.resolve() + return dep + +def expand(fmt, settings): + bits = parse_expander(fmt) + return ''.join((bit if isinstance(bit, basestring) else eval_expand_bit(bit[0], settings)) for bit in bits) + +def expand_argv(argv, settings): + if isinstance(argv, basestring): + bits = parse_expander(argv) + shell = ''.join(bit if isinstance(bit, basestring) else '(!)' for bit in bits) + codes = [bit for bit in bits if not isinstance(bit, basestring)] + argv = shlex.split(shell) + out_argv = [] + for arg in argv: + first = True + out_argv.append('') + for bit in arg.split('(!)'): + if not first: + code, should_shlex_result = codes.pop(0) + res = eval_expand_bit(code, settings) + res = shlex.split(res) if should_shlex_result else [res] + out_argv[-1] += res[0] + out_argv.extend(res[1:]) + first = False + out_argv[-1] += bit + return out_argv + else: + return [expand(arg, settings) for arg in argv] + +def installation_dirs_group(sg): + section = OptSection('Fine tuning of the installation directories:') + for name, optname, optdesc, default in [ + ('prefix', '--prefix', '', '/usr/local'), + ('exec_prefix', '--exec-prefix', '', '(prefix)'), + ('bin', '--bindir', '', '(exec_prefix)/bin'), + ('sbin', '--sbindir', '', '(exec_prefix)/sbin'), + ('libexec', '--libexecdir', '', '(exec_prefix)/libexec'), + ('etc', '--sysconfdir', '', '(prefix)/etc'), + ('var', '--localstatedir', '', '(prefix)/var'), + ('lib', '--libdir', '', '(prefix)/lib'), + ('include', '--includedir', '', '(prefix)/include'), + ('datarootdir', '--datarootdir', '', '(prefix)/share'), + ('share', '--datadir', '', '(datarootdir)'), + ('locale', '--localedir', '', '(datarootdir)/locale'), + ('man', '--mandir', '', '(datarootdir)/man'), + ('doc', '--docdir', '', '(datarootdir)/doc/(group_parent.package_unix_name)'), + ('html', '--htmldir', '', '(doc)'), + ('pdf', '--pdfdir', '', '(doc)'), + ]: + sg.add_setting_option(name, optname, optdesc, default, section=section, show=False) + for ignored in ['--sharedstatedir', '--oldincludedir', '--infodir', '--dvidir', '--psdir']: + Option(ignored, 'Ignored autotools compatibility setting', None, section=section, show=False) + +def _make_argparse(include_unused, include_env): + parser = argparse.ArgumentParser( + add_help=False, + usage='configure [OPTION]... [VAR=VALUE]...', + prefix_chars=('-' + string.ascii_letters if include_env else '-'), + ) + parser.add_argument('--help', action='store_true', help='Show this help', dest='__help') + parser.add_argument('--help-all', action='store_true', help='Show this help, including unused options', dest='__help_all') + for sect in all_opt_sections: + def include(opt): + return (include_unused or opt.show) and (include_env or not opt.is_env) + if not any(map(include, sect.opts)): + continue + ag = parser.add_argument_group(description=sect.desc) + for opt in sect.opts: + if not include(opt): + continue + ag.add_argument(opt.name, + action='store_true' if opt.bool else 'store', + dest=opt.name[2:], + help=opt.help, + type=opt.type, + metavar=opt.metavar, + **opt.argparse_kw) + return parser + +def _print_help(include_unused=False): + parser = _make_argparse(include_unused, include_env=True) + parser.print_help() + +def parse_args(): + will_need(pre_parse_args_will_need) + default_opt_section.move_to_end() + parser = _make_argparse(include_unused=True, include_env=False) + args, argv = parser.parse_known_args() + if args.__help or args.__help_all: + _print_help(include_unused=args.__help_all) + sys.exit(0) + unrecognized_env = [] + def do_env_arg(arg): + m = re.match('([^- ]+)=(.*)', arg) + if not m: + return True # keep for unrecognized + if m.group(1) + '=' not in all_options_by_name: + unrecognized_env.append(arg) + else: + os.environ[m.group(1)] = m.group(2) + return False + unrecognized_argv = list(filter(do_env_arg, argv)) + if unrecognized_argv: + print ('unrecognized arguments: %s' % (argv_to_shell(unrecognized_argv),)) + if unrecognized_env: + print ('unrecognized environment: %s' % (argv_to_shell(unrecognized_env),)) + if unrecognized_argv or unrecognized_env: + _print_help() + sys.exit(0) + + for opt in all_options: + try: + if opt.is_env: + name = opt.name[:-1] + opt.set(opt.type(os.environ[name]) if name in os.environ else None) + else: + opt.set(getattr(args, opt.name[2:])) + except DependencyNotFoundException as e: + def f(): raise e + post_parse_args_will_need.append(f) + #print args._unrecognized_args + + global did_parse_args + did_parse_args = True + will_need(post_parse_args_will_need) + +# -- toolchains -- +class Triple(namedtuple('Triple', 'triple arch vendor os abi')): + def __new__(self, triple): + if isinstance(triple, Triple): + return triple + else: + bits = triple.split('-') + numbits = len(bits) + if numbits > 4: + raise Exception('strange triple %r' % (triple,)) + if numbits in (2, 3) and bits[1] not in ('unknown', 'none', 'pc'): + # assume the vendor was left out + bits.insert(1, None) + return super(Triple, self).__new__(self, triple, *((bits.pop(0) if bits else None) for i in range(4))) + def __str__(self): + return self.triple + +class Machine(object): + def __init__(self, name, settings, triple_help, triple_default): + self.name = name + self.settings = settings + def on_set(val): + self.triple = Triple(val) + if isinstance(triple_default, basestring): + triple_help += '; default: %r' % (triple_default,) + self.triple_option = Option('--' + name, help=triple_help, default=triple_default, on_set=on_set, type=Triple, section=triple_options_section) + self.triple = PendingOption(self.triple_option) + + self.toolchains = memoize(self.toolchains) + self.c_tools = memoize(self.c_tools) + + def __eq__(self, other): + return self.triple == other.triple + def __ne__(self, other): + return self.triple != other.triple + def __repr__(self): + return 'Machine(name=%r, triple=%s)' % (self.name, repr(self.triple) if hasattr(self, 'triple') else '') + + def is_cross(self): + # This is only really meaningful in GNU land, as it decides whether to + # prepend the triple (hopefully other targets are sane enough not to + # have a special separate "cross compilation mode" that skips + # configuration checks, but...). Declared here because it may be + # useful to override. + if not hasattr(self, '_is_cross'): + self._is_cross = self.triple != self.settings.build_machine().triple + return self._is_cross + + def is_darwin(self): + return (self.triple.os is not None and 'darwin' in self.triple.os) or \ + (self.triple.triple == '' and os.path.exists('/System/Library/Frameworks')) + + # Get a list of appropriate toolchains. + def toolchains(self): # memoized + tcs = [] + if os.path.exists('/usr/bin/xcrun'): + tcs.append(XcodeToolchain(self, self.settings)) + tcs.append(UnixToolchain(self, self.settings)) + return tcs + + #memoize + def c_tools(self): + return CTools(self.settings, self, self.toolchains()) + +class CLITool(object): + def __init__(self, name, defaults, env, machine, toolchains, dont_suffix_env=False, section=None): + self.name = name + self.defaults = defaults + self.env = env + self.toolchains = toolchains + self.needed = False + self.machine = machine + if machine.name != 'host' and not dont_suffix_env: + env = '%s_FOR_%s' % (env, to_upper_and_underscore(machine.name)) + def on_set(val): + if val is not None: + self.argv_from_opt = shlex.split(val) + self.argv_opt = Option(env + '=', help='Default: %r' % (defaults,), on_set=on_set, show=False, section=section) + self.argv = memoize(self.argv) + + def __repr__(self): + return 'CLITool(name=%r, defaults=%r, env=%r)' % (self.name, self.defaults, self.env) + + def optional(self): + self.argv_opt.need() + + def required(self): + self.optional() + post_parse_args_will_need.append(lambda: self.argv()) + + def argv(self): # mem + if not self.argv_opt.show: + raise Exception("You asked for argv but didn't call required() or optional() before parsing args: %r" % (self,)) + # If the user specified it explicitly, don't question. + if hasattr(self, 'argv_from_opt'): + log('Using %s from command line: %s\n' % (self.name, argv_to_shell(self.argv_from_opt))) + return self.argv_from_opt + + failure_notes = [] + for tc in self.toolchains: + argv = tc.find_tool(self, failure_notes) + if argv is not None: + log('Found %s%s: %s\n' % ( + self.name, + (' for %r' % (self.machine.name,) if self.machine is not None else ''), + argv_to_shell(argv))) + return argv + + log('** Failed to locate %s\n' % (self.name,)) + for n in failure_notes: + log(' note: %s\n' % indentify(n, ' ')) + raise DependencyNotFoundException + + def locate_in_paths(self, prefix, paths): + for path in paths: + for default in self.defaults: + default = prefix + default + filename = os.path.join(path, default) + if os.path.exists(filename): + return [filename] + return None + + +class UnixToolchain(object): + def __init__(self, machine, settings): + self.machine = machine + self.settings = settings + + def find_tool(self, tool, failure_notes): + prefix = '' + if self.machine.is_cross(): + prefix = self.machine.triple.triple + '-' + failure_notes.append('detected cross compilation, so searched for %s-%s' % (self.machine.triple.triple, tool.name)) + return tool.locate_in_paths(prefix, self.settings.tool_search_paths) + +# Reads a binary or XML plist (on OS X) +def read_plist(gunk): + import plistlib + if sys.version_info >= (3, 0): + return plistlib.loads(gunk) # it can do it out of the box + else: + if gunk.startswith('bplist'): + p = subprocess.Popen('plutil -convert xml1 - -o -'.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE) + gunk, _ = p.communicate(gunk) + assert p.returncode == 0 + + return plistlib.readPlistFromString(gunk) + +class XcodeToolchain(object): + def __init__(self, machine, settings): + self.machine = machine + prefix = (machine.name + '-') if machine.name != 'host' else '' + section = OptSection('Xcode SDK options (%s):' % (machine.name,)) + name = '--%sxcode-sdk' % (prefix,) + self.sdk_opt = Option(name, help='Use Xcode SDK - `xcodebuild -showsdks` lists; typical values: macosx, iphoneos, iphonesimulator, watchos, watchsimulator', on_set=None, section=section) + name = '--%sxcode-archs' % (prefix,) + self.arch_opt = Option(name, help='Comma-separated list of -arch settings for use with an Xcode toolchain', on_set=self.on_set_arch, section=section) + self.ok = False + + def on_set_arch(self, arch): + self.sdk = self.sdk_opt.value + some_explicit_xcode_request = bool(self.sdk or arch) + tarch = arch + if not arch and self.machine.triple.arch is not None: + tarch = self.machine.triple.arch + if tarch == 'arm': + #log("Warning: treating 'arm' in triple %r as '-arch armv7'; you can specify a triple like 'armv7-apple-darwin10', or override with %r\n" % (self.machine.triple.triple, self.arch_opt.name)) + tarch = 'armv7' + elif tarch == 'armv8': # XXX is this right? + tarch = 'arm64' + if not self.sdk: + is_armish = tarch is not None and tarch.startswith('arm') + self.sdk = 'iphoneos' if is_armish else 'macosx' + # this is used for arch and also serves as a check + sdk_platform_path, _, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, '--show-sdk-platform-path']) + if code == 127: + log('* Failed to run /usr/bin/xcrun\n') + if some_explicit_xcode_request: + raise DependencyNotFoundException + return + elif code: + log('* Xcode SDK %r not found\n' % (self.sdk,)) + if some_explicit_xcode_request: + raise DependencyNotFoundException + return + self.sdk_platform_path = sdk_platform_path.rstrip() + log('Xcode SDK platform path: %r\n' % (self.sdk_platform_path,)) + + self.archs = self.get_archs(arch, tarch) + if self.archs is None: + log("%s default Xcode SDK for %r because %s; pass %s=arch1,arch2 to override\n" % ( + "Can't use" if some_explicit_xcode_request else "Not using", + self.machine.name, + ("triple architecture %r doesn't seem to be valid" % (tarch,)) if tarch else "I couldn't guess a list of architectures from the SDK", + self.arch_opt.name, + )) + if some_explicit_xcode_request: + raise DependencyNotFoundException + return + log('Using architectures for %r: %s\n' % (self.machine.name, repr(self.archs) if self.archs != [] else '(native)')) + self.ok = True + + def get_archs(self, arch, tarch): + if arch: + return re.sub('\s', '', arch).split(',') + if tarch: + # we need to validate it + sod, sed, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, 'ld', '-arch', tarch]) + if 'unsupported arch' in sed: + return None + return [tarch] + triple = self.machine.triple + # try to divine appropriate architectures + # this may fail with future versions of Xcode, but at least we tried + if self.sdk_platform_path.endswith('MacOSX.platform'): + # Assume you just wanted to build natively + return [] + xcspecs = glob.glob('%s/Developer/Library/Xcode/Specifications/*Architectures.xcspec' % (self.sdk_platform_path,)) + \ + glob.glob('%s/Developer/Library/Xcode/PrivatePlugIns/*/Contents/Resources/Device.xcspec' % (self.sdk_platform_path,)) + for spec in xcspecs: + def f(): + try: + pl = read_plist(open(spec, 'rb').read()) + except: + raise + return + if not isinstance(pl, list): + return + for item in pl: + if not isinstance(item, dict): + return + if item.get('ArchitectureSetting') != 'ARCHS_STANDARD': + return + archs = item.get('RealArchitectures') + if not isinstance(archs, list) and not all(isinstance(arch, basestring) for arch in archs): + return + return archs + archs = f() + if archs is not None: + return archs + log('(Failed to divine architectures from %r for some reason...)\n' % (spec,)) + + # give up + return None + + def arch_flags(self): + return [flag for arch in self.archs for flag in ('-arch', arch)] + + def find_tool(self, tool, failure_notes): + if not self.ok: + return None + argv = ['/usr/bin/xcrun', '--sdk', self.sdk, tool.name] + self.arch_flags() + sod, sed, code = run_command(argv + ['--asdf']) + if code != 0: + if sed.startswith('xcrun: error: unable to find utility'): + failure_notes.append(sed) + return None + return argv + +# Just a collection of common tools, plus flag options +class CTools(object): + def __init__(self, settings, machine, toolchains): + flags_section = OptSection('Compiler/linker flags (%s):' % (machine.name,)) + tools_section = OptSection('Tool overrides (%s):' % (machine.name,)) + + tools = [ + ('cc', ['cc', 'gcc', 'clang'], 'CC'), + ('cxx', ['c++', 'g++', 'clang++'], 'CXX'), + ('ar',), + ('nm',), + ('ranlib',), + ('strip',), + # GNU + ('objdump', ['objdump', 'gobjdump'], 'OBJDUMP'), + ('objcopy', ['objcopy', 'gobjcopy'], 'OBJCOPY'), + # OS X + ('lipo',), + ('dsymutil',), + ] + for spec in tools: + if len(spec) == 1: + name, defaults, env = spec[0], [spec[0]], spec[0].upper() + else: + name, defaults, env = spec + tool = CLITool(name, defaults, env, machine, toolchains, section=tools_section) + setattr(self, name, tool) + + suff = '' + if machine.name != 'host': + suff = '_FOR_' + to_upper_and_underscore(machine.name) + suff += '=' + self.cflags_opt = settings.add_setting_option('cflags', 'CFLAGS'+suff, 'Flags for $CC', [], section=flags_section, type=shlex.split) + self.cxxflags_opt = settings.add_setting_option('cxxflags', 'CXXFLAGS'+suff, 'Flags for $CXX', [], section=flags_section, type=shlex.split) + self.ldflags_opt = settings.add_setting_option('ldflags', 'LDFLAGS'+suff, 'Flags for $CC/$CXX when linking', [], section=flags_section, type=shlex.split) + self.cppflags_opt = settings.add_setting_option('cppflags', 'CPPFLAGS'+suff, 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=flags_section, type=shlex.split) + + +# A nicer - but optional - way of doing multiple tests that will print all the +# errors in one go and exit cleanly +def will_need(tests): + failures = 0 + for test in tests: + try: + test() + except DependencyNotFoundException: + failures += 1 + if failures > 0: + log('(%d failure%s.)\n' % (failures, 's' if failures != 1 else '')) + sys.exit(1) + +def within_dirtree(tree, fn): + return not os.path.relpath(fn, tree).startswith('..'+os.path.sep) + +real_out = memoize(lambda: os.path.realpath(settings_root.out)) +def clean_files(fns, settings): + ro = real_out() + for fn in fns: + if not os.path.exists(fn) or os.path.isdir(fn): + continue + if not settings.allow_autoclean_outside_out and not within_dirtree(ro, os.path.realpath(fn)): + log("* Would clean %r as previous build leftover, but it isn't in settings.out (%r) so keeping it for safety.\n" % (fn, ro)) + continue + config_log.write('Removing %r\n' % (fn,)) + os.remove(fn) + +def list_mconfig_scripts(settings): + real_src = os.path.realpath(settings.src) + res = [] + for mod in sys.modules.values(): + if hasattr(mod, '__file__') and within_dirtree(real_src, os.path.realpath(mod.__file__)): + if is_py3: + fn = mod.__loader__.path + else: + fn = mod.__file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): + if os.path.exists(fn[:-1]): + fn = fn[:-1] + else: + # who knows? + continue + res.append(fn) + return res + +def write_file_loudly(fn, data, perm=None): + log('Writing %s\n' % (fn,)) + with open(fn, 'w') as fp: + fp.write(data) + if perm is not None: + try: + os.chmod(fn, perm) + except Exception as e: + log('chmod: %r' % (e,)) + +class Emitter(object): + def __init__(self, settings): + self.settings = settings + def pre_output(self): + assert not hasattr(self, 'did_output') + self.did_output = True + def set_default_rule(self, rule): + self.default_rule = rule + def add_command(self, settings, outs, ins, argvs, *args, **kwargs): + if kwargs.get('expand', True): + outs = [expand(x, settings) for x in outs] + ins = [expand(x, settings) for x in ins] + argvs = [expand_argv(x, settings) for x in argvs] + if 'expand' in kwargs: + del kwargs['expand'] + if settings.enable_rule_hashing: + sha = hashlib.sha1(json.dumps((outs, ins, argvs)).encode('utf-8')).hexdigest() + if sha not in prev_rule_hashes: + clean_files(outs, settings) + cur_rule_hashes.add(sha) + return self.add_command_raw(outs, ins, argvs, *args, **kwargs) + def emit(self, fn=None): + if fn is None: + fn = self.settings.emit_fn + output = self.output() + write_file_loudly(fn, output) + + +# In the future it may be desirable to use make variables and nontrivial ninja rules for efficiency. + +class MakefileEmitter(Emitter): + def __init__(self, settings): + Emitter.__init__(self, settings) + self.banner = '# Generated by mconfig.py' + self.makefile_bits = [self.banner] + self.main_mk = settings.get('main_mk') + if self.main_mk is None: + self.main_mk = lambda: os.path.join(dirname(settings.emit_fn), 'main.mk') + + def add_all_and_clean(self): + if hasattr(self, 'default_rule'): + if self.default_rule != 'all': + self.add_command_raw(['all'], [self.default_rule], [], phony=True) + else: + log('Warning: %r: no default rule\n' % (self,)) + self.makefile_bits.append('clean:\n\trm -rf %s\n' % (self.filename_rel_and_escape(self.settings.out))) + + @staticmethod + def filename_escape(fn): + if re.search('[\n\0]', fn): + raise ValueError("your awful filename %r can't be encoded in make (probably)" % (fn,)) + return re.sub(r'([ :\$\\])', r'\\\1', fn) + def filename_rel_and_escape(self, fn): + fn = os.path.relpath(fn, dirname(self.settings.emit_fn)) + return self.filename_escape(fn) + # depfile = ('makefile', filename) or ('msvc',) + def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): + bit = '' + outs = ' '.join(map(self.filename_rel_and_escape, outs)) + ins = ' '.join(map(self.filename_rel_and_escape, ins)) + if phony: + bit += '.PHONY: %s\n' % (outs,) + bit += '%s:%s%s\n' % (outs, ' ' if ins else '', ins) + for argv in argvs: + bit += '\t' + argv_to_shell(argv) + '\n' + if depfile is not None: + if depfile[0] != 'makefile': + raise ValueError("don't support depfile of type %r" % (depfile[0],)) + bit += '-include %s\n' % (self.filename_rel_and_escape(depfile[1]),) + if 'all' in outs: + self.makefile_bits.insert(0, bit) + else: + self.makefile_bits.append(bit) + + def output(self): + self.pre_output() + self.add_all_and_clean() + return '\n'.join(self.makefile_bits) + + def emit(self): + makefile = self.settings.emit_fn + main_mk = self.main_mk() + cs_argvs = [['echo', 'Running config.status...'], ['./config.status']] + self.add_command_raw([makefile], list_mconfig_scripts(self.settings), cs_argvs) + Emitter.emit(self, main_mk) + # Write the stub + # TODO is there something better than shell? + # TODO avoid deleting partial output? + stub = ''' +%(banner)s +_ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) +include %(main_mk)s +'''.lstrip() \ + % { + 'makefile_arg': argv_to_shell([makefile]), + 'main_mk_arg': argv_to_shell([main_mk]), + 'main_mk': self.filename_rel_and_escape(main_mk), + 'banner': self.banner, + } + write_file_loudly(makefile, stub) + + def default_outfile(self): + return 'Makefile' + +class NinjaEmitter(Emitter): + def __init__(self, settings): + Emitter.__init__(self, settings) + self.ninja_bits = [] + self.ruleno = 0 + @staticmethod + def filename_escape(fn): + if re.search('[\n\0]', fn): + raise ValueError("your awful filename %r can't be encoded in ninja (probably)" % (fn,)) + return re.sub(r'([ :\$])', r'$\1', fn) + def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): + bit = '' + if phony: + if len(argvs) == 0: + self.ninja_bits.append('build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, ins)))) + return + outs2 = ['__phony_' + out for out in outs] + bit += 'build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, outs2))) + outs = outs2 + rule_name = 'rule_%d' % (self.ruleno,) + self.ruleno += 1 + bit += 'rule %s\n' % (rule_name,) + bit += ' command = %s\n' % (' && $\n '.join(map(argv_to_shell, argvs))) + if depfile: + if depfile[0] not in ('makefile', 'msvc'): + raise ValueError("don't support depfile of type %r" % (depfile[0],)) + bit += ' deps = %s\n' % ({'makefile': 'gcc', 'msvc': 'msvc'}[depfile[0]],) + bit += ' depfile = %s\n' % (self.filename_escape(depfile[1]),) + bit += 'build %s: %s' % (' '.join(map(self.filename_escape, outs),), rule_name) + if ins: + bit += ' | %s' % (' '.join(map(self.filename_escape, ins),)) + bit += '\n' + self.ninja_bits.append(bit) + + def add_default(self): + if hasattr(self, 'default_rule'): + self.ninja_bits.append('default %s\n' % (self.default_rule,)) + else: + log('Warning: %r: no default rule\n' % (self,)) + + def output(self): + self.pre_output() + self.add_default() + return '\n'.join(self.ninja_bits) + + def default_outfile(self): + return 'build.ninja' + + +def add_emitter_option(): + def on_set_generate(val): + if val not in emitters: + raise DependencyNotFoundException('Unknown build script type: %s (options: %s)' % (val, ' '.join(emitters.keys()))) + settings_root.emitter = emitters[val](settings_root) + Option( + '--generate', + 'The type of build script to generate. Options: %s (default makefile)' % (', '.join(emitters.keys()),), + on_set_generate, default='makefile', section=output_section) + settings_root.add_setting_option('emit_fn', '--outfile', 'Output file. Default: depends on type', section=output_section, default=lambda: settings_root.emitter.default_outfile()) + +def config_status(): + return '#!/bin/sh\n' + argv_to_shell([sys.executable] + sys.argv) + '\n' + +def finish_and_emit(): + settings_root.emitter.emit() + if settings_root.enable_rule_hashing: + emit_rule_hashes() + write_file_loudly('config.status', config_status(), 0o755) + +def check_rule_hashes(): + if not settings_root.enable_rule_hashing: + return + global prev_rule_hashes, cur_rule_hashes + cur_rule_hashes = set() + rule_path = os.path.join(settings_root.out, 'mconfig-hashes.txt') + try: + fp = open(rule_path) + except IOError: + prev_rule_hashes = set() + return + prev_rule_hashes = set(json.load(fp)) + fp.close() + +def emit_rule_hashes(): + rule_path = os.path.join(settings_root.out, 'mconfig-hashes.txt') + with open(rule_path, 'w') as fp: + json.dump(list(cur_rule_hashes), fp) + +def default_is_cxx(filename): + root, ext = os.path.splitext(filename) + return ext in ('cc', 'cpp', 'cxx', 'mm') + +# emitter: the emitter to add rules to +# machine: machine +# settings: settings object; will inspect {c,cxx,cpp,ld}flags +# sources: list of source files +# headers: *optional* list of header files that will be used in the future to +# generate IDE projects - unused for makefile/ninja due to +# depfiles +# objs: list of .o files or other things to add to the link +# link_out: optional linker output +# link_type: 'exec', 'dylib', 'staticlib', 'obj'; default exec +# settings_cb: (filename) -> None or a settings object to override the default +# the following keys are accepted: +# override_cxx: True ($CXX) or False ($CC); ignored in IDE native mode +# override_cc: override cc altogther; ignored in IDE native mode +# override_obj_fn: the .o file +# extra_deps: dependencies +# force_cli: don't use IDEs' native C/C++ compilation mechanism +# expand: call expand on filenames +def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=None, force_cli=False, expand=True): + if expand: + headers = [expand(header, settings) for header in headers] + tools = machine.c_tools() + any_was_cxx = False + obj_fns = [] + ldflag_sets = set() + _expand = globals()['expand'] + for fn in sources: + if expand: + fn = _expand(fn, settings) + my_settings = settings + if settings_cb is not None: + s = settings_cb(fn) + if s is not None: + my_settings = s + obj_fn = my_settings.get('override_obj_fn') or guess_obj_fn(fn, settings) + is_cxx = my_settings.get('override_is_cxx') + if is_cxx is None: + is_cxx = default_is_cxx(fn) + dbg = ['-g'] if my_settings.debug_info else [] + cflags = my_settings.cxxflags if is_cxx else my_settings.cflags + cc = my_settings.get('override_cc') or (tools.cxx if is_cxx else tools.cc).argv() + extra_deps = my_settings.get('extra_deps', []) + any_was_cxx = any_was_cxx or is_cxx + dep_fn = os.path.splitext(obj_fn)[0] + '.d' + + mkdir_cmd = ['mkdir', '-p', dirname(obj_fn)] + cmd = cc + dbg + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] + + emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn), expand=False) + + for lset in my_settings.get('obj_ldflag_sets', ()): + ldflag_sets.add(tuple(lset)) + obj_fns.append(obj_fn) + + return obj_fns, any_was_cxx, ldflag_sets + +def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): + if expand: + _expand = globals()['expand'] + link_out = _expand(link_out, settings) + objs = [_expand(obj, settings) for obj in objs] + tools = machine.c_tools() + assert link_type in ('exec', 'dylib', 'staticlib', 'obj') + if link_type in ('exec', 'dylib'): + assert link_with_cxx in (False, True) + cc_for_link = (tools.cxx if link_with_cxx else tools.cc).argv() + if link_type == 'dylib': + typeflag = ['-dynamiclib'] if machine.is_darwin() else ['-shared'] + else: + typeflag = [] + cmds = [cc_for_link + typeflag + settings.ldflags + extra_ldflags + ['-o', link_out] + objs] + if machine.is_darwin() and settings.debug_info: + cmds.append(tools.dsymutil.argv() + [link_out]) + elif link_type == 'staticlib': + cmds = [tools.ar.argv() + ['rcs'] + objs] + elif link_type == 'obj': + cmds = [tools.cc.argv() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs] + cmds.insert(0, ['mkdir', '-p', dirname(link_out)]) + emitter.add_command(settings, [link_out], objs + extra_deps, cmds, expand=False) + +def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): + more_objs, link_with_cxx, ldflag_sets = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) + extra_ldflags = [flag for lset in ldflag_sets for flag in lset] + extra_ldflags + link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps, extra_ldflags) + +def guess_obj_fn(fn, settings): + rel = os.path.relpath(fn, settings.src) + if not rel.startswith('..'+os.path.sep): + rel = os.path.splitext(rel)[0] + '.o' + return os.path.join(settings.out, rel) + raise ValueError("can't guess .o filename for %r, as it's not in settings.src" % (fn,)) + +# -- init code -- + + +init_config_log() + +did_parse_args = False + +all_options = [] +all_options_by_name = {} +all_opt_sections = [] +default_opt_section = OptSection('Uncategorized options:') +pre_parse_args_will_need = [] +post_parse_args_will_need = [] + +settings_root = SettingsGroup(name='root') +settings_root.package_unix_name = Pending() +installation_dirs_group(settings_root.new_child('idirs')) + +output_section = OptSection('Output options:') + +triple_options_section = OptSection('System types:') +settings_root.build_machine = memoize(lambda: Machine('build', settings_root, 'the machine doing the build', lambda: Triple(''))) +settings_root.host_machine = memoize(lambda: settings_root.build_machine() and Machine('host', settings_root, 'the machine that will run the compiled program', lambda: settings_root.build_machine().triple)) +# ...'the machine that the program will itself compile programs for', + +settings_root.tool_search_paths = os.environ['PATH'].split(':') + +settings_root.src = dirname(sys.argv[0]) +settings_root.out = os.path.join(os.getcwd(), 'out') + +settings_root.debug_info = False + +settings_root.enable_rule_hashing = True +settings_root.allow_autoclean_outside_out = False +post_parse_args_will_need.append(check_rule_hashes) +settings_root.add_deps_on_config_scripts = True + +emitters = { + 'makefile': MakefileEmitter, + 'ninja': NinjaEmitter, +} + +pre_parse_args_will_need.append(add_emitter_option) + +# -- + -- cgit v1.2.3 From ebc817c57a1ba8e3461833681e44178101f53d72 Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 30 Jun 2015 18:53:03 +0100 Subject: fix auto_rerun_config for ninja/etc --- script/mconfig.py | 91 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/script/mconfig.py b/script/mconfig.py index 2624c33..c5a4aeb 100644 --- a/script/mconfig.py +++ b/script/mconfig.py @@ -1,4 +1,4 @@ -import re, argparse, sys, os, string, shlex, subprocess, glob, parser, hashlib, json +import re, argparse, sys, os, string, shlex, subprocess, glob, parser, hashlib, json, errno from collections import OrderedDict, namedtuple import curses.ascii @@ -9,6 +9,14 @@ if is_py3: def dirname(fn): return os.path.dirname(fn) or '.' +def makedirs(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(path): + return + raise + def indentify(s, indent=' '): return s.replace('\n', '\n' + indent) @@ -770,6 +778,9 @@ class Emitter(object): self.did_output = True def set_default_rule(self, rule): self.default_rule = rule + def filename_rel_and_escape(self, fn): + fn = os.path.relpath(fn, dirname(self.settings.emit_fn)) + return self.filename_escape(fn) def add_command(self, settings, outs, ins, argvs, *args, **kwargs): if kwargs.get('expand', True): outs = [expand(x, settings) for x in outs] @@ -814,9 +825,6 @@ class MakefileEmitter(Emitter): if re.search('[\n\0]', fn): raise ValueError("your awful filename %r can't be encoded in make (probably)" % (fn,)) return re.sub(r'([ :\$\\])', r'\\\1', fn) - def filename_rel_and_escape(self, fn): - fn = os.path.relpath(fn, dirname(self.settings.emit_fn)) - return self.filename_escape(fn) # depfile = ('makefile', filename) or ('msvc',) def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): bit = '' @@ -843,25 +851,28 @@ class MakefileEmitter(Emitter): def emit(self): makefile = self.settings.emit_fn - main_mk = self.main_mk() - cs_argvs = [['echo', 'Running config.status...'], ['./config.status']] - self.add_command_raw([makefile], list_mconfig_scripts(self.settings), cs_argvs) - Emitter.emit(self, main_mk) - # Write the stub - # TODO is there something better than shell? - # TODO avoid deleting partial output? - stub = ''' -%(banner)s -_ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) -include %(main_mk)s -'''.lstrip() \ - % { - 'makefile_arg': argv_to_shell([makefile]), - 'main_mk_arg': argv_to_shell([main_mk]), - 'main_mk': self.filename_rel_and_escape(main_mk), - 'banner': self.banner, - } - write_file_loudly(makefile, stub) + if self.settings.auto_rerun_config: + main_mk = self.main_mk() + cs_argvs = [['echo', 'Running config.status...'], ['./config.status']] + self.add_command_raw([makefile], list_mconfig_scripts(self.settings), cs_argvs) + Emitter.emit(self, main_mk) + # Write the stub + # TODO is there something better than shell? + # TODO avoid deleting partial output? + stub = ''' + %(banner)s + _ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) + include %(main_mk)s + '''.lstrip() \ + % { + 'makefile_arg': argv_to_shell([makefile]), + 'main_mk_arg': argv_to_shell([main_mk]), + 'main_mk': self.filename_rel_and_escape(main_mk), + 'banner': self.banner, + } + write_file_loudly(makefile, stub) + else: + Emitter.emit(self) def default_outfile(self): return 'Makefile' @@ -876,14 +887,24 @@ class NinjaEmitter(Emitter): if re.search('[\n\0]', fn): raise ValueError("your awful filename %r can't be encoded in ninja (probably)" % (fn,)) return re.sub(r'([ :\$])', r'$\1', fn) - def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None): + + def add_command(self, settings, outs, ins, argvs, *args, **kwargs): + if self.settings.auto_rerun_config: + kwargs['order_only_ins'] = kwargs.get('order_only_ins', []) + ['build.ninja'] + Emitter.add_command(self, settings, outs, ins, argvs, *args, **kwargs) + + def add_command_raw(self, outs, ins, argvs, phony=False, depfile=None, order_only_ins=[]): bit = '' if phony: if len(argvs) == 0: - self.ninja_bits.append('build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, ins)))) + self.ninja_bits.append('build %s: phony %s%s\n' % ( + ' '.join(map(self.filename_rel_and_escape, outs)), + ' '.join(map(self.filename_rel_and_escape, ins)), + '' if not order_only_ins else (' || ' + ' '.join(map(self.filename_rel_and_escape, order_only_ins))), + )) return outs2 = ['__phony_' + out for out in outs] - bit += 'build %s: phony %s\n' % (' '.join(map(self.filename_escape, outs)), ' '.join(map(self.filename_escape, outs2))) + bit += 'build %s: phony %s\n' % (' '.join(map(self.filename_rel_and_escape, outs)), ' '.join(map(self.filename_rel_and_escape, outs2))) outs = outs2 rule_name = 'rule_%d' % (self.ruleno,) self.ruleno += 1 @@ -893,13 +914,20 @@ class NinjaEmitter(Emitter): if depfile[0] not in ('makefile', 'msvc'): raise ValueError("don't support depfile of type %r" % (depfile[0],)) bit += ' deps = %s\n' % ({'makefile': 'gcc', 'msvc': 'msvc'}[depfile[0]],) - bit += ' depfile = %s\n' % (self.filename_escape(depfile[1]),) - bit += 'build %s: %s' % (' '.join(map(self.filename_escape, outs),), rule_name) + bit += ' depfile = %s\n' % (self.filename_rel_and_escape(depfile[1]),) + bit += 'build %s: %s' % (' '.join(map(self.filename_rel_and_escape, outs),), rule_name) if ins: - bit += ' | %s' % (' '.join(map(self.filename_escape, ins),)) + bit += ' | %s' % (' '.join(map(self.filename_rel_and_escape, ins),)) bit += '\n' self.ninja_bits.append(bit) + def add_configstatus_rule(self): + # Unlike with make, we don't need to do this separately, before the + # other rules are read, because ninja automatically rereads rules when + # build.ninja has changed. + cs_argvs = [['echo', 'Running config.status...'], ['./config.status']] + self.add_command_raw(['build.ninja'], list_mconfig_scripts(self.settings), cs_argvs) + def add_default(self): if hasattr(self, 'default_rule'): self.ninja_bits.append('default %s\n' % (self.default_rule,)) @@ -908,6 +936,8 @@ class NinjaEmitter(Emitter): def output(self): self.pre_output() + if self.settings.auto_rerun_config: + self.add_configstatus_rule() self.add_default() return '\n'.join(self.ninja_bits) @@ -950,6 +980,7 @@ def check_rule_hashes(): fp.close() def emit_rule_hashes(): + makedirs(settings_root.out) rule_path = os.path.join(settings_root.out, 'mconfig-hashes.txt') with open(rule_path, 'w') as fp: json.dump(list(cur_rule_hashes), fp) @@ -1085,7 +1116,7 @@ settings_root.debug_info = False settings_root.enable_rule_hashing = True settings_root.allow_autoclean_outside_out = False post_parse_args_will_need.append(check_rule_hashes) -settings_root.add_deps_on_config_scripts = True +settings_root.auto_rerun_config = True emitters = { 'makefile': MakefileEmitter, -- cgit v1.2.3 From 1e5ead35d7de129c4cbfd043658d5cd9b1c940bb Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 7 Jul 2015 14:19:56 -0400 Subject: ... --- configure | 44 +++++++++--- script/gen-inject-asm.sh | 8 ++- script/mconfig.py | 171 ++++++++++++++++++++++++++++++----------------- 3 files changed, 150 insertions(+), 73 deletions(-) diff --git a/configure b/configure index 218b2cf..cfc2f70 100755 --- a/configure +++ b/configure @@ -6,10 +6,13 @@ settings = mconfig.settings_root settings.package_unix_name.value = 'substitute' c = settings.host_machine().c_tools() - c.cc.required() c.dsymutil.required() + +settings.add_setting_option('imaon2', '--with-imaon2', 'path to imaon2 (optional)', '') +settings.add_setting_option('gen_dia', '--enable-recompile-dia', 'generate darwin-inject-asm.S', False, bool=True) + asm_archs = [ ('x86_64', []), ('i386', []), @@ -21,12 +24,22 @@ machs = [] for name, cflags in asm_archs: mach = mconfig.Machine('asm-' + name, settings, 'for cross-compiling the inject baton', name + '-apple-darwin10') machs.append(mach) - mach.c_tools().cc.required() + cc = mach.c_tools().cc + cc.optional() + def f(): + if settings.gen_dia: + cc.argv() + mach_settings = settings[mach.name] + mach_settings.cflags = cflags + mach_settings.cflags + mconfig.post_parse_args_will_need.append(f) mconfig.parse_args() -settings.cflags = ['-I%s/lib' % (settings.src,)] + settings.cflags -settings.debug_info = True +#################################### +mconfig.mark_safe_to_clean('(src)/generated/darwin-inject-asm.S', settings) + +settings.host.cflags = ['-I%s/lib' % (settings.src,)] + settings.host.cflags +settings.host.debug_info = True emitter = settings.emitter @@ -67,14 +80,27 @@ balco( ], settings_cb=cb ) +#settings.test = 'foo baz' -#for name, arch_flag, opts in [ -#]: -#compile_c_objs(emitter, settings.host_machine(), - +if settings.gen_dia: + bins = [] + for (name, _cflags), mach in zip(asm_archs, machs): + exe = '(out)/inject-asm-raw-%s' % (name,) + bin = exe + '.bin' + mconfig.build_and_link_c_objs(emitter, mach, + settings.specialize( + override_obj_fn='(out)/inject-asm-raw-%s.o' % (name,), + override_ldflags=['-Wl,-order_file,(src)/lib/darwin/inject-asm-raw.order'] + settings[mach.name].ldflags, + ), + 'exec', + exe, + ['(src)/lib/darwin/inject-asm-raw.c']) + bins.append(bin) + emitter.add_command(settings, [bin], [exe], ['segedit -extract __TEXT __text (outs[0]) (ins[0])']) + emitter.add_command(settings, ['(src)/generated/darwin-inject-asm.S'], bins, [['(src)/script/gen-inject-asm.sh', '(out)'] + bins]) -#settings.test = 'foo baz' emitter.add_command(settings, ['all'], ['(out)/libsubstitute.dylib'], [], phony=True) emitter.set_default_rule('all') + mconfig.finish_and_emit() diff --git a/script/gen-inject-asm.sh b/script/gen-inject-asm.sh index a4dfc5b..161bbe7 100755 --- a/script/gen-inject-asm.sh +++ b/script/gen-inject-asm.sh @@ -13,10 +13,12 @@ cat < "$outfile" diff --git a/script/mconfig.py b/script/mconfig.py index c5a4aeb..f056c10 100644 --- a/script/mconfig.py +++ b/script/mconfig.py @@ -136,7 +136,7 @@ class SettingsGroup(object): if inherit_parent is not None: ret = SettingsGroup.get_meat(inherit_parent, attr, exctype) if isinstance(ret, SettingsGroup): - ret = self[attr] = ret.specialize(name='%s.%s' % (object.__getattribute__(self, 'name'), attr)) + ret = self[attr] = ret.specialize(name='%s.%s' % (object.__getattribute__(self, 'name'), attr), group_parent=self) return ret raise exctype(attr) else: @@ -161,13 +161,13 @@ class SettingsGroup(object): else: object.__setattribute__(self, attr, val) def __getitem__(self, attr): - return self.__getattribute__(attr) + return SettingsGroup.get_meat(self, attr, KeyError) def __setitem__(self, attr, val): self.vals[attr] = val def get(self, attr, default=None): try: return self[attr] - except AttributeError: + except KeyError: return default def __iter__(self): @@ -197,13 +197,14 @@ class SettingsGroup(object): opt = Option(optname, optdesc, f, default, **kwargs) self[name] = PendingOption(opt) - def specialize(self, name=None, **kwargs): - sg = SettingsGroup(inherit_parent=self, name=name) + def specialize(self, name=None, group_parent=None, **kwargs): + sg = SettingsGroup(inherit_parent=self, group_parent=group_parent, name=name) for key, val in kwargs.items(): sg[key] = val return sg def new_child(self, name, *args, **kwargs): + assert name not in self sg = SettingsGroup(group_parent=self, name='%s.%s' % (self.name, name), *args, **kwargs) self[name] = sg return sg @@ -287,17 +288,17 @@ def parse_expander(fmt): z = y+1+offset return bits -def eval_expand_bit(bit, settings): - dep = eval(bit, settings.vals, settings.__dict__) +def eval_expand_bit(bit, settings, extra_vars={}): + dep = eval(bit, {}, settings.specialize(**extra_vars)) if isinstance(dep, Pending): dep = dep.resolve() return dep -def expand(fmt, settings): +def expand(fmt, settings, extra_vars={}): bits = parse_expander(fmt) - return ''.join((bit if isinstance(bit, basestring) else eval_expand_bit(bit[0], settings)) for bit in bits) + return ''.join((bit if isinstance(bit, basestring) else eval_expand_bit(bit[0], settings, extra_vars)) for bit in bits) -def expand_argv(argv, settings): +def expand_argv(argv, settings, extra_vars={}): if isinstance(argv, basestring): bits = parse_expander(argv) shell = ''.join(bit if isinstance(bit, basestring) else '(!)' for bit in bits) @@ -310,7 +311,7 @@ def expand_argv(argv, settings): for bit in arg.split('(!)'): if not first: code, should_shlex_result = codes.pop(0) - res = eval_expand_bit(code, settings) + res = eval_expand_bit(code, settings, extra_vars) res = shlex.split(res) if should_shlex_result else [res] out_argv[-1] += res[0] out_argv.extend(res[1:]) @@ -318,7 +319,7 @@ def expand_argv(argv, settings): out_argv[-1] += bit return out_argv else: - return [expand(arg, settings) for arg in argv] + return [expand(arg, settings, extra_vars) for arg in argv] def installation_dirs_group(sg): section = OptSection('Fine tuning of the installation directories:') @@ -361,13 +362,16 @@ def _make_argparse(include_unused, include_env): for opt in sect.opts: if not include(opt): continue + kw = opt.argparse_kw + if not opt.bool: + kw = kw.copy() + kw['type'] = opt.type + kw['metavar'] = opt.metavar ag.add_argument(opt.name, action='store_true' if opt.bool else 'store', dest=opt.name[2:], help=opt.help, - type=opt.type, - metavar=opt.metavar, - **opt.argparse_kw) + **kw) return parser def _print_help(include_unused=False): @@ -438,6 +442,7 @@ class Machine(object): def __init__(self, name, settings, triple_help, triple_default): self.name = name self.settings = settings + settings.new_child(name) def on_set(val): self.triple = Triple(val) if isinstance(triple_default, basestring): @@ -679,6 +684,7 @@ class XcodeToolchain(object): # Just a collection of common tools, plus flag options class CTools(object): def __init__(self, settings, machine, toolchains): + group = settings[machine.name] flags_section = OptSection('Compiler/linker flags (%s):' % (machine.name,)) tools_section = OptSection('Tool overrides (%s):' % (machine.name,)) @@ -708,10 +714,11 @@ class CTools(object): if machine.name != 'host': suff = '_FOR_' + to_upper_and_underscore(machine.name) suff += '=' - self.cflags_opt = settings.add_setting_option('cflags', 'CFLAGS'+suff, 'Flags for $CC', [], section=flags_section, type=shlex.split) - self.cxxflags_opt = settings.add_setting_option('cxxflags', 'CXXFLAGS'+suff, 'Flags for $CXX', [], section=flags_section, type=shlex.split) - self.ldflags_opt = settings.add_setting_option('ldflags', 'LDFLAGS'+suff, 'Flags for $CC/$CXX when linking', [], section=flags_section, type=shlex.split) - self.cppflags_opt = settings.add_setting_option('cppflags', 'CPPFLAGS'+suff, 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=flags_section, type=shlex.split) + self.cflags_opt = group.add_setting_option('cflags', 'CFLAGS'+suff, 'Flags for $CC', [], section=flags_section, type=shlex.split) + self.cxxflags_opt = group.add_setting_option('cxxflags', 'CXXFLAGS'+suff, 'Flags for $CXX', [], section=flags_section, type=shlex.split) + self.ldflags_opt = group.add_setting_option('ldflags', 'LDFLAGS'+suff, 'Flags for $CC/$CXX when linking', [], section=flags_section, type=shlex.split) + self.cppflags_opt = group.add_setting_option('cppflags', 'CPPFLAGS'+suff, 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=flags_section, type=shlex.split) + group.debug_info = False # A nicer - but optional - way of doing multiple tests that will print all the @@ -736,11 +743,27 @@ def clean_files(fns, settings): for fn in fns: if not os.path.exists(fn) or os.path.isdir(fn): continue - if not settings.allow_autoclean_outside_out and not within_dirtree(ro, os.path.realpath(fn)): + real_fn = os.path.realpath(fn) + if not settings.allow_autoclean_outside_out and not within_dirtree(ro, real_fn) and real_fn not in safe_to_clean: log("* Would clean %r as previous build leftover, but it isn't in settings.out (%r) so keeping it for safety.\n" % (fn, ro)) continue - config_log.write('Removing %r\n' % (fn,)) - os.remove(fn) + log('Removing %r\n' % (fn,)) + os.remove(real_fn) +def plan_clean_target(fns, settings): + ro = real_out() + actions = [] + for fn in fns: + real_fn = os.path.realpath(fn) + if not settings.allow_autoclean_outside_out and not within_dirtree(ro, real_fn) and real_fn not in safe_to_clean: + actions.append(('log', "* Would clean %r, but it isn't in settings.out (%r) so keeping it for safety." % (fn, ro))) + continue + actions.append(('remove', fn)) + return actions + +safe_to_clean = set() +def mark_safe_to_clean(fn, settings=None): + fn = expand(fn, settings) + safe_to_clean.add(os.path.realpath(fn)) def list_mconfig_scripts(settings): real_src = os.path.realpath(settings.src) @@ -773,6 +796,7 @@ def write_file_loudly(fn, data, perm=None): class Emitter(object): def __init__(self, settings): self.settings = settings + self.all_outs = set() def pre_output(self): assert not hasattr(self, 'did_output') self.did_output = True @@ -781,19 +805,22 @@ class Emitter(object): def filename_rel_and_escape(self, fn): fn = os.path.relpath(fn, dirname(self.settings.emit_fn)) return self.filename_escape(fn) - def add_command(self, settings, outs, ins, argvs, *args, **kwargs): + def add_command(self, settings, outs, ins, argvs, phony=False, *args, **kwargs): if kwargs.get('expand', True): - outs = [expand(x, settings) for x in outs] - ins = [expand(x, settings) for x in ins] - argvs = [expand_argv(x, settings) for x in argvs] + ev = {'raw_outs': outs, 'raw_ins': ins, 'raw_argvs': argvs} + outs = ev['outs'] = [expand(x, settings, ev) for x in outs] + ins = ev['ins'] = [expand(x, settings, ev) for x in ins] + argvs = [expand_argv(x, settings, ev) for x in argvs] if 'expand' in kwargs: del kwargs['expand'] - if settings.enable_rule_hashing: - sha = hashlib.sha1(json.dumps((outs, ins, argvs)).encode('utf-8')).hexdigest() - if sha not in prev_rule_hashes: - clean_files(outs, settings) - cur_rule_hashes.add(sha) - return self.add_command_raw(outs, ins, argvs, *args, **kwargs) + if not phony: + self.all_outs.update(outs) + if settings.enable_rule_hashing: + sha = hashlib.sha1(json.dumps((outs, ins, argvs)).encode('utf-8')).hexdigest() + if sha not in prev_rule_hashes: + clean_files(outs, settings) + cur_rule_hashes.add(sha) + return self.add_command_raw(outs, ins, argvs, phony, *args, **kwargs) def emit(self, fn=None): if fn is None: fn = self.settings.emit_fn @@ -812,13 +839,21 @@ class MakefileEmitter(Emitter): if self.main_mk is None: self.main_mk = lambda: os.path.join(dirname(settings.emit_fn), 'main.mk') - def add_all_and_clean(self): + def add_all(self): if hasattr(self, 'default_rule'): if self.default_rule != 'all': self.add_command_raw(['all'], [self.default_rule], [], phony=True) else: log('Warning: %r: no default rule\n' % (self,)) - self.makefile_bits.append('clean:\n\trm -rf %s\n' % (self.filename_rel_and_escape(self.settings.out))) + + def add_clean(self): + argvs = [] + for a, b in plan_clean_target(sorted(self.all_outs), self.settings): + if a == 'log': + argvs.append(['@echo', b]) + elif a == 'remove': + argvs.append(['rm', '-f', b]) + self.add_command_raw(['clean'], [], argvs, phony=True) @staticmethod def filename_escape(fn): @@ -846,7 +881,8 @@ class MakefileEmitter(Emitter): def output(self): self.pre_output() - self.add_all_and_clean() + self.add_all() + self.add_clean() return '\n'.join(self.makefile_bits) def emit(self): @@ -860,10 +896,10 @@ class MakefileEmitter(Emitter): # TODO is there something better than shell? # TODO avoid deleting partial output? stub = ''' - %(banner)s - _ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) - include %(main_mk)s - '''.lstrip() \ +%(banner)s +_ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) +include %(main_mk)s +'''.lstrip() \ % { 'makefile_arg': argv_to_shell([makefile]), 'main_mk_arg': argv_to_shell([main_mk]), @@ -985,6 +1021,14 @@ def emit_rule_hashes(): with open(rule_path, 'w') as fp: json.dump(list(cur_rule_hashes), fp) +def get_else_and(container, key, def_func, transform_func=lambda x: x): + try: + val = container[key] + except KeyError: + return def_func() + else: + return transform_func(val) + def default_is_cxx(filename): root, ext = os.path.splitext(filename) return ext in ('cc', 'cpp', 'cxx', 'mm') @@ -1014,23 +1058,25 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No any_was_cxx = False obj_fns = [] ldflag_sets = set() - _expand = globals()['expand'] - for fn in sources: - if expand: - fn = _expand(fn, settings) + if expand: + _expand = lambda x: globals()['expand'](x, settings) + _expand_argv = lambda x: expand_argv(x, settings) + else: + _expand = _expand_argv = lambda x: x + for fn in map(_expand, sources): my_settings = settings if settings_cb is not None: s = settings_cb(fn) if s is not None: my_settings = s - obj_fn = my_settings.get('override_obj_fn') or guess_obj_fn(fn, settings) - is_cxx = my_settings.get('override_is_cxx') - if is_cxx is None: - is_cxx = default_is_cxx(fn) - dbg = ['-g'] if my_settings.debug_info else [] - cflags = my_settings.cxxflags if is_cxx else my_settings.cflags - cc = my_settings.get('override_cc') or (tools.cxx if is_cxx else tools.cc).argv() - extra_deps = my_settings.get('extra_deps', []) + obj_fn = get_else_and(my_settings, 'override_obj_fn', lambda: guess_obj_fn(fn, settings), _expand) + is_cxx = get_else_and(my_settings, 'override_is_cxx', lambda: default_is_cxx(fn)) + includes = list(map(_expand, my_settings.get('c_includes', []))) + mach_settings = my_settings[machine.name] + dbg = ['-g'] if mach_settings.debug_info else [] + cflags = _expand_argv(get_else_and(my_settings, 'override_cflags', lambda: (mach_settings.cxxflags if is_cxx else mach_settings.cflags))) + cc = _expand_argv(get_else_and(my_settings, 'override_cc', lambda: (tools.cxx if is_cxx else tools.cc).argv())) + extra_deps = list(map(_expand, my_settings.get('extra_deps', []))) any_was_cxx = any_was_cxx or is_cxx dep_fn = os.path.splitext(obj_fn)[0] + '.d' @@ -1045,11 +1091,14 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No return obj_fns, any_was_cxx, ldflag_sets -def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): +def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[], ldflags_from_sets=[]): if expand: - _expand = globals()['expand'] - link_out = _expand(link_out, settings) - objs = [_expand(obj, settings) for obj in objs] + _expand = lambda x: globals()['expand'](x, settings) + _expand_argv = lambda x: expand_argv(x, settings) + link_out = _expand(link_out) + objs = list(map(_expand, objs)) + else: + _expand = _expand_argv = lambda x: x tools = machine.c_tools() assert link_type in ('exec', 'dylib', 'staticlib', 'obj') if link_type in ('exec', 'dylib'): @@ -1059,8 +1108,10 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with typeflag = ['-dynamiclib'] if machine.is_darwin() else ['-shared'] else: typeflag = [] - cmds = [cc_for_link + typeflag + settings.ldflags + extra_ldflags + ['-o', link_out] + objs] - if machine.is_darwin() and settings.debug_info: + mach_settings = settings[machine.name] + ldflags = get_else_and(settings, 'override_ldflags', lambda: mach_settings.ldflags, _expand_argv) + cmds = [cc_for_link + typeflag + ['-o', link_out] + objs + ldflags_from_sets + ldflags] + if machine.is_darwin() and mach_settings.debug_info: cmds.append(tools.dsymutil.argv() + [link_out]) elif link_type == 'staticlib': cmds = [tools.ar.argv() + ['rcs'] + objs] @@ -1071,8 +1122,8 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): more_objs, link_with_cxx, ldflag_sets = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) - extra_ldflags = [flag for lset in ldflag_sets for flag in lset] + extra_ldflags - link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps, extra_ldflags) + ldflags_from_sets = [flag for lset in ldflag_sets for flag in lset] + link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps, ldflags_from_sets) def guess_obj_fn(fn, settings): rel = os.path.relpath(fn, settings.src) @@ -1111,8 +1162,6 @@ settings_root.tool_search_paths = os.environ['PATH'].split(':') settings_root.src = dirname(sys.argv[0]) settings_root.out = os.path.join(os.getcwd(), 'out') -settings_root.debug_info = False - settings_root.enable_rule_hashing = True settings_root.allow_autoclean_outside_out = False post_parse_args_will_need.append(check_rule_hashes) -- cgit v1.2.3 From 69752843f1b6460ebb23584401661613d0b5bacf Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 7 Jul 2015 15:19:20 -0400 Subject: tests --- configure | 98 +++++++++++++++++++++++++++++++++++++++++------- lib/jump-dis.c | 4 ++ script/gen-inject-asm.sh | 19 +++++----- script/mconfig.py | 15 +++++--- 4 files changed, 108 insertions(+), 28 deletions(-) diff --git a/configure b/configure index cfc2f70..61ebf00 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #!/usr/bin/env python -import sys, os +import sys, os, glob sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'script')) import mconfig settings = mconfig.settings_root @@ -12,6 +12,7 @@ c.dsymutil.required() settings.add_setting_option('imaon2', '--with-imaon2', 'path to imaon2 (optional)', '') settings.add_setting_option('gen_dia', '--enable-recompile-dia', 'generate darwin-inject-asm.S', False, bool=True) +settings.add_setting_option('enable_tests', '--enable-tests', 'tests!', False, bool=True) asm_archs = [ ('x86_64', []), @@ -20,6 +21,8 @@ asm_archs = [ ('arm64', []), # XXX ] +asm_cflags = ['-Os', '-fno-stack-protector', '-isysroot', '/dev/null', '-fPIC'] +asm_ldflags = ['-nostartfiles', '-nodefaultlibs'] machs = [] for name, cflags in asm_archs: mach = mconfig.Machine('asm-' + name, settings, 'for cross-compiling the inject baton', name + '-apple-darwin10') @@ -30,7 +33,8 @@ for name, cflags in asm_archs: if settings.gen_dia: cc.argv() mach_settings = settings[mach.name] - mach_settings.cflags = cflags + mach_settings.cflags + mach_settings.cflags = cflags + asm_cflags + mach_settings.cflags + mach_settings.ldflags = asm_ldflags + mach_settings.ldflags mconfig.post_parse_args_will_need.append(f) @@ -38,13 +42,11 @@ mconfig.parse_args() #################################### mconfig.mark_safe_to_clean('(src)/generated/darwin-inject-asm.S', settings) -settings.host.cflags = ['-I%s/lib' % (settings.src,)] + settings.host.cflags settings.host.debug_info = True +settings.c_includes = ['(src)/lib', '(src)/substrate'] emitter = settings.emitter -balco = lambda *args, **kwargs: mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, *args, **kwargs) - def cb(fn): if fn.endswith('/objc.c'): return settings.specialize(obj_ldflag_sets=[('-lobjc',)]) @@ -59,7 +61,8 @@ def cb(fn): # (This only matters on 32-bit ARM, and the text segment is currently 0xa000 # bytes there, more than enough.) -balco( +mconfig.build_and_link_c_objs( + emitter, settings.host_machine(), settings, 'dylib', '(out)/libsubstitute.dylib', [ @@ -82,8 +85,13 @@ balco( ) #settings.test = 'foo baz' +def o_to_bin(exe): + bin = os.path.splitext(exe)[0] + '.bin' + emitter.add_command(settings, [bin], [exe], ['segedit -extract __TEXT __text (outs[0]) (ins[0])']) + return bin + if settings.gen_dia: - bins = [] + args = [] for (name, _cflags), mach in zip(asm_archs, machs): exe = '(out)/inject-asm-raw-%s' % (name,) bin = exe + '.bin' @@ -92,15 +100,77 @@ if settings.gen_dia: override_obj_fn='(out)/inject-asm-raw-%s.o' % (name,), override_ldflags=['-Wl,-order_file,(src)/lib/darwin/inject-asm-raw.order'] + settings[mach.name].ldflags, ), - 'exec', + 'dylib', exe, ['(src)/lib/darwin/inject-asm-raw.c']) - bins.append(bin) - emitter.add_command(settings, [bin], [exe], ['segedit -extract __TEXT __text (outs[0]) (ins[0])']) - emitter.add_command(settings, ['(src)/generated/darwin-inject-asm.S'], bins, [['(src)/script/gen-inject-asm.sh', '(out)'] + bins]) - -emitter.add_command(settings, ['all'], ['(out)/libsubstitute.dylib'], [], phony=True) + bin = o_to_bin(exe) + args.extend([name, bin]) + emitter.add_command(settings, ['(src)/generated/darwin-inject-asm.S'], ['(src)/script/gen-inject-asm.sh'] + args[1::2], [['(src)/script/gen-inject-asm.sh', '(outs[0])'] + args]) + +all_deps = ['(out)/libsubstitute.dylib'] + +if settings.enable_tests: + # just for quick testing + for ofile, sfile, cflags, mach in [ + ('insns-arm.o', 'insns-arm.S', [], machs[2]), + ('insns-thumb2.o', 'insns-arm.S', ['-DTHUMB2'], machs[2]), + ('insns-libz-arm.o', 'insns-libz-arm.S', [], machs[2]), + ('insns-libz-thumb2.o', 'insns-libz-arm.S', ['-DTHUMB2'], machs[2]), + ('transform-dis-cases-arm64.o', 'transform-dis-cases-arm64.S', [], machs[3]), + ('transform-dis-cases-i386.o', 'transform-dis-cases-i386.S', [], machs[1]), + ('transform-dis-cases-x86_64.o', 'transform-dis-cases-x86_64.S', [], machs[0]), + ]: + mconfig.build_c_objs(emitter, mach, settings.specialize(override_obj_fn='(out)/'+ofile), ['(src)/test/'+sfile]) + all_deps.append(o_to_bin('(out)/'+ofile)) + + tests = [ + ('find-syms', ['-std=c89']), + ('find-syms-cpp', 'find-syms', ['-x', 'c++', '-std=c++98'], {'cpp': True}), + ('substrate', ['-x', 'c++', '-std=c++98'], {'cpp': True}), + ('imp-forwarding', [], ['-framework', 'Foundation', '-lobjc']), + ('objc-hook', [], ['-framework', 'Foundation']), + ('interpose',), + ('inject', {'extra_objs': ['(out)/lib/darwin/inject.o', '(out)/lib/darwin/read.o']}), + ('pc-patch', {'extra_objs': ['(out)/lib/darwin/execmem.o']}), + ('execmem', [], ['-segprot', '__TEST', 'rwx', 'rx'], {'extra_objs': ['(out)/lib/darwin/execmem.o']}), + ('hook-functions', [], ['-segprot', '__TEST', 'rwx', 'rx']), + ('posixspawn-hook',), + ('htab',), + ('vec', {'cpp': True, 'extra_objs': ['(out)/lib/cbit/vec.o']}), + ] + + for arch, hdr, xdis, target in [ + ('arm', 'arm/dis-arm.inc.h', 'dis_arm', 'arm'), + ('thumb', 'arm/dis-thumb.inc.h', 'dis_thumb', 'arm'), + ('thumb2', 'arm/dis-thumb2.inc.h', 'dis_thumb2', 'arm'), + ('arm64', 'arm64/dis-main.inc.h', 'dis', 'arm64'), + ('i386', 'x86/dis-main.inc.h', 'dis', 'i386'), + ('x86_64', 'x86/dis-main.inc.h', 'dis', 'x86_64') + ]: + tests.append(('td-simple-'+arch, 'td-simple', ['-DHDR="%s"' % (hdr,), '-Dxdis='+xdis, '-DFORCE_TARGET_'+target])) + tests.append(('jump-dis-'+arch, 'jump-dis', ['-O0', '-DFORCE_TARGET_'+target], {'extra_objs': ['(out)/lib/cbit/vec.o']})) + tests.append(('transform-dis-'+arch, 'transform-dis', ['-O0', '-DFORCE_TARGET_'+target], {'extra_objs': ['(out)/lib/cbit/vec.o']})) + + for tup in tests: + tup = list(tup) + ibase = obase = tup.pop(0) + cflags = ldflags = [] + options = {} + if tup and isinstance(tup[0], basestring): ibase = tup.pop(0) + if tup and isinstance(tup[0], (list, tuple)): cflags = tup.pop(0) + if tup and isinstance(tup[0], (list, tuple)): ldflags = tup.pop(0) + if tup: options, = tup + o = '(out)/test-'+obase + cfile = glob.glob(settings.src+'/test/test-'+ibase+'.*')[0] + mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings.specialize( + override_cflags=cflags+settings.host.cflags, + override_ldflags=ldflags+['-L(out)', '-lsubstitute']+settings.host.ldflags, + override_obj_fn=o+'.o', + override_is_cxx=options.get('cxx', False), + ), 'exec', o, [cfile], objs=options.get('extra_objs', [])) + all_deps.append(o) + +emitter.add_command(settings, ['all'], all_deps, [], phony=True) emitter.set_default_rule('all') - mconfig.finish_and_emit() diff --git a/lib/jump-dis.c b/lib/jump-dis.c index 13845f5..f909cc7 100644 --- a/lib/jump-dis.c +++ b/lib/jump-dis.c @@ -140,7 +140,11 @@ bool jump_dis_main(void *code_ptr, uint_tptr pc_patch_start, uint_tptr pc_patch_ #ifdef JUMP_DIS_VERBOSE printf("jump-dis: pc=%llx op=%08x size=%x bad=%d continue_after=%d\n", (unsigned long long) ctx.base.pc, +#if defined(TARGET_x86_64) || defined(TARGET_i386) + 0, +#else ctx.base.op, +#endif ctx.base.op_size, ctx.bad_insn, ctx.continue_after_this_insn); diff --git a/script/gen-inject-asm.sh b/script/gen-inject-asm.sh index 161bbe7..633a1a5 100755 --- a/script/gen-inject-asm.sh +++ b/script/gen-inject-asm.sh @@ -1,5 +1,7 @@ #!/bin/sh -cat < "$outfile" diff --git a/script/mconfig.py b/script/mconfig.py index f056c10..e009675 100644 --- a/script/mconfig.py +++ b/script/mconfig.py @@ -30,7 +30,7 @@ def to_upper_and_underscore(s): def argv_to_shell(argv): quoteds = [] for arg in argv: - if re.match('^[a-zA-Z0-9_\.@/+=-]+$', arg): + if re.match('^[a-zA-Z0-9_\.@/+=,-]+$', arg): quoteds.append(arg) else: quoted = '' @@ -1071,7 +1071,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No my_settings = s obj_fn = get_else_and(my_settings, 'override_obj_fn', lambda: guess_obj_fn(fn, settings), _expand) is_cxx = get_else_and(my_settings, 'override_is_cxx', lambda: default_is_cxx(fn)) - includes = list(map(_expand, my_settings.get('c_includes', []))) + include_args = ['-I'+_expand(inc) for inc in my_settings.c_includes] mach_settings = my_settings[machine.name] dbg = ['-g'] if mach_settings.debug_info else [] cflags = _expand_argv(get_else_and(my_settings, 'override_cflags', lambda: (mach_settings.cxxflags if is_cxx else mach_settings.cflags))) @@ -1081,9 +1081,11 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No dep_fn = os.path.splitext(obj_fn)[0] + '.d' mkdir_cmd = ['mkdir', '-p', dirname(obj_fn)] - cmd = cc + dbg + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] + cmd = cc + dbg + include_args + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] - emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, [mkdir_cmd, cmd], depfile=('makefile', dep_fn), expand=False) + cmds = [mkdir_cmd, cmd] + cmds = settings.get('modify_compile_commands', lambda x: x)(cmds) + emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, cmds, depfile=('makefile', dep_fn), expand=False) for lset in my_settings.get('obj_ldflag_sets', ()): ldflag_sets.add(tuple(lset)) @@ -1103,7 +1105,7 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with assert link_type in ('exec', 'dylib', 'staticlib', 'obj') if link_type in ('exec', 'dylib'): assert link_with_cxx in (False, True) - cc_for_link = (tools.cxx if link_with_cxx else tools.cc).argv() + cc_for_link = _expand_argv(get_else_and(settings, 'override_ld', lambda: (tools.cxx if link_with_cxx else tools.cc).argv())) if link_type == 'dylib': typeflag = ['-dynamiclib'] if machine.is_darwin() else ['-shared'] else: @@ -1118,6 +1120,7 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with elif link_type == 'obj': cmds = [tools.cc.argv() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs] cmds.insert(0, ['mkdir', '-p', dirname(link_out)]) + cmds = settings.get('modify_link_commands', lambda x: x)(cmds) emitter.add_command(settings, [link_out], objs + extra_deps, cmds, expand=False) def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): @@ -1167,6 +1170,8 @@ settings_root.allow_autoclean_outside_out = False post_parse_args_will_need.append(check_rule_hashes) settings_root.auto_rerun_config = True +settings_root.c_includes = [] + emitters = { 'makefile': MakefileEmitter, 'ninja': NinjaEmitter, -- cgit v1.2.3 From 5162bf232ed5e24a34c5de9796b35f7a133eb399 Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 7 Jul 2015 15:47:33 -0400 Subject: build more stuff - need ldid and arguably dsym fixup --- configure | 46 +++++++++++++++++++++++++++++++++++++++------- script/mconfig.py | 15 ++++++++++----- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/configure b/configure index 61ebf00..524fe0e 100755 --- a/configure +++ b/configure @@ -13,6 +13,9 @@ c.dsymutil.required() settings.add_setting_option('imaon2', '--with-imaon2', 'path to imaon2 (optional)', '') settings.add_setting_option('gen_dia', '--enable-recompile-dia', 'generate darwin-inject-asm.S', False, bool=True) settings.add_setting_option('enable_tests', '--enable-tests', 'tests!', False, bool=True) +settings.add_setting_option('enable_ios_bootstrap', '--enable-ios-bootstrap', 'default: true if you pass --xcode-sdk=iphoneos', + lambda: 'iphoneos' in str(settings.host_machine().toolchains()[0].sdk_opt.value), + bool=True) asm_archs = [ ('x86_64', []), @@ -42,6 +45,9 @@ mconfig.parse_args() #################################### mconfig.mark_safe_to_clean('(src)/generated/darwin-inject-asm.S', settings) +if settings.enable_ios_bootstrap: + mconfig.log('Will build iOS bootstrap.\n') + settings.host.debug_info = True settings.c_includes = ['(src)/lib', '(src)/substrate'] @@ -107,8 +113,6 @@ if settings.gen_dia: args.extend([name, bin]) emitter.add_command(settings, ['(src)/generated/darwin-inject-asm.S'], ['(src)/script/gen-inject-asm.sh'] + args[1::2], [['(src)/script/gen-inject-asm.sh', '(outs[0])'] + args]) -all_deps = ['(out)/libsubstitute.dylib'] - if settings.enable_tests: # just for quick testing for ofile, sfile, cflags, mach in [ @@ -121,7 +125,7 @@ if settings.enable_tests: ('transform-dis-cases-x86_64.o', 'transform-dis-cases-x86_64.S', [], machs[0]), ]: mconfig.build_c_objs(emitter, mach, settings.specialize(override_obj_fn='(out)/'+ofile), ['(src)/test/'+sfile]) - all_deps.append(o_to_bin('(out)/'+ofile)) + o_to_bin('(out)/'+ofile) tests = [ ('find-syms', ['-std=c89']), @@ -164,13 +168,41 @@ if settings.enable_tests: cfile = glob.glob(settings.src+'/test/test-'+ibase+'.*')[0] mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings.specialize( override_cflags=cflags+settings.host.cflags, - override_ldflags=ldflags+['-L(out)', '-lsubstitute']+settings.host.ldflags, + override_ldflags=ldflags+settings.host.ldflags, override_obj_fn=o+'.o', override_is_cxx=options.get('cxx', False), - ), 'exec', o, [cfile], objs=options.get('extra_objs', [])) - all_deps.append(o) + ), 'exec', o, [cfile], objs=options.get('extra_objs', [])+['(out)/libsubstitute.dylib']) + + mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, 'dylib', '(out)/injected-test-dylib.dylib', ['(src)/test/injected-test-dylib.c']) + +if settings.enable_ios_bootstrap: + mconfig.build_and_link_c_objs(emitter, settings.host_machine(), + settings.specialize( + override_cflags=['-fobjc-arc', '-Wno-unused-parameter']+settings.host.cflags, + override_ldflags=['-framework', 'UIKit', '-framework', 'Foundation', '-dead_strip']+settings.host.ldflags, + ), + 'exec', + '(out)/safety-dance/SafetyDance.app/SafetyDance', + [ + '(src)/darwin-bootstrap/safety-dance/AutoGrid.m', + '(src)/darwin-bootstrap/safety-dance/main.m', + ] + ) + emitter.add_command(settings, ['(out)/safety-dance/SafetyDance.app/Info.plist'], ['(src)/darwin-bootstrap/safety-dance/Info.plist'], ['plutil -convert binary1 -o (outs[0]) (ins[0])']) + for out in ['Default.png', 'Default@2x.png']: + emitter.add_command(settings, ['(out)/safety-dance/SafetyDance.app/'+out], ['(src)/darwin-bootstrap/safety-dance/white.png'], ['cp (ins[0]) (outs[0])']) + + ls = ['(out)/libsubstitute.dylib'] + for ty, out, ins, objs, ldf, cf in [ + ('dylib', '(out)/posixspawn-hook.dylib', ['(src)/darwin-bootstrap/posixspawn-hook.c'], ls, [], []), + ('dylib', '(out)/bundle-loader.dylib', ['(src)/darwin-bootstrap/bundle-loader.c'], [], [], []), + ('exec', '(out)/unrestrict', ['(src)/darwin-bootstrap/unrestrict.c'], ls, [], []), + ('exec', '(out)/inject-into-launchd', ['(src)/darwin-bootstrap/inject-into-launchd.c'], ls, ['-framework', 'IOKit', '-framework', 'CoreFoundation'], []), + ('exec', '(out)/substituted', ['(src)/darwin-bootstrap/substituted.c', '(src)/darwin-bootstrap/substituted-plist-loader.m'], [], ['-lbsm', '-framework', 'Foundation', '-framework', 'CoreFoundation'], ['-fobjc-arc']), + ]: + mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings.specialize(override_ldflags=ldf+settings.host.ldflags, override_cflags=cf+settings.host.cflags), ty, out, ins, objs=objs) -emitter.add_command(settings, ['all'], all_deps, [], phony=True) +emitter.add_command(settings, ['all'], list(emitter.all_outs), [], phony=True) emitter.set_default_rule('all') mconfig.finish_and_emit() diff --git a/script/mconfig.py b/script/mconfig.py index e009675..aa84df8 100644 --- a/script/mconfig.py +++ b/script/mconfig.py @@ -257,7 +257,7 @@ class Option(object): if not self.show: # If you didn't mention the option in help, you don't get no stinking value. This is for ignored options only. return - if value is None: + if value is (False if self.bool else None): value = self.default if callable(value): # Pending value = value() @@ -507,9 +507,15 @@ class CLITool(object): def optional(self): self.argv_opt.need() + def f(): + try: + self.argv() + except DependencyNotFoundException: + pass + post_parse_args_will_need.append(f) def required(self): - self.optional() + self.argv_opt.need() post_parse_args_will_need.append(lambda: self.argv()) def argv(self): # mem @@ -673,7 +679,7 @@ class XcodeToolchain(object): def find_tool(self, tool, failure_notes): if not self.ok: return None - argv = ['/usr/bin/xcrun', '--sdk', self.sdk, tool.name] + self.arch_flags() + argv = ['/usr/bin/xcrun', '--sdk', self.sdk, tool.name] + ([] if tool.name == 'dsymutil' else self.arch_flags()) sod, sed, code = run_command(argv + ['--asdf']) if code != 0: if sed.startswith('xcrun: error: unable to find utility'): @@ -1052,8 +1058,6 @@ def default_is_cxx(filename): # force_cli: don't use IDEs' native C/C++ compilation mechanism # expand: call expand on filenames def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=None, force_cli=False, expand=True): - if expand: - headers = [expand(header, settings) for header in headers] tools = machine.c_tools() any_was_cxx = False obj_fns = [] @@ -1063,6 +1067,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No _expand_argv = lambda x: expand_argv(x, settings) else: _expand = _expand_argv = lambda x: x + headers = list(map(_expand, headers)) for fn in map(_expand, sources): my_settings = settings if settings_cb is not None: -- cgit v1.2.3 From 83d0dcdb986320041301425e4db1a016434a52b8 Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 7 Jul 2015 16:08:26 -0400 Subject: ldid --- configure | 10 ++++++++++ script/mconfig.py | 40 +++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/configure b/configure index 524fe0e..e8c5b15 100755 --- a/configure +++ b/configure @@ -17,6 +17,9 @@ settings.add_setting_option('enable_ios_bootstrap', '--enable-ios-bootstrap', 'd lambda: 'iphoneos' in str(settings.host_machine().toolchains()[0].sdk_opt.value), bool=True) +ldid_tool = mconfig.CLITool('ldid', ['ldid'], 'LDID', settings.host_machine(), settings.host_machine().toolchains()) +ldid_tool.optional() + asm_archs = [ ('x86_64', []), ('i386', []), @@ -48,6 +51,13 @@ mconfig.mark_safe_to_clean('(src)/generated/darwin-inject-asm.S', settings) if settings.enable_ios_bootstrap: mconfig.log('Will build iOS bootstrap.\n') + +# todo make overridable? +cc_argv = c.cc.argv() +if 'armv7' in cc_argv or 'arm64' in cc_argv: + settings.modify_link_commands = lambda cmds, env: cmds + [ldid_tool.argv() + ['-S'+settings.src+'/ent.plist', env['link_out']]] + settings.extra_link_deps = ['(src)/ent.plist'] + settings.host.debug_info = True settings.c_includes = ['(src)/lib', '(src)/substrate'] diff --git a/script/mconfig.py b/script/mconfig.py index aa84df8..26556d6 100644 --- a/script/mconfig.py +++ b/script/mconfig.py @@ -452,6 +452,8 @@ class Machine(object): self.toolchains = memoize(self.toolchains) self.c_tools = memoize(self.c_tools) + self.flags_section = OptSection('Compiler/linker flags (%s):' % (self.name,)) + self.tools_section = OptSection('Tool overrides (%s):' % (self.name,)) def __eq__(self, other): return self.triple == other.triple @@ -488,6 +490,8 @@ class Machine(object): class CLITool(object): def __init__(self, name, defaults, env, machine, toolchains, dont_suffix_env=False, section=None): + if section is None: + section = machine.tools_section self.name = name self.defaults = defaults self.env = env @@ -679,20 +683,19 @@ class XcodeToolchain(object): def find_tool(self, tool, failure_notes): if not self.ok: return None - argv = ['/usr/bin/xcrun', '--sdk', self.sdk, tool.name] + ([] if tool.name == 'dsymutil' else self.arch_flags()) - sod, sed, code = run_command(argv + ['--asdf']) + arch_flags = self.arch_flags() if tool.name in {'cc', 'cxx', 'nm'} else [] + argv = ['/usr/bin/xcrun', '--sdk', self.sdk, tool.name] + arch_flags + sod, sed, code = run_command(['/usr/bin/xcrun', '--sdk', self.sdk, '-f', tool.name]) if code != 0: - if sed.startswith('xcrun: error: unable to find utility'): - failure_notes.append(sed) - return None + failure_notes.append(sed) + return None + # note: we can't just use the found path because xcrun sets some env magic return argv # Just a collection of common tools, plus flag options class CTools(object): def __init__(self, settings, machine, toolchains): group = settings[machine.name] - flags_section = OptSection('Compiler/linker flags (%s):' % (machine.name,)) - tools_section = OptSection('Tool overrides (%s):' % (machine.name,)) tools = [ ('cc', ['cc', 'gcc', 'clang'], 'CC'), @@ -713,17 +716,17 @@ class CTools(object): name, defaults, env = spec[0], [spec[0]], spec[0].upper() else: name, defaults, env = spec - tool = CLITool(name, defaults, env, machine, toolchains, section=tools_section) + tool = CLITool(name, defaults, env, machine, toolchains) setattr(self, name, tool) suff = '' if machine.name != 'host': suff = '_FOR_' + to_upper_and_underscore(machine.name) suff += '=' - self.cflags_opt = group.add_setting_option('cflags', 'CFLAGS'+suff, 'Flags for $CC', [], section=flags_section, type=shlex.split) - self.cxxflags_opt = group.add_setting_option('cxxflags', 'CXXFLAGS'+suff, 'Flags for $CXX', [], section=flags_section, type=shlex.split) - self.ldflags_opt = group.add_setting_option('ldflags', 'LDFLAGS'+suff, 'Flags for $CC/$CXX when linking', [], section=flags_section, type=shlex.split) - self.cppflags_opt = group.add_setting_option('cppflags', 'CPPFLAGS'+suff, 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=flags_section, type=shlex.split) + self.cflags_opt = group.add_setting_option('cflags', 'CFLAGS'+suff, 'Flags for $CC', [], section=machine.flags_section, type=shlex.split) + self.cxxflags_opt = group.add_setting_option('cxxflags', 'CXXFLAGS'+suff, 'Flags for $CXX', [], section=machine.flags_section, type=shlex.split) + self.ldflags_opt = group.add_setting_option('ldflags', 'LDFLAGS'+suff, 'Flags for $CC/$CXX when linking', [], section=machine.flags_section, type=shlex.split) + self.cppflags_opt = group.add_setting_option('cppflags', 'CPPFLAGS'+suff, 'Flags for $CC/$CXX when not linking (supposed to be used for preprocessor flags)', [], section=machine.flags_section, type=shlex.split) group.debug_info = False @@ -1067,6 +1070,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No _expand_argv = lambda x: expand_argv(x, settings) else: _expand = _expand_argv = lambda x: x + env = {} # todo: ... headers = list(map(_expand, headers)) for fn in map(_expand, sources): my_settings = settings @@ -1081,7 +1085,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No dbg = ['-g'] if mach_settings.debug_info else [] cflags = _expand_argv(get_else_and(my_settings, 'override_cflags', lambda: (mach_settings.cxxflags if is_cxx else mach_settings.cflags))) cc = _expand_argv(get_else_and(my_settings, 'override_cc', lambda: (tools.cxx if is_cxx else tools.cc).argv())) - extra_deps = list(map(_expand, my_settings.get('extra_deps', []))) + extra_deps = list(map(_expand, my_settings.get('extra_compile_deps', []))) any_was_cxx = any_was_cxx or is_cxx dep_fn = os.path.splitext(obj_fn)[0] + '.d' @@ -1089,7 +1093,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No cmd = cc + dbg + include_args + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn] cmds = [mkdir_cmd, cmd] - cmds = settings.get('modify_compile_commands', lambda x: x)(cmds) + cmds = settings.get('modify_compile_commands', lambda x, env: x)(cmds, env) emitter.add_command(my_settings, [obj_fn], [fn] + extra_deps, cmds, depfile=('makefile', dep_fn), expand=False) for lset in my_settings.get('obj_ldflag_sets', ()): @@ -1098,7 +1102,7 @@ def build_c_objs(emitter, machine, settings, sources, headers=[], settings_cb=No return obj_fns, any_was_cxx, ldflag_sets -def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, extra_deps=[], ldflags_from_sets=[]): +def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with_cxx=None, force_cli=False, expand=True, ldflags_from_sets=[]): if expand: _expand = lambda x: globals()['expand'](x, settings) _expand_argv = lambda x: expand_argv(x, settings) @@ -1106,6 +1110,7 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with objs = list(map(_expand, objs)) else: _expand = _expand_argv = lambda x: x + env = {'link_out': link_out} # todo: ... tools = machine.c_tools() assert link_type in ('exec', 'dylib', 'staticlib', 'obj') if link_type in ('exec', 'dylib'): @@ -1125,13 +1130,14 @@ def link_c_objs(emitter, machine, settings, link_type, link_out, objs, link_with elif link_type == 'obj': cmds = [tools.cc.argv() + ['-Wl,-r', '-nostdlib', '-o', link_out] + objs] cmds.insert(0, ['mkdir', '-p', dirname(link_out)]) - cmds = settings.get('modify_link_commands', lambda x: x)(cmds) + cmds = settings.get('modify_link_commands', lambda x, env: x)(cmds, env) + extra_deps = list(map(_expand, settings.get('extra_link_deps', []))) emitter.add_command(settings, [link_out], objs + extra_deps, cmds, expand=False) def build_and_link_c_objs(emitter, machine, settings, link_type, link_out, sources, headers=[], objs=[], settings_cb=None, force_cli=False, expand=True, extra_deps=[], extra_ldflags=[]): more_objs, link_with_cxx, ldflag_sets = build_c_objs(emitter, machine, settings, sources, headers, settings_cb, force_cli, expand) ldflags_from_sets = [flag for lset in ldflag_sets for flag in lset] - link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, extra_deps, ldflags_from_sets) + link_c_objs(emitter, machine, settings, link_type, link_out, objs + more_objs, link_with_cxx, force_cli, expand, ldflags_from_sets) def guess_obj_fn(fn, settings): rel = os.path.relpath(fn, settings.src) -- cgit v1.2.3 From 71ab294102f551e83deaef702ccec7a2b0864017 Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 7 Jul 2015 16:10:00 -0400 Subject: commit new compiled version of darwin-inject-asm so i don't go crazy... --- generated/darwin-inject-asm.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/generated/darwin-inject-asm.S b/generated/darwin-inject-asm.S index 0f1620e..9d551fb 100644 --- a/generated/darwin-inject-asm.S +++ b/generated/darwin-inject-asm.S @@ -13,16 +13,16 @@ _inject_page_start: .align 2 .globl _inject_start_x86_64 _inject_start_x86_64: -.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x48, 0x89, 0xe5, 0x53, 0x50, 0x48, 0x89, 0xfb, 0xc7, 0x45, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x15, 0x4f, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x7d, 0xf4, 0x31, 0xf6, 0x48, 0x89, 0xd9, 0xff, 0x13, 0x8b, 0x7d, 0xf4, 0xff, 0x53, 0x08, 0x8b, 0x4b, 0x30, 0x31, 0xff, 0x31, 0xf6, 0x31, 0xd2, 0xe8, 0x14, 0x00, 0x00, 0x00, 0xb9, 0xad, 0x0b, 0x00, 0x00, 0x31, 0xc0, 0xff, 0xd1, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0x5d, 0xc3, 0x90, 0x90, 0x90, 0x90, 0xb8, 0x69, 0x01, 0x00, 0x02, 0x49, 0x89, 0xca, 0x0f, 0x05, 0xc3, 0xb8, 0x24, 0x00, 0x00, 0x01, 0x49, 0x89, 0xca, 0x0f, 0x05, 0xc3, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x55, 0x48, 0x89, 0xe5, 0x53, 0x50, 0x48, 0x89, 0xfb, 0x48, 0x8b, 0x7b, 0x28, 0x31, 0xf6, 0xff, 0x53, 0x10, 0x48, 0x85, 0xc0, 0x74, 0x1c, 0x48, 0x8d, 0x35, 0x46, 0x00, 0x00, 0x00, 0x48, 0x89, 0xc7, 0xff, 0x53, 0x18, 0x48, 0x85, 0xc0, 0x74, 0x0a, 0x48, 0x8d, 0x7b, 0x40, 0x48, 0x8b, 0x73, 0x38, 0xff, 0xd0, 0x8b, 0x7b, 0x30, 0xe8, 0xb4, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x43, 0x20, 0x48, 0x81, 0xe3, 0x00, 0xf0, 0xff, 0xff, 0xbe, 0x00, 0x20, 0x00, 0x00, 0x48, 0x89, 0xdf, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0x5d, 0xff, 0xe0, 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 +.byte 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x30, 0x48, 0x8d, 0x45, 0xf4, 0x31, 0xc9, 0x89, 0xce, 0x48, 0x8d, 0x15, 0x99, 0x00, 0x00, 0x00, 0x48, 0x89, 0x7d, 0xf8, 0xc7, 0x45, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x7d, 0xf8, 0x48, 0x8b, 0x3f, 0x4c, 0x8b, 0x45, 0xf8, 0x48, 0x89, 0x7d, 0xe8, 0x48, 0x89, 0xc7, 0x4c, 0x89, 0xc1, 0x48, 0x8b, 0x45, 0xe8, 0xff, 0xd0, 0x48, 0x8b, 0x4d, 0xf8, 0x48, 0x8b, 0x49, 0x08, 0x8b, 0x7d, 0xf4, 0x89, 0x45, 0xe4, 0xff, 0xd1, 0x31, 0xff, 0x89, 0xf9, 0x31, 0xd2, 0x48, 0x8b, 0x75, 0xf8, 0x48, 0x8b, 0x76, 0x30, 0x89, 0xf7, 0x89, 0x7d, 0xe0, 0x48, 0x89, 0xcf, 0x48, 0x89, 0xce, 0x8b, 0x4d, 0xe0, 0x89, 0x45, 0xdc, 0xe8, 0x1f, 0x00, 0x00, 0x00, 0xb9, 0xad, 0x0b, 0x00, 0x00, 0x89, 0xce, 0x89, 0x45, 0xd8, 0xb0, 0x00, 0xff, 0xd6, 0x48, 0x83, 0xc4, 0x30, 0x5d, 0xc3, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x69, 0x01, 0x00, 0x02, 0x49, 0x89, 0xca, 0x0f, 0x05, 0xc3, 0xb8, 0x24, 0x00, 0x00, 0x01, 0x49, 0x89, 0xca, 0x0f, 0x05, 0xc3, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x40, 0x31, 0xf6, 0x48, 0x89, 0x7d, 0xf8, 0x48, 0x8b, 0x7d, 0xf8, 0x48, 0x89, 0x7d, 0xf0, 0x48, 0x8b, 0x7d, 0xf0, 0x48, 0x8b, 0x7f, 0x10, 0x48, 0x8b, 0x45, 0xf0, 0x48, 0x8b, 0x40, 0x28, 0x48, 0x89, 0x7d, 0xd0, 0x48, 0x89, 0xc7, 0x48, 0x8b, 0x45, 0xd0, 0xff, 0xd0, 0x48, 0x89, 0x45, 0xe8, 0x48, 0x81, 0x7d, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x84, 0x48, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x35, 0x84, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x45, 0xf0, 0x48, 0x8b, 0x40, 0x18, 0x48, 0x8b, 0x7d, 0xe8, 0xff, 0xd0, 0x48, 0x89, 0x45, 0xe0, 0x48, 0x81, 0x7d, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x84, 0x1c, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x45, 0xe0, 0x48, 0x8b, 0x4d, 0xf0, 0x48, 0x81, 0xc1, 0x40, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x72, 0x38, 0x48, 0x89, 0xcf, 0xff, 0xd0, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x45, 0xf0, 0x48, 0x8b, 0x40, 0x30, 0x89, 0xc1, 0x89, 0xcf, 0xe8, 0x4d, 0xff, 0xff, 0xff, 0xb9, 0x00, 0x20, 0x00, 0x00, 0x89, 0xce, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x81, 0xe2, 0x00, 0xf0, 0xff, 0xff, 0x48, 0x89, 0x55, 0xd8, 0x48, 0x8b, 0x55, 0xf0, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x7d, 0xd8, 0x89, 0x45, 0xcc, 0xff, 0xd2, 0x48, 0x83, 0xc4, 0x40, 0x5d, 0xc3, 0x0f, 0x1f, 0x44, 0x00, 0x00, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 .align 2 .globl _inject_start_i386 _inject_start_i386: -.byte 0x55, 0x89, 0xe5, 0x56, 0x83, 0xec, 0x14, 0x89, 0xce, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0xc7, 0x45, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x89, 0x74, 0x24, 0x0c, 0x8d, 0x80, 0xb0, 0x00, 0x00, 0x00, 0x89, 0x44, 0x24, 0x08, 0x8d, 0x45, 0xf8, 0x89, 0x04, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0x16, 0x8b, 0x45, 0xf8, 0x89, 0x04, 0x24, 0xff, 0x56, 0x04, 0x8b, 0x46, 0x18, 0x89, 0x44, 0x24, 0x0c, 0xc7, 0x44, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x00, 0x00, 0xb8, 0xad, 0x0b, 0x00, 0x00, 0xff, 0xd0, 0x83, 0xc4, 0x14, 0x5e, 0x5d, 0xc3, 0xb8, 0x69, 0x01, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x0b, 0x00, 0x00, 0x00, 0x89, 0xe1, 0x0f, 0x34, 0xc3, 0xb8, 0xdc, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x0b, 0x00, 0x00, 0x00, 0x89, 0xe1, 0x0f, 0x34, 0xc3, 0x55, 0x89, 0xe5, 0x81, 0xed, 0x00, 0x04, 0x00, 0x00, 0x8b, 0x54, 0x24, 0x08, 0x8b, 0x42, 0x10, 0x81, 0xe2, 0x00, 0xf0, 0xff, 0xff, 0x89, 0x55, 0x08, 0xc7, 0x45, 0x0c, 0x00, 0x20, 0x00, 0x00, 0x83, 0xc0, 0x03, 0xff, 0xe0, 0x55, 0x89, 0xe5, 0x57, 0x56, 0x83, 0xec, 0x10, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x8b, 0x75, 0x08, 0x8b, 0x46, 0x14, 0x89, 0x04, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0x56, 0x08, 0x85, 0xc0, 0x74, 0x23, 0x8d, 0x8f, 0x52, 0x00, 0x00, 0x00, 0x89, 0x4c, 0x24, 0x04, 0x89, 0x04, 0x24, 0xff, 0x56, 0x0c, 0x85, 0xc0, 0x74, 0x0f, 0x8d, 0x4e, 0x20, 0x8b, 0x56, 0x1c, 0x89, 0x54, 0x24, 0x04, 0x89, 0x0c, 0x24, 0xff, 0xd0, 0x8b, 0x46, 0x18, 0x89, 0x04, 0x24, 0xe8, 0x71, 0xff, 0xff, 0xff, 0x83, 0xc4, 0x10, 0x5e, 0x5f, 0x5d, 0xe9, 0x7c, 0xff, 0xff, 0xff, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 +.byte 0x55, 0x89, 0xe5, 0x57, 0x56, 0x83, 0xec, 0x30, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x8d, 0x55, 0xf0, 0x31, 0xf6, 0x8d, 0x80, 0xf3, 0x00, 0x00, 0x00, 0x89, 0x4d, 0xf4, 0xc7, 0x45, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x4d, 0xf4, 0x8b, 0x09, 0x8b, 0x7d, 0xf4, 0x89, 0x14, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0x89, 0x44, 0x24, 0x08, 0x89, 0x7c, 0x24, 0x0c, 0x89, 0x75, 0xec, 0xff, 0xd1, 0x8b, 0x4d, 0xf4, 0x8b, 0x49, 0x04, 0x8b, 0x55, 0xf0, 0x89, 0x14, 0x24, 0x89, 0x45, 0xe8, 0xff, 0xd1, 0x31, 0xc9, 0x8b, 0x55, 0xf4, 0x8b, 0x52, 0x18, 0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0x89, 0x54, 0x24, 0x0c, 0x89, 0x45, 0xe4, 0x89, 0x4d, 0xe0, 0xe8, 0x1e, 0x00, 0x00, 0x00, 0xb9, 0xad, 0x0b, 0x00, 0x00, 0x89, 0x45, 0xdc, 0xff, 0xd1, 0x83, 0xc4, 0x30, 0x5e, 0x5f, 0x5d, 0xc3, 0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x69, 0x01, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x0b, 0x00, 0x00, 0x00, 0x89, 0xe1, 0x0f, 0x34, 0xc3, 0xb8, 0xdc, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0xc2, 0x0b, 0x00, 0x00, 0x00, 0x89, 0xe1, 0x0f, 0x34, 0xc3, 0x55, 0x89, 0xe5, 0x81, 0xed, 0x00, 0x04, 0x00, 0x00, 0x8b, 0x54, 0x24, 0x08, 0x8b, 0x42, 0x10, 0x81, 0xe2, 0x00, 0xf0, 0xff, 0xff, 0x89, 0x55, 0x08, 0xc7, 0x45, 0x0c, 0x00, 0x20, 0x00, 0x00, 0x83, 0xc0, 0x03, 0xff, 0xe0, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x89, 0xe5, 0x56, 0x83, 0xec, 0x24, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x8b, 0x4d, 0x08, 0x31, 0xd2, 0x89, 0x4d, 0xf8, 0x8b, 0x4d, 0xf8, 0x89, 0x4d, 0xf4, 0x8b, 0x4d, 0xf4, 0x8b, 0x49, 0x08, 0x8b, 0x75, 0xf4, 0x8b, 0x76, 0x14, 0x89, 0x34, 0x24, 0xc7, 0x44, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0x89, 0x45, 0xe8, 0x89, 0x55, 0xe4, 0xff, 0xd1, 0x89, 0x45, 0xf0, 0x81, 0x7d, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x84, 0x4b, 0x00, 0x00, 0x00, 0x8b, 0x45, 0xe8, 0x8d, 0x88, 0xab, 0x00, 0x00, 0x00, 0x8b, 0x55, 0xf4, 0x8b, 0x52, 0x0c, 0x8b, 0x75, 0xf0, 0x89, 0x34, 0x24, 0x89, 0x4c, 0x24, 0x04, 0xff, 0xd2, 0x89, 0x45, 0xec, 0x81, 0x7d, 0xec, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x84, 0x1b, 0x00, 0x00, 0x00, 0x8b, 0x45, 0xec, 0x8b, 0x4d, 0xf4, 0x81, 0xc1, 0x20, 0x00, 0x00, 0x00, 0x8b, 0x55, 0xf4, 0x8b, 0x52, 0x1c, 0x89, 0x0c, 0x24, 0x89, 0x54, 0x24, 0x04, 0xff, 0xd0, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x45, 0xf4, 0x8b, 0x40, 0x18, 0x89, 0x04, 0x24, 0xe8, 0x13, 0xff, 0xff, 0xff, 0x8b, 0x4d, 0xf4, 0x89, 0x0c, 0x24, 0x89, 0x45, 0xe0, 0xe8, 0x1b, 0xff, 0xff, 0xff, 0x83, 0xc4, 0x24, 0x5e, 0x5d, 0xc3, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 .align 2 .globl _inject_start_arm _inject_start_arm: -.byte 0x90, 0x40, 0x2d, 0xe9, 0x04, 0x70, 0x8d, 0xe2, 0x04, 0xd0, 0x4d, 0xe2, 0x78, 0x20, 0x00, 0xe3, 0x00, 0x40, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x20, 0x40, 0xe3, 0x00, 0x00, 0x8d, 0xe5, 0x02, 0x20, 0x8f, 0xe0, 0x00, 0x90, 0x94, 0xe5, 0x0d, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x04, 0x30, 0xa0, 0xe1, 0x39, 0xff, 0x2f, 0xe1, 0x04, 0x10, 0x94, 0xe5, 0x00, 0x00, 0x9d, 0xe5, 0x31, 0xff, 0x2f, 0xe1, 0x18, 0x30, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x20, 0xa0, 0xe3, 0x03, 0x00, 0x00, 0xeb, 0xad, 0x0b, 0x00, 0xe3, 0x30, 0xff, 0x2f, 0xe1, 0x04, 0xd0, 0x47, 0xe2, 0x90, 0x80, 0xbd, 0xe8, 0x0d, 0xc0, 0xa0, 0xe1, 0x70, 0x00, 0x2d, 0xe9, 0x70, 0x00, 0x9c, 0xe8, 0x69, 0xc1, 0x00, 0xe3, 0x80, 0x00, 0x00, 0xef, 0x70, 0x00, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x0d, 0xc0, 0xa0, 0xe1, 0x70, 0x00, 0x2d, 0xe9, 0x70, 0x00, 0x9c, 0xe8, 0x23, 0xc0, 0xe0, 0xe3, 0x80, 0x00, 0x00, 0xef, 0x70, 0x00, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x90, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x08, 0x20, 0x94, 0xe5, 0x04, 0x70, 0x8d, 0xe2, 0x14, 0x00, 0x94, 0xe5, 0x32, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3, 0x0a, 0x00, 0x00, 0x0a, 0x0c, 0x20, 0x94, 0xe5, 0x38, 0x10, 0x00, 0xe3, 0x00, 0x10, 0x40, 0xe3, 0x01, 0x10, 0x8f, 0xe0, 0x32, 0xff, 0x2f, 0xe1, 0x00, 0x20, 0xa0, 0xe1, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x1c, 0x10, 0x94, 0xe5, 0x20, 0x00, 0x84, 0xe2, 0x32, 0xff, 0x2f, 0xe1, 0x18, 0x00, 0x94, 0xe5, 0xe2, 0xff, 0xff, 0xeb, 0x10, 0x20, 0x94, 0xe5, 0x1f, 0x40, 0xcb, 0xe7, 0x02, 0x1a, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0x90, 0x40, 0xbd, 0xe8, 0x12, 0xff, 0x2f, 0xe1, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 +.byte 0x80, 0xb5, 0x6f, 0x46, 0x87, 0xb0, 0x05, 0xa9, 0x00, 0x22, 0x40, 0xf2, 0x6f, 0x03, 0xc0, 0xf2, 0x00, 0x03, 0x7b, 0x44, 0x06, 0x90, 0x05, 0x92, 0x06, 0x98, 0x00, 0x68, 0xdd, 0xf8, 0x18, 0x90, 0x04, 0x90, 0x08, 0x46, 0x11, 0x46, 0x1a, 0x46, 0x4b, 0x46, 0xdd, 0xf8, 0x10, 0x90, 0xc8, 0x47, 0x06, 0x99, 0x49, 0x68, 0x05, 0x9a, 0x03, 0x90, 0x10, 0x46, 0x88, 0x47, 0x00, 0x21, 0x06, 0x9a, 0x93, 0x69, 0x02, 0x90, 0x08, 0x46, 0x01, 0x91, 0x01, 0x9a, 0x00, 0xf0, 0x07, 0xf8, 0x40, 0xf6, 0xad, 0x31, 0x00, 0x90, 0x88, 0x47, 0x07, 0xb0, 0x80, 0xbd, 0x00, 0xbf, 0xec, 0x46, 0x70, 0xb4, 0x9c, 0xe8, 0x70, 0x00, 0x40, 0xf2, 0x69, 0x1c, 0x80, 0xdf, 0x70, 0xbc, 0x70, 0x47, 0x00, 0xbf, 0xec, 0x46, 0x70, 0xb4, 0x9c, 0xe8, 0x70, 0x00, 0x6f, 0xf0, 0x23, 0x0c, 0x80, 0xdf, 0x70, 0xbc, 0x70, 0x47, 0x00, 0xbf, 0x80, 0xb5, 0x6f, 0x46, 0x89, 0xb0, 0x00, 0x21, 0x08, 0x90, 0x08, 0x98, 0x07, 0x90, 0x07, 0x98, 0x80, 0x68, 0x07, 0x9a, 0x52, 0x69, 0x03, 0x90, 0x10, 0x46, 0x03, 0x9a, 0x90, 0x47, 0x00, 0x21, 0x06, 0x90, 0x06, 0x98, 0x88, 0x42, 0x1b, 0xd0, 0x40, 0xf2, 0x56, 0x01, 0xc0, 0xf2, 0x00, 0x01, 0x79, 0x44, 0x07, 0x98, 0xc0, 0x68, 0x06, 0x9a, 0x02, 0x90, 0x10, 0x46, 0x02, 0x9a, 0x90, 0x47, 0x00, 0x21, 0x05, 0x90, 0x05, 0x98, 0x88, 0x42, 0x09, 0xd0, 0x05, 0x98, 0x07, 0x99, 0x20, 0x31, 0x07, 0x9a, 0xd2, 0x69, 0x01, 0x90, 0x08, 0x46, 0x11, 0x46, 0x01, 0x9a, 0x90, 0x47, 0xff, 0xe7, 0x07, 0x98, 0x80, 0x69, 0xff, 0xf7, 0xc2, 0xff, 0x42, 0xf2, 0x00, 0x01, 0x07, 0x9a, 0x4f, 0xf2, 0x00, 0x03, 0xcf, 0xf6, 0xff, 0x73, 0x1a, 0x40, 0x04, 0x92, 0x07, 0x9a, 0x12, 0x69, 0x04, 0x9b, 0x00, 0x90, 0x18, 0x46, 0x90, 0x47, 0x09, 0xb0, 0x80, 0xbd, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 .align 2 .globl _inject_start_arm64 _inject_start_arm64: -.byte 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xff, 0x43, 0x00, 0xd1, 0xf3, 0x03, 0x00, 0xaa, 0xff, 0x0f, 0x00, 0xb9, 0x68, 0x02, 0x40, 0xf9, 0x01, 0x00, 0x80, 0xd2, 0x22, 0x03, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0xe0, 0x33, 0x00, 0x91, 0xe3, 0x03, 0x13, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x68, 0x06, 0x40, 0xf9, 0xe0, 0x0f, 0x40, 0xb9, 0x00, 0x01, 0x3f, 0xd6, 0x63, 0x32, 0x40, 0xb9, 0x00, 0x00, 0x80, 0xd2, 0x01, 0x00, 0x80, 0xd2, 0x02, 0x00, 0x80, 0x52, 0x07, 0x00, 0x00, 0x94, 0xa8, 0x75, 0x81, 0xd2, 0x00, 0x01, 0x3f, 0xd6, 0xbf, 0x43, 0x00, 0xd1, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x30, 0x2d, 0x80, 0xd2, 0x01, 0x10, 0x00, 0xd4, 0xc0, 0x03, 0x5f, 0xd6, 0x70, 0x04, 0x80, 0x92, 0x01, 0x10, 0x00, 0xd4, 0xc0, 0x03, 0x5f, 0xd6, 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xf3, 0x03, 0x00, 0xaa, 0x68, 0x0a, 0x40, 0xf9, 0x60, 0x16, 0x40, 0xf9, 0x01, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x40, 0x01, 0x00, 0xb4, 0x68, 0x0e, 0x40, 0xf9, 0x01, 0x02, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0x00, 0x01, 0x3f, 0xd6, 0xe8, 0x03, 0x00, 0xaa, 0x88, 0x00, 0x00, 0xb4, 0x60, 0x02, 0x01, 0x91, 0x61, 0x1e, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x60, 0x32, 0x40, 0xb9, 0xea, 0xff, 0xff, 0x97, 0x60, 0xc6, 0x72, 0x92, 0x62, 0x12, 0x40, 0xf9, 0xe1, 0x03, 0x73, 0xb2, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0x40, 0x00, 0x1f, 0xd6, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 +.byte 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xff, 0x43, 0x00, 0xd1, 0xf3, 0x03, 0x00, 0xaa, 0xff, 0x0f, 0x00, 0xb9, 0x68, 0x02, 0x40, 0xf9, 0x42, 0x03, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0xe0, 0x33, 0x00, 0x91, 0x01, 0x00, 0x80, 0xd2, 0xe3, 0x03, 0x13, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x68, 0x06, 0x40, 0xf9, 0xe0, 0x0f, 0x40, 0xb9, 0x00, 0x01, 0x3f, 0xd6, 0x63, 0x32, 0x40, 0xb9, 0x00, 0x00, 0x80, 0xd2, 0x01, 0x00, 0x80, 0xd2, 0x02, 0x00, 0x80, 0x52, 0x07, 0x00, 0x00, 0x94, 0xa8, 0x75, 0x81, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0xbf, 0x43, 0x00, 0xd1, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x30, 0x2d, 0x80, 0xd2, 0x01, 0x10, 0x00, 0xd4, 0xc0, 0x03, 0x5f, 0xd6, 0x70, 0x04, 0x80, 0x92, 0x01, 0x10, 0x00, 0xd4, 0xc0, 0x03, 0x5f, 0xd6, 0xf4, 0x4f, 0xbe, 0xa9, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91, 0xf3, 0x03, 0x00, 0xaa, 0x68, 0x0a, 0x40, 0xf9, 0x60, 0x16, 0x40, 0xf9, 0x01, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x40, 0x01, 0x00, 0xb4, 0x68, 0x0e, 0x40, 0xf9, 0x01, 0x02, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0x00, 0x01, 0x3f, 0xd6, 0xe8, 0x03, 0x00, 0xaa, 0x88, 0x00, 0x00, 0xb4, 0x60, 0x02, 0x01, 0x91, 0x61, 0x1e, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x60, 0x32, 0x40, 0xb9, 0xea, 0xff, 0xff, 0x97, 0x60, 0xc6, 0x72, 0x92, 0x62, 0x12, 0x40, 0xf9, 0xe1, 0x03, 0x13, 0x32, 0xfd, 0x7b, 0x41, 0xa9, 0xf4, 0x4f, 0xc2, 0xa8, 0x40, 0x00, 0x1f, 0xd6, 0x73, 0x75, 0x62, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00 -- cgit v1.2.3 From 193c6ba8dc61e2a3797ce4431656aa8491e11aaf Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 7 Jul 2015 16:15:24 -0400 Subject: Werror, Makefile fix --- configure | 4 ++++ script/mconfig.py | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/configure b/configure index e8c5b15..e50683d 100755 --- a/configure +++ b/configure @@ -16,6 +16,7 @@ settings.add_setting_option('enable_tests', '--enable-tests', 'tests!', False, b settings.add_setting_option('enable_ios_bootstrap', '--enable-ios-bootstrap', 'default: true if you pass --xcode-sdk=iphoneos', lambda: 'iphoneos' in str(settings.host_machine().toolchains()[0].sdk_opt.value), bool=True) +settings.add_setting_option('enable_werror', '--enable-werror', '', False, bool=True) ldid_tool = mconfig.CLITool('ldid', ['ldid'], 'LDID', settings.host_machine(), settings.host_machine().toolchains()) ldid_tool.optional() @@ -51,6 +52,9 @@ mconfig.mark_safe_to_clean('(src)/generated/darwin-inject-asm.S', settings) if settings.enable_ios_bootstrap: mconfig.log('Will build iOS bootstrap.\n') +if settings.enable_werror: + for mach in machs + [settings.host_machine()]: + settings[mach.name].cflags = ['-Werror'] + settings[mach.name].cflags # todo make overridable? cc_argv = c.cc.argv() diff --git a/script/mconfig.py b/script/mconfig.py index 26556d6..88e5341 100644 --- a/script/mconfig.py +++ b/script/mconfig.py @@ -906,8 +906,10 @@ class MakefileEmitter(Emitter): # TODO avoid deleting partial output? stub = ''' %(banner)s -_ := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2) +_out := $(shell "$(MAKE_COMMAND)" -s -f %(main_mk_arg)s %(makefile_arg)s >&2 || echo fail) +ifneq ($(_out),fail) include %(main_mk)s +endif '''.lstrip() \ % { 'makefile_arg': argv_to_shell([makefile]), -- cgit v1.2.3 From 03b2f5352bd5f4ff957cb4a34e114049b951369d Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 7 Jul 2015 16:17:38 -0400 Subject: warning fix --- Makefile.old | 207 ----------------------------------- darwin-bootstrap/safety-dance/main.m | 2 +- 2 files changed, 1 insertion(+), 208 deletions(-) delete mode 100644 Makefile.old diff --git a/Makefile.old b/Makefile.old deleted file mode 100644 index a9e18f6..0000000 --- a/Makefile.old +++ /dev/null @@ -1,207 +0,0 @@ -# I really want to rewrite this with some configure script written in a real -# language, that supports cross compilation properly, etc. In fact, making a -# good generic configure framework is on my todo list; but since that's a lot -# of work, have fun with this hacky Makefile. -CC := clang -CXX := clang++ -ARCH := -arch x86_64 -XCFLAGS := -g -O3 -Wall -Wextra -Werror -Ilib $(ARCH) -LIB_LDFLAGS := -lobjc -dynamiclib -fvisibility=hidden -install_name /usr/lib/libsubstitute.0.dylib -dead_strip -IOS_APP_LDFLAGS := -framework UIKit -framework Foundation -dead_strip -IS_IOS := $(findstring -arch arm,$(CC) $(CFLAGS) $(XCFLAGS)) -ifneq (,$(IS_IOS)) -# I don't know anything in particular that would break this on older versions, -# but I don't have any good way to test it and don't really care. So ensure it -# doesn't get run on them. -XCFLAGS := $(XCFLAGS) -miphoneos-version-min=7.0 -endif -override CC := $(CC) $(XCFLAGS) $(CFLAGS) -override CXX := $(CXX) $(XCFLAGS) $(CFLAGS) -fno-exceptions -fno-asynchronous-unwind-tables - -# These are only required to rebuild the generated disassemblers. -IMAON2 := /Users/comex/c/imaon2 -GEN_JS := node --harmony --harmony_arrow_functions $(IMAON2)/tables/gen.js - -all: \ - out/libsubstitute.dylib - -$(shell mkdir -p out generated) - -GENERATED_DIS_HEADERS := generated/generic-dis-arm.inc.h generated/generic-dis-thumb.inc.h generated/generic-dis-thumb2.inc.h generated/generic-dis-arm64.inc.h -define do_prefix -generated/generic-dis-$(1).inc.h: - $(GEN_JS) --gen-hook-disassembler $(2) --dis-pattern='P(XXX)' $(IMAON2)/out/out-$(3).json > $$@ || rm -f $$@ -generateds: generated/generic-dis-$(1).inc.h -endef -$(eval $(call do_prefix,thumb2,-n _thumb2,ARM)) -$(eval $(call do_prefix,thumb,-n _thumb,ARM)) -$(eval $(call do_prefix,arm,-n _arm,ARM)) -$(eval $(call do_prefix,arm64,,AArch64)) - -HEADERS := lib/*.h lib/*/*.h generated/manual-mach.inc.h - -out/%.o: lib/%.c Makefile $(HEADERS) - @mkdir -p $(dir $@) - $(CC) -fvisibility=hidden -std=c11 -c -o $@ $< -out/%.o: generated/%.S Makefile $(HEADERS) - $(CC) -fvisibility=hidden -c -o $@ $< -out/%.o: lib/%.S Makefile $(HEADERS) - @mkdir -p $(dir $@) - $(CC) -fvisibility=hidden -c -o $@ $< -out/jump-dis.o: $(GENERATED_DIS_HEADERS) -out/transform-dis.o: $(GENERATED_DIS_HEADERS) - -# Note: the order of darwin-inject-asm.o is significant. Per man page, ld is -# guaranteed to link objects in order, which is necessary because -# darwin-inject-asm.S does not itself ensure there is at least 0x4000 bytes of -# executable stuff after inject_page_start (so that arm can remap into arm64). -# By putting it at the beginning, we can just reuse the space for the rest of -# the library rather than having to pad with zeroes. -# (This only matters on 32-bit ARM, and the text segment is currently 0xa000 -# bytes there, more than enough.) - -LIB_OBJS := \ - out/darwin-inject-asm.o \ - out/darwin/find-syms.o \ - out/darwin/inject.o \ - out/darwin/interpose.o \ - out/darwin/objc-asm.o \ - out/darwin/objc.o \ - out/darwin/read.o \ - out/darwin/substrate-compat.o \ - out/darwin/execmem.o \ - out/cbit/vec.o \ - out/jump-dis.o \ - out/transform-dis.o \ - out/hook-functions.o \ - out/strerror.o - -out/libsubstitute.dylib: $(LIB_OBJS) - $(CC) -o $@ $(LIB_OBJS) $(LIB_LDFLAGS) - dsymutil $@ - -# The result of this is also checked into generated, just in case someone is -# trying to build with some Linux compiler that doesn't support all the -# architectures or something - meh. -# Did you know? With -Oz + -marm, Apple clang-600.0.56 actually generated -# wrong code for the ARM version. It works with -Os and with newer clang. -IACLANG := clang -Os -fno-stack-protector -dynamiclib -nostartfiles -nodefaultlibs -isysroot /dev/null -Ilib -fPIC -define define_iar -out/inject-asm-raw-$(1).o: lib/darwin/inject-asm-raw.c Makefile lib/darwin/manual-syscall.h lib/darwin/inject-asm-raw.order - $(IACLANG) -arch $(2) -Wl,-order_file,lib/darwin/inject-asm-raw.order -o $$@ $$< -endef -$(eval $(call define_iar,x86_64,x86_64)) -$(eval $(call define_iar,i386,i386)) -$(eval $(call define_iar,arm,armv7 -marm)) -$(eval $(call define_iar,arm64,arm64)) - -IAR_BINS := out/inject-asm-raw-x86_64.bin out/inject-asm-raw-i386.bin out/inject-asm-raw-arm.bin out/inject-asm-raw-arm64.bin -out/darwin-inject-asm.S: $(IAR_BINS) Makefile script/gen-inject-asm.sh - ./script/gen-inject-asm.sh > $@ || rm -f $@ -generateds: out/darwin-inject-asm.S -out/darwin-inject-asm.S: out/darwin-inject-asm.S - cp $< generated/ - -generateds: generated/manual-mach.inc.h -generated/manual-mach.inc.h: ./script/gen-manual-mach.sh - ./script/gen-manual-mach.sh - -out/%.bin: out/%.o Makefile - segedit -extract __TEXT __text $@ $< - -define define_test -out/test-$(1): test/test-$(2).[cm]* $(HEADERS) $(GENERATED) Makefile out/libsubstitute.dylib - $(3) -o $$@ $$< -Ilib -Isubstrate -Lout -dead_strip -lsubstitute - install_name_tool -change /usr/lib/libsubstitute.0.dylib '@executable_path/libsubstitute.dylib' $$@ -ifneq (,$(IS_IOS)) - ldid -Sent.plist $$@ -endif -tests: out/test-$(1) -endef -$(eval $(call define_test,td-simple-arm,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-arm.inc.h"' -Dxdis=dis_arm -DFORCE_TARGET_arm)) -$(eval $(call define_test,td-simple-thumb,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-thumb.inc.h"' -Dxdis=dis_thumb -DFORCE_TARGET_arm)) -$(eval $(call define_test,td-simple-thumb2,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-thumb2.inc.h"' -Dxdis=dis_thumb2 -DFORCE_TARGET_arm)) -$(eval $(call define_test,td-simple-arm64,td-simple,$(CC) -std=c11 -DHDR='"arm64/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_arm64)) -$(eval $(call define_test,td-simple-i386,td-simple,$(CC) -std=c11 -DHDR='"x86/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_i386)) -$(eval $(call define_test,td-simple-x86-64,td-simple,$(CC) -std=c11 -DHDR='"x86/dis-main.inc.h"' -Dxdis=dis -DFORCE_TARGET_x86_64)) -$(eval $(call define_test,dis-arm,dis,$(CC) -std=c11 -DFORCE_TARGET_arm)) -$(eval $(call define_test,dis-arm64,dis,$(CC) -std=c11 -DFORCE_TARGET_arm64)) -$(eval $(call define_test,jump-dis-arm,jump-dis,$(CC) -std=c11 -DFORCE_TARGET_arm -O0 out/cbit/vec.o)) -$(eval $(call define_test,jump-dis-arm64,jump-dis,$(CC) -std=c11 -DFORCE_TARGET_arm64 -O0 out/cbit/vec.o)) -$(eval $(call define_test,transform-dis-arm,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_arm -O0)) -$(eval $(call define_test,transform-dis-arm64,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_arm64 -O0)) -$(eval $(call define_test,transform-dis-i386,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_i386 -O0)) -$(eval $(call define_test,transform-dis-x86_64,transform-dis,$(CC) -std=c11 -DFORCE_TARGET_x86_64 -O0)) -$(eval $(call define_test,find-syms,find-syms,$(CC) -std=c89)) -$(eval $(call define_test,find-syms-cpp,find-syms,$(CXX) -x c++ -std=c++98)) -$(eval $(call define_test,substrate,substrate,$(CXX) -std=c++98)) -$(eval $(call define_test,imp-forwarding,imp-forwarding,$(CC) -std=c11 -framework Foundation -lobjc)) -$(eval $(call define_test,objc-hook,objc-hook,$(CC) -std=c11 -framework Foundation -lsubstitute)) -$(eval $(call define_test,interpose,interpose,$(CC) -std=c11 -lsubstitute)) -$(eval $(call define_test,inject,inject,$(CC) -std=c11 -lsubstitute out/darwin/inject.o out/darwin/read.o)) -$(eval $(call define_test,pc-patch,pc-patch,$(CC) -std=c11 out/darwin/execmem.o)) -$(eval $(call define_test,execmem,execmem,$(CC) -std=c11 out/darwin/execmem.o -segprot __TEST rwx rx)) -$(eval $(call define_test,hook-functions,hook-functions,$(CC) -std=c11 -lsubstitute -segprot __TEST rwx rx)) -$(eval $(call define_test,posixspawn-hook,posixspawn-hook,$(CC) -std=c11)) -$(eval $(call define_test,htab,htab,$(CC) -std=c11)) -$(eval $(call define_test,vec,vec,$(CXX) -std=c++98 out/cbit/vec.o)) - -out/injected-test-dylib.dylib: test/injected-test-dylib.c Makefile - $(CC) -std=c11 -dynamiclib -o $@ $< -tests: out/injected-test-dylib.dylib - -# These are just random sequences of instructions which you can compile to .bin -# for testing. - -out/insns-arm.o: test/insns-arm.S Makefile - clang -arch armv7 -c -o $@ $< -out/insns-thumb2.o: test/insns-arm.S Makefile - clang -arch armv7 -DTHUMB2 -c -o $@ $< - -out/insns-libz-arm.o: test/insns-libz-arm.S Makefile - clang -arch armv7 -c -o $@ $< -out/insns-libz-thumb2.o: test/insns-libz-arm.S Makefile - clang -arch armv7 -c -o $@ $< -DTHUMB2 - -define transform-dis-cases -out/transform-dis-cases-$(arch).o: test/transform-dis-cases-$(arch).S Makefile - clang -arch $(arch) -c -o $$@ $$< -endef -$(foreach arch,i386 x86_64 armv7 arm64,$(eval $(transform-dis-cases))) - -# iOS bootstrap... -ifneq (,$(IS_IOS)) -SD_OBJS := out/safety-dance/main.o out/safety-dance/AutoGrid.o -out/safety-dance/%.o: darwin-bootstrap/safety-dance/%.m darwin-bootstrap/safety-dance/*.h Makefile - @mkdir -p $(dir $@) - $(CC) -c -o $@ $< -fobjc-arc -Wno-unused-parameter -out/safety-dance/SafetyDance.app/SafetyDance: $(SD_OBJS) Makefile - @mkdir -p $(dir $@) - $(CC) -o $@ $(SD_OBJS) $(IOS_APP_LDFLAGS) - ldid -S $@ -out/safety-dance/SafetyDance.app/Info.plist: darwin-bootstrap/safety-dance/Info.plist Makefile - @mkdir -p $(dir $@) - plutil -convert binary1 -o $@ $< - cp darwin-bootstrap/safety-dance/white.png out/safety-dance/SafetyDance.app/Default.png - cp darwin-bootstrap/safety-dance/white.png out/safety-dance/SafetyDance.app/Default@2x.png -safety-dance: out/safety-dance/SafetyDance.app/SafetyDance out/safety-dance/SafetyDance.app/Info.plist -all: safety-dance - -out/posixspawn-hook.dylib: darwin-bootstrap/posixspawn-hook.c out/libsubstitute.dylib - $(CC) -dynamiclib -o $@ $< -Lout -lsubstitute -out/bundle-loader.dylib: darwin-bootstrap/bundle-loader.c darwin-bootstrap/substituted-messages.h out/libsubstitute.dylib - $(CC) -dynamiclib -o $@ $< -Lout -out/unrestrict: darwin-bootstrap/unrestrict.c darwin-bootstrap/ib-log.h out/libsubstitute.dylib - $(CC) -o $@ $< -Lout -lsubstitute - ldid -Sent.plist $@ -out/inject-into-launchd: darwin-bootstrap/inject-into-launchd.c darwin-bootstrap/ib-log.h out/libsubstitute.dylib - $(CC) -o $@ $< -Lout -lsubstitute -framework IOKit -framework CoreFoundation - ldid -Sent.plist $@ -out/substituted: darwin-bootstrap/substituted* - $(CC) -o $@ darwin-bootstrap/substituted{.c,-plist-loader.m} -framework Foundation -framework CoreFoundation -lbsm -fobjc-arc -all: out/posixspawn-hook.dylib out/bundle-loader.dylib out/unrestrict out/inject-into-launchd out/substituted -endif - - -clean: - rm -rf out diff --git a/darwin-bootstrap/safety-dance/main.m b/darwin-bootstrap/safety-dance/main.m index 0d05e00..28aec24 100644 --- a/darwin-bootstrap/safety-dance/main.m +++ b/darwin-bootstrap/safety-dance/main.m @@ -118,7 +118,7 @@ static void compression(UIView *view, UILayoutPriority pri) { } -- (NSUInteger)supportedInterfaceOrientations +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) return UIInterfaceOrientationMaskAll; -- cgit v1.2.3