waf: fix creation of non-delatable directories
[ladish.git] / wscript
blobd138d008ffd5221122fb5622254e91d60ff0ef8a
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-rc'
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')
46 opt.add_option('--distnodeps', action='store_true', default=False, help="When creating distribution tarball, don't package git submodules")
48 def add_cflag(conf, flag):
49 conf.env.append_unique('CXXFLAGS', flag)
50 conf.env.append_unique('CCFLAGS', flag)
52 def add_linkflag(conf, flag):
53 conf.env.append_unique('LINKFLAGS', flag)
55 def check_gcc_optimizations_enabled(flags):
56 gcc_optimizations_enabled = False
57 for flag in flags:
58 if len(flag) < 2 or flag[0] != '-' or flag[1] != 'O':
59 continue
60 if len(flag) == 2:
61 gcc_optimizations_enabled = True;
62 else:
63 gcc_optimizations_enabled = flag[2] != '0';
64 return gcc_optimizations_enabled
66 def configure(conf):
67 conf.check_tool('compiler_cc')
68 conf.check_tool('compiler_cxx')
69 conf.check_tool('boost')
71 conf.check_cfg(
72 package = 'jack',
73 mandatory = True,
74 errmsg = "not installed, see http://jackaudio.org/",
75 args = '--cflags --libs')
77 conf.check_cfg(
78 package = 'dbus-1',
79 atleast_version = '1.0.0',
80 mandatory = True,
81 errmsg = "not installed, see http://dbus.freedesktop.org/",
82 args = '--cflags --libs')
84 dbus_dir = conf.check_cfg(package='dbus-1', args='--variable=session_bus_services_dir', msg="Retrieving D-Bus services dir")
85 if not dbus_dir:
86 return
88 dbus_dir = dbus_dir.strip()
89 conf.env['DBUS_SERVICES_DIR_REAL'] = dbus_dir
91 if Options.options.enable_pkg_config_dbus_service_dir:
92 conf.env['DBUS_SERVICES_DIR'] = dbus_dir
93 else:
94 conf.env['DBUS_SERVICES_DIR'] = os.path.join(os.path.normpath(conf.env['PREFIX']), 'share', 'dbus-1', 'services')
96 conf.env['LIBDIR'] = os.path.join(os.path.normpath(conf.env['PREFIX']), 'lib')
98 conf.env['BUILD_LIBLASH'] = Options.options.enable_liblash
99 conf.env['BUILD_DOXYGEN_DOCS'] = Options.options.doxygen
101 conf.check_cfg(
102 package = 'uuid',
103 mandatory = True,
104 errmsg = "not installed, see http://e2fsprogs.sourceforge.net/",
105 args = '--cflags --libs')
107 conf.check(
108 header_name='expat.h',
109 mandatory = True,
110 errmsg = "not installed, see http://expat.sourceforge.net/")
112 conf.env['LIB_EXPAT'] = ['expat']
114 build_gui = True
116 if build_gui and not conf.check_cfg(
117 package = 'glib-2.0',
118 mandatory = False,
119 errmsg = "not installed, see http://www.gtk.org/",
120 args = '--cflags --libs'):
121 build_gui = False
123 if build_gui and not conf.check_cfg(
124 package = 'dbus-glib-1',
125 mandatory = False,
126 errmsg = "not installed, see http://dbus.freedesktop.org/",
127 args = '--cflags --libs'):
128 build_gui = False
130 if build_gui and not conf.check_cfg(
131 package = 'gtk+-2.0',
132 mandatory = False,
133 atleast_version = '2.20.0',
134 errmsg = "not installed, see http://www.gtk.org/",
135 args = '--cflags --libs'):
136 build_gui = False
138 if build_gui and not conf.check_cfg(
139 package = 'flowcanvas',
140 mandatory = False,
141 atleast_version = '0.6.4',
142 errmsg = "not installed, see http://drobilla.net/software/flowcanvas/",
143 args = '--cflags --libs'):
144 build_gui = False
146 if build_gui:
147 # We need the boost headers package (e.g. libboost-dev)
148 # shared_ptr.hpp and weak_ptr.hpp
149 build_gui = conf.check_boost(errmsg="not found, see http://boost.org/")
151 conf.env['BUILD_GLADISH'] = build_gui
153 conf.env['BUILD_WERROR'] = not RELEASE
154 if conf.env['BUILD_WERROR']:
155 add_cflag(conf, '-Wall')
156 add_cflag(conf, '-Werror')
157 # for pre gcc-4.4, enable optimizations so use of uninitialized variables gets detected
158 try:
159 is_gcc = conf.env['CC_NAME'] == 'gcc'
160 if is_gcc:
161 gcc_ver = []
162 for n in conf.env['CC_VERSION']:
163 gcc_ver.append(int(n))
164 if gcc_ver[0] < 4 or gcc_ver[1] < 4:
165 #print "optimize force enable is required"
166 if not check_gcc_optimizations_enabled(conf.env['CCFLAGS']):
167 if Options.options.debug:
168 print "C optimization must be forced in order to enable -Wuninitialized"
169 print "However this will not be made because debug compilation is enabled"
170 else:
171 print "C optimization forced in order to enable -Wuninitialized"
172 conf.env.append_unique('CCFLAGS', "-O")
173 except:
174 pass
176 conf.env['BUILD_DEBUG'] = Options.options.debug
177 if conf.env['BUILD_DEBUG']:
178 add_cflag(conf, '-g')
179 add_cflag(conf, '-O0')
180 add_linkflag(conf, '-g')
182 conf.define('DATA_DIR', os.path.normpath(os.path.join(conf.env['PREFIX'], 'share', APPNAME)))
183 conf.define('PACKAGE_VERSION', VERSION)
184 conf.define('DBUS_NAME_BASE', DBUS_NAME_BASE)
185 conf.define('DBUS_BASE_PATH', '/' + DBUS_NAME_BASE.replace('.', '/'))
186 conf.define('BASE_NAME', APPNAME)
187 conf.define('_GNU_SOURCE', 1)
188 conf.write_config_header('config.h')
190 display_msg(conf)
192 display_msg(conf, "==================")
193 version_msg = APPNAME + "-" + VERSION
195 if os.access('version.h', os.R_OK):
196 data = file('version.h').read()
197 m = re.match(r'^#define GIT_VERSION "([^"]*)"$', data)
198 if m != None:
199 version_msg += " exported from " + m.group(1)
200 elif os.access('.git', os.R_OK):
201 version_msg += " git revision will checked and eventually updated during build"
203 display_msg(conf, version_msg)
205 display_msg(conf)
206 display_msg(conf, "Install prefix", conf.env['PREFIX'], 'CYAN')
208 display_msg(conf, 'Build gladish', yesno(conf.env['BUILD_GLADISH']))
209 display_msg(conf, 'Build liblash', yesno(Options.options.enable_liblash))
210 display_msg(conf, 'Treat warnings as errors', yesno(conf.env['BUILD_WERROR']))
211 display_msg(conf, 'Debuggable binaries', yesno(conf.env['BUILD_DEBUG']))
212 display_msg(conf, 'Build doxygen documentation', yesno(conf.env['BUILD_DOXYGEN_DOCS']))
214 if conf.env['DBUS_SERVICES_DIR'] != conf.env['DBUS_SERVICES_DIR_REAL']:
215 display_msg(conf)
216 display_line(conf, "WARNING: D-Bus session services directory as reported by pkg-config is", 'RED')
217 display_raw_text(conf, "WARNING:", 'RED')
218 display_line(conf, conf.env['DBUS_SERVICES_DIR_REAL'], 'CYAN')
219 display_line(conf, 'WARNING: but service file will be installed in', 'RED')
220 display_raw_text(conf, "WARNING:", 'RED')
221 display_line(conf, conf.env['DBUS_SERVICES_DIR'], 'CYAN')
222 display_line(conf, 'WARNING: You may need to adjust your D-Bus configuration after installing ladish', 'RED')
223 display_line(conf, 'WARNING: You can override dbus service install directory', 'RED')
224 display_line(conf, 'WARNING: with --enable-pkg-config-dbus-service-dir option to this script', 'RED')
226 display_msg(conf, 'C compiler flags', repr(conf.env['CCFLAGS']))
227 display_msg(conf, 'C++ compiler flags', repr(conf.env['CXXFLAGS']))
229 if not conf.env['BUILD_GLADISH']:
230 display_msg(conf)
231 display_line(conf, "WARNING: The GUI frontend will not built", 'RED')
233 display_msg(conf)
235 def build(bld):
236 daemon = bld.new_task_gen('cc', 'program')
237 daemon.target = 'ladishd'
238 daemon.includes = "build/default" # XXX config.h version.h and other generated files
239 daemon.uselib = 'DBUS-1 UUID EXPAT'
240 daemon.ver_header = 'version.h'
241 daemon.env.append_value("LINKFLAGS", ["-lutil", "-ldl", "-Wl,-E"])
243 daemon.source = [
244 'catdup.c',
247 for source in [
248 'main.c',
249 'loader.c',
250 'log.c',
251 'dirhelpers.c',
252 'sigsegv.c',
253 'proctitle.c',
254 'appdb.c',
255 'procfs.c',
256 'control.c',
257 'studio.c',
258 'graph.c',
259 'client.c',
260 'port.c',
261 'virtualizer.c',
262 'dict.c',
263 'graph_dict.c',
264 'escape.c',
265 'studio_jack_conf.c',
266 'save.c',
267 'load.c',
268 'cmd_load_studio.c',
269 'cmd_new_studio.c',
270 'cmd_rename_studio.c',
271 'cmd_save_studio.c',
272 'cmd_start_studio.c',
273 'cmd_stop_studio.c',
274 'cmd_unload_studio.c',
275 'cmd_new_app.c',
276 'cmd_change_app_state.c',
277 'cmd_remove_app.c',
278 'cmd_create_room.c',
279 'cmd_delete_room.c',
280 'cmd_save_project.c',
281 'cmd_unload_project.c',
282 'cmd_load_project.c',
283 'cmd_exit.c',
284 'cqueue.c',
285 'app_supervisor.c',
286 'room.c',
287 'room_save.c',
288 'room_load.c',
290 daemon.source.append(os.path.join("daemon", source))
292 for source in [
293 'jack_proxy.c',
294 'graph_proxy.c',
295 'a2j_proxy.c',
296 "jmcore_proxy.c",
297 "notify_proxy.c",
299 daemon.source.append(os.path.join("proxies", source))
301 for source in [
302 'signal.c',
303 'method.c',
304 'error.c',
305 'object_path.c',
306 'interface.c',
307 'helpers.c',
309 daemon.source.append(os.path.join("dbus", source))
311 for source in [
312 'time.c',
314 daemon.source.append(os.path.join("common", source))
316 # process dbus.service.in -> ladish.service
317 import misc
318 obj = bld.new_task_gen('subst')
319 obj.source = os.path.join('daemon', 'dbus.service.in')
320 obj.target = DBUS_NAME_BASE + '.service'
321 obj.dict = {'dbus_object_path': DBUS_NAME_BASE,
322 'daemon_bin_path': os.path.join(bld.env['PREFIX'], 'bin', daemon.target)}
323 obj.install_path = bld.env['DBUS_SERVICES_DIR'] + os.path.sep
324 obj.fun = misc.subst_func
326 #####################################################
327 # jmcore
328 jmcore = bld.new_task_gen('cc', 'program')
329 jmcore.target = 'jmcore'
330 jmcore.includes = "build/default" # XXX config.h version.h and other generated files
331 jmcore.uselib = 'DBUS-1 JACK'
332 jmcore.defines = ['LOG_OUTPUT_STDOUT']
333 jmcore.source = ['jmcore.c']
335 for source in [
336 #'signal.c',
337 'method.c',
338 'error.c',
339 'object_path.c',
340 'interface.c',
341 'helpers.c',
343 jmcore.source.append(os.path.join("dbus", source))
345 if bld.env['BUILD_LIBLASH']:
346 liblash = bld.new_task_gen('cc', 'shlib')
347 liblash.includes = "build/default" # XXX config.h version.h and other generated files
348 liblash.uselib = 'DBUS-1'
349 liblash.target = 'lash'
350 liblash.vnum = "1.1.1"
351 liblash.defines = ['LOG_OUTPUT_STDOUT']
352 liblash.source = [os.path.join("lash_compat", "liblash", 'lash.c')]
354 bld.install_files('${PREFIX}/include/lash', 'lash_compat/liblash/lash/*.h')
356 # process lash-1.0.pc.in -> lash-1.0.pc
357 obj = bld.new_task_gen('subst')
358 obj.source = [os.path.join("lash_compat", 'lash-1.0.pc.in')]
359 obj.target = 'lash-1.0.pc'
360 obj.dict = {'prefix': bld.env['PREFIX'],
361 'exec_prefix': bld.env['PREFIX'],
362 'libdir': bld.env['LIBDIR'],
363 'includedir': os.path.normpath(bld.env['PREFIX'] + '/include'),
365 obj.install_path = '${LIBDIR}/pkgconfig/'
366 obj.fun = misc.subst_func
368 obj = bld.new_task_gen('subst')
369 obj.source = os.path.join('daemon', 'dbus.service.in')
370 obj.target = DBUS_NAME_BASE + '.jmcore.service'
371 obj.dict = {'dbus_object_path': DBUS_NAME_BASE + ".jmcore",
372 'daemon_bin_path': os.path.join(bld.env['PREFIX'], 'bin', jmcore.target)}
373 obj.install_path = bld.env['DBUS_SERVICES_DIR'] + os.path.sep
374 obj.fun = misc.subst_func
376 #####################################################
377 # pylash
379 # pkgpyexec_LTLIBRARIES = _lash.la
380 # INCLUDES = $(PYTHON_INCLUDES)
381 # _lash_la_LDFLAGS = -module -avoid-version ../liblash/liblash.la
382 # _lash_la_SOURCES = lash.c lash.h lash_wrap.c
383 # pkgpyexec_SCRIPTS = lash.py
384 # CLEANFILES = lash_wrap.c lash.py lash.pyc zynjacku.defs
385 # EXTRA_DIST = test.py lash.i lash.py
386 # lash_wrap.c lash.py: lash.i lash.h
387 # swig -o lash_wrap.c -I$(top_srcdir) -python $(top_srcdir)/$(subdir)/lash.i
389 #####################################################
390 # gladish
391 if bld.env['BUILD_GLADISH']:
392 gladish = bld.new_task_gen('cxx', 'program')
393 gladish.features.append('cc')
394 gladish.target = 'gladish'
395 gladish.defines = ['LOG_OUTPUT_STDOUT']
396 gladish.includes = "build/default" # XXX config.h version.h and other generated files
397 gladish.uselib = 'DBUS-1 DBUS-GLIB-1 FLOWCANVAS'
399 gladish.source = [
400 'catdup.c',
403 for source in [
404 'main.c',
405 'load_project_dialog.c',
406 'save_project_dialog.c',
407 'world_tree.c',
408 'graph_view.c',
409 'canvas.cpp',
410 'graph_canvas.c',
411 'gtk_builder.c',
412 'ask_dialog.c',
413 'create_room_dialog.c',
414 'menu.c',
415 'about.c',
416 'dbus.c',
417 'studio.c',
418 'studio_list.c',
419 'dialogs.c',
420 'jack.c',
421 'control.c',
422 'pixbuf.c',
423 'room.c',
424 'statusbar.c',
425 'action.c',
427 gladish.source.append(os.path.join("gui", source))
429 for source in [
430 'jack_proxy.c',
431 'graph_proxy.c',
432 'studio_proxy.c',
433 'control_proxy.c',
434 'app_supervisor_proxy.c',
435 "room_proxy.c",
437 gladish.source.append(os.path.join("proxies", source))
439 for source in [
440 'method.c',
441 'helpers.c',
443 gladish.source.append(os.path.join("dbus", source))
445 # GtkBuilder UI definitions (XML)
446 bld.install_files(bld.env['DATA_DIR'], 'gui/gladish.ui')
448 bld.install_files('${PREFIX}/bin', 'ladish_control', chmod=0755)
450 # 'Desktop' file (menu entry, icon, etc)
451 bld.install_files('${PREFIX}/share/applications/', 'gui/gladish.desktop', chmod=0644)
453 # Icons
454 icon_sizes = ['16x16', '22x22', '24x24', '32x32', '48x48', '256x256']
455 for icon_size in icon_sizes:
456 bld.path.ant_glob('art/' + icon_size + '/apps/*.png')
457 bld.install_files('${PREFIX}/share/icons/hicolor/' + icon_size + '/apps/', 'art/' + icon_size + '/apps/gladish.png')
459 status_images = []
460 for status in ["down", "unloaded", "started", "stopped", "warning", "error"]:
461 status_images.append("art/status_" + status + ".png")
463 bld.install_files(bld.env['DATA_DIR'], status_images)
464 bld.install_files(bld.env['DATA_DIR'], "art/ladish-logo-128x128.png")
465 bld.install_files(bld.env['DATA_DIR'], ["COPYING", "AUTHORS", "README", "NEWS"])
467 if bld.env['BUILD_DOXYGEN_DOCS'] == True:
468 html_docs_source_dir = "build/default/html"
469 if Options.commands['clean']:
470 if os.access(html_docs_source_dir, os.R_OK):
471 Utils.pprint('CYAN', "Removing doxygen generated documentation...")
472 shutil.rmtree(html_docs_source_dir)
473 Utils.pprint('CYAN', "Removing doxygen generated documentation done.")
474 elif Options.commands['build']:
475 if not os.access(html_docs_source_dir, os.R_OK):
476 os.popen("doxygen").read()
477 else:
478 Utils.pprint('CYAN', "doxygen documentation already built.")
480 def get_tags_dirs():
481 source_root = os.path.dirname(Utils.g_module.root_path)
482 if 'relpath' in os.path.__all__:
483 source_root = os.path.relpath(source_root)
484 paths = source_root
485 paths += " " + os.path.join(source_root, "common")
486 paths += " " + os.path.join(source_root, "dbus")
487 paths += " " + os.path.join(source_root, "proxies")
488 paths += " " + os.path.join(source_root, "daemon")
489 paths += " " + os.path.join(source_root, "gui")
490 paths += " " + os.path.join(source_root, "example-apps")
491 paths += " " + os.path.join(source_root, "lib")
492 paths += " " + os.path.join(source_root, "lash_compat", "liblash")
493 paths += " " + os.path.join(source_root, "lash_compat", "liblash", "lash")
494 return paths
496 def gtags(ctx):
497 '''build tag files for GNU global'''
498 cmd = "find %s -mindepth 1 -maxdepth 1 -name '*.[ch]' -print | gtags --statistics -f -" % get_tags_dirs()
499 #print("Running: %s" % cmd)
500 os.system(cmd)
502 def etags(ctx):
503 '''build TAGS file using etags'''
504 cmd = "find %s -mindepth 1 -maxdepth 1 -name '*.[ch]' -print | etags -" % get_tags_dirs()
505 #print("Running: %s" % cmd)
506 os.system(cmd)
507 os.system("stat -c '%y' TAGS")
509 def dist_hook():
510 #print repr(Options.options)
511 if Options.options.distnodeps:
512 shutil.rmtree('laditools')
513 shutil.rmtree('flowcanvas')
514 shutil.rmtree('jack2')
515 shutil.rmtree('a2jmidid')
516 nodist_files = ['.gitmodules', 'GTAGS', 'GRTAGS', 'GPATH', 'GSYMS'] # waf does not ignore these file
517 for nodist_file in nodist_files:
518 os.remove(nodist_file)
519 shutil.copy('../build/default/version.h', "./")
521 import commands
522 from Constants import RUN_ME
523 from TaskGen import feature, after
524 import Task, Utils
526 @feature('cc')
527 @after('apply_core')
528 def process_git(self):
529 if getattr(self, 'ver_header', None):
530 tsk = self.create_task('git_ver')
531 tsk.set_outputs(self.path.find_or_declare(self.ver_header))
533 def git_ver(self):
534 header = self.outputs[0].abspath(self.env)
535 if os.access('../version.h', os.R_OK):
536 shutil.copy('../version.h', header)
537 data = file(header).read()
538 m = re.match(r'^#define GIT_VERSION "([^"]*)"$', data)
539 if m != None:
540 self.ver = m.group(1)
541 Utils.pprint('BLUE', "tarball from git revision " + self.ver)
542 else:
543 self.ver = "tarball"
544 return
546 if os.access('../.git', os.R_OK):
547 self.ver = commands.getoutput("LANG= git rev-parse HEAD").splitlines()[0]
548 if commands.getoutput("LANG= git diff-index --name-only HEAD").splitlines():
549 self.ver += "-dirty"
551 Utils.pprint('BLUE', "git revision " + self.ver)
552 else:
553 self.ver = "unknown"
555 fi = open(header, 'w')
556 fi.write('#define GIT_VERSION "%s"\n' % self.ver)
557 fi.close()
559 cls = Task.task_type_from_func('git_ver', vars=[], func=git_ver, color='BLUE', before='cc')
561 def always(self):
562 return RUN_ME
563 cls.runnable_status = always
565 def post_run(self):
566 sg = Utils.h_list(self.ver)
567 node = self.outputs[0]
568 variant = node.variant(self.env)
569 self.generator.bld.node_sigs[variant][node.id] = sg
570 cls.post_run = post_run