Fix typos in German translation
[geany-mirror.git] / wscript
blob427d7eb904d811271b5258ad6475f3bb50fd81ac
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.24.0'
58 MINIMUM_GTK3_VERSION = '3.0.0'
59 MINIMUM_GLIB_VERSION = '2.28.0'
61 GEANY_LIB_VERSION = '0.0.0'
63 top = '.'
64 out = '_build_'
66 mio_sources = set(['tagmanager/mio/mio.c'])
68 ctags_sources = set([
69     'tagmanager/ctags/abaqus.c',
70     'tagmanager/ctags/args.c',
71     'tagmanager/ctags/abc.c',
72     'tagmanager/ctags/actionscript.c',
73     'tagmanager/ctags/asciidoc.c',
74     'tagmanager/ctags/asm.c',
75     'tagmanager/ctags/basic.c',
76     'tagmanager/ctags/c.c',
77     'tagmanager/ctags/cobol.c',
78     'tagmanager/ctags/conf.c',
79     'tagmanager/ctags/css.c',
80     'tagmanager/ctags/ctags.c',
81     'tagmanager/ctags/diff.c',
82     'tagmanager/ctags/docbook.c',
83     'tagmanager/ctags/erlang.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_bin_sources = set(['src/main.c'])
145 geany_icons = {
146     'hicolor/16x16/apps':       ['16x16/classviewer-class.png',
147                                  '16x16/classviewer-macro.png',
148                                  '16x16/classviewer-member.png',
149                                  '16x16/classviewer-method.png',
150                                  '16x16/classviewer-namespace.png',
151                                  '16x16/classviewer-other.png',
152                                  '16x16/classviewer-struct.png',
153                                  '16x16/classviewer-var.png',
154                                  '16x16/geany.png'],
155     'hicolor/16x16/actions':    ['16x16/geany-build.png',
156                                  '16x16/geany-close-all.png',
157                                  '16x16/geany-save-all.png'],
158     'hicolor/24x24/actions':    ['24x24/geany-build.png',
159                                  '24x24/geany-close-all.png',
160                                  '24x24/geany-save-all.png'],
161     'hicolor/32x32/actions':    ['32x32/geany-build.png',
162                                  '32x32/geany-close-all.png',
163                                  '32x32/geany-save-all.png'],
164     'hicolor/32x32/apps':       ['32x32/geany.png'],
165     'hicolor/48x48/actions':    ['48x48/geany-build.png',
166                                  '48x48/geany-close-all.png',
167                                  '48x48/geany-save-all.png'],
168     'hicolor/48x48/apps':       ['48x48/geany.png'],
169     'hicolor/scalable/apps':    ['scalable/geany.svg'],
170     'hicolor/scalable/actions': ['scalable/geany-build.svg',
171                                  'scalable/geany-close-all.svg',
172                                  'scalable/geany-save-all.svg'],
173     'Tango/16x16/actions':      ['tango/16x16/geany-save-all.png'],
174     'Tango/24x24/actions':      ['tango/24x24/geany-save-all.png'],
175     'Tango/32x32/actions':      ['tango/32x32/geany-save-all.png'],
176     'Tango/48x48/actions':      ['tango/48x48/geany-save-all.png'],
177     'Tango/scalable/actions':   ['tango/scalable/geany-save-all.svg']
179 geany_icons_indexes = {
180     'hicolor':  ['index.theme'],
181     'Tango':    ['tango/index.theme']
185 def configure(conf):
187     conf.check_waf_version(mini='1.6.1')
189     conf.load('compiler_c')
190     is_win32 = _target_is_win32(conf)
192     visibility_hidden_supported = conf.check_cc(cflags=['-Werror', '-fvisibility=hidden'], mandatory=False)
193     conf.check_cc(header_name='fcntl.h', mandatory=False)
194     conf.check_cc(header_name='fnmatch.h', mandatory=False)
195     conf.check_cc(header_name='glob.h', mandatory=False)
196     conf.check_cc(header_name='sys/time.h', mandatory=False)
197     conf.check_cc(header_name='sys/types.h', mandatory=False)
198     conf.check_cc(header_name='sys/stat.h', mandatory=False)
199     conf.define('HAVE_STDLIB_H', 1)  # are there systems without stdlib.h?
200     conf.define('STDC_HEADERS', 1)  # an optimistic guess ;-)
201     _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1)  # needed for CTags
203     conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
204     conf.check_cc(function_name='fnmatch', header_name='fnmatch.h', mandatory=False)
205     conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
206     conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
207     conf.check_cc(function_name='strstr', header_name='string.h')
209     conf.check_cc(function_name='pow', header_name='math.h', lib='m', uselib_store='M')
211     # check sunOS socket support
212     if Options.platform == 'sunos':
213         conf.check_cc(function_name='socket', lib='socket',
214                       header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
216     # check for cxx after the header and function checks have been done to ensure they are
217     # checked with cc not cxx
218     conf.load('compiler_cxx')
219     if is_win32:
220         conf.load('winres')
221     _load_intltool_if_available(conf)
223     # GTK / GIO version check
224     gtk_package_name = 'gtk+-3.0' if conf.options.use_gtk3 else 'gtk+-2.0'
225     minimum_gtk_version = MINIMUM_GTK3_VERSION if conf.options.use_gtk3 else MINIMUM_GTK_VERSION
226     conf.check_cfg(package=gtk_package_name, atleast_version=minimum_gtk_version, uselib_store='GTK',
227         mandatory=True, args='--cflags --libs')
228     conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
229         mandatory=True, args='--cflags --libs')
230     conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
231         mandatory=True, args='--cflags --libs')
232     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
233     gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
234     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
235     if conf.options.enable_mac_integration:
236         pkgname = 'gtk-mac-integration-gtk3' if conf.options.use_gtk3 else 'gtk-mac-integration-gtk2'
237         conf.check_cfg(package=pkgname, uselib_store='MAC_INTEGRATION',
238             mandatory=True, args='--cflags --libs')
239     # remember GTK version for the build step
240     conf.env['gtk_package_name'] = gtk_package_name
241     conf.env['minimum_gtk_version'] = minimum_gtk_version
242     conf.env['use_gtk3'] = conf.options.use_gtk3
244     revision = _get_git_rev(conf)
246     # rst2html for the HTML manual
247     if not conf.options.no_html_doc and revision is not None:
248         try:
249             conf.env['RST2HTML'] = _find_rst2html(conf)
250         except WafError:
251             error_msg = '''Documentation enabled but rst2html not found.
252 You can explicitly disable building of the HTML manual with --disable-html-docs,
253 but you then may not have a local copy of the HTML manual.'''
254             raise WafError(error_msg)
256     # Windows specials
257     if is_win32:
258         if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
259             # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
260             new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
261             _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
262             _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
263         _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
264         _add_to_env_and_define(conf, 'LIBDIR', '%s/lib' % conf.env['PREFIX'], quote=True)
265         conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
266         # overwrite LOCALEDIR to install message catalogues properly
267         conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share', 'locale')
268         # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
269         conf.undefine('DATADIR')
270         conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
271         conf.env.append_value('LINKFLAGS_cprogram', [
272             '-mwindows',
273             '-static-libgcc',
274             '-static-libstdc++'])
275         conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'comdlg32'])
276         # explicitly define Windows version for older Mingw environments
277         conf.define('WINVER', '0x0501', quote=False)  # for SHGetFolderPathAndSubDirW
278         conf.define('_WIN32_IE', '0x0500', quote=False)  # for SHGFP_TYPE
279     else:
280         conf.env['cshlib_PATTERN'] = '%s.so'
281         # DATADIR and LOCALEDIR are defined by the intltool tool
282         # but they are not added to the environment, so we need to
283         _add_define_to_env(conf, 'DATADIR')
284         _add_define_to_env(conf, 'LOCALEDIR')
285         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
286         libdir = os.path.join(conf.env['PREFIX'], 'lib')
287         mandir = os.path.join(conf.env['DATADIR'], 'man')
288         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
289         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
290         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
292     conf.define('ENABLE_NLS', 1)
293     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
294     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
295     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
296     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
297     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
298     conf.define('PACKAGE', APPNAME, quote=True)
299     conf.define('VERSION', VERSION, quote=True)
300     conf.define('REVISION', revision or '-1', quote=True)
302     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
304     # no VTE on Windows
305     if is_win32:
306         conf.options.no_vte = True
308     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
309     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
310     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
312     conf.write_config_header('config.h', remove=False)
314     # GEANY_EXPORT_SYMBOL and GEANY_API_SYMBOL
315     if is_win32:
316         geanyexport_cflags = []
317         geanyexport_defines = ['GEANY_EXPORT_SYMBOL=__declspec(dllexport)']
318     elif visibility_hidden_supported:
319         geanyexport_cflags = ['-fvisibility=hidden']
320         geanyexport_defines = ['GEANY_EXPORT_SYMBOL=__attribute__((visibility("default")))']
321     else:  # unknown, define to nothing
322         geanyexport_cflags = []
323         geanyexport_defines = ['GEANY_EXPORT_SYMBOL=']
324     geanyexport_defines.append('GEANY_API_SYMBOL=GEANY_EXPORT_SYMBOL')
325     conf.env['DEFINES_geanyexport'] = geanyexport_defines
326     conf.env['CFLAGS_geanyexport'] = geanyexport_cflags
327     conf.env['CXXFLAGS_geanyexport'] = geanyexport_cflags
329     # some more compiler flags
330     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
331     if conf.env['CC_NAME'] == 'gcc' and '-O' not in ''.join(conf.env['CFLAGS']):
332         conf.env.append_value('CFLAGS', ['-O2'])
333     if revision is not None:
334         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
335     # Scintilla flags
336     conf.env.append_value('CFLAGS', ['-DGTK'])
337     conf.env.append_value('CXXFLAGS',
338         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
340     # summary
341     Logs.pprint('BLUE', 'Summary:')
342     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
343     conf.msg('Using GTK version', gtk_version)
344     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
345     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
346     if revision is not None:
347         conf.msg('Compiling Git revision', revision)
350 def options(opt):
351     # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
352     # If anyone wants to add support for building with MSVC, this hack should be removed.
353     c_compiler['win32'] = ['gcc']
354     cxx_compiler['win32'] = ['g++']
356     opt.load('compiler_cc')
357     opt.load('compiler_cxx')
358     opt.load('intltool')
360     # Option
361     opt.add_option('--no-scm', action='store_true', default=False,
362         help='Disable SCM detection [default: No]', dest='no_scm')
363     # Features
364     opt.add_option('--disable-plugins', action='store_true', default=False,
365         help='compile without plugin support [default: No]', dest='no_plugins')
366     opt.add_option('--disable-socket', action='store_true', default=False,
367         help='compile without support to detect a running instance [[default: No]',
368         dest='no_socket')
369     opt.add_option('--disable-vte', action='store_true', default=False,
370         help='compile without support for an embedded virtual terminal [[default: No]',
371         dest='no_vte')
372     opt.add_option('--enable-gtk3', action='store_true', default=False,
373         help='compile with GTK3 support (experimental) [[default: No]',
374         dest='use_gtk3')
375     opt.add_option('--enable-mac-integration', action='store_true', default=False,
376         help='use gtk-mac-integration to enable improved OS X integration [[default: No]',
377         dest='enable_mac_integration')
378     opt.add_option('--disable-html-docs', action='store_true', default=False,
379         help='do not generate HTML documentation using rst2html [[default: No]',
380         dest='no_html_doc')
381     # Paths
382     opt.add_option('--mandir', type='string', default='',
383         help='man documentation', dest='mandir')
384     opt.add_option('--docdir', type='string', default='',
385         help='documentation root', dest='docdir')
386     opt.add_option('--libdir', type='string', default='',
387         help='object code libraries', dest='libdir')
390 def build(bld):
391     is_win32 = _target_is_win32(bld)
393     if bld.cmd == 'clean':
394         _remove_linguas_file()
395     if bld.cmd in ('install', 'uninstall'):
396         bld.add_post_fun(_post_install)
398     def build_plugin(plugin_name, install=True, uselib_add=[]):
399         if install:
400             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
401         else:
402             instpath = None
404         bld(
405             features                = ['c', 'cshlib'],
406             source                  = 'plugins/%s.c' % plugin_name,
407             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
408             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
409             target                  = plugin_name,
410             uselib                  = ['GTK', 'GLIB', 'GMODULE'] + uselib_add,
411             use                     = ['geany'],
412             install_path            = instpath)
414     # CTags
415     bld.objects(
416         features        = ['c'],
417         source          = ctags_sources,
418         name            = 'ctags',
419         target          = 'ctags',
420         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
421         defines         = 'G_LOG_DOMAIN="CTags"',
422         uselib          = ['cshlib', 'GLIB', 'geanyexport'])
424     # Tagmanager
425     bld.objects(
426         features        = ['c'],
427         source          = tagmanager_sources,
428         name            = 'tagmanager',
429         target          = 'tagmanager',
430         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
431         defines         = ['GEANY_PRIVATE', 'G_LOG_DOMAIN="Tagmanager"'],
432         uselib          = ['cshlib', 'GTK', 'GLIB', 'geanyexport'])
434     # MIO
435     bld.objects(
436         features        = ['c'],
437         source          = mio_sources,
438         name            = 'mio',
439         target          = 'mio',
440         includes        = ['.', 'tagmanager/mio/'],
441         defines         = 'G_LOG_DOMAIN="MIO"',
442         uselib          = ['cshlib', 'GTK', 'GLIB', 'geanyexport'])
444     # Scintilla
445     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
446     scintilla_sources.update([file.path_from(bld.srcnode) for file in files])
447     bld.objects(
448         features        = ['c', 'cxx'],
449         name            = 'scintilla',
450         target          = 'scintilla',
451         source          = scintilla_sources,
452         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
453         uselib          = ['cshlib', 'cxxshlib', 'GTK', 'GLIB', 'GMODULE', 'M', 'geanyexport'])
455     # Geany
456     if bld.env['HAVE_VTE'] == 1:
457         geany_sources.add('src/vte.c')
458     if is_win32:
459         geany_sources.add('src/win32.c')
460         geany_bin_sources.add('geany_private.rc')
462     def gen_signallist(task):
463         from xml.etree import ElementTree
465         def find_handlers(xml_filename):
466             tree = ElementTree.parse(xml_filename)
467             signals = tree.getroot().findall(".//signal")
468             return [sig.attrib["handler"] for sig in signals]
470         handlers = []
471         for node in task.inputs:
472             handlers += find_handlers(node.abspath())
473         handlers = sorted(set(handlers))
475         for node in task.outputs:
476             node.write("/* This file is auto-generated, do not edit. */\n" +
477                        ''.join(["ITEM(%s)\n" % h for h in handlers]))
479     # signallist.i
480     bld(
481         source  = 'data/geany.glade',
482         target  = bld.path.get_bld().make_node('src/signallist.i'),
483         name    = 'signallist.i',
484         rule    = gen_signallist)
486     base_uselibs = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'MAC_INTEGRATION', 'SUNOS_SOCKET', 'M']
488     # libgeany
489     bld.shlib(
490         features        = ['c', 'cxx'],
491         name            = 'geany',
492         target          = 'geany',
493         source          = geany_sources,
494         includes        = ['.', 'scintilla/include', 'tagmanager/src', 'src'],
495         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
496         uselib          = base_uselibs + ['geanyexport'],
497         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'],
498         linkflags       = bld.env['LINKFLAGS_cprogram'],
499         vnum            = GEANY_LIB_VERSION,
500         install_path    = '${PREFIX}/bin' if is_win32 else '${LIBDIR}')
502     # geany executable
503     t = bld.program(
504         features        = ['c', 'cxx'],
505         name            = 'geany_bin',
506         target          = 'geany',
507         source          = geany_bin_sources,
508         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
509         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
510         uselib          = base_uselibs + ['geanyexport'],
511         use             = ['geany'])
512     if not is_win32:
513         # http://www.freehackers.org/~tnagy/testdoc/single.html#common_c
514         t.rpath = bld.env['LIBDIR']
516     # Plugins
517     if bld.env['HAVE_PLUGINS'] == 1:
518         build_plugin('classbuilder')
519         build_plugin('demoplugin', False)
520         build_plugin('export', uselib_add=['M'])
521         build_plugin('filebrowser')
522         build_plugin('htmlchars')
523         build_plugin('saveactions')
524         build_plugin('splitwindow')
526     # Translations
527     if bld.env['INTLTOOL']:
528         bld(
529             features        = ['linguas', 'intltool_po'],
530             podir           = 'po',
531             install_path    = '${LOCALEDIR}',
532             appname         = 'geany')
534     # HTML documentation (build if it is not part of the tree already, as it is required for install)
535     html_doc_filename = os.path.join(bld.out_dir, 'doc', 'geany.html')
536     if bld.env['RST2HTML']:
537         rst2html = bld.env['RST2HTML']
538         bld(
539             source  = ['doc/geany.txt'],
540             deps    = ['doc/geany.css'],
541             target  = bld.path.get_bld().make_node('doc/geany.html'),
542             name    = 'geany.html',
543             cwd     = os.path.join(bld.path.abspath(), 'doc'),
544             rule    = '%s  -stg --stylesheet=geany.css geany.txt %s' % (rst2html, html_doc_filename))
546     # geany.pc
547     if is_win32:
548         # replace backward slashes by forward slashes as they could be interepreted as escape
549         # characters
550         geany_pc_prefix = bld.env['PREFIX'].replace('\\', '/')
551     else:
552         geany_pc_prefix = bld.env['PREFIX']
553     bld(
554         source          = 'geany.pc.in',
555         dct             = {'VERSION': VERSION,
556                            'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
557                                 (bld.env['gtk_package_name'],
558                                  bld.env['minimum_gtk_version'],
559                                  MINIMUM_GLIB_VERSION),
560                            'prefix': geany_pc_prefix,
561                            'exec_prefix': '${prefix}',
562                            'libdir': '${exec_prefix}/lib',
563                            'includedir': '${prefix}/include',
564                            'datarootdir': '${prefix}/share',
565                            'datadir': '${datarootdir}',
566                            'localedir': '${datarootdir}/locale'})
568     if not is_win32:
569         # geany.desktop
570         if bld.env['INTLTOOL']:
571             bld(
572                 features        = 'intltool_in',
573                 source          = 'geany.desktop.in',
574                 flags           = ['-d', '-q', '-u', '-c'],
575                 install_path    = '${DATADIR}/applications')
577         # geany.1
578         bld(
579             features        = 'subst',
580             source          = 'doc/geany.1.in',
581             target          = 'geany.1',
582             dct             = {'VERSION': VERSION,
583                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
584             install_path    = '${MANDIR}/man1')
586         # geany.spec
587         bld(
588             features        = 'subst',
589             source          = 'geany.spec.in',
590             target          = 'geany.spec',
591             install_path    = None,
592             dct             = {'VERSION': VERSION})
594         # Doxyfile
595         bld(
596             features        = 'subst',
597             source          = 'doc/Doxyfile.in',
598             target          = 'doc/Doxyfile',
599             install_path    = None,
600             dct             = {'VERSION': VERSION,
601                                'top_builddir': bld.out_dir,
602                                'top_srcdir': bld.top_dir,})
604     # disable build/install phase interleaving
605     bld.add_group()
607     ###
608     # Install files
609     ###
610     # Headers
611     bld.install_files('${PREFIX}/include/geany', '''
612         src/app.h
613         src/build.h
614         src/dialogs.h
615         src/document.h
616         src/editor.h
617         src/encodings.h
618         src/filetypes.h
619         src/geany.h
620         src/highlighting.h
621         src/keybindings.h
622         src/main.h
623         src/msgwindow.h
624         src/navqueue.h
625         src/plugindata.h
626         src/pluginutils.h
627         src/prefs.h
628         src/project.h
629         src/sciwrappers.h
630         src/search.h
631         src/stash.h
632         src/support.h
633         src/symbols.h
634         src/templates.h
635         src/toolbar.h
636         src/ui_utils.h
637         src/utils.h
638         src/gtkcompat.h
639         plugins/geanyplugin.h
640         plugins/geanyfunctions.h
641         ''')
642     bld.install_files('${PREFIX}/include/geany/scintilla', '''
643         scintilla/include/SciLexer.h scintilla/include/Scintilla.h
644         scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
645     bld.install_files('${PREFIX}/include/geany/tagmanager', '''
646         tagmanager/src/tm_source_file.h
647         tagmanager/src/tm_tag.h
648         tagmanager/src/tm_tagmanager.h
649         tagmanager/src/tm_workspace.h ''')
650     # Docs
651     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
652     ext = '.txt' if is_win32 else ''
653     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
654         basename = _uc_first(filename, bld)
655         destination_filename = '%s%s' % (basename, ext)
656         destination = os.path.join(base_dir, destination_filename)
657         bld.install_as(destination, filename)
659     # install HTML documentation only if it exists, i.e. it was built before
660     # local_html_doc_filename supports installing HTML doc from in-tree geany.html if it exists
661     local_html_doc_filename = os.path.join(bld.path.abspath(), 'doc', 'geany.html')
662     if os.path.exists(html_doc_filename) or os.path.exists(local_html_doc_filename):
663         html_dir = '' if is_win32 else 'html/'
664         html_name = 'Manual.html' if is_win32 else 'index.html'
665         start_dir = bld.path.find_dir('doc/images')
666         bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
667         bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
669     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
670     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
671     if is_win32:
672         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
673         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
674     # Data
675     data_dir = '' if is_win32 else 'geany'
676     start_dir = bld.path.find_dir('data')
677     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
678     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
679     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
680     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
681     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
682     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
683     if bld.env['use_gtk3']:
684         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
685     else:
686         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
688     start_dir = bld.path.find_dir('data/colorschemes')
689     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
690     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
691     start_dir = bld.path.find_dir('data/templates')
692     template_dest = '${DATADIR}/%s/templates' % data_dir
693     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
694     # Icons
695     for dest, srcs in geany_icons.items():
696         dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
697         bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
698     # install theme indexes on Windows
699     if is_win32:
700         for dest, srcs in geany_icons_indexes.items():
701             bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
704 def distclean(ctx):
705     Scripting.distclean(ctx)
706     _remove_linguas_file()
709 def _remove_linguas_file():
710     # remove LINGUAS file as well
711     try:
712         os.unlink(LINGUAS_FILE)
713     except OSError:
714         pass
717 @feature('linguas')
718 @before_method('apply_intltool_po')
719 def write_linguas_file(self):
720     if os.path.exists(LINGUAS_FILE):
721         return
722     linguas = ''
723     if 'LINGUAS' in self.env:
724         files = self.env['LINGUAS']
725         for po_filename in files.split(' '):
726             if os.path.exists('po/%s.po' % po_filename):
727                 linguas += '%s ' % po_filename
728     else:
729         files = os.listdir('%s/po' % self.path.abspath())
730         files.sort()
731         for filename in files:
732             if filename.endswith('.po'):
733                 linguas += '%s ' % filename[:-3]
734     file_h = open(LINGUAS_FILE, 'w')
735     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
736     file_h.close()
739 def _post_install(ctx):
740     is_win32 = _target_is_win32(ctx)
741     if is_win32:
742         return
743     for d in 'hicolor', 'Tango':
744         theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
745         icon_cache_updated = False
746         if not ctx.options.destdir:
747             ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
748             Logs.pprint('GREEN', 'GTK icon cache updated.')
749             icon_cache_updated = True
750         if not icon_cache_updated:
751             Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
752             Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
755 def updatepo(ctx):
756     """update the message catalogs for internationalization"""
757     potfile = '%s.pot' % APPNAME
758     os.chdir('%s/po' % top)
759     try:
760         try:
761             old_size = os.stat(potfile).st_size
762         except OSError:
763             old_size = 0
764         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
765         size_new = os.stat(potfile).st_size
766         if size_new != old_size:
767             Logs.pprint('CYAN', 'Updated POT file.')
768             Logs.pprint('CYAN', 'Updating translations')
769             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
770             if ret != 0:
771                 Logs.pprint('RED', 'Updating translations failed')
772         else:
773             Logs.pprint('CYAN', 'POT file is up to date.')
774     except OSError:
775         Logs.pprint('RED', 'Failed to generate pot file.')
778 def apidoc(ctx):
779     """generate API reference documentation"""
780     ctx = BuildContext()  # create our own context to have ctx.top_dir
781     basedir = ctx.top_dir
782     doxygen = _find_program(ctx, 'doxygen')
783     doxyfile = '%s/doc/Doxyfile' % ctx.out_dir
784     Logs.pprint('CYAN', 'Generating API documentation')
785     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
786     if ret != 0:
787         raise WafError('Generating API documentation failed')
790 def hackingdoc(ctx):
791     """generate HACKING documentation"""
792     ctx = BuildContext()  # create our own context to have ctx.top_dir
793     Logs.pprint('CYAN', 'Generating HACKING documentation')
794     cmd = _find_rst2html(ctx)
795     hacking_file = os.path.join(ctx.top_dir, 'HACKING')
796     hacking_html_file = os.path.join(ctx.top_dir, 'doc', 'hacking.html')
797     stylesheet = os.path.join(ctx.top_dir, 'doc', 'geany.css')
798     ret = ctx.exec_command('%s  -stg --stylesheet=%s %s %s' % (
799         cmd, stylesheet, hacking_file, hacking_html_file))
800     if ret != 0:
801         raise WafError('Generating HACKING documentation failed')
804 def _find_program(ctx, cmd, **kw):
805     def noop(*args):
806         pass
808     if ctx is None or not isinstance(ctx, ConfigurationContext):
809         ctx = ConfigurationContext()
810         ctx.to_log = noop
811         ctx.msg = noop
812     return ctx.find_program(cmd, **kw)
815 def _find_rst2html(ctx):
816     cmds = ['rst2html', 'rst2html2']
817     for command in cmds:
818         cmd = _find_program(ctx, command, mandatory=False, exts=',.py')
819         if cmd:
820             break
821     if not cmd:
822         raise WafError(
823             'rst2html.py could not be found. Please install the Python docutils package.')
824     return cmd
827 def _add_define_to_env(conf, key):
828     value = conf.get_define(key)
829     # strip quotes
830     value = value.replace('"', '')
831     conf.env[key] = value
834 def _add_to_env_and_define(conf, key, value, quote=False):
835     conf.define(key, value, quote)
836     conf.env[key] = value
839 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
840     value = default_value
841     if opt_value:
842         if isinstance(opt_value, bool):
843             opt_value = 1
844         value = opt_value
846     if value is not None:
847         _add_to_env_and_define(conf, define_name, value, quote)
848     else:
849         conf.undefine(define_name)
852 def _get_git_rev(conf):
853     if conf.options.no_scm:
854         return
856     if not os.path.isdir('.git'):
857         return
859     try:
860         cmd = 'git rev-parse --short --revs-only HEAD'
861         revision = conf.cmd_and_log(cmd).strip()
862     except WafError:
863         return None
864     else:
865         return revision
868 def _load_intltool_if_available(conf):
869     try:
870         conf.load('intltool')
871         if 'LINGUAS' in os.environ:
872             conf.env['LINGUAS'] = os.environ['LINGUAS']
873     except WafError:
874         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
875         if not _target_is_win32(conf):
876             raise
879 def _target_is_win32(ctx):
880     if 'is_win32' in ctx.env:
881         # cached
882         return ctx.env['is_win32']
883     is_win32 = None
884     if sys.platform == 'win32':
885         is_win32 = True
886     if is_win32 is None:
887         if ctx.env and 'CC' in ctx.env:
888             env_cc = ctx.env['CC']
889             if not isinstance(env_cc, str):
890                 env_cc = ''.join(env_cc)
891             is_win32 = (env_cc.find('mingw') != -1)
892     if is_win32 is None:
893         is_win32 = False
894     # cache for future checks
895     ctx.env['is_win32'] = is_win32
896     return is_win32
899 def _uc_first(string, ctx):
900     if _target_is_win32(ctx):
901         return string.title()
902     return string