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.
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)
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).
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
56 LINGUAS_FILE = os.path.join('po', 'LINGUAS')
57 MINIMUM_GTK_VERSION = '2.24.0'
58 MINIMUM_GTK3_VERSION = '3.0.0'
59 MINIMUM_GLIB_VERSION = '2.28.0'
61 GEANY_LIB_VERSION = '0.0.0'
66 mio_sources = set(['tagmanager/mio/mio.c'])
69 'tagmanager/ctags/abaqus.c',
70 'tagmanager/ctags/args.c',
71 'tagmanager/ctags/abc.c',
72 'tagmanager/ctags/actionscript.c',
73 'tagmanager/ctags/asciidoc.c',
74 'tagmanager/ctags/asm.c',
75 'tagmanager/ctags/basic.c',
76 'tagmanager/ctags/c.c',
77 'tagmanager/ctags/cobol.c',
78 'tagmanager/ctags/conf.c',
79 'tagmanager/ctags/css.c',
80 'tagmanager/ctags/ctags.c',
81 'tagmanager/ctags/diff.c',
82 'tagmanager/ctags/docbook.c',
83 'tagmanager/ctags/erlang.c',
84 'tagmanager/ctags/entry.c',
85 'tagmanager/ctags/fortran.c',
86 'tagmanager/ctags/get.c',
87 'tagmanager/ctags/go.c',
88 'tagmanager/ctags/haskell.c',
89 'tagmanager/ctags/haxe.c',
90 'tagmanager/ctags/html.c',
91 'tagmanager/ctags/js.c',
92 'tagmanager/ctags/json.c',
93 'tagmanager/ctags/keyword.c',
94 'tagmanager/ctags/latex.c',
95 'tagmanager/ctags/lregex.c',
96 'tagmanager/ctags/lua.c',
97 'tagmanager/ctags/make.c',
98 'tagmanager/ctags/markdown.c',
99 'tagmanager/ctags/matlab.c',
100 'tagmanager/ctags/nsis.c',
101 'tagmanager/ctags/nestlevel.c',
102 'tagmanager/ctags/objc.c',
103 'tagmanager/ctags/options.c',
104 'tagmanager/ctags/parse.c',
105 'tagmanager/ctags/pascal.c',
106 'tagmanager/ctags/r.c',
107 'tagmanager/ctags/perl.c',
108 'tagmanager/ctags/php.c',
109 'tagmanager/ctags/python.c',
110 'tagmanager/ctags/read.c',
111 'tagmanager/ctags/rest.c',
112 'tagmanager/ctags/ruby.c',
113 'tagmanager/ctags/rust.c',
114 'tagmanager/ctags/sh.c',
115 'tagmanager/ctags/sort.c',
116 'tagmanager/ctags/sql.c',
117 'tagmanager/ctags/strlist.c',
118 'tagmanager/ctags/txt2tags.c',
119 'tagmanager/ctags/tcl.c',
120 'tagmanager/ctags/vhdl.c',
121 'tagmanager/ctags/verilog.c',
122 'tagmanager/ctags/vstring.c'])
124 tagmanager_sources = set([
125 'tagmanager/src/tm_source_file.c',
126 'tagmanager/src/tm_tag.c',
127 'tagmanager/src/tm_workspace.c'])
129 scintilla_sources = set(['scintilla/gtk/scintilla-marshal.c'])
131 geany_sources = set([
132 'src/about.c', 'src/build.c', 'src/callbacks.c', 'src/dialogs.c', 'src/document.c',
133 'src/editor.c', 'src/encodings.c', 'src/filetypes.c', 'src/geanyentryaction.c',
134 'src/geanymenubuttonaction.c', 'src/geanyobject.c', 'src/geanywraplabel.c',
135 'src/highlighting.c', 'src/keybindings.c',
136 'src/keyfile.c', 'src/log.c', 'src/libmain.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c', 'src/osx.c',
137 'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
138 'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
140 'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
141 'src/ui_utils.c', 'src/utils.c'])
143 geany_bin_sources = set(['src/main.c'])
146 'hicolor/16x16/apps': ['16x16/classviewer-class.png',
147 '16x16/classviewer-macro.png',
148 '16x16/classviewer-member.png',
149 '16x16/classviewer-method.png',
150 '16x16/classviewer-namespace.png',
151 '16x16/classviewer-other.png',
152 '16x16/classviewer-struct.png',
153 '16x16/classviewer-var.png',
155 'hicolor/16x16/actions': ['16x16/geany-build.png',
156 '16x16/geany-close-all.png',
157 '16x16/geany-save-all.png'],
158 'hicolor/24x24/actions': ['24x24/geany-build.png',
159 '24x24/geany-close-all.png',
160 '24x24/geany-save-all.png'],
161 'hicolor/32x32/actions': ['32x32/geany-build.png',
162 '32x32/geany-close-all.png',
163 '32x32/geany-save-all.png'],
164 'hicolor/32x32/apps': ['32x32/geany.png'],
165 'hicolor/48x48/actions': ['48x48/geany-build.png',
166 '48x48/geany-close-all.png',
167 '48x48/geany-save-all.png'],
168 'hicolor/48x48/apps': ['48x48/geany.png'],
169 'hicolor/scalable/apps': ['scalable/geany.svg'],
170 'hicolor/scalable/actions': ['scalable/geany-build.svg',
171 'scalable/geany-close-all.svg',
172 'scalable/geany-save-all.svg'],
173 'Tango/16x16/actions': ['tango/16x16/geany-save-all.png'],
174 'Tango/24x24/actions': ['tango/24x24/geany-save-all.png'],
175 'Tango/32x32/actions': ['tango/32x32/geany-save-all.png'],
176 'Tango/48x48/actions': ['tango/48x48/geany-save-all.png'],
177 'Tango/scalable/actions': ['tango/scalable/geany-save-all.svg']
179 geany_icons_indexes = {
180 'hicolor': ['index.theme'],
181 'Tango': ['tango/index.theme']
187 conf.check_waf_version(mini='1.6.1')
189 conf.load('compiler_c')
190 is_win32 = _target_is_win32(conf)
192 visibility_hidden_supported = conf.check_cc(cflags=['-Werror', '-fvisibility=hidden'], mandatory=False)
193 conf.check_cc(header_name='fcntl.h', mandatory=False)
194 conf.check_cc(header_name='fnmatch.h', mandatory=False)
195 conf.check_cc(header_name='glob.h', mandatory=False)
196 conf.check_cc(header_name='sys/time.h', mandatory=False)
197 conf.check_cc(header_name='sys/types.h', mandatory=False)
198 conf.check_cc(header_name='sys/stat.h', mandatory=False)
199 conf.define('HAVE_STDLIB_H', 1) # are there systems without stdlib.h?
200 conf.define('STDC_HEADERS', 1) # an optimistic guess ;-)
201 _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1) # needed for CTags
203 conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
204 conf.check_cc(function_name='fnmatch', header_name='fnmatch.h', mandatory=False)
205 conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
206 conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
207 conf.check_cc(function_name='strstr', header_name='string.h')
209 conf.check_cc(function_name='pow', header_name='math.h', lib='m', uselib_store='M')
211 # check sunOS socket support
212 if Options.platform == 'sunos':
213 conf.check_cc(function_name='socket', lib='socket',
214 header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
216 # check for cxx after the header and function checks have been done to ensure they are
217 # checked with cc not cxx
218 conf.load('compiler_cxx')
221 _load_intltool_if_available(conf)
223 # GTK / GIO version check
224 gtk_package_name = 'gtk+-3.0' if conf.options.use_gtk3 else 'gtk+-2.0'
225 minimum_gtk_version = MINIMUM_GTK3_VERSION if conf.options.use_gtk3 else MINIMUM_GTK_VERSION
226 conf.check_cfg(package=gtk_package_name, atleast_version=minimum_gtk_version, uselib_store='GTK',
227 mandatory=True, args='--cflags --libs')
228 conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
229 mandatory=True, args='--cflags --libs')
230 conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
231 mandatory=True, args='--cflags --libs')
232 conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
233 gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
234 conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
235 if conf.options.enable_mac_integration:
236 pkgname = 'gtk-mac-integration-gtk3' if conf.options.use_gtk3 else 'gtk-mac-integration-gtk2'
237 conf.check_cfg(package=pkgname, uselib_store='MAC_INTEGRATION',
238 mandatory=True, args='--cflags --libs')
239 # remember GTK version for the build step
240 conf.env['gtk_package_name'] = gtk_package_name
241 conf.env['minimum_gtk_version'] = minimum_gtk_version
242 conf.env['use_gtk3'] = conf.options.use_gtk3
244 revision = _get_git_rev(conf)
246 # rst2html for the HTML manual
247 if not conf.options.no_html_doc and revision is not None:
249 conf.env['RST2HTML'] = _find_rst2html(conf)
251 error_msg = '''Documentation enabled but rst2html not found.
252 You can explicitly disable building of the HTML manual with --disable-html-docs,
253 but you then may not have a local copy of the HTML manual.'''
254 raise WafError(error_msg)
258 if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
259 # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
260 new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
261 _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
262 _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
263 _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
264 _add_to_env_and_define(conf, 'LIBDIR', '%s/lib' % conf.env['PREFIX'], quote=True)
265 conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
266 # overwrite LOCALEDIR to install message catalogues properly
267 conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share', 'locale')
268 # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
269 conf.undefine('DATADIR')
270 conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
271 conf.env.append_value('LINKFLAGS_cprogram', [
274 '-static-libstdc++'])
275 conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'comdlg32'])
276 # explicitly define Windows version for older Mingw environments
277 conf.define('WINVER', '0x0501', quote=False) # for SHGetFolderPathAndSubDirW
278 conf.define('_WIN32_IE', '0x0500', quote=False) # for SHGFP_TYPE
280 conf.env['cshlib_PATTERN'] = '%s.so'
281 # DATADIR and LOCALEDIR are defined by the intltool tool
282 # but they are not added to the environment, so we need to
283 _add_define_to_env(conf, 'DATADIR')
284 _add_define_to_env(conf, 'LOCALEDIR')
285 docdir = os.path.join(conf.env['DATADIR'], 'doc', 'geany')
286 libdir = os.path.join(conf.env['PREFIX'], 'lib')
287 mandir = os.path.join(conf.env['DATADIR'], 'man')
288 _define_from_opt(conf, 'DOCDIR', conf.options.docdir, docdir)
289 _define_from_opt(conf, 'LIBDIR', conf.options.libdir, libdir)
290 _define_from_opt(conf, 'MANDIR', conf.options.mandir, mandir)
292 conf.define('ENABLE_NLS', 1)
293 conf.define('GEANY_LOCALEDIR', '' if is_win32 else conf.env['LOCALEDIR'], quote=True)
294 conf.define('GEANY_DATADIR', 'data' if is_win32 else conf.env['DATADIR'], quote=True)
295 conf.define('GEANY_DOCDIR', conf.env['DOCDIR'], quote=True)
296 conf.define('GEANY_LIBDIR', '' if is_win32 else conf.env['LIBDIR'], quote=True)
297 conf.define('GEANY_PREFIX', '' if is_win32 else conf.env['PREFIX'], quote=True)
298 conf.define('PACKAGE', APPNAME, quote=True)
299 conf.define('VERSION', VERSION, quote=True)
300 conf.define('REVISION', revision or '-1', quote=True)
302 conf.define('GETTEXT_PACKAGE', APPNAME, quote=True)
306 conf.options.no_vte = True
308 _define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
309 _define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
310 _define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
312 conf.write_config_header('config.h', remove=False)
314 # GEANY_EXPORT_SYMBOL and GEANY_API_SYMBOL
316 geanyexport_cflags = []
317 geanyexport_defines = ['GEANY_EXPORT_SYMBOL=__declspec(dllexport)']
318 elif visibility_hidden_supported:
319 geanyexport_cflags = ['-fvisibility=hidden']
320 geanyexport_defines = ['GEANY_EXPORT_SYMBOL=__attribute__((visibility("default")))']
321 else: # unknown, define to nothing
322 geanyexport_cflags = []
323 geanyexport_defines = ['GEANY_EXPORT_SYMBOL=']
324 geanyexport_defines.append('GEANY_API_SYMBOL=GEANY_EXPORT_SYMBOL')
325 conf.env['DEFINES_geanyexport'] = geanyexport_defines
326 conf.env['CFLAGS_geanyexport'] = geanyexport_cflags
327 conf.env['CXXFLAGS_geanyexport'] = geanyexport_cflags
329 # some more compiler flags
330 conf.env.append_value('CFLAGS', ['-DHAVE_CONFIG_H'])
331 if conf.env['CC_NAME'] == 'gcc' and '-O' not in ''.join(conf.env['CFLAGS']):
332 conf.env.append_value('CFLAGS', ['-O2'])
333 if revision is not None:
334 conf.env.append_value('CFLAGS', ['-g', '-DGEANY_DEBUG'])
336 conf.env.append_value('CFLAGS', ['-DGTK'])
337 conf.env.append_value('CXXFLAGS',
338 ['-DNDEBUG', '-DGTK', '-DSCI_LEXER', '-DG_THREADS_IMPL_NONE'])
341 Logs.pprint('BLUE', 'Summary:')
342 conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
343 conf.msg('Using GTK version', gtk_version)
344 conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
345 conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
346 if revision is not None:
347 conf.msg('Compiling Git revision', revision)
351 # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
352 # If anyone wants to add support for building with MSVC, this hack should be removed.
353 c_compiler['win32'] = ['gcc']
354 cxx_compiler['win32'] = ['g++']
356 opt.load('compiler_cc')
357 opt.load('compiler_cxx')
361 opt.add_option('--no-scm', action='store_true', default=False,
362 help='Disable SCM detection [default: No]', dest='no_scm')
364 opt.add_option('--disable-plugins', action='store_true', default=False,
365 help='compile without plugin support [default: No]', dest='no_plugins')
366 opt.add_option('--disable-socket', action='store_true', default=False,
367 help='compile without support to detect a running instance [[default: No]',
369 opt.add_option('--disable-vte', action='store_true', default=False,
370 help='compile without support for an embedded virtual terminal [[default: No]',
372 opt.add_option('--enable-gtk3', action='store_true', default=False,
373 help='compile with GTK3 support (experimental) [[default: No]',
375 opt.add_option('--enable-mac-integration', action='store_true', default=False,
376 help='use gtk-mac-integration to enable improved OS X integration [[default: No]',
377 dest='enable_mac_integration')
378 opt.add_option('--disable-html-docs', action='store_true', default=False,
379 help='do not generate HTML documentation using rst2html [[default: No]',
382 opt.add_option('--mandir', type='string', default='',
383 help='man documentation', dest='mandir')
384 opt.add_option('--docdir', type='string', default='',
385 help='documentation root', dest='docdir')
386 opt.add_option('--libdir', type='string', default='',
387 help='object code libraries', dest='libdir')
391 is_win32 = _target_is_win32(bld)
393 if bld.cmd == 'clean':
394 _remove_linguas_file()
395 if bld.cmd in ('install', 'uninstall'):
396 bld.add_post_fun(_post_install)
398 def build_plugin(plugin_name, install=True, uselib_add=[]):
400 instpath = '${PREFIX}/lib' if is_win32 else '${LIBDIR}/geany'
405 features = ['c', 'cshlib'],
406 source = 'plugins/%s.c' % plugin_name,
407 includes = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
408 defines = 'G_LOG_DOMAIN="%s"' % plugin_name,
409 target = plugin_name,
410 uselib = ['GTK', 'GLIB', 'GMODULE'] + uselib_add,
412 install_path = instpath)
417 source = ctags_sources,
420 includes = ['.', 'tagmanager', 'tagmanager/ctags'],
421 defines = 'G_LOG_DOMAIN="CTags"',
422 uselib = ['cshlib', 'GLIB', 'geanyexport'])
427 source = tagmanager_sources,
429 target = 'tagmanager',
430 includes = ['.', 'tagmanager', 'tagmanager/ctags'],
431 defines = ['GEANY_PRIVATE', 'G_LOG_DOMAIN="Tagmanager"'],
432 uselib = ['cshlib', 'GTK', 'GLIB', 'geanyexport'])
437 source = mio_sources,
440 includes = ['.', 'tagmanager/mio/'],
441 defines = 'G_LOG_DOMAIN="MIO"',
442 uselib = ['cshlib', 'GTK', 'GLIB', 'geanyexport'])
445 files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
446 scintilla_sources.update([file.path_from(bld.srcnode) for file in files])
448 features = ['c', 'cxx'],
450 target = 'scintilla',
451 source = scintilla_sources,
452 includes = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
453 uselib = ['cshlib', 'cxxshlib', 'GTK', 'GLIB', 'GMODULE', 'M', 'geanyexport'])
456 if bld.env['HAVE_VTE'] == 1:
457 geany_sources.add('src/vte.c')
459 geany_sources.add('src/win32.c')
460 geany_sources.add('geany_private.rc')
461 geany_bin_sources.add('geany_private.rc')
463 def gen_signallist(task):
464 from xml.etree import ElementTree
466 def find_handlers(xml_filename):
467 tree = ElementTree.parse(xml_filename)
468 signals = tree.getroot().findall(".//signal")
469 return [sig.attrib["handler"] for sig in signals]
472 for node in task.inputs:
473 handlers += find_handlers(node.abspath())
474 handlers = sorted(set(handlers))
476 for node in task.outputs:
477 node.write("/* This file is auto-generated, do not edit. */\n" +
478 ''.join(["ITEM(%s)\n" % h for h in handlers]))
482 source = 'data/geany.glade',
483 target = bld.path.get_bld().make_node('src/signallist.i'),
484 name = 'signallist.i',
485 rule = gen_signallist)
487 base_uselibs = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'MAC_INTEGRATION', 'SUNOS_SOCKET', 'M']
491 features = ['c', 'cxx'],
494 source = geany_sources,
495 includes = ['.', 'scintilla/include', 'tagmanager/src', 'src'],
496 defines = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
497 uselib = base_uselibs + ['geanyexport'],
498 use = ['scintilla', 'ctags', 'tagmanager', 'mio'],
499 linkflags = bld.env['LINKFLAGS_cprogram'],
500 vnum = GEANY_LIB_VERSION,
501 install_path = '${PREFIX}/bin' if is_win32 else '${LIBDIR}')
505 features = ['c', 'cxx'],
508 source = geany_bin_sources,
509 includes = ['.', 'scintilla/include', 'tagmanager/src'],
510 defines = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
511 uselib = base_uselibs + ['geanyexport'],
514 # http://www.freehackers.org/~tnagy/testdoc/single.html#common_c
515 t.rpath = bld.env['LIBDIR']
518 if bld.env['HAVE_PLUGINS'] == 1:
519 build_plugin('classbuilder')
520 build_plugin('demoplugin', False)
521 build_plugin('export', uselib_add=['M'])
522 build_plugin('filebrowser')
523 build_plugin('htmlchars')
524 build_plugin('saveactions')
525 build_plugin('splitwindow')
528 if bld.env['INTLTOOL']:
530 features = ['linguas', 'intltool_po'],
532 install_path = '${LOCALEDIR}',
535 # HTML documentation (build if it is not part of the tree already, as it is required for install)
536 html_doc_filename = os.path.join(bld.out_dir, 'doc', 'geany.html')
537 if bld.env['RST2HTML']:
538 rst2html = bld.env['RST2HTML']
540 source = ['doc/geany.txt'],
541 deps = ['doc/geany.css'],
542 target = bld.path.get_bld().make_node('doc/geany.html'),
544 cwd = os.path.join(bld.path.abspath(), 'doc'),
545 rule = '%s -stg --stylesheet=geany.css geany.txt %s' % (rst2html, html_doc_filename))
549 # replace backward slashes by forward slashes as they could be interepreted as escape
551 geany_pc_prefix = bld.env['PREFIX'].replace('\\', '/')
553 geany_pc_prefix = bld.env['PREFIX']
555 source = 'geany.pc.in',
556 dct = {'VERSION': VERSION,
557 'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
558 (bld.env['gtk_package_name'],
559 bld.env['minimum_gtk_version'],
560 MINIMUM_GLIB_VERSION),
561 'prefix': geany_pc_prefix,
562 'exec_prefix': '${prefix}',
563 'libdir': '${exec_prefix}/lib',
564 'includedir': '${prefix}/include',
565 'datarootdir': '${prefix}/share',
566 'datadir': '${datarootdir}',
567 'localedir': '${datarootdir}/locale'})
571 if bld.env['INTLTOOL']:
573 features = 'intltool_in',
574 source = 'geany.desktop.in',
575 flags = ['-d', '-q', '-u', '-c'],
576 install_path = '${DATADIR}/applications')
581 source = 'doc/geany.1.in',
583 dct = {'VERSION': VERSION,
584 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
585 install_path = '${MANDIR}/man1')
590 source = 'geany.spec.in',
591 target = 'geany.spec',
593 dct = {'VERSION': VERSION})
598 source = 'doc/Doxyfile.in',
599 target = 'doc/Doxyfile',
601 dct = {'VERSION': VERSION,
602 'top_builddir': bld.out_dir,
603 'top_srcdir': bld.top_dir,})
605 # disable build/install phase interleaving
612 bld.install_files('${PREFIX}/include/geany', '''
640 plugins/geanyplugin.h
641 plugins/geanyfunctions.h
643 bld.install_files('${PREFIX}/include/geany/scintilla', '''
644 scintilla/include/SciLexer.h scintilla/include/Scintilla.h
645 scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h ''')
646 bld.install_files('${PREFIX}/include/geany/tagmanager', '''
647 tagmanager/src/tm_source_file.h
648 tagmanager/src/tm_tag.h
649 tagmanager/src/tm_tagmanager.h
650 tagmanager/src/tm_workspace.h ''')
652 base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
653 ext = '.txt' if is_win32 else ''
654 for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
655 basename = _uc_first(filename, bld)
656 destination_filename = '%s%s' % (basename, ext)
657 destination = os.path.join(base_dir, destination_filename)
658 bld.install_as(destination, filename)
660 # install HTML documentation only if it exists, i.e. it was built before
661 # local_html_doc_filename supports installing HTML doc from in-tree geany.html if it exists
662 local_html_doc_filename = os.path.join(bld.path.abspath(), 'doc', 'geany.html')
663 if os.path.exists(html_doc_filename) or os.path.exists(local_html_doc_filename):
664 html_dir = '' if is_win32 else 'html/'
665 html_name = 'Manual.html' if is_win32 else 'index.html'
666 start_dir = bld.path.find_dir('doc/images')
667 bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
668 bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
670 bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
671 bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
673 bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
674 bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
676 data_dir = '' if is_win32 else 'geany'
677 start_dir = bld.path.find_dir('data')
678 bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
679 bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
680 bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
681 bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
682 bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
683 bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
684 if bld.env['use_gtk3']:
685 bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
687 bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
689 start_dir = bld.path.find_dir('data/colorschemes')
690 template_dest = '${DATADIR}/%s/colorschemes' % data_dir
691 bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
692 start_dir = bld.path.find_dir('data/templates')
693 template_dest = '${DATADIR}/%s/templates' % data_dir
694 bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
696 for dest, srcs in geany_icons.items():
697 dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
698 bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
699 # install theme indexes on Windows
701 for dest, srcs in geany_icons_indexes.items():
702 bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
706 Scripting.distclean(ctx)
707 _remove_linguas_file()
710 def _remove_linguas_file():
711 # remove LINGUAS file as well
713 os.unlink(LINGUAS_FILE)
719 @before_method('apply_intltool_po')
720 def write_linguas_file(self):
721 if os.path.exists(LINGUAS_FILE):
724 if 'LINGUAS' in self.env:
725 files = self.env['LINGUAS']
726 for po_filename in files.split(' '):
727 if os.path.exists('po/%s.po' % po_filename):
728 linguas += '%s ' % po_filename
730 files = os.listdir('%s/po' % self.path.abspath())
732 for filename in files:
733 if filename.endswith('.po'):
734 linguas += '%s ' % filename[:-3]
735 file_h = open(LINGUAS_FILE, 'w')
736 file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
740 def _post_install(ctx):
741 is_win32 = _target_is_win32(ctx)
744 for d in 'hicolor', 'Tango':
745 theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
746 icon_cache_updated = False
747 if not ctx.options.destdir:
748 ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
749 Logs.pprint('GREEN', 'GTK icon cache updated.')
750 icon_cache_updated = True
751 if not icon_cache_updated:
752 Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
753 Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
757 """update the message catalogs for internationalization"""
758 potfile = '%s.pot' % APPNAME
759 os.chdir('%s/po' % top)
762 old_size = os.stat(potfile).st_size
765 ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
766 size_new = os.stat(potfile).st_size
767 if size_new != old_size:
768 Logs.pprint('CYAN', 'Updated POT file.')
769 Logs.pprint('CYAN', 'Updating translations')
770 ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
772 Logs.pprint('RED', 'Updating translations failed')
774 Logs.pprint('CYAN', 'POT file is up to date.')
776 Logs.pprint('RED', 'Failed to generate pot file.')
780 """generate API reference documentation"""
781 ctx = BuildContext() # create our own context to have ctx.top_dir
782 basedir = ctx.top_dir
783 doxygen = _find_program(ctx, 'doxygen')
784 doxyfile = '%s/doc/Doxyfile' % ctx.out_dir
785 Logs.pprint('CYAN', 'Generating API documentation')
786 ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
788 raise WafError('Generating API documentation failed')
792 """generate HACKING documentation"""
793 ctx = BuildContext() # create our own context to have ctx.top_dir
794 Logs.pprint('CYAN', 'Generating HACKING documentation')
795 cmd = _find_rst2html(ctx)
796 hacking_file = os.path.join(ctx.top_dir, 'HACKING')
797 hacking_html_file = os.path.join(ctx.top_dir, 'doc', 'hacking.html')
798 stylesheet = os.path.join(ctx.top_dir, 'doc', 'geany.css')
799 ret = ctx.exec_command('%s -stg --stylesheet=%s %s %s' % (
800 cmd, stylesheet, hacking_file, hacking_html_file))
802 raise WafError('Generating HACKING documentation failed')
805 def _find_program(ctx, cmd, **kw):
809 if ctx is None or not isinstance(ctx, ConfigurationContext):
810 ctx = ConfigurationContext()
813 return ctx.find_program(cmd, **kw)
816 def _find_rst2html(ctx):
817 cmds = ['rst2html', 'rst2html2']
819 cmd = _find_program(ctx, command, mandatory=False, exts=',.py')
824 'rst2html.py could not be found. Please install the Python docutils package.')
828 def _add_define_to_env(conf, key):
829 value = conf.get_define(key)
831 value = value.replace('"', '')
832 conf.env[key] = value
835 def _add_to_env_and_define(conf, key, value, quote=False):
836 conf.define(key, value, quote)
837 conf.env[key] = value
840 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
841 value = default_value
843 if isinstance(opt_value, bool):
847 if value is not None:
848 _add_to_env_and_define(conf, define_name, value, quote)
850 conf.undefine(define_name)
853 def _get_git_rev(conf):
854 if conf.options.no_scm:
857 if not os.path.isdir('.git'):
861 cmd = 'git rev-parse --short --revs-only HEAD'
862 revision = conf.cmd_and_log(cmd).strip()
869 def _load_intltool_if_available(conf):
871 conf.load('intltool')
872 if 'LINGUAS' in os.environ:
873 conf.env['LINGUAS'] = os.environ['LINGUAS']
875 # on Windows, we don't hard depend on intltool, on all other platforms raise an error
876 if not _target_is_win32(conf):
880 def _target_is_win32(ctx):
881 if 'is_win32' in ctx.env:
883 return ctx.env['is_win32']
885 if sys.platform == 'win32':
888 if ctx.env and 'CC' in ctx.env:
889 env_cc = ctx.env['CC']
890 if not isinstance(env_cc, str):
891 env_cc = ''.join(env_cc)
892 is_win32 = (env_cc.find('mingw') != -1)
895 # cache for future checks
896 ctx.env['is_win32'] = is_win32
900 def _uc_first(string, ctx):
901 if _target_is_win32(ctx):
902 return string.title()