aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/contrib/cmake/tools/create_def_file.py
diff options
context:
space:
mode:
Diffstat (limited to 'tensorflow/contrib/cmake/tools/create_def_file.py')
-rw-r--r--tensorflow/contrib/cmake/tools/create_def_file.py134
1 files changed, 134 insertions, 0 deletions
diff --git a/tensorflow/contrib/cmake/tools/create_def_file.py b/tensorflow/contrib/cmake/tools/create_def_file.py
new file mode 100644
index 0000000000..950c8f79bc
--- /dev/null
+++ b/tensorflow/contrib/cmake/tools/create_def_file.py
@@ -0,0 +1,134 @@
+# Copyright 2017 The TensorFlow 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.
+# ==============================================================================
+
+"""
+create_def_file.py - tool to create a windows def file to export
+symbols from tensorflow.dll to enable tf.load_library().
+Because the linker allows only 64K symbols to be exported per dll
+we filter the symbols down to the essentials. The regular expressions
+we use for this are specific to tensorflow.
+
+TODO: this works fine but there is an issue with exporting
+'const char * const' and importing it from a user_ops. The problem is
+on the importing end and using __declspec(dllimport) works around it.
+"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import argparse
+import io
+import os
+import re
+import sys
+import tempfile
+from subprocess import Popen, PIPE
+
+# External tools we use that come with visual studio sdk and
+# we assume that the caller has the correct PATH to the sdk
+UNDNAME = "undname.exe"
+DUMPBIN = "dumpbin.exe"
+
+# Exclude if matched
+EXCLUDE_RE = re.compile(r"deleting destructor|::internal::")
+
+# Include if matched before exclude
+INCLUDEPRE_RE = re.compile(r"tensorflow::internal::LogMessage|" +
+ r"tensorflow::internal::CheckOpMessageBuilder")
+
+# Include if matched after exclude
+INCLUDE_RE = re.compile(r"^(TF_\w*)$|" +
+ r"tensorflow::|" +
+ r"functor::|" +
+ r"perftools::gputools")
+
+
+def get_args():
+ """Parse command line."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--input", help="input library", required=True)
+ parser.add_argument("--output", help="output deffile", required=True)
+ args = parser.parse_args()
+ return args
+
+
+def main():
+ """main."""
+ args = get_args()
+
+ # Pipe dumpbin to extract all linkable symbols from a lib.
+ # Good symbols are collected in candidates and also written to
+ # a temp file.
+ candidates = []
+ tmpfile = tempfile.NamedTemporaryFile(mode="w", delete=False)
+ proc = Popen([DUMPBIN, "/nologo", "/linkermember:1", args.input], stdout=PIPE)
+ for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
+ cols = line.split()
+ if len(cols) < 2:
+ continue
+ sym = cols[1]
+ tmpfile.file.write(sym + "\n")
+ candidates.append(sym)
+ tmpfile.file.close()
+ exit_code = proc.wait()
+ if exit_code != 0:
+ print("{} failed, exit={}".format(DUMPBIN, exit_code))
+ return exit_code
+
+ # Run the symbols through undname to get their undecorated name
+ # so we can filter on something readable.
+ with open(args.output, "w") as def_fp:
+ # track dupes
+ taken = set()
+
+ # Header for the def file. Since the tensorflow.dll is actually called
+ # _pywrap_tensorflow.pyd in the python wheel, hint that in the def file.
+ def_fp.write("LIBRARY _pywrap_tensorflow_internal.pyd\n")
+ def_fp.write("EXPORTS\n")
+ def_fp.write("\t ??1OpDef@tensorflow@@UEAA@XZ\n")
+
+ # Each symbols returned by undname matches the same position in candidates.
+ # We compare on undname but use the decorated name from candidates.
+ dupes = 0
+ proc = Popen([UNDNAME, tmpfile.name], stdout=PIPE)
+ for idx, line in enumerate(io.TextIOWrapper(proc.stdout, encoding="utf-8")):
+ decorated = candidates[idx]
+ if decorated in taken:
+ # Symbol is already in output, done.
+ dupes += 1
+ continue
+
+ if not INCLUDEPRE_RE.search(line):
+ if EXCLUDE_RE.search(line):
+ continue
+ if not INCLUDE_RE.search(line):
+ continue
+
+ def_fp.write("\t" + decorated + "\n")
+ taken.add(decorated)
+ exit_code = proc.wait()
+ if exit_code != 0:
+ print("{} failed, exit={}".format(UNDNAME, exit_code))
+ return exit_code
+
+ os.unlink(tmpfile.name)
+
+ print("symbols={}, taken={}, dupes={}"
+ .format(len(candidates), len(taken), dupes))
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())