Index: util/mach/mig.py |
diff --git a/util/mach/mig.py b/util/mach/mig.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..2d248854d59ce5f171e6f69262bd4871631bc330 |
--- /dev/null |
+++ b/util/mach/mig.py |
@@ -0,0 +1,123 @@ |
+#!/usr/bin/env python |
+# coding: utf-8 |
+ |
+# Copyright 2014 The Crashpad Authors. All rights reserved. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+import re |
+import subprocess |
+import sys |
+ |
+def FixUserImplementation(implementation): |
+ """Rewrites a MIG-generated user implementation (.c) file. |
+ |
+ Rewrites the file at |implementation| by adding “__attribute__((unused))” to |
+ the definition of any structure typedefed as “__Reply” by searching for the |
+ pattern unique to those structure definitions. These structures are in fact |
+ unused in the user implementation file, and this will trigger a |
+ -Wunused-local-typedefs warning in gcc unless removed or marked with the |
+ “unused” attribute. |
+ """ |
+ |
+ file = open(implementation, 'r+') |
+ contents = file.read() |
+ |
+ pattern = re.compile('^(\t} __Reply);$', re.MULTILINE) |
+ contents = pattern.sub(r'\1 __attribute__((unused));', contents) |
+ |
+ file.seek(0) |
+ file.truncate() |
+ file.write(contents) |
+ file.close() |
+ |
+def FixServerImplementation(implementation): |
+ """Rewrites a MIG-generated server implementation (.c) file. |
+ |
+ Rewrites the file at |implementation| by replacing “mig_internal” with |
+ “mig_external” on functions that begin with “__MIG_check__”. This makes these |
+ functions available to other callers outside this file from a linkage |
+ perspective. It then returns, as a list of lines, declarations that can be |
+ added to a header file, so that other files that include that header file will |
+ have access to these declarations from a compilation perspective. |
+ """ |
+ |
+ file = open(implementation, 'r+') |
+ contents = file.read() |
+ |
+ # Find interesting declarations. |
+ declaration_pattern = \ |
+ re.compile('^mig_internal (kern_return_t __MIG_check__.*)$', |
+ re.MULTILINE) |
+ declarations = declaration_pattern.findall(contents) |
+ |
+ # Remove “__attribute__((__unused__))” from the declarations, and call them |
+ # “mig_external” or “extern” depending on whether “mig_external” is defined. |
+ attribute_pattern = re.compile(r'__attribute__\(\(__unused__\)\) ') |
+ declarations = ['#ifdef mig_external\nmig_external\n#else\nextern\n#endif\n' + |
+ attribute_pattern.sub('', x) + |
+ ';\n' for x in declarations] |
+ |
+ # Rewrite the declarations in this file as “mig_external”. |
+ contents = declaration_pattern.sub(r'mig_external \1', contents); |
+ |
+ file.seek(0) |
+ file.truncate() |
+ file.write(contents) |
+ file.close() |
+ return declarations |
+ |
+def FixHeader(header, declarations=[]): |
+ """Rewrites a MIG-generated header (.h) file. |
+ |
+ Rewrites the file at |header| by placing it inside an “extern "C"” block, so |
+ that it declares things properly when included by a C++ compilation unit. |
+ |declarations| can be a list of additional declarations to place inside the |
+ “extern "C"” block after the original contents of |header|. |
+ """ |
+ |
+ file = open(header, 'r+') |
+ contents = file.read() |
+ declarations_text = ''.join(declarations) |
+ contents = '''\ |
+#ifdef __cplusplus |
+extern "C" { |
+#endif |
+ |
+%s |
+%s |
+#ifdef __cplusplus |
+} |
+#endif |
+''' % (contents, declarations_text) |
+ file.seek(0) |
+ file.truncate() |
+ file.write(contents) |
+ file.close() |
+ |
+def main(args): |
+ assert len(args) == 5 |
+ (defs_file, user_c, server_c, user_h, server_h) = args |
+ subprocess.check_call(['mig', |
+ '-user', user_c, |
+ '-server', server_c, |
+ '-header', user_h, |
+ '-sheader', server_h, |
+ defs_file]) |
+ FixUserImplementation(user_c) |
+ server_declarations = FixServerImplementation(server_c) |
+ FixHeader(user_h) |
+ FixHeader(server_h, server_declarations) |
+ |
+if __name__ == '__main__': |
+ sys.exit(main(sys.argv[1:])) |