Bump Geany API and ABI for TagManager API changes
[geany-mirror.git] / wscript
blobeb81b4d49225f71c72e84971d0b422d70eb0ab12
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.Build import BuildContext
47 from waflib.Configure import ConfigurationContext
48 from waflib.Errors import WafError
49 from waflib.TaskGen import feature, before_method
50 from waflib.Tools.compiler_c import c_compiler
51 from waflib.Tools.compiler_cxx import cxx_compiler
54 APPNAME = 'geany'
55 VERSION = '1.25'
56 LINGUAS_FILE = os.path.join('po', 'LINGUAS')
57 MINIMUM_GTK_VERSION = '2.16.0'
58 MINIMUM_GTK3_VERSION = '3.0.0'
59 MINIMUM_GLIB_VERSION = '2.20.0'
61 top = '.'
62 out = '_build_'
65 mio_sources = set(['tagmanager/mio/mio.c'])
67 ctags_sources = set([
68     'tagmanager/ctags/abaqus.c',
69     'tagmanager/ctags/args.c',
70     'tagmanager/ctags/abc.c',
71     'tagmanager/ctags/actionscript.c',
72     'tagmanager/ctags/asciidoc.c',
73     'tagmanager/ctags/asm.c',
74     'tagmanager/ctags/basic.c',
75     'tagmanager/ctags/c.c',
76     'tagmanager/ctags/cobol.c',
77     'tagmanager/ctags/conf.c',
78     'tagmanager/ctags/css.c',
79     'tagmanager/ctags/ctags.c',
80     'tagmanager/ctags/diff.c',
81     'tagmanager/ctags/docbook.c',
82     'tagmanager/ctags/entry.c',
83     'tagmanager/ctags/fortran.c',
84     'tagmanager/ctags/get.c',
85     'tagmanager/ctags/haskell.c',
86     'tagmanager/ctags/haxe.c',
87     'tagmanager/ctags/html.c',
88     'tagmanager/ctags/js.c',
89     'tagmanager/ctags/keyword.c',
90     'tagmanager/ctags/latex.c',
91     'tagmanager/ctags/lregex.c',
92     'tagmanager/ctags/lua.c',
93     'tagmanager/ctags/make.c',
94     'tagmanager/ctags/markdown.c',
95     'tagmanager/ctags/matlab.c',
96     'tagmanager/ctags/nsis.c',
97     'tagmanager/ctags/nestlevel.c',
98     'tagmanager/ctags/objc.c',
99     'tagmanager/ctags/options.c',
100     'tagmanager/ctags/parse.c',
101     'tagmanager/ctags/pascal.c',
102     'tagmanager/ctags/r.c',
103     'tagmanager/ctags/perl.c',
104     'tagmanager/ctags/php.c',
105     'tagmanager/ctags/python.c',
106     'tagmanager/ctags/read.c',
107     'tagmanager/ctags/rest.c',
108     'tagmanager/ctags/ruby.c',
109     'tagmanager/ctags/rust.c',
110     'tagmanager/ctags/sh.c',
111     'tagmanager/ctags/sort.c',
112     'tagmanager/ctags/sql.c',
113     'tagmanager/ctags/strlist.c',
114     'tagmanager/ctags/txt2tags.c',
115     'tagmanager/ctags/tcl.c',
116     'tagmanager/ctags/vhdl.c',
117     'tagmanager/ctags/verilog.c',
118     'tagmanager/ctags/vstring.c'])
120 tagmanager_sources = set([
121     'tagmanager/src/tm_source_file.c',
122     'tagmanager/src/tm_tag.c',
123     'tagmanager/src/tm_workspace.c'])
125 scintilla_sources = set(['scintilla/gtk/scintilla-marshal.c'])
127 geany_sources = set([
128     'src/about.c', 'src/build.c', 'src/callbacks.c', 'src/dialogs.c', 'src/document.c',
129     'src/editor.c', 'src/encodings.c', 'src/filetypes.c', 'src/geanyentryaction.c',
130     'src/geanymenubuttonaction.c', 'src/geanyobject.c', 'src/geanywraplabel.c',
131     'src/highlighting.c', 'src/keybindings.c',
132     'src/keyfile.c', 'src/log.c', 'src/main.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c',
133     'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
134     'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
135     'src/symbols.c',
136     'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
137     'src/ui_utils.c', 'src/utils.c'])
139 geany_icons = {
140     'hicolor/16x16/apps':       ['16x16/classviewer-class.png',
141                                  '16x16/classviewer-macro.png',
142                                  '16x16/classviewer-member.png',
143                                  '16x16/classviewer-method.png',
144                                  '16x16/classviewer-namespace.png',
145                                  '16x16/classviewer-other.png',
146                                  '16x16/classviewer-struct.png',
147                                  '16x16/classviewer-var.png',
148                                  '16x16/geany.png'],
149     'hicolor/16x16/actions':    ['16x16/geany-build.png',
150                                  '16x16/geany-close-all.png',
151                                  '16x16/geany-save-all.png'],
152     'hicolor/24x24/actions':    ['24x24/geany-build.png',
153                                  '24x24/geany-close-all.png',
154                                  '24x24/geany-save-all.png'],
155     'hicolor/32x32/actions':    ['32x32/geany-build.png',
156                                  '32x32/geany-close-all.png',
157                                  '32x32/geany-save-all.png'],
158     'hicolor/48x48/actions':    ['48x48/geany-build.png',
159                                  '48x48/geany-close-all.png',
160                                  '48x48/geany-save-all.png'],
161     'hicolor/48x48/apps':       ['48x48/geany.png'],
162     'hicolor/scalable/apps':    ['scalable/geany.svg'],
163     'hicolor/scalable/actions': ['scalable/geany-build.svg',
164                                  'scalable/geany-close-all.svg',
165                                  'scalable/geany-save-all.svg'],
166     'Tango/16x16/actions':      ['tango/16x16/geany-save-all.png'],
167     'Tango/24x24/actions':      ['tango/24x24/geany-save-all.png'],
168     'Tango/32x32/actions':      ['tango/32x32/geany-save-all.png'],
169     'Tango/48x48/actions':      ['tango/48x48/geany-save-all.png'],
170     'Tango/scalable/actions':   ['tango/scalable/geany-save-all.svg']
172 geany_icons_indexes = {
173     'hicolor':  ['index.theme'],
174     'Tango':    ['tango/index.theme']
178 def configure(conf):
180     conf.check_waf_version(mini='1.6.1')
182     conf.load('compiler_c')
183     is_win32 = _target_is_win32(conf)
185     conf.check_cc(header_name='fcntl.h', mandatory=False)
186     conf.check_cc(header_name='fnmatch.h', mandatory=False)
187     conf.check_cc(header_name='glob.h', mandatory=False)
188     conf.check_cc(header_name='sys/time.h', mandatory=False)
189     conf.check_cc(header_name='sys/types.h', mandatory=False)
190     conf.check_cc(header_name='sys/stat.h', mandatory=False)
191     conf.define('HAVE_STDLIB_H', 1)  # are there systems without stdlib.h?
192     conf.define('STDC_HEADERS', 1)  # an optimistic guess ;-)
193     _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1)  # needed for CTags
195     conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
196     conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
197     conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
198     conf.check_cc(function_name='strstr', header_name='string.h')
200     conf.check_cc(function_name='pow', header_name='math.h', lib='m', uselib_store='M')
202     # check sunOS socket support
203     if Options.platform == 'sunos':
204         conf.check_cc(function_name='socket', lib='socket',
205                       header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
207     # check for cxx after the header and function checks have been done to ensure they are
208     # checked with cc not cxx
209     conf.load('compiler_cxx')
210     if is_win32:
211         conf.load('winres')
212     _load_intltool_if_available(conf)
214     # GTK / GIO version check
215     gtk_package_name = 'gtk+-3.0' if conf.options.use_gtk3 else 'gtk+-2.0'
216     minimum_gtk_version = MINIMUM_GTK3_VERSION if conf.options.use_gtk3 else MINIMUM_GTK_VERSION
217     conf.check_cfg(package=gtk_package_name, atleast_version=minimum_gtk_version, uselib_store='GTK',
218         mandatory=True, args='--cflags --libs')
219     conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
220         mandatory=True, args='--cflags --libs')
221     conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
222         mandatory=True, args='--cflags --libs')
223     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
224     gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
225     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
226     # remember GTK version for the build step
227     conf.env['gtk_package_name'] = gtk_package_name
228     conf.env['minimum_gtk_version'] = minimum_gtk_version
229     conf.env['use_gtk3'] = conf.options.use_gtk3
231     revision = _get_git_rev(conf)
233     # rst2html for the HTML manual
234     if not conf.options.no_html_doc and revision is not None:
235         try:
236             conf.env['RST2HTML'] = _find_rst2html(conf)
237         except WafError:
238             error_msg = '''Documentation enabled but rst2html not found.
239 You can explicitly disable building of the HTML manual with --disable-html-docs,
240 but you then may not have a local copy of the HTML manual.'''
241             raise WafError(error_msg)
243     # Windows specials
244     if is_win32:
245         if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
246             # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
247             new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
248             _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
249             _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
250         _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
251         _add_to_env_and_define(conf, 'LIBDIR', '%s/lib' % conf.env['PREFIX'], quote=True)
252         conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
253         # overwrite LOCALEDIR to install message catalogues properly
254         conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share', 'locale')
255         # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
256         conf.undefine('DATADIR')
257         conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
258         conf.env.append_value('LINKFLAGS_cprogram', [
259             '-mwindows',
260             '-static-libgcc',
261             '-static-libstdc++'])
262         conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'iberty'])
263         # explicitly define Windows version for older Mingw environments
264         conf.define('WINVER', '0x0501', quote=False)  # for SHGetFolderPathAndSubDirW
265         conf.define('_WIN32_IE', '0x0500', quote=False)  # for SHGFP_TYPE
266     else:
267         conf.env['cshlib_PATTERN'] = '%s.so'
268         # DATADIR and LOCALEDIR are defined by the intltool tool
269         # but they are not added to the environment, so we need to
270         _add_define_to_env(conf, 'DATADIR')
271         _add_define_to_env(conf, 'LOCALEDIR')
272         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
273         libdir = os.path.join(conf.env['PREFIX'], 'lib')
274         mandir = os.path.join(conf.env['DATADIR'], 'man')
275         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
276         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
277         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
279     conf.define('ENABLE_NLS', 1)
280     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
281     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
282     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
283     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
284     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
285     conf.define('PACKAGE', APPNAME, quote=True)
286     conf.define('VERSION', VERSION, quote=True)
287     conf.define('REVISION', revision or '-1', quote=True)
289     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
291     # no VTE on Windows
292     if is_win32:
293         conf.options.no_vte = True
295     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
296     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
297     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
299     conf.write_config_header('config.h', remove=False)
301     # some more compiler flags
302     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
303     if revision is not None:
304         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
305     # Scintilla flags
306     conf.env.append_value('CFLAGS', ['-DGTK'])
307     conf.env.append_value('CXXFLAGS',
308         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
310     # summary
311     Logs.pprint('BLUE', 'Summary:')
312     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
313     conf.msg('Using GTK version', gtk_version)
314     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
315     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
316     if revision is not None:
317         conf.msg('Compiling Git revision', revision)
320 def options(opt):
321     # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
322     # If anyone wants to add support for building with MSVC, this hack should be removed.
323     c_compiler['win32'] = ['gcc']
324     cxx_compiler['win32'] = ['g++']
326     opt.load('compiler_cc')
327     opt.load('compiler_cxx')
328     opt.load('intltool')
330     # Option
331     opt.add_option('--no-scm', action='store_true', default=False,
332         help='Disable SCM detection [default: No]', dest='no_scm')
333     # Features
334     opt.add_option('--disable-plugins', action='store_true', default=False,
335         help='compile without plugin support [default: No]', dest='no_plugins')
336     opt.add_option('--disable-socket', action='store_true', default=False,
337         help='compile without support to detect a running instance [[default: No]',
338         dest='no_socket')
339     opt.add_option('--disable-vte', action='store_true', default=False,
340         help='compile without support for an embedded virtual terminal [[default: No]',
341         dest='no_vte')
342     opt.add_option('--enable-gtk3', action='store_true', default=False,
343         help='compile with GTK3 support (experimental) [[default: No]',
344         dest='use_gtk3')
345     opt.add_option('--disable-html-docs', action='store_true', default=False,
346         help='do not generate HTML documentation using rst2html [[default: No]',
347         dest='no_html_doc')
348     # Paths
349     opt.add_option('--mandir', type='string', default='',
350         help='man documentation', dest='mandir')
351     opt.add_option('--docdir', type='string', default='',
352         help='documentation root', dest='docdir')
353     opt.add_option('--libdir', type='string', default='',
354         help='object code libraries', dest='libdir')
357 def build(bld):
358     is_win32 = _target_is_win32(bld)
360     if bld.cmd == 'clean':
361         _remove_linguas_file()
362     if bld.cmd in ('install', 'uninstall'):
363         bld.add_post_fun(_post_install)
365     def build_plugin(plugin_name, install=True, uselib_add=[]):
366         if install:
367             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
368         else:
369             instpath = None
371         bld(
372             features                = ['c', 'cshlib'],
373             source                  = 'plugins/%s.c' % plugin_name,
374             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
375             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
376             target                  = plugin_name,
377             uselib                  = ['GTK', 'GLIB', 'GMODULE'] + uselib_add,
378             install_path            = instpath)
380     # CTags
381     bld(
382         features        = ['c', 'cstlib'],
383         source          = ctags_sources,
384         name            = 'ctags',
385         target          = 'ctags',
386         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
387         defines         = 'G_LOG_DOMAIN="CTags"',
388         uselib          = ['GLIB'],
389         install_path    = None)  # do not install this library
391     # Tagmanager
392     bld(
393         features        = ['c', 'cstlib'],
394         source          = tagmanager_sources,
395         name            = 'tagmanager',
396         target          = 'tagmanager',
397         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
398         defines         = ['GEANY_PRIVATE', 'G_LOG_DOMAIN="Tagmanager"'],
399         uselib          = ['GTK', 'GLIB'],
400         install_path    = None)  # do not install this library
402     # MIO
403     bld(
404         features        = ['c', 'cstlib'],
405         source          = mio_sources,
406         name            = 'mio',
407         target          = 'mio',
408         includes        = ['.', 'tagmanager/mio/'],
409         defines         = 'G_LOG_DOMAIN="MIO"',
410         uselib          = ['GTK', 'GLIB'],
411         install_path    = None)  # do not install this library
413     # Scintilla
414     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
415     scintilla_sources.update(files)
416     bld(
417         features        = ['c', 'cxx', 'cxxstlib'],
418         name            = 'scintilla',
419         target          = 'scintilla',
420         source          = scintilla_sources,
421         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
422         uselib          = ['GTK', 'GLIB', 'GMODULE', 'M'],
423         install_path    = None)  # do not install this library
425     # Geany
426     if bld.env['HAVE_VTE'] == 1:
427         geany_sources.add('src/vte.c')
428     if is_win32:
429         geany_sources.add('src/win32.c')
430         geany_sources.add('geany_private.rc')
432     bld(
433         features        = ['c', 'cxx', 'cprogram'],
434         name            = 'geany',
435         target          = 'geany',
436         source          = geany_sources,
437         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
438         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
439         uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET', 'M'],
440         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'])
442     # geanyfunctions.h
443     bld(
444         source  = ['plugins/genapi.py', 'src/plugins.c'],
445         name    = 'geanyfunctions.h',
446         before  = ['c', 'cxx'],
447         cwd     = '%s/plugins' % bld.path.abspath(),
448         rule    = '%s genapi.py -q' % sys.executable)
450     # Plugins
451     if bld.env['HAVE_PLUGINS'] == 1:
452         build_plugin('classbuilder')
453         build_plugin('demoplugin', False)
454         build_plugin('export', uselib_add=['M'])
455         build_plugin('filebrowser')
456         build_plugin('htmlchars')
457         build_plugin('saveactions')
458         build_plugin('splitwindow')
460     # Translations
461     if bld.env['INTLTOOL']:
462         bld(
463             features        = ['linguas', 'intltool_po'],
464             podir           = 'po',
465             install_path    = '${LOCALEDIR}',
466             appname         = 'geany')
468     # HTML documentation (build if it is not part of the tree already, as it is required for install)
469     html_doc_filename = os.path.join(bld.out_dir, 'doc', 'geany.html')
470     if bld.env['RST2HTML']:
471         rst2html = bld.env['RST2HTML']
472         bld(
473             source  = ['doc/geany.txt'],
474             deps    = ['doc/geany.css'],
475             target  = 'doc/geany.html',
476             name    = 'geany.html',
477             cwd     = os.path.join(bld.path.abspath(), 'doc'),
478             rule    = '%s  -stg --stylesheet=geany.css geany.txt %s' % (rst2html, html_doc_filename))
480     # geany.pc
481     if is_win32:
482         # replace backward slashes by forward slashes as they could be interepreted as escape
483         # characters
484         geany_pc_prefix = bld.env['PREFIX'].replace('\\', '/')
485     else:
486         geany_pc_prefix = bld.env['PREFIX']
487     bld(
488         source          = 'geany.pc.in',
489         dct             = {'VERSION': VERSION,
490                            'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
491                                 (bld.env['gtk_package_name'],
492                                  bld.env['minimum_gtk_version'],
493                                  MINIMUM_GLIB_VERSION),
494                            'prefix': geany_pc_prefix,
495                            'exec_prefix': '${prefix}',
496                            'libdir': '${exec_prefix}/lib',
497                            'includedir': '${prefix}/include',
498                            'datarootdir': '${prefix}/share',
499                            'datadir': '${datarootdir}',
500                            'localedir': '${datarootdir}/locale'})
502     if not is_win32:
503         # geany.desktop
504         if bld.env['INTLTOOL']:
505             bld(
506                 features        = 'intltool_in',
507                 source          = 'geany.desktop.in',
508                 flags           = ['-d', '-q', '-u', '-c'],
509                 install_path    = '${DATADIR}/applications')
511         # geany.1
512         bld(
513             features        = 'subst',
514             source          = 'doc/geany.1.in',
515             target          = 'geany.1',
516             dct             = {'VERSION': VERSION,
517                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
518             install_path    = '${MANDIR}/man1')
520         # geany.spec
521         bld(
522             features        = 'subst',
523             source          = 'geany.spec.in',
524             target          = 'geany.spec',
525             install_path    = None,
526             dct             = {'VERSION': VERSION})
528         # Doxyfile
529         bld(
530             features        = 'subst',
531             source          = 'doc/Doxyfile.in',
532             target          = 'doc/Doxyfile',
533             install_path    = None,
534             dct             = {'VERSION': VERSION,
535                                'top_builddir': bld.out_dir,
536                                'top_srcdir': bld.top_dir,})
538     ###
539     # Install files
540     ###
541     # Headers
542     bld.install_files('${PREFIX}/include/geany', '''
543         src/app.h src/document.h src/editor.h src/encodings.h src/filetypes.h src/geany.h
544         src/highlighting.h src/keybindings.h src/msgwindow.h src/plugindata.h
545         src/prefs.h src/project.h src/search.h src/stash.h src/support.h
546         src/templates.h src/toolbar.h src/ui_utils.h src/utils.h src/build.h src/gtkcompat.h
547         plugins/geanyplugin.h plugins/geanyfunctions.h''')
548     bld.install_files('${PREFIX}/include/geany/scintilla', '''
549         scintilla/include/SciLexer.h scintilla/include/Scintilla.h
550         scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
551     bld.install_files('${PREFIX}/include/geany/tagmanager', '''
552         tagmanager/src/tm_source_file.h
553         tagmanager/src/tm_tag.h
554         tagmanager/src/tm_tagmanager.h
555         tagmanager/src/tm_workspace.h ''')
556     # Docs
557     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
558     ext = '.txt' if is_win32 else ''
559     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
560         basename = _uc_first(filename, bld)
561         destination_filename = '%s%s' % (basename, ext)
562         destination = os.path.join(base_dir, destination_filename)
563         bld.install_as(destination, filename)
565     # install HTML documentation only if it exists, i.e. it was built before
566     # local_html_doc_filename supports installing HTML doc from in-tree geany.html if it exists
567     local_html_doc_filename = os.path.join(bld.path.abspath(), 'doc', 'geany.html')
568     if os.path.exists(html_doc_filename) or os.path.exists(local_html_doc_filename):
569         html_dir = '' if is_win32 else 'html/'
570         html_name = 'Manual.html' if is_win32 else 'index.html'
571         start_dir = bld.path.find_dir('doc/images')
572         bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
573         bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
575     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
576     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
577     if is_win32:
578         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
579         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
580     # Data
581     data_dir = '' if is_win32 else 'geany'
582     start_dir = bld.path.find_dir('data')
583     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
584     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
585     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
586     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
587     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
588     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
589     if bld.env['use_gtk3']:
590         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
591     else:
592         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
594     start_dir = bld.path.find_dir('data/colorschemes')
595     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
596     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
597     start_dir = bld.path.find_dir('data/templates')
598     template_dest = '${DATADIR}/%s/templates' % data_dir
599     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
600     # Icons
601     for dest, srcs in geany_icons.items():
602         dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
603         bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
604     # install theme indexes on Windows
605     if is_win32:
606         for dest, srcs in geany_icons_indexes.items():
607             bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
610 def distclean(ctx):
611     Scripting.distclean(ctx)
612     _remove_linguas_file()
615 def _remove_linguas_file():
616     # remove LINGUAS file as well
617     try:
618         os.unlink(LINGUAS_FILE)
619     except OSError:
620         pass
623 @feature('linguas')
624 @before_method('apply_intltool_po')
625 def write_linguas_file(self):
626     if os.path.exists(LINGUAS_FILE):
627         return
628     linguas = ''
629     if 'LINGUAS' in self.env:
630         files = self.env['LINGUAS']
631         for po_filename in files.split(' '):
632             if os.path.exists('po/%s.po' % po_filename):
633                 linguas += '%s ' % po_filename
634     else:
635         files = os.listdir('%s/po' % self.path.abspath())
636         files.sort()
637         for filename in files:
638             if filename.endswith('.po'):
639                 linguas += '%s ' % filename[:-3]
640     file_h = open(LINGUAS_FILE, 'w')
641     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
642     file_h.close()
645 def _post_install(ctx):
646     is_win32 = _target_is_win32(ctx)
647     if is_win32:
648         return
649     for d in 'hicolor', 'Tango':
650         theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
651         icon_cache_updated = False
652         if not ctx.options.destdir:
653             ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
654             Logs.pprint('GREEN', 'GTK icon cache updated.')
655             icon_cache_updated = True
656         if not icon_cache_updated:
657             Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
658             Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
661 def updatepo(ctx):
662     """update the message catalogs for internationalization"""
663     potfile = '%s.pot' % APPNAME
664     os.chdir('%s/po' % top)
665     try:
666         try:
667             old_size = os.stat(potfile).st_size
668         except OSError:
669             old_size = 0
670         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
671         size_new = os.stat(potfile).st_size
672         if size_new != old_size:
673             Logs.pprint('CYAN', 'Updated POT file.')
674             Logs.pprint('CYAN', 'Updating translations')
675             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
676             if ret != 0:
677                 Logs.pprint('RED', 'Updating translations failed')
678         else:
679             Logs.pprint('CYAN', 'POT file is up to date.')
680     except OSError:
681         Logs.pprint('RED', 'Failed to generate pot file.')
684 def apidoc(ctx):
685     """generate API reference documentation"""
686     ctx = BuildContext()  # create our own context to have ctx.top_dir
687     basedir = ctx.top_dir
688     doxygen = _find_program(ctx, 'doxygen')
689     doxyfile = '%s/doc/Doxyfile' % ctx.out_dir
690     Logs.pprint('CYAN', 'Generating API documentation')
691     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
692     if ret != 0:
693         raise WafError('Generating API documentation failed')
696 def hackingdoc(ctx):
697     """generate HACKING documentation"""
698     ctx = BuildContext()  # create our own context to have ctx.top_dir
699     Logs.pprint('CYAN', 'Generating HACKING documentation')
700     cmd = _find_rst2html(ctx)
701     hacking_file = os.path.join(ctx.top_dir, 'HACKING')
702     hacking_html_file = os.path.join(ctx.top_dir, 'doc', 'hacking.html')
703     stylesheet = os.path.join(ctx.top_dir, 'doc', 'geany.css')
704     ret = ctx.exec_command('%s  -stg --stylesheet=%s %s %s' % (
705         cmd, stylesheet, hacking_file, hacking_html_file))
706     if ret != 0:
707         raise WafError('Generating HACKING documentation failed')
710 def _find_program(ctx, cmd, **kw):
711     def noop(*args):
712         pass
714     if ctx is None or not isinstance(ctx, ConfigurationContext):
715         ctx = ConfigurationContext()
716         ctx.to_log = noop
717         ctx.msg = noop
718     return ctx.find_program(cmd, **kw)
721 def _find_rst2html(ctx):
722     cmds = ['rst2html', 'rst2html2']
723     for command in cmds:
724         cmd = _find_program(ctx, command, mandatory=False, exts=',.py')
725         if cmd:
726             break
727     if not cmd:
728         raise WafError(
729             'rst2html.py could not be found. Please install the Python docutils package.')
730     return cmd
733 def _add_define_to_env(conf, key):
734     value = conf.get_define(key)
735     # strip quotes
736     value = value.replace('"', '')
737     conf.env[key] = value
740 def _add_to_env_and_define(conf, key, value, quote=False):
741     conf.define(key, value, quote)
742     conf.env[key] = value
745 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
746     value = default_value
747     if opt_value:
748         if isinstance(opt_value, bool):
749             opt_value = 1
750         value = opt_value
752     if value is not None:
753         _add_to_env_and_define(conf, define_name, value, quote)
754     else:
755         conf.undefine(define_name)
758 def _get_git_rev(conf):
759     if conf.options.no_scm:
760         return
762     if not os.path.isdir('.git'):
763         return
765     try:
766         cmd = 'git rev-parse --short --revs-only HEAD'
767         revision = conf.cmd_and_log(cmd).strip()
768     except WafError:
769         return None
770     else:
771         return revision
774 def _load_intltool_if_available(conf):
775     try:
776         conf.load('intltool')
777         if 'LINGUAS' in os.environ:
778             conf.env['LINGUAS'] = os.environ['LINGUAS']
779     except WafError:
780         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
781         if not _target_is_win32(conf):
782             raise
785 def _target_is_win32(ctx):
786     if 'is_win32' in ctx.env:
787         # cached
788         return ctx.env['is_win32']
789     is_win32 = None
790     if sys.platform == 'win32':
791         is_win32 = True
792     if is_win32 is None:
793         if ctx.env and 'CC' in ctx.env:
794             env_cc = ctx.env['CC']
795             if not isinstance(env_cc, str):
796                 env_cc = ''.join(env_cc)
797             is_win32 = (env_cc.find('mingw') != -1)
798     if is_win32 is None:
799         is_win32 = False
800     # cache for future checks
801     ctx.env['is_win32'] = is_win32
802     return is_win32
805 def _uc_first(string, ctx):
806     if _target_is_win32(ctx):
807         return string.title()
808     return string