Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: build/win/importlibs/create_importlib_win.py

Issue 12295040: Stop delay loading user32.dll from chrome.dll on x86/Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Make sure both MSVS and ninja builds link correctly. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « build/win/importlibs/create_import_lib.gypi ('k') | build/win/importlibs/filter_export_list.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5 #
6 """Creates an import library from an import description file."""
7 import ast
8 import logging
9 import optparse
10 import os
11 import os.path
12 import shutil
13 import subprocess
14 import sys
15 import tempfile
16
17
18 _USAGE = """\
19 Usage: %prog [options] [imports-file]
20
21 Creates an import library from imports-file.
22
23 Note: this script uses the microsoft assembler (ml.exe) and the library tool
24 (lib.exe), both of which must be in path.
25 """
26
27
28 _ASM_STUB_HEADER = """\
29 ; This file is autogenerated by create_importlib_win.py, do not edit.
30 .386
31 .MODEL FLAT, C
32 .CODE
33
34 ; Stubs to provide mangled names to lib.exe for the
35 ; correct generation of import libs.
36 """
37
38
39 _DEF_STUB_HEADER = """\
40 ; This file is autogenerated by create_importlib_win.py, do not edit.
41
42 ; Export declarations for generating import libs.
43 """
44
45
46 _LOGGER = logging.getLogger()
47
48
49
50 class _Error(Exception):
51 pass
52
53
54 class _ImportLibraryGenerator(object):
55 def __init__(self, temp_dir):
56 self._temp_dir = temp_dir
57
58 def _Shell(self, cmd, **kw):
59 ret = subprocess.call(cmd, **kw)
60 _LOGGER.info('Running "%s" returned %d.', cmd, ret)
61 if ret != 0:
62 raise _Error('Command "%s" returned %d.' % (cmd, ret))
63
64 def _ReadImportsFile(self, imports_file):
65 # Slurp the imports file.
66 return ast.literal_eval(open(imports_file).read())
67
68 def _WriteStubsFile(self, import_names, output_file):
69 output_file.write(_ASM_STUB_HEADER)
70
71 for name in import_names:
72 output_file.write('%s PROC\n' % name)
73 output_file.write('%s ENDP\n' % name)
74
75 output_file.write('END\n')
76
77 def _WriteDefFile(self, dll_name, import_names, output_file):
78 output_file.write(_DEF_STUB_HEADER)
79 output_file.write('NAME %s\n' % dll_name)
80 output_file.write('EXPORTS\n')
81 for name in import_names:
82 name = name.split('@')[0]
83 output_file.write(' %s\n' % name)
84
85 def _CreateObj(self, dll_name, imports):
86 """Writes an assembly file containing empty declarations.
87
88 For each imported function of the form:
89
90 AddClipboardFormatListener@4 PROC
91 AddClipboardFormatListener@4 ENDP
92
93 The resulting object file is then supplied to lib.exe with a .def file
94 declaring the corresponding non-adorned exports as they appear on the
95 exporting DLL, e.g.
96
97 EXPORTS
98 AddClipboardFormatListener
99
100 In combination, the .def file and the .obj file cause lib.exe to generate
101 an x86 import lib with public symbols named like
102 "__imp__AddClipboardFormatListener@4", binding to exports named like
103 "AddClipboardFormatListener".
104
105 All of this is perpetrated in a temporary directory, as the intermediate
106 artifacts are quick and easy to produce, and of no interest to anyone
107 after the fact."""
108
109 # Create an .asm file to provide stdcall-like stub names to lib.exe.
110 asm_name = dll_name + '.asm'
111 _LOGGER.info('Writing asm file "%s".', asm_name)
112 with open(os.path.join(self._temp_dir, asm_name), 'wb') as stubs_file:
113 self._WriteStubsFile(imports, stubs_file)
114
115 # Invoke on the assembler to compile it to .obj.
116 obj_name = dll_name + '.obj'
117 cmdline = ['ml.exe', '/nologo', '/c', asm_name, '/Fo', obj_name]
118 self._Shell(cmdline, cwd=self._temp_dir)
119
120 return obj_name
121
122 def _CreateImportLib(self, dll_name, imports, architecture, output_file):
123 """Creates an import lib binding imports to dll_name for architecture.
124
125 On success, writes the import library to output file.
126 """
127 obj_file = None
128
129 # For x86 architecture we have to provide an object file for correct
130 # name mangling between the import stubs and the exported functions.
131 if architecture == 'x86':
132 obj_file = self._CreateObj(dll_name, imports)
133
134 # Create the corresponding .def file. This file has the non stdcall-adorned
135 # names, as exported by the destination DLL.
136 def_name = dll_name + '.def'
137 _LOGGER.info('Writing def file "%s".', def_name)
138 with open(os.path.join(self._temp_dir, def_name), 'wb') as def_file:
139 self._WriteDefFile(dll_name, imports, def_file)
140
141 # Invoke on lib.exe to create the import library.
142 # We generate everything into the temporary directory, as the .exp export
143 # files will be generated at the same path as the import library, and we
144 # don't want those files potentially gunking the works.
145 dll_base_name, ext = os.path.splitext(dll_name)
146 lib_name = dll_base_name + '.lib'
147 cmdline = ['lib.exe',
148 '/machine:%s' % architecture,
149 '/def:%s' % def_name,
150 '/out:%s' % lib_name]
151 if obj_file:
152 cmdline.append(obj_file)
153
154 self._Shell(cmdline, cwd=self._temp_dir)
155
156 # Copy the .lib file to the output directory.
157 shutil.copyfile(os.path.join(self._temp_dir, lib_name), output_file)
158 _LOGGER.info('Created "%s".', output_file)
159
160 def CreateImportLib(self, imports_file, output_file):
161 # Read the imports file.
162 imports = self._ReadImportsFile(imports_file)
163
164 # Creates the requested import library in the output directory.
165 self._CreateImportLib(imports['dll_name'],
166 imports['imports'],
167 imports.get('architecture', 'x86'),
168 output_file)
169
170
171 def main():
172 parser = optparse.OptionParser(usage=_USAGE)
173 parser.add_option('-o', '--output-file',
174 help='Specifies the output file path.')
175 parser.add_option('-k', '--keep-temp-dir',
176 action='store_true',
177 help='Keep the temporary directory.')
178 parser.add_option('-v', '--verbose',
179 action='store_true',
180 help='Verbose logging.')
181
182 options, args = parser.parse_args()
183
184 print args
185 if len(args) != 1:
186 parser.error('You must provide an imports file.')
187
188 if not options.output_file:
189 parser.error('You must provide an output file.')
190
191 options.output_file = os.path.abspath(options.output_file)
192
193 if options.verbose:
194 logging.basicConfig(level=logging.INFO)
195 else:
196 logging.basicConfig(level=logging.WARN)
197
198
199 temp_dir = tempfile.mkdtemp()
200 _LOGGER.info('Created temporary directory "%s."', temp_dir)
201 try:
202 # Create a generator and create the import lib.
203 generator = _ImportLibraryGenerator(temp_dir)
204
205 ret = generator.CreateImportLib(args[0], options.output_file)
206 except Exception, e:
207 _LOGGER.exception('Failed to create imports.')
208 ret = 1
209 finally:
210 if not options.keep_temp_dir:
211 shutil.rmtree(temp_dir)
212 _LOGGER.info('Deleted temporary directory "%s."', temp_dir)
213
214 return ret
215
216
217 if __name__ == '__main__':
218 sys.exit(main())
OLDNEW
« no previous file with comments | « build/win/importlibs/create_import_lib.gypi ('k') | build/win/importlibs/filter_export_list.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698