this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Rewrite stub generator to also generate CMakeLists

This combines the C function stub generator and
the Objective-C class generator.

It also detects the dylib current and compat
versions.

It basically creates a stub folder that you can
copy directly into /src.

+224
+224
tools/darling-stub-gen
··· 1 + #!/usr/bin/env python3 2 + 3 + import sys, os, subprocess, re 4 + 5 + # Data 6 + library = False 7 + framework = False 8 + private_framework = False 9 + uses_objc = False 10 + full_path = "" 11 + output_dir = "" 12 + target_name = "" 13 + header_dir = "" 14 + source_dir = "" 15 + 16 + # Constants 17 + library_prefix = "/usr/lib/" 18 + framework_prefix = "/System/Library/Frameworks/" 19 + private_framework_prefix = "/System/Library/PrivateFrameworks/" 20 + 21 + class_dump = "~/bin/class-dump" 22 + 23 + copyright ="""/* 24 + This file is part of Darling. 25 + 26 + Copyright (C) 2017 Lubos Dolezel 27 + 28 + Darling is free software: you can redistribute it and/or modify 29 + it under the terms of the GNU General Public License as published by 30 + the Free Software Foundation, either version 3 of the License, or 31 + (at your option) any later version. 32 + 33 + Darling is distributed in the hope that it will be useful, 34 + but WITHOUT ANY WARRANTY; without even the implied warranty of 35 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 + GNU General Public License for more details. 37 + 38 + You should have received a copy of the GNU General Public License 39 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 40 + */ 41 + 42 + """ 43 + 44 + c_func_impl_stub = """ 45 + void* %s(void) { 46 + if (verbose) puts("STUB: %s called"); 47 + return NULL; 48 + } 49 + """ 50 + 51 + msg_handling = """- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { 52 + return [NSMethodSignature signatureWithObjCTypes: \"v@:\"]; 53 + } 54 + 55 + - (void)forwardInvocation:(NSInvocation *)anInvocation { 56 + NSLog(@\"Stub called: %@ in %@\", NSStringFromSelector([anInvocation selector]), [self class]); 57 + } 58 + 59 + """ 60 + # Utility functions 61 + def usage(): 62 + print("Usage: " + sys.argv[0] + " <Mach-O> <output directory>") 63 + exit(1) 64 + 65 + def extract_library_name(name): 66 + prefix_len = len(library_prefix) + len("lib") 67 + ext_len = len(".dylib") 68 + 69 + return name[prefix_len : len(name) - ext_len] 70 + 71 + def extract_framework_name(name): 72 + return name[name.rfind("/") + 1 :] 73 + 74 + # Main program start 75 + if len(sys.argv) != 3: 76 + usage() 77 + 78 + full_path = sys.argv[1] 79 + output_dir = sys.argv[2] 80 + 81 + try: 82 + os.makedirs(output_dir) 83 + except FileExistsError: 84 + pass 85 + 86 + 87 + if len(full_path) > len(library_prefix) and full_path[:len(library_prefix)] == library_prefix: 88 + library = True 89 + target_name = extract_library_name(full_path) 90 + elif len(full_path) > len(framework_prefix) and full_path[:len(framework_prefix)] == framework_prefix: 91 + framework = True 92 + target_name = extract_framework_name(full_path) 93 + elif len(full_path) > len(private_framework_prefix) and full_path[:len(private_framework_prefix)] == private_framework_prefix: 94 + private_framework = True 95 + target_name = extract_framework_name(full_path) 96 + else: 97 + print("Failed to recognize Mach-O location") 98 + exit(1) 99 + 100 + header_dir = output_dir + "/include/" + target_name + "/" 101 + source_dir = output_dir + "/src/" 102 + 103 + try: 104 + os.makedirs(header_dir) 105 + except FileExistsError: 106 + pass 107 + 108 + try: 109 + os.makedirs(source_dir) 110 + except FileExistsError: 111 + pass 112 + 113 + # Get C functions 114 + 115 + c_func_out = subprocess.check_output(["nm", "-Ug", full_path]) 116 + c_func_out = c_func_out.decode('utf8').strip() 117 + 118 + functions = [] 119 + for line in c_func_out.splitlines(): 120 + 121 + if line == "": 122 + continue 123 + 124 + address, id, name = line.split(" ") 125 + # Remove the underscore 126 + name = name[1 : ] 127 + 128 + if id == "T": 129 + functions.append(name) 130 + 131 + c_header = open(header_dir + target_name + ".h", "w") 132 + c_source = open(source_dir + target_name + ".c", "w") 133 + 134 + c_header.write(copyright) 135 + c_source.write(copyright) 136 + 137 + c_source.write(""" 138 + #include <stdlib.h> 139 + 140 + static int verbose = 0; 141 + 142 + __attribute__((constructor)) 143 + static void initme(void) { 144 + verbose = getenv("STUB_VERBOSE") != NULL; 145 + } 146 + """) 147 + 148 + c_hdr_buffer = "\n#ifndef _%s_H_\n#define _%s_H_\n\n" % (target_name, target_name) 149 + 150 + for funcname in functions: 151 + #c_header.write("void* %s(void);\n" % funcname) 152 + c_hdr_buffer += "void* %s(void);\n" % funcname 153 + c_source.write(c_func_impl_stub % (funcname, funcname)) 154 + 155 + cmake = open(output_dir + "/CMakeLists.txt", "w") 156 + 157 + cmake.write("project(%s)\n\n" % target_name) 158 + 159 + # Get current and compat versions 160 + 161 + otool_out = subprocess.check_output(["otool", "-L", full_path]) 162 + otool_out = otool_out.decode('utf8').strip() 163 + version_line = otool_out.splitlines()[1] 164 + 165 + get_versions = re.compile("\\(compatibility version (.*?), current version (.*?)\\)") 166 + 167 + compat, current = get_versions.search(version_line).groups() 168 + 169 + if library: 170 + cmake.write("set(DYLIB_INSTALL_NAME \"%s\")\n" % full_path) 171 + cmake.write("set(DYLIB_COMPAT_VERSION \"%s\")\n" % compat) 172 + cmake.write("set(DYLIB_CURRENT_VERSION \"%s\")\n\n" % current) 173 + 174 + class_dump_output = subprocess.check_output(["class-dump", full_path]).decode('utf8').strip() 175 + 176 + uses_objc = "This file does not contain any Objective-C runtime information." not in class_dump_output 177 + 178 + if uses_objc: 179 + class_dump_all = subprocess.check_output(["class-dump", "-H", "-o", header_dir, full_path]).decode('utf8').strip() 180 + get_class_names = re.compile("@interface (.+) :.+") 181 + classes = get_class_names.findall(class_dump_output) 182 + for classname in classes: 183 + impl = open(source_dir + classname + ".m", "w") 184 + impl.write(copyright) 185 + 186 + impl.write("#import <%s/%s.h>\n\n" % (target_name, target_name)) 187 + impl.write("@implementation " + classname + "\n\n") 188 + impl.write(msg_handling) 189 + impl.write("@end\n") 190 + 191 + c_header.write("#import <%s/%s.h>\n" % (target_name, classname)) 192 + 193 + if uses_objc: 194 + cmake.write("file(GLOB %s_OBJC_SOURCES src/*.m)\n\n" % target_name) 195 + 196 + if library: 197 + source_files = "src/%s.c\n${%s_OBJC_SOURCES}" % (target_name, target_name) 198 + cmake.write("add_darling_library(%s SHARED %s)\n" % (target_name, source_files)) 199 + cmake.write("make_fat(%s)\n" % target_name) 200 + libraries = "system objc" if uses_objc else "system" 201 + cmake.write("target_link_libraries(%s %s)\n" % (target_name, libraries)) 202 + cmake.write("install(TARGETS %s DESTINATION libexec/darling/usr/lib)\n" % target_name) 203 + else: 204 + cmake.write("add_framework(%s\n" %target_name) 205 + cmake.write(" FAT\n CURRENT_VERSION\n") 206 + if private_framework: 207 + cmake.write(" PRIVATE\n") 208 + cmake.write(" VERSION \"A\"\n\n") 209 + cmake.write(" SOURCES\n") 210 + cmake.write(" src/%s.c\n" % target_name) 211 + if uses_objc: 212 + cmake.write(" ${%s_OBJC_SOURCES}\n" % target_name) 213 + 214 + cmake.write("\n") 215 + 216 + cmake.write(" DEPENDENCIES\n") 217 + cmake.write(" system\n") 218 + if uses_objc: 219 + cmake.write(" objc\n") 220 + cmake.write(" Foundation\n") 221 + cmake.write(")\n") 222 + 223 + c_header.write(c_hdr_buffer) 224 + c_header.write("\n#endif\n")