gui: fix race in app list retrival
[ladish.git] / wscript
blob374cee3c19711adfc43abfe7d0beb3726ee93d93
1 #! /usr/bin/env python
2 # encoding: utf-8
4 import os
5 import Options
6 import Utils
7 import shutil
8 import re
10 APPNAME='ladish'
11 VERSION='0.3'
12 DBUS_NAME_BASE = 'org.ladish'
13 RELEASE = False
15 # these variables are mandatory ('/' are converted automatically)
16 srcdir = '.'
17 blddir = 'build'
19 def display_msg(conf, msg="", status = None, color = None):
20 if status:
21 conf.check_message_1(msg)
22 conf.check_message_2(status, color)
23 else:
24 Utils.pprint('NORMAL', msg)
26 def display_raw_text(conf, text, color = 'NORMAL'):
27 Utils.pprint(color, text, sep = '')
29 def display_line(conf, text, color = 'NORMAL'):
30 Utils.pprint(color, text, sep = os.linesep)
32 def yesno(bool):
33 if bool:
34 return "yes"
35 else:
36 return "no"
38 def set_options(opt):
39 opt.tool_options('compiler_cc')
40 opt.tool_options('compiler_cxx')
41 opt.tool_options('boost')
42 opt.add_option('--enable-pkg-config-dbus-service-dir', action='store_true', default=False, help='force D-Bus service install dir to be one returned by pkg-config')
43 opt.add_option('--enable-liblash', action='store_true', default=False, help='Build LASH compatibility library')
44 opt.add_option('--debug', action='store_true', default=False, dest='debug', help="Build debuggable binaries")
45 opt.add_option('--doxygen', action='store_true', default=False, help='Enable build of doxygen documentation')
47 def add_cflag(conf, flag):
48 conf.env.append_unique('CXXFLAGS', flag)
49 conf.env.append_unique('CCFLAGS', flag)
51 def add_linkflag(conf, flag):
52 conf.env.append_unique('LINKFLAGS', flag)
54 def check_gcc_optimizations_enabled(flags):
55 gcc_optimizations_enabled = False
56 for flag in flags:
57 if len(flag) < 2 or flag[0] != '-' or flag[1] != 'O':
58 continue
59 if len(flag) == 2:
60 gcc_optimizations_enabled = True;
61 else:
62 gcc_optimizations_enabled = flag[2] != '0';
63 return gcc_optimizations_enabled
65 def configure(conf):
66 conf.check_tool('compiler_cc')
67 conf.check_tool('compiler_cxx')
68 conf.check_tool('boost')
70 conf.check_cfg(
71 package = 'jack',
72 mandatory = True,
73 errmsg = "not installed, see http://jackaudio.org/",
74 args = '--cflags --libs')
76 conf.check_cfg(
77 package = 'dbus-1',
78 atleast_version = '1.0.0',
79 mandatory = True,
80 errmsg = "not installed, see http://dbus.freedesktop.org/",
81 args = '--cflags --libs')
83 dbus_dir = conf.check_cfg(package='dbus-1', args='--variable=session_bus_services_dir', msg="Retrieving D-Bus services dir")
84 if not dbus_dir:
85 return
87 dbus_dir = dbus_dir.strip()
88 conf.env['DBUS_SERVICES_DIR_REAL'] = dbus_dir
90 if Options.options.enable_pkg_config_dbus_service_dir:
91 conf.env['DBUS_SERVICES_DIR'] = dbus_dir
92 else:
93 conf.env['DBUS_SERVICES_DIR'] = os.path.join(os.path.normpath(conf.env['PREFIX']), 'share', 'dbus-1', 'services')
95 conf.env['LIBDIR'] = os.path.join(os.path.normpath(conf.env['PREFIX']), 'lib')
97 conf.env['BUILD_LIBLASH'] = Options.options.enable_liblash
98 conf.env['BUILD_DOXYGEN_DOCS'] = Options.options.doxygen
100 conf.check_cfg(
101 package = 'uuid',
102 mandatory = True,
103 errmsg = "not installed, see http://e2fsprogs.sourceforge.net/",
104 args = '--cflags --libs')
106 conf.check(
107 header_name='expat.h',
108 mandatory = True,
109 errmsg = "not installed, see http://expat.sourceforge.net/")
111 conf.env['LIB_EXPAT'] = ['expat']
113 build_gui = True
115 if build_gui and not conf.check_cfg(
116 package = 'glib-2.0',
117 mandatory = False,
118 errmsg = "not installed, see http://www.gtk.org/",
119 args = '--cflags --libs'):
120 build_gui = False
122 if build_gui and not conf.check_cfg(
123 package = 'dbus-glib-1',
124 mandatory = False,
125 errmsg = "not installed, see http://dbus.freedesktop.org/",
126 args = '--cflags --libs'):
127 build_gui = False
129 if build_gui and not conf.check_cfg(
130 package = 'gtk+-2.0',
131 mandatory = False,
132 atleast_version = '2.16.0',
133 errmsg = "not installed, see http://www.gtk.org/",
134 args = '--cflags --libs'):
135 build_gui = False
137 if build_gui and not conf.check_cfg(
138 package = 'flowcanvas',
139 mandatory = False,
140 atleast_version = '0.6.0',
141 errmsg = "not installed, see http://drobilla.net/software/flowcanvas/",
142 args = '--cflags --libs'):
143 build_gui = False
145 if build_gui:
146 # We need the boost headers package (e.g. libboost-dev)
147 # shared_ptr.hpp and weak_ptr.hpp
148 build_gui = conf.check_boost(errmsg="not found, see http://boost.org/")
150 conf.env['BUILD_GLADISH'] = build_gui
152 conf.env['BUILD_WERROR'] = not RELEASE
153 if conf.env['BUILD_WERROR']:
154 add_cflag(conf, '-Wall')
155 add_cflag(conf, '-Werror')
156 # for pre gcc-4.4, enable optimizations so use of uninitialized variables gets detected
157 try:
158 is_gcc = conf.env['CC_NAME'] == 'gcc'
159 if is_gcc:
160 gcc_ver = []
161 for n in conf.env['CC_VERSION']:
162 gcc_ver.append(int(n))
163 if gcc_ver[0] < 4 or gcc_ver[1] < 4:
164 #print "optimize force enable is required"
165 if not check_gcc_optimizations_enabled(conf.env['CCFLAGS']):
166 if Options.options.debug:
167 print "C optimization must be forced in order to enable -Wuninitialized"
168 print "However this will not be made because debug compilation is enabled"
169 else:
170 print "C optimization forced in order to enable -Wuninitialized"
171 conf.env.append_unique('CCFLAGS', "-O")
172 except:
173 pass
175 conf.env['BUILD_DEBUG'] = Options.options.debug
176 if conf.env['BUILD_DEBUG']:
177 add_cflag(conf, '-g')
178 add_cflag(conf, '-O0')
179 add_linkflag(conf, '-g')
181 conf.define('DATA_DIR', os.path.normpath(os.path.join(conf.env['PREFIX'], 'share', APPNAME)))
182 conf.define('PACKAGE_VERSION', VERSION)
183 conf.define('DBUS_NAME_BASE', DBUS_NAME_BASE)
184 conf.define('DBUS_BASE_PATH', '/' + DBUS_NAME_BASE.replace('.', '/'))
185 conf.define('BASE_NAME', APPNAME)
186 conf.define('_GNU_SOURCE', 1)
187 conf.write_config_header('config.h')
189 display_msg(conf)
191 display_msg(conf, "==================")
192 version_msg = APPNAME + "-" + VERSION
194 if os.access('version.h', os.R_OK):
195 data = file('version.h').read()
196 m = re.match(r'^#define GIT_VERSION "([^"]*)"$', data)
197 if m != None:
198 version_msg += " exported from " + m.group(1)
199 elif os.access('.git', os.R_OK):
200 version_msg += " git revision will checked and eventually updated during build"
202 display_msg(conf, version_msg)
204 display_msg(conf)
205 display_msg(conf, "Install prefix", conf.env['PREFIX'], 'CYAN')
207 display_msg(conf, 'Build gladish', yesno(conf.env['BUILD_GLADISH']))
208 display_msg(conf, 'Build liblash', yesno(Options.options.enable_liblash))
209 display_msg(conf, 'Treat warnings as errors', yesno(conf.env['BUILD_WERROR']))
210 display_msg(conf, 'Debuggable binaries', yesno(conf.env['BUILD_DEBUG']))
211 display_msg(conf, 'Build doxygen documentation', yesno(conf.env['BUILD_DOXYGEN_DOCS']))
213 if conf.env['DBUS_SERVICES_DIR'] != conf.env['DBUS_SERVICES_DIR_REAL']:
214 display_msg(conf)
215 display_line(conf, "WARNING: D-Bus session services directory as reported by pkg-config is", 'RED')
216 display_raw_text(conf, "WARNING:", 'RED')
217 display_line(conf, conf.env['DBUS_SERVICES_DIR_REAL'], 'CYAN')
218 display_line(conf, 'WARNING: but service file will be installed in', 'RED')
219 display_raw_text(conf, "WARNING:", 'RED')
220 display_line(conf, conf.env['DBUS_SERVICES_DIR'], 'CYAN')
221 display_line(conf, 'WARNING: You may need to adjust your D-Bus configuration after installing ladish', 'RED')
222 display_line(conf, 'WARNING: You can override dbus service install directory', 'RED')
223 display_line(conf, 'WARNING: with --enable-pkg-config-dbus-service-dir option to this script', 'RED')
225 display_msg(conf, 'C compiler flags', conf.env['CCFLAGS'])
226 display_msg(conf, 'C++ compiler flags', conf.env['CXXFLAGS'])
228 display_msg(conf)
230 def build(bld):
231 daemon = bld.new_task_gen('cc', 'program')
232 daemon.target = 'ladishd'
233 daemon.includes = "build/default" # XXX config.h version.h and other generated files
234 daemon.uselib = 'DBUS-1 UUID EXPAT'
235 daemon.ver_header = 'version.h'
236 daemon.env.append_value("LINKFLAGS", ["-lutil", "-ldl", "-Wl,-E"])
238 daemon.source = [
239 'catdup.c',
242 for source in [
243 'main.c',
244 'loader.c',
245 'log.c',
246 'dirhelpers.c',
247 'sigsegv.c',
248 'proctitle.c',
249 'appdb.c',
250 'procfs.c',
251 'control.c',
252 'studio.c',
253 'graph.c',
254 'client.c',
255 'port.c',
256 'virtualizer.c',
257 'dict.c',
258 'graph_dict.c',
259 'escape.c',
260 'studio_jack_conf.c',
261 'save.c',
262 'load.c',
263 'cmd_load_studio.c',
264 'cmd_new_studio.c',
265 'cmd_rename_studio.c',
266 'cmd_save_studio.c',
267 'cmd_start_studio.c',
268 'cmd_stop_studio.c',
269 'cmd_unload_studio.c',
270 'cmd_new_app.c',
271 'cmd_change_app_state.c',
272 'cmd_remove_app.c',
273 'cmd_create_room.c',
274 'cmd_delete_room.c',
275 'cmd_save_project.c',
276 'cmd_unload_project.c',
277 'cmd_load_project.c',
278 'cmd_exit.c',
279 'cqueue.c',
280 'app_supervisor.c',
281 'room.c',
282 'room_save.c',
283 'room_load.c',
285 daemon.source.append(os.path.join("daemon", source))
287 for source in [
288 'jack_proxy.c',
289 'graph_proxy.c',
290 'a2j_proxy.c',
291 "jmcore_proxy.c",
292 "notify_proxy.c",
294 daemon.source.append(os.path.join("proxies", source))
296 for source in [
297 'signal.c',
298 'method.c',
299 'error.c',
300 'object_path.c',
301 'interface.c',
302 'helpers.c',
304 daemon.source.append(os.path.join("dbus", source))
306 for source in [
307 'time.c',
309 daemon.source.append(os.path.join("common", source))
311 # process dbus.service.in -> ladish.service
312 import misc
313 obj = bld.new_task_gen('subst')
314 obj.source = os.path.join('daemon', 'dbus.service.in')
315 obj.target = DBUS_NAME_BASE + '.service'
316 obj.dict = {'dbus_object_path': DBUS_NAME_BASE,
317 'daemon_bin_path': os.path.join(bld.env['PREFIX'], 'bin', daemon.target)}
318 obj.install_path = bld.env['DBUS_SERVICES_DIR'] + os.path.sep
319 obj.fun = misc.subst_func
321 #####################################################
322 # jmcore
323 jmcore = bld.new_task_gen('cc', 'program')
324 jmcore.target = 'jmcore'
325 jmcore.includes = "build/default" # XXX config.h version.h and other generated files
326 jmcore.uselib = 'DBUS-1 JACK'
327 jmcore.defines = ['LOG_OUTPUT_STDOUT']
328 jmcore.source = ['jmcore.c']
330 for source in [
331 #'signal.c',
332 'method.c',
333 'error.c',
334 'object_path.c',
335 'interface.c',
336 'helpers.c',
338 jmcore.source.append(os.path.join("dbus", source))
340 if bld.env['BUILD_LIBLASH']:
341 liblash = bld.new_task_gen('cc', 'shlib')
342 liblash.includes = "build/default" # XXX config.h version.h and other generated files
343 liblash.uselib = 'DBUS-1'
344 liblash.target = 'lash'
345 liblash.vnum = "1.1.1"
346 liblash.defines = ['LOG_OUTPUT_STDOUT']
347 liblash.source = [os.path.join("lash_compat", "liblash", 'lash.c')]
349 bld.install_files('${PREFIX}/include/lash', 'lash_compat/liblash/lash/*.h')
351 # process lash-1.0.pc.in -> lash-1.0.pc
352 obj = bld.new_task_gen('subst')
353 obj.source = [os.path.join("lash_compat", 'lash-1.0.pc.in')]
354 obj.target = 'lash-1.0.pc'
355 obj.dict = {'prefix': bld.env['PREFIX'],
356 'exec_prefix': bld.env['PREFIX'],
357 'libdir': bld.env['LIBDIR'],
358 'includedir': os.path.normpath(bld.env['PREFIX'] + '/include'),
360 obj.install_path = '${LIBDIR}/pkgconfig/'
361 obj.fun = misc.subst_func
363 obj = bld.new_task_gen('subst')
364 obj.source = os.path.join('daemon', 'dbus.service.in')
365 obj.target = DBUS_NAME_BASE + '.jmcore.service'
366 obj.dict = {'dbus_object_path': DBUS_NAME_BASE + ".jmcore",
367 'daemon_bin_path': os.path.join(bld.env['PREFIX'], 'bin', jmcore.target)}
368 obj.install_path = bld.env['DBUS_SERVICES_DIR'] + os.path.sep
369 obj.fun = misc.subst_func
371 #####################################################
372 # pylash
374 # pkgpyexec_LTLIBRARIES = _lash.la
375 # INCLUDES = $(PYTHON_INCLUDES)
376 # _lash_la_LDFLAGS = -module -avoid-version ../liblash/liblash.la
377 # _lash_la_SOURCES = lash.c lash.h lash_wrap.c
378 # pkgpyexec_SCRIPTS = lash.py
379 # CLEANFILES = lash_wrap.c lash.py lash.pyc zynjacku.defs
380 # EXTRA_DIST = test.py lash.i lash.py
381 # lash_wrap.c lash.py: lash.i lash.h
382 # swig -o lash_wrap.c -I$(top_srcdir) -python $(top_srcdir)/$(subdir)/lash.i
384 #####################################################
385 # gladish
386 if bld.env['BUILD_GLADISH']:
387 gladish = bld.new_task_gen('cxx', 'program')
388 gladish.features.append('cc')
389 gladish.target = 'gladish'
390 gladish.defines = ['LOG_OUTPUT_STDOUT']
391 gladish.includes = "build/default" # XXX config.h version.h and other generated files
392 gladish.uselib = 'DBUS-1 DBUS-GLIB-1 FLOWCANVAS'
394 gladish.source = [
395 'catdup.c',
398 for source in [
399 'main.c',
400 'load_project_dialog.c',
401 'save_project_dialog.c',
402 'world_tree.c',
403 'graph_view.c',
404 'canvas.cpp',
405 'graph_canvas.c',
406 'gtk_builder.c',
407 'ask_dialog.c',
408 'create_room_dialog.c',
409 'menu.c',
411 gladish.source.append(os.path.join("gui", source))
413 for source in [
414 'jack_proxy.c',
415 'graph_proxy.c',
416 'studio_proxy.c',
417 'control_proxy.c',
418 'app_supervisor_proxy.c',
419 "room_proxy.c",
421 gladish.source.append(os.path.join("proxies", source))
423 for source in [
424 'method.c',
425 'helpers.c',
427 gladish.source.append(os.path.join("dbus", source))
429 # GtkBuilder UI definitions (XML)
430 bld.install_files(bld.env['DATA_DIR'], 'gui/gladish.ui')
432 bld.install_files('${PREFIX}/bin', 'ladish_control', chmod=0755)
434 # 'Desktop' file (menu entry, icon, etc)
435 bld.install_files('${PREFIX}/share/applications/', 'gui/gladish.desktop', chmod=0644)
437 # Icons
438 icon_sizes = ['16x16', '22x22', '24x24', '32x32', '48x48', '256x256']
439 for icon_size in icon_sizes:
440 bld.install_files('${PREFIX}/share/icons/hicolor/' + icon_size + '/apps/', 'art/' + icon_size + '/apps/gladish.png')
442 status_images = []
443 for status in ["down", "unloaded", "started", "stopped", "warning", "error"]:
444 status_images.append("art/status_" + status + ".png")
446 bld.install_files(bld.env['DATA_DIR'], status_images)
447 bld.install_files(bld.env['DATA_DIR'], "art/ladish-logo-128x128.png")
448 bld.install_files(bld.env['DATA_DIR'], ["COPYING", "AUTHORS", "README", "NEWS"])
450 if bld.env['BUILD_DOXYGEN_DOCS'] == True:
451 html_docs_source_dir = "build/default/html"
452 if Options.commands['clean']:
453 if os.access(html_docs_source_dir, os.R_OK):
454 Utils.pprint('CYAN', "Removing doxygen generated documentation...")
455 shutil.rmtree(html_docs_source_dir)
456 Utils.pprint('CYAN', "Removing doxygen generated documentation done.")
457 elif Options.commands['build']:
458 if not os.access(html_docs_source_dir, os.R_OK):
459 os.popen("doxygen").read()
460 else:
461 Utils.pprint('CYAN', "doxygen documentation already built.")
463 def get_tags_dirs():
464 source_root = os.path.dirname(Utils.g_module.root_path)
465 if 'relpath' in os.path.__all__:
466 source_root = os.path.relpath(source_root)
467 paths = source_root
468 paths += " " + os.path.join(source_root, "common")
469 paths += " " + os.path.join(source_root, "dbus")
470 paths += " " + os.path.join(source_root, "proxies")
471 paths += " " + os.path.join(source_root, "daemon")
472 paths += " " + os.path.join(source_root, "gui")
473 paths += " " + os.path.join(source_root, "example-apps")
474 paths += " " + os.path.join(source_root, "lib")
475 paths += " " + os.path.join(source_root, "lash_compat", "liblash")
476 paths += " " + os.path.join(source_root, "lash_compat", "liblash", "lash")
477 return paths
479 def gtags(ctx):
480 '''build tag files for GNU global'''
481 cmd = "find %s -mindepth 1 -maxdepth 1 -name '*.[ch]' -print | gtags --statistics -f -" % get_tags_dirs()
482 #print("Running: %s" % cmd)
483 os.system(cmd)
485 def etags(ctx):
486 '''build TAGS file using etags'''
487 cmd = "find %s -mindepth 1 -maxdepth 1 -name '*.[ch]' -print | etags -" % get_tags_dirs()
488 #print("Running: %s" % cmd)
489 os.system(cmd)
490 os.system("stat -c '%y' TAGS")
492 def dist_hook():
493 shutil.copy('../build/default/version.h', "./")
495 import commands
496 from Constants import RUN_ME
497 from TaskGen import feature, after
498 import Task, Utils
500 @feature('cc')
501 @after('apply_core')
502 def process_git(self):
503 if getattr(self, 'ver_header', None):
504 tsk = self.create_task('git_ver')
505 tsk.set_outputs(self.path.find_or_declare(self.ver_header))
507 def git_ver(self):
508 header = self.outputs[0].abspath(self.env)
509 if os.access('../version.h', os.R_OK):
510 shutil.copy('../version.h', header)
511 data = file(header).read()
512 m = re.match(r'^#define GIT_VERSION "([^"]*)"$', data)
513 if m != None:
514 self.ver = m.group(1)
515 Utils.pprint('BLUE', "tarball from git revision " + self.ver)
516 else:
517 self.ver = "tarball"
518 return
520 if os.access('../.git', os.R_OK):
521 self.ver = commands.getoutput("LANG= git rev-parse HEAD").splitlines()[0]
522 if commands.getoutput("LANG= git diff-index --name-only HEAD").splitlines():
523 self.ver += "-dirty"
525 Utils.pprint('BLUE', "git revision " + self.ver)
526 else:
527 self.ver = "unknown"
529 fi = open(header, 'w')
530 fi.write('#define GIT_VERSION "%s"\n' % self.ver)
531 fi.close()
533 cls = Task.task_type_from_func('git_ver', vars=[], func=git_ver, color='BLUE', before='cc')
535 def always(self):
536 return RUN_ME
537 cls.runnable_status = always
539 def post_run(self):
540 sg = Utils.h_list(self.ver)
541 node = self.outputs[0]
542 variant = node.variant(self.env)
543 self.generator.bld.node_sigs[variant][node.id] = sg
544 cls.post_run = post_run