win32: Fix crash with -v if stream redirection setup fails
[geany-mirror.git] / wscript
blob57ba4a811bfd587d941d0903a5769f25ce9e0224
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
51 APPNAME = 'geany'
52 VERSION = '1.23'
53 LINGUAS_FILE = 'po/LINGUAS'
54 MINIMUM_GTK_VERSION = '2.16.0'
55 MINIMUM_GLIB_VERSION = '2.20.0'
57 top = '.'
58 out = '_build_'
61 mio_sources = set(['tagmanager/mio/mio.c'])
63 ctags_sources = set([
64     'tagmanager/ctags/abaqus.c',
65     'tagmanager/ctags/args.c',
66     'tagmanager/ctags/abc.c',
67     'tagmanager/ctags/actionscript.c',
68     'tagmanager/ctags/asciidoc.c',
69     'tagmanager/ctags/asm.c',
70     'tagmanager/ctags/basic.c',
71     'tagmanager/ctags/c.c',
72     'tagmanager/ctags/cobol.c',
73     'tagmanager/ctags/conf.c',
74     'tagmanager/ctags/css.c',
75     'tagmanager/ctags/ctags.c',
76     'tagmanager/ctags/diff.c',
77     'tagmanager/ctags/docbook.c',
78     'tagmanager/ctags/entry.c',
79     'tagmanager/ctags/fortran.c',
80     'tagmanager/ctags/get.c',
81     'tagmanager/ctags/haskell.c',
82     'tagmanager/ctags/haxe.c',
83     'tagmanager/ctags/html.c',
84     'tagmanager/ctags/js.c',
85     'tagmanager/ctags/keyword.c',
86     'tagmanager/ctags/latex.c',
87     'tagmanager/ctags/lregex.c',
88     'tagmanager/ctags/lua.c',
89     'tagmanager/ctags/make.c',
90     'tagmanager/ctags/markdown.c',
91     'tagmanager/ctags/matlab.c',
92     'tagmanager/ctags/nsis.c',
93     'tagmanager/ctags/nestlevel.c',
94     'tagmanager/ctags/objc.c',
95     'tagmanager/ctags/options.c',
96     'tagmanager/ctags/parse.c',
97     'tagmanager/ctags/pascal.c',
98     'tagmanager/ctags/r.c',
99     'tagmanager/ctags/perl.c',
100     'tagmanager/ctags/php.c',
101     'tagmanager/ctags/python.c',
102     'tagmanager/ctags/read.c',
103     'tagmanager/ctags/rest.c',
104     'tagmanager/ctags/ruby.c',
105     'tagmanager/ctags/sh.c',
106     'tagmanager/ctags/sort.c',
107     'tagmanager/ctags/sql.c',
108     'tagmanager/ctags/strlist.c',
109     'tagmanager/ctags/txt2tags.c',
110     'tagmanager/ctags/tcl.c',
111     'tagmanager/ctags/vhdl.c',
112     'tagmanager/ctags/verilog.c',
113     'tagmanager/ctags/vstring.c'])
115 tagmanager_sources = set([
116     'tagmanager/src/tm_file_entry.c',
117     'tagmanager/src/tm_project.c',
118     'tagmanager/src/tm_source_file.c',
119     'tagmanager/src/tm_symbol.c',
120     'tagmanager/src/tm_tag.c',
121     'tagmanager/src/tm_tagmanager.c',
122     'tagmanager/src/tm_work_object.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='gethostname', header_name='unistd.h', mandatory=False)
198     conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
199     conf.check_cc(function_name='strstr', header_name='string.h')
201     # check sunOS socket support
202     if Options.platform == 'sunos':
203         conf.check_cc(function_name='socket', lib='socket',
204                       header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
206     # check for cxx after the header and function checks have been done to ensure they are
207     # checked with cc not cxx
208     conf.load('compiler_cxx')
209     if is_win32:
210         conf.load('winres')
211     _load_intltool_if_available(conf)
213     # GTK / GIO version check
214     conf.check_cfg(package='gtk+-2.0', atleast_version=MINIMUM_GTK_VERSION, uselib_store='GTK',
215         mandatory=True, args='--cflags --libs')
216     conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
217         mandatory=True, args='--cflags --libs')
218     conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
219         mandatory=True, args='--cflags --libs')
220     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
221     gtk_version = conf.check_cfg(modversion='gtk+-2.0', uselib_store='GTK') or 'Unknown'
222     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
224     # Windows specials
225     if is_win32:
226         if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
227             # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
228             new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
229             _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
230             _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
231         _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
232         _add_to_env_and_define(conf, 'LIBDIR', conf.env['PREFIX'], quote=True)
233         conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
234         # overwrite LOCALEDIR to install message catalogues properly
235         conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share/locale')
236         # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
237         conf.undefine('DATADIR')
238         conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
239         conf.env.append_value('LINKFLAGS_cprogram', ['-mwindows'])
240         conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'iberty'])
241     else:
242         conf.env['cshlib_PATTERN'] = '%s.so'
243         # DATADIR and LOCALEDIR are defined by the intltool tool
244         # but they are not added to the environment, so we need to
245         _add_define_to_env(conf, 'DATADIR')
246         _add_define_to_env(conf, 'LOCALEDIR')
247         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
248         libdir = os.path.join(conf.env['PREFIX'], 'lib')
249         mandir = os.path.join(conf.env['DATADIR'], 'man')
250         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
251         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
252         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
254     revision = _get_git_rev(conf)
256     conf.define('ENABLE_NLS', 1)
257     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
258     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
259     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
260     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
261     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
262     conf.define('PACKAGE', APPNAME, quote=True)
263     conf.define('VERSION', VERSION, quote=True)
264     conf.define('REVISION', revision or '-1', quote=True)
266     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
268     # no VTE on Windows
269     if is_win32:
270         conf.options.no_vte = True
272     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
273     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
274     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
276     conf.write_config_header('config.h', remove=False)
278     # some more compiler flags
279     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
280     if revision is not None:
281         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
282     # Scintilla flags
283     conf.env.append_value('CFLAGS', ['-DGTK'])
284     conf.env.append_value('CXXFLAGS',
285         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
287     # summary
288     Logs.pprint('BLUE', 'Summary:')
289     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
290     conf.msg('Using GTK version', gtk_version)
291     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
292     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
293     if revision is not None:
294         conf.msg('Compiling Git revision', revision)
297 def options(opt):
298     opt.tool_options('compiler_cc')
299     opt.tool_options('compiler_cxx')
300     opt.tool_options('intltool')
302     # Features
303     opt.add_option('--disable-plugins', action='store_true', default=False,
304         help='compile without plugin support [default: No]', dest='no_plugins')
305     opt.add_option('--disable-socket', action='store_true', default=False,
306         help='compile without support to detect a running instance [[default: No]',
307         dest='no_socket')
308     opt.add_option('--disable-vte', action='store_true', default=False,
309         help='compile without support for an embedded virtual terminal [[default: No]',
310         dest='no_vte')
311     # Paths
312     opt.add_option('--mandir', type='string', default='',
313         help='man documentation', dest='mandir')
314     opt.add_option('--docdir', type='string', default='',
315         help='documentation root', dest='docdir')
316     opt.add_option('--libdir', type='string', default='',
317         help='object code libraries', dest='libdir')
318     # Actions
319     opt.add_option('--hackingdoc', action='store_true', default=False,
320         help='generate HTML documentation from HACKING file', dest='hackingdoc')
323 def build(bld):
324     is_win32 = _target_is_win32(bld)
326     if bld.cmd == 'clean':
327         _remove_linguas_file()
328     if bld.cmd in ('install', 'uninstall'):
329         bld.add_post_fun(_post_install)
331     def build_plugin(plugin_name, install=True):
332         if install:
333             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
334         else:
335             instpath = None
337         bld.new_task_gen(
338             features                = ['c', 'cshlib'],
339             source                  = 'plugins/%s.c' % plugin_name,
340             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
341             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
342             target                  = plugin_name,
343             uselib                  = ['GTK', 'GLIB', 'GMODULE'],
344             install_path            = instpath)
346     # CTags
347     bld.new_task_gen(
348         features        = ['c', 'cstlib'],
349         source          = ctags_sources,
350         name            = 'ctags',
351         target          = 'ctags',
352         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
353         defines         = 'G_LOG_DOMAIN="CTags"',
354         uselib          = ['GLIB'],
355         install_path    = None)  # do not install this library
357     # Tagmanager
358     bld.new_task_gen(
359         features        = ['c', 'cstlib'],
360         source          = tagmanager_sources,
361         name            = 'tagmanager',
362         target          = 'tagmanager',
363         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
364         defines         = 'G_LOG_DOMAIN="Tagmanager"',
365         uselib          = ['GTK', 'GLIB'],
366         install_path    = None)  # do not install this library
368     # MIO
369     bld.new_task_gen(
370         features        = ['c', 'cstlib'],
371         source          = mio_sources,
372         name            = 'mio',
373         target          = 'mio',
374         includes        = ['.', 'tagmanager/mio/'],
375         defines         = 'G_LOG_DOMAIN="MIO"',
376         uselib          = ['GTK', 'GLIB'],
377         install_path    = None)  # do not install this library
379     # Scintilla
380     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
381     scintilla_sources.update(files)
382     bld.new_task_gen(
383         features        = ['c', 'cxx', 'cxxstlib'],
384         name            = 'scintilla',
385         target          = 'scintilla',
386         source          = scintilla_sources,
387         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
388         uselib          = ['GTK', 'GLIB', 'GMODULE'],
389         install_path    = None)  # do not install this library
391     # Geany
392     if bld.env['HAVE_VTE'] == 1:
393         geany_sources.add('src/vte.c')
394     if is_win32:
395         geany_sources.add('src/win32.c')
396         geany_sources.add('geany_private.rc')
398     bld.new_task_gen(
399         features        = ['c', 'cxx', 'cprogram'],
400         name            = 'geany',
401         target          = 'geany',
402         source          = geany_sources,
403         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
404         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
405         uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET'],
406         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'])
408     # geanyfunctions.h
409     bld.new_task_gen(
410         source  = ['plugins/genapi.py', 'src/plugins.c'],
411         name    = 'geanyfunctions.h',
412         before  = ['c', 'cxx'],
413         cwd     = '%s/plugins' % bld.path.abspath(),
414         rule    = '%s genapi.py -q' % sys.executable)
416     # Plugins
417     if bld.env['HAVE_PLUGINS'] == 1:
418         build_plugin('classbuilder')
419         build_plugin('demoplugin', False)
420         build_plugin('export')
421         build_plugin('filebrowser')
422         build_plugin('htmlchars')
423         build_plugin('saveactions')
424         build_plugin('splitwindow')
426     # Translations
427     if bld.env['INTLTOOL']:
428         bld.new_task_gen(
429             features        = ['linguas', 'intltool_po'],
430             podir           = 'po',
431             install_path    = '${LOCALEDIR}',
432             appname         = 'geany')
434     # geany.pc
435     bld.new_task_gen(
436         source          = 'geany.pc.in',
437         dct             = {'VERSION': VERSION,
438                            'DEPENDENCIES': 'gtk+-2.0 >= %s glib-2.0 >= %s' % \
439                                 (MINIMUM_GTK_VERSION, MINIMUM_GLIB_VERSION),
440                            'prefix': bld.env['PREFIX'],
441                            'exec_prefix': '${prefix}',
442                            'libdir': '${exec_prefix}/lib',
443                            'includedir': '${prefix}/include',
444                            'datarootdir': '${prefix}/share',
445                            'datadir': '${datarootdir}',
446                            'localedir': '${datarootdir}/locale'})
448     if not is_win32:
449         # geany.desktop
450         if bld.env['INTLTOOL']:
451             bld.new_task_gen(
452                 features        = 'intltool_in',
453                 source          = 'geany.desktop.in',
454                 flags           = ['-d', '-q', '-u', '-c'],
455                 install_path    = '${DATADIR}/applications')
457         # geany.1
458         bld.new_task_gen(
459             features        = 'subst',
460             source          = 'doc/geany.1.in',
461             target          = 'geany.1',
462             dct             = {'VERSION': VERSION,
463                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
464             install_path    = '${MANDIR}/man1')
466         # geany.spec
467         bld.new_task_gen(
468             features        = 'subst',
469             source          = 'geany.spec.in',
470             target          = 'geany.spec',
471             install_path    = None,
472             dct             = {'VERSION': VERSION})
474         # Doxyfile
475         bld.new_task_gen(
476             features        = 'subst',
477             source          = 'doc/Doxyfile.in',
478             target          = 'doc/Doxyfile',
479             install_path    = None,
480             dct             = {'VERSION': VERSION})
482     ###
483     # Install files
484     ###
485     if not is_win32:
486         # Headers
487         bld.install_files('${PREFIX}/include/geany', '''
488             src/document.h src/editor.h src/encodings.h src/filetypes.h src/geany.h
489             src/highlighting.h src/keybindings.h src/msgwindow.h src/plugindata.h
490             src/prefs.h src/project.h src/search.h src/stash.h src/support.h
491             src/templates.h src/toolbar.h src/ui_utils.h src/utils.h src/build.h
492             plugins/geanyplugin.h plugins/geanyfunctions.h''')
493         bld.install_files('${PREFIX}/include/geany/scintilla', '''
494             scintilla/include/SciLexer.h scintilla/include/Scintilla.h
495             scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
496         bld.install_files('${PREFIX}/include/geany/tagmanager', '''
497             tagmanager/src/tm_file_entry.h tagmanager/src/tm_project.h
498             tagmanager/src/tm_source_file.h
499             tagmanager/src/tm_symbol.h tagmanager/src/tm_tag.h
500             tagmanager/src/tm_tagmanager.h tagmanager/src/tm_work_object.h
501             tagmanager/src/tm_workspace.h ''')
502     # Docs
503     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
504     ext = '.txt' if is_win32 else ''
505     html_dir = '' if is_win32 else 'html/'
506     html_name = 'Manual.html' if is_win32 else 'index.html'
507     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
508         basename = _uc_first(filename, bld)
509         destination_filename = '%s%s' % (basename, ext)
510         destination = os.path.join(base_dir, destination_filename)
511         bld.install_as(destination, filename)
513     start_dir = bld.path.find_dir('doc/images')
514     bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
515     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
516     bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
517     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
518     if is_win32:
519         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
520         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
521     # Data
522     data_dir = '' if is_win32 else 'geany'
523     start_dir = bld.path.find_dir('data')
524     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
525     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
526     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
527     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
528     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
529     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
530     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
531     start_dir = bld.path.find_dir('data/colorschemes')
532     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
533     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
534     start_dir = bld.path.find_dir('data/templates')
535     template_dest = '${DATADIR}/%s/templates' % data_dir
536     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
537     # Icons
538     for dest, srcs in geany_icons.items():
539         dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
540         bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
541     # install theme indexes on Windows
542     if is_win32:
543         for dest, srcs in geany_icons_indexes.items():
544             bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
547 def distclean(ctx):
548     Scripting.distclean(ctx)
549     _remove_linguas_file()
552 def _remove_linguas_file():
553     # remove LINGUAS file as well
554     try:
555         os.unlink(LINGUAS_FILE)
556     except OSError:
557         pass
560 @feature('linguas')
561 def write_linguas_file(self):
562     if os.path.exists(LINGUAS_FILE):
563         return
564     linguas = ''
565     if 'LINGUAS' in self.env:
566         files = self.env['LINGUAS']
567         for po_filename in files.split(' '):
568             if os.path.exists('po/%s.po' % po_filename):
569                 linguas += '%s ' % po_filename
570     else:
571         files = os.listdir('%s/po' % self.path.abspath())
572         files.sort()
573         for filename in files:
574             if filename.endswith('.po'):
575                 linguas += '%s ' % filename[:-3]
576     file_h = open(LINGUAS_FILE, 'w')
577     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
578     file_h.close()
581 def _post_install(ctx):
582     is_win32 = _target_is_win32(ctx)
583     if is_win32:
584         return
585     for d in 'hicolor', 'Tango':
586         theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
587         icon_cache_updated = False
588         if not ctx.options.destdir:
589             ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
590             Logs.pprint('GREEN', 'GTK icon cache updated.')
591             icon_cache_updated = True
592         if not icon_cache_updated:
593             Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
594             Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
597 def updatepo(ctx):
598     """update the message catalogs for internationalization"""
599     potfile = '%s.pot' % APPNAME
600     os.chdir('%s/po' % top)
601     try:
602         try:
603             old_size = os.stat(potfile).st_size
604         except OSError:
605             old_size = 0
606         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
607         size_new = os.stat(potfile).st_size
608         if size_new != old_size:
609             Logs.pprint('CYAN', 'Updated POT file.')
610             Logs.pprint('CYAN', 'Updating translations')
611             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
612             if ret != 0:
613                 Logs.pprint('RED', 'Updating translations failed')
614         else:
615             Logs.pprint('CYAN', 'POT file is up to date.')
616     except OSError:
617         Logs.pprint('RED', 'Failed to generate pot file.')
620 def apidoc(ctx):
621     """generate API reference documentation"""
622     basedir = ctx.path.abspath()
623     doxygen = _find_program(ctx, 'doxygen')
624     doxyfile = '%s/%s/doc/Doxyfile' % (basedir, out)
625     os.chdir('doc')
626     Logs.pprint('CYAN', 'Generating API documentation')
627     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
628     if ret != 0:
629         raise WafError('Generating API documentation failed')
630     # update hacking.html
631     cmd = _find_rst2html(ctx)
632     ctx.exec_command('%s  -stg --stylesheet=geany.css %s %s' % (cmd, '../HACKING', 'hacking.html'))
633     os.chdir('..')
636 def htmldoc(ctx):
637     """generate HTML documentation"""
638     # first try rst2html.py as it is the upstream default, fall back to rst2html
639     cmd = _find_rst2html(ctx)
640     os.chdir('doc')
641     Logs.pprint('CYAN', 'Generating HTML documentation')
642     ctx.exec_command('%s  -stg --stylesheet=geany.css %s %s' % (cmd, 'geany.txt', 'geany.html'))
643     os.chdir('..')
646 def _find_program(ctx, cmd, **kw):
647     def noop(*args):
648         pass
650     ctx = ConfigurationContext()
651     ctx.to_log = noop
652     ctx.msg = noop
653     return ctx.find_program(cmd, **kw)
656 def _find_rst2html(ctx):
657     cmds = ['rst2html.py', 'rst2html']
658     for command in cmds:
659         cmd = _find_program(ctx, command, mandatory=False)
660         if cmd:
661             break
662     if not cmd:
663         raise WafError(
664             'rst2html.py could not be found. Please install the Python docutils package.')
665     return cmd
668 def _add_define_to_env(conf, key):
669     value = conf.get_define(key)
670     # strip quotes
671     value = value.replace('"', '')
672     conf.env[key] = value
675 def _add_to_env_and_define(conf, key, value, quote=False):
676     conf.define(key, value, quote)
677     conf.env[key] = value
680 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
681     value = default_value
682     if opt_value:
683         if isinstance(opt_value, bool):
684             opt_value = 1
685         value = opt_value
687     if value is not None:
688         _add_to_env_and_define(conf, define_name, value, quote)
689     else:
690         conf.undefine(define_name)
693 def _get_git_rev(conf):
694     if not os.path.isdir('.git'):
695         return
697     try:
698         cmd = 'git rev-parse --short --revs-only HEAD'
699         revision = conf.cmd_and_log(cmd).strip()
700     except WafError:
701         return None
702     else:
703         return revision
706 def _load_intltool_if_available(conf):
707     try:
708         conf.check_tool('intltool')
709         if 'LINGUAS' in os.environ:
710             conf.env['LINGUAS'] = os.environ['LINGUAS']
711     except WafError:
712         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
713         if not _target_is_win32(conf):
714             raise
717 def _target_is_win32(ctx):
718     if 'is_win32' in ctx.env:
719         # cached
720         return ctx.env['is_win32']
721     is_win32 = None
722     if sys.platform == 'win32':
723         is_win32 = True
724     if is_win32 is None:
725         if ctx.env and 'CC' in ctx.env:
726             env_cc = ctx.env['CC']
727             if not isinstance(env_cc, str):
728                 env_cc = ''.join(env_cc)
729             is_win32 = (env_cc.find('mingw') != -1)
730     if is_win32 is None:
731         is_win32 = False
732     # cache for future checks
733     ctx.env['is_win32'] = is_win32
734     return is_win32
737 def _uc_first(string, ctx):
738     if _target_is_win32(ctx):
739         return string.title()
740     return string