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