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