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

Side by Side Diff: tools/generate_library_loader/generate_library_loader.py

Issue 11415138: Linux: create a library loader code generator for dlopen and use it for libpci. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixes Created 8 years 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 """
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
28 #define %(unique_prefix)s
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 void CleanUp(bool unload);
Mark Mentovai 2012/11/27 23:09:11 Nothing ever calls CleanUp(false), so get rid of t
Paweł Hajdan Jr. 2012/11/28 01:05:52 In theory when loaded_ is false that would happen.
51
52 #ifdef %(unique_prefix)s_DLOPEN
53 base::NativeLibrary library_;
54 #endif
55
56 bool loaded_;
Mark Mentovai 2012/11/27 23:09:11 In the DLOPEN variant, you can get rid of loaded_
Paweł Hajdan Jr. 2012/11/28 01:05:52 Yeah, I think it'd just further complicate the cod
57
58 DISALLOW_COPY_AND_ASSIGN(%(class_name)s);
59 };
60
61 #endif // %(unique_prefix)s
62 """
63
64
65 HEADER_MEMBER_TEMPLATE = """ typeof(&::%(function_name)s) %(function_name)s;
66 """
67
68
69 IMPL_TEMPLATE = """// This is generated file. Do not modify directly.
70 // Path to the code generator: %(generator_path)s .
71
72 #include "%(generated_header_name)s"
73
74 #include "base/file_path.h"
75 #include "base/logging.h"
76
77 %(class_name)s::%(class_name)s() : loaded_(false) {
78 }
79
80 %(class_name)s::~%(class_name)s() {
81 CleanUp(loaded_);
Mark Mentovai 2012/11/27 23:09:11 I’d just leave the destructor at calling base::Unl
Paweł Hajdan Jr. 2012/11/28 01:05:52 That's guarded by loaded_. I think you've asked fo
Mark Mentovai 2012/11/28 04:29:12 Paweł Hajdan Jr. wrote:
82 }
83
84 bool %(class_name)s::Load(const std::string& library_name) {
85 if (loaded_) {
86 NOTREACHED();
87 return false;
88 }
89
90 #ifdef %(unique_prefix)s_DLOPEN
91 library_ = base::LoadNativeLibrary(FilePath(library_name), NULL);
92 if (!library_)
93 return false;
94 #endif
95
96 %(member_init)s
97
98 loaded_ = true;
99 return true;
100 }
101
102 void %(class_name)s::CleanUp(bool unload) {
103 #if defined(%(unique_prefix)s_DLOPEN)
104 if (unload) {
105 base::UnloadNativeLibrary(library_);
106 library_ = NULL;
107 }
108 #endif
109 loaded_ = false;
110 %(member_cleanup)s
111 }
112 """
113
114 IMPL_MEMBER_INIT_TEMPLATE = """
115 #if defined(%(unique_prefix)s_DLOPEN)
116 this->%(function_name)s =
Mark Mentovai 2012/11/27 23:09:11 What’s all this->, then? We don’t normally write t
Paweł Hajdan Jr. 2012/11/28 01:05:52 Done.
117 reinterpret_cast<typeof(this->%(function_name)s)>(
118 base::GetFunctionPointerFromNativeLibrary(
119 library_, "%(function_name)s"));
120 #elif defined(%(unique_prefix)s_DT_NEEDED)
Mark Mentovai 2012/11/27 23:09:11 Good name choice. It’s nice to have a name for thi
121 this->%(function_name)s = &::%(function_name)s;
122 #else
123 #error neither %(unique_prefix)s_DLOPEN nor %(unique_prefix)s_DT_NEEDED defined
Mark Mentovai 2012/11/27 23:09:11 I don’t think you need one #error for each functio
Paweł Hajdan Jr. 2012/11/28 01:05:52 Done.
124 #endif
125 if (!this->%(function_name)s) {
126 CleanUp(true);
127 return false;
128 }
129 """
130
131 IMPL_MEMBER_CLEANUP_TEMPLATE = """ this->%(function_name)s = NULL;
132 """
133
134 def main():
135 parser = optparse.OptionParser()
136 parser.add_option('--name')
137 parser.add_option('--output-cc')
138 parser.add_option('--output-h')
139 parser.add_option('--header')
140
141 parser.add_option('--use-extern-c', action='store_true', default=False)
142 parser.add_option('--link-directly', type=int, default=0)
143
144 options, args = parser.parse_args()
145
146 if not options.name:
147 parser.error('Missing --name parameter')
148 if not options.output_cc:
149 parser.error('Missing --output-cc parameter')
150 if not options.output_h:
151 parser.error('Missing --output-h parameter')
152 if not options.header:
153 parser.error('Missing --header paramater')
154 if not args:
155 parser.error('No function names specified')
156
157 # Make sure we are always dealing with an absolute path
158 # to avoid issues caused by different relative path roots.
159 options.output_cc = os.path.abspath(options.output_cc)
160 options.output_h = os.path.abspath(options.output_h)
161
162 # Create a unique prefix, e.g. for header guards.
163 # Stick a known string at the beginning to ensure this doesn't begin
164 # with an underscore, which is reserved for the C++ implementation.
165 unique_prefix = ('LIBRARY_LOADER_' +
166 re.sub(r'[\W]', '_', options.output_h).upper())
167
168 member_decls = []
169 member_init = []
170 member_cleanup = []
171 for fn in args:
172 member_decls += HEADER_MEMBER_TEMPLATE % {
173 'function_name': fn,
174 'unique_prefix': unique_prefix
175 }
176 member_init += IMPL_MEMBER_INIT_TEMPLATE % {
177 'function_name': fn,
178 'unique_prefix': unique_prefix
179 }
180 member_cleanup += IMPL_MEMBER_CLEANUP_TEMPLATE % {
181 'function_name': fn,
182 'unique_prefix': unique_prefix
183 }
184
185 wrapped_header_include = '#include %s' % options.header
186
187 # Some libraries (e.g. libpci) have headers that cannot be included
188 # without extern "C", otherwise they cause the link to fail.
189 # TODO(phajdan.jr): This is a workaround for broken headers. Remove it.
190 if options.use_extern_c:
191 wrapped_header_include = 'extern "C" {\n%s\n}\n' % wrapped_header_include
192
193 # It seems cleaner just to have a single #define here and #ifdefs in bunch
194 # of places, rather than having a different set of templates, duplicating
195 # or complicating more code.
196 if options.link_directly == 0:
197 wrapped_header_include += '#define %s_DLOPEN\n' % unique_prefix
198 elif options.link_directly == 1:
199 wrapped_header_include += '#define %s_DT_NEEDED\n' % unique_prefix
200 else:
201 parser.error('Invalid value for --link-directly. Should be 0 or 1.')
202
203 # Make it easier for people to find the code generator just in case.
204 # Doing it this way is more maintainable, because it's going to work
205 # even if file gets moved without updating the contents.
206 generator_path = os.path.abspath(__file__)
207
208 header_contents = HEADER_TEMPLATE % {
209 'generator_path': generator_path,
210 'unique_prefix': unique_prefix,
211 'wrapped_header_include': wrapped_header_include,
212 'class_name': options.name,
213 'member_decls': ''.join(member_decls),
214 }
215
216 impl_contents = IMPL_TEMPLATE % {
217 'generator_path': generator_path,
218 'unique_prefix': unique_prefix,
219 'generated_header_name': options.output_h,
220 'class_name': options.name,
221 'member_init': ''.join(member_init),
222 'member_cleanup': ''.join(member_cleanup),
223 }
224
225 header_file = open(options.output_h, 'w')
226 try:
227 header_file.write(header_contents)
228 finally:
229 header_file.close()
230
231 impl_file = open(options.output_cc, 'w')
232 try:
233 impl_file.write(impl_contents)
234 finally:
235 impl_file.close()
236
237 return 0
238
239 if __name__ == '__main__':
240 sys.exit(main())
OLDNEW
« build/linux/system.gyp ('K') | « content/gpu/gpu_info_collector_linux.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698