Add status bar warning if Windows spawn timed out
[geany-mirror.git] / wscript
blobcdafce2f6885aa884fa2c2e29254638518396dc0
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/args.c',
65     'tagmanager/ctags/abc.c',
66     'tagmanager/ctags/actionscript.c',
67     'tagmanager/ctags/asm.c',
68     'tagmanager/ctags/basic.c',
69     'tagmanager/ctags/c.c',
70     'tagmanager/ctags/cobol.c',
71     'tagmanager/ctags/conf.c',
72     'tagmanager/ctags/css.c',
73     'tagmanager/ctags/ctags.c',
74     'tagmanager/ctags/diff.c',
75     'tagmanager/ctags/docbook.c',
76     'tagmanager/ctags/entry.c',
77     'tagmanager/ctags/fortran.c',
78     'tagmanager/ctags/get.c',
79     'tagmanager/ctags/haskell.c',
80     'tagmanager/ctags/haxe.c',
81     'tagmanager/ctags/html.c',
82     'tagmanager/ctags/js.c',
83     'tagmanager/ctags/keyword.c',
84     'tagmanager/ctags/latex.c',
85     'tagmanager/ctags/lregex.c',
86     'tagmanager/ctags/lua.c',
87     'tagmanager/ctags/make.c',
88     'tagmanager/ctags/markdown.c',
89     'tagmanager/ctags/matlab.c',
90     'tagmanager/ctags/nsis.c',
91     'tagmanager/ctags/nestlevel.c',
92     'tagmanager/ctags/objc.c',
93     'tagmanager/ctags/options.c',
94     'tagmanager/ctags/parse.c',
95     'tagmanager/ctags/pascal.c',
96     'tagmanager/ctags/r.c',
97     'tagmanager/ctags/perl.c',
98     'tagmanager/ctags/php.c',
99     'tagmanager/ctags/python.c',
100     'tagmanager/ctags/read.c',
101     'tagmanager/ctags/rest.c',
102     'tagmanager/ctags/ruby.c',
103     'tagmanager/ctags/sh.c',
104     'tagmanager/ctags/sort.c',
105     'tagmanager/ctags/sql.c',
106     'tagmanager/ctags/strlist.c',
107     'tagmanager/ctags/txt2tags.c',
108     'tagmanager/ctags/tcl.c',
109     'tagmanager/ctags/vhdl.c',
110     'tagmanager/ctags/verilog.c',
111     'tagmanager/ctags/vstring.c'])
113 tagmanager_sources = set([
114     'tagmanager/src/tm_file_entry.c',
115     'tagmanager/src/tm_project.c',
116     'tagmanager/src/tm_source_file.c',
117     'tagmanager/src/tm_symbol.c',
118     'tagmanager/src/tm_tag.c',
119     'tagmanager/src/tm_tagmanager.c',
120     'tagmanager/src/tm_work_object.c',
121     'tagmanager/src/tm_workspace.c'])
123 scintilla_sources = set(['scintilla/gtk/scintilla-marshal.c'])
125 geany_sources = set([
126     'src/about.c', 'src/build.c', 'src/callbacks.c', 'src/dialogs.c', 'src/document.c',
127     'src/editor.c', 'src/encodings.c', 'src/filetypes.c', 'src/geanyentryaction.c',
128     'src/geanymenubuttonaction.c', 'src/geanyobject.c', 'src/geanywraplabel.c',
129     'src/highlighting.c', 'src/keybindings.c',
130     'src/keyfile.c', 'src/log.c', 'src/main.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c',
131     'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
132     'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
133     'src/symbols.c',
134     'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
135     'src/ui_utils.c', 'src/utils.c'])
138 def configure(conf):
140     conf.check_waf_version(mini='1.6.1')
142     conf.load('compiler_c')
143     is_win32 = _target_is_win32(conf)
145     conf.check_cc(header_name='fcntl.h', mandatory=False)
146     conf.check_cc(header_name='fnmatch.h', mandatory=False)
147     conf.check_cc(header_name='glob.h', mandatory=False)
148     conf.check_cc(header_name='sys/time.h', mandatory=False)
149     conf.check_cc(header_name='sys/types.h', mandatory=False)
150     conf.check_cc(header_name='sys/stat.h', mandatory=False)
151     conf.define('HAVE_STDLIB_H', 1)  # are there systems without stdlib.h?
152     conf.define('STDC_HEADERS', 1)  # an optimistic guess ;-)
153     _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1)  # needed for CTags
155     conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
156     conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
157     conf.check_cc(function_name='gethostname', header_name='unistd.h', mandatory=False)
158     conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
159     conf.check_cc(function_name='strstr', header_name='string.h')
161     # check sunOS socket support
162     if Options.platform == 'sunos':
163         conf.check_cc(function_name='socket', lib='socket',
164                       header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
166     # check for cxx after the header and function checks have been done to ensure they are
167     # checked with cc not cxx
168     conf.load('compiler_cxx')
169     if is_win32:
170         conf.load('winres')
171     _load_intltool_if_available(conf)
173     # GTK / GIO version check
174     conf.check_cfg(package='gtk+-2.0', atleast_version=MINIMUM_GTK_VERSION, uselib_store='GTK',
175         mandatory=True, args='--cflags --libs')
176     conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
177         mandatory=True, args='--cflags --libs')
178     conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
179         mandatory=True, args='--cflags --libs')
180     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
181     gtk_version = conf.check_cfg(modversion='gtk+-2.0', uselib_store='GTK') or 'Unknown'
182     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
184     # Windows specials
185     if is_win32:
186         if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
187             # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
188             new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
189             _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
190             _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
191         _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
192         _add_to_env_and_define(conf, 'LIBDIR', conf.env['PREFIX'], quote=True)
193         conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
194         # overwrite LOCALEDIR to install message catalogues properly
195         conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share/locale')
196         # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
197         conf.undefine('DATADIR')
198         conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
199         conf.env.append_value('LINKFLAGS_cprogram', ['-mwindows'])
200         conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'iberty'])
201     else:
202         conf.env['cshlib_PATTERN'] = '%s.so'
203         # DATADIR and LOCALEDIR are defined by the intltool tool
204         # but they are not added to the environment, so we need to
205         _add_define_to_env(conf, 'DATADIR')
206         _add_define_to_env(conf, 'LOCALEDIR')
207         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
208         libdir = os.path.join(conf.env['PREFIX'], 'lib')
209         mandir = os.path.join(conf.env['DATADIR'], 'man')
210         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
211         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
212         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
214     revision = _get_git_rev(conf)
216     conf.define('ENABLE_NLS', 1)
217     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
218     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
219     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
220     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
221     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
222     conf.define('PACKAGE', APPNAME, quote=True)
223     conf.define('VERSION', VERSION, quote=True)
224     conf.define('REVISION', revision or '-1', quote=True)
226     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
228     # no VTE on Windows
229     if is_win32:
230         conf.options.no_vte = True
232     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
233     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
234     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
236     conf.write_config_header('config.h', remove=False)
238     # some more compiler flags
239     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
240     if revision is not None:
241         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
242     # Scintilla flags
243     conf.env.append_value('CFLAGS', ['-DGTK'])
244     conf.env.append_value('CXXFLAGS',
245         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
247     # summary
248     Logs.pprint('BLUE', 'Summary:')
249     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
250     conf.msg('Using GTK version', gtk_version)
251     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
252     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
253     if revision is not None:
254         conf.msg('Compiling Git revision', revision)
257 def options(opt):
258     opt.tool_options('compiler_cc')
259     opt.tool_options('compiler_cxx')
260     opt.tool_options('intltool')
262     # Features
263     opt.add_option('--disable-plugins', action='store_true', default=False,
264         help='compile without plugin support [default: No]', dest='no_plugins')
265     opt.add_option('--disable-socket', action='store_true', default=False,
266         help='compile without support to detect a running instance [[default: No]',
267         dest='no_socket')
268     opt.add_option('--disable-vte', action='store_true', default=False,
269         help='compile without support for an embedded virtual terminal [[default: No]',
270         dest='no_vte')
271     # Paths
272     opt.add_option('--mandir', type='string', default='',
273         help='man documentation', dest='mandir')
274     opt.add_option('--docdir', type='string', default='',
275         help='documentation root', dest='docdir')
276     opt.add_option('--libdir', type='string', default='',
277         help='object code libraries', dest='libdir')
278     # Actions
279     opt.add_option('--hackingdoc', action='store_true', default=False,
280         help='generate HTML documentation from HACKING file', dest='hackingdoc')
283 def build(bld):
284     is_win32 = _target_is_win32(bld)
286     if bld.cmd == 'clean':
287         _remove_linguas_file()
288     if bld.cmd in ('install', 'uninstall'):
289         bld.add_post_fun(_post_install)
291     def build_plugin(plugin_name, install=True):
292         if install:
293             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
294         else:
295             instpath = None
297         bld.new_task_gen(
298             features                = ['c', 'cshlib'],
299             source                  = 'plugins/%s.c' % plugin_name,
300             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
301             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
302             target                  = plugin_name,
303             uselib                  = ['GTK', 'GLIB', 'GMODULE'],
304             install_path            = instpath)
306     # CTags
307     bld.new_task_gen(
308         features        = ['c', 'cstlib'],
309         source          = ctags_sources,
310         name            = 'ctags',
311         target          = 'ctags',
312         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
313         defines         = 'G_LOG_DOMAIN="CTags"',
314         uselib          = ['GLIB'],
315         install_path    = None)  # do not install this library
317     # Tagmanager
318     bld.new_task_gen(
319         features        = ['c', 'cstlib'],
320         source          = tagmanager_sources,
321         name            = 'tagmanager',
322         target          = 'tagmanager',
323         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
324         defines         = 'G_LOG_DOMAIN="Tagmanager"',
325         uselib          = ['GTK', 'GLIB'],
326         install_path    = None)  # do not install this library
328     # MIO
329     bld.new_task_gen(
330         features        = ['c', 'cstlib'],
331         source          = mio_sources,
332         name            = 'mio',
333         target          = 'mio',
334         includes        = ['.', 'tagmanager/mio/'],
335         defines         = 'G_LOG_DOMAIN="MIO"',
336         uselib          = ['GTK', 'GLIB'],
337         install_path    = None)  # do not install this library
339     # Scintilla
340     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
341     scintilla_sources.update(files)
342     bld.new_task_gen(
343         features        = ['c', 'cxx', 'cxxstlib'],
344         name            = 'scintilla',
345         target          = 'scintilla',
346         source          = scintilla_sources,
347         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
348         uselib          = ['GTK', 'GLIB', 'GMODULE'],
349         install_path    = None)  # do not install this library
351     # Geany
352     if bld.env['HAVE_VTE'] == 1:
353         geany_sources.add('src/vte.c')
354     if is_win32:
355         geany_sources.add('src/win32.c')
356         geany_sources.add('geany_private.rc')
358     bld.new_task_gen(
359         features        = ['c', 'cxx', 'cprogram'],
360         name            = 'geany',
361         target          = 'geany',
362         source          = geany_sources,
363         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
364         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
365         linkflags       = [] if is_win32 else ['-Wl,--export-dynamic'],
366         uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET'],
367         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'])
369     # geanyfunctions.h
370     bld.new_task_gen(
371         source  = ['plugins/genapi.py', 'src/plugins.c'],
372         name    = 'geanyfunctions.h',
373         before  = ['c', 'cxx'],
374         cwd     = '%s/plugins' % bld.path.abspath(),
375         rule    = '%s genapi.py -q' % sys.executable)
377     # Plugins
378     if bld.env['HAVE_PLUGINS'] == 1:
379         build_plugin('classbuilder')
380         build_plugin('demoplugin', False)
381         build_plugin('export')
382         build_plugin('filebrowser')
383         build_plugin('htmlchars')
384         build_plugin('saveactions')
385         build_plugin('splitwindow')
387     # Translations
388     if bld.env['INTLTOOL']:
389         bld.new_task_gen(
390             features        = ['linguas', 'intltool_po'],
391             podir           = 'po',
392             install_path    = '${LOCALEDIR}',
393             appname         = 'geany')
395     # geany.pc
396     bld.new_task_gen(
397         source          = 'geany.pc.in',
398         dct             = {'VERSION': VERSION,
399                            'DEPENDENCIES': 'gtk+-2.0 >= %s glib-2.0 >= %s' % \
400                                 (MINIMUM_GTK_VERSION, MINIMUM_GLIB_VERSION),
401                            'prefix': bld.env['PREFIX'],
402                            'exec_prefix': '${prefix}',
403                            'libdir': '${exec_prefix}/lib',
404                            'includedir': '${prefix}/include',
405                            'datarootdir': '${prefix}/share',
406                            'datadir': '${datarootdir}',
407                            'localedir': '${datarootdir}/locale'})
409     if not is_win32:
410         # geany.desktop
411         if bld.env['INTLTOOL']:
412             bld.new_task_gen(
413                 features        = 'intltool_in',
414                 source          = 'geany.desktop.in',
415                 flags           = ['-d', '-q', '-u', '-c'],
416                 install_path    = '${DATADIR}/applications')
418         # geany.1
419         bld.new_task_gen(
420             features        = 'subst',
421             source          = 'doc/geany.1.in',
422             target          = 'geany.1',
423             dct             = {'VERSION': VERSION,
424                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
425             install_path    = '${MANDIR}/man1')
427         # geany.spec
428         bld.new_task_gen(
429             features        = 'subst',
430             source          = 'geany.spec.in',
431             target          = 'geany.spec',
432             install_path    = None,
433             dct             = {'VERSION': VERSION})
435         # Doxyfile
436         bld.new_task_gen(
437             features        = 'subst',
438             source          = 'doc/Doxyfile.in',
439             target          = 'doc/Doxyfile',
440             install_path    = None,
441             dct             = {'VERSION': VERSION})
443     ###
444     # Install files
445     ###
446     if not is_win32:
447         # Headers
448         bld.install_files('${PREFIX}/include/geany', '''
449             src/document.h src/editor.h src/encodings.h src/filetypes.h src/geany.h
450             src/highlighting.h src/keybindings.h src/msgwindow.h src/plugindata.h
451             src/prefs.h src/project.h src/search.h src/stash.h src/support.h
452             src/templates.h src/toolbar.h src/ui_utils.h src/utils.h src/build.h
453             plugins/geanyplugin.h plugins/geanyfunctions.h''')
454         bld.install_files('${PREFIX}/include/geany/scintilla', '''
455             scintilla/include/SciLexer.h scintilla/include/Scintilla.h
456             scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
457         bld.install_files('${PREFIX}/include/geany/tagmanager', '''
458             tagmanager/src/tm_file_entry.h tagmanager/src/tm_project.h
459             tagmanager/src/tm_source_file.h
460             tagmanager/src/tm_symbol.h tagmanager/src/tm_tag.h
461             tagmanager/src/tm_tagmanager.h tagmanager/src/tm_work_object.h
462             tagmanager/src/tm_workspace.h ''')
463     # Docs
464     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
465     ext = '.txt' if is_win32 else ''
466     html_dir = '' if is_win32 else 'html/'
467     html_name = 'Manual.html' if is_win32 else 'index.html'
468     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
469         basename = _uc_first(filename, bld)
470         destination_filename = '%s%s' % (basename, ext)
471         destination = os.path.join(base_dir, destination_filename)
472         bld.install_as(destination, filename)
474     start_dir = bld.path.find_dir('doc/images')
475     bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
476     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
477     bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
478     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
479     if is_win32:
480         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
481         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
482     # Data
483     data_dir = '' if is_win32 else 'geany'
484     start_dir = bld.path.find_dir('data')
485     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
486     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
487     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
488     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
489     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
490     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
491     start_dir = bld.path.find_dir('data/colorschemes')
492     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
493     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
494     start_dir = bld.path.find_dir('data/templates')
495     template_dest = '${DATADIR}/%s/templates' % data_dir
496     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
497     # Icons
498     icon_dest = '${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons/hicolor/16x16/apps'
499     start_dir = bld.path.find_dir('icons/16x16')
500     bld.install_files(icon_dest, start_dir.ant_glob('*.png'), cwd=start_dir)
501     if not is_win32:
502         start_dir = bld.path.find_dir('icons/48x48')
503         icon_dest = '${DATADIR}/icons/hicolor/48x48/apps'
504         bld.install_files(icon_dest, start_dir.ant_glob('*.png'), cwd=start_dir)
505         start_dir = bld.path.find_dir('icons/scalable')
506         scalable_dest = '${DATADIR}/icons/hicolor/scalable/apps'
507         bld.install_files(scalable_dest, start_dir.ant_glob('*.svg'), cwd=start_dir)
510 def distclean(ctx):
511     Scripting.distclean(ctx)
512     _remove_linguas_file()
515 def _remove_linguas_file():
516     # remove LINGUAS file as well
517     try:
518         os.unlink(LINGUAS_FILE)
519     except OSError:
520         pass
523 @feature('linguas')
524 def write_linguas_file(self):
525     if os.path.exists(LINGUAS_FILE):
526         return
527     linguas = ''
528     if 'LINGUAS' in self.env:
529         files = self.env['LINGUAS']
530         for po_filename in files.split(' '):
531             if os.path.exists('po/%s.po' % po_filename):
532                 linguas += '%s ' % po_filename
533     else:
534         files = os.listdir('%s/po' % self.path.abspath())
535         files.sort()
536         for filename in files:
537             if filename.endswith('.po'):
538                 linguas += '%s ' % filename[:-3]
539     file_h = open(LINGUAS_FILE, 'w')
540     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
541     file_h.close()
544 def _post_install(ctx):
545     is_win32 = _target_is_win32(ctx)
546     if is_win32:
547         return
548     theme_dir = Utils.subst_vars('${DATADIR}/icons/hicolor', ctx.env)
549     icon_cache_updated = False
550     if not ctx.options.destdir:
551         ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
552         Logs.pprint('GREEN', 'GTK icon cache updated.')
553         icon_cache_updated = True
554     if not icon_cache_updated:
555         Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
556         Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
559 def updatepo(ctx):
560     """update the message catalogs for internationalization"""
561     potfile = '%s.pot' % APPNAME
562     os.chdir('%s/po' % top)
563     try:
564         try:
565             old_size = os.stat(potfile).st_size
566         except OSError:
567             old_size = 0
568         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
569         size_new = os.stat(potfile).st_size
570         if size_new != old_size:
571             Logs.pprint('CYAN', 'Updated POT file.')
572             Logs.pprint('CYAN', 'Updating translations')
573             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
574             if ret != 0:
575                 Logs.pprint('RED', 'Updating translations failed')
576         else:
577             Logs.pprint('CYAN', 'POT file is up to date.')
578     except OSError:
579         Logs.pprint('RED', 'Failed to generate pot file.')
582 def apidoc(ctx):
583     """generate API reference documentation"""
584     basedir = ctx.path.abspath()
585     doxygen = _find_program(ctx, 'doxygen')
586     doxyfile = '%s/%s/doc/Doxyfile' % (basedir, out)
587     os.chdir('doc')
588     Logs.pprint('CYAN', 'Generating API documentation')
589     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
590     if ret != 0:
591         raise WafError('Generating API documentation failed')
592     # update hacking.html
593     cmd = _find_rst2html(ctx)
594     ctx.exec_command('%s  -stg --stylesheet=geany.css %s %s' % (cmd, '../HACKING', 'hacking.html'))
595     os.chdir('..')
598 def htmldoc(ctx):
599     """generate HTML documentation"""
600     # first try rst2html.py as it is the upstream default, fall back to rst2html
601     cmd = _find_rst2html(ctx)
602     os.chdir('doc')
603     Logs.pprint('CYAN', 'Generating HTML documentation')
604     ctx.exec_command('%s  -stg --stylesheet=geany.css %s %s' % (cmd, 'geany.txt', 'geany.html'))
605     os.chdir('..')
608 def _find_program(ctx, cmd, **kw):
609     def noop(*args):
610         pass
612     ctx = ConfigurationContext()
613     ctx.to_log = noop
614     ctx.msg = noop
615     return ctx.find_program(cmd, **kw)
618 def _find_rst2html(ctx):
619     cmds = ['rst2html.py', 'rst2html']
620     for command in cmds:
621         cmd = _find_program(ctx, command, mandatory=False)
622         if cmd:
623             break
624     if not cmd:
625         raise WafError(
626             'rst2html.py could not be found. Please install the Python docutils package.')
627     return cmd
630 def _add_define_to_env(conf, key):
631     value = conf.get_define(key)
632     # strip quotes
633     value = value.replace('"', '')
634     conf.env[key] = value
637 def _add_to_env_and_define(conf, key, value, quote=False):
638     conf.define(key, value, quote)
639     conf.env[key] = value
642 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
643     value = default_value
644     if opt_value:
645         if isinstance(opt_value, bool):
646             opt_value = 1
647         value = opt_value
649     if value is not None:
650         _add_to_env_and_define(conf, define_name, value, quote)
651     else:
652         conf.undefine(define_name)
655 def _get_git_rev(conf):
656     if not os.path.isdir('.git'):
657         return
659     try:
660         cmd = 'git rev-parse --short --revs-only HEAD'
661         revision = conf.cmd_and_log(cmd).strip()
662     except WafError:
663         return None
664     else:
665         return revision
668 def _load_intltool_if_available(conf):
669     try:
670         conf.check_tool('intltool')
671         if 'LINGUAS' in os.environ:
672             conf.env['LINGUAS'] = os.environ['LINGUAS']
673     except WafError:
674         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
675         if not _target_is_win32(conf):
676             raise
679 def _target_is_win32(ctx):
680     if 'is_win32' in ctx.env:
681         # cached
682         return ctx.env['is_win32']
683     is_win32 = None
684     if sys.platform == 'win32':
685         is_win32 = True
686     if is_win32 is None:
687         if ctx.env and 'CC' in ctx.env:
688             env_cc = ctx.env['CC']
689             if not isinstance(env_cc, str):
690                 env_cc = ''.join(env_cc)
691             is_win32 = (env_cc.find('mingw') != -1)
692     if is_win32 is None:
693         is_win32 = False
694     # cache for future checks
695     ctx.env['is_win32'] = is_win32
696     return is_win32
699 def _uc_first(string, ctx):
700     if _target_is_win32(ctx):
701         return string.title()
702     return string