David Bolvansky | ab2cbad | 2018-08-07 15:54:50 +0000 | [diff] [blame] | 1 | #===- gen-msvc-exports.py - Generate C API export file -------*- python -*--===# |
| 2 | # |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 |
David Bolvansky | ab2cbad | 2018-08-07 15:54:50 +0000 | [diff] [blame] | 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 | #===------------------------------------------------------------------------===# |
| 26 | from tempfile import mkstemp |
| 27 | from contextlib import contextmanager |
| 28 | from subprocess import check_call |
| 29 | import argparse |
| 30 | import os |
| 31 | import 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 |
| 41 | def removing(path): |
| 42 | try: |
| 43 | yield path |
| 44 | finally: |
| 45 | os.unlink(path) |
| 46 | |
| 47 | |
| 48 | def touch_tempfile(*args, **kwargs): |
| 49 | fd, name = mkstemp(*args, **kwargs) |
| 50 | os.close(fd) |
| 51 | return name |
| 52 | |
| 53 | |
| 54 | def 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 | |
| 82 | def main(): |
| 83 | parser = argparse.ArgumentParser('gen-msvc-exports') |
| 84 | |
| 85 | parser.add_argument( |
Serge Guelton | d2f2f33 | 2019-03-19 09:14:09 +0000 | [diff] [blame] | 86 | '-i', '--libsfile', help='file with list of libs, new line separated', |
| 87 | action='store', default=None |
| 88 | ) |
| 89 | parser.add_argument( |
David Bolvansky | ab2cbad | 2018-08-07 15:54:50 +0000 | [diff] [blame] | 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( |
Serge Guelton | d2f2f33 | 2019-03-19 09:14:09 +0000 | [diff] [blame] | 100 | 'libs', metavar='LIBS', nargs='*', help='list of libraries to generate export from' |
David Bolvansky | ab2cbad | 2018-08-07 15:54:50 +0000 | [diff] [blame] | 101 | ) |
| 102 | |
| 103 | ns = parser.parse_args() |
| 104 | |
Serge Guelton | d2f2f33 | 2019-03-19 09:14:09 +0000 | [diff] [blame] | 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) |
David Bolvansky | ab2cbad | 2018-08-07 15:54:50 +0000 | [diff] [blame] | 113 | |
| 114 | |
| 115 | if __name__ == '__main__': |
| 116 | main() |