3
# Copyright (C) 2009 Sun Microsystems
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.
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.
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
19
# Find plugins in the tree and add them to the build system
21
import ConfigParser, os, sys
27
plugin_ini_fname='plugin.ini'
32
plugin_suffix='_plugin'
36
root_plugin_dir='plugin'
37
pkgplugindir='$(libdir)/drizzle'
38
default_install='True'
39
default_plugin_version=''
41
class ChangeProtectedFile(object):
43
def __init__(self, fname):
44
self.bogus_file= False
45
self.real_fname= fname
46
self.new_fname= "%s.new" % fname
48
self.new_file= open(self.new_fname,'w+')
52
def write(self, text):
53
if not self.bogus_file:
54
self.new_file.write(text)
56
# We've written all of this out into .new files, now we only copy them
57
# over the old ones if they are different, so that we don't cause
58
# unnecessary recompiles
60
"""Return True if the file had changed."""
64
new_content = self.new_file.read()
67
old_file = file(self.real_fname, 'r')
68
old_content = old_file.read()
72
if new_content != old_content:
73
if old_content != None:
74
os.unlink(self.real_fname)
75
os.rename(self.new_fname, self.real_fname)
79
os.unlink(self.new_fname)
84
def write_external_configure(plugin, plugin_file):
85
"""Write the initial bits of the configure.ac file"""
86
if not os.path.exists('m4'):
89
AC_PREREQ(2.59)dnl Minimum Autoconf version required.
90
AC_INIT([%(name)s],[%(version)s],[%(url)s])
91
AC_CONFIG_SRCDIR([%(main_source)s])
92
AC_CONFIG_AUX_DIR(config)
94
PANDORA_CANONICAL_TARGET(less-warnings, warnings-always-on, require-cxx, force-gcc42,skip-visibility)
96
PANDORA_REQUIRE_LIBPROTOBUF
97
PANDORA_PROTOBUF_REQUIRE_VERSION([2.1.0])
98
PANDORA_REQUIRE_PROTOC
101
PANDORA_REQUIRE_PTHREAD
102
PANDORA_REQUIRE_LIBDL
105
PANDORA_USE_BETTER_MALLOC
107
PANDORA_DRIZZLE_BUILD
110
write_plugin_ac(plugin, plugin_file)
112
plugin_file.write("""
113
AC_CONFIG_FILES(Makefile)
118
echo "Configuration summary for $PACKAGE_NAME version $VERSION $PANDORA_RELEASE_COMMENT"
120
echo " * Installation prefix: $prefix"
121
echo " * System type: $host_vendor-$host_os"
122
echo " * Host CPU: $host_cpu"
123
echo " * C Compiler: $CC_VERSION"
124
echo " * C++ Compiler: $CXX_VERSION"
125
echo " * Debug enabled: $with_debug"
126
echo " * Warnings as failure: $ac_cv_warnings_as_errors"
127
echo " * C++ cstdint location: $ac_cv_cxx_cstdint"
128
echo " * C++ hash_map location: $ac_cv_cxx_hash_map"
129
echo " * C++ hash namespace: $ac_cv_cxx_hash_namespace"
130
echo " * C++ shared_ptr namespace: $ac_cv_shared_ptr_namespace"
136
def write_external_makefile(plugin, plugin_file):
138
plugin_file.write("""
139
ACLOCAL_AMFLAGS = -I m4 --force
140
VERSION=$(PANDORA_RELEASE_VERSION)
142
pkgplugindir=%(pkgplugindir)s
143
EXTRA_DIST = plugin.ini
146
if plugin['headers'] != "":
147
plugin_file.write("noinst_HEADERS = %(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=%(pname)s.la
153
%(pname)s_la_LDFLAGS=-avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
154
%(pname)s_la_LIBADD=%(libs)s
155
%(pname)s_la_DEPENDENCIES=%(libs)s
156
%(pname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_DYNAMIC_PLUGIN -DPANDORA_MODULE_NAME=%(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
%(pname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
158
%(pname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
160
%(pname)s_la_SOURCES=%(sources)s
163
plugin_am_file=os.path.join(plugin['rel_path'],'plugin.am')
164
if os.path.exists(plugin_am_file):
165
plugin_file.write('include %s\n' % plugin_am_file)
167
def write_external_plugin():
168
"""Return True if the plugin had changed."""
169
plugin = read_plugin_ini('.')
170
expand_plugin_ini(plugin, '.')
171
plugin_file = ChangeProtectedFile('configure.ac')
172
write_external_configure(plugin, plugin_file)
173
result = plugin_file.close()
174
plugin_file = ChangeProtectedFile('Makefile.am')
175
write_external_makefile(plugin, plugin_file)
176
# Write some stub configure.ac and Makefile.am files that include the above
177
result = plugin_file.close() or result
180
def write_plugin(plugin_dir):
181
"""Return True if the plugin had changed."""
182
plugin = read_plugin_ini(plugin_dir)
183
expand_plugin_ini(plugin, plugin_dir)
184
write_plugin_ac(plugin, plugin_ac_file)
185
write_plugin_am(plugin, plugin_am_file)
187
def write_plugin_ac(plugin, plugin_ac):
189
# Write plugin config instructions into plugin.ac file.
191
plugin_ac_file=os.path.join(plugin['rel_path'],'plugin.ac')
192
plugin_m4_dir=os.path.join(plugin['rel_path'],'m4')
194
if os.path.exists(plugin_m4_dir) and os.path.isdir(plugin_m4_dir):
195
for m4_file in os.listdir(plugin_m4_dir):
196
if os.path.splitext(m4_file)[-1] == '.m4':
197
plugin_m4_files.append(os.path.join(plugin['rel_path'], m4_file))
199
dnl Config for %(title)s
201
for m4_file in plugin_m4_files:
202
plugin_ac.write('m4_sinclude([%s])\n' % m4_file)
203
plugin['plugin_dep_libs']=" ".join(["\${top_builddir}/%s" % f for f in plugin['libs'].split()])
207
dnl This plugin is staticly built, which means we cannot live without and it is not
208
dnl possible to disable it. Once it is disableable, we will make it non-static.
209
with_%(name)s_plugin=yes
210
pandora_builtin_list="_drizzled_%(name)s_plugin_,${pandora_builtin_list}"
211
pandora_plugin_libs="${pandora_plugin_libs} \${top_builddir}/%(root_plugin_dir)s/%(pname)s.la"
212
PANDORA_PLUGIN_DEP_LIBS="${PANDORA_PLUGIN_DEP_LIBS} %(plugin_dep_libs)s"
215
if plugin['testsuite']:
217
pandora_plugin_test_list="%(name)s,${pandora_plugin_test_list}"
221
AC_ARG_WITH([%(name_with_dashes)s-plugin],[
222
dnl indented wierd to make the help output correct
223
AS_HELP_STRING([--with-%(name_with_dashes)s-plugin],[Build %(title)s. @<:@default=%(enabled)s@:>@])
224
AS_HELP_STRING([--without-%(name_with_dashes)s-plugin],[Disable building %(title)s])
226
with_%(name)s_plugin="$withval"
227
AS_IF([test "x$with_%(name)s_plugin" = "xyes"],[
228
requested_%(name)s_plugin="yes"
230
requested_%(name)s_plugin="no"
233
with_%(name)s_plugin="%(enabled)s"
234
requested_%(name)s_plugin="no"
236
AC_ARG_ENABLE([%(name_with_dashes)s-plugin],[
237
dnl indented wierd to make the help output correct
238
AS_HELP_STRING([--enable-%(name_with_dashes)s-plugin],[Build %(title)s. @<:@default=%(default_yesno)s@:>@])
239
AS_HELP_STRING([--disable-%(name_with_dashes)s-plugin],[Disable building %(title)s])
241
[enable_%(name)s_plugin="$withval"],
242
[enable_%(name)s_plugin=%(default_yesno)s])
245
if os.path.exists(plugin_ac_file):
246
plugin_ac.write('m4_sinclude([%s])\n' % plugin_ac_file)
247
# The plugin author has specified some check to make to determine
248
# if the plugin can be built. If the plugin is turned on and this
249
# check fails, then configure should error out. If the plugin is not
250
# turned on, then the normal conditional build stuff should just let
251
# it silently not build
252
if plugin['has_build_conditional']:
254
AS_IF([test %(build_conditional)s],
255
[], dnl build_conditional can only negate
257
AS_IF([test "x${requested_%(name)s_plugin}" = "xyes"],
258
[AC_MSG_ERROR([Plugin %(name)s was explicitly requested, yet failed build dependency checks. Aborting!])])
259
with_%(name)s_plugin=no
263
if not plugin['unconditional']:
265
AM_CONDITIONAL([%(build_conditional_tag)s],
266
[test %(build_conditional)s])
268
if not plugin['static']:
270
AS_IF([test "x$with_%(name)s_plugin" = "xyes"],
273
if plugin['testsuite']:
275
pandora_plugin_test_list="%(name)s,${pandora_plugin_test_list}"
279
AS_IF([test "x$enable_%(name)s_plugin" = "xyes"],[
280
pandora_default_plugin_list="%(name)s,${pandora_default_plugin_list}"
283
plugin_ac.write(" ])\n")
286
def expand_plugin_ini(plugin, plugin_dir):
287
if plugin['name'] == "**OUT-OF-TREE**":
288
print "Out of tree plugins require the name field to be specified in plugin.ini"
291
if plugin_dir == ".":
292
plugin['rel_path']= plugin_dir
293
plugin['unconditional']=True
295
plugin['rel_path']= plugin_dir[len(top_srcdir)+len(os.path.sep):]
296
plugin['unconditional']=False
297
# TODO: determine path to plugin dir relative to top_srcdir... append it to
298
# source files if they don't already have it
299
if plugin['sources'] == "":
300
plugin['sources']="%s.cc" % plugin['name']
302
if plugin_dir != ".":
303
for src in plugin['sources'].split():
304
if not src.startswith(plugin['rel_path']):
305
src= os.path.join(plugin['rel_path'], src)
306
new_sources= "%s %s" % (new_sources, src)
308
new_sources= " ".join(plugin['sources'].split())
309
if new_sources != "":
310
plugin['sources']= new_sources
311
plugin['main_source']= plugin['sources'].split()[0]
314
if plugin_dir != ".":
315
for header in plugin['headers'].split():
316
if not header.startswith(plugin['rel_path']):
317
header= os.path.join(plugin['rel_path'], header)
318
new_headers= "%s %s" % (new_headers, header)
320
new_headers= " ".join(plugin['headers'].split())
321
if new_headers != "":
322
plugin['headers']= new_headers
324
# Make a yes/no version for autoconf help messages
325
if plugin['load_by_default']:
326
plugin['default_yesno']="yes"
328
plugin['default_yesno']="no"
331
plugin['build_conditional_tag']= "BUILD_%s_PLUGIN" % plugin['name'].upper()
332
plugin['name_with_dashes']= plugin['name'].replace('_','-')
333
if plugin.has_key('build_conditional'):
334
plugin['has_build_conditional']=True
335
plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes" -a %(build_conditional)s' % plugin
337
plugin['has_build_conditional']=False
338
plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes"' %plugin
340
if plugin['install']:
341
plugin['library_type']= 'pkgplugin';
343
plugin['library_type']= 'noinst';
345
def find_testsuite(plugin_dir):
346
for testdir in ['drizzle-tests','tests']:
347
if os.path.isdir(os.path.join(plugin_dir,testdir)):
349
if os.path.isdir(os.path.join('tests','suite',os.path.basename(plugin_dir))):
353
def read_plugin_ini(plugin_dir):
354
if plugin_dir == ".":
355
plugin_name="**OUT-OF-TREE**"
357
plugin_name=os.path.basename(plugin_dir)
359
plugin_file= os.path.join(plugin_dir,plugin_ini_fname)
360
plugin_defaults= dict(sources="",
370
license="PLUGIN_LICENSE_GPL",
372
load_by_default="False",
375
install=default_install)
376
parser=ConfigParser.ConfigParser(defaults= plugin_defaults)
377
parser.read(plugin_file)
378
plugin=dict(parser.items('plugin'))
379
if plugin_dir == '.':
380
if not plugin.has_key('url'):
381
print "External Plugins are required to specifiy a url"
382
plugin['url']= 'http://launchpad.net/%(name)s' % plugin
384
if plugin_dir == '.' and not plugin.has_key('version'):
385
print "External Plugins are required to specifiy a version"
387
if not plugin.has_key('version'):
388
plugin['version'] = default_plugin_version
390
if plugin.has_key('load_by_default'):
391
plugin['load_by_default']=parser.getboolean('plugin','load_by_default')
392
if plugin.has_key('disabled'):
393
plugin['disabled']=parser.getboolean('plugin','disabled')
394
if plugin['disabled']:
395
plugin['enabled']="no"
397
plugin['enabled']="yes"
398
if plugin.has_key('static'):
399
plugin['static']= parser.getboolean('plugin','static')
400
if plugin.has_key('install'):
401
plugin['install']= parser.getboolean('plugin','install')
402
if plugin.has_key('testsuite'):
403
if plugin['testsuite'] == 'disable':
404
plugin['testsuite']= False
406
plugin_testsuite= find_testsuite(plugin_dir)
407
plugin['testsuitedir']=plugin_testsuite
408
if plugin_testsuite is not None:
409
plugin['testsuite']=True
411
plugin['testsuite']=False
413
plugin['cflags']+= extra_cflags
414
plugin['cppflags']+= extra_cppflags
415
plugin['cxxflags']+= extra_cxxflags
417
plugin['pname']= "lib%s%s%s" % (plugin_prefix, plugin['name'], plugin_suffix)
418
plugin['root_plugin_dir']= root_plugin_dir
419
plugin['plugin_prefix']= plugin_prefix
420
plugin['plugin_suffix']= plugin_suffix
421
plugin['pkgplugindir']= pkgplugindir
426
def write_plugin_am(plugin, plugin_am):
427
"""Write an automake fragment for this plugin.
429
:param plugin: The plugin dict.
430
:param plugin_am: The file to write to.
432
# The .plugin.ini.stamp avoids changing the datestamp on plugin.ini which can
433
# confuse VCS systems.
435
EXTRA_DIST += %(rel_path)s/plugin.ini
437
# Prevent errors when a plugin dir is removed
438
%(rel_path)s/plugin.ini:
441
if plugin['headers'] != "":
442
plugin_am.write("noinst_HEADERS += %(headers)s\n" % plugin)
443
if plugin['testsuite']:
444
if plugin.has_key('testsuitedir') and plugin['testsuitedir'] != "":
445
plugin_am.write("EXTRA_DIST += %(rel_path)s/%(testsuitedir)s\n" % plugin)
448
%(root_plugin_dir)s_%(plugin_prefix)s%(name)s_dir=${top_srcdir}/%(rel_path)s
449
EXTRA_DIST += %(rel_path)s/plugin.ini
450
if %(build_conditional_tag)s
451
noinst_LTLIBRARIES+=%(root_plugin_dir)s/%(pname)s.la
452
%(root_plugin_dir)s_%(pname)s_la_LIBADD=%(libs)s
453
%(root_plugin_dir)s_%(pname)s_la_DEPENDENCIES=%(libs)s
454
%(root_plugin_dir)s_%(pname)s_la_LDFLAGS=$(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
455
%(root_plugin_dir)s_%(pname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_MODULE_NAME=%(name)s -DPANDORA_MODULE_AUTHOR="%(author)s" -DPANDORA_MODULE_TITLE="%(title)s" -DPANDORA_MODULE_VERSION="%(version)s" -DPANDORA_MODULE_LICENSE=%(license)s %(cppflags)s
456
%(root_plugin_dir)s_%(pname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
457
%(root_plugin_dir)s_%(pname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
459
%(root_plugin_dir)s_%(pname)s_la_SOURCES=%(sources)s
460
PANDORA_DYNAMIC_LDADDS+=${top_builddir}/%(root_plugin_dir)s/%(pname)s.la
465
%(root_plugin_dir)s_%(plugin_prefix)s%(name)s_dir=${top_srcdir}/%(rel_path)s
466
EXTRA_DIST += %(rel_path)s/plugin.ini
467
if %(build_conditional_tag)s
468
%(library_type)s_LTLIBRARIES+=%(root_plugin_dir)s/%(pname)s.la
469
%(root_plugin_dir)s_%(pname)s_la_LDFLAGS=-avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
470
%(root_plugin_dir)s_%(pname)s_la_LIBADD=%(libs)s
471
%(root_plugin_dir)s_%(pname)s_la_DEPENDENCIES=%(libs)s
472
%(root_plugin_dir)s_%(pname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_DYNAMIC_PLUGIN -DPANDORA_MODULE_NAME=%(name)s -DPANDORA_MODULE_AUTHOR="%(author)s" -DPANDORA_MODULE_TITLE="%(title)s" -DPANDORA_MODULE_VERSION="%(version)s" -DPANDORA_MODULE_LICENSE=%(license)s %(cppflags)s
473
%(root_plugin_dir)s_%(pname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
474
%(root_plugin_dir)s_%(pname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
476
%(root_plugin_dir)s_%(pname)s_la_SOURCES=%(sources)s
479
plugin_am_file=os.path.join(plugin['rel_path'],'plugin.am')
480
if os.path.exists(plugin_am_file):
481
plugin_am.write('include %s\n' % plugin_am_file)
485
# I'm 3 seconds away from writing a comprehensive build solution
486
if not os.path.exists('config/pandora_vc_revinfo'):
487
if os.path.exists('.bzr'):
488
bzr_revno= subprocess.Popen(["bzr", "revno"], stdout=subprocess.PIPE).communicate()[0].strip()
489
rev_date= datetime.date.fromtimestamp(time.time())
490
default_plugin_version = "%d.%02d.%s" % (rev_date.year, rev_date.month, bzr_revno)
492
default_plugin_version=datetime.date.fromtimestamp(time.time()).isoformat()
494
# need to read config/pandora_vc_revno
495
pandora_vc_revno=open('config/pandora_vc_revinfo','r').read().split()
498
for revno_line in pandora_vc_revno:
499
(revno_key,revno_val)= revno_line.split("=")
500
if revno_key == 'PANDORA_VC_REVNO':
501
bzr_revno=revno_val.strip()
502
elif revno_key == 'PANDORA_RELEASE_DATE':
503
rev_date=revno_val.strip()
505
default_plugin_version = "%s.%s" % (rev_date, bzr_revno)
509
if arg.startswith('--top_srcdir='):
511
elif arg.startswith('--top_builddir='):
512
top_builddir=arg[14:]
513
elif arg == "--force-all":
514
actions=['plugin-list','pandora-plugin.am','write']
518
if len(actions) == 0:
519
actions.append('write')
521
def accumulate_plugins(arg, dirname, fnames):
522
# plugin_ini_fname is a name in dirname indicating dirname is a plugin.
523
if plugin_ini_fname in fnames:
525
os.path.walk(os.path.join(top_srcdir,root_plugin_dir),accumulate_plugins,plugin_list)
528
if not os.path.exists("config/pandora-plugin.am") or "write" in actions:
529
plugin_am_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.am'))
530
plugin_am_file.write("""
531
# always the current list, generated every build so keep this lean.
532
# pandora-plugin.list: datestamp preserved list
533
${srcdir}/config/pandora-plugin.list: .plugin.scan
535
@cd ${top_srcdir} && python config/pandora-plugin plugin-list
537
# Plugins affect configure; so to prevent configure running twice in a tarball
538
# build (once up front, once with the right list of plugins, we ship the
539
# generated list of plugins and the housekeeping material for that list so it
540
# is likewise not updated.
542
config/pandora-plugin.am \
543
config/pandora-plugin.ac \
544
config/pandora-plugin
547
# Seed the list of plugin LDADDS which plugins may extend.
548
PANDORA_DYNAMIC_LDADDS=
550
# plugin.stamp: graph dominator for creating all per pandora-plugin.ac/am
551
# files. This is invoked when the code to generate such files has altered.""")
553
if not os.path.exists("config/pandora-plugin.ac") or "write" in actions:
554
plugin_ac_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.ac'))
555
plugin_ac_file.write("dnl Generated file, run make to rebuild\n")
558
if os.path.exists('plugin.ini'):
559
# Are we in a plugin dir which wants to have a self-sufficient build system?
562
write_external_plugin()
564
plugin_list_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.list'))
565
for p in plugin_list:
566
plugin_list_file.write(p)
567
plugin_list_file.write("\n")
569
plugin_list_file.close()
571
if not os.path.exists("config/pandora-plugin.am") or 'write' in actions:
572
plugin_am_file.write("\n${top_srcdir}/config/pandora-plugin.am: ${top_srcdir}/config/pandora-plugin.list ${top_srcdir}/config/pandora-plugin ")
573
for plugin_dir in plugin_list:
574
plugin_am_file.write("\\\n\t%s/plugin.ini " % plugin_dir)
575
plugin_am_file.write("\n\tcd ${top_srcdir} && python config/pandora-plugin write\n")
576
for plugin_dir in plugin_list:
577
write_plugin(plugin_dir)
579
if plugin_am_file is not None:
580
plugin_am_file.close()
581
if plugin_ac_file is not None:
582
plugin_ac_file.close()