Prepare 1.9.12 release
[jack2.git] / wscript
blob3ee472df5ade780187f8087ff57f95b81844e824
1 #! /usr/bin/env python
2 # encoding: utf-8
3 from __future__ import print_function
5 import os
6 import subprocess
7 import shutil
8 import re
9 import sys
11 from waflib import Logs, Options, Task, Utils
12 from waflib.Build import BuildContext, CleanContext, InstallContext, UninstallContext
14 VERSION='1.9.12'
15 APPNAME='jack'
16 JACK_API_VERSION = '0.1.0'
18 # these variables are mandatory ('/' are converted automatically)
19 top = '.'
20 out = 'build'
22 # lib32 variant name used when building in mixed mode
23 lib32 = 'lib32'
25 auto_options = []
27 def display_feature(conf, msg, build):
28 if build:
29 conf.msg(msg, 'yes', color='GREEN')
30 else:
31 conf.msg(msg, 'no', color='YELLOW')
33 # This function prints an error without stopping waf. The reason waf should not
34 # be stopped is to be able to list all missing dependencies in one chunk.
35 def print_error(msg):
36 print(Logs.colors.RED + msg + Logs.colors.NORMAL)
38 class AutoOption:
39 """
40 This class is the foundation for the auto options. It adds an option
41 --foo=no|yes to the list of options and deals with all logic and checks for
42 these options.
44 Each option can have different dependencies that will be checked. If all
45 dependencies are available and the user has not done any request the option
46 will be enabled. If the user has requested to enable the option the class
47 ensures that all dependencies are available and prints an error message
48 otherwise. If the user disables the option, i.e. --foo=no, no checks are
49 made.
51 For each option it is possible to add packages that are required for the
52 option using the add_package function. For dependency programs add_program
53 should be used. For libraries (without pkg-config support) the add_library
54 function should be used. For headers the add_header function exists. If
55 there is another type of requirement or dependency the check hook (an
56 external function called when configuring) can be used.
58 When all checks have been made and the class has made a decision the result
59 is saved in conf.env['NAME'] where 'NAME' by default is the uppercase of the
60 name argument to __init__, but it can be changed with the conf_dest argument
61 to __init__.
63 The class will define a preprocessor symbol with the result. The default
64 name is HAVE_NAME, but it can be changed using the define argument to
65 __init__.
66 """
68 def __init__(self, opt, name, help, conf_dest=None, define=None):
69 # check hook to call upon configuration
70 self.check_hook = None
71 self.check_hook_error = None
72 self.check_hook_found = True
74 # required libraries
75 self.libs = [] # elements on the form [lib,uselib_store]
76 self.libs_not_found = [] # elements on the form lib
78 # required headers
79 self.headers = []
80 self.headers_not_found = []
82 # required packages (checked with pkg-config)
83 self.packages = [] # elements on the form [package,uselib_store,atleast_version]
84 self.packages_not_found = [] # elements on the form [package,atleast_version]
86 # required programs
87 self.programs = [] # elements on the form [program,var]
88 self.programs_not_found = [] # elements on the form program
90 # the result of the configuration (should the option be enabled or not?)
91 self.result = False
93 self.help = help
94 self.option = '--' + name
95 self.dest = 'auto_option_' + name
96 if conf_dest:
97 self.conf_dest = conf_dest
98 else:
99 self.conf_dest = name.upper()
100 if not define:
101 self.define = 'HAVE_' + name.upper()
102 else:
103 self.define = define
104 opt.add_option(self.option, type='string', default='auto', dest=self.dest, help=self.help+' (enabled by default if possible)', metavar='no|yes')
106 def add_library(self, library, uselib_store=None):
108 Add a required library that should be checked during configuration. The
109 library will be checked using the conf.check function. If the
110 uselib_store arugment is not given it defaults to LIBRARY (the uppercase
111 of the library argument). The uselib_store argument will be passed to
112 check which means LIB_LIBRARY, CFLAGS_LIBRARY and DEFINES_LIBRARY, etc.
113 will be defined if the option is enabled.
115 if not uselib_store:
116 uselib_store = library.upper().replace('-', '_')
117 self.libs.append([library, uselib_store])
119 def add_header(self, header):
121 Add a required header that should be checked during configuration. The
122 header will be checked using the conf.check function which means
123 HAVE_HEADER_H will be defined if found.
125 self.headers.append(header)
127 def add_package(self, package, uselib_store=None, atleast_version=None):
129 Add a required package that should be checked using pkg-config during
130 configuration. The package will be checked using the conf.check_cfg
131 function and the uselib_store and atleast_version will be passed to
132 check_cfg. If uselib_store is None it defaults to PACKAGE (uppercase of
133 the package argument) with hyphens and dots replaced with underscores.
134 If atleast_version is None it defaults to '0'.
136 if not uselib_store:
137 uselib_store = package.upper().replace('-', '_').replace('.', '_')
138 if not atleast_version:
139 atleast_version = '0'
140 self.packages.append([package, uselib_store, atleast_version])
142 def add_program(self, program, var=None):
144 Add a required program that should be checked during configuration. If
145 var is not given it defaults to PROGRAM (the uppercase of the program
146 argument). If the option is enabled the program is saved as a list (?!)
147 in conf.env['PROGRAM'].
149 if not var:
150 var = program.upper().replace('-', '_')
151 self.programs.append([program, var])
153 def set_check_hook(self, check_hook, check_hook_error):
155 Set the check hook and the corresponding error printing function to the
156 configure step. The check_hook argument is a function that should return
157 True if the extra prerequisites were found and False if not. The
158 check_hook_error argument is an error printing function that should
159 print an error message telling the user that --foo was explicitly
160 requested but cannot be built since the extra prerequisites were not
161 found. Both function should take a single argument that is the waf
162 configuration context.
164 self.check_hook = check_hook
165 self.check_hook_error = check_hook_error
167 def _check(self, conf):
169 This is an internal function that runs all necessary configure checks.
170 It checks all dependencies (even if some dependency was not found) so
171 that the user can install all missing dependencies in one go, instead
172 of playing the infamous hit-configure-hit-configure game.
174 This function returns True if all dependencies were found and False if
175 not.
177 all_found = True
179 # Use-variables that should be used when checking libraries, headers and
180 # programs. The list will be populated when looking for packages.
181 use = []
183 # check for packages
184 for package,uselib_store,atleast_version in self.packages:
185 try:
186 conf.check_cfg(package=package, uselib_store=uselib_store, atleast_version=atleast_version, args='--cflags --libs')
187 use.append(uselib_store)
188 except conf.errors.ConfigurationError:
189 all_found = False
190 self.packages_not_found.append([package,atleast_version])
192 # check for libraries
193 for lib,uselib_store in self.libs:
194 try:
195 conf.check(lib=lib, uselib_store=uselib_store, use=use)
196 except conf.errors.ConfigurationError:
197 all_found = False
198 self.libs_not_found.append(lib)
200 # check for headers
201 for header in self.headers:
202 try:
203 conf.check(header_name=header, use=use)
204 except conf.errors.ConfigurationError:
205 all_found = False
206 self.headers_not_found.append(header)
208 # check for programs
209 for program,var in self.programs:
210 try:
211 conf.find_program(program, var=var, use=use)
212 except conf.errors.ConfigurationError:
213 all_found = False
214 self.programs_not_found.append(program)
216 # call hook (if specified)
217 if self.check_hook:
218 self.check_hook_found = self.check_hook(conf)
219 if not self.check_hook_found:
220 all_found = False
222 return all_found
224 def _configure_error(self, conf):
226 This is an internal function that prints errors for each missing
227 dependency. The error messages tell the user that this option required
228 some dependency, but it cannot be found.
231 for lib in self.libs_not_found:
232 print_error('%s requires the %s library, but it cannot be found.' % (self.option, lib))
234 for header in self.headers_not_found:
235 print_error('%s requires the %s header, but it cannot be found.' % (self.option, header))
237 for package,atleast_version in self.packages_not_found:
238 string = package
239 if atleast_version:
240 string += ' >= ' + atleast_version
241 print_error('%s requires the package %s, but it cannot be found.' % (self.option, string))
243 for program in self.programs_not_found:
244 print_error('%s requires the %s program, but it cannot be found.' % (self.option, program))
246 if not self.check_hook_found:
247 self.check_hook_error(conf)
249 def configure(self, conf):
251 This function configures the option examining the argument given too
252 --foo (where foo is this option). This function sets self.result to the
253 result of the configuration; True if the option should be enabled or
254 False if not. If not all dependencies were found self.result will shall
255 be False. conf.env['NAME'] will be set to the same value aswell as a
256 preprocessor symbol will be defined according to the result.
258 If --foo[=yes] was given, but some dependency was not found an error
259 message is printed (foreach missing dependency).
261 This function returns True on success and False on error.
263 argument = getattr(Options.options, self.dest)
264 if argument == 'no':
265 self.result = False
266 retvalue = True
267 elif argument == 'yes':
268 if self._check(conf):
269 self.result = True
270 retvalue = True
271 else:
272 self.result = False
273 retvalue = False
274 self._configure_error(conf)
275 elif argument == 'auto':
276 self.result = self._check(conf)
277 retvalue = True
278 else:
279 print_error('Invalid argument "' + argument + '" to ' + self.option)
280 self.result = False
281 retvalue = False
283 conf.env[self.conf_dest] = self.result
284 if self.result:
285 conf.define(self.define, 1)
286 else:
287 conf.define(self.define, 0)
288 return retvalue
290 def display_message(self, conf):
292 This function displays a result message with the help text and the
293 result of the configuration.
295 display_feature(conf, self.help, self.result)
297 # This function adds an option to the list of auto options and returns the newly
298 # created option.
299 def add_auto_option(opt, name, help, conf_dest=None, define=None):
300 option = AutoOption(opt, name, help, conf_dest=conf_dest, define=define)
301 auto_options.append(option)
302 return option
304 # This function applies a hack that for each auto option --foo=no|yes replaces
305 # any occurence --foo in argv with --foo=yes, in effect interpreting --foo as
306 # --foo=yes. The function has to be called before waf issues the option parser,
307 # i.e. before the configure phase.
308 def auto_options_argv_hack():
309 for option in auto_options:
310 for x in range(1, len(sys.argv)):
311 if sys.argv[x] == option.option:
312 sys.argv[x] += '=yes'
314 # This function configures all auto options. It stops waf and prints an error
315 # message if there were unsatisfied requirements.
316 def configure_auto_options(conf):
317 ok = True
318 for option in auto_options:
319 if not option.configure(conf):
320 ok = False
321 if not ok:
322 conf.fatal('There were unsatisfied requirements.')
324 # This function displays all options and the configuration results.
325 def display_auto_options_messages(conf):
326 for option in auto_options:
327 option.display_message(conf)
329 def check_for_celt(conf):
330 found = False
331 for version in ['11', '8', '7', '5']:
332 define = 'HAVE_CELT_API_0_' + version
333 if not found:
334 try:
335 conf.check_cfg(package='celt', atleast_version='0.' + version + '.0', args='--cflags --libs')
336 found = True
337 conf.define(define, 1)
338 continue
339 except conf.errors.ConfigurationError:
340 pass
341 conf.define(define, 0)
342 return found
344 def check_for_celt_error(conf):
345 print_error('--celt requires the package celt, but it could not be found.')
347 # The readline/readline.h header does not work if stdio.h is not included
348 # before. Thus a fragment with both stdio.h and readline/readline.h need to be
349 # test-compiled to find out whether readline is available.
350 def check_for_readline(conf):
351 # FIXME: This check can be incorporated into the AutoOptions class by
352 # passing header_name=['stdio.h', 'readline/readline.h'] to check.
353 try:
354 conf.check(fragment='''
355 #include <stdio.h>
356 #include <readline/readline.h>
357 int main(void) { return 0; }''',
358 execute=False,
359 msg='Checking for header readline/readline.h',
360 errmsg='not found')
361 return True
362 except conf.errors.ConfigurationError:
363 return False
365 def check_for_readline_error(conf):
366 print_error('--readline requires the readline/readline.h header, but it cannot be found.')
368 def check_for_mmsystem(conf):
369 # FIXME: See comment in check_for_readline.
370 try:
371 conf.check(fragment='''
372 #include <windows.h>
373 #include <mmsystem.h>
374 int main(void) { return 0; }''',
375 execute=False,
376 msg='Checking for header mmsystem.h',
377 errmsg='not found')
378 return True
379 except conf.errors.ConfigurationError:
380 return False
382 def check_for_mmsystem_error(conf):
383 print_error('--winmme requires the mmsystem.h header, but it cannot be found.')
385 def options(opt):
386 # options provided by the modules
387 opt.load('compiler_cxx')
388 opt.load('compiler_c')
390 opt.load('xcode')
391 opt.load('xcode6')
393 # install directories
394 opt.add_option('--htmldir', type='string', default=None, help='HTML documentation directory [Default: <prefix>/share/jack-audio-connection-kit/reference/html/')
395 opt.add_option('--libdir', type='string', help='Library directory [Default: <prefix>/lib]')
396 opt.add_option('--libdir32', type='string', help='32bit Library directory [Default: <prefix>/lib32]')
397 opt.add_option('--mandir', type='string', help='Manpage directory [Default: <prefix>/share/man/man1]')
399 # options affecting binaries
400 opt.add_option('--platform', type='string', default=sys.platform, help='Target platform for cross-compiling, e.g. cygwin or win32')
401 opt.add_option('--mixed', action='store_true', default=False, help='Build with 32/64 bits mixed mode')
402 opt.add_option('--debug', action='store_true', default=False, dest='debug', help='Build debuggable binaries')
404 # options affecting general jack functionality
405 opt.add_option('--classic', action='store_true', default=False, help='Force enable standard JACK (jackd) even if D-Bus JACK (jackdbus) is enabled too')
406 opt.add_option('--dbus', action='store_true', default=False, help='Enable D-Bus JACK (jackdbus)')
407 opt.add_option('--autostart', type='string', default='default', help='Autostart method. Possible values: "default", "classic", "dbus", "none"')
408 opt.add_option('--profile', action='store_true', default=False, help='Build with engine profiling')
409 opt.add_option('--clients', default=64, type='int', dest='clients', help='Maximum number of JACK clients')
410 opt.add_option('--ports-per-application', default=768, type='int', dest='application_ports', help='Maximum number of ports per application')
412 # options with third party dependencies
413 doxygen = add_auto_option(opt, 'doxygen', help='Build doxygen documentation', conf_dest='BUILD_DOXYGEN_DOCS')
414 doxygen.add_program('doxygen')
415 alsa = add_auto_option(opt, 'alsa', help='Enable ALSA driver', conf_dest='BUILD_DRIVER_ALSA')
416 alsa.add_package('alsa', atleast_version='1.0.18')
417 firewire = add_auto_option(opt, 'firewire', help='Enable FireWire driver (FFADO)', conf_dest='BUILD_DRIVER_FFADO')
418 firewire.add_package('libffado', atleast_version='1.999.17')
419 freebob = add_auto_option(opt, 'freebob', help='Enable FreeBob driver')
420 freebob.add_package('libfreebob', atleast_version='1.0.0')
421 iio = add_auto_option(opt, 'iio', help='Enable IIO driver', conf_dest='BUILD_DRIVER_IIO')
422 iio.add_package('gtkIOStream', atleast_version='1.4.0')
423 iio.add_package('eigen3', atleast_version='3.1.2')
424 portaudio = add_auto_option(opt, 'portaudio', help='Enable Portaudio driver', conf_dest='BUILD_DRIVER_PORTAUDIO')
425 portaudio.add_header('windows.h') # only build portaudio on windows
426 portaudio.add_package('portaudio-2.0', uselib_store='PORTAUDIO', atleast_version='19')
427 winmme = add_auto_option(opt, 'winmme', help='Enable WinMME driver', conf_dest='BUILD_DRIVER_WINMME')
428 winmme.set_check_hook(check_for_mmsystem, check_for_mmsystem_error)
430 celt = add_auto_option(opt, 'celt', help='Build with CELT')
431 celt.set_check_hook(check_for_celt, check_for_celt_error)
432 opus = add_auto_option(opt, 'opus', help='Build Opus netjack2')
433 opus.add_header('opus/opus_custom.h')
434 opus.add_package('opus', atleast_version='0.9.0')
435 samplerate = add_auto_option(opt, 'samplerate', help='Build with libsamplerate')
436 samplerate.add_package('samplerate')
437 sndfile = add_auto_option(opt, 'sndfile', help='Build with libsndfile')
438 sndfile.add_package('sndfile')
439 readline = add_auto_option(opt, 'readline', help='Build with readline')
440 readline.add_library('readline')
441 readline.set_check_hook(check_for_readline, check_for_readline_error)
443 # dbus options
444 opt.recurse('dbus')
446 # this must be called before the configure phase
447 auto_options_argv_hack()
449 def detect_platform(conf):
450 # GNU/kFreeBSD and GNU/Hurd are treated as Linux
451 platforms = [
452 # ('KEY, 'Human readable name', ['strings', 'to', 'check', 'for'])
453 ('IS_LINUX', 'Linux', ['gnu0', 'gnukfreebsd', 'linux', 'posix']),
454 ('IS_MACOSX', 'MacOS X', ['darwin']),
455 ('IS_SUN', 'SunOS', ['sunos']),
456 ('IS_WINDOWS', 'Windows', ['cygwin', 'msys', 'win32'])
459 for key,name,strings in platforms:
460 conf.env[key] = False
462 conf.start_msg('Checking platform')
463 platform = Options.options.platform
464 for key,name,strings in platforms:
465 for s in strings:
466 if platform.startswith(s):
467 conf.env[key] = True
468 conf.end_msg(name, color='CYAN')
469 break
471 def configure(conf):
472 conf.load('compiler_cxx')
473 conf.load('compiler_c')
475 detect_platform(conf)
477 if conf.env['IS_WINDOWS']:
478 conf.env.append_unique('CCDEFINES', '_POSIX')
479 conf.env.append_unique('CXXDEFINES', '_POSIX')
481 conf.env.append_unique('CXXFLAGS', '-Wall')
482 conf.env.append_unique('CFLAGS', '-Wall')
484 if conf.env['IS_MACOSX']:
485 conf.check(lib='aften', uselib='AFTEN', define_name='AFTEN')
487 # configure all auto options
488 configure_auto_options(conf)
490 # Check for functions.
491 conf.check(
492 function_name='ppoll',
493 header_name=['poll.h', 'signal.h'],
494 defines=['_GNU_SOURCE'],
495 mandatory=False)
497 # Check for backtrace support
498 conf.check(
499 header_name='execinfo.h',
500 define_name='HAVE_EXECINFO_H',
501 mandatory=False)
503 conf.recurse('common')
504 if Options.options.dbus:
505 conf.recurse('dbus')
506 if conf.env['BUILD_JACKDBUS'] != True:
507 conf.fatal('jackdbus was explicitly requested but cannot be built')
509 conf.recurse('example-clients')
511 # test for the availability of ucontext, and how it should be used
512 for t in ['gp_regs', 'uc_regs', 'mc_gregs', 'gregs']:
513 fragment = '#include <ucontext.h>\n'
514 fragment += 'int main() { ucontext_t *ucontext; return (int) ucontext->uc_mcontext.%s[0]; }' % t
515 confvar = 'HAVE_UCONTEXT_%s' % t.upper()
516 conf.check_cc(fragment=fragment, define_name=confvar, mandatory=False,
517 msg='Checking for ucontext->uc_mcontext.%s' % t)
518 if conf.is_defined(confvar):
519 conf.define('HAVE_UCONTEXT', 1)
521 fragment = '#include <ucontext.h>\n'
522 fragment += 'int main() { return NGREG; }'
523 conf.check_cc(fragment=fragment, define_name='HAVE_NGREG', mandatory=False,
524 msg='Checking for NGREG')
526 conf.env['LIB_PTHREAD'] = ['pthread']
527 conf.env['LIB_DL'] = ['dl']
528 conf.env['LIB_RT'] = ['rt']
529 conf.env['LIB_M'] = ['m']
530 conf.env['LIB_STDC++'] = ['stdc++']
531 conf.env['JACK_API_VERSION'] = JACK_API_VERSION
532 conf.env['JACK_VERSION'] = VERSION
534 conf.env['BUILD_WITH_PROFILE'] = Options.options.profile
535 conf.env['BUILD_WITH_32_64'] = Options.options.mixed
536 conf.env['BUILD_CLASSIC'] = Options.options.classic
537 conf.env['BUILD_DEBUG'] = Options.options.debug
539 if conf.env['BUILD_JACKDBUS']:
540 conf.env['BUILD_JACKD'] = conf.env['BUILD_CLASSIC']
541 else:
542 conf.env['BUILD_JACKD'] = True
544 conf.env['BINDIR'] = conf.env['PREFIX'] + '/bin'
546 if Options.options.htmldir:
547 conf.env['HTMLDIR'] = Options.options.htmldir
548 else:
549 # set to None here so that the doxygen code can find out the highest
550 # directory to remove upon install
551 conf.env['HTMLDIR'] = None
553 if Options.options.libdir:
554 conf.env['LIBDIR'] = Options.options.libdir
555 else:
556 conf.env['LIBDIR'] = conf.env['PREFIX'] + '/lib'
558 if Options.options.mandir:
559 conf.env['MANDIR'] = Options.options.mandir
560 else:
561 conf.env['MANDIR'] = conf.env['PREFIX'] + '/share/man/man1'
563 if conf.env['BUILD_DEBUG']:
564 conf.env.append_unique('CXXFLAGS', '-g')
565 conf.env.append_unique('CFLAGS', '-g')
566 conf.env.append_unique('LINKFLAGS', '-g')
568 if not Options.options.autostart in ['default', 'classic', 'dbus', 'none']:
569 conf.fatal('Invalid autostart value "' + Options.options.autostart + '"')
571 if Options.options.autostart == 'default':
572 if conf.env['BUILD_JACKD']:
573 conf.env['AUTOSTART_METHOD'] = 'classic'
574 else:
575 conf.env['AUTOSTART_METHOD'] = 'dbus'
576 else:
577 conf.env['AUTOSTART_METHOD'] = Options.options.autostart
579 if conf.env['AUTOSTART_METHOD'] == 'dbus' and not conf.env['BUILD_JACKDBUS']:
580 conf.fatal('D-Bus autostart mode was specified but jackdbus will not be built')
581 if conf.env['AUTOSTART_METHOD'] == 'classic' and not conf.env['BUILD_JACKD']:
582 conf.fatal('Classic autostart mode was specified but jackd will not be built')
584 if conf.env['AUTOSTART_METHOD'] == 'dbus':
585 conf.define('USE_LIBDBUS_AUTOLAUNCH', 1)
586 elif conf.env['AUTOSTART_METHOD'] == 'classic':
587 conf.define('USE_CLASSIC_AUTOLAUNCH', 1)
589 conf.define('CLIENT_NUM', Options.options.clients)
590 conf.define('PORT_NUM_FOR_CLIENT', Options.options.application_ports)
592 if conf.env['IS_WINDOWS']:
593 # we define this in the environment to maintain compatability with
594 # existing install paths that use ADDON_DIR rather than have to
595 # have special cases for windows each time.
596 conf.env['ADDON_DIR'] = conf.env['BINDIR'] + '/jack'
597 # don't define ADDON_DIR in config.h, use the default 'jack' defined in
598 # windows/JackPlatformPlug_os.h
599 else:
600 conf.env['ADDON_DIR'] = os.path.normpath(os.path.join(conf.env['LIBDIR'], 'jack'))
601 conf.define('ADDON_DIR', conf.env['ADDON_DIR'])
602 conf.define('JACK_LOCATION', os.path.normpath(os.path.join(conf.env['PREFIX'], 'bin')))
604 if not conf.env['IS_WINDOWS']:
605 conf.define('USE_POSIX_SHM', 1)
606 conf.define('JACKMP', 1)
607 if conf.env['BUILD_JACKDBUS']:
608 conf.define('JACK_DBUS', 1)
609 if conf.env['BUILD_WITH_PROFILE']:
610 conf.define('JACK_MONITOR', 1)
611 conf.write_config_header('config.h', remove=False)
613 svnrev = None
614 try:
615 f = open('svnversion.h')
616 data = f.read()
617 m = re.match(r'^#define SVN_VERSION "([^"]*)"$', data)
618 if m != None:
619 svnrev = m.group(1)
620 f.close()
621 except IOError:
622 pass
624 if Options.options.mixed:
625 conf.setenv(lib32, env=conf.env.derive())
626 conf.env.append_unique('CXXFLAGS', '-m32')
627 conf.env.append_unique('CFLAGS', '-m32')
628 conf.env.append_unique('LINKFLAGS', '-m32')
629 if Options.options.libdir32:
630 conf.env['LIBDIR'] = Options.options.libdir32
631 else:
632 conf.env['LIBDIR'] = conf.env['PREFIX'] + '/lib32'
633 conf.write_config_header('config.h')
635 print()
636 print('==================')
637 version_msg = 'JACK ' + VERSION
638 if svnrev:
639 version_msg += ' exported from r' + svnrev
640 else:
641 version_msg += ' svn revision will checked and eventually updated during build'
642 print(version_msg)
644 conf.msg('Maximum JACK clients', Options.options.clients, color='NORMAL')
645 conf.msg('Maximum ports per application', Options.options.application_ports, color='NORMAL')
647 conf.msg('Install prefix', conf.env['PREFIX'], color='CYAN')
648 conf.msg('Library directory', conf.all_envs['']['LIBDIR'], color='CYAN')
649 if conf.env['BUILD_WITH_32_64']:
650 conf.msg('32-bit library directory', conf.all_envs[lib32]['LIBDIR'], color='CYAN')
651 conf.msg('Drivers directory', conf.env['ADDON_DIR'], color='CYAN')
652 display_feature(conf, 'Build debuggable binaries', conf.env['BUILD_DEBUG'])
654 tool_flags = [
655 ('C compiler flags', ['CFLAGS', 'CPPFLAGS']),
656 ('C++ compiler flags', ['CXXFLAGS', 'CPPFLAGS']),
657 ('Linker flags', ['LINKFLAGS', 'LDFLAGS'])
659 for name,vars in tool_flags:
660 flags = []
661 for var in vars:
662 flags += conf.all_envs[''][var]
663 conf.msg(name, repr(flags), color='NORMAL')
665 if conf.env['BUILD_WITH_32_64']:
666 conf.msg('32-bit C compiler flags', repr(conf.all_envs[lib32]['CFLAGS']))
667 conf.msg('32-bit C++ compiler flags', repr(conf.all_envs[lib32]['CXXFLAGS']))
668 conf.msg('32-bit linker flags', repr(conf.all_envs[lib32]['LINKFLAGS']))
669 display_feature(conf, 'Build with engine profiling', conf.env['BUILD_WITH_PROFILE'])
670 display_feature(conf, 'Build with 32/64 bits mixed mode', conf.env['BUILD_WITH_32_64'])
672 display_feature(conf, 'Build standard JACK (jackd)', conf.env['BUILD_JACKD'])
673 display_feature(conf, 'Build D-Bus JACK (jackdbus)', conf.env['BUILD_JACKDBUS'])
674 conf.msg('Autostart method', conf.env['AUTOSTART_METHOD'])
676 if conf.env['BUILD_JACKDBUS'] and conf.env['BUILD_JACKD']:
677 print(Logs.colors.RED + 'WARNING !! mixing both jackd and jackdbus may cause issues:' + Logs.colors.NORMAL)
678 print(Logs.colors.RED + 'WARNING !! jackdbus does not use .jackdrc nor qjackctl settings' + Logs.colors.NORMAL)
680 # display configuration result messages for auto options
681 display_auto_options_messages(conf)
683 if conf.env['BUILD_JACKDBUS']:
684 conf.msg('D-Bus service install directory', conf.env['DBUS_SERVICES_DIR'], color='CYAN')
686 if conf.env['DBUS_SERVICES_DIR'] != conf.env['DBUS_SERVICES_DIR_REAL']:
687 print()
688 print(Logs.colors.RED + 'WARNING: D-Bus session services directory as reported by pkg-config is')
689 print(Logs.colors.RED + 'WARNING:', end=' ')
690 print(Logs.colors.CYAN + conf.env['DBUS_SERVICES_DIR_REAL'])
691 print(Logs.colors.RED + 'WARNING: but service file will be installed in')
692 print(Logs.colors.RED + 'WARNING:', end=' ')
693 print(Logs.colors.CYAN + conf.env['DBUS_SERVICES_DIR'])
694 print(Logs.colors.RED + 'WARNING: You may need to adjust your D-Bus configuration after installing jackdbus')
695 print('WARNING: You can override dbus service install directory')
696 print('WARNING: with --enable-pkg-config-dbus-service-dir option to this script')
697 print(Logs.colors.NORMAL, end=' ')
698 print()
700 def init(ctx):
701 for y in (BuildContext, CleanContext, InstallContext, UninstallContext):
702 name = y.__name__.replace('Context','').lower()
703 class tmp(y):
704 cmd = name + '_' + lib32
705 variant = lib32
707 def obj_add_includes(bld, obj):
708 if bld.env['BUILD_JACKDBUS']:
709 obj.includes += ['dbus']
711 if bld.env['IS_LINUX']:
712 obj.includes += ['linux', 'posix']
714 if bld.env['IS_MACOSX']:
715 obj.includes += ['macosx', 'posix']
717 if bld.env['IS_SUN']:
718 obj.includes += ['posix', 'solaris']
720 if bld.env['IS_WINDOWS']:
721 obj.includes += ['windows']
723 # FIXME: Is SERVER_SIDE needed?
724 def build_jackd(bld):
725 jackd = bld(
726 features = ['cxx', 'cxxprogram'],
727 defines = ['HAVE_CONFIG_H','SERVER_SIDE'],
728 includes = ['.', 'common', 'common/jack'],
729 target = 'jackd',
730 source = ['common/Jackdmp.cpp'],
731 use = ['serverlib']
734 if bld.env['BUILD_JACKDBUS']:
735 jackd.source += ['dbus/audio_reserve.c', 'dbus/reserve.c']
736 jackd.use += ['DBUS-1']
738 if bld.env['IS_LINUX']:
739 jackd.use += ['DL', 'M', 'PTHREAD', 'RT', 'STDC++']
741 if bld.env['IS_MACOSX']:
742 jackd.use += ['DL', 'PTHREAD']
743 jackd.framework = ['CoreFoundation']
745 if bld.env['IS_SUN']:
746 jackd.use += ['DL', 'PTHREAD']
748 obj_add_includes(bld, jackd)
750 return jackd
752 # FIXME: Is SERVER_SIDE needed?
753 def create_driver_obj(bld, **kw):
754 if bld.env['IS_MACOSX'] or bld.env['IS_WINDOWS']:
755 # On MacOSX this is necessary.
756 # I do not know if this is necessary on Windows.
757 # Note added on 2015-12-13 by lilrc.
758 if 'use' in kw:
759 kw['use'] += ['serverlib']
760 else:
761 kw['use'] = ['serverlib']
763 driver = bld(
764 features = ['c', 'cxx', 'cshlib', 'cxxshlib'],
765 defines = ['HAVE_CONFIG_H', 'SERVER_SIDE'],
766 includes = ['.', 'common', 'common/jack'],
767 install_path = '${ADDON_DIR}/',
768 **kw)
770 if bld.env['IS_WINDOWS']:
771 driver.env['cxxshlib_PATTERN'] = 'jack_%s.dll'
772 else:
773 driver.env['cxxshlib_PATTERN'] = 'jack_%s.so'
775 obj_add_includes(bld, driver)
777 return driver
779 def build_drivers(bld):
780 # Non-hardware driver sources. Lexically sorted.
781 dummy_src = [
782 'common/JackDummyDriver.cpp'
785 loopback_src = [
786 'common/JackLoopbackDriver.cpp'
789 net_src = [
790 'common/JackNetDriver.cpp'
793 netone_src = [
794 'common/JackNetOneDriver.cpp',
795 'common/netjack.c',
796 'common/netjack_packet.c'
799 proxy_src = [
800 'common/JackProxyDriver.cpp'
803 # Hardware driver sources. Lexically sorted.
804 alsa_src = [
805 'common/memops.c',
806 'linux/alsa/JackAlsaDriver.cpp',
807 'linux/alsa/alsa_rawmidi.c',
808 'linux/alsa/alsa_seqmidi.c',
809 'linux/alsa/alsa_midi_jackmp.cpp',
810 'linux/alsa/generic_hw.c',
811 'linux/alsa/hdsp.c',
812 'linux/alsa/alsa_driver.c',
813 'linux/alsa/hammerfall.c',
814 'linux/alsa/ice1712.c'
817 alsarawmidi_src = [
818 'linux/alsarawmidi/JackALSARawMidiDriver.cpp',
819 'linux/alsarawmidi/JackALSARawMidiInputPort.cpp',
820 'linux/alsarawmidi/JackALSARawMidiOutputPort.cpp',
821 'linux/alsarawmidi/JackALSARawMidiPort.cpp',
822 'linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp',
823 'linux/alsarawmidi/JackALSARawMidiSendQueue.cpp',
824 'linux/alsarawmidi/JackALSARawMidiUtil.cpp'
827 boomer_src = [
828 'common/memops.c',
829 'solaris/oss/JackBoomerDriver.cpp'
832 coreaudio_src = [
833 'macosx/coreaudio/JackCoreAudioDriver.mm',
834 'common/JackAC3Encoder.cpp'
837 coremidi_src = [
838 'macosx/coremidi/JackCoreMidiInputPort.mm',
839 'macosx/coremidi/JackCoreMidiOutputPort.mm',
840 'macosx/coremidi/JackCoreMidiPhysicalInputPort.mm',
841 'macosx/coremidi/JackCoreMidiPhysicalOutputPort.mm',
842 'macosx/coremidi/JackCoreMidiVirtualInputPort.mm',
843 'macosx/coremidi/JackCoreMidiVirtualOutputPort.mm',
844 'macosx/coremidi/JackCoreMidiPort.mm',
845 'macosx/coremidi/JackCoreMidiUtil.mm',
846 'macosx/coremidi/JackCoreMidiDriver.mm'
849 ffado_src = [
850 'linux/firewire/JackFFADODriver.cpp',
851 'linux/firewire/JackFFADOMidiInputPort.cpp',
852 'linux/firewire/JackFFADOMidiOutputPort.cpp',
853 'linux/firewire/JackFFADOMidiReceiveQueue.cpp',
854 'linux/firewire/JackFFADOMidiSendQueue.cpp'
857 freebob_src = [
858 'linux/freebob/JackFreebobDriver.cpp'
861 iio_driver_src = [
862 'linux/iio/JackIIODriver.cpp'
865 oss_src = [
866 'common/memops.c',
867 'solaris/oss/JackOSSDriver.cpp'
870 portaudio_src = [
871 'windows/portaudio/JackPortAudioDevices.cpp',
872 'windows/portaudio/JackPortAudioDriver.cpp',
875 winmme_src = [
876 'windows/winmme/JackWinMMEDriver.cpp',
877 'windows/winmme/JackWinMMEInputPort.cpp',
878 'windows/winmme/JackWinMMEOutputPort.cpp',
879 'windows/winmme/JackWinMMEPort.cpp',
882 # Create non-hardware driver objects. Lexically sorted.
883 create_driver_obj(
884 bld,
885 target = 'dummy',
886 source = dummy_src)
888 create_driver_obj(
889 bld,
890 target = 'loopback',
891 source = loopback_src)
893 create_driver_obj(
894 bld,
895 target = 'net',
896 source = net_src)
898 create_driver_obj(
899 bld,
900 target = 'netone',
901 source = netone_src,
902 use = ['SAMPLERATE', 'CELT'])
904 create_driver_obj(
905 bld,
906 target = 'proxy',
907 source = proxy_src)
909 # Create hardware driver objects. Lexically sorted after the conditional,
910 # e.g. BUILD_DRIVER_ALSA.
911 if bld.env['BUILD_DRIVER_ALSA']:
912 create_driver_obj(
913 bld,
914 target = 'alsa',
915 source = alsa_src,
916 use = ['ALSA'])
917 create_driver_obj(
918 bld,
919 target = 'alsarawmidi',
920 source = alsarawmidi_src,
921 use = ['ALSA'])
923 if bld.env['BUILD_DRIVER_FREEBOB']:
924 create_driver_obj(
925 bld,
926 target = 'freebob',
927 source = freebob_src,
928 use = ['LIBFREEBOB'])
930 if bld.env['BUILD_DRIVER_FFADO']:
931 create_driver_obj(
932 bld,
933 target = 'firewire',
934 source = ffado_src,
935 use = ['LIBFFADO'])
937 if bld.env['BUILD_DRIVER_IIO']:
938 create_driver_obj(
939 bld,
940 target = 'iio',
941 source = iio_src,
942 use = ['GTKIOSTREAM', 'EIGEN3'])
944 if bld.env['BUILD_DRIVER_PORTAUDIO']:
945 create_driver_obj(
946 bld,
947 target = 'portaudio',
948 source = portaudio_src,
949 use = ['PORTAUDIO'])
951 if bld.env['BUILD_DRIVER_WINMME']:
952 create_driver_obj(
953 bld,
954 target = 'winmme',
955 source = winmme_src,
956 use = ['WINMME'])
958 if bld.env['IS_MACOSX']:
959 create_driver_obj(
960 bld,
961 target = 'coreaudio',
962 source = coreaudio_src,
963 use = ['AFTEN'],
964 framework = ['AudioUnit', 'CoreAudio', 'CoreServices'])
966 create_driver_obj(
967 bld,
968 target = 'coremidi',
969 source = coremidi_src,
970 use = ['serverlib'], # FIXME: Is this needed?
971 framework = ['AudioUnit', 'CoreMIDI', 'CoreServices', 'Foundation'])
973 if bld.env['IS_SUN']:
974 create_driver_obj(
975 bld,
976 target = 'boomer',
977 source = boomer_src)
978 create_driver_obj(
979 bld,
980 target = 'oss',
981 source = oss_src)
983 def build(bld):
984 if not bld.variant and bld.env['BUILD_WITH_32_64']:
985 Options.commands.append(bld.cmd + '_' + lib32)
987 # process subfolders from here
988 bld.recurse('common')
990 if bld.variant:
991 # only the wscript in common/ knows how to handle variants
992 return
994 if not os.access('svnversion.h', os.R_OK):
995 def post_run(self):
996 sg = Utils.h_file(self.outputs[0].abspath(self.env))
997 #print sg.encode('hex')
998 Build.bld.node_sigs[self.env.variant()][self.outputs[0].id] = sg
1000 script = bld.path.find_resource('svnversion_regenerate.sh')
1001 script = script.abspath()
1003 bld(
1004 rule = '%s ${TGT}' % script,
1005 name = 'svnversion',
1006 runnable_status = Task.RUN_ME,
1007 before = 'c cxx',
1008 color = 'BLUE',
1009 post_run = post_run,
1010 source = ['svnversion_regenerate.sh'],
1011 target = [bld.path.find_or_declare('svnversion.h')]
1014 if bld.env['BUILD_JACKD']:
1015 build_jackd(bld)
1017 build_drivers(bld)
1019 bld.recurse('example-clients')
1020 if bld.env['IS_LINUX']:
1021 bld.recurse('man')
1022 if not bld.env['IS_WINDOWS']:
1023 bld.recurse('tests')
1024 if bld.env['BUILD_JACKDBUS']:
1025 bld.recurse('dbus')
1027 if bld.env['BUILD_DOXYGEN_DOCS']:
1028 html_build_dir = bld.path.find_or_declare('html').abspath()
1030 bld(
1031 features = 'subst',
1032 source = 'doxyfile.in',
1033 target = 'doxyfile',
1034 HTML_BUILD_DIR = html_build_dir,
1035 SRCDIR = bld.srcnode.abspath(),
1036 VERSION = VERSION
1039 # There are two reasons for logging to doxygen.log and using it as
1040 # target in the build rule (rather than html_build_dir):
1041 # (1) reduce the noise when running the build
1042 # (2) waf has a regular file to check for a timestamp. If the directory
1043 # is used instead waf will rebuild the doxygen target (even upon
1044 # install).
1045 def doxygen(task):
1046 doxyfile = task.inputs[0].abspath()
1047 logfile = task.outputs[0].abspath()
1048 cmd = '%s %s &> %s' % (task.env['DOXYGEN'][0], doxyfile, logfile)
1049 return task.exec_command(cmd)
1051 bld(
1052 rule = doxygen,
1053 source = 'doxyfile',
1054 target = 'doxygen.log'
1057 # Determine where to install HTML documentation. Since share_dir is the
1058 # highest directory the uninstall routine should remove, there is no
1059 # better candidate for share_dir, but the requested HTML directory if
1060 # --htmldir is given.
1061 if bld.env['HTMLDIR']:
1062 html_install_dir = bld.options.destdir + bld.env['HTMLDIR']
1063 share_dir = html_install_dir
1064 else:
1065 share_dir = bld.options.destdir + bld.env['PREFIX'] + '/share/jack-audio-connection-kit'
1066 html_install_dir = share_dir + '/reference/html/'
1068 if bld.cmd == 'install':
1069 if os.path.isdir(html_install_dir):
1070 Logs.pprint('CYAN', 'Removing old doxygen documentation installation...')
1071 shutil.rmtree(html_install_dir)
1072 Logs.pprint('CYAN', 'Removing old doxygen documentation installation done.')
1073 Logs.pprint('CYAN', 'Installing doxygen documentation...')
1074 shutil.copytree(html_build_dir, html_install_dir)
1075 Logs.pprint('CYAN', 'Installing doxygen documentation done.')
1076 elif bld.cmd =='uninstall':
1077 Logs.pprint('CYAN', 'Uninstalling doxygen documentation...')
1078 if os.path.isdir(share_dir):
1079 shutil.rmtree(share_dir)
1080 Logs.pprint('CYAN', 'Uninstalling doxygen documentation done.')
1081 elif bld.cmd =='clean':
1082 if os.access(html_build_dir, os.R_OK):
1083 Logs.pprint('CYAN', 'Removing doxygen generated documentation...')
1084 shutil.rmtree(html_build_dir)
1085 Logs.pprint('CYAN', 'Removing doxygen generated documentation done.')
1087 def dist(ctx):
1088 # This code blindly assumes it is working in the toplevel source directory.
1089 if not os.path.exists('svnversion.h'):
1090 os.system('./svnversion_regenerate.sh svnversion.h')
1092 from waflib import TaskGen
1093 @TaskGen.extension('.mm')
1094 def mm_hook(self, node):
1095 """Alias .mm files to be compiled the same as .cpp files, gcc will do the right thing."""
1096 return self.create_compiled_task('cxx', node)