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.
7 Creates a library loader (a header and implementation file),
8 which is a wrapper for dlopen or direct linking with given library.
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).
14 For more info refer to http://crbug.com/162733 .
24 HEADER_TEMPLATE
= """// This is generated file. Do not modify directly.
25 // Path to the code generator: %(generator_path)s .
27 #ifndef %(unique_prefix)s
28 #define %(unique_prefix)s
30 %(wrapped_header_include)s
34 #include "base/basictypes.h"
35 #include "base/compiler_specific.h"
36 #if defined(%(unique_prefix)s_DLOPEN)
37 #include "base/native_library.h"
40 class %(class_name)s {
45 bool Load(const std::string& library_name) WARN_UNUSED_RESULT;
47 bool loaded() const { return loaded_; }
52 void CleanUp(bool unload);
54 #if defined(%(unique_prefix)s_DLOPEN)
55 base::NativeLibrary library_;
60 DISALLOW_COPY_AND_ASSIGN(%(class_name)s);
63 #endif // %(unique_prefix)s
67 HEADER_MEMBER_TEMPLATE
= """ typeof(&::%(function_name)s) %(function_name)s;
71 IMPL_TEMPLATE
= """// This is generated file. Do not modify directly.
72 // Path to the code generator: %(generator_path)s .
74 #include "%(generated_header_name)s"
76 // Put these sanity checks here so that they fire at most once
77 // (to avoid cluttering the build output).
78 #if !defined(%(unique_prefix)s_DLOPEN) && !defined(%(unique_prefix)s_DT_NEEDED)
79 #error neither %(unique_prefix)s_DLOPEN nor %(unique_prefix)s_DT_NEEDED defined
81 #if defined(%(unique_prefix)s_DLOPEN) && defined(%(unique_prefix)s_DT_NEEDED)
82 #error both %(unique_prefix)s_DLOPEN and %(unique_prefix)s_DT_NEEDED defined
85 #include "base/files/file_path.h"
86 #include "base/logging.h"
88 %(class_name)s::%(class_name)s() : loaded_(false) {
91 %(class_name)s::~%(class_name)s() {
95 bool %(class_name)s::Load(const std::string& library_name) {
101 #if defined(%(unique_prefix)s_DLOPEN)
102 library_ = base::LoadNativeLibrary(base::FilePath(library_name), NULL);
113 void %(class_name)s::CleanUp(bool unload) {
114 #if defined(%(unique_prefix)s_DLOPEN)
116 base::UnloadNativeLibrary(library_);
125 IMPL_MEMBER_INIT_TEMPLATE
= """
126 #if defined(%(unique_prefix)s_DLOPEN)
128 reinterpret_cast<typeof(this->%(function_name)s)>(
129 base::GetFunctionPointerFromNativeLibrary(
130 library_, "%(function_name)s"));
132 #if defined(%(unique_prefix)s_DT_NEEDED)
133 %(function_name)s = &::%(function_name)s;
135 if (!%(function_name)s) {
141 IMPL_MEMBER_CLEANUP_TEMPLATE
= """ %(function_name)s = NULL;
145 parser
= optparse
.OptionParser()
146 parser
.add_option('--name')
147 parser
.add_option('--output-cc')
148 parser
.add_option('--output-h')
149 parser
.add_option('--header')
151 parser
.add_option('--bundled-header')
152 parser
.add_option('--use-extern-c', action
='store_true', default
=False)
153 parser
.add_option('--link-directly', type=int, default
=0)
155 options
, args
= parser
.parse_args()
158 parser
.error('Missing --name parameter')
159 if not options
.output_cc
:
160 parser
.error('Missing --output-cc parameter')
161 if not options
.output_h
:
162 parser
.error('Missing --output-h parameter')
163 if not options
.header
:
164 parser
.error('Missing --header paramater')
166 parser
.error('No function names specified')
168 # Make sure we are always dealing with paths relative to source tree root
169 # to avoid issues caused by different relative path roots.
170 source_tree_root
= os
.path
.abspath(
171 os
.path
.join(os
.path
.dirname(__file__
), '..', '..'))
172 options
.output_cc
= os
.path
.relpath(options
.output_cc
, source_tree_root
)
173 options
.output_h
= os
.path
.relpath(options
.output_h
, source_tree_root
)
175 # Create a unique prefix, e.g. for header guards.
176 # Stick a known string at the beginning to ensure this doesn't begin
177 # with an underscore, which is reserved for the C++ implementation.
178 unique_prefix
= ('LIBRARY_LOADER_' +
179 re
.sub(r
'[\W]', '_', options
.output_h
).upper())
185 member_decls
.append(HEADER_MEMBER_TEMPLATE
% {
187 'unique_prefix': unique_prefix
189 member_init
.append(IMPL_MEMBER_INIT_TEMPLATE
% {
191 'unique_prefix': unique_prefix
193 member_cleanup
.append(IMPL_MEMBER_CLEANUP_TEMPLATE
% {
195 'unique_prefix': unique_prefix
198 header
= options
.header
199 if options
.link_directly
== 0 and options
.bundled_header
:
200 header
= options
.bundled_header
201 wrapped_header_include
= '#include %s\n' % header
203 # Some libraries (e.g. libpci) have headers that cannot be included
204 # without extern "C", otherwise they cause the link to fail.
205 # TODO(phajdan.jr): This is a workaround for broken headers. Remove it.
206 if options
.use_extern_c
:
207 wrapped_header_include
= 'extern "C" {\n%s\n}\n' % wrapped_header_include
209 # It seems cleaner just to have a single #define here and #ifdefs in bunch
210 # of places, rather than having a different set of templates, duplicating
211 # or complicating more code.
212 if options
.link_directly
== 0:
213 wrapped_header_include
+= '#define %s_DLOPEN\n' % unique_prefix
214 elif options
.link_directly
== 1:
215 wrapped_header_include
+= '#define %s_DT_NEEDED\n' % unique_prefix
217 parser
.error('Invalid value for --link-directly. Should be 0 or 1.')
219 # Make it easier for people to find the code generator just in case.
220 # Doing it this way is more maintainable, because it's going to work
221 # even if file gets moved without updating the contents.
222 generator_path
= os
.path
.relpath(__file__
, source_tree_root
)
224 header_contents
= HEADER_TEMPLATE
% {
225 'generator_path': generator_path
,
226 'unique_prefix': unique_prefix
,
227 'wrapped_header_include': wrapped_header_include
,
228 'class_name': options
.name
,
229 'member_decls': ''.join(member_decls
),
232 impl_contents
= IMPL_TEMPLATE
% {
233 'generator_path': generator_path
,
234 'unique_prefix': unique_prefix
,
235 'generated_header_name': options
.output_h
,
236 'class_name': options
.name
,
237 'member_init': ''.join(member_init
),
238 'member_cleanup': ''.join(member_cleanup
),
241 header_file
= open(os
.path
.join(source_tree_root
, options
.output_h
), 'w')
243 header_file
.write(header_contents
)
247 impl_file
= open(os
.path
.join(source_tree_root
, options
.output_cc
), 'w')
249 impl_file
.write(impl_contents
)
255 if __name__
== '__main__':