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

Side by Side Diff: chrome/imports/build_import_libraries.py

Issue 12210017: Start of build config for custom user32 import libs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Implement the delay load hook. Created 7 years, 10 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
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 # A utility script to create minimal import libs from an import description
M-A Ruel 2013/02/07 21:14:30 Make that a docstring
7 # file.
8 import ast
9 import logging
10 import optparse
11 import os
12 import os.path
13 import shutil
14 import subprocess
15 import sys
16 import tempfile
17
18
19 _USAGE = """\
20 Usage: %prog [options] [imports-file]
21
22 Creates a pair of import libraries from imports-file.
M-A Ruel 2013/02/07 21:14:30 Often, I make this the docstring and then use: op
23
24 Note: this script uses the microsoft assembler (ml.exe) and the library tool
25 (lib.exe), both of which must be in path.
26 """
27
28
29 _ASM_STUB_HEADER = """\
30 ; This file is autogenerated, do not edit.
31 .386
32 .MODEL FLAT, C
33 .CODE
34
35 ; Stubs to provide mangled names to lib.exe for the
36 ; correct generation of import libs.
37 """
38
39
40 _DEF_STUB_HEADER = """\
41 ; This file is autogenerated, do not edit.
42
43 ; Export declarations for generating import libs.
44 """
45
46
47 _LOGGER = logging.getLogger()
48
49
50
51 class _Error(Exception):
52 pass
53
54
55 def _Shell(cmd, **kw):
56 ret = subprocess.call(cmd, **kw)
57 _LOGGER.info('Running "%s" returned %d.', cmd, ret)
58 if ret != 0:
59 raise _Error('Command "%s" returned %d.' % (cmd, ret))
60
61
62 def _ReadImportsFile(imports_file):
63 # Slurp the imports file.
64 return ast.literal_eval(open(imports_file).read())
65
66
67 def _WriteStubsFile(import_names, output_file):
68 output_file.write(_ASM_STUB_HEADER)
69
70 for name in import_names:
71 output_file.write('%s PROC\n' % name)
72 output_file.write('%s ENDP\n' % name)
73
74 output_file.write('END\n')
75
76
77 def _WriteDefFile(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
86 def _CreateImportLib(dll_name, imports, temp_dir, output_file):
87 # For each library write an assmbly file containing empty declarations
M-A Ruel 2013/02/07 21:14:30 assembly And I'd make the whole thing a docstring
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, these two things cause lib.exe to generate an import lib
101 # with public symbols named like "__imp__AddClipboardFormatListener@4",
102 # binding to names like "AddClipboardFormatListener".
103 #
104 # All of this is perpetrated in a temporary directory, as the intermediate
105 # artifacts are quick and easy to produce, and of no interest to anyone
106 # after the fact.
107
108 # Create an .asm file to provide stdcall-like stub names to lib.exe.
109 asm_name = dll_name + '.asm'
110 _LOGGER.info('Writing asm file "%s".', asm_name)
111 with open(os.path.join(temp_dir, asm_name), 'w') as stubs_file:
112 _WriteStubsFile(imports, stubs_file)
113
114 # Invoke on the assembler to compile it to .obj.
115 obj_name = dll_name + '.obj'
116 cmdline = ['ml.exe', '/nologo', '/c', asm_name, '/Fo', obj_name]
117 _Shell(cmdline, cwd=temp_dir)
118
119 # Create the corresponding .def file. This file has the non stdcall-adorned
120 # names, that need to correlate to the ASM above.
121 def_name = dll_name + '.def'
122 _LOGGER.info('Writing def file "%s".', def_name)
123 with open(os.path.join(temp_dir, def_name), 'w') as def_file:
124 _WriteDefFile(dll_name, imports, def_file)
125
126 # Invoke on lib.exe to create the import library.
127 # We generate everything into the temporary directory, as the .exp export
128 # files will be generated at the same path as the import library, and we
129 # don't want those files potentially gunking the works.
130 dll_base_name, ext = os.path.splitext(dll_name)
131 lib_name = dll_base_name + '.lib'
132 cmdline = ['lib.exe',
133 obj_name,
134 '/def:%s' % def_name,
135 '/out:%s' % lib_name]
136
137 _Shell(cmdline, cwd=temp_dir)
138
139 # Copy the .lib file to the output directory.
140 shutil.copyfile(os.path.join(temp_dir, lib_name), output_file)
141 _LOGGER.info('Created "%s".', output_file)
142
143
144 def _CreateImportLibs(imports, temp_dir, output_dir):
145 dll_name = imports['dll_name']
146 dll_base_name, ext = os.path.splitext(dll_name)
147
148 # Creates an import library for the hard imports named DLL-imports.lib,
149 # e.g. user32-imports.lib. This import library will bind to dll_name.
150 _CreateImportLib(dll_name,
151 imports['imports'],
152 temp_dir,
153 os.path.join(output_dir, dll_base_name + '-imports.lib'))
154 # Creates an import library for the delay imports named DLL-delay.lib,
155 # e.g. user32-delay.lib. This import library will bind to dll_name-delay.dll,
156 # e.g. user32-delay.dll.
157 _CreateImportLib(dll_base_name + '-delay' + ext,
158 imports['delay_imports'],
159 temp_dir,
160 os.path.join(output_dir, dll_base_name + '-delay.lib'))
161
162
163 def main():
164 parser = optparse.OptionParser(usage=_USAGE)
165 parser.add_option('-o', '--output-dir',
166 dest='output_dir',
167 help='Specifies the output directory.')
168 parser.add_option('-k', '--keep-temp-dir',
169 dest='keep_temp_dir',
170 action='store_true',
171 default=False,
172 help='Keep the temporary directory.')
173 parser.add_option('-v', '--verbose',
174 dest='verbose',
175 action='store_true',
176 default=False,
177 help='Verbose logging.')
178
179 options, args = parser.parse_args()
180 if len(args) != 1:
181 parser.error('Must provide an imports file.')
182
183 if not options.output_dir:
184 parser.error('Must provide an output directory.')
185
186 options.output_dir = os.path.abspath(options.output_dir)
187
188 if options.verbose:
189 logging.basicConfig(level=logging.INFO)
190 else:
191 logging.basicConfig(level=logging.WARN)
192
193 # Read the imports file.
194 imports = _ReadImportsFile(args[0])
195
196 temp_dir = tempfile.mkdtemp()
197 _LOGGER.info('Created temporary directory "%s."', temp_dir)
198 try:
199 ret = _CreateImportLibs(imports, temp_dir, options.output_dir)
200 except Exception, e:
201 _LOGGER.exception('Failed to create imports.')
202 ret = 1
203 finally:
204 if not options.keep_temp_dir:
205 shutil.rmtree(temp_dir)
206 _LOGGER.info('Deleted temporary directory "%s."', temp_dir)
207
208 return ret
209
210
211 if __name__ == '__main__':
212 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698