autotools: Only uninstall what we actually installed
[geany-mirror.git] / wscript
blob73a8e5c4edc6394a85ebc9841db86b83decdfa54
1 # -*- coding: utf-8 -*-
3 # WAF build script - this file is part of Geany, a fast and lightweight IDE
5 # Copyright 2008-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
6 # Copyright 2008-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 """
23 This is a WAF build script (http://code.google.com/p/waf/).
24 It can be used as an alternative build system to autotools
25 for Geany. It does not (yet) cover all of the autotools tests and
26 configure options but all important things are working.
27 "make dist" should be done with autotools, most other targets and
28 functions should work better (regarding performance and flexibility)
29 or at least equally.
31 Missing features: --enable-binreloc, make targets: dist, pdf (in doc/)
32 Known issues: Dependency handling is buggy, e.g. if src/document.h is
33               changed, depending source files are not rebuilt (maybe Waf bug).
35 The code of this file itself loosely follows PEP 8 with some exceptions
36 (line width 100 characters and some other minor things).
38 Requires WAF 1.6.1 and Python 2.5 (or later).
39 """
42 import sys
43 import os
44 import tempfile
45 from waflib import Logs, Options, Scripting, Utils
46 from waflib.Build import BuildContext
47 from waflib.Configure import ConfigurationContext
48 from waflib.Errors import WafError
49 from waflib.TaskGen import feature, before_method
50 from waflib.Tools.compiler_c import c_compiler
51 from waflib.Tools.compiler_cxx import cxx_compiler
54 APPNAME = 'geany'
55 VERSION = '1.25'
56 LINGUAS_FILE = os.path.join('po', 'LINGUAS')
57 MINIMUM_GTK_VERSION = '2.16.0'
58 MINIMUM_GTK3_VERSION = '3.0.0'
59 MINIMUM_GLIB_VERSION = '2.20.0'
61 top = '.'
62 out = '_build_'
65 mio_sources = set(['tagmanager/mio/mio.c'])
67 ctags_sources = set([
68     'tagmanager/ctags/abaqus.c',
69     'tagmanager/ctags/args.c',
70     'tagmanager/ctags/abc.c',
71     'tagmanager/ctags/actionscript.c',
72     'tagmanager/ctags/asciidoc.c',
73     'tagmanager/ctags/asm.c',
74     'tagmanager/ctags/basic.c',
75     'tagmanager/ctags/c.c',
76     'tagmanager/ctags/cobol.c',
77     'tagmanager/ctags/conf.c',
78     'tagmanager/ctags/css.c',
79     'tagmanager/ctags/ctags.c',
80     'tagmanager/ctags/diff.c',
81     'tagmanager/ctags/docbook.c',
82     'tagmanager/ctags/entry.c',
83     'tagmanager/ctags/fortran.c',
84     'tagmanager/ctags/get.c',
85     'tagmanager/ctags/haskell.c',
86     'tagmanager/ctags/haxe.c',
87     'tagmanager/ctags/html.c',
88     'tagmanager/ctags/js.c',
89     'tagmanager/ctags/keyword.c',
90     'tagmanager/ctags/latex.c',
91     'tagmanager/ctags/lregex.c',
92     'tagmanager/ctags/lua.c',
93     'tagmanager/ctags/make.c',
94     'tagmanager/ctags/markdown.c',
95     'tagmanager/ctags/matlab.c',
96     'tagmanager/ctags/nsis.c',
97     'tagmanager/ctags/nestlevel.c',
98     'tagmanager/ctags/objc.c',
99     'tagmanager/ctags/options.c',
100     'tagmanager/ctags/parse.c',
101     'tagmanager/ctags/pascal.c',
102     'tagmanager/ctags/r.c',
103     'tagmanager/ctags/perl.c',
104     'tagmanager/ctags/php.c',
105     'tagmanager/ctags/python.c',
106     'tagmanager/ctags/read.c',
107     'tagmanager/ctags/rest.c',
108     'tagmanager/ctags/ruby.c',
109     'tagmanager/ctags/rust.c',
110     'tagmanager/ctags/sh.c',
111     'tagmanager/ctags/sort.c',
112     'tagmanager/ctags/sql.c',
113     'tagmanager/ctags/strlist.c',
114     'tagmanager/ctags/txt2tags.c',
115     'tagmanager/ctags/tcl.c',
116     'tagmanager/ctags/vhdl.c',
117     'tagmanager/ctags/verilog.c',
118     'tagmanager/ctags/vstring.c'])
120 tagmanager_sources = set([
121     'tagmanager/src/tm_file_entry.c',
122     'tagmanager/src/tm_source_file.c',
123     'tagmanager/src/tm_tag.c',
124     'tagmanager/src/tm_work_object.c',
125     'tagmanager/src/tm_workspace.c'])
127 scintilla_sources = set(['scintilla/gtk/scintilla-marshal.c'])
129 geany_sources = set([
130     'src/about.c', 'src/build.c', 'src/callbacks.c', 'src/dialogs.c', 'src/document.c',
131     'src/editor.c', 'src/encodings.c', 'src/filetypes.c', 'src/geanyentryaction.c',
132     'src/geanymenubuttonaction.c', 'src/geanyobject.c', 'src/geanywraplabel.c',
133     'src/highlighting.c', 'src/keybindings.c',
134     'src/keyfile.c', 'src/log.c', 'src/main.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c',
135     'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
136     'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
137     'src/symbols.c',
138     'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
139     'src/ui_utils.c', 'src/utils.c'])
141 geany_icons = {
142     'hicolor/16x16/apps':       ['16x16/classviewer-class.png',
143                                  '16x16/classviewer-macro.png',
144                                  '16x16/classviewer-member.png',
145                                  '16x16/classviewer-method.png',
146                                  '16x16/classviewer-namespace.png',
147                                  '16x16/classviewer-other.png',
148                                  '16x16/classviewer-struct.png',
149                                  '16x16/classviewer-var.png',
150                                  '16x16/geany.png'],
151     'hicolor/16x16/actions':    ['16x16/geany-build.png',
152                                  '16x16/geany-close-all.png',
153                                  '16x16/geany-save-all.png'],
154     'hicolor/24x24/actions':    ['24x24/geany-build.png',
155                                  '24x24/geany-close-all.png',
156                                  '24x24/geany-save-all.png'],
157     'hicolor/32x32/actions':    ['32x32/geany-build.png',
158                                  '32x32/geany-close-all.png',
159                                  '32x32/geany-save-all.png'],
160     'hicolor/48x48/actions':    ['48x48/geany-build.png',
161                                  '48x48/geany-close-all.png',
162                                  '48x48/geany-save-all.png'],
163     'hicolor/48x48/apps':       ['48x48/geany.png'],
164     'hicolor/scalable/apps':    ['scalable/geany.svg'],
165     'hicolor/scalable/actions': ['scalable/geany-build.svg',
166                                  'scalable/geany-close-all.svg',
167                                  'scalable/geany-save-all.svg'],
168     'Tango/16x16/actions':      ['tango/16x16/geany-save-all.png'],
169     'Tango/24x24/actions':      ['tango/24x24/geany-save-all.png'],
170     'Tango/32x32/actions':      ['tango/32x32/geany-save-all.png'],
171     'Tango/48x48/actions':      ['tango/48x48/geany-save-all.png'],
172     'Tango/scalable/actions':   ['tango/scalable/geany-save-all.svg']
174 geany_icons_indexes = {
175     'hicolor':  ['index.theme'],
176     'Tango':    ['tango/index.theme']
180 def configure(conf):
182     conf.check_waf_version(mini='1.6.1')
184     conf.load('compiler_c')
185     is_win32 = _target_is_win32(conf)
187     conf.check_cc(header_name='fcntl.h', mandatory=False)
188     conf.check_cc(header_name='fnmatch.h', mandatory=False)
189     conf.check_cc(header_name='glob.h', mandatory=False)
190     conf.check_cc(header_name='sys/time.h', mandatory=False)
191     conf.check_cc(header_name='sys/types.h', mandatory=False)
192     conf.check_cc(header_name='sys/stat.h', mandatory=False)
193     conf.define('HAVE_STDLIB_H', 1)  # are there systems without stdlib.h?
194     conf.define('STDC_HEADERS', 1)  # an optimistic guess ;-)
195     _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1)  # needed for CTags
197     conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
198     conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
199     conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
200     conf.check_cc(function_name='strstr', header_name='string.h')
202     conf.check_cc(function_name='pow', header_name='math.h', lib='m', uselib_store='M')
204     # check sunOS socket support
205     if Options.platform == 'sunos':
206         conf.check_cc(function_name='socket', lib='socket',
207                       header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
209     # check for cxx after the header and function checks have been done to ensure they are
210     # checked with cc not cxx
211     conf.load('compiler_cxx')
212     if is_win32:
213         conf.load('winres')
214     _load_intltool_if_available(conf)
216     # GTK / GIO version check
217     gtk_package_name = 'gtk+-3.0' if conf.options.use_gtk3 else 'gtk+-2.0'
218     minimum_gtk_version = MINIMUM_GTK3_VERSION if conf.options.use_gtk3 else MINIMUM_GTK_VERSION
219     conf.check_cfg(package=gtk_package_name, atleast_version=minimum_gtk_version, uselib_store='GTK',
220         mandatory=True, args='--cflags --libs')
221     conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
222         mandatory=True, args='--cflags --libs')
223     conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
224         mandatory=True, args='--cflags --libs')
225     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
226     gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
227     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
228     # remember GTK version for the build step
229     conf.env['gtk_package_name'] = gtk_package_name
230     conf.env['minimum_gtk_version'] = minimum_gtk_version
231     conf.env['use_gtk3'] = conf.options.use_gtk3
233     revision = _get_git_rev(conf)
235     # rst2html for the HTML manual
236     if not conf.options.no_html_doc and revision is not None:
237         try:
238             conf.env['RST2HTML'] = _find_rst2html(conf)
239         except WafError:
240             error_msg = '''Documentation enabled but rst2html not found.
241 You can explicitly disable building of the HTML manual with --disable-html-docs,
242 but you then may not have a local copy of the HTML manual.'''
243             raise WafError(error_msg)
245     # Windows specials
246     if is_win32:
247         if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
248             # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
249             new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
250             _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
251             _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
252         _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
253         _add_to_env_and_define(conf, 'LIBDIR', '%s/lib' % conf.env['PREFIX'], quote=True)
254         conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
255         # overwrite LOCALEDIR to install message catalogues properly
256         conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share', 'locale')
257         # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
258         conf.undefine('DATADIR')
259         conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
260         conf.env.append_value('LINKFLAGS_cprogram', [
261             '-mwindows',
262             '-static-libgcc',
263             '-static-libstdc++'])
264         conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'iberty'])
265     else:
266         conf.env['cshlib_PATTERN'] = '%s.so'
267         # DATADIR and LOCALEDIR are defined by the intltool tool
268         # but they are not added to the environment, so we need to
269         _add_define_to_env(conf, 'DATADIR')
270         _add_define_to_env(conf, 'LOCALEDIR')
271         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
272         libdir = os.path.join(conf.env['PREFIX'], 'lib')
273         mandir = os.path.join(conf.env['DATADIR'], 'man')
274         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
275         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
276         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
278     conf.define('ENABLE_NLS', 1)
279     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
280     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
281     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
282     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
283     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
284     conf.define('PACKAGE', APPNAME, quote=True)
285     conf.define('VERSION', VERSION, quote=True)
286     conf.define('REVISION', revision or '-1', quote=True)
288     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
290     # no VTE on Windows
291     if is_win32:
292         conf.options.no_vte = True
294     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
295     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
296     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
298     conf.write_config_header('config.h', remove=False)
300     # some more compiler flags
301     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
302     if revision is not None:
303         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
304     # Scintilla flags
305     conf.env.append_value('CFLAGS', ['-DGTK'])
306     conf.env.append_value('CXXFLAGS',
307         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
309     # summary
310     Logs.pprint('BLUE', 'Summary:')
311     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
312     conf.msg('Using GTK version', gtk_version)
313     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
314     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
315     if revision is not None:
316         conf.msg('Compiling Git revision', revision)
319 def options(opt):
320     # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
321     # If anyone wants to add support for building with MSVC, this hack should be removed.
322     c_compiler['win32'] = ['gcc']
323     cxx_compiler['win32'] = ['g++']
325     opt.load('compiler_cc')
326     opt.load('compiler_cxx')
327     opt.load('intltool')
329     # Option
330     opt.add_option('--no-scm', action='store_true', default=False,
331         help='Disable SCM detection [default: No]', dest='no_scm')
332     # Features
333     opt.add_option('--disable-plugins', action='store_true', default=False,
334         help='compile without plugin support [default: No]', dest='no_plugins')
335     opt.add_option('--disable-socket', action='store_true', default=False,
336         help='compile without support to detect a running instance [[default: No]',
337         dest='no_socket')
338     opt.add_option('--disable-vte', action='store_true', default=False,
339         help='compile without support for an embedded virtual terminal [[default: No]',
340         dest='no_vte')
341     opt.add_option('--enable-gtk3', action='store_true', default=False,
342         help='compile with GTK3 support (experimental) [[default: No]',
343         dest='use_gtk3')
344     opt.add_option('--disable-html-docs', action='store_true', default=False,
345         help='do not generate HTML documentation using rst2html [[default: No]',
346         dest='no_html_doc')
347     # Paths
348     opt.add_option('--mandir', type='string', default='',
349         help='man documentation', dest='mandir')
350     opt.add_option('--docdir', type='string', default='',
351         help='documentation root', dest='docdir')
352     opt.add_option('--libdir', type='string', default='',
353         help='object code libraries', dest='libdir')
356 def build(bld):
357     is_win32 = _target_is_win32(bld)
359     if bld.cmd == 'clean':
360         _remove_linguas_file()
361     if bld.cmd in ('install', 'uninstall'):
362         bld.add_post_fun(_post_install)
364     def build_plugin(plugin_name, install=True, uselib_add=[]):
365         if install:
366             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
367         else:
368             instpath = None
370         bld(
371             features                = ['c', 'cshlib'],
372             source                  = 'plugins/%s.c' % plugin_name,
373             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
374             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
375             target                  = plugin_name,
376             uselib                  = ['GTK', 'GLIB', 'GMODULE'] + uselib_add,
377             install_path            = instpath)
379     # CTags
380     bld(
381         features        = ['c', 'cstlib'],
382         source          = ctags_sources,
383         name            = 'ctags',
384         target          = 'ctags',
385         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
386         defines         = 'G_LOG_DOMAIN="CTags"',
387         uselib          = ['GLIB'],
388         install_path    = None)  # do not install this library
390     # Tagmanager
391     bld(
392         features        = ['c', 'cstlib'],
393         source          = tagmanager_sources,
394         name            = 'tagmanager',
395         target          = 'tagmanager',
396         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
397         defines         = 'G_LOG_DOMAIN="Tagmanager"',
398         uselib          = ['GTK', 'GLIB'],
399         install_path    = None)  # do not install this library
401     # MIO
402     bld(
403         features        = ['c', 'cstlib'],
404         source          = mio_sources,
405         name            = 'mio',
406         target          = 'mio',
407         includes        = ['.', 'tagmanager/mio/'],
408         defines         = 'G_LOG_DOMAIN="MIO"',
409         uselib          = ['GTK', 'GLIB'],
410         install_path    = None)  # do not install this library
412     # Scintilla
413     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
414     scintilla_sources.update(files)
415     bld(
416         features        = ['c', 'cxx', 'cxxstlib'],
417         name            = 'scintilla',
418         target          = 'scintilla',
419         source          = scintilla_sources,
420         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
421         uselib          = ['GTK', 'GLIB', 'GMODULE', 'M'],
422         install_path    = None)  # do not install this library
424     # Geany
425     if bld.env['HAVE_VTE'] == 1:
426         geany_sources.add('src/vte.c')
427     if is_win32:
428         geany_sources.add('src/win32.c')
429         geany_sources.add('geany_private.rc')
431     bld(
432         features        = ['c', 'cxx', 'cprogram'],
433         name            = 'geany',
434         target          = 'geany',
435         source          = geany_sources,
436         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
437         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
438         uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET', 'M'],
439         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'])
441     # geanyfunctions.h
442     bld(
443         source  = ['plugins/genapi.py', 'src/plugins.c'],
444         name    = 'geanyfunctions.h',
445         before  = ['c', 'cxx'],
446         cwd     = '%s/plugins' % bld.path.abspath(),
447         rule    = '%s genapi.py -q' % sys.executable)
449     # Plugins
450     if bld.env['HAVE_PLUGINS'] == 1:
451         build_plugin('classbuilder')
452         build_plugin('demoplugin', False)
453         build_plugin('export', uselib_add=['M'])
454         build_plugin('filebrowser')
455         build_plugin('htmlchars')
456         build_plugin('saveactions')
457         build_plugin('splitwindow')
459     # Translations
460     if bld.env['INTLTOOL']:
461         bld(
462             features        = ['linguas', 'intltool_po'],
463             podir           = 'po',
464             install_path    = '${LOCALEDIR}',
465             appname         = 'geany')
467     # HTML documentation (build if it is not part of the tree already, as it is required for install)
468     html_doc_filename = os.path.join(bld.out_dir, 'doc', 'geany.html')
469     if bld.env['RST2HTML']:
470         rst2html = bld.env['RST2HTML']
471         bld(
472             source  = ['doc/geany.txt'],
473             deps    = ['doc/geany.css'],
474             target  = 'doc/geany.html',
475             name    = 'geany.html',
476             cwd     = os.path.join(bld.path.abspath(), 'doc'),
477             rule    = '%s  -stg --stylesheet=geany.css geany.txt %s' % (rst2html, html_doc_filename))
479     # geany.pc
480     if is_win32:
481         # replace backward slashes by forward slashes as they could be interepreted as escape
482         # characters
483         geany_pc_prefix = bld.env['PREFIX'].replace('\\', '/')
484     else:
485         geany_pc_prefix = bld.env['PREFIX']
486     bld(
487         source          = 'geany.pc.in',
488         dct             = {'VERSION': VERSION,
489                            'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
490                                 (bld.env['gtk_package_name'],
491                                  bld.env['minimum_gtk_version'],
492                                  MINIMUM_GLIB_VERSION),
493                            'prefix': geany_pc_prefix,
494                            'exec_prefix': '${prefix}',
495                            'libdir': '${exec_prefix}/lib',
496                            'includedir': '${prefix}/include',
497                            'datarootdir': '${prefix}/share',
498                            'datadir': '${datarootdir}',
499                            'localedir': '${datarootdir}/locale'})
501     if not is_win32:
502         # geany.desktop
503         if bld.env['INTLTOOL']:
504             bld(
505                 features        = 'intltool_in',
506                 source          = 'geany.desktop.in',
507                 flags           = ['-d', '-q', '-u', '-c'],
508                 install_path    = '${DATADIR}/applications')
510         # geany.1
511         bld(
512             features        = 'subst',
513             source          = 'doc/geany.1.in',
514             target          = 'geany.1',
515             dct             = {'VERSION': VERSION,
516                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
517             install_path    = '${MANDIR}/man1')
519         # geany.spec
520         bld(
521             features        = 'subst',
522             source          = 'geany.spec.in',
523             target          = 'geany.spec',
524             install_path    = None,
525             dct             = {'VERSION': VERSION})
527         # Doxyfile
528         bld(
529             features        = 'subst',
530             source          = 'doc/Doxyfile.in',
531             target          = 'doc/Doxyfile',
532             install_path    = None,
533             dct             = {'VERSION': VERSION,
534                                'top_builddir': bld.out_dir,
535                                'top_srcdir': bld.top_dir,})
537     ###
538     # Install files
539     ###
540     # Headers
541     bld.install_files('${PREFIX}/include/geany', '''
542         src/app.h src/document.h src/editor.h src/encodings.h src/filetypes.h src/geany.h
543         src/highlighting.h src/keybindings.h src/msgwindow.h src/plugindata.h
544         src/prefs.h src/project.h src/search.h src/stash.h src/support.h
545         src/templates.h src/toolbar.h src/ui_utils.h src/utils.h src/build.h src/gtkcompat.h
546         plugins/geanyplugin.h plugins/geanyfunctions.h''')
547     bld.install_files('${PREFIX}/include/geany/scintilla', '''
548         scintilla/include/SciLexer.h scintilla/include/Scintilla.h
549         scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
550     bld.install_files('${PREFIX}/include/geany/tagmanager', '''
551         tagmanager/src/tm_file_entry.h
552         tagmanager/src/tm_source_file.h tagmanager/src/tm_parser.h
553         tagmanager/src/tm_tag.h
554         tagmanager/src/tm_tagmanager.h tagmanager/src/tm_work_object.h
555         tagmanager/src/tm_workspace.h ''')
556     # Docs
557     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
558     ext = '.txt' if is_win32 else ''
559     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
560         basename = _uc_first(filename, bld)
561         destination_filename = '%s%s' % (basename, ext)
562         destination = os.path.join(base_dir, destination_filename)
563         bld.install_as(destination, filename)
565     # install HTML documentation only if it exists, i.e. it was built before
566     # local_html_doc_filename supports installing HTML doc from in-tree geany.html if it exists
567     local_html_doc_filename = os.path.join(bld.path.abspath(), 'doc', 'geany.html')
568     if os.path.exists(html_doc_filename) or os.path.exists(local_html_doc_filename):
569         html_dir = '' if is_win32 else 'html/'
570         html_name = 'Manual.html' if is_win32 else 'index.html'
571         start_dir = bld.path.find_dir('doc/images')
572         bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
573         bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
575     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
576     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
577     if is_win32:
578         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
579         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
580     # Data
581     data_dir = '' if is_win32 else 'geany'
582     start_dir = bld.path.find_dir('data')
583     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
584     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
585     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
586     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
587     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
588     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
589     if bld.env['use_gtk3']:
590         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
591     else:
592         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
594     start_dir = bld.path.find_dir('data/colorschemes')
595     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
596     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
597     start_dir = bld.path.find_dir('data/templates')
598     template_dest = '${DATADIR}/%s/templates' % data_dir
599     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
600     # Icons
601     for dest, srcs in geany_icons.items():
602         dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
603         bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
604     # install theme indexes on Windows
605     if is_win32:
606         for dest, srcs in geany_icons_indexes.items():
607             bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
610 def distclean(ctx):
611     Scripting.distclean(ctx)
612     _remove_linguas_file()
615 def _remove_linguas_file():
616     # remove LINGUAS file as well
617     try:
618         os.unlink(LINGUAS_FILE)
619     except OSError:
620         pass
623 @feature('linguas')
624 @before_method('apply_intltool_po')
625 def write_linguas_file(self):
626     if os.path.exists(LINGUAS_FILE):
627         return
628     linguas = ''
629     if 'LINGUAS' in self.env:
630         files = self.env['LINGUAS']
631         for po_filename in files.split(' '):
632             if os.path.exists('po/%s.po' % po_filename):
633                 linguas += '%s ' % po_filename
634     else:
635         files = os.listdir('%s/po' % self.path.abspath())
636         files.sort()
637         for filename in files:
638             if filename.endswith('.po'):
639                 linguas += '%s ' % filename[:-3]
640     file_h = open(LINGUAS_FILE, 'w')
641     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
642     file_h.close()
645 def _post_install(ctx):
646     is_win32 = _target_is_win32(ctx)
647     if is_win32:
648         return
649     for d in 'hicolor', 'Tango':
650         theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
651         icon_cache_updated = False
652         if not ctx.options.destdir:
653             ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
654             Logs.pprint('GREEN', 'GTK icon cache updated.')
655             icon_cache_updated = True
656         if not icon_cache_updated:
657             Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
658             Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
661 def updatepo(ctx):
662     """update the message catalogs for internationalization"""
663     potfile = '%s.pot' % APPNAME
664     os.chdir('%s/po' % top)
665     try:
666         try:
667             old_size = os.stat(potfile).st_size
668         except OSError:
669             old_size = 0
670         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
671         size_new = os.stat(potfile).st_size
672         if size_new != old_size:
673             Logs.pprint('CYAN', 'Updated POT file.')
674             Logs.pprint('CYAN', 'Updating translations')
675             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
676             if ret != 0:
677                 Logs.pprint('RED', 'Updating translations failed')
678         else:
679             Logs.pprint('CYAN', 'POT file is up to date.')
680     except OSError:
681         Logs.pprint('RED', 'Failed to generate pot file.')
684 def apidoc(ctx):
685     """generate API reference documentation"""
686     ctx = BuildContext()  # create our own context to have ctx.top_dir
687     basedir = ctx.top_dir
688     doxygen = _find_program(ctx, 'doxygen')
689     doxyfile = '%s/doc/Doxyfile' % ctx.out_dir
690     Logs.pprint('CYAN', 'Generating API documentation')
691     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
692     if ret != 0:
693         raise WafError('Generating API documentation failed')
696 def hackingdoc(ctx):
697     """generate HACKING documentation"""
698     ctx = BuildContext()  # create our own context to have ctx.top_dir
699     Logs.pprint('CYAN', 'Generating HACKING documentation')
700     cmd = _find_rst2html(ctx)
701     hacking_file = os.path.join(ctx.top_dir, 'HACKING')
702     hacking_html_file = os.path.join(ctx.top_dir, 'doc', 'hacking.html')
703     stylesheet = os.path.join(ctx.top_dir, 'doc', 'geany.css')
704     ret = ctx.exec_command('%s  -stg --stylesheet=%s %s %s' % (
705         cmd, stylesheet, hacking_file, hacking_html_file))
706     if ret != 0:
707         raise WafError('Generating HACKING documentation failed')
710 def _find_program(ctx, cmd, **kw):
711     def noop(*args):
712         pass
714     if ctx is None or not isinstance(ctx, ConfigurationContext):
715         ctx = ConfigurationContext()
716         ctx.to_log = noop
717         ctx.msg = noop
718     return ctx.find_program(cmd, **kw)
721 def _find_rst2html(ctx):
722     cmds = ['rst2html', 'rst2html2']
723     for command in cmds:
724         cmd = _find_program(ctx, command, mandatory=False, exts=',.py')
725         if cmd:
726             break
727     if not cmd:
728         raise WafError(
729             'rst2html.py could not be found. Please install the Python docutils package.')
730     return cmd
733 def _add_define_to_env(conf, key):
734     value = conf.get_define(key)
735     # strip quotes
736     value = value.replace('"', '')
737     conf.env[key] = value
740 def _add_to_env_and_define(conf, key, value, quote=False):
741     conf.define(key, value, quote)
742     conf.env[key] = value
745 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
746     value = default_value
747     if opt_value:
748         if isinstance(opt_value, bool):
749             opt_value = 1
750         value = opt_value
752     if value is not None:
753         _add_to_env_and_define(conf, define_name, value, quote)
754     else:
755         conf.undefine(define_name)
758 def _get_git_rev(conf):
759     if conf.options.no_scm:
760         return
762     if not os.path.isdir('.git'):
763         return
765     try:
766         cmd = 'git rev-parse --short --revs-only HEAD'
767         revision = conf.cmd_and_log(cmd).strip()
768     except WafError:
769         return None
770     else:
771         return revision
774 def _load_intltool_if_available(conf):
775     try:
776         conf.load('intltool')
777         if 'LINGUAS' in os.environ:
778             conf.env['LINGUAS'] = os.environ['LINGUAS']
779     except WafError:
780         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
781         if not _target_is_win32(conf):
782             raise
785 def _target_is_win32(ctx):
786     if 'is_win32' in ctx.env:
787         # cached
788         return ctx.env['is_win32']
789     is_win32 = None
790     if sys.platform == 'win32':
791         is_win32 = True
792     if is_win32 is None:
793         if ctx.env and 'CC' in ctx.env:
794             env_cc = ctx.env['CC']
795             if not isinstance(env_cc, str):
796                 env_cc = ''.join(env_cc)
797             is_win32 = (env_cc.find('mingw') != -1)
798     if is_win32 is None:
799         is_win32 = False
800     # cache for future checks
801     ctx.env['is_win32'] = is_win32
802     return is_win32
805 def _uc_first(string, ctx):
806     if _target_is_win32(ctx):
807         return string.title()
808     return string