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