1#===- gen-msvc-exports.py - Generate C API export file -------*- python -*--===# 2# 3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4# See https://llvm.org/LICENSE.txt for license information. 5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6# 7#===------------------------------------------------------------------------===# 8# 9# Generate an export file from a list of given LIB files. This only exports symbols 10# that start with LLVM, so it only exports the LLVM C API. 11# 12# To have CMake run this, set LLVM_BUILD_LLVM_C_DYLIB to on while 13# building on Windows. 14# 15# To run manually, build LLVM with Visual Studio, use a Command prompt 16# to navigate to the directory with the .lib files (Debug\lib etc). Then run 17# python C:\Path\To\gen-msvc-exports.py --nm ..\bin\llvm-nm.exe LLVM*.lib 18# 19# If you're generating a 32 bit DLL, use the `--underscore` flag. 20# If you want to use a different `llvm-nm` executable, pass the path 21# with the `--nm` flag. 22# 23# You can use the --output flag to set the name of the export file. 24# 25#===------------------------------------------------------------------------===# 26from tempfile import mkstemp 27from contextlib import contextmanager 28from subprocess import check_call 29import argparse 30import os 31import re 32 33 34_UNDERSCORE_REGEX = { 35 False: re.compile(r"^\w+\s+T\s+(LLVM.*)$"), 36 True: re.compile(r"^\w+\s+T\s+_(LLVM.*)$") 37} 38 39 40@contextmanager 41def removing(path): 42 try: 43 yield path 44 finally: 45 os.unlink(path) 46 47 48def touch_tempfile(*args, **kwargs): 49 fd, name = mkstemp(*args, **kwargs) 50 os.close(fd) 51 return name 52 53 54def gen_llvm_c_export(output, underscore, libs, nm): 55 """Generate the export file for the LLVM-C DLL. 56 57 Run `nm` for each lib in `libs`, and output an export file 58 to `output`. If `underscore` is true, symbols will 59 be assumed to be prefixed with an underscore. 60 """ 61 with removing(touch_tempfile(prefix='dumpout', suffix='.txt')) as dumpout: 62 63 # Get the right regex. 64 p = _UNDERSCORE_REGEX[underscore] 65 66 with open(output, 'w+t') as output_f: 67 68 # For each lib get the LLVM* functions it exports. 69 for lib in libs: 70 # Call dumpbin. 71 with open(dumpout, 'w+t') as dumpout_f: 72 check_call([nm, '-g', lib], stdout=dumpout_f) 73 74 # Get the matching lines. 75 with open(dumpout) as dumpbin: 76 for line in dumpbin: 77 m = p.match(line) 78 if m is not None: 79 output_f.write(m.group(1) + '\n') 80 81 82def main(): 83 parser = argparse.ArgumentParser('gen-msvc-exports') 84 85 parser.add_argument( 86 '-i', '--libsfile', help='file with list of libs, new line separated', 87 action='store', default=None 88 ) 89 parser.add_argument( 90 '-o', '--output', help='output filename', default='LLVM-C.exports' 91 ) 92 parser.add_argument('-u', '--underscore', 93 help='labels are prefixed with an underscore (use for 32 bit DLLs)', 94 action='store_true' 95 ) 96 parser.add_argument( 97 '--nm', help='path to the llvm-nm executable', default='llvm-nm' 98 ) 99 parser.add_argument( 100 'libs', metavar='LIBS', nargs='*', help='list of libraries to generate export from' 101 ) 102 103 ns = parser.parse_args() 104 105 libs = ns.libs 106 107 # Add if we where given a libsfile add it to the libs. 108 if ns.libsfile: 109 with open(ns.libsfile) as f: 110 libs.extend(f.read().splitlines()) 111 112 gen_llvm_c_export(ns.output, ns.underscore, libs, ns.nm) 113 114 115if __name__ == '__main__': 116 main() 117