Merge PR#113
[geany-mirror.git] / wscript
blob3c88a0ea7586e9b2603d1daa80abd747f0884ab0
1 # -*- coding: utf-8 -*-
3 # WAF build script - this file is part of Geany, a fast and lightweight IDE
5 # Copyright 2008-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
6 # Copyright 2008-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 """
23 This is a WAF build script (http://code.google.com/p/waf/).
24 It can be used as an alternative build system to autotools
25 for Geany. It does not (yet) cover all of the autotools tests and
26 configure options but all important things are working.
27 "make dist" should be done with autotools, most other targets and
28 functions should work better (regarding performance and flexibility)
29 or at least equally.
31 Missing features: --enable-binreloc, make targets: dist, pdf (in doc/)
32 Known issues: Dependency handling is buggy, e.g. if src/document.h is
33               changed, depending source files are not rebuilt (maybe Waf bug).
35 The code of this file itself loosely follows PEP 8 with some exceptions
36 (line width 100 characters and some other minor things).
38 Requires WAF 1.6.1 and Python 2.5 (or later).
39 """
42 import sys
43 import os
44 import tempfile
45 from waflib import Logs, Options, Scripting, Utils
46 from waflib.Configure import ConfigurationContext
47 from waflib.Errors import WafError
48 from waflib.TaskGen import feature, before_method
49 from waflib.Tools.compiler_c import c_compiler
50 from waflib.Tools.compiler_cxx import cxx_compiler
53 APPNAME = 'geany'
54 VERSION = '1.25'
55 LINGUAS_FILE = os.path.join('po', 'LINGUAS')
56 MINIMUM_GTK_VERSION = '2.16.0'
57 MINIMUM_GTK3_VERSION = '3.0.0'
58 MINIMUM_GLIB_VERSION = '2.20.0'
60 top = '.'
61 out = '_build_'
64 mio_sources = set(['tagmanager/mio/mio.c'])
66 ctags_sources = set([
67     'tagmanager/ctags/abaqus.c',
68     'tagmanager/ctags/args.c',
69     'tagmanager/ctags/abc.c',
70     'tagmanager/ctags/actionscript.c',
71     'tagmanager/ctags/asciidoc.c',
72     'tagmanager/ctags/asm.c',
73     'tagmanager/ctags/basic.c',
74     'tagmanager/ctags/c.c',
75     'tagmanager/ctags/cobol.c',
76     'tagmanager/ctags/conf.c',
77     'tagmanager/ctags/css.c',
78     'tagmanager/ctags/ctags.c',
79     'tagmanager/ctags/diff.c',
80     'tagmanager/ctags/docbook.c',
81     'tagmanager/ctags/entry.c',
82     'tagmanager/ctags/fortran.c',
83     'tagmanager/ctags/get.c',
84     'tagmanager/ctags/haskell.c',
85     'tagmanager/ctags/haxe.c',
86     'tagmanager/ctags/html.c',
87     'tagmanager/ctags/js.c',
88     'tagmanager/ctags/keyword.c',
89     'tagmanager/ctags/latex.c',
90     'tagmanager/ctags/lregex.c',
91     'tagmanager/ctags/lua.c',
92     'tagmanager/ctags/make.c',
93     'tagmanager/ctags/markdown.c',
94     'tagmanager/ctags/matlab.c',
95     'tagmanager/ctags/nsis.c',
96     'tagmanager/ctags/nestlevel.c',
97     'tagmanager/ctags/objc.c',
98     'tagmanager/ctags/options.c',
99     'tagmanager/ctags/parse.c',
100     'tagmanager/ctags/pascal.c',
101     'tagmanager/ctags/r.c',
102     'tagmanager/ctags/perl.c',
103     'tagmanager/ctags/php.c',
104     'tagmanager/ctags/python.c',
105     'tagmanager/ctags/read.c',
106     'tagmanager/ctags/rest.c',
107     'tagmanager/ctags/ruby.c',
108     'tagmanager/ctags/rust.c',
109     'tagmanager/ctags/sh.c',
110     'tagmanager/ctags/sort.c',
111     'tagmanager/ctags/sql.c',
112     'tagmanager/ctags/strlist.c',
113     'tagmanager/ctags/txt2tags.c',
114     'tagmanager/ctags/tcl.c',
115     'tagmanager/ctags/vhdl.c',
116     'tagmanager/ctags/verilog.c',
117     'tagmanager/ctags/vstring.c'])
119 tagmanager_sources = set([
120     'tagmanager/src/tm_file_entry.c',
121     'tagmanager/src/tm_project.c',
122     'tagmanager/src/tm_source_file.c',
123     'tagmanager/src/tm_symbol.c',
124     'tagmanager/src/tm_tag.c',
125     'tagmanager/src/tm_tagmanager.c',
126     'tagmanager/src/tm_work_object.c',
127     'tagmanager/src/tm_workspace.c'])
129 scintilla_sources = set(['scintilla/gtk/scintilla-marshal.c'])
131 geany_sources = set([
132     'src/about.c', 'src/build.c', 'src/callbacks.c', 'src/dialogs.c', 'src/document.c',
133     'src/editor.c', 'src/encodings.c', 'src/filetypes.c', 'src/geanyentryaction.c',
134     'src/geanymenubuttonaction.c', 'src/geanyobject.c', 'src/geanywraplabel.c',
135     'src/highlighting.c', 'src/keybindings.c',
136     'src/keyfile.c', 'src/log.c', 'src/main.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c',
137     'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
138     'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
139     'src/symbols.c',
140     'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
141     'src/ui_utils.c', 'src/utils.c'])
143 geany_icons = {
144     'hicolor/16x16/apps':       ['16x16/classviewer-class.png',
145                                  '16x16/classviewer-macro.png',
146                                  '16x16/classviewer-member.png',
147                                  '16x16/classviewer-method.png',
148                                  '16x16/classviewer-namespace.png',
149                                  '16x16/classviewer-other.png',
150                                  '16x16/classviewer-struct.png',
151                                  '16x16/classviewer-var.png',
152                                  '16x16/geany.png'],
153     'hicolor/16x16/actions':    ['16x16/geany-build.png',
154                                  '16x16/geany-close-all.png',
155                                  '16x16/geany-save-all.png'],
156     'hicolor/24x24/actions':    ['24x24/geany-build.png',
157                                  '24x24/geany-close-all.png',
158                                  '24x24/geany-save-all.png'],
159     'hicolor/32x32/actions':    ['32x32/geany-build.png',
160                                  '32x32/geany-close-all.png',
161                                  '32x32/geany-save-all.png'],
162     'hicolor/48x48/actions':    ['48x48/geany-build.png',
163                                  '48x48/geany-close-all.png',
164                                  '48x48/geany-save-all.png'],
165     'hicolor/48x48/apps':       ['48x48/geany.png'],
166     'hicolor/scalable/apps':    ['scalable/geany.svg'],
167     'hicolor/scalable/actions': ['scalable/geany-build.svg',
168                                  'scalable/geany-close-all.svg',
169                                  'scalable/geany-save-all.svg'],
170     'Tango/16x16/actions':      ['tango/16x16/geany-save-all.png'],
171     'Tango/24x24/actions':      ['tango/24x24/geany-save-all.png'],
172     'Tango/32x32/actions':      ['tango/32x32/geany-save-all.png'],
173     'Tango/48x48/actions':      ['tango/48x48/geany-save-all.png'],
174     'Tango/scalable/actions':   ['tango/scalable/geany-save-all.svg']
176 geany_icons_indexes = {
177     'hicolor':  ['index.theme'],
178     'Tango':    ['tango/index.theme']
182 def configure(conf):
184     conf.check_waf_version(mini='1.6.1')
186     conf.load('compiler_c')
187     is_win32 = _target_is_win32(conf)
189     conf.check_cc(header_name='fcntl.h', mandatory=False)
190     conf.check_cc(header_name='fnmatch.h', mandatory=False)
191     conf.check_cc(header_name='glob.h', mandatory=False)
192     conf.check_cc(header_name='sys/time.h', mandatory=False)
193     conf.check_cc(header_name='sys/types.h', mandatory=False)
194     conf.check_cc(header_name='sys/stat.h', mandatory=False)
195     conf.define('HAVE_STDLIB_H', 1)  # are there systems without stdlib.h?
196     conf.define('STDC_HEADERS', 1)  # an optimistic guess ;-)
197     _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1)  # needed for CTags
199     conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
200     conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
201     conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
202     conf.check_cc(function_name='strstr', header_name='string.h')
204     conf.check_cc(function_name='pow', header_name='math.h', lib='m', uselib_store='M')
206     # check sunOS socket support
207     if Options.platform == 'sunos':
208         conf.check_cc(function_name='socket', lib='socket',
209                       header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
211     # check for cxx after the header and function checks have been done to ensure they are
212     # checked with cc not cxx
213     conf.load('compiler_cxx')
214     if is_win32:
215         conf.load('winres')
216     _load_intltool_if_available(conf)
218     # GTK / GIO version check
219     gtk_package_name = 'gtk+-3.0' if conf.options.use_gtk3 else 'gtk+-2.0'
220     minimum_gtk_version = MINIMUM_GTK3_VERSION if conf.options.use_gtk3 else MINIMUM_GTK_VERSION
221     conf.check_cfg(package=gtk_package_name, atleast_version=minimum_gtk_version, uselib_store='GTK',
222         mandatory=True, args='--cflags --libs')
223     conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
224         mandatory=True, args='--cflags --libs')
225     conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
226         mandatory=True, args='--cflags --libs')
227     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
228     gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
229     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
230     # remember GTK version for the build step
231     conf.env['gtk_package_name'] = gtk_package_name
232     conf.env['minimum_gtk_version'] = minimum_gtk_version
233     conf.env['use_gtk3'] = conf.options.use_gtk3
235     # Windows specials
236     if is_win32:
237         if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
238             # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
239             new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
240             _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
241             _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
242         _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
243         _add_to_env_and_define(conf, 'LIBDIR', '%s/lib' % conf.env['PREFIX'], quote=True)
244         conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
245         # overwrite LOCALEDIR to install message catalogues properly
246         conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share', 'locale')
247         # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
248         conf.undefine('DATADIR')
249         conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
250         conf.env.append_value('LINKFLAGS_cprogram', [
251             '-mwindows',
252             '-static-libgcc',
253             '-static-libstdc++'])
254         conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'iberty'])
255     else:
256         conf.env['cshlib_PATTERN'] = '%s.so'
257         # DATADIR and LOCALEDIR are defined by the intltool tool
258         # but they are not added to the environment, so we need to
259         _add_define_to_env(conf, 'DATADIR')
260         _add_define_to_env(conf, 'LOCALEDIR')
261         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
262         libdir = os.path.join(conf.env['PREFIX'], 'lib')
263         mandir = os.path.join(conf.env['DATADIR'], 'man')
264         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
265         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
266         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
268     revision = _get_git_rev(conf)
270     conf.define('ENABLE_NLS', 1)
271     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
272     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
273     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
274     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
275     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
276     conf.define('PACKAGE', APPNAME, quote=True)
277     conf.define('VERSION', VERSION, quote=True)
278     conf.define('REVISION', revision or '-1', quote=True)
280     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
282     # no VTE on Windows
283     if is_win32:
284         conf.options.no_vte = True
286     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
287     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
288     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
290     conf.write_config_header('config.h', remove=False)
292     # some more compiler flags
293     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
294     if revision is not None:
295         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
296     # Scintilla flags
297     conf.env.append_value('CFLAGS', ['-DGTK'])
298     conf.env.append_value('CXXFLAGS',
299         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
301     # summary
302     Logs.pprint('BLUE', 'Summary:')
303     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
304     conf.msg('Using GTK version', gtk_version)
305     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
306     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
307     if revision is not None:
308         conf.msg('Compiling Git revision', revision)
311 def options(opt):
312     # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
313     # If anyone wants to add support for building with MSVC, this hack should be removed.
314     c_compiler['win32'] = ['gcc']
315     cxx_compiler['win32'] = ['g++']
317     opt.load('compiler_cc')
318     opt.load('compiler_cxx')
319     opt.load('intltool')
321     # Option
322     opt.add_option('--no-scm', action='store_true', default=False,
323         help='Disable SCM detection [default: No]', dest='no_scm')
324     # Features
325     opt.add_option('--disable-plugins', action='store_true', default=False,
326         help='compile without plugin support [default: No]', dest='no_plugins')
327     opt.add_option('--disable-socket', action='store_true', default=False,
328         help='compile without support to detect a running instance [[default: No]',
329         dest='no_socket')
330     opt.add_option('--disable-vte', action='store_true', default=False,
331         help='compile without support for an embedded virtual terminal [[default: No]',
332         dest='no_vte')
333     opt.add_option('--enable-gtk3', action='store_true', default=False,
334         help='compile with GTK3 support (experimental) [[default: No]',
335         dest='use_gtk3')
336     # Paths
337     opt.add_option('--mandir', type='string', default='',
338         help='man documentation', dest='mandir')
339     opt.add_option('--docdir', type='string', default='',
340         help='documentation root', dest='docdir')
341     opt.add_option('--libdir', type='string', default='',
342         help='object code libraries', dest='libdir')
343     # Actions
344     opt.add_option('--hackingdoc', action='store_true', default=False,
345         help='generate HTML documentation from HACKING file', dest='hackingdoc')
348 def build(bld):
349     is_win32 = _target_is_win32(bld)
351     if bld.cmd == 'clean':
352         _remove_linguas_file()
353     if bld.cmd in ('install', 'uninstall'):
354         bld.add_post_fun(_post_install)
356     def build_plugin(plugin_name, install=True, uselib_add=[]):
357         if install:
358             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
359         else:
360             instpath = None
362         bld(
363             features                = ['c', 'cshlib'],
364             source                  = 'plugins/%s.c' % plugin_name,
365             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
366             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
367             target                  = plugin_name,
368             uselib                  = ['GTK', 'GLIB', 'GMODULE'] + uselib_add,
369             install_path            = instpath)
371     # CTags
372     bld(
373         features        = ['c', 'cstlib'],
374         source          = ctags_sources,
375         name            = 'ctags',
376         target          = 'ctags',
377         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
378         defines         = 'G_LOG_DOMAIN="CTags"',
379         uselib          = ['GLIB'],
380         install_path    = None)  # do not install this library
382     # Tagmanager
383     bld(
384         features        = ['c', 'cstlib'],
385         source          = tagmanager_sources,
386         name            = 'tagmanager',
387         target          = 'tagmanager',
388         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
389         defines         = 'G_LOG_DOMAIN="Tagmanager"',
390         uselib          = ['GTK', 'GLIB'],
391         install_path    = None)  # do not install this library
393     # MIO
394     bld(
395         features        = ['c', 'cstlib'],
396         source          = mio_sources,
397         name            = 'mio',
398         target          = 'mio',
399         includes        = ['.', 'tagmanager/mio/'],
400         defines         = 'G_LOG_DOMAIN="MIO"',
401         uselib          = ['GTK', 'GLIB'],
402         install_path    = None)  # do not install this library
404     # Scintilla
405     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
406     scintilla_sources.update(files)
407     bld(
408         features        = ['c', 'cxx', 'cxxstlib'],
409         name            = 'scintilla',
410         target          = 'scintilla',
411         source          = scintilla_sources,
412         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
413         uselib          = ['GTK', 'GLIB', 'GMODULE', 'M'],
414         install_path    = None)  # do not install this library
416     # Geany
417     if bld.env['HAVE_VTE'] == 1:
418         geany_sources.add('src/vte.c')
419     if is_win32:
420         geany_sources.add('src/win32.c')
421         geany_sources.add('geany_private.rc')
423     bld(
424         features        = ['c', 'cxx', 'cprogram'],
425         name            = 'geany',
426         target          = 'geany',
427         source          = geany_sources,
428         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
429         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
430         uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET', 'M'],
431         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'])
433     # geanyfunctions.h
434     bld(
435         source  = ['plugins/genapi.py', 'src/plugins.c'],
436         name    = 'geanyfunctions.h',
437         before  = ['c', 'cxx'],
438         cwd     = '%s/plugins' % bld.path.abspath(),
439         rule    = '%s genapi.py -q' % sys.executable)
441     # Plugins
442     if bld.env['HAVE_PLUGINS'] == 1:
443         build_plugin('classbuilder')
444         build_plugin('demoplugin', False)
445         build_plugin('export', uselib_add=['M'])
446         build_plugin('filebrowser')
447         build_plugin('htmlchars')
448         build_plugin('saveactions')
449         build_plugin('splitwindow')
451     # Translations
452     if bld.env['INTLTOOL']:
453         bld(
454             features        = ['linguas', 'intltool_po'],
455             podir           = 'po',
456             install_path    = '${LOCALEDIR}',
457             appname         = 'geany')
459     # geany.pc
460     bld(
461         source          = 'geany.pc.in',
462         dct             = {'VERSION': VERSION,
463                            'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
464                                 (bld.env['gtk_package_name'],
465                                  bld.env['minimum_gtk_version'],
466                                  MINIMUM_GLIB_VERSION),
467                            'prefix': bld.env['PREFIX'],
468                            'exec_prefix': '${prefix}',
469                            'libdir': os.path.join('${exec_prefix}', 'lib'),
470                            'includedir': os.path.join('${prefix}', 'include'),
471                            'datarootdir': os.path.join('${prefix}', 'share'),
472                            'datadir': '${datarootdir}',
473                            'localedir': os.path.join('${datarootdir}', 'locale')})
475     if not is_win32:
476         # geany.desktop
477         if bld.env['INTLTOOL']:
478             bld(
479                 features        = 'intltool_in',
480                 source          = 'geany.desktop.in',
481                 flags           = ['-d', '-q', '-u', '-c'],
482                 install_path    = '${DATADIR}/applications')
484         # geany.1
485         bld(
486             features        = 'subst',
487             source          = 'doc/geany.1.in',
488             target          = 'geany.1',
489             dct             = {'VERSION': VERSION,
490                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
491             install_path    = '${MANDIR}/man1')
493         # geany.spec
494         bld(
495             features        = 'subst',
496             source          = 'geany.spec.in',
497             target          = 'geany.spec',
498             install_path    = None,
499             dct             = {'VERSION': VERSION})
501         # Doxyfile
502         bld(
503             features        = 'subst',
504             source          = 'doc/Doxyfile.in',
505             target          = 'doc/Doxyfile',
506             install_path    = None,
507             dct             = {'VERSION': VERSION,
508                                'top_builddir': bld.out_dir,
509                                'top_srcdir': bld.top_dir,})
511     ###
512     # Install files
513     ###
514     # Headers
515     bld.install_files('${PREFIX}/include/geany', '''
516         src/app.h src/document.h src/editor.h src/encodings.h src/filetypes.h src/geany.h
517         src/highlighting.h src/keybindings.h src/msgwindow.h src/plugindata.h
518         src/prefs.h src/project.h src/search.h src/stash.h src/support.h
519         src/templates.h src/toolbar.h src/ui_utils.h src/utils.h src/build.h src/gtkcompat.h
520         plugins/geanyplugin.h plugins/geanyfunctions.h''')
521     bld.install_files('${PREFIX}/include/geany/scintilla', '''
522         scintilla/include/SciLexer.h scintilla/include/Scintilla.h
523         scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
524     bld.install_files('${PREFIX}/include/geany/tagmanager', '''
525         tagmanager/src/tm_file_entry.h tagmanager/src/tm_project.h
526         tagmanager/src/tm_source_file.h tagmanager/src/tm_parser.h
527         tagmanager/src/tm_symbol.h tagmanager/src/tm_tag.h
528         tagmanager/src/tm_tagmanager.h tagmanager/src/tm_work_object.h
529         tagmanager/src/tm_workspace.h ''')
530     # Docs
531     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
532     ext = '.txt' if is_win32 else ''
533     html_dir = '' if is_win32 else 'html/'
534     html_name = 'Manual.html' if is_win32 else 'index.html'
535     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
536         basename = _uc_first(filename, bld)
537         destination_filename = '%s%s' % (basename, ext)
538         destination = os.path.join(base_dir, destination_filename)
539         bld.install_as(destination, filename)
541     start_dir = bld.path.find_dir('doc/images')
542     bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
543     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
544     bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
545     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
546     if is_win32:
547         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
548         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
549     # Data
550     data_dir = '' if is_win32 else 'geany'
551     start_dir = bld.path.find_dir('data')
552     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
553     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
554     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
555     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
556     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
557     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
558     if bld.env['use_gtk3']:
559         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
560     else:
561         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
563     start_dir = bld.path.find_dir('data/colorschemes')
564     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
565     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
566     start_dir = bld.path.find_dir('data/templates')
567     template_dest = '${DATADIR}/%s/templates' % data_dir
568     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
569     # Icons
570     for dest, srcs in geany_icons.items():
571         dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
572         bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
573     # install theme indexes on Windows
574     if is_win32:
575         for dest, srcs in geany_icons_indexes.items():
576             bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
579 def distclean(ctx):
580     Scripting.distclean(ctx)
581     _remove_linguas_file()
584 def _remove_linguas_file():
585     # remove LINGUAS file as well
586     try:
587         os.unlink(LINGUAS_FILE)
588     except OSError:
589         pass
592 @feature('linguas')
593 @before_method('apply_intltool_po')
594 def write_linguas_file(self):
595     if os.path.exists(LINGUAS_FILE):
596         return
597     linguas = ''
598     if 'LINGUAS' in self.env:
599         files = self.env['LINGUAS']
600         for po_filename in files.split(' '):
601             if os.path.exists('po/%s.po' % po_filename):
602                 linguas += '%s ' % po_filename
603     else:
604         files = os.listdir('%s/po' % self.path.abspath())
605         files.sort()
606         for filename in files:
607             if filename.endswith('.po'):
608                 linguas += '%s ' % filename[:-3]
609     file_h = open(LINGUAS_FILE, 'w')
610     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
611     file_h.close()
614 def _post_install(ctx):
615     is_win32 = _target_is_win32(ctx)
616     if is_win32:
617         return
618     for d in 'hicolor', 'Tango':
619         theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
620         icon_cache_updated = False
621         if not ctx.options.destdir:
622             ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
623             Logs.pprint('GREEN', 'GTK icon cache updated.')
624             icon_cache_updated = True
625         if not icon_cache_updated:
626             Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
627             Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
630 def updatepo(ctx):
631     """update the message catalogs for internationalization"""
632     potfile = '%s.pot' % APPNAME
633     os.chdir('%s/po' % top)
634     try:
635         try:
636             old_size = os.stat(potfile).st_size
637         except OSError:
638             old_size = 0
639         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
640         size_new = os.stat(potfile).st_size
641         if size_new != old_size:
642             Logs.pprint('CYAN', 'Updated POT file.')
643             Logs.pprint('CYAN', 'Updating translations')
644             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
645             if ret != 0:
646                 Logs.pprint('RED', 'Updating translations failed')
647         else:
648             Logs.pprint('CYAN', 'POT file is up to date.')
649     except OSError:
650         Logs.pprint('RED', 'Failed to generate pot file.')
653 def apidoc(ctx):
654     """generate API reference documentation"""
655     basedir = ctx.path.abspath()
656     doxygen = _find_program(ctx, 'doxygen')
657     doxyfile = '%s/%s/doc/Doxyfile' % (basedir, out)
658     os.chdir('doc')
659     Logs.pprint('CYAN', 'Generating API documentation')
660     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
661     if ret != 0:
662         raise WafError('Generating API documentation failed')
663     # update hacking.html
664     cmd = _find_rst2html(ctx)
665     ctx.exec_command('%s  -stg --stylesheet=geany.css %s %s' % (cmd, '../HACKING', 'hacking.html'))
666     os.chdir('..')
669 def htmldoc(ctx):
670     """generate HTML documentation"""
671     # first try rst2html.py as it is the upstream default, fall back to rst2html
672     cmd = _find_rst2html(ctx)
673     os.chdir('doc')
674     Logs.pprint('CYAN', 'Generating HTML documentation')
675     ctx.exec_command('%s  -stg --stylesheet=geany.css %s %s' % (cmd, 'geany.txt', 'geany.html'))
676     os.chdir('..')
679 def _find_program(ctx, cmd, **kw):
680     def noop(*args):
681         pass
683     ctx = ConfigurationContext()
684     ctx.to_log = noop
685     ctx.msg = noop
686     return ctx.find_program(cmd, **kw)
689 def _find_rst2html(ctx):
690     cmds = ['rst2html.py', 'rst2html']
691     for command in cmds:
692         cmd = _find_program(ctx, command, mandatory=False)
693         if cmd:
694             break
695     if not cmd:
696         raise WafError(
697             'rst2html.py could not be found. Please install the Python docutils package.')
698     return cmd
701 def _add_define_to_env(conf, key):
702     value = conf.get_define(key)
703     # strip quotes
704     value = value.replace('"', '')
705     conf.env[key] = value
708 def _add_to_env_and_define(conf, key, value, quote=False):
709     conf.define(key, value, quote)
710     conf.env[key] = value
713 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
714     value = default_value
715     if opt_value:
716         if isinstance(opt_value, bool):
717             opt_value = 1
718         value = opt_value
720     if value is not None:
721         _add_to_env_and_define(conf, define_name, value, quote)
722     else:
723         conf.undefine(define_name)
726 def _get_git_rev(conf):
727     if conf.options.no_scm:
728         return
730     if not os.path.isdir('.git'):
731         return
733     try:
734         cmd = 'git rev-parse --short --revs-only HEAD'
735         revision = conf.cmd_and_log(cmd).strip()
736     except WafError:
737         return None
738     else:
739         return revision
742 def _load_intltool_if_available(conf):
743     try:
744         conf.load('intltool')
745         if 'LINGUAS' in os.environ:
746             conf.env['LINGUAS'] = os.environ['LINGUAS']
747     except WafError:
748         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
749         if not _target_is_win32(conf):
750             raise
753 def _target_is_win32(ctx):
754     if 'is_win32' in ctx.env:
755         # cached
756         return ctx.env['is_win32']
757     is_win32 = None
758     if sys.platform == 'win32':
759         is_win32 = True
760     if is_win32 is None:
761         if ctx.env and 'CC' in ctx.env:
762             env_cc = ctx.env['CC']
763             if not isinstance(env_cc, str):
764                 env_cc = ''.join(env_cc)
765             is_win32 = (env_cc.find('mingw') != -1)
766     if is_win32 is None:
767         is_win32 = False
768     # cache for future checks
769     ctx.env['is_win32'] = is_win32
770     return is_win32
773 def _uc_first(string, ctx):
774     if _target_is_win32(ctx):
775         return string.title()
776     return string