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
26
plugin_ini_fname='plugin.ini'
34
extra_cxxflags=' -DBUILDING_SCALESTACK'
35
root_plugin_dir='ScaleStack'
36
pkgplugindir='$(libdir)/ScaleStack'
38
class ChangeProtectedFile(object):
40
def __init__(self, fname):
41
self.bogus_file= False
42
self.real_fname= fname
43
self.new_fname= "%s.new" % fname
45
self.new_file= open(self.new_fname,'w+')
49
def write(self, text):
50
if not self.bogus_file:
51
self.new_file.write(text)
53
# We've written all of this out into .new files, now we only copy them
54
# over the old ones if they are different, so that we don't cause
55
# unnecessary recompiles
57
"""Return True if the file had changed."""
61
new_content = self.new_file.read()
64
old_file = file(self.real_fname, 'r')
65
old_content = old_file.read()
69
if new_content != old_content:
70
if old_content != None:
71
os.unlink(self.real_fname)
72
os.rename(self.new_fname, self.real_fname)
76
os.unlink(self.new_fname)
81
def write_external_configure(plugin, plugin_file):
82
"""Write the initial bits of the configure.ac file"""
83
if not os.path.exists('m4'):
86
AC_PREREQ(2.59)dnl Minimum Autoconf version required.
87
AC_INIT([%(name)s],[%(version)s],[%(url)s])
88
AC_CONFIG_SRCDIR([%(main_source)s])
89
AC_CONFIG_AUX_DIR(config)
90
AC_CONFIG_HEADERS([config.h])
91
AC_CONFIG_MACRO_DIR([m4])
93
PANDORA_CANONICAL_TARGET(less-warnings, warnings-always-on, require-cxx, force-gcc42,skip-visibility)
95
PANDORA_REQUIRE_LIBPROTOBUF
96
PANDORA_PROTOBUF_REQUIRE_VERSION([2.1.0])
97
PANDORA_REQUIRE_PROTOC
100
PANDORA_REQUIRE_PTHREAD
101
PANDORA_REQUIRE_LIBDL
104
PANDORA_USE_BETTER_MALLOC
106
PANDORA_DRIZZLE_BUILD
109
write_plugin_ac(plugin, plugin_file)
111
plugin_file.write("""
112
AC_CONFIG_FILES(Makefile)
117
echo "Configuration summary for $PACKAGE_NAME version $VERSION $PANDORA_RELEASE_COMMENT"
119
echo " * Installation prefix: $prefix"
120
echo " * System type: $host_vendor-$host_os"
121
echo " * Host CPU: $host_cpu"
122
echo " * C Compiler: $CC_VERSION"
123
echo " * C++ Compiler: $CXX_VERSION"
124
echo " * Debug enabled: $with_debug"
125
echo " * Warnings as failure: $ac_cv_warnings_as_errors"
126
echo " * C++ cstdint location: $ac_cv_cxx_cstdint"
127
echo " * C++ hash_map location: $ac_cv_cxx_hash_map"
128
echo " * C++ hash namespace: $ac_cv_cxx_hash_namespace"
129
echo " * C++ shared_ptr namespace: $ac_cv_shared_ptr_namespace"
135
def write_external_makefile(plugin, plugin_file):
137
plugin_file.write("""
138
ACLOCAL_AMFLAGS = -I m4 --force
139
VERSION=$(PANDORA_RELEASE_VERSION)
141
pkgplugindir=%(pkgplugindir)s
142
EXTRA_DIST = plugin.ini
145
if plugin['headers'] != "":
146
plugin_file.write("noinst_HEADERS = %(headers)s\n" % plugin)
147
if plugin['testsuite']:
148
if plugin.has_key('testsuitedir') and plugin['testsuitedir'] != "":
149
plugin_file.write("EXTRA_DIST += %(testsuitedir)s\n" % plugin)
150
plugin_file.write("""
151
pkgplugin_LTLIBRARIES=%(pname)s.la
152
%(pname)s_la_LDFLAGS=-module -avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
153
%(pname)s_la_LIBADD=%(libs)s
154
%(pname)s_la_DEPENDENCIES=%(libs)s
155
%(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
156
%(pname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
157
%(pname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
159
%(pname)s_la_SOURCES=%(sources)s
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)
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
179
def write_plugin(plugin_dir):
180
"""Return True if the plugin had changed."""
181
plugin = read_plugin_ini(plugin_dir)
182
expand_plugin_ini(plugin, plugin_dir)
183
write_plugin_ac(plugin, plugin_ac_file)
184
write_plugin_am(plugin, plugin_am_file)
186
def write_plugin_ac(plugin, plugin_ac):
188
# Write plugin config instructions into plugin.ac file.
190
plugin_ac_file=os.path.join(plugin['rel_path'],'plugin.ac')
191
plugin_m4_dir=os.path.join(plugin['rel_path'],'m4')
193
if os.path.exists(plugin_m4_dir) and os.path.isdir(plugin_m4_dir):
194
for m4_file in os.listdir(plugin_m4_dir):
195
if os.path.splitext(m4_file)[-1] == '.m4':
196
plugin_m4_files.append(os.path.join(plugin['rel_path'], m4_file))
198
dnl Config for %(title)s
200
for m4_file in plugin_m4_files:
201
plugin_ac.write('m4_sinclude([%s])\n' % m4_file)
202
plugin['plugin_dep_libs']=" ".join(["\${top_builddir}/%s" % f for f in plugin['libs'].split()])
206
dnl This plugin is staticly built, which means we cannot live without and it is not
207
dnl possible to disable it. Once it is disableable, we will make it non-static.
208
with_%(name)s_plugin=yes
209
pandora_builtin_list="_drizzled_%(name)s_plugin_,${pandora_builtin_list}"
210
pandora_plugin_libs="${pandora_plugin_libs} \${top_builddir}/%(root_plugin_dir)s/%(pname)s_plugin.la"
211
PANDORA_PLUGIN_DEP_LIBS="${PANDORA_PLUGIN_DEP_LIBS} %(plugin_dep_libs)s"
214
if plugin['testsuite']:
216
pandora_plugin_test_list="%(name)s,${pandora_plugin_test_list}"
220
AC_ARG_WITH([%(name_with_dashes)s-plugin],[
221
dnl indented wierd to make the help output correct
222
AS_HELP_STRING([--with-%(name_with_dashes)s-plugin],[Build %(title)s. @<:@default=%(enabled)s@:>@])
223
AS_HELP_STRING([--without-%(name_with_dashes)s-plugin],[Disable building %(title)s])
225
with_%(name)s_plugin="$withval"
226
requested_%(name)s_plugin="yes"
228
with_%(name)s_plugin="%(enabled)s"
229
requested_%(name)s_plugin="no"
231
AC_ARG_ENABLE([%(name_with_dashes)s-plugin],[
232
dnl indented wierd to make the help output correct
233
AS_HELP_STRING([--enable-%(name_with_dashes)s-plugin],[Build %(title)s. @<:@default=%(default_yesno)s@:>@])
234
AS_HELP_STRING([--disable-%(name_with_dashes)s-plugin],[Disable building %(title)s])
236
[enable_%(name)s_plugin="$withval"],
237
[enable_%(name)s_plugin=%(default_yesno)s])
240
if os.path.exists(plugin_ac_file):
241
plugin_ac.write('m4_sinclude([%s])\n' % plugin_ac_file)
242
# The plugin author has specified some check to make to determine
243
# if the plugin can be built. If the plugin is turned on and this
244
# check fails, then configure should error out. If the plugin is not
245
# turned on, then the normal conditional build stuff should just let
246
# it silently not build
247
if plugin['has_build_conditional']:
249
AS_IF([test %(build_conditional)s],
250
[], dnl build_conditional can only negate
252
AS_IF([test "x${requested_%(name)s_plugin}" = "xyes"],
253
[AC_MSG_ERROR([Plugin %(name)s was explicitly requested, yet failed build dependency checks. Aborting!])])
254
with_%(name)s_plugin=no
258
if not plugin['unconditional']:
260
AM_CONDITIONAL([%(build_conditional_tag)s],
261
[test %(build_conditional)s])
263
if not plugin['static']:
265
AS_IF([test "x$with_%(name)s_plugin" = "xyes"],
268
if plugin['testsuite']:
270
pandora_plugin_test_list="%(name)s,${pandora_plugin_test_list}"
274
AS_IF([test "x$enable_%(name)s_plugin" = "xyes"],[
275
pandora_default_plugin_list="%(name)s,${pandora_default_plugin_list}"
278
plugin_ac.write(" ])\n")
281
def expand_plugin_ini(plugin, plugin_dir):
282
if plugin_dir == ".":
283
plugin['rel_path']= plugin_dir
284
plugin['unconditional']=True
286
plugin['rel_path']= plugin_dir[len(top_srcdir)+len(os.path.sep):]
287
plugin['unconditional']=False
288
# TODO: determine path to plugin dir relative to top_srcdir... append it to
289
# source files if they don't already have it
290
if plugin['sources'] == "":
291
plugin['sources']="%s.cc" % plugin['name']
293
if plugin_dir != ".":
294
for src in plugin['sources'].split():
295
if not src.startswith(plugin['rel_path']):
296
src= os.path.join(plugin['rel_path'], src)
297
new_sources= "%s %s" % (new_sources, src)
298
if new_sources != "":
299
plugin['sources']= new_sources
300
plugin['main_source']= plugin['sources'].split()[0]
302
if plugin_dir != ".":
304
for header in plugin['headers'].split():
305
if not header.startswith(plugin['rel_path']):
306
header= os.path.join(plugin['rel_path'], header)
307
new_headers= "%s %s" % (new_headers, header)
308
plugin['headers']= new_headers
310
# Make a yes/no version for autoconf help messages
311
if plugin['load_by_default']:
312
plugin['default_yesno']="yes"
314
plugin['default_yesno']="no"
317
plugin['build_conditional_tag']= "BUILD_%s_PLUGIN" % plugin['name'].upper()
318
plugin['name_with_dashes']= plugin['name'].replace('_','-')
319
if plugin.has_key('build_conditional'):
320
plugin['has_build_conditional']=True
321
plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes" -a %(build_conditional)s' % plugin
323
plugin['has_build_conditional']=False
324
plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes"' %plugin
326
def find_testsuite(plugin_dir):
327
for testdir in ['drizzle-tests','tests']:
328
if os.path.isdir(os.path.join(plugin_dir,testdir)):
330
if os.path.isdir(os.path.join('tests','suite',os.path.basename(plugin_dir))):
334
def read_plugin_ini(plugin_dir):
335
plugin_file= os.path.join(plugin_dir,plugin_ini_fname)
336
plugin_defaults= dict(sources="",
346
license="PLUGIN_LICENSE_GPL",
347
name=os.path.basename(plugin_dir),
348
load_by_default="False",
351
parser=ConfigParser.ConfigParser(defaults= plugin_defaults)
352
parser.read(plugin_file)
353
plugin=dict(parser.items('plugin'))
354
if plugin_dir == '.':
355
if not plugin.has_key('url'):
356
print "External Plugins are required to specifiy a url"
357
plugin['url']= 'http://launchpad.net/%(name)s' % plugin
359
if plugin_dir == '.' and not plugin.has_key('version'):
360
print "External Plugins are required to specifiy a version"
362
if not plugin.has_key('version'):
363
plugin['version']=datetime.date.fromtimestamp(time.time()).isoformat()
365
if plugin.has_key('load_by_default'):
366
plugin['load_by_default']=parser.getboolean('plugin','load_by_default')
367
if plugin.has_key('disabled'):
368
plugin['disabled']=parser.getboolean('plugin','disabled')
369
if plugin['disabled']:
370
plugin['enabled']="no"
372
plugin['enabled']="yes"
373
if plugin.has_key('static'):
374
plugin['static']= parser.getboolean('plugin','static')
375
if plugin.has_key('testsuite'):
376
if plugin['testsuite'] == 'disable':
377
plugin['testsuite']= False
379
plugin_testsuite= find_testsuite(plugin_dir)
380
plugin['testsuitedir']=plugin_testsuite
381
if plugin_testsuite is not None:
382
plugin['testsuite']=True
384
plugin['testsuite']=False
386
plugin['cflags']+= extra_cflags
387
plugin['cppflags']+= extra_cppflags
388
plugin['cxxflags']+= extra_cxxflags
390
plugin['pname']= "%s%s%s" % (plugin_prefix, plugin['name'], plugin_suffix)
391
plugin['root_plugin_dir']= root_plugin_dir
392
plugin['plugin_prefix']= plugin_prefix
393
plugin['plugin_suffix']= plugin_suffix
394
plugin['pkgplugindir']= pkgplugindir
399
def write_plugin_am(plugin, plugin_am):
400
"""Write an automake fragment for this plugin.
402
:param plugin: The plugin dict.
403
:param plugin_am: The file to write to.
405
# The .plugin.ini.stamp avoids changing the datestamp on plugin.ini which can
406
# confuse VCS systems.
408
EXTRA_DIST += %(rel_path)s/plugin.ini
410
# Prevent errors when a plugin dir is removed
411
%(rel_path)s/plugin.ini:
414
if plugin['headers'] != "":
415
plugin_am.write("noinst_HEADERS += %(headers)s\n" % plugin)
416
if plugin['testsuite']:
417
if plugin.has_key('testsuitedir') and plugin['testsuitedir'] != "":
418
plugin_am.write("EXTRA_DIST += %(rel_path)s/%(testsuitedir)s\n" % plugin)
421
%(root_plugin_dir)s_%(plugin_prefix)s%(name)s_dir=${top_srcdir}/%(rel_path)s
422
EXTRA_DIST += %(rel_path)s/plugin.ini
423
if %(build_conditional_tag)s
424
noinst_LTLIBRARIES+=%(root_plugin_dir)s/%(pname)s.la
425
%(root_plugin_dir)s_%(pname)s_la_LIBADD=%(libs)s
426
%(root_plugin_dir)s_%(pname)s_la_DEPENDENCIES=%(libs)s
427
%(root_plugin_dir)s_%(pname)s_la_LDFLAGS=$(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
428
%(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
429
%(root_plugin_dir)s_%(pname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
430
%(root_plugin_dir)s_%(pname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
432
%(root_plugin_dir)s_%(pname)s_la_SOURCES=%(sources)s
433
PANDORA_DYNAMIC_LDADDS+=${top_builddir}/%(root_plugin_dir)s/%(pname)s.la
438
%(root_plugin_dir)s_%(plugin_prefix)s%(name)s_dir=${top_srcdir}/%(rel_path)s
439
EXTRA_DIST += %(rel_path)s/plugin.ini
440
if %(build_conditional_tag)s
441
pkgplugin_LTLIBRARIES+=%(root_plugin_dir)s/%(pname)s.la
442
%(root_plugin_dir)s_%(pname)s_la_LDFLAGS=-module -avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
443
%(root_plugin_dir)s_%(pname)s_la_LIBADD=%(libs)s
444
%(root_plugin_dir)s_%(pname)s_la_DEPENDENCIES=%(libs)s
445
%(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
446
%(root_plugin_dir)s_%(pname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
447
%(root_plugin_dir)s_%(pname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
449
%(root_plugin_dir)s_%(pname)s_la_SOURCES=%(sources)s
452
plugin_am_file=os.path.join(plugin['rel_path'],'plugin.am')
453
if os.path.exists(plugin_am_file):
454
plugin_am.write('include %s\n' % plugin_am_file)
460
if arg.startswith('--top_srcdir='):
462
elif arg.startswith('--top_builddir='):
463
top_builddir=arg[14:]
464
elif arg == "--force-all":
465
actions=['plugin-list','pandora-plugin.am','write']
469
if len(actions) == 0:
470
actions.append('write')
472
def accumulate_plugins(arg, dirname, fnames):
473
# plugin_ini_fname is a name in dirname indicating dirname is a plugin.
474
if plugin_ini_fname in fnames:
476
os.path.walk(os.path.join(top_srcdir,root_plugin_dir),accumulate_plugins,plugin_list)
479
if not os.path.exists("config/pandora-plugin.am") or "write" in actions:
480
plugin_am_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.am'))
481
plugin_am_file.write("""
482
# always the current list, generated every build so keep this lean.
483
# pandora-plugin.list: datestamp preserved list
484
${srcdir}/config/pandora-plugin.list: .plugin.scan
486
@cd ${top_srcdir} && python config/pandora-plugin plugin-list
488
# Plugins affect configure; so to prevent configure running twice in a tarball
489
# build (once up front, once with the right list of plugins, we ship the
490
# generated list of plugins and the housekeeping material for that list so it
491
# is likewise not updated.
493
config/pandora-plugin.am \
494
config/pandora-plugin.ac \
495
config/pandora-plugin
498
# Seed the list of plugin LDADDS which plugins may extend.
499
PANDORA_DYNAMIC_LDADDS=
501
# plugin.stamp: graph dominator for creating all per pandora-plugin.ac/am
502
# files. This is invoked when the code to generate such files has altered.""")
504
if not os.path.exists("config/pandora-plugin.ac") or "write" in actions:
505
plugin_ac_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.ac'))
506
plugin_ac_file.write("dnl Generated file, run make to rebuild\n")
509
if os.path.exists('plugin.ini'):
510
# Are we in a plugin dir which wants to have a self-sufficient build system?
513
write_external_plugin()
515
plugin_list_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.list'))
516
for p in plugin_list:
517
plugin_list_file.write(p)
518
plugin_list_file.write("\n")
520
plugin_list_file.close()
522
if not os.path.exists("config/pandora-plugin.am") or 'write' in actions:
523
plugin_am_file.write("\n${top_srcdir}/config/pandora-plugin.am: ${top_srcdir}/config/pandora-plugin.list ${top_srcdir}/config/pandora-plugin ")
524
for plugin_dir in plugin_list:
525
plugin_am_file.write("\\\n\t%s/plugin.ini " % plugin_dir)
526
plugin_am_file.write("\n\tcd ${top_srcdir} && python config/pandora-plugin write\n")
527
for plugin_dir in plugin_list:
528
write_plugin(plugin_dir)
530
if plugin_am_file is not None:
531
plugin_am_file.close()
532
if plugin_ac_file is not None:
533
plugin_ac_file.close()