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

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: rebase 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
« no previous file with comments | « content/gpu/gpu_info_collector_linux.cc ('k') | no next file » | 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 """
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 #if defined(%(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);
51
52 #if defined(%(unique_prefix)s_DLOPEN)
53 base::NativeLibrary library_;
54 #endif
55
56 bool loaded_;
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 // Put these sanity checks here so that they fire at most once
75 // (to avoid cluttering the build output).
76 #if !defined(%(unique_prefix)s_DLOPEN) && !defined(%(unique_prefix)s_DT_NEEDED)
77 #error neither %(unique_prefix)s_DLOPEN nor %(unique_prefix)s_DT_NEEDED defined
78 #endif
79 #if defined(%(unique_prefix)s_DLOPEN) && defined(%(unique_prefix)s_DT_NEEDED)
80 #error both %(unique_prefix)s_DLOPEN and %(unique_prefix)s_DT_NEEDED defined
81 #endif
82
83 #include "base/file_path.h"
84 #include "base/logging.h"
85
86 %(class_name)s::%(class_name)s() : loaded_(false) {
87 }
88
89 %(class_name)s::~%(class_name)s() {
90 CleanUp(loaded_);
91 }
92
93 bool %(class_name)s::Load(const std::string& library_name) {
94 if (loaded_) {
95 NOTREACHED();
96 return false;
97 }
98
99 #if defined(%(unique_prefix)s_DLOPEN)
100 library_ = base::LoadNativeLibrary(FilePath(library_name), NULL);
101 if (!library_)
102 return false;
103 #endif
104
105 %(member_init)s
106
107 loaded_ = true;
108 return true;
109 }
110
111 void %(class_name)s::CleanUp(bool unload) {
112 #if defined(%(unique_prefix)s_DLOPEN)
113 if (unload) {
114 base::UnloadNativeLibrary(library_);
115 library_ = NULL;
116 }
117 #endif
118 loaded_ = false;
119 %(member_cleanup)s
120 }
121 """
122
123 IMPL_MEMBER_INIT_TEMPLATE = """
124 #if defined(%(unique_prefix)s_DLOPEN)
125 %(function_name)s =
126 reinterpret_cast<typeof(this->%(function_name)s)>(
127 base::GetFunctionPointerFromNativeLibrary(
128 library_, "%(function_name)s"));
129 #endif
130 #if defined(%(unique_prefix)s_DT_NEEDED)
131 %(function_name)s = &::%(function_name)s;
132 #endif
133 if (!%(function_name)s) {
134 CleanUp(true);
135 return false;
136 }
137 """
138
139 IMPL_MEMBER_CLEANUP_TEMPLATE = """ %(function_name)s = NULL;
140 """
141
142 def main():
143 parser = optparse.OptionParser()
144 parser.add_option('--name')
145 parser.add_option('--output-cc')
146 parser.add_option('--output-h')
147 parser.add_option('--header')
148
149 parser.add_option('--use-extern-c', action='store_true', default=False)
150 parser.add_option('--link-directly', type=int, default=0)
151
152 options, args = parser.parse_args()
153
154 if not options.name:
155 parser.error('Missing --name parameter')
156 if not options.output_cc:
157 parser.error('Missing --output-cc parameter')
158 if not options.output_h:
159 parser.error('Missing --output-h parameter')
160 if not options.header:
161 parser.error('Missing --header paramater')
162 if not args:
163 parser.error('No function names specified')
164
165 # Make sure we are always dealing with an absolute path
166 # to avoid issues caused by different relative path roots.
167 options.output_cc = os.path.abspath(options.output_cc)
168 options.output_h = os.path.abspath(options.output_h)
169
170 # Create a unique prefix, e.g. for header guards.
171 # Stick a known string at the beginning to ensure this doesn't begin
172 # with an underscore, which is reserved for the C++ implementation.
173 unique_prefix = ('LIBRARY_LOADER_' +
174 re.sub(r'[\W]', '_', options.output_h).upper())
175
176 member_decls = []
177 member_init = []
178 member_cleanup = []
179 for fn in args:
180 member_decls.append(HEADER_MEMBER_TEMPLATE % {
181 'function_name': fn,
182 'unique_prefix': unique_prefix
183 })
184 member_init.append(IMPL_MEMBER_INIT_TEMPLATE % {
185 'function_name': fn,
186 'unique_prefix': unique_prefix
187 })
188 member_cleanup.append(IMPL_MEMBER_CLEANUP_TEMPLATE % {
189 'function_name': fn,
190 'unique_prefix': unique_prefix
191 })
192
193 wrapped_header_include = '#include %s' % options.header
194
195 # Some libraries (e.g. libpci) have headers that cannot be included
196 # without extern "C", otherwise they cause the link to fail.
197 # TODO(phajdan.jr): This is a workaround for broken headers. Remove it.
198 if options.use_extern_c:
199 wrapped_header_include = 'extern "C" {\n%s\n}\n' % wrapped_header_include
200
201 # It seems cleaner just to have a single #define here and #ifdefs in bunch
202 # of places, rather than having a different set of templates, duplicating
203 # or complicating more code.
204 if options.link_directly == 0:
205 wrapped_header_include += '#define %s_DLOPEN\n' % unique_prefix
206 elif options.link_directly == 1:
207 wrapped_header_include += '#define %s_DT_NEEDED\n' % unique_prefix
208 else:
209 parser.error('Invalid value for --link-directly. Should be 0 or 1.')
210
211 # Make it easier for people to find the code generator just in case.
212 # Doing it this way is more maintainable, because it's going to work
213 # even if file gets moved without updating the contents.
214 generator_path = os.path.abspath(__file__)
215
216 header_contents = HEADER_TEMPLATE % {
217 'generator_path': generator_path,
218 'unique_prefix': unique_prefix,
219 'wrapped_header_include': wrapped_header_include,
220 'class_name': options.name,
221 'member_decls': ''.join(member_decls),
222 }
223
224 impl_contents = IMPL_TEMPLATE % {
225 'generator_path': generator_path,
226 'unique_prefix': unique_prefix,
227 'generated_header_name': options.output_h,
228 'class_name': options.name,
229 'member_init': ''.join(member_init),
230 'member_cleanup': ''.join(member_cleanup),
231 }
232
233 header_file = open(options.output_h, 'w')
234 try:
235 header_file.write(header_contents)
236 finally:
237 header_file.close()
238
239 impl_file = open(options.output_cc, 'w')
240 try:
241 impl_file.write(impl_contents)
242 finally:
243 impl_file.close()
244
245 return 0
246
247 if __name__ == '__main__':
248 sys.exit(main())
OLDNEW
« no previous file with comments | « 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