Merge pull request #363 from techee/prj_dialog
[geany-mirror.git] / wscript
blob343b68e0a21d29bb34d50f2dd4ed396eab113752
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         # explicitly define Windows version for older Mingw environments
266         conf.define('WINVER', '0x0501', quote=False)  # for SHGetFolderPathAndSubDirW
267         conf.define('_WIN32_IE', '0x0500', quote=False)  # for SHGFP_TYPE
268     else:
269         conf.env['cshlib_PATTERN'] = '%s.so'
270         # DATADIR and LOCALEDIR are defined by the intltool tool
271         # but they are not added to the environment, so we need to
272         _add_define_to_env(conf, 'DATADIR')
273         _add_define_to_env(conf, 'LOCALEDIR')
274         docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
275         libdir = os.path.join(conf.env['PREFIX'], 'lib')
276         mandir = os.path.join(conf.env['DATADIR'], 'man')
277         _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
278         _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
279         _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
281     conf.define('ENABLE_NLS', 1)
282     conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
283     conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
284     conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
285     conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
286     conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
287     conf.define('PACKAGE', APPNAME, quote=True)
288     conf.define('VERSION', VERSION, quote=True)
289     conf.define('REVISION', revision or '-1', quote=True)
291     conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
293     # no VTE on Windows
294     if is_win32:
295         conf.options.no_vte = True
297     _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
298     _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
299     _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
301     conf.write_config_header('config.h', remove=False)
303     # some more compiler flags
304     conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
305     if conf.env['CC_NAME'] == 'gcc' and '-O' not in ''.join(conf.env['CFLAGS']):
306         conf.env.append_value('CFLAGS', ['-O2'])
307     if revision is not None:
308         conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
309     # Scintilla flags
310     conf.env.append_value('CFLAGS', ['-DGTK'])
311     conf.env.append_value('CXXFLAGS',
312         ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
314     # summary
315     Logs.pprint('BLUE', 'Summary:')
316     conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
317     conf.msg('Using GTK version', gtk_version)
318     conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
319     conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
320     if revision is not None:
321         conf.msg('Compiling Git revision', revision)
324 def options(opt):
325     # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
326     # If anyone wants to add support for building with MSVC, this hack should be removed.
327     c_compiler['win32'] = ['gcc']
328     cxx_compiler['win32'] = ['g++']
330     opt.load('compiler_cc')
331     opt.load('compiler_cxx')
332     opt.load('intltool')
334     # Option
335     opt.add_option('--no-scm', action='store_true', default=False,
336         help='Disable SCM detection [default: No]', dest='no_scm')
337     # Features
338     opt.add_option('--disable-plugins', action='store_true', default=False,
339         help='compile without plugin support [default: No]', dest='no_plugins')
340     opt.add_option('--disable-socket', action='store_true', default=False,
341         help='compile without support to detect a running instance [[default: No]',
342         dest='no_socket')
343     opt.add_option('--disable-vte', action='store_true', default=False,
344         help='compile without support for an embedded virtual terminal [[default: No]',
345         dest='no_vte')
346     opt.add_option('--enable-gtk3', action='store_true', default=False,
347         help='compile with GTK3 support (experimental) [[default: No]',
348         dest='use_gtk3')
349     opt.add_option('--disable-html-docs', action='store_true', default=False,
350         help='do not generate HTML documentation using rst2html [[default: No]',
351         dest='no_html_doc')
352     # Paths
353     opt.add_option('--mandir', type='string', default='',
354         help='man documentation', dest='mandir')
355     opt.add_option('--docdir', type='string', default='',
356         help='documentation root', dest='docdir')
357     opt.add_option('--libdir', type='string', default='',
358         help='object code libraries', dest='libdir')
361 def build(bld):
362     is_win32 = _target_is_win32(bld)
364     if bld.cmd == 'clean':
365         _remove_linguas_file()
366     if bld.cmd in ('install', 'uninstall'):
367         bld.add_post_fun(_post_install)
369     def build_plugin(plugin_name, install=True, uselib_add=[]):
370         if install:
371             instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
372         else:
373             instpath = None
375         bld(
376             features                = ['c', 'cshlib'],
377             source                  = 'plugins/%s.c' % plugin_name,
378             includes                = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
379             defines                 = 'G_LOG_DOMAIN="%s"' % plugin_name,
380             target                  = plugin_name,
381             uselib                  = ['GTK', 'GLIB', 'GMODULE'] + uselib_add,
382             install_path            = instpath)
384     # CTags
385     bld(
386         features        = ['c', 'cstlib'],
387         source          = ctags_sources,
388         name            = 'ctags',
389         target          = 'ctags',
390         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
391         defines         = 'G_LOG_DOMAIN="CTags"',
392         uselib          = ['GLIB'],
393         install_path    = None)  # do not install this library
395     # Tagmanager
396     bld(
397         features        = ['c', 'cstlib'],
398         source          = tagmanager_sources,
399         name            = 'tagmanager',
400         target          = 'tagmanager',
401         includes        = ['.', 'tagmanager', 'tagmanager/ctags'],
402         defines         = ['GEANY_PRIVATE', 'G_LOG_DOMAIN="Tagmanager"'],
403         uselib          = ['GTK', 'GLIB'],
404         install_path    = None)  # do not install this library
406     # MIO
407     bld(
408         features        = ['c', 'cstlib'],
409         source          = mio_sources,
410         name            = 'mio',
411         target          = 'mio',
412         includes        = ['.', 'tagmanager/mio/'],
413         defines         = 'G_LOG_DOMAIN="MIO"',
414         uselib          = ['GTK', 'GLIB'],
415         install_path    = None)  # do not install this library
417     # Scintilla
418     files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
419     scintilla_sources.update(files)
420     bld(
421         features        = ['c', 'cxx', 'cxxstlib'],
422         name            = 'scintilla',
423         target          = 'scintilla',
424         source          = scintilla_sources,
425         includes        = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
426         uselib          = ['GTK', 'GLIB', 'GMODULE', 'M'],
427         install_path    = None)  # do not install this library
429     # Geany
430     if bld.env['HAVE_VTE'] == 1:
431         geany_sources.add('src/vte.c')
432     if is_win32:
433         geany_sources.add('src/win32.c')
434         geany_sources.add('geany_private.rc')
436     bld(
437         features        = ['c', 'cxx', 'cprogram'],
438         name            = 'geany',
439         target          = 'geany',
440         source          = geany_sources,
441         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
442         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
443         uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET', 'M'],
444         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'])
446     # geanyfunctions.h
447     bld(
448         source  = ['plugins/genapi.py', 'src/plugins.c'],
449         name    = 'geanyfunctions.h',
450         before  = ['c', 'cxx'],
451         cwd     = '%s/plugins' % bld.path.abspath(),
452         rule    = '%s genapi.py -q' % sys.executable)
454     # Plugins
455     if bld.env['HAVE_PLUGINS'] == 1:
456         build_plugin('classbuilder')
457         build_plugin('demoplugin', False)
458         build_plugin('export', uselib_add=['M'])
459         build_plugin('filebrowser')
460         build_plugin('htmlchars')
461         build_plugin('saveactions')
462         build_plugin('splitwindow')
464     # Translations
465     if bld.env['INTLTOOL']:
466         bld(
467             features        = ['linguas', 'intltool_po'],
468             podir           = 'po',
469             install_path    = '${LOCALEDIR}',
470             appname         = 'geany')
472     # HTML documentation (build if it is not part of the tree already, as it is required for install)
473     html_doc_filename = os.path.join(bld.out_dir, 'doc', 'geany.html')
474     if bld.env['RST2HTML']:
475         rst2html = bld.env['RST2HTML']
476         bld(
477             source  = ['doc/geany.txt'],
478             deps    = ['doc/geany.css'],
479             target  = 'doc/geany.html',
480             name    = 'geany.html',
481             cwd     = os.path.join(bld.path.abspath(), 'doc'),
482             rule    = '%s  -stg --stylesheet=geany.css geany.txt %s' % (rst2html, html_doc_filename))
484     # geany.pc
485     if is_win32:
486         # replace backward slashes by forward slashes as they could be interepreted as escape
487         # characters
488         geany_pc_prefix = bld.env['PREFIX'].replace('\\', '/')
489     else:
490         geany_pc_prefix = bld.env['PREFIX']
491     bld(
492         source          = 'geany.pc.in',
493         dct             = {'VERSION': VERSION,
494                            'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
495                                 (bld.env['gtk_package_name'],
496                                  bld.env['minimum_gtk_version'],
497                                  MINIMUM_GLIB_VERSION),
498                            'prefix': geany_pc_prefix,
499                            'exec_prefix': '${prefix}',
500                            'libdir': '${exec_prefix}/lib',
501                            'includedir': '${prefix}/include',
502                            'datarootdir': '${prefix}/share',
503                            'datadir': '${datarootdir}',
504                            'localedir': '${datarootdir}/locale'})
506     if not is_win32:
507         # geany.desktop
508         if bld.env['INTLTOOL']:
509             bld(
510                 features        = 'intltool_in',
511                 source          = 'geany.desktop.in',
512                 flags           = ['-d', '-q', '-u', '-c'],
513                 install_path    = '${DATADIR}/applications')
515         # geany.1
516         bld(
517             features        = 'subst',
518             source          = 'doc/geany.1.in',
519             target          = 'geany.1',
520             dct             = {'VERSION': VERSION,
521                                 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
522             install_path    = '${MANDIR}/man1')
524         # geany.spec
525         bld(
526             features        = 'subst',
527             source          = 'geany.spec.in',
528             target          = 'geany.spec',
529             install_path    = None,
530             dct             = {'VERSION': VERSION})
532         # Doxyfile
533         bld(
534             features        = 'subst',
535             source          = 'doc/Doxyfile.in',
536             target          = 'doc/Doxyfile',
537             install_path    = None,
538             dct             = {'VERSION': VERSION,
539                                'top_builddir': bld.out_dir,
540                                'top_srcdir': bld.top_dir,})
542     ###
543     # Install files
544     ###
545     # Headers
546     bld.install_files('${PREFIX}/include/geany', '''
547         src/app.h src/document.h src/editor.h src/encodings.h src/filetypes.h src/geany.h
548         src/highlighting.h src/keybindings.h src/msgwindow.h src/plugindata.h
549         src/prefs.h src/project.h src/search.h src/stash.h src/support.h
550         src/templates.h src/toolbar.h src/ui_utils.h src/utils.h src/build.h src/gtkcompat.h
551         plugins/geanyplugin.h plugins/geanyfunctions.h''')
552     bld.install_files('${PREFIX}/include/geany/scintilla', '''
553         scintilla/include/SciLexer.h scintilla/include/Scintilla.h
554         scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
555     bld.install_files('${PREFIX}/include/geany/tagmanager', '''
556         tagmanager/src/tm_source_file.h
557         tagmanager/src/tm_tag.h
558         tagmanager/src/tm_tagmanager.h tagmanager/src/tm_work_object.h
559         tagmanager/src/tm_workspace.h ''')
560     # Docs
561     base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
562     ext = '.txt' if is_win32 else ''
563     for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
564         basename = _uc_first(filename, bld)
565         destination_filename = '%s%s' % (basename, ext)
566         destination = os.path.join(base_dir, destination_filename)
567         bld.install_as(destination, filename)
569     # install HTML documentation only if it exists, i.e. it was built before
570     # local_html_doc_filename supports installing HTML doc from in-tree geany.html if it exists
571     local_html_doc_filename = os.path.join(bld.path.abspath(), 'doc', 'geany.html')
572     if os.path.exists(html_doc_filename) or os.path.exists(local_html_doc_filename):
573         html_dir = '' if is_win32 else 'html/'
574         html_name = 'Manual.html' if is_win32 else 'index.html'
575         start_dir = bld.path.find_dir('doc/images')
576         bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
577         bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
579     bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
580     bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
581     if is_win32:
582         bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
583         bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
584     # Data
585     data_dir = '' if is_win32 else 'geany'
586     start_dir = bld.path.find_dir('data')
587     bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
588     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
589     bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
590     bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
591     bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
592     bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
593     if bld.env['use_gtk3']:
594         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
595     else:
596         bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
598     start_dir = bld.path.find_dir('data/colorschemes')
599     template_dest = '${DATADIR}/%s/colorschemes' % data_dir
600     bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
601     start_dir = bld.path.find_dir('data/templates')
602     template_dest = '${DATADIR}/%s/templates' % data_dir
603     bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
604     # Icons
605     for dest, srcs in geany_icons.items():
606         dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
607         bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
608     # install theme indexes on Windows
609     if is_win32:
610         for dest, srcs in geany_icons_indexes.items():
611             bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
614 def distclean(ctx):
615     Scripting.distclean(ctx)
616     _remove_linguas_file()
619 def _remove_linguas_file():
620     # remove LINGUAS file as well
621     try:
622         os.unlink(LINGUAS_FILE)
623     except OSError:
624         pass
627 @feature('linguas')
628 @before_method('apply_intltool_po')
629 def write_linguas_file(self):
630     if os.path.exists(LINGUAS_FILE):
631         return
632     linguas = ''
633     if 'LINGUAS' in self.env:
634         files = self.env['LINGUAS']
635         for po_filename in files.split(' '):
636             if os.path.exists('po/%s.po' % po_filename):
637                 linguas += '%s ' % po_filename
638     else:
639         files = os.listdir('%s/po' % self.path.abspath())
640         files.sort()
641         for filename in files:
642             if filename.endswith('.po'):
643                 linguas += '%s ' % filename[:-3]
644     file_h = open(LINGUAS_FILE, 'w')
645     file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
646     file_h.close()
649 def _post_install(ctx):
650     is_win32 = _target_is_win32(ctx)
651     if is_win32:
652         return
653     for d in 'hicolor', 'Tango':
654         theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
655         icon_cache_updated = False
656         if not ctx.options.destdir:
657             ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
658             Logs.pprint('GREEN', 'GTK icon cache updated.')
659             icon_cache_updated = True
660         if not icon_cache_updated:
661             Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
662             Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
665 def updatepo(ctx):
666     """update the message catalogs for internationalization"""
667     potfile = '%s.pot' % APPNAME
668     os.chdir('%s/po' % top)
669     try:
670         try:
671             old_size = os.stat(potfile).st_size
672         except OSError:
673             old_size = 0
674         ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
675         size_new = os.stat(potfile).st_size
676         if size_new != old_size:
677             Logs.pprint('CYAN', 'Updated POT file.')
678             Logs.pprint('CYAN', 'Updating translations')
679             ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
680             if ret != 0:
681                 Logs.pprint('RED', 'Updating translations failed')
682         else:
683             Logs.pprint('CYAN', 'POT file is up to date.')
684     except OSError:
685         Logs.pprint('RED', 'Failed to generate pot file.')
688 def apidoc(ctx):
689     """generate API reference documentation"""
690     ctx = BuildContext()  # create our own context to have ctx.top_dir
691     basedir = ctx.top_dir
692     doxygen = _find_program(ctx, 'doxygen')
693     doxyfile = '%s/doc/Doxyfile' % ctx.out_dir
694     Logs.pprint('CYAN', 'Generating API documentation')
695     ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
696     if ret != 0:
697         raise WafError('Generating API documentation failed')
700 def hackingdoc(ctx):
701     """generate HACKING documentation"""
702     ctx = BuildContext()  # create our own context to have ctx.top_dir
703     Logs.pprint('CYAN', 'Generating HACKING documentation')
704     cmd = _find_rst2html(ctx)
705     hacking_file = os.path.join(ctx.top_dir, 'HACKING')
706     hacking_html_file = os.path.join(ctx.top_dir, 'doc', 'hacking.html')
707     stylesheet = os.path.join(ctx.top_dir, 'doc', 'geany.css')
708     ret = ctx.exec_command('%s  -stg --stylesheet=%s %s %s' % (
709         cmd, stylesheet, hacking_file, hacking_html_file))
710     if ret != 0:
711         raise WafError('Generating HACKING documentation failed')
714 def _find_program(ctx, cmd, **kw):
715     def noop(*args):
716         pass
718     if ctx is None or not isinstance(ctx, ConfigurationContext):
719         ctx = ConfigurationContext()
720         ctx.to_log = noop
721         ctx.msg = noop
722     return ctx.find_program(cmd, **kw)
725 def _find_rst2html(ctx):
726     cmds = ['rst2html', 'rst2html2']
727     for command in cmds:
728         cmd = _find_program(ctx, command, mandatory=False, exts=',.py')
729         if cmd:
730             break
731     if not cmd:
732         raise WafError(
733             'rst2html.py could not be found. Please install the Python docutils package.')
734     return cmd
737 def _add_define_to_env(conf, key):
738     value = conf.get_define(key)
739     # strip quotes
740     value = value.replace('"', '')
741     conf.env[key] = value
744 def _add_to_env_and_define(conf, key, value, quote=False):
745     conf.define(key, value, quote)
746     conf.env[key] = value
749 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
750     value = default_value
751     if opt_value:
752         if isinstance(opt_value, bool):
753             opt_value = 1
754         value = opt_value
756     if value is not None:
757         _add_to_env_and_define(conf, define_name, value, quote)
758     else:
759         conf.undefine(define_name)
762 def _get_git_rev(conf):
763     if conf.options.no_scm:
764         return
766     if not os.path.isdir('.git'):
767         return
769     try:
770         cmd = 'git rev-parse --short --revs-only HEAD'
771         revision = conf.cmd_and_log(cmd).strip()
772     except WafError:
773         return None
774     else:
775         return revision
778 def _load_intltool_if_available(conf):
779     try:
780         conf.load('intltool')
781         if 'LINGUAS' in os.environ:
782             conf.env['LINGUAS'] = os.environ['LINGUAS']
783     except WafError:
784         # on Windows, we don't hard depend on intltool, on all other platforms raise an error
785         if not _target_is_win32(conf):
786             raise
789 def _target_is_win32(ctx):
790     if 'is_win32' in ctx.env:
791         # cached
792         return ctx.env['is_win32']
793     is_win32 = None
794     if sys.platform == 'win32':
795         is_win32 = True
796     if is_win32 is None:
797         if ctx.env and 'CC' in ctx.env:
798             env_cc = ctx.env['CC']
799             if not isinstance(env_cc, str):
800                 env_cc = ''.join(env_cc)
801             is_win32 = (env_cc.find('mingw') != -1)
802     if is_win32 is None:
803         is_win32 = False
804     # cache for future checks
805     ctx.env['is_win32'] = is_win32
806     return is_win32
809 def _uc_first(string, ctx):
810     if _target_is_win32(ctx):
811         return string.title()
812     return string