waf: The GEANY_*_SYMBOL flags also need to be defined for C++
[geany-mirror.git] / wscript
blob49bdd8912e8c7ed677aa6024356ea5d41d41cb5b
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     conf.check_cc(header_name='fcntl.h', mandatory=False)
190     conf.check_cc(header_name='fnmatch.h', mandatory=False)
191     conf.check_cc(header_name='glob.h', mandatory=False)
192     conf.check_cc(header_name='sys/time.h', mandatory=False)
193     conf.check_cc(header_name='sys/types.h', mandatory=False)
194     conf.check_cc(header_name='sys/stat.h', mandatory=False)
195     conf.define('HAVE_STDLIB_H', 1)  # are there systems without stdlib.h?
196     conf.define('STDC_HEADERS', 1)  # an optimistic guess ;-)
197     _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1)  # needed for CTags
199     conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
200     conf.check_cc(function_name='fnmatch', header_name='fnmatch.h', mandatory=False)
201     conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
202     conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
203     conf.check_cc(function_name='strstr', header_name='string.h')
205     conf.check_cc(function_name='pow', header_name='math.h', lib='m', uselib_store='M')
207     # check sunOS socket support
208     if Options.platform == 'sunos':
209         conf.check_cc(function_name='socket', lib='socket',
210                       header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
212     # check for cxx after the header and function checks have been done to ensure they are
213     # checked with cc not cxx
214     conf.load('compiler_cxx')
215     if is_win32:
216         conf.load('winres')
217     _load_intltool_if_available(conf)
219     # GTK / GIO version check
220     gtk_package_name = 'gtk+-3.0' if conf.options.use_gtk3 else 'gtk+-2.0'
221     minimum_gtk_version = MINIMUM_GTK3_VERSION if conf.options.use_gtk3 else MINIMUM_GTK_VERSION
222     conf.check_cfg(package=gtk_package_name, atleast_version=minimum_gtk_version, uselib_store='GTK',
223         mandatory=True, args='--cflags --libs')
224     conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
225         mandatory=True, args='--cflags --libs')
226     conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
227         mandatory=True, args='--cflags --libs')
228     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
229     gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
230     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
231     if conf.options.enable_mac_integration:
232         pkgname = 'gtk-mac-integration-gtk3' if conf.options.use_gtk3 else 'gtk-mac-integration-gtk2'
233         conf.check_cfg(package=pkgname, uselib_store='MAC_INTEGRATION', 
234             mandatory=True, args='--cflags --libs')
235     # remember GTK version for the build step
236     conf.env['gtk_package_name'] = gtk_package_name
237     conf.env['minimum_gtk_version'] = minimum_gtk_version
238     conf.env['use_gtk3'] = conf.options.use_gtk3
240     revision = _get_git_rev(conf)
242     # rst2html for the HTML manual
243     if not conf.options.no_html_doc and revision is not None:
244         try:
245             conf.env['RST2HTML'] = _find_rst2html(conf)
246         except WafError:
247             error_msg = '''Documentation enabled but rst2html not found.
248 You can explicitly disable building of the HTML manual with --disable-html-docs,
249 but you then may not have a local copy of the HTML manual.'''
250             raise WafError(error_msg)
252     # Windows specials
253     if is_win32:
254         if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
255             # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
256             new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
257             _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
258             _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
259         _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
260         _add_to_env_and_define(conf, 'LIBDIR', '%s/lib' % conf.env['PREFIX'], quote=True)
261         conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
262         # overwrite LOCALEDIR to install message catalogues properly
263         conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share', 'locale')
264         # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
265         conf.undefine('DATADIR')
266         conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
267         conf.env.append_value('LINKFLAGS_cprogram', [
268             '-mwindows',
269             '-static-libgcc',
270             '-static-libstdc++'])
271         conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32'])
272         # explicitly define Windows version for older Mingw environments
273         conf.define('WINVER', '0x0501', quote=False)  # for SHGetFolderPathAndSubDirW
274         conf.define('_WIN32_IE', '0x0500', quote=False)  # for SHGFP_TYPE
275     else:
276         conf.env['cshlib_PATTERN'] = '%s.so'
277         # DATADIR and LOCALEDIR are defined by the intltool tool
278         # but they are not added to the environment, so we need to
279         _add_define_to_env(conf, 'DATADIR')
280         _add_define_to_env(conf, 'LOCALEDIR')
281         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
282         libdir = os.path.join(conf.env['PREFIX'], 'lib')
283         mandir = os.path.join(conf.env['DATADIR'], 'man')
284         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
285         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
286         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
288     conf.define('ENABLE_NLS', 1)
289     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
290     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
291     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
292     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
293     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
294     conf.define('PACKAGE', APPNAME, quote=True)
295     conf.define('VERSION', VERSION, quote=True)
296     conf.define('REVISION', revision or '-1', quote=True)
298     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
300     # no VTE on Windows
301     if is_win32:
302         conf.options.no_vte = True
304     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
305     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
306     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
308     conf.write_config_header('config.h', remove=False)
310     # GEANY_EXPORT_SYMBOL and GEANY_API_SYMBOL
311     if is_win32:
312         geany_symbol_flags = ['-DGEANY_EXPORT_SYMBOL=__declspec(dllexport)']
313     # FIXME: check for -fvisibility and the __attribute__((visibility)), or
314     #        at least for GCC >= 4
315     elif conf.env['CC_NAME'] == 'gcc':
316         geany_symbol_flags = ['-fvisibility=hidden',
317                               '-DGEANY_EXPORT_SYMBOL=__attribute__((visibility("default")))']
318     else:  # unknown, define to nothing
319         geany_symbol_flags = ['-DGEANY_EXPORT_SYMBOL=']
320     geany_symbol_flags.append('-DGEANY_API_SYMBOL=GEANY_EXPORT_SYMBOL')
321     conf.env.append_value('CFLAGS', geany_symbol_flags)
322     conf.env.append_value('CXXFLAGS', geany_symbol_flags)
324     # some more compiler flags
325     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
326     if conf.env['CC_NAME'] == 'gcc' and '-O' not in ''.join(conf.env['CFLAGS']):
327         conf.env.append_value('CFLAGS', ['-O2'])
328     if revision is not None:
329         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
330     # Scintilla flags
331     conf.env.append_value('CFLAGS', ['-DGTK'])
332     conf.env.append_value('CXXFLAGS',
333         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
335     # summary
336     Logs.pprint('BLUE', 'Summary:')
337     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
338     conf.msg('Using GTK version', gtk_version)
339     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
340     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
341     if revision is not None:
342         conf.msg('Compiling Git revision', revision)
345 def options(opt):
346     # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
347     # If anyone wants to add support for building with MSVC, this hack should be removed.
348     c_compiler['win32'] = ['gcc']
349     cxx_compiler['win32'] = ['g++']
351     opt.load('compiler_cc')
352     opt.load('compiler_cxx')
353     opt.load('intltool')
355     # Option
356     opt.add_option('--no-scm', action='store_true', default=False,
357         help='Disable SCM detection [default: No]', dest='no_scm')
358     # Features
359     opt.add_option('--disable-plugins', action='store_true', default=False,
360         help='compile without plugin support [default: No]', dest='no_plugins')
361     opt.add_option('--disable-socket', action='store_true', default=False,
362         help='compile without support to detect a running instance [[default: No]',
363         dest='no_socket')
364     opt.add_option('--disable-vte', action='store_true', default=False,
365         help='compile without support for an embedded virtual terminal [[default: No]',
366         dest='no_vte')
367     opt.add_option('--enable-gtk3', action='store_true', default=False,
368         help='compile with GTK3 support (experimental) [[default: No]',
369         dest='use_gtk3')
370     opt.add_option('--enable-mac-integration', action='store_true', default=False,
371         help='use gtk-mac-integration to enable improved OS X integration [[default: No]',
372         dest='enable_mac_integration')
373     opt.add_option('--disable-html-docs', action='store_true', default=False,
374         help='do not generate HTML documentation using rst2html [[default: No]',
375         dest='no_html_doc')
376     # Paths
377     opt.add_option('--mandir', type='string', default='',
378         help='man documentation', dest='mandir')
379     opt.add_option('--docdir', type='string', default='',
380         help='documentation root', dest='docdir')
381     opt.add_option('--libdir', type='string', default='',
382         help='object code libraries', dest='libdir')
385 def build(bld):
386     is_win32 = _target_is_win32(bld)
388     if bld.cmd == 'clean':
389         _remove_linguas_file()
390     if bld.cmd in ('install', 'uninstall'):
391         bld.add_post_fun(_post_install)
393     def build_plugin(plugin_name, install=True, uselib_add=[]):
394         if install:
395             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
396         else:
397             instpath = None
399         bld(
400             features                = ['c', 'cshlib'],
401             source                  = 'plugins/%s.c' % plugin_name,
402             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
403             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
404             target                  = plugin_name,
405             uselib                  = ['GTK', 'GLIB', 'GMODULE'] + uselib_add,
406             use                     = ['geany'],
407             install_path            = instpath)
409     # CTags
410     bld(
411         features        = ['c', 'cstlib'],
412         source          = ctags_sources,
413         name            = 'ctags',
414         target          = 'ctags',
415         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
416         defines         = 'G_LOG_DOMAIN="CTags"',
417         uselib          = ['GLIB'],
418         install_path    = None)  # do not install this library
420     # Tagmanager
421     bld(
422         features        = ['c', 'cstlib'],
423         source          = tagmanager_sources,
424         name            = 'tagmanager',
425         target          = 'tagmanager',
426         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
427         defines         = ['GEANY_PRIVATE', 'G_LOG_DOMAIN="Tagmanager"'],
428         uselib          = ['GTK', 'GLIB'],
429         install_path    = None)  # do not install this library
431     # MIO
432     bld(
433         features        = ['c', 'cstlib'],
434         source          = mio_sources,
435         name            = 'mio',
436         target          = 'mio',
437         includes        = ['.', 'tagmanager/mio/'],
438         defines         = 'G_LOG_DOMAIN="MIO"',
439         uselib          = ['GTK', 'GLIB'],
440         install_path    = None)  # do not install this library
442     # Scintilla
443     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
444     scintilla_sources.update([file.path_from(bld.srcnode) for file in files])
445     bld(
446         features        = ['c', 'cxx', 'cxxstlib'],
447         name            = 'scintilla',
448         target          = 'scintilla',
449         source          = scintilla_sources,
450         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
451         uselib          = ['GTK', 'GLIB', 'GMODULE', 'M'],
452         install_path    = None)  # do not install this library
454     # Geany
455     if bld.env['HAVE_VTE'] == 1:
456         geany_sources.add('src/vte.c')
457     if is_win32:
458         geany_sources.add('src/win32.c')
459         geany_sources.add('geany_private.rc')
461     base_uselibs = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'MAC_INTEGRATION', 'SUNOS_SOCKET', 'M']
462     # libgeany
463     bld(
464         features        = ['c', 'cxx', 'cshlib'],
465         name            = 'geany',
466         target          = 'geany',
467         source          = geany_sources,
468         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
469         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
470         uselib          = base_uselibs,
471         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'],
472         vnum            = GEANY_LIB_VERSION)
474     # geany executable
475     bld(
476         features        = ['c', 'cxx', 'cprogram'],
477         name            = 'geany_bin',
478         target          = 'geany',
479         source          = ['src/main.c'],
480         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
481         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
482         uselib          = base_uselibs,
483         use             = ['geany'])
485     # Plugins
486     if bld.env['HAVE_PLUGINS'] == 1:
487         build_plugin('classbuilder')
488         build_plugin('demoplugin', False)
489         build_plugin('export', uselib_add=['M'])
490         build_plugin('filebrowser')
491         build_plugin('htmlchars')
492         build_plugin('saveactions')
493         build_plugin('splitwindow')
495     # Translations
496     if bld.env['INTLTOOL']:
497         bld(
498             features        = ['linguas', 'intltool_po'],
499             podir           = 'po',
500             install_path    = '${LOCALEDIR}',
501             appname         = 'geany')
503     # HTML documentation (build if it is not part of the tree already, as it is required for install)
504     html_doc_filename = os.path.join(bld.out_dir, 'doc', 'geany.html')
505     if bld.env['RST2HTML']:
506         rst2html = bld.env['RST2HTML']
507         bld(
508             source  = ['doc/geany.txt'],
509             deps    = ['doc/geany.css'],
510             target  = 'doc/geany.html',
511             name    = 'geany.html',
512             cwd     = os.path.join(bld.path.abspath(), 'doc'),
513             rule    = '%s  -stg --stylesheet=geany.css geany.txt %s' % (rst2html, html_doc_filename))
515     # geany.pc
516     if is_win32:
517         # replace backward slashes by forward slashes as they could be interepreted as escape
518         # characters
519         geany_pc_prefix = bld.env['PREFIX'].replace('\\', '/')
520     else:
521         geany_pc_prefix = bld.env['PREFIX']
522     bld(
523         source          = 'geany.pc.in',
524         dct             = {'VERSION': VERSION,
525                            'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
526                                 (bld.env['gtk_package_name'],
527                                  bld.env['minimum_gtk_version'],
528                                  MINIMUM_GLIB_VERSION),
529                            'prefix': geany_pc_prefix,
530                            'exec_prefix': '${prefix}',
531                            'libdir': '${exec_prefix}/lib',
532                            'includedir': '${prefix}/include',
533                            'datarootdir': '${prefix}/share',
534                            'datadir': '${datarootdir}',
535                            'localedir': '${datarootdir}/locale'})
537     if not is_win32:
538         # geany.desktop
539         if bld.env['INTLTOOL']:
540             bld(
541                 features        = 'intltool_in',
542                 source          = 'geany.desktop.in',
543                 flags           = ['-d', '-q', '-u', '-c'],
544                 install_path    = '${DATADIR}/applications')
546         # geany.1
547         bld(
548             features        = 'subst',
549             source          = 'doc/geany.1.in',
550             target          = 'geany.1',
551             dct             = {'VERSION': VERSION,
552                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
553             install_path    = '${MANDIR}/man1')
555         # geany.spec
556         bld(
557             features        = 'subst',
558             source          = 'geany.spec.in',
559             target          = 'geany.spec',
560             install_path    = None,
561             dct             = {'VERSION': VERSION})
563         # Doxyfile
564         bld(
565             features        = 'subst',
566             source          = 'doc/Doxyfile.in',
567             target          = 'doc/Doxyfile',
568             install_path    = None,
569             dct             = {'VERSION': VERSION,
570                                'top_builddir': bld.out_dir,
571                                'top_srcdir': bld.top_dir,})
573     ###
574     # Install files
575     ###
576     # Headers
577     bld.install_files('${PREFIX}/include/geany', '''
578         src/app.h src/document.h src/editor.h src/encodings.h src/filetypes.h src/geany.h
579         src/highlighting.h src/keybindings.h src/msgwindow.h src/plugindata.h
580         src/prefs.h src/project.h src/search.h src/stash.h src/support.h
581         src/templates.h src/toolbar.h src/ui_utils.h src/utils.h src/build.h src/gtkcompat.h
582         plugins/geanyplugin.h plugins/geanyfunctions.h''')
583     bld.install_files('${PREFIX}/include/geany/scintilla', '''
584         scintilla/include/SciLexer.h scintilla/include/Scintilla.h
585         scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
586     bld.install_files('${PREFIX}/include/geany/tagmanager', '''
587         tagmanager/src/tm_source_file.h
588         tagmanager/src/tm_tag.h
589         tagmanager/src/tm_tagmanager.h
590         tagmanager/src/tm_workspace.h ''')
591     # Docs
592     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
593     ext = '.txt' if is_win32 else ''
594     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
595         basename = _uc_first(filename, bld)
596         destination_filename = '%s%s' % (basename, ext)
597         destination = os.path.join(base_dir, destination_filename)
598         bld.install_as(destination, filename)
600     # install HTML documentation only if it exists, i.e. it was built before
601     # local_html_doc_filename supports installing HTML doc from in-tree geany.html if it exists
602     local_html_doc_filename = os.path.join(bld.path.abspath(), 'doc', 'geany.html')
603     if os.path.exists(html_doc_filename) or os.path.exists(local_html_doc_filename):
604         html_dir = '' if is_win32 else 'html/'
605         html_name = 'Manual.html' if is_win32 else 'index.html'
606         start_dir = bld.path.find_dir('doc/images')
607         bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
608         bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
610     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
611     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
612     if is_win32:
613         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
614         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
615     # Data
616     data_dir = '' if is_win32 else 'geany'
617     start_dir = bld.path.find_dir('data')
618     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
619     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
620     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
621     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
622     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
623     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
624     if bld.env['use_gtk3']:
625         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
626     else:
627         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
629     start_dir = bld.path.find_dir('data/colorschemes')
630     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
631     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
632     start_dir = bld.path.find_dir('data/templates')
633     template_dest = '${DATADIR}/%s/templates' % data_dir
634     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
635     # Icons
636     for dest, srcs in geany_icons.items():
637         dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
638         bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
639     # install theme indexes on Windows
640     if is_win32:
641         for dest, srcs in geany_icons_indexes.items():
642             bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
645 def distclean(ctx):
646     Scripting.distclean(ctx)
647     _remove_linguas_file()
650 def _remove_linguas_file():
651     # remove LINGUAS file as well
652     try:
653         os.unlink(LINGUAS_FILE)
654     except OSError:
655         pass
658 @feature('linguas')
659 @before_method('apply_intltool_po')
660 def write_linguas_file(self):
661     if os.path.exists(LINGUAS_FILE):
662         return
663     linguas = ''
664     if 'LINGUAS' in self.env:
665         files = self.env['LINGUAS']
666         for po_filename in files.split(' '):
667             if os.path.exists('po/%s.po' % po_filename):
668                 linguas += '%s ' % po_filename
669     else:
670         files = os.listdir('%s/po' % self.path.abspath())
671         files.sort()
672         for filename in files:
673             if filename.endswith('.po'):
674                 linguas += '%s ' % filename[:-3]
675     file_h = open(LINGUAS_FILE, 'w')
676     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
677     file_h.close()
680 def _post_install(ctx):
681     is_win32 = _target_is_win32(ctx)
682     if is_win32:
683         return
684     for d in 'hicolor', 'Tango':
685         theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
686         icon_cache_updated = False
687         if not ctx.options.destdir:
688             ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
689             Logs.pprint('GREEN', 'GTK icon cache updated.')
690             icon_cache_updated = True
691         if not icon_cache_updated:
692             Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
693             Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
696 def updatepo(ctx):
697     """update the message catalogs for internationalization"""
698     potfile = '%s.pot' % APPNAME
699     os.chdir('%s/po' % top)
700     try:
701         try:
702             old_size = os.stat(potfile).st_size
703         except OSError:
704             old_size = 0
705         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
706         size_new = os.stat(potfile).st_size
707         if size_new != old_size:
708             Logs.pprint('CYAN', 'Updated POT file.')
709             Logs.pprint('CYAN', 'Updating translations')
710             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
711             if ret != 0:
712                 Logs.pprint('RED', 'Updating translations failed')
713         else:
714             Logs.pprint('CYAN', 'POT file is up to date.')
715     except OSError:
716         Logs.pprint('RED', 'Failed to generate pot file.')
719 def apidoc(ctx):
720     """generate API reference documentation"""
721     ctx = BuildContext()  # create our own context to have ctx.top_dir
722     basedir = ctx.top_dir
723     doxygen = _find_program(ctx, 'doxygen')
724     doxyfile = '%s/doc/Doxyfile' % ctx.out_dir
725     Logs.pprint('CYAN', 'Generating API documentation')
726     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
727     if ret != 0:
728         raise WafError('Generating API documentation failed')
731 def hackingdoc(ctx):
732     """generate HACKING documentation"""
733     ctx = BuildContext()  # create our own context to have ctx.top_dir
734     Logs.pprint('CYAN', 'Generating HACKING documentation')
735     cmd = _find_rst2html(ctx)
736     hacking_file = os.path.join(ctx.top_dir, 'HACKING')
737     hacking_html_file = os.path.join(ctx.top_dir, 'doc', 'hacking.html')
738     stylesheet = os.path.join(ctx.top_dir, 'doc', 'geany.css')
739     ret = ctx.exec_command('%s  -stg --stylesheet=%s %s %s' % (
740         cmd, stylesheet, hacking_file, hacking_html_file))
741     if ret != 0:
742         raise WafError('Generating HACKING documentation failed')
745 def _find_program(ctx, cmd, **kw):
746     def noop(*args):
747         pass
749     if ctx is None or not isinstance(ctx, ConfigurationContext):
750         ctx = ConfigurationContext()
751         ctx.to_log = noop
752         ctx.msg = noop
753     return ctx.find_program(cmd, **kw)
756 def _find_rst2html(ctx):
757     cmds = ['rst2html', 'rst2html2']
758     for command in cmds:
759         cmd = _find_program(ctx, command, mandatory=False, exts=',.py')
760         if cmd:
761             break
762     if not cmd:
763         raise WafError(
764             'rst2html.py could not be found. Please install the Python docutils package.')
765     return cmd
768 def _add_define_to_env(conf, key):
769     value = conf.get_define(key)
770     # strip quotes
771     value = value.replace('"', '')
772     conf.env[key] = value
775 def _add_to_env_and_define(conf, key, value, quote=False):
776     conf.define(key, value, quote)
777     conf.env[key] = value
780 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
781     value = default_value
782     if opt_value:
783         if isinstance(opt_value, bool):
784             opt_value = 1
785         value = opt_value
787     if value is not None:
788         _add_to_env_and_define(conf, define_name, value, quote)
789     else:
790         conf.undefine(define_name)
793 def _get_git_rev(conf):
794     if conf.options.no_scm:
795         return
797     if not os.path.isdir('.git'):
798         return
800     try:
801         cmd = 'git rev-parse --short --revs-only HEAD'
802         revision = conf.cmd_and_log(cmd).strip()
803     except WafError:
804         return None
805     else:
806         return revision
809 def _load_intltool_if_available(conf):
810     try:
811         conf.load('intltool')
812         if 'LINGUAS' in os.environ:
813             conf.env['LINGUAS'] = os.environ['LINGUAS']
814     except WafError:
815         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
816         if not _target_is_win32(conf):
817             raise
820 def _target_is_win32(ctx):
821     if 'is_win32' in ctx.env:
822         # cached
823         return ctx.env['is_win32']
824     is_win32 = None
825     if sys.platform == 'win32':
826         is_win32 = True
827     if is_win32 is None:
828         if ctx.env and 'CC' in ctx.env:
829             env_cc = ctx.env['CC']
830             if not isinstance(env_cc, str):
831                 env_cc = ''.join(env_cc)
832             is_win32 = (env_cc.find('mingw') != -1)
833     if is_win32 is None:
834         is_win32 = False
835     # cache for future checks
836     ctx.env['is_win32'] = is_win32
837     return is_win32
840 def _uc_first(string, ctx):
841     if _target_is_win32(ctx):
842         return string.title()
843     return string