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 ConfigurationError, 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/powershell.c',
110 'tagmanager/ctags/python.c',
111 'tagmanager/ctags/read.c',
112 'tagmanager/ctags/rest.c',
113 'tagmanager/ctags/ruby.c',
114 'tagmanager/ctags/rust.c',
115 'tagmanager/ctags/sh.c',
116 'tagmanager/ctags/sort.c',
117 'tagmanager/ctags/sql.c',
118 'tagmanager/ctags/strlist.c',
119 'tagmanager/ctags/txt2tags.c',
120 'tagmanager/ctags/tcl.c',
121 'tagmanager/ctags/vhdl.c',
122 'tagmanager/ctags/verilog.c',
123 'tagmanager/ctags/vstring.c'])
125 tagmanager_sources = set([
126 'tagmanager/src/tm_source_file.c',
127 'tagmanager/src/tm_tag.c',
128 'tagmanager/src/tm_workspace.c'])
130 scintilla_sources = set(['scintilla/gtk/scintilla-marshal.c'])
132 geany_sources = set([
133 'src/about.c', 'src/build.c', 'src/callbacks.c', 'src/dialogs.c', 'src/document.c',
134 'src/editor.c', 'src/encodings.c', 'src/filetypes.c', 'src/geanyentryaction.c',
135 'src/geanymenubuttonaction.c', 'src/geanyobject.c', 'src/geanywraplabel.c',
136 'src/highlighting.c', 'src/keybindings.c',
137 'src/keyfile.c', 'src/log.c', 'src/libmain.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c', 'src/osx.c',
138 'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
139 'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/spawn.c', 'src/stash.c',
141 'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
142 'src/ui_utils.c', 'src/utils.c'])
144 geany_bin_sources = set(['src/main.c'])
147 'hicolor/16x16/apps': ['16x16/classviewer-class.png',
148 '16x16/classviewer-macro.png',
149 '16x16/classviewer-member.png',
150 '16x16/classviewer-method.png',
151 '16x16/classviewer-namespace.png',
152 '16x16/classviewer-other.png',
153 '16x16/classviewer-struct.png',
154 '16x16/classviewer-var.png',
156 'hicolor/16x16/actions': ['16x16/geany-build.png',
157 '16x16/geany-close-all.png',
158 '16x16/geany-save-all.png'],
159 'hicolor/24x24/actions': ['24x24/geany-build.png',
160 '24x24/geany-close-all.png',
161 '24x24/geany-save-all.png'],
162 'hicolor/32x32/actions': ['32x32/geany-build.png',
163 '32x32/geany-close-all.png',
164 '32x32/geany-save-all.png'],
165 'hicolor/32x32/apps': ['32x32/geany.png'],
166 'hicolor/48x48/actions': ['48x48/geany-build.png',
167 '48x48/geany-close-all.png',
168 '48x48/geany-save-all.png'],
169 'hicolor/48x48/apps': ['48x48/geany.png'],
170 'hicolor/scalable/apps': ['scalable/geany.svg'],
171 'hicolor/scalable/actions': ['scalable/geany-build.svg',
172 'scalable/geany-close-all.svg',
173 'scalable/geany-save-all.svg'],
174 'Tango/16x16/actions': ['tango/16x16/geany-save-all.png'],
175 'Tango/24x24/actions': ['tango/24x24/geany-save-all.png'],
176 'Tango/32x32/actions': ['tango/32x32/geany-save-all.png'],
177 'Tango/48x48/actions': ['tango/48x48/geany-save-all.png'],
178 'Tango/scalable/actions': ['tango/scalable/geany-save-all.svg']
180 geany_icons_indexes = {
181 'hicolor': ['index.theme'],
182 'Tango': ['tango/index.theme']
188 conf.check_waf_version(mini='1.6.1')
190 conf.load('compiler_c')
192 is_win32 = _target_is_win32(conf)
194 visibility_hidden_supported = conf.check_cc(cflags=['-Werror', '-fvisibility=hidden'], mandatory=False)
195 conf.check_cc(header_name='fcntl.h', mandatory=False)
196 conf.check_cc(header_name='fnmatch.h', mandatory=False)
197 conf.check_cc(header_name='glob.h', mandatory=False)
198 conf.check_cc(header_name='sys/time.h', mandatory=False)
199 conf.check_cc(header_name='sys/types.h', mandatory=False)
200 conf.check_cc(header_name='sys/stat.h', mandatory=False)
201 conf.define('HAVE_STDLIB_H', 1) # are there systems without stdlib.h?
202 conf.define('STDC_HEADERS', 1) # an optimistic guess ;-)
203 _add_to_env_and_define(conf, 'HAVE_REGCOMP', 1) # needed for CTags
205 conf.check_cc(function_name='fgetpos', header_name='stdio.h', mandatory=False)
206 conf.check_cc(function_name='fnmatch', header_name='fnmatch.h', mandatory=False)
207 conf.check_cc(function_name='ftruncate', header_name='unistd.h', mandatory=False)
208 conf.check_cc(function_name='mkstemp', header_name='stdlib.h', mandatory=False)
209 conf.check_cc(function_name='strstr', header_name='string.h')
211 conf.check_cc(function_name='pow', header_name='math.h', lib='m', uselib_store='M')
213 # check sunOS socket support
214 if Options.platform == 'sunos':
215 conf.check_cc(function_name='socket', lib='socket',
216 header_name='sys/socket.h', uselib_store='SUNOS_SOCKET', mandatory=True)
218 # check for cxx after the header and function checks have been done to ensure they are
219 # checked with cc not cxx
220 conf.load('compiler_cxx')
223 _load_intltool_if_available(conf)
225 # GTK / GIO version check
226 gtk_package_name = 'gtk+-3.0' if conf.options.use_gtk3 else 'gtk+-2.0'
227 minimum_gtk_version = MINIMUM_GTK3_VERSION if conf.options.use_gtk3 else MINIMUM_GTK_VERSION
228 conf.check_cfg(package=gtk_package_name, atleast_version=minimum_gtk_version, uselib_store='GTK',
229 mandatory=True, args='--cflags --libs')
230 conf.check_cfg(package='glib-2.0', atleast_version=MINIMUM_GLIB_VERSION, uselib_store='GLIB',
231 mandatory=True, args='--cflags --libs')
232 conf.check_cfg(package='gmodule-2.0', uselib_store='GMODULE',
233 mandatory=True, args='--cflags --libs')
234 conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
235 gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
236 conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
237 if conf.options.enable_mac_integration:
238 pkgname = 'gtk-mac-integration-gtk3' if conf.options.use_gtk3 else 'gtk-mac-integration-gtk2'
239 conf.check_cfg(package=pkgname, uselib_store='MAC_INTEGRATION',
240 mandatory=True, args='--cflags --libs')
241 # remember GTK version for the build step
242 conf.env['gtk_package_name'] = gtk_package_name
243 conf.env['gtk_version'] = gtk_version
244 conf.env['minimum_gtk_version'] = minimum_gtk_version
245 conf.env['use_gtk3'] = conf.options.use_gtk3
247 revision = _get_git_rev(conf)
249 # rst2html for the HTML manual
250 if not conf.options.no_html_doc and revision is not None:
252 conf.env['RST2HTML'] = _find_rst2html(conf)
254 error_msg = '''Documentation enabled but rst2html not found.
255 You can explicitly disable building of the HTML manual with --disable-html-docs,
256 but you then may not have a local copy of the HTML manual.'''
257 raise WafError(error_msg)
261 if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
262 # overwrite default prefix on Windows (tempfile.gettempdir() is the Waf default)
263 new_prefix = os.path.join(str(conf.root), '%s-%s' % (APPNAME, VERSION))
264 _add_to_env_and_define(conf, 'PREFIX', new_prefix, quote=True)
265 _add_to_env_and_define(conf, 'BINDIR', os.path.join(new_prefix, 'bin'), quote=True)
266 _add_to_env_and_define(conf, 'DOCDIR', os.path.join(conf.env['PREFIX'], 'doc'), quote=True)
267 _add_to_env_and_define(conf, 'LIBDIR', '%s/lib' % conf.env['PREFIX'], quote=True)
268 conf.define('LOCALEDIR', os.path.join('share' 'locale'), quote=True)
269 # overwrite LOCALEDIR to install message catalogues properly
270 conf.env['LOCALEDIR'] = os.path.join(conf.env['PREFIX'], 'share', 'locale')
271 # DATADIR is defined in objidl.h, so we remove it from config.h but keep it in env
272 conf.undefine('DATADIR')
273 conf.env['DATADIR'] = os.path.join(conf.env['PREFIX'], 'data')
274 conf.env.append_value('LINKFLAGS_cprogram', [
277 '-static-libstdc++'])
278 conf.env.append_value('LIB_WIN32', ['wsock32', 'uuid', 'ole32', 'comdlg32'])
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'])
339 if conf.env['CXX_NAME'] == 'gcc' and '-O' not in ''.join(conf.env['CXXFLAGS']):
340 conf.env.append_value('CXXFLAGS', ['-O2'])
341 if revision is not None:
342 conf.env.append_value('CXXFLAGS', ['-g'])
345 Logs.pprint('BLUE', 'Summary:')
346 conf.msg('Install Geany ' + VERSION + ' in', conf.env['PREFIX'])
347 conf.msg('Using GTK version', gtk_version)
348 conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
349 conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
350 if revision is not None:
351 conf.msg('Compiling Git revision', revision)
355 # Disable MSVC detection on win32: building Geany with MSVC is currently not supported
356 # If anyone wants to add support for building with MSVC, this hack should be removed.
357 c_compiler['win32'] = ['gcc']
358 cxx_compiler['win32'] = ['g++']
360 opt.load('compiler_cc')
361 opt.load('compiler_cxx')
365 opt.add_option('--no-scm', action='store_true', default=False,
366 help='Disable SCM detection [default: No]', dest='no_scm')
368 opt.add_option('--disable-plugins', action='store_true', default=False,
369 help='compile without plugin support [default: No]', dest='no_plugins')
370 opt.add_option('--disable-socket', action='store_true', default=False,
371 help='compile without support to detect a running instance [[default: No]',
373 opt.add_option('--disable-vte', action='store_true', default=False,
374 help='compile without support for an embedded virtual terminal [[default: No]',
376 opt.add_option('--enable-gtk3', action='store_true', default=False,
377 help='compile with GTK3 support (experimental) [[default: No]',
379 opt.add_option('--enable-mac-integration', action='store_true', default=False,
380 help='use gtk-mac-integration to enable improved OS X integration [[default: No]',
381 dest='enable_mac_integration')
382 opt.add_option('--disable-html-docs', action='store_true', default=False,
383 help='do not generate HTML documentation using rst2html [[default: No]',
386 opt.add_option('--mandir', type='string', default='',
387 help='man documentation', dest='mandir')
388 opt.add_option('--docdir', type='string', default='',
389 help='documentation root', dest='docdir')
390 opt.add_option('--libdir', type='string', default='',
391 help='object code libraries', dest='libdir')
395 is_win32 = _target_is_win32(bld)
397 if bld.cmd == 'clean':
398 _remove_linguas_file()
399 if bld.cmd in ('install', 'uninstall'):
400 bld.add_post_fun(_post_install)
402 def build_plugin(plugin_name, install=True, uselib_add=[]):
404 instpath = '${LIBDIR}/geany'
409 features = ['c', 'cshlib'],
410 source = 'plugins/%s.c' % plugin_name,
411 includes = ['.', 'src/', 'scintilla/include', 'tagmanager/src'],
412 defines = 'G_LOG_DOMAIN="%s"' % plugin_name,
413 target = plugin_name,
414 uselib = ['GTK', 'GLIB', 'GMODULE', 'C99'] + uselib_add,
416 install_path = instpath)
421 source = ctags_sources,
424 includes = ['.', 'tagmanager', 'tagmanager/ctags'],
425 defines = 'G_LOG_DOMAIN="CTags"',
426 uselib = ['cshlib', 'GLIB', 'geanyexport', 'C99'])
431 source = tagmanager_sources,
433 target = 'tagmanager',
434 includes = ['.', 'tagmanager', 'tagmanager/ctags'],
435 defines = ['GEANY_PRIVATE', 'G_LOG_DOMAIN="Tagmanager"'],
436 uselib = ['cshlib', 'GTK', 'GLIB', 'geanyexport', 'C99'])
441 source = mio_sources,
444 includes = ['.', 'tagmanager/mio/'],
445 defines = 'G_LOG_DOMAIN="MIO"',
446 uselib = ['cshlib', 'GTK', 'GLIB', 'geanyexport'])
449 files = bld.srcnode.ant_glob('scintilla/**/*.cxx', src=True, dir=False)
450 scintilla_sources.update([file.path_from(bld.srcnode) for file in files])
452 features = ['c', 'cxx'],
454 target = 'scintilla',
455 source = scintilla_sources,
456 includes = ['.', 'scintilla/include', 'scintilla/src', 'scintilla/lexlib'],
457 uselib = ['cshlib', 'cxxshlib', 'GTK', 'GLIB', 'GMODULE', 'M', 'geanyexport'])
460 if bld.env['HAVE_VTE'] == 1:
461 geany_sources.add('src/vte.c')
463 geany_sources.add('src/win32.c')
464 geany_bin_sources.add('geany_private.rc')
466 def gen_signallist(task):
467 from xml.etree import ElementTree
469 def find_handlers(xml_filename):
470 tree = ElementTree.parse(xml_filename)
471 signals = tree.getroot().findall(".//signal")
472 return [sig.attrib["handler"] for sig in signals]
475 for node in task.inputs:
476 handlers += find_handlers(node.abspath())
477 handlers = sorted(set(handlers))
479 for node in task.outputs:
480 node.write("/* This file is auto-generated, do not edit. */\n" +
481 ''.join(["ITEM(%s)\n" % h for h in handlers]))
485 source = 'data/geany.glade',
486 target = bld.path.get_bld().make_node('src/signallist.i'),
487 name = 'signallist.i',
488 rule = gen_signallist)
490 base_uselibs = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'MAC_INTEGRATION', 'SUNOS_SOCKET', 'M', 'C99']
494 features = ['c', 'cxx'],
497 source = geany_sources,
498 includes = ['.', 'scintilla/include', 'tagmanager/src', 'src'],
499 defines = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
500 uselib = base_uselibs + ['geanyexport'],
501 use = ['scintilla', 'ctags', 'tagmanager', 'mio'],
502 linkflags = bld.env['LINKFLAGS_cprogram'],
503 vnum = GEANY_LIB_VERSION,
504 install_path = '${PREFIX}/bin' if is_win32 else '${LIBDIR}')
508 features = ['c', 'cxx'],
511 source = geany_bin_sources,
512 includes = ['.', 'scintilla/include', 'tagmanager/src'],
513 defines = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
514 uselib = base_uselibs + ['geanyexport'],
517 # http://www.freehackers.org/~tnagy/testdoc/single.html#common_c
518 t.rpath = bld.env['LIBDIR']
521 if bld.env['HAVE_PLUGINS'] == 1:
522 build_plugin('classbuilder')
523 build_plugin('demoplugin', False)
524 build_plugin('export', uselib_add=['M'])
525 build_plugin('filebrowser')
526 build_plugin('htmlchars')
527 build_plugin('saveactions')
528 build_plugin('splitwindow')
531 if bld.env['INTLTOOL']:
533 features = ['linguas', 'intltool_po'],
535 install_path = '${LOCALEDIR}',
538 # HTML documentation (build if it is not part of the tree already, as it is required for install)
539 html_doc_filename = os.path.join(bld.out_dir, 'doc', 'geany.html')
540 if bld.env['RST2HTML']:
541 rst2html = bld.env['RST2HTML']
543 source = ['doc/geany.txt'],
544 deps = ['doc/geany.css'],
545 target = bld.path.get_bld().make_node('doc/geany.html'),
547 cwd = os.path.join(bld.path.abspath(), 'doc'),
548 rule = '%s -stg --stylesheet=geany.css geany.txt %s' % (rst2html, html_doc_filename))
552 # replace backward slashes by forward slashes as they could be interepreted as escape
554 geany_pc_prefix = bld.env['PREFIX'].replace('\\', '/')
556 geany_pc_prefix = bld.env['PREFIX']
558 source = 'geany.pc.in',
559 dct = {'VERSION': VERSION,
560 'DEPENDENCIES': '%s >= %s glib-2.0 >= %s' % \
561 (bld.env['gtk_package_name'],
562 bld.env['minimum_gtk_version'],
563 MINIMUM_GLIB_VERSION),
564 'prefix': geany_pc_prefix,
565 'exec_prefix': '${prefix}',
566 'libdir': '${exec_prefix}/lib',
567 'includedir': '${prefix}/include',
568 'datarootdir': '${prefix}/share',
569 'datadir': '${datarootdir}',
570 'localedir': '${datarootdir}/locale'})
575 source = 'geany.nsi.in',
576 target = 'geany.nsi',
577 dct = {'VERSION': VERSION,
578 'GTK_VERSION': bld.env['gtk_version']},
583 if bld.env['INTLTOOL']:
585 features = 'intltool_in',
586 source = 'geany.desktop.in',
587 flags = ['-d', '-q', '-u', '-c'],
588 install_path = '${DATADIR}/applications')
593 source = 'doc/geany.1.in',
595 dct = {'VERSION': VERSION,
596 'GEANY_DATA_DIR': bld.env['DATADIR'] + '/geany'},
597 install_path = '${MANDIR}/man1')
602 source = 'geany.spec.in',
603 target = 'geany.spec',
605 dct = {'VERSION': VERSION})
610 source = 'doc/Doxyfile.in',
611 target = 'doc/Doxyfile',
613 dct = {'VERSION': VERSION,
614 'top_builddir': bld.out_dir,
615 'top_srcdir': bld.top_dir,})
617 # disable build/install phase interleaving
624 bld.install_files('${PREFIX}/include/geany', '''
653 plugins/geanyplugin.h
654 plugins/geanyfunctions.h
656 bld.install_files('${PREFIX}/include/geany/scintilla', '''
657 scintilla/include/SciLexer.h scintilla/include/Scintilla.h
658 scintilla/include/Scintilla.iface scintilla/include/ScintillaWidget.h
659 scintilla/include/Sci_Position.h ''')
660 bld.install_files('${PREFIX}/include/geany/tagmanager', '''
661 tagmanager/src/tm_source_file.h
662 tagmanager/src/tm_tag.h
663 tagmanager/src/tm_tagmanager.h
664 tagmanager/src/tm_workspace.h ''')
666 base_dir = '${PREFIX}' if is_win32 else '${DOCDIR}'
667 ext = '.txt' if is_win32 else ''
668 for filename in 'AUTHORS ChangeLog COPYING README NEWS THANKS TODO'.split():
669 basename = _uc_first(filename, bld)
670 destination_filename = '%s%s' % (basename, ext)
671 destination = os.path.join(base_dir, destination_filename)
672 bld.install_as(destination, filename)
674 # install HTML documentation only if it exists, i.e. it was built before
675 # local_html_doc_filename supports installing HTML doc from in-tree geany.html if it exists
676 local_html_doc_filename = os.path.join(bld.path.abspath(), 'doc', 'geany.html')
677 if os.path.exists(html_doc_filename) or os.path.exists(local_html_doc_filename):
678 html_dir = '' if is_win32 else 'html/'
679 html_name = 'Manual.html' if is_win32 else 'index.html'
680 start_dir = bld.path.find_dir('doc/images')
681 bld.install_files('${DOCDIR}/%simages' % html_dir, start_dir.ant_glob('*.png'), cwd=start_dir)
682 bld.install_as('${DOCDIR}/%s%s' % (html_dir, html_name), 'doc/geany.html')
684 bld.install_as('${DOCDIR}/%s' % _uc_first('manual.txt', bld), 'doc/geany.txt')
685 bld.install_as('${DOCDIR}/ScintillaLicense.txt', 'scintilla/License.txt')
687 bld.install_as('${DOCDIR}/ReadMe.I18n.txt', 'README.I18N')
688 bld.install_as('${DOCDIR}/Hacking.txt', 'HACKING')
690 data_dir = '' if is_win32 else 'geany'
691 start_dir = bld.path.find_dir('data')
692 bld.install_as('${DATADIR}/%s/GPL-2' % data_dir, 'COPYING')
693 bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('filetype*'), cwd=start_dir)
694 bld.install_files('${DATADIR}/%s' % data_dir, start_dir.ant_glob('*.tags'), cwd=start_dir)
695 bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.glade')
696 bld.install_files('${DATADIR}/%s' % data_dir, 'data/snippets.conf')
697 bld.install_files('${DATADIR}/%s' % data_dir, 'data/ui_toolbar.xml')
698 if bld.env['use_gtk3']:
699 bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.css')
701 bld.install_files('${DATADIR}/%s' % data_dir, 'data/geany.gtkrc')
703 start_dir = bld.path.find_dir('data/colorschemes')
704 template_dest = '${DATADIR}/%s/colorschemes' % data_dir
705 bld.install_files(template_dest, start_dir.ant_glob('*'), cwd=start_dir)
706 start_dir = bld.path.find_dir('data/templates')
707 template_dest = '${DATADIR}/%s/templates' % data_dir
708 bld.install_files(template_dest, start_dir.ant_glob('**/*'), cwd=start_dir, relative_trick=True)
710 for dest, srcs in geany_icons.items():
711 dest_dir = os.path.join('${PREFIX}/share/icons' if is_win32 else '${DATADIR}/icons', dest)
712 bld.install_files(dest_dir, srcs, cwd=bld.path.find_dir('icons'))
713 # install theme indexes on Windows
715 for dest, srcs in geany_icons_indexes.items():
716 bld.install_files(os.path.join('${PREFIX}/share/icons', dest), srcs, cwd=bld.path.find_dir('icons'))
720 Scripting.distclean(ctx)
721 _remove_linguas_file()
724 def _remove_linguas_file():
725 # remove LINGUAS file as well
727 os.unlink(LINGUAS_FILE)
733 @before_method('apply_intltool_po')
734 def write_linguas_file(self):
735 if os.path.exists(LINGUAS_FILE):
738 if 'LINGUAS' in self.env:
739 files = self.env['LINGUAS']
740 for po_filename in files.split(' '):
741 if os.path.exists('po/%s.po' % po_filename):
742 linguas += '%s ' % po_filename
744 files = os.listdir('%s/po' % self.path.abspath())
746 for filename in files:
747 if filename.endswith('.po'):
748 linguas += '%s ' % filename[:-3]
749 file_h = open(LINGUAS_FILE, 'w')
750 file_h.write('# This file is autogenerated. Do not edit.\n%s\n' % linguas)
754 def _post_install(ctx):
755 is_win32 = _target_is_win32(ctx)
758 for d in 'hicolor', 'Tango':
759 theme_dir = Utils.subst_vars('${DATADIR}/icons/' + d, ctx.env)
760 icon_cache_updated = False
761 if not ctx.options.destdir:
762 ctx.exec_command('gtk-update-icon-cache -q -f -t %s' % theme_dir)
763 Logs.pprint('GREEN', 'GTK icon cache updated.')
764 icon_cache_updated = True
765 if not icon_cache_updated:
766 Logs.pprint('YELLOW', 'Icon cache not updated. After install, run this:')
767 Logs.pprint('YELLOW', 'gtk-update-icon-cache -q -f -t %s' % theme_dir)
771 """update the message catalogs for internationalization"""
772 potfile = '%s.pot' % APPNAME
773 os.chdir('%s/po' % top)
776 old_size = os.stat(potfile).st_size
779 ctx.exec_command('intltool-update --pot -g %s' % APPNAME)
780 size_new = os.stat(potfile).st_size
781 if size_new != old_size:
782 Logs.pprint('CYAN', 'Updated POT file.')
783 Logs.pprint('CYAN', 'Updating translations')
784 ret = ctx.exec_command('intltool-update -r -g %s' % APPNAME)
786 Logs.pprint('RED', 'Updating translations failed')
788 Logs.pprint('CYAN', 'POT file is up to date.')
790 Logs.pprint('RED', 'Failed to generate pot file.')
794 """generate API reference documentation"""
795 ctx = BuildContext() # create our own context to have ctx.top_dir
796 basedir = ctx.top_dir
797 doxygen = _find_program(ctx, 'doxygen')
798 doxyfile = '%s/doc/Doxyfile' % ctx.out_dir
799 Logs.pprint('CYAN', 'Generating API documentation')
800 ret = ctx.exec_command('%s %s' % (doxygen, doxyfile))
802 raise WafError('Generating API documentation failed')
806 """generate HACKING documentation"""
807 ctx = BuildContext() # create our own context to have ctx.top_dir
808 Logs.pprint('CYAN', 'Generating HACKING documentation')
809 cmd = _find_rst2html(ctx)
810 hacking_file = os.path.join(ctx.top_dir, 'HACKING')
811 hacking_html_file = os.path.join(ctx.top_dir, 'doc', 'hacking.html')
812 stylesheet = os.path.join(ctx.top_dir, 'doc', 'geany.css')
813 ret = ctx.exec_command('%s -stg --stylesheet=%s %s %s' % (
814 cmd, stylesheet, hacking_file, hacking_html_file))
816 raise WafError('Generating HACKING documentation failed')
819 def _find_program(ctx, cmd, **kw):
823 if ctx is None or not isinstance(ctx, ConfigurationContext):
824 ctx = ConfigurationContext()
827 return ctx.find_program(cmd, **kw)
830 def _find_rst2html(ctx):
831 cmds = ['rst2html', 'rst2html2']
833 cmd = _find_program(ctx, command, mandatory=False, exts=',.py')
838 'rst2html.py could not be found. Please install the Python docutils package.')
842 def _add_define_to_env(conf, key):
843 value = conf.get_define(key)
845 value = value.replace('"', '')
846 conf.env[key] = value
849 def _add_to_env_and_define(conf, key, value, quote=False):
850 conf.define(key, value, quote)
851 conf.env[key] = value
854 def _define_from_opt(conf, define_name, opt_value, default_value, quote=1):
855 value = default_value
857 if isinstance(opt_value, bool):
861 if value is not None:
862 _add_to_env_and_define(conf, define_name, value, quote)
864 conf.undefine(define_name)
867 def _get_git_rev(conf):
868 if conf.options.no_scm:
871 if not os.path.isdir('.git'):
875 cmd = 'git rev-parse --short --revs-only HEAD'
876 revision = conf.cmd_and_log(cmd).strip()
883 def _load_intltool_if_available(conf):
885 conf.load('intltool')
886 if 'LINGUAS' in os.environ:
887 conf.env['LINGUAS'] = os.environ['LINGUAS']
889 # on Windows, we don't hard depend on intltool, on all other platforms raise an error
890 if not _target_is_win32(conf):
894 def _target_is_win32(ctx):
895 if 'is_win32' in ctx.env:
897 return ctx.env['is_win32']
899 if sys.platform == 'win32':
902 if ctx.env and 'CC' in ctx.env:
903 env_cc = ctx.env['CC']
904 if not isinstance(env_cc, str):
905 env_cc = ''.join(env_cc)
906 is_win32 = (env_cc.find('mingw') != -1)
909 # cache for future checks
910 ctx.env['is_win32'] = is_win32
914 def _uc_first(string, ctx):
915 if _target_is_win32(ctx):
916 return string.title()
920 # Copied from Geany-Plugins
921 def _check_c99(conf):
922 # FIXME: improve some checks?
923 # TODO: look at Autoconf's C99 checks?
925 // single-line comments
929 struct s { int a, b; };
932 static inline void fun_inline(struct s param) {}
937 // variable declaration in for body
938 for (int i = 0; i < 2; i++);
941 fun_inline((struct s) { 1, 2 });
943 // mixed declarations and code
946 // named initializers
947 struct s name_inited = {
952 return (b || mixed || ! name_inited.a);
957 # list of flags is stolen from Autoconf 2.69
958 flags = ['', '-std=gnu99', '-std=c99', '-c99', '-AC99',
959 '-D_STDC_C99=', '-qlanglvl=extc99']
962 desc = ['with flag %s' % flag, 'with no flags'][not flag]
963 conf.check_cc(fragment=fragment, uselib_store='C99', cflags=flag,
964 msg="Checking for C99 support (%s)" % desc)
967 except ConfigurationError as e: