245 lines · python
1#!/usr/bin/env python32 3#4# //===----------------------------------------------------------------------===//5# //6# // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.7# // See https://llvm.org/LICENSE.txt for license information.8# // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception9# //10# //===----------------------------------------------------------------------===//11#12 13import argparse14import os15import re16import sys17from libomputils import error, ScriptError, print_error_line18 19 20class DllExports(object):21 def __init__(self):22 self.filename = None23 self.exports = {}24 self.ordinals = set([])25 26 def add_uppercase_entries(self):27 # Ignored entries are C/C++ only functions28 ignores = [29 "omp_alloc",30 "omp_free",31 "omp_calloc",32 "omp_realloc",33 "omp_aligned_alloc",34 "omp_aligned_calloc",35 ]36 keys = list(self.exports.keys())37 for entry in keys:38 info = self.exports[entry]39 if info["obsolete"] or info["is_data"] or entry in ignores:40 continue41 if entry.startswith("omp_") or entry.startswith("kmp_"):42 newentry = entry.upper()43 if info["ordinal"]:44 newordinal = info["ordinal"] + 100045 else:46 newordinal = None47 self.exports[newentry] = {48 "obsolete": False,49 "is_data": False,50 "ordinal": newordinal,51 }52 53 @staticmethod54 def create(inputFile, defs=None):55 """Creates DllExports object from inputFile"""56 dllexports = DllExports()57 dllexports.filename = inputFile58 # Create a (possibly empty) list of definitions59 if defs:60 definitions = set(list(defs))61 else:62 definitions = set([])63 # Different kinds of lines to parse64 kw = r"[a-zA-Z_][a-zA-Z0-9_]*"65 ifndef = re.compile(r"%ifndef\s+({})".format(kw))66 ifdef = re.compile(r"%ifdef\s+({})".format(kw))67 endif = re.compile(r"%endif")68 export = re.compile(r"(-)?\s*({0})(=({0}))?(\s+([0-9]+|DATA))?".format(kw))69 70 def err(fil, num, msg):71 error("{}: {}: {}".format(fil, num, msg))72 73 defs_stack = []74 with open(inputFile) as f:75 for lineNumber, line in enumerate(f):76 line = line.strip()77 # Skip empty lines78 if not line:79 continue80 # Skip comment lines81 if line.startswith("#"):82 continue83 # Encountered %ifndef DEF84 m = ifndef.search(line)85 if m:86 defs_stack.append(m.group(1) not in definitions)87 continue88 # Encountered %ifdef DEF89 m = ifdef.search(line)90 if m:91 defs_stack.append(m.group(1) in definitions)92 continue93 # Encountered %endif94 m = endif.search(line)95 if m:96 if not defs_stack:97 err(inputFile, lineNumber, "orphan %endif directive")98 defs_stack.pop()99 continue100 # Skip lines when not all %ifdef or %ifndef are true101 if defs_stack and not all(defs_stack):102 continue103 # Encountered an export line104 m = export.search(line)105 if m:106 obsolete = m.group(1) is not None107 entry = m.group(2)108 rename = m.group(4)109 ordinal = m.group(6)110 if entry in dllexports.exports:111 err(112 inputFile,113 lineNumber,114 "already specified entry: {}".format(entry),115 )116 if rename:117 entry += "={}".format(rename)118 # No ordinal number nor DATA specified119 if not ordinal:120 ordinal = None121 is_data = False122 # DATA ordinal123 elif ordinal == "DATA":124 ordinal = None125 is_data = True126 # Regular ordinal number127 else:128 is_data = False129 try:130 ordinal = int(ordinal)131 except:132 err(133 inputFile,134 lineNumber,135 "Bad ordinal value: {}".format(ordinal),136 )137 if ordinal >= 1000 and (138 entry.startswith("omp_") or entry.startswith("kmp_")139 ):140 err(141 inputFile,142 lineNumber,143 "Ordinal of user-callable entry must be < 1000",144 )145 if ordinal >= 1000 and ordinal < 2000:146 err(147 inputFile,148 lineNumber,149 "Ordinals between 1000 and 1999 are reserved.",150 )151 if ordinal in dllexports.ordinals:152 err(153 inputFile,154 lineNumber,155 "Ordinal {} has already been used.".format(ordinal),156 )157 dllexports.exports[entry] = {158 "ordinal": ordinal,159 "obsolete": obsolete,160 "is_data": is_data,161 }162 continue163 err(164 inputFile,165 lineNumber,166 'Cannot parse line:{}"{}"'.format(os.linesep, line),167 )168 if defs_stack:169 error("syntax error: Unterminated %if directive")170 return dllexports171 172 173def generate_def(dllexports, f, no_ordinals=False, name=None):174 """Using dllexports data, write the exports to file, f"""175 if name:176 f.write("LIBRARY {}\n".format(name))177 f.write("EXPORTS\n")178 for entry in sorted(list(dllexports.exports.keys())):179 info = dllexports.exports[entry]180 if info["obsolete"]:181 continue182 f.write(" {:<40} ".format(entry))183 if info["is_data"]:184 f.write("DATA\n")185 elif no_ordinals or not info["ordinal"]:186 f.write("\n")187 else:188 f.write("@{}\n".format(info["ordinal"]))189 190 191def main():192 parser = argparse.ArgumentParser(193 description="Reads input file of dllexports, processes conditional"194 " directives, checks content for consistency, and generates"195 " output file suitable for linker"196 )197 parser.add_argument(198 "-D",199 metavar="DEF",200 action="append",201 dest="defs",202 help="Define a variable. Can specify" " this more than once.",203 )204 parser.add_argument(205 "--no-ordinals",206 action="store_true",207 help="Specify that no ordinal numbers should be generated",208 )209 parser.add_argument(210 "-n",211 "--name",212 dest="name",213 help="Specify library name for def file LIBRARY statement",214 )215 parser.add_argument(216 "-o",217 "--output",218 metavar="FILE",219 dest="output",220 help="Specify output file name. If not specified," " output is sent to stdout",221 )222 parser.add_argument("dllexports", help="The input file describing dllexports")223 commandArgs = parser.parse_args()224 defs = set([])225 if commandArgs.defs:226 defs = set(commandArgs.defs)227 dllexports = DllExports.create(commandArgs.dllexports, defs)228 dllexports.add_uppercase_entries()229 try:230 output = open(commandArgs.output, "w") if commandArgs.output else sys.stdout231 generate_def(dllexports, output, commandArgs.no_ordinals, commandArgs.name)232 finally:233 if commandArgs.output:234 output.close()235 236 237if __name__ == "__main__":238 try:239 main()240 except ScriptError as e:241 print_error_line(str(e))242 sys.exit(1)243 244# end of file245