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