Merge in ability for memcapable to handle ascii/binary as flags to the
[awesomized/libmemcached] / config / pandora-plugin
1 #!/usr/bin/python
2
3 # Copyright (C) 2009 Sun Microsystems, Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 pandora_plugin_file = 'config/pandora-plugin.ini'
19
20 # Find plugins in the tree and add them to the build system
21
22 import ConfigParser, os, sys
23 import datetime, time
24 import subprocess
25
26 plugin_am_file=None
27 plugin_ac_file=None
28 plugin_doc_index=None
29
30 class ChangeProtectedFile(object):
31
32 def __init__(self, fname):
33 self.bogus_file= False
34 self.real_fname= fname
35 self.new_fname= "%s.new" % fname
36 try:
37 self.new_file= open(self.new_fname,'w+')
38 except IOError:
39 self.bogus_file= True
40
41 def write(self, text):
42 if not self.bogus_file:
43 self.new_file.write(text)
44
45 # We've written all of this out into .new files, now we only copy them
46 # over the old ones if they are different, so that we don't cause
47 # unnecessary recompiles
48 def close(self):
49 """Return True if the file had changed."""
50 if self.bogus_file:
51 return
52 self.new_file.seek(0)
53 new_content = self.new_file.read()
54 self.new_file.close()
55 try:
56 old_file = file(self.real_fname, 'r')
57 old_content = old_file.read()
58 old_file.close()
59 except IOError:
60 old_content = None
61 if new_content != old_content:
62 if old_content != None:
63 os.unlink(self.real_fname)
64 os.rename(self.new_fname, self.real_fname)
65 return True
66 else:
67 try:
68 os.unlink(self.new_fname)
69 except:
70 pass
71
72
73 def write_external_configure(plugin, plugin_file):
74 """Write the initial bits of the configure.ac file"""
75 if not os.path.exists('m4'):
76 os.mkdir('m4')
77 plugin_file.write("""
78 AC_PREREQ(2.59)dnl Minimum Autoconf version required.
79 AC_INIT([%(name)s],[%(version)s],[%(url)s])
80 AC_CONFIG_SRCDIR([%(main_source)s])
81 AC_CONFIG_AUX_DIR(config)
82
83 PANDORA_CANONICAL_TARGET(less-warnings, warnings-always-on, require-cxx, force-gcc42,skip-visibility)
84
85 PANDORA_REQUIRE_LIBPROTOBUF
86 PANDORA_PROTOBUF_REQUIRE_VERSION([2.1.0])
87 PANDORA_REQUIRE_PROTOC
88
89 AC_LANG_PUSH(C++)
90 PANDORA_REQUIRE_PTHREAD
91 PANDORA_REQUIRE_LIBDL
92 AC_LANG_POP
93
94 PANDORA_USE_BETTER_MALLOC
95
96 PANDORA_DRIZZLE_BUILD
97 """ % plugin)
98
99 write_plugin_ac(plugin, plugin_file)
100
101 plugin_file.write("""
102 AC_CONFIG_FILES(Makefile)
103
104 AC_OUTPUT
105
106 echo "---"
107 echo "Configuration summary for $PACKAGE_NAME version $VERSION $PANDORA_RELEASE_COMMENT"
108 echo ""
109 echo " * Installation prefix: $prefix"
110 echo " * System type: $host_vendor-$host_os"
111 echo " * Host CPU: $host_cpu"
112 echo " * C Compiler: $CC_VERSION"
113 echo " * C++ Compiler: $CXX_VERSION"
114 echo " * Debug enabled: $with_debug"
115 echo " * Warnings as failure: $ac_cv_warnings_as_errors"
116 echo " * C++ cstdint location: $ac_cv_cxx_cstdint"
117 echo " * C++ hash_map location: $ac_cv_cxx_hash_map"
118 echo " * C++ hash namespace: $ac_cv_cxx_hash_namespace"
119 echo " * C++ shared_ptr namespace: $ac_cv_shared_ptr_namespace"
120 echo ""
121 echo "---"
122
123 """ % plugin)
124
125 def write_external_makefile(plugin, plugin_file):
126
127 plugin_file.write("""
128 ACLOCAL_AMFLAGS = -I m4 --force
129 VERSION=$(PANDORA_RELEASE_VERSION)
130
131 pkgplugindir=%(pkgplugindir)s
132 EXTRA_DIST = plugin.ini
133
134 noinst_HEADERS=
135 nobase_include_HEADERS=
136 check_PROGRAMS=
137 noinst_LTLIBRARIES=
138 bin_PROGRAMS=
139
140
141 """ % plugin)
142 if plugin['headers'] != "":
143 plugin_file.write("noinst_HEADERS += %(headers)s\n" % plugin)
144 if plugin['install_headers'] != "":
145 plugin_file.write("nobase_include_HEADERS += %(install_headers)s\n" % plugin)
146 if plugin['testsuite']:
147 if plugin.has_key('testsuitedir') and plugin['testsuitedir'] != "":
148 plugin_file.write("EXTRA_DIST += %(testsuitedir)s\n" % plugin)
149 plugin_file.write("""
150 pkgplugin_LTLIBRARIES=%(libname)s.la
151 %(libname)s_la_LDFLAGS=-avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
152 %(libname)s_la_LIBADD=%(libs)s
153 %(libname)s_la_DEPENDENCIES=%(libs)s
154 %(libname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_DYNAMIC_PLUGIN -DPANDORA_MODULE_NAME=%(module_name)s -DPANDORA_MODULE_AUTHOR='"%(author)s"' -DPANDORA_MODULE_TITLE='"%(title)s"' -DPANDORA_MODULE_VERSION='"%(version)s"' -DPANDORA_MODULE_LICENSE=%(license)s %(cppflags)s
155 %(libname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
156 %(libname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
157 %(libname)s_la_SOURCES=%(sources)s
158 check_PROGRAMS += %(tests)s
159 """ % plugin)
160 plugin_am_file=os.path.join(plugin['rel_path'],'plugin.am')
161 if os.path.exists(plugin_am_file):
162 plugin_file.write('include %s\n' % plugin_am_file)
163
164 def write_external_plugin():
165 """Return True if the plugin had changed."""
166 plugin = read_plugin_ini('.')
167 expand_plugin_ini(plugin)
168 plugin_file = ChangeProtectedFile('configure.ac')
169 write_external_configure(plugin, plugin_file)
170 result = plugin_file.close()
171 plugin_file = ChangeProtectedFile('Makefile.am')
172 write_external_makefile(plugin, plugin_file)
173 # Write some stub configure.ac and Makefile.am files that include the above
174 result = plugin_file.close() or result
175 return result
176
177 def write_plugin(plugin, plugin_ini_list):
178 # Since this function is recursive, make sure we're not already in it.
179 if plugin.has_key('writing_status'):
180 if plugin['writing_status'] == 'done':
181 return
182 else:
183 print "Dependency loop detected with %s" % plugin['name']
184 exit(1)
185
186 plugin['writing_status'] = 'dependencies'
187
188 # Write all dependencies first to get around annoying automake bug
189 for dependency in plugin['dependency_list']:
190 found = False
191 for find_plugin in plugin_ini_list:
192 if find_plugin['module_name'] == dependency:
193 found = True
194 write_plugin(find_plugin, plugin_ini_list)
195 break
196 if found is False:
197 print "Could not find dependency %s: %s" % (plugin['name'], dependency)
198 exit(1)
199
200 write_plugin_ac(plugin, plugin_ac_file)
201 write_plugin_am(plugin, plugin_am_file)
202 write_plugin_docs(plugin, plugin_doc_index)
203 plugin['writing_status'] = 'done'
204
205 def write_plugin_docs(plugin, doc_index):
206 if plugin['docs'] is not None and os.path.isdir("docs/plugins"):
207 if not os.path.exists(os.path.join("docs/plugins",plugin["name"])):
208 os.symlink(os.path.abspath(plugin["docs"]), os.path.join("docs/plugins",plugin["name"]))
209 doc_index.write("""
210 %(name)s/index""" % plugin)
211
212 def write_plugin_ac(plugin, plugin_ac):
213 #
214 # Write plugin config instructions into plugin.ac file.
215 #
216 plugin_ac_file=os.path.join(plugin['rel_path'],'plugin.ac')
217 plugin_m4_dir=os.path.join(plugin['rel_path'],'m4')
218 plugin_m4_files=[]
219 if os.path.exists(plugin_m4_dir) and os.path.isdir(plugin_m4_dir):
220 for m4_file in os.listdir(plugin_m4_dir):
221 if os.path.splitext(m4_file)[-1] == '.m4':
222 plugin_m4_files.append(os.path.join(plugin['rel_path'], m4_file))
223 plugin_ac.write("""
224 dnl Config for %(title)s
225 """ % plugin)
226 for m4_file in plugin_m4_files:
227 plugin_ac.write('m4_sinclude([%s])\n' % m4_file)
228 plugin['plugin_dep_libs']=" ".join(["\${top_builddir}/%s" % f for f in plugin['libs'].split()])
229
230 plugin_ac.write("""
231 AC_ARG_WITH([%(name_with_dashes)s-plugin],[
232 dnl indented wierd to make the help output correct
233 AS_HELP_STRING([--with-%(name_with_dashes)s-plugin],[Build %(title)s. @<:@default=%(enabled)s@:>@])
234 AS_HELP_STRING([--without-%(name_with_dashes)s-plugin],[Disable building %(title)s])
235 ],[
236 with_%(name)s_plugin="$withval"
237 AS_IF([test "x$with_%(name)s_plugin" = "xyes"],[
238 requested_%(name)s_plugin="yes"
239 ],[
240 requested_%(name)s_plugin="no"
241 ])
242 ],[
243 with_%(name)s_plugin="%(enabled)s"
244 requested_%(name)s_plugin="no"
245 ])
246 AC_ARG_ENABLE([%(name_with_dashes)s-plugin],[
247 dnl indented wierd to make the help output correct
248 AS_HELP_STRING([--enable-%(name_with_dashes)s-plugin],[Enable loading %(title)s by default. @<:@default=%(default_yesno)s@:>@])
249 AS_HELP_STRING([--disable-%(name_with_dashes)s-plugin],[Disable loading %(title)s by default.])
250 ],
251 [enable_%(name)s_plugin="$enableval"],
252 [enable_%(name)s_plugin=%(default_yesno)s])
253
254 """ % plugin)
255 if os.path.exists(plugin_ac_file):
256 plugin_ac.write('m4_sinclude([%s])\n' % plugin_ac_file)
257 # The plugin author has specified some check to make to determine
258 # if the plugin can be built. If the plugin is turned on and this
259 # check fails, then configure should error out. If the plugin is not
260 # turned on, then the normal conditional build stuff should just let
261 # it silently not build
262 if plugin['has_build_conditional']:
263 plugin_ac.write("""
264 AS_IF([test %(build_conditional)s],
265 [], dnl build_conditional can only negate
266 [
267 AS_IF([test "x${requested_%(name)s_plugin}" = "xyes"],
268 [AC_MSG_ERROR([Plugin %(name)s was explicitly requested, yet failed build dependency checks. Aborting!])])
269 with_%(name)s_plugin=no
270 ])
271
272 """ % plugin)
273 if not plugin['unconditional']:
274 plugin_ac.write("""
275 AM_CONDITIONAL([%(build_conditional_tag)s],
276 [test %(build_conditional)s])
277 """ % plugin)
278
279 plugin_ac.write("""
280 AS_IF([test "x$with_%(name)s_plugin" = "xyes"],
281 [
282 """ % plugin)
283 if plugin['testsuite']:
284 plugin_ac.write("""
285 pandora_plugin_test_list="%(name)s,${pandora_plugin_test_list}"
286 """ % plugin)
287 if plugin['static']:
288 plugin_ac.write("""
289 AS_IF([test "x$enable_%(name)s_plugin" = "xyes"],[
290 pandora_builtin_load_list="%(module_name)s,${pandora_builtin_load_list}"
291 pandora_builtin_load_symbols_list="_drizzled_%(module_name)s_plugin_,${pandora_builtin_load_symbols_list}"
292 PANDORA_PLUGIN_DEP_LIBS="${PANDORA_PLUGIN_DEP_LIBS} %(plugin_dep_libs)s"
293 ])
294 pandora_builtin_list="%(module_name)s,${pandora_builtin_list}"
295 pandora_builtin_symbols_list="_drizzled_%(module_name)s_plugin_,${pandora_builtin_symbols_list}"
296 pandora_plugin_libs="${pandora_plugin_libs} \${top_builddir}/%(root_plugin_dir)s/%(libname)s.la"
297 """ % plugin)
298
299 else:
300 plugin_ac.write("""
301 AS_IF([test "x$enable_%(name)s_plugin" = "xyes"],[
302 pandora_default_plugin_list="%(name)s,${pandora_default_plugin_list}"
303 ])
304 """ % plugin)
305 plugin_ac.write(" ])\n")
306
307 def fix_file_paths(plugin, files):
308 # TODO: determine path to plugin dir relative to top_srcdir... append it to
309 # source files if they don't already have it
310 new_files=""
311 if plugin['plugin_dir'] != ".":
312 for file in files.split():
313 if not file.startswith(plugin['rel_path']):
314 file= os.path.join(plugin['rel_path'], file)
315 new_files= "%s %s" % (new_files, file)
316 else:
317 new_files= " ".join(plugin['sources'].split())
318 if new_files != "":
319 return new_files
320 return files
321
322 def expand_plugin_ini(plugin):
323 if plugin['name'] == "**OUT-OF-TREE**":
324 print "Out of tree plugins require the name field to be specified in plugin.ini"
325 sys.exit(1)
326
327 if plugin['plugin_dir'] == ".":
328 plugin['rel_path']= plugin['plugin_dir']
329 plugin['unconditional']=True
330 else:
331 plugin['rel_path']= plugin['plugin_dir'][len(config['top_srcdir'])+len(os.path.sep):]
332 plugin['unconditional']=False
333
334 plugin['sources']= fix_file_paths(plugin, plugin['sources'])
335 plugin['main_source']= plugin['sources'].split()[0]
336 plugin['headers']= fix_file_paths(plugin, plugin['headers'])
337 plugin['install_headers']= fix_file_paths(plugin, plugin['install_headers'])
338 plugin['tests']= fix_file_paths(plugin, plugin['tests'])
339
340 # Make a yes/no version for autoconf help messages
341 if plugin['load_by_default']:
342 plugin['default_yesno']="yes"
343 else:
344 plugin['default_yesno']="no"
345
346 if plugin.has_key('extra_dist'):
347 plugin['extra_dist']=" ".join([os.path.join(plugin['rel_path'],f) for f in plugin['extra_dist'].split()])
348
349
350 plugin['build_conditional_tag']= "BUILD_%s_PLUGIN" % plugin['name'].upper()
351 plugin['name_with_dashes']= plugin['name'].replace('_','-')
352 if plugin.has_key('build_conditional'):
353 plugin['has_build_conditional']=True
354 plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes" -a %(build_conditional)s' % plugin
355 else:
356 plugin['has_build_conditional']=False
357 plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes"' %plugin
358
359 if plugin['install']:
360 plugin['library_type']= 'pkgplugin'
361 else:
362 plugin['library_type']= 'noinst'
363
364 def find_testsuite(plugin_dir):
365 for testdir in ['drizzle-tests','tests']:
366 if os.path.isdir(os.path.join(plugin_dir,testdir)):
367 return testdir
368 if os.path.isdir(os.path.join('tests','suite',os.path.basename(plugin_dir))):
369 return ""
370 return None
371
372 def find_docs(plugin_dir):
373 if os.path.isfile(os.path.join(plugin_dir, "docs", "index.rst")):
374 return os.path.join(plugin_dir, "docs")
375
376 def read_plugin_ini(plugin_dir):
377 sources_default=""
378 if plugin_dir == ".":
379 plugin_name="**OUT-OF-TREE**"
380 module_name="**OUT-OF-TREE**"
381 else:
382 sources_default="%s.cc" % os.path.basename(plugin_dir)
383 plugin_name = plugin_dir[plugin_dir.index(config['root_plugin_dir']) + len(config['root_plugin_dir']) + 1:]
384 module_name = plugin_name.replace("/", config['module_name_separator']).replace("\\", config['module_name_separator'])
385 plugin_name = plugin_name.replace("/", config['plugin_name_separator']).replace("\\", config['plugin_name_separator'])
386
387
388 plugin_file= os.path.join(plugin_dir,config['plugin_ini_fname'])
389 plugin_defaults= dict(sources=sources_default,
390 headers="",
391 install_headers="",
392 cflags="",
393 cppflags="",
394 cxxflags="",
395 libs="",
396 ldflags="",
397 author="",
398 title="",
399 description="",
400 license="PLUGIN_LICENSE_GPL",
401 name=plugin_name,
402 module_name=module_name,
403 load_by_default=config['default_load_by_default'],
404 disabled="False",
405 static="False",
406 dependencies="",
407 dependency_aliases="",
408 tests="",
409 install=config['default_install'])
410 parser=ConfigParser.ConfigParser(defaults= plugin_defaults)
411 parser.read(plugin_file)
412 plugin=dict(parser.items('plugin'))
413 plugin['plugin_dir'] = plugin_dir
414 if plugin_dir == '.':
415 if not plugin.has_key('url'):
416 print "External Plugins are required to specifiy a url"
417 plugin['url']= 'http://launchpad.net/%(name)s' % plugin
418 sys.exit(1)
419 if plugin_dir == '.' and not plugin.has_key('version'):
420 print "External Plugins are required to specifiy a version"
421 sys.exit(1)
422 if not plugin.has_key('version'):
423 plugin['version'] = config['default_plugin_version']
424 if plugin.has_key('load_by_default'):
425 plugin['load_by_default']=parser.getboolean('plugin','load_by_default')
426 if plugin.has_key('disabled'):
427 plugin['disabled']=parser.getboolean('plugin','disabled')
428 if plugin['disabled']:
429 plugin['enabled']="no"
430 else:
431 plugin['enabled']="yes"
432 if plugin.has_key('static'):
433 try:
434 plugin['static']= parser.getboolean('plugin','static')
435 except:
436 if plugin['static'][:5] == os.sys.platform[:5]:
437 plugin['static']= True
438 else:
439 plugin['static']= False
440 if plugin.has_key('install'):
441 plugin['install']= parser.getboolean('plugin','install')
442 if plugin.has_key('testsuite'):
443 if plugin['testsuite'] == 'disable':
444 plugin['testsuite']= False
445 plugin['dist_testsuite']= find_testsuite(plugin_dir)
446 else:
447 plugin_testsuite= find_testsuite(plugin_dir)
448 plugin['testsuitedir']=plugin_testsuite
449 if plugin_testsuite is not None:
450 plugin['testsuite']=True
451 else:
452 plugin['testsuite']=False
453 plugin['docs']= find_docs(plugin_dir)
454
455 plugin['cflags']+= ' ' + config['extra_cflags']
456 plugin['cppflags']+= ' ' + config['extra_cppflags']
457 plugin['cxxflags']+= ' ' + config['extra_cxxflags']
458
459 plugin['libname']= "lib%s%s%s" % (config['plugin_prefix'],
460 plugin['name'],
461 config['plugin_suffix'])
462 if config['force_lowercase_libname']:
463 plugin['libname']= plugin['libname'].lower()
464
465 plugin['root_plugin_dir']= config['root_plugin_dir']
466 plugin['plugin_prefix']= config['plugin_prefix']
467 plugin['plugin_suffix']= config['plugin_suffix']
468 plugin['pkgplugindir']= config['pkgplugindir']
469
470 # Dependencies must have a module but dependency aliases are simply added
471 # to the variable passed during compile.
472 plugin['dependency_list'] = plugin['dependencies'].split()
473 dependency_aliases = plugin['dependency_aliases'].split()
474 plugin['dependencies'] = ','.join(plugin['dependency_list'] +
475 plugin['dependency_aliases'].split())
476 dependency_libs = ["%s/lib%s%s.la" % (config['root_plugin_dir'],
477 dependency.lower().replace('::', '_'),
478 config['plugin_suffix'])
479 for dependency in plugin['dependency_list']]
480 plugin['libs'] = " ".join(plugin['libs'].split() + dependency_libs);
481
482 # Libtool is going to expand:
483 # -DPANDORA_MODULE_AUTHOR='"Padraig O'"'"'Sullivan"'
484 # to:
485 # "-DPANDORA_MODULE_AUTHOR=\"Padraig O'Sullivan\""
486 # So we have to replace internal ''s to '"'"'
487 for key in ('author','title','description','version'):
488 plugin[key]=plugin[key].replace('"','\\"')
489 plugin[key]=plugin[key].replace("'","'\"'\"'")
490 return plugin
491
492
493 def write_plugin_am(plugin, plugin_am):
494 """Write an automake fragment for this plugin.
495
496 :param plugin: The plugin dict.
497 :param plugin_am: The file to write to.
498 """
499 # The .plugin.ini.stamp avoids changing the datestamp on plugin.ini which can
500 # confuse VCS systems.
501 plugin_am.write("""
502 EXTRA_DIST += %(rel_path)s/plugin.ini
503
504 # Prevent errors when a plugin dir is removed
505 %(rel_path)s/plugin.ini:
506
507 """ % plugin)
508 if plugin.has_key('extra_dist') and plugin['extra_dist'] != "":
509 plugin_am.write("EXTRA_DIST += %(extra_dist)s\n" % plugin)
510 if plugin['headers'] != "":
511 plugin_am.write("noinst_HEADERS += %(headers)s\n" % plugin)
512 if plugin['install_headers'] != "":
513 plugin_am.write("nobase_include_HEADERS += %(install_headers)s\n" % plugin)
514 if plugin['testsuite']:
515 if plugin.has_key('testsuitedir') and plugin['testsuitedir'] != "":
516 plugin_am.write("EXTRA_DIST += %(rel_path)s/%(testsuitedir)s\n" % plugin)
517 if plugin.has_key('dist_testsuite') and plugin['dist_testsuite'] != "":
518 plugin_am.write("EXTRA_DIST += %(rel_path)s/%(dist_testsuite)s\n" % plugin)
519 if plugin['docs'] is not None:
520 plugin_am.write("EXTRA_DIST += ${top_srcdir}/%(rel_path)s/docs/*.rst\n" % plugin)
521 if plugin['static']:
522 plugin_am.write("""
523 %(root_plugin_dir)s_%(plugin_prefix)s%(name)s_dir=${top_srcdir}/%(rel_path)s
524 EXTRA_DIST += %(rel_path)s/plugin.ini
525 if %(build_conditional_tag)s
526 noinst_LTLIBRARIES+=%(root_plugin_dir)s/%(libname)s.la
527 %(root_plugin_dir)s_%(libname)s_la_LIBADD=%(libs)s
528 %(root_plugin_dir)s_%(libname)s_la_DEPENDENCIES=%(libs)s
529 %(root_plugin_dir)s_%(libname)s_la_LDFLAGS=$(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
530 %(root_plugin_dir)s_%(libname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_MODULE_NAME=%(module_name)s -DPANDORA_MODULE_AUTHOR='"%(author)s"' -DPANDORA_MODULE_TITLE='"%(title)s"' -DPANDORA_MODULE_VERSION='"%(version)s"' -DPANDORA_MODULE_LICENSE=%(license)s -DPANDORA_MODULE_DEPENDENCIES='"%(dependencies)s"' %(cppflags)s
531 %(root_plugin_dir)s_%(libname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
532 %(root_plugin_dir)s_%(libname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
533 %(root_plugin_dir)s_%(libname)s_la_SOURCES=%(sources)s
534 check_PROGRAMS += %(tests)s
535 PANDORA_DYNAMIC_LDADDS+=${top_builddir}/%(root_plugin_dir)s/%(libname)s.la
536 endif
537 """ % plugin)
538 else:
539 plugin_am.write("""
540 %(root_plugin_dir)s_%(plugin_prefix)s%(name)s_dir=${top_srcdir}/%(rel_path)s
541 EXTRA_DIST += %(rel_path)s/plugin.ini
542 if %(build_conditional_tag)s
543 %(library_type)s_LTLIBRARIES+=%(root_plugin_dir)s/%(libname)s.la
544 %(root_plugin_dir)s_%(libname)s_la_LDFLAGS=-avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
545 %(root_plugin_dir)s_%(libname)s_la_LIBADD=%(libs)s
546 %(root_plugin_dir)s_%(libname)s_la_DEPENDENCIES=%(libs)s
547 %(root_plugin_dir)s_%(libname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_DYNAMIC_PLUGIN -DPANDORA_MODULE_NAME=%(module_name)s -DPANDORA_MODULE_AUTHOR='"%(author)s"' -DPANDORA_MODULE_TITLE='"%(title)s"' -DPANDORA_MODULE_VERSION='"%(version)s"' -DPANDORA_MODULE_LICENSE=%(license)s -DPANDORA_MODULE_DEPENDENCIES='"%(dependencies)s"' %(cppflags)s
548 %(root_plugin_dir)s_%(libname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
549 %(root_plugin_dir)s_%(libname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
550 %(root_plugin_dir)s_%(libname)s_la_SOURCES=%(sources)s
551 check_PROGRAMS += %(tests)s
552 endif
553 """ % plugin)
554 plugin_am_file=os.path.join(plugin['rel_path'],'plugin.am')
555 if os.path.exists(plugin_am_file):
556 plugin_am.write('include %s\n' % plugin_am_file)
557
558 #
559 # MAIN STARTS HERE:
560 #
561
562 # Parse the pandora-plugin config file
563
564 config_defaults= dict(
565 top_srcdir='.',
566 top_builddir='.',
567 plugin_ini_fname='plugin.ini',
568 plugin_prefix='',
569 plugin_suffix='',
570 extra_cflags='',
571 extra_cppflags='',
572 extra_cxxflags='',
573 root_plugin_dir='',
574 pkgplugindir='',
575 default_install='True',
576 default_plugin_version='',
577 default_load_by_default='False',
578 force_lowercase_libname='True',
579 plugin_name_separator='_',
580 module_name_separator='::'
581 )
582
583 config_parser = ConfigParser.ConfigParser(defaults=config_defaults)
584 config_parser.read(pandora_plugin_file)
585 config = dict(config_parser.items('pandora-plugin'))
586 config['force_lowercase_libname']=config_parser.getboolean('pandora-plugin','force_lowercase_libname')
587
588 # I'm 3 seconds away from writing a comprehensive build solution
589 if not os.path.exists('config/pandora_vc_revinfo'):
590 if os.path.exists('.bzr'):
591 bzr_revno= subprocess.Popen(["bzr", "revno"], stdout=subprocess.PIPE).communicate()[0].strip()
592 rev_date= datetime.date.fromtimestamp(time.time())
593 config['default_plugin_version'] = "%d.%02d.%s" % (rev_date.year, rev_date.month, bzr_revno)
594 else:
595 config['default_plugin_version']=datetime.date.fromtimestamp(time.time()).isoformat()
596 else:
597 # need to read config/pandora_vc_revno
598 pandora_vc_revno=open('config/pandora_vc_revinfo','r').read().split()
599 rev_date=""
600 bzr_revno=""
601 for revno_line in pandora_vc_revno:
602 (revno_key,revno_val)= revno_line.split("=")
603 if revno_key == 'PANDORA_VC_REVNO':
604 bzr_revno=revno_val.strip()
605 elif revno_key == 'PANDORA_RELEASE_DATE':
606 rev_date=revno_val.strip()
607
608 config['default_plugin_version'] = "%s.%s" % (rev_date, bzr_revno)
609
610 actions=[]
611 for arg in sys.argv:
612 if arg.startswith('--top_srcdir='):
613 config['top_srcdir']=arg[12:]
614 elif arg.startswith('--top_builddir='):
615 config['top_builddir']=arg[14:]
616 elif arg == "--force-all":
617 actions=['plugin-list','pandora-plugin.am','write']
618 break
619 else:
620 actions.append(arg)
621 if len(actions) == 0:
622 actions.append('write')
623
624 plugin_list=[]
625
626 def accumulate_plugins(arg, dirname, fnames):
627 # plugin_ini_fname is a name in dirname indicating dirname is a plugin.
628 if config['plugin_ini_fname'] in fnames:
629 arg.append(dirname)
630
631 os.path.walk(os.path.join(config['top_srcdir'],
632 config['root_plugin_dir']),
633 accumulate_plugins,
634 plugin_list)
635
636 if not os.path.exists("config/pandora-plugin.am") or "write" in actions:
637 plugin_am_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.am'))
638 plugin_am_file.write("""
639 # always the current list, generated every build so keep this lean.
640 # pandora-plugin.list: datestamp preserved list
641 ${srcdir}/config/pandora-plugin.list: .plugin.scan
642 .plugin.scan:
643 @cd ${top_srcdir} && python config/pandora-plugin plugin-list
644
645 # Plugins affect configure; so to prevent configure running twice in a tarball
646 # build (once up front, once with the right list of plugins, we ship the
647 # generated list of plugins and the housekeeping material for that list so it
648 # is likewise not updated.
649 EXTRA_DIST += \
650 config/pandora-plugin.am \
651 config/pandora-plugin.ac \
652 config/pandora-plugin \
653 config/pandora-plugin.ini
654
655
656 # Seed the list of plugin LDADDS which plugins may extend.
657 PANDORA_DYNAMIC_LDADDS=
658
659 # plugin.stamp: graph dominator for creating all per pandora-plugin.ac/am
660 # files. This is invoked when the code to generate such files has altered.""")
661
662 if not os.path.exists("config/pandora-plugin.ac") or "write" in actions:
663 plugin_ac_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.ac'))
664 plugin_ac_file.write("dnl Generated file, run make to rebuild\n")
665
666 if os.path.exists("docs/plugins"):
667 if not os.path.exists("docs/plugins/list.rst") or "write" in actions:
668 plugin_doc_index = ChangeProtectedFile("docs/plugins/list.rst")
669 plugin_doc_index.write("""
670 Plugin Documentation
671 ====================
672
673 .. toctree::
674 :maxdepth: 2
675 """)
676
677
678 if os.path.exists('plugin.ini'):
679 # Are we in a plugin dir which wants to have a self-sufficient build system?
680 plugin_list=['.']
681
682 write_external_plugin()
683 else:
684 plugin_list_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.list'))
685 for p in plugin_list:
686 plugin_list_file.write(p)
687 plugin_list_file.write("\n")
688 plugin_list.sort()
689 plugin_list_file.close()
690
691 if not os.path.exists("config/pandora-plugin.am") or 'write' in actions:
692 plugin_am_file.write("\n${top_srcdir}/config/pandora-plugin.am: ${top_srcdir}/config/pandora-plugin.list ${top_srcdir}/config/pandora-plugin ")
693 for plugin_dir in plugin_list:
694 plugin_am_file.write("\\\n\t%s/plugin.ini " % plugin_dir)
695 plugin_am_file.write("\n\tcd ${top_srcdir} && python config/pandora-plugin write\n")
696 plugin_ini_list=[]
697
698 # Load all plugin.ini files first so we can do dependency tracking.
699 for plugin_dir in plugin_list:
700 plugin = read_plugin_ini(plugin_dir)
701 expand_plugin_ini(plugin)
702 plugin_ini_list.append(plugin)
703
704 # Check for duplicates
705 plugin_name_list = [plugin['libname'] for plugin in plugin_ini_list]
706 for plugin in plugin_ini_list:
707 if plugin_name_list.count(plugin['libname']) != 1:
708 print "Duplicate module name %s" % plugin['libname']
709 exit(1)
710
711 for plugin in plugin_ini_list:
712 write_plugin(plugin, plugin_ini_list)
713
714 if plugin_am_file is not None:
715 plugin_am_file.close()
716 if plugin_ac_file is not None:
717 plugin_ac_file.close()
718 if plugin_doc_index is not None:
719 plugin_doc_index.close()