OLD | NEW |
---|---|
(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 """ | |
7 Creates a library loader (a header and implementation file), | |
8 which is a wrapper for dlopen or direct linking with given library. | |
9 | |
10 The loader makes it possible to have the same client code for both cases, | |
11 and also makes it easier to write code using dlopen (and also provides | |
12 a standard way to do so, and limits the ugliness just to generated files). | |
13 | |
14 For more info refer to http://crbug.com/162733 . | |
15 """ | |
16 | |
17 | |
18 import optparse | |
19 import os.path | |
20 import re | |
21 import sys | |
22 | |
23 | |
24 HEADER_TEMPLATE = """// This is generated file. Do not modify directly. | |
25 // Path to the code generator: %(generator_path)s . | |
26 | |
27 #ifndef %(unique_prefix)s_H_ | |
28 #define %(unique_prefix)s_H_ | |
29 | |
30 %(wrapped_header_include)s | |
31 | |
32 #include <string> | |
33 | |
34 #include "base/basictypes.h" | |
35 #include "base/compiler_specific.h" | |
36 #ifdef %(unique_prefix)s_DLOPEN | |
37 #include "base/native_library.h" | |
38 #endif | |
39 | |
40 class %(class_name)s { | |
41 public: | |
42 %(class_name)s(); | |
43 ~%(class_name)s(); | |
44 | |
45 bool Load(const std::string& library_name) WARN_UNUSED_RESULT; | |
46 | |
47 %(member_decls)s | |
48 | |
49 private: | |
50 #ifdef %(unique_prefix)s_DLOPEN | |
51 base::NativeLibrary library_; | |
52 #endif | |
53 | |
54 bool loaded_; | |
55 | |
56 DISALLOW_COPY_AND_ASSIGN(%(class_name)s); | |
57 }; | |
58 | |
59 #endif // %(unique_prefix)s_H_ | |
60 """ | |
61 | |
62 | |
63 HEADER_MEMBER_TEMPLATE = """ typeof(&::%(function_name)s) %(function_name)s; | |
64 """ | |
65 | |
66 | |
67 IMPL_TEMPLATE = """// This is generated file. Do not modify directly. | |
68 // Path to the code generator: %(generator_path)s . | |
69 | |
70 #include "%(generated_header_name)s" | |
71 | |
72 #include "base/file_path.h" | |
73 #include "base/logging.h" | |
74 | |
75 %(class_name)s::%(class_name)s() : loaded_(false) { | |
76 } | |
77 | |
78 %(class_name)s::~%(class_name)s() { | |
79 #ifdef %(unique_prefix)s_DLOPEN | |
80 if (loaded_) | |
81 base::UnloadNativeLibrary(library_); | |
82 #endif | |
83 } | |
84 | |
85 bool %(class_name)s::Load(const std::string& library_name) { | |
86 if (loaded_) { | |
87 NOTREACHED(); | |
88 return false; | |
89 } | |
90 | |
91 #ifdef %(unique_prefix)s_DLOPEN | |
92 library_ = base::LoadNativeLibrary(FilePath(library_name), NULL); | |
93 if (library_) { | |
94 #endif | |
95 | |
96 %(member_init)s | |
97 | |
98 loaded_ = true; | |
99 return true; | |
100 #ifdef %(unique_prefix)s_DLOPEN | |
101 } | |
102 | |
103 return false; | |
104 #endif | |
105 } | |
106 """ | |
107 | |
108 IMPL_MEMBER_TEMPLATE = """ | |
109 #ifdef %(unique_prefix)s_DLOPEN | |
110 this->%(function_name)s = | |
111 reinterpret_cast<typeof(this->%(function_name)s)>( | |
112 base::GetFunctionPointerFromNativeLibrary( | |
113 library_, "%(function_name)s")); | |
114 if (!this->%(function_name)s) { | |
Mark Mentovai
2012/11/27 21:01:18
If you’re using the dlopen-at-runtime variant, a f
Paweł Hajdan Jr.
2012/11/27 22:27:24
Done.
| |
115 base::UnloadNativeLibrary(library_); | |
Mark Mentovai
2012/11/27 21:01:18
Clear loaded_? Zero the function pointers?
Paweł Hajdan Jr.
2012/11/27 22:27:24
Done.
| |
116 return false; | |
117 } | |
118 #else | |
119 this->%(function_name)s = &::%(function_name)s; | |
Mark Mentovai
2012/11/27 21:01:18
In this case, I think it’s better to just have the
Paweł Hajdan Jr.
2012/11/27 22:27:24
Hmm, what's the advantage? And then, should I also
Mark Mentovai
2012/11/27 23:09:11
Paweł Hajdan Jr. wrote:
Paweł Hajdan Jr.
2012/11/28 01:05:51
Not sure if that's worth it for possible weird int
| |
120 #endif | |
121 """ | |
122 | |
123 | |
124 def main(): | |
125 parser = optparse.OptionParser() | |
126 parser.add_option('--name') | |
127 parser.add_option('--output') | |
128 parser.add_option('--header') | |
129 | |
130 parser.add_option('--use-extern-c', action='store_true', default=False) | |
131 parser.add_option('--link-directly', type=int, default=0) | |
132 | |
133 options, args = parser.parse_args() | |
134 | |
135 if not options.name: | |
136 parser.error('Missing --name parameter') | |
137 if not options.output: | |
138 parser.error('Missing --output parameter') | |
139 if not options.header: | |
140 parser.error('Missing --header paramater') | |
141 if not args: | |
142 parser.error('No function names specified') | |
143 | |
144 # Make sure we are always dealing with an absolute path | |
145 # to avoid issues caused by different relative path roots. | |
146 options.output = os.path.abspath(options.output) | |
147 | |
148 # Create a unique prefix, e.g. for header guards. | |
149 unique_prefix = re.sub(r'[\W]', '_', options.output).upper(); | |
Mark Mentovai
2012/11/27 21:01:18
Because options.output is likely an absolute path
Paweł Hajdan Jr.
2012/11/27 22:27:24
Done.
| |
150 | |
151 member_decls = [] | |
152 member_init = [] | |
153 for fn in args: | |
154 member_decls += HEADER_MEMBER_TEMPLATE % { | |
155 'function_name': fn, | |
156 'unique_prefix': unique_prefix | |
157 } | |
158 member_init += IMPL_MEMBER_TEMPLATE % { | |
159 'function_name': fn, | |
160 'unique_prefix': unique_prefix | |
161 } | |
162 | |
163 wrapped_header_include = '#include %s' % options.header | |
164 | |
165 # Some libraries (e.g. libpci) have headers that cannot be included | |
166 # without extern "C", otherwise they cause the link to fail. | |
167 if options.use_extern_c: | |
168 wrapped_header_include = 'extern "C" {\n%s\n}\n' % wrapped_header_include | |
Mark Mentovai
2012/11/27 21:01:18
You’re losing a TODO in the existing code that sai
Paweł Hajdan Jr.
2012/11/27 22:27:24
Done.
| |
169 | |
170 # It seems cleaner just to have a single #define here and #ifdefs in bunch | |
171 # of places, rather than having a different set of templates, duplicating | |
172 # or complicating more code. | |
173 if options.link_directly == 0: | |
174 wrapped_header_include += '#define %s_DLOPEN\n' % unique_prefix | |
Mark Mentovai
2012/11/27 21:01:18
I don’t agree with this 100%. I think I’d be happi
Paweł Hajdan Jr.
2012/11/27 22:27:24
Done.
| |
175 | |
176 # Make it easier for people to find the code generator just in case. | |
177 # Doing it this way is more maintainable, because it's going to work | |
178 # even if file gets moved without updating the contents. | |
179 generator_path = os.path.abspath(__file__) | |
180 | |
181 header_contents = HEADER_TEMPLATE % { | |
182 'generator_path': generator_path, | |
183 'unique_prefix': unique_prefix, | |
184 'wrapped_header_include': wrapped_header_include, | |
185 'class_name': options.name, | |
186 'member_decls': ''.join(member_decls), | |
187 } | |
188 | |
189 impl_contents = IMPL_TEMPLATE % { | |
190 'generator_path': generator_path, | |
191 'unique_prefix': unique_prefix, | |
192 'generated_header_name': options.output + '.h', | |
193 'class_name': options.name, | |
194 'member_init': ''.join(member_init), | |
195 } | |
196 | |
197 header_file = open(options.output + '.h', 'w') | |
198 try: | |
199 header_file.write(header_contents) | |
200 finally: | |
201 header_file.close() | |
202 | |
203 impl_file = open(options.output + '.cc', 'w') | |
204 try: | |
205 impl_file.write(impl_contents) | |
206 finally: | |
207 impl_file.close() | |
208 | |
209 return 0 | |
210 | |
211 if __name__ == '__main__': | |
212 sys.exit(main()) | |
OLD | NEW |