aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcomex2015-07-07 16:17:49 -0400
committercomex2015-07-07 16:17:49 -0400
commitca6dcad6bde14ae030814bf5ce1b22af8d805792 (patch)
tree7da5edd95014cbeca992eedd723495a1072a2ef9
parentprogress (diff)
parentwarning fix (diff)
downloadsubstitute-ca6dcad6bde14ae030814bf5ce1b22af8d805792.tar.gz
Merge branch 'mconfig-work'
My pet build system project - not terribly useful for a relatively simple thing like this, but I want to use it for other purposes, and it does provide a nice ./configure...
-rw-r--r--Makefile207
-rwxr-xr-xconfigure222
-rw-r--r--darwin-bootstrap/safety-dance/main.m2
-rw-r--r--generated/darwin-inject-asm.S8
-rw-r--r--lib/jump-dis.c4
-rw-r--r--mconfig.py641
-rwxr-xr-xscript/gen-inject-asm.sh19
-rw-r--r--script/mconfig.py1196
8 files changed, 1438 insertions, 861 deletions
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/configure b/configure
new file mode 100755
index 0000000..e50683d
--- /dev/null
+++ b/configure
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+import sys, os, glob
+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'
+
+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)
+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)
+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()
+
+asm_archs = [
+ ('x86_64', []),
+ ('i386', []),
+ ('arm', ['-marm']),
+ ('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')
+ machs.append(mach)
+ cc = mach.c_tools().cc
+ cc.optional()
+ def f():
+ if settings.gen_dia:
+ cc.argv()
+ mach_settings = settings[mach.name]
+ 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)
+
+
+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')
+
+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()
+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']
+
+emitter = settings.emitter
+
+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
+# 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.)
+
+mconfig.build_and_link_c_objs(
+ emitter, settings.host_machine(), settings,
+ '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=cb
+)
+#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:
+ args = []
+ 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,
+ ),
+ 'dylib',
+ exe,
+ ['(src)/lib/darwin/inject-asm-raw.c'])
+ 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])
+
+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])
+ 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+settings.host.ldflags,
+ override_obj_fn=o+'.o',
+ override_is_cxx=options.get('cxx', False),
+ ), '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'], list(emitter.all_outs), [], phony=True)
+emitter.set_default_rule('all')
+
+mconfig.finish_and_emit()
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;
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
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/mconfig.py b/mconfig.py
deleted file mode 100644
index 8bfea5a..0000000
--- a/mconfig.py
+++ /dev/null
@@ -1,641 +0,0 @@
-# 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
-
-def indentify(s, indent=' '):
- return s.replace('\n', '\n' + indent)
-
-def log(x):
- sys.stdout.write(x)
- config_log.write(x)
-
-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 = 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())
- 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 self.threw:
- raise
-
-class Pending(object):
- def __str__(self):
- return 'Pending',
- def resolve(self):
- return self.value
- # xxx py3
- def __getattr__(self, attr):
- 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)
-
-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.new_inheritor(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 __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 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
- default = Expansion(default, self) if isinstance(default, str) else default
- 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 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 '<none yet>'
- 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 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)
-
-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 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/(..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():
- 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 forgot1 os forgot2')):
- 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 != 4:
- 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
-
-class Machine(object):
- def __init__(self, name, settings, triple_help, triple_default):
- self.name = name
- self.settings = settings
- def on_set(val):
- self.triple = val
- 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 '<none yet>')
-
- 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
-
- # 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, self.toolchains())
-
-class UnixTool(object):
- def __init__(self, name, defaults, env, machine, toolchains, dont_suffix_env=False):
- 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())
- 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 = memoize(self.argv)
-
- def __repr__(self):
- return 'UnixTool(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): # memoized
- # 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\n' % (self.name, 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)
-
- 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
- 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 ''
- 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
- 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'
- # 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'])
- if code == 127:
- log('* Failed to run /usr/bin/xcrun\n')
- if not using_default:
- raise DependencyNotFoundException
- return
- elif code:
- log('* Xcode SDK %r not found\n' % (val,))
- if not using_default:
- 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:
- return
- self.archs = self.get_archs(val)
- log('Using architectures: %s\n' % (repr(self.archs) if self.archs != [] else '(native)'))
- self.got_arch = True
-
- def get_archs(self, val):
- if val is not None:
- return re.sub('\s', '', val).split(',')
- # 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
- 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
-
- def find_tool(self, tool, failure_notes):
- if not self.got_arch:
- return None
- argv = ['/usr/bin/xcrun', tool.name]
- 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.
-class CTools(object):
- def __init__(self, machine, toolchains):
- tools = [
- # TODO figure out ld
- ('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',),
- ]
- for spec in tools:
- if len(spec) == 1:
- name, defaults, env = spec[0], [spec[0]], spec[0].upper()
- else:
- name, defaults, env = spec
- tool = UnixTool(name, defaults, env, machine, toolchains)
- setattr(self, name, tool)
-
-
-# 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)
-
-# -- init code --
-
-
-init_config_log()
-
-did_parse_args = False
-
-all_options = []
-all_options_by_name = {}
-all_opt_sections = []
-default_opt_section = OptSection('Uncategorized options:')
-post_parse_args_will_need = []
-
-settings_root = SettingsGroup(name='root')
-settings_root.package_unix_name = Pending()
-installation_dirs_group(settings_root.new_child('idirs'))
-
-triple_options_section = OptSection('System types:')
-settings_root.build_machine = memoize(lambda: Machine('build', settings_root, 'the machine doing the build', ''))
-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(':')
-
-# --
-
diff --git a/script/gen-inject-asm.sh b/script/gen-inject-asm.sh
index a4dfc5b..633a1a5 100755
--- a/script/gen-inject-asm.sh
+++ b/script/gen-inject-asm.sh
@@ -1,5 +1,7 @@
#!/bin/sh
-cat <<END
+outfile="$1"
+shift
+(cat <<END
/* Generated by script/gen-inject-asm.sh. The relevant source is in-tree (make
* out/darwin-inject-asm.S), but this file has been checked in too, in case
* your C compiler doesn't support all of these architectures.
@@ -13,10 +15,11 @@ cat <<END
.globl _inject_page_start
_inject_page_start:
END
-for i in x86_64 i386 arm arm64; do
- echo ".align 2"
- echo ".globl _inject_start_$i"
- echo "_inject_start_$i:"
- printf ".byte "
- xxd -i < out/inject-asm-raw-$i.bin | xargs echo
-done
+while [ -n "$1" ]; do
+ echo ".align 2"
+ echo ".globl _inject_start_$1"
+ echo "_inject_start_$1:"
+ printf ".byte "
+ xxd -i < "$2" | xargs echo
+ shift 2
+done) > "$outfile"
diff --git a/script/mconfig.py b/script/mconfig.py
new file mode 100644
index 0000000..88e5341
--- /dev/null
+++ b/script/mconfig.py
@@ -0,0 +1,1196 @@
+import re, argparse, sys, os, string, shlex, subprocess, glob, parser, hashlib, json, errno
+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 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)
+
+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), group_parent=self)
+ 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 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 KeyError:
+ 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, 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
+
+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 '<none yet>'
+ 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 (False if self.bool else 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], '<string>', 'eval'), should_shlex_result))
+ z = y+1+offset
+ return bits
+
+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, extra_vars={}):
+ bits = parse_expander(fmt)
+ 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, extra_vars={}):
+ 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, extra_vars)
+ 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, extra_vars) 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
+ 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,
+ **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
+ settings.new_child(name)
+ 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)
+ 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
+ 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 '<none yet>')
+
+ 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):
+ if section is None:
+ section = machine.tools_section
+ 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 f():
+ try:
+ self.argv()
+ except DependencyNotFoundException:
+ pass
+ post_parse_args_will_need.append(f)
+
+ def required(self):
+ self.argv_opt.need()
+ 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
+ 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:
+ 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]
+
+ 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)
+ 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=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
+
+
+# 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
+ 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
+ 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)
+ 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
+ self.all_outs = set()
+ 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 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, phony=False, *args, **kwargs):
+ if kwargs.get('expand', True):
+ 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 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
+ 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(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,))
+
+ 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):
+ 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)
+ # 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()
+ self.add_clean()
+ return '\n'.join(self.makefile_bits)
+
+ def emit(self):
+ makefile = self.settings.emit_fn
+ 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
+_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]),
+ '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'
+
+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(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%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_rel_and_escape, outs)), ' '.join(map(self.filename_rel_and_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_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_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,))
+ else:
+ log('Warning: %r: no default rule\n' % (self,))
+
+ 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)
+
+ 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():
+ 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)
+
+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')
+
+# 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):
+ tools = machine.c_tools()
+ any_was_cxx = False
+ obj_fns = []
+ ldflag_sets = set()
+ if expand:
+ _expand = lambda x: globals()['expand'](x, settings)
+ _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
+ if settings_cb is not None:
+ s = settings_cb(fn)
+ if s is not None:
+ 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))
+ 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)))
+ 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_compile_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 + include_args + cflags + ['-c', '-o', obj_fn, '-MMD', '-MF', dep_fn, fn]
+
+ cmds = [mkdir_cmd, cmd]
+ 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', ()):
+ 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, ldflags_from_sets=[]):
+ if expand:
+ _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
+ env = {'link_out': link_out} # todo: ...
+ 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 = _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:
+ typeflag = []
+ 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]
+ 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, 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, ldflags_from_sets)
+
+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.enable_rule_hashing = True
+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,
+}
+
+pre_parse_args_will_need.append(add_emitter_option)
+
+# --
+