Update copyright year in jackd
[jack2.git] / wscript
blob70462cc8913f94163f7d3da4cd07f95b5dc6f02d
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)
442 sd = add_auto_option(opt, 'systemd', help='Use systemd notify')
443 sd.add_header('systemd/sd-daemon.h')
444 sd.add_library('systemd')
446 # dbus options
447 opt.recurse('dbus')
449 # this must be called before the configure phase
450 auto_options_argv_hack()
452 def detect_platform(conf):
453 # GNU/kFreeBSD and GNU/Hurd are treated as Linux
454 platforms = [
455 # ('KEY, 'Human readable name', ['strings', 'to', 'check', 'for'])
456 ('IS_LINUX', 'Linux', ['gnu0', 'gnukfreebsd', 'linux', 'posix']),
457 ('IS_MACOSX', 'MacOS X', ['darwin']),
458 ('IS_SUN', 'SunOS', ['sunos']),
459 ('IS_WINDOWS', 'Windows', ['cygwin', 'msys', 'win32'])
462 for key,name,strings in platforms:
463 conf.env[key] = False
465 conf.start_msg('Checking platform')
466 platform = Options.options.platform
467 for key,name,strings in platforms:
468 for s in strings:
469 if platform.startswith(s):
470 conf.env[key] = True
471 conf.end_msg(name, color='CYAN')
472 break
474 def configure(conf):
475 conf.load('compiler_cxx')
476 conf.load('compiler_c')
478 detect_platform(conf)
480 if conf.env['IS_WINDOWS']:
481 conf.env.append_unique('CCDEFINES', '_POSIX')
482 conf.env.append_unique('CXXDEFINES', '_POSIX')
484 conf.env.append_unique('CXXFLAGS', '-Wall')
485 conf.env.append_unique('CFLAGS', '-Wall')
487 if conf.env['IS_MACOSX']:
488 conf.check(lib='aften', uselib='AFTEN', define_name='AFTEN')
490 # configure all auto options
491 configure_auto_options(conf)
493 # Check for functions.
494 conf.check(
495 function_name='ppoll',
496 header_name=['poll.h', 'signal.h'],
497 defines=['_GNU_SOURCE'],
498 mandatory=False)
500 # Check for backtrace support
501 conf.check(
502 header_name='execinfo.h',
503 define_name='HAVE_EXECINFO_H',
504 mandatory=False)
506 conf.recurse('common')
507 if Options.options.dbus:
508 conf.recurse('dbus')
509 if conf.env['BUILD_JACKDBUS'] != True:
510 conf.fatal('jackdbus was explicitly requested but cannot be built')
512 conf.recurse('example-clients')
514 # test for the availability of ucontext, and how it should be used
515 for t in ['gp_regs', 'uc_regs', 'mc_gregs', 'gregs']:
516 fragment = '#include <ucontext.h>\n'
517 fragment += 'int main() { ucontext_t *ucontext; return (int) ucontext->uc_mcontext.%s[0]; }' % t
518 confvar = 'HAVE_UCONTEXT_%s' % t.upper()
519 conf.check_cc(fragment=fragment, define_name=confvar, mandatory=False,
520 msg='Checking for ucontext->uc_mcontext.%s' % t)
521 if conf.is_defined(confvar):
522 conf.define('HAVE_UCONTEXT', 1)
524 fragment = '#include <ucontext.h>\n'
525 fragment += 'int main() { return NGREG; }'
526 conf.check_cc(fragment=fragment, define_name='HAVE_NGREG', mandatory=False,
527 msg='Checking for NGREG')
529 conf.env['LIB_PTHREAD'] = ['pthread']
530 conf.env['LIB_DL'] = ['dl']
531 conf.env['LIB_RT'] = ['rt']
532 conf.env['LIB_M'] = ['m']
533 conf.env['LIB_STDC++'] = ['stdc++']
534 conf.env['JACK_API_VERSION'] = JACK_API_VERSION
535 conf.env['JACK_VERSION'] = VERSION
537 conf.env['BUILD_WITH_PROFILE'] = Options.options.profile
538 conf.env['BUILD_WITH_32_64'] = Options.options.mixed
539 conf.env['BUILD_CLASSIC'] = Options.options.classic
540 conf.env['BUILD_DEBUG'] = Options.options.debug
542 if conf.env['BUILD_JACKDBUS']:
543 conf.env['BUILD_JACKD'] = conf.env['BUILD_CLASSIC']
544 else:
545 conf.env['BUILD_JACKD'] = True
547 conf.env['BINDIR'] = conf.env['PREFIX'] + '/bin'
549 if Options.options.htmldir:
550 conf.env['HTMLDIR'] = Options.options.htmldir
551 else:
552 # set to None here so that the doxygen code can find out the highest
553 # directory to remove upon install
554 conf.env['HTMLDIR'] = None
556 if Options.options.libdir:
557 conf.env['LIBDIR'] = Options.options.libdir
558 else:
559 conf.env['LIBDIR'] = conf.env['PREFIX'] + '/lib'
561 if Options.options.mandir:
562 conf.env['MANDIR'] = Options.options.mandir
563 else:
564 conf.env['MANDIR'] = conf.env['PREFIX'] + '/share/man/man1'
566 if conf.env['BUILD_DEBUG']:
567 conf.env.append_unique('CXXFLAGS', '-g')
568 conf.env.append_unique('CFLAGS', '-g')
569 conf.env.append_unique('LINKFLAGS', '-g')
571 if not Options.options.autostart in ['default', 'classic', 'dbus', 'none']:
572 conf.fatal('Invalid autostart value "' + Options.options.autostart + '"')
574 if Options.options.autostart == 'default':
575 if conf.env['BUILD_JACKD']:
576 conf.env['AUTOSTART_METHOD'] = 'classic'
577 else:
578 conf.env['AUTOSTART_METHOD'] = 'dbus'
579 else:
580 conf.env['AUTOSTART_METHOD'] = Options.options.autostart
582 if conf.env['AUTOSTART_METHOD'] == 'dbus' and not conf.env['BUILD_JACKDBUS']:
583 conf.fatal('D-Bus autostart mode was specified but jackdbus will not be built')
584 if conf.env['AUTOSTART_METHOD'] == 'classic' and not conf.env['BUILD_JACKD']:
585 conf.fatal('Classic autostart mode was specified but jackd will not be built')
587 if conf.env['AUTOSTART_METHOD'] == 'dbus':
588 conf.define('USE_LIBDBUS_AUTOLAUNCH', 1)
589 elif conf.env['AUTOSTART_METHOD'] == 'classic':
590 conf.define('USE_CLASSIC_AUTOLAUNCH', 1)
592 conf.define('CLIENT_NUM', Options.options.clients)
593 conf.define('PORT_NUM_FOR_CLIENT', Options.options.application_ports)
595 if conf.env['IS_WINDOWS']:
596 # we define this in the environment to maintain compatability with
597 # existing install paths that use ADDON_DIR rather than have to
598 # have special cases for windows each time.
599 conf.env['ADDON_DIR'] = conf.env['BINDIR'] + '/jack'
600 # don't define ADDON_DIR in config.h, use the default 'jack' defined in
601 # windows/JackPlatformPlug_os.h
602 else:
603 conf.env['ADDON_DIR'] = os.path.normpath(os.path.join(conf.env['LIBDIR'], 'jack'))
604 conf.define('ADDON_DIR', conf.env['ADDON_DIR'])
605 conf.define('JACK_LOCATION', os.path.normpath(os.path.join(conf.env['PREFIX'], 'bin')))
607 if not conf.env['IS_WINDOWS']:
608 conf.define('USE_POSIX_SHM', 1)
609 conf.define('JACKMP', 1)
610 if conf.env['BUILD_JACKDBUS']:
611 conf.define('JACK_DBUS', 1)
612 if conf.env['BUILD_WITH_PROFILE']:
613 conf.define('JACK_MONITOR', 1)
614 conf.write_config_header('config.h', remove=False)
616 svnrev = None
617 try:
618 f = open('svnversion.h')
619 data = f.read()
620 m = re.match(r'^#define SVN_VERSION "([^"]*)"$', data)
621 if m != None:
622 svnrev = m.group(1)
623 f.close()
624 except IOError:
625 pass
627 if Options.options.mixed:
628 conf.setenv(lib32, env=conf.env.derive())
629 conf.env.append_unique('CXXFLAGS', '-m32')
630 conf.env.append_unique('CFLAGS', '-m32')
631 conf.env.append_unique('LINKFLAGS', '-m32')
632 if Options.options.libdir32:
633 conf.env['LIBDIR'] = Options.options.libdir32
634 else:
635 conf.env['LIBDIR'] = conf.env['PREFIX'] + '/lib32'
636 conf.write_config_header('config.h')
638 print()
639 print('==================')
640 version_msg = 'JACK ' + VERSION
641 if svnrev:
642 version_msg += ' exported from r' + svnrev
643 else:
644 version_msg += ' svn revision will checked and eventually updated during build'
645 print(version_msg)
647 conf.msg('Maximum JACK clients', Options.options.clients, color='NORMAL')
648 conf.msg('Maximum ports per application', Options.options.application_ports, color='NORMAL')
650 conf.msg('Install prefix', conf.env['PREFIX'], color='CYAN')
651 conf.msg('Library directory', conf.all_envs['']['LIBDIR'], color='CYAN')
652 if conf.env['BUILD_WITH_32_64']:
653 conf.msg('32-bit library directory', conf.all_envs[lib32]['LIBDIR'], color='CYAN')
654 conf.msg('Drivers directory', conf.env['ADDON_DIR'], color='CYAN')
655 display_feature(conf, 'Build debuggable binaries', conf.env['BUILD_DEBUG'])
657 tool_flags = [
658 ('C compiler flags', ['CFLAGS', 'CPPFLAGS']),
659 ('C++ compiler flags', ['CXXFLAGS', 'CPPFLAGS']),
660 ('Linker flags', ['LINKFLAGS', 'LDFLAGS'])
662 for name,vars in tool_flags:
663 flags = []
664 for var in vars:
665 flags += conf.all_envs[''][var]
666 conf.msg(name, repr(flags), color='NORMAL')
668 if conf.env['BUILD_WITH_32_64']:
669 conf.msg('32-bit C compiler flags', repr(conf.all_envs[lib32]['CFLAGS']))
670 conf.msg('32-bit C++ compiler flags', repr(conf.all_envs[lib32]['CXXFLAGS']))
671 conf.msg('32-bit linker flags', repr(conf.all_envs[lib32]['LINKFLAGS']))
672 display_feature(conf, 'Build with engine profiling', conf.env['BUILD_WITH_PROFILE'])
673 display_feature(conf, 'Build with 32/64 bits mixed mode', conf.env['BUILD_WITH_32_64'])
675 display_feature(conf, 'Build standard JACK (jackd)', conf.env['BUILD_JACKD'])
676 display_feature(conf, 'Build D-Bus JACK (jackdbus)', conf.env['BUILD_JACKDBUS'])
677 conf.msg('Autostart method', conf.env['AUTOSTART_METHOD'])
679 if conf.env['BUILD_JACKDBUS'] and conf.env['BUILD_JACKD']:
680 print(Logs.colors.RED + 'WARNING !! mixing both jackd and jackdbus may cause issues:' + Logs.colors.NORMAL)
681 print(Logs.colors.RED + 'WARNING !! jackdbus does not use .jackdrc nor qjackctl settings' + Logs.colors.NORMAL)
683 # display configuration result messages for auto options
684 display_auto_options_messages(conf)
686 if conf.env['BUILD_JACKDBUS']:
687 conf.msg('D-Bus service install directory', conf.env['DBUS_SERVICES_DIR'], color='CYAN')
689 if conf.env['DBUS_SERVICES_DIR'] != conf.env['DBUS_SERVICES_DIR_REAL']:
690 print()
691 print(Logs.colors.RED + 'WARNING: D-Bus session services directory as reported by pkg-config is')
692 print(Logs.colors.RED + 'WARNING:', end=' ')
693 print(Logs.colors.CYAN + conf.env['DBUS_SERVICES_DIR_REAL'])
694 print(Logs.colors.RED + 'WARNING: but service file will be installed in')
695 print(Logs.colors.RED + 'WARNING:', end=' ')
696 print(Logs.colors.CYAN + conf.env['DBUS_SERVICES_DIR'])
697 print(Logs.colors.RED + 'WARNING: You may need to adjust your D-Bus configuration after installing jackdbus')
698 print('WARNING: You can override dbus service install directory')
699 print('WARNING: with --enable-pkg-config-dbus-service-dir option to this script')
700 print(Logs.colors.NORMAL, end=' ')
701 print()
703 def init(ctx):
704 for y in (BuildContext, CleanContext, InstallContext, UninstallContext):
705 name = y.__name__.replace('Context','').lower()
706 class tmp(y):
707 cmd = name + '_' + lib32
708 variant = lib32
710 def obj_add_includes(bld, obj):
711 if bld.env['BUILD_JACKDBUS']:
712 obj.includes += ['dbus']
714 if bld.env['IS_LINUX']:
715 obj.includes += ['linux', 'posix']
717 if bld.env['IS_MACOSX']:
718 obj.includes += ['macosx', 'posix']
720 if bld.env['IS_SUN']:
721 obj.includes += ['posix', 'solaris']
723 if bld.env['IS_WINDOWS']:
724 obj.includes += ['windows']
726 # FIXME: Is SERVER_SIDE needed?
727 def build_jackd(bld):
728 jackd = bld(
729 features = ['cxx', 'cxxprogram'],
730 defines = ['HAVE_CONFIG_H','SERVER_SIDE'],
731 includes = ['.', 'common', 'common/jack'],
732 target = 'jackd',
733 source = ['common/Jackdmp.cpp'],
734 use = ['serverlib', 'SYSTEMD']
737 if bld.env['BUILD_JACKDBUS']:
738 jackd.source += ['dbus/audio_reserve.c', 'dbus/reserve.c']
739 jackd.use += ['DBUS-1']
741 if bld.env['IS_LINUX']:
742 jackd.use += ['DL', 'M', 'PTHREAD', 'RT', 'STDC++']
744 if bld.env['IS_MACOSX']:
745 jackd.use += ['DL', 'PTHREAD']
746 jackd.framework = ['CoreFoundation']
748 if bld.env['IS_SUN']:
749 jackd.use += ['DL', 'PTHREAD']
751 obj_add_includes(bld, jackd)
753 return jackd
755 # FIXME: Is SERVER_SIDE needed?
756 def create_driver_obj(bld, **kw):
757 if bld.env['IS_MACOSX'] or bld.env['IS_WINDOWS']:
758 # On MacOSX this is necessary.
759 # I do not know if this is necessary on Windows.
760 # Note added on 2015-12-13 by karllinden.
761 if 'use' in kw:
762 kw['use'] += ['serverlib']
763 else:
764 kw['use'] = ['serverlib']
766 driver = bld(
767 features = ['c', 'cxx', 'cshlib', 'cxxshlib'],
768 defines = ['HAVE_CONFIG_H', 'SERVER_SIDE'],
769 includes = ['.', 'common', 'common/jack'],
770 install_path = '${ADDON_DIR}/',
771 **kw)
773 if bld.env['IS_WINDOWS']:
774 driver.env['cxxshlib_PATTERN'] = 'jack_%s.dll'
775 else:
776 driver.env['cxxshlib_PATTERN'] = 'jack_%s.so'
778 obj_add_includes(bld, driver)
780 return driver
782 def build_drivers(bld):
783 # Non-hardware driver sources. Lexically sorted.
784 dummy_src = [
785 'common/JackDummyDriver.cpp'
788 loopback_src = [
789 'common/JackLoopbackDriver.cpp'
792 net_src = [
793 'common/JackNetDriver.cpp'
796 netone_src = [
797 'common/JackNetOneDriver.cpp',
798 'common/netjack.c',
799 'common/netjack_packet.c'
802 proxy_src = [
803 'common/JackProxyDriver.cpp'
806 # Hardware driver sources. Lexically sorted.
807 alsa_src = [
808 'common/memops.c',
809 'linux/alsa/JackAlsaDriver.cpp',
810 'linux/alsa/alsa_rawmidi.c',
811 'linux/alsa/alsa_seqmidi.c',
812 'linux/alsa/alsa_midi_jackmp.cpp',
813 'linux/alsa/generic_hw.c',
814 'linux/alsa/hdsp.c',
815 'linux/alsa/alsa_driver.c',
816 'linux/alsa/hammerfall.c',
817 'linux/alsa/ice1712.c'
820 alsarawmidi_src = [
821 'linux/alsarawmidi/JackALSARawMidiDriver.cpp',
822 'linux/alsarawmidi/JackALSARawMidiInputPort.cpp',
823 'linux/alsarawmidi/JackALSARawMidiOutputPort.cpp',
824 'linux/alsarawmidi/JackALSARawMidiPort.cpp',
825 'linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp',
826 'linux/alsarawmidi/JackALSARawMidiSendQueue.cpp',
827 'linux/alsarawmidi/JackALSARawMidiUtil.cpp'
830 boomer_src = [
831 'common/memops.c',
832 'solaris/oss/JackBoomerDriver.cpp'
835 coreaudio_src = [
836 'macosx/coreaudio/JackCoreAudioDriver.mm',
837 'common/JackAC3Encoder.cpp'
840 coremidi_src = [
841 'macosx/coremidi/JackCoreMidiInputPort.mm',
842 'macosx/coremidi/JackCoreMidiOutputPort.mm',
843 'macosx/coremidi/JackCoreMidiPhysicalInputPort.mm',
844 'macosx/coremidi/JackCoreMidiPhysicalOutputPort.mm',
845 'macosx/coremidi/JackCoreMidiVirtualInputPort.mm',
846 'macosx/coremidi/JackCoreMidiVirtualOutputPort.mm',
847 'macosx/coremidi/JackCoreMidiPort.mm',
848 'macosx/coremidi/JackCoreMidiUtil.mm',
849 'macosx/coremidi/JackCoreMidiDriver.mm'
852 ffado_src = [
853 'linux/firewire/JackFFADODriver.cpp',
854 'linux/firewire/JackFFADOMidiInputPort.cpp',
855 'linux/firewire/JackFFADOMidiOutputPort.cpp',
856 'linux/firewire/JackFFADOMidiReceiveQueue.cpp',
857 'linux/firewire/JackFFADOMidiSendQueue.cpp'
860 freebob_src = [
861 'linux/freebob/JackFreebobDriver.cpp'
864 iio_driver_src = [
865 'linux/iio/JackIIODriver.cpp'
868 oss_src = [
869 'common/memops.c',
870 'solaris/oss/JackOSSDriver.cpp'
873 portaudio_src = [
874 'windows/portaudio/JackPortAudioDevices.cpp',
875 'windows/portaudio/JackPortAudioDriver.cpp',
878 winmme_src = [
879 'windows/winmme/JackWinMMEDriver.cpp',
880 'windows/winmme/JackWinMMEInputPort.cpp',
881 'windows/winmme/JackWinMMEOutputPort.cpp',
882 'windows/winmme/JackWinMMEPort.cpp',
885 # Create non-hardware driver objects. Lexically sorted.
886 create_driver_obj(
887 bld,
888 target = 'dummy',
889 source = dummy_src)
891 create_driver_obj(
892 bld,
893 target = 'loopback',
894 source = loopback_src)
896 create_driver_obj(
897 bld,
898 target = 'net',
899 source = net_src)
901 create_driver_obj(
902 bld,
903 target = 'netone',
904 source = netone_src,
905 use = ['SAMPLERATE', 'CELT'])
907 create_driver_obj(
908 bld,
909 target = 'proxy',
910 source = proxy_src)
912 # Create hardware driver objects. Lexically sorted after the conditional,
913 # e.g. BUILD_DRIVER_ALSA.
914 if bld.env['BUILD_DRIVER_ALSA']:
915 create_driver_obj(
916 bld,
917 target = 'alsa',
918 source = alsa_src,
919 use = ['ALSA'])
920 create_driver_obj(
921 bld,
922 target = 'alsarawmidi',
923 source = alsarawmidi_src,
924 use = ['ALSA'])
926 if bld.env['BUILD_DRIVER_FREEBOB']:
927 create_driver_obj(
928 bld,
929 target = 'freebob',
930 source = freebob_src,
931 use = ['LIBFREEBOB'])
933 if bld.env['BUILD_DRIVER_FFADO']:
934 create_driver_obj(
935 bld,
936 target = 'firewire',
937 source = ffado_src,
938 use = ['LIBFFADO'])
940 if bld.env['BUILD_DRIVER_IIO']:
941 create_driver_obj(
942 bld,
943 target = 'iio',
944 source = iio_src,
945 use = ['GTKIOSTREAM', 'EIGEN3'])
947 if bld.env['BUILD_DRIVER_PORTAUDIO']:
948 create_driver_obj(
949 bld,
950 target = 'portaudio',
951 source = portaudio_src,
952 use = ['PORTAUDIO'])
954 if bld.env['BUILD_DRIVER_WINMME']:
955 create_driver_obj(
956 bld,
957 target = 'winmme',
958 source = winmme_src,
959 use = ['WINMME'])
961 if bld.env['IS_MACOSX']:
962 create_driver_obj(
963 bld,
964 target = 'coreaudio',
965 source = coreaudio_src,
966 use = ['AFTEN'],
967 framework = ['AudioUnit', 'CoreAudio', 'CoreServices'])
969 create_driver_obj(
970 bld,
971 target = 'coremidi',
972 source = coremidi_src,
973 use = ['serverlib'], # FIXME: Is this needed?
974 framework = ['AudioUnit', 'CoreMIDI', 'CoreServices', 'Foundation'])
976 if bld.env['IS_SUN']:
977 create_driver_obj(
978 bld,
979 target = 'boomer',
980 source = boomer_src)
981 create_driver_obj(
982 bld,
983 target = 'oss',
984 source = oss_src)
986 def build(bld):
987 if not bld.variant and bld.env['BUILD_WITH_32_64']:
988 Options.commands.append(bld.cmd + '_' + lib32)
990 # process subfolders from here
991 bld.recurse('common')
993 if bld.variant:
994 # only the wscript in common/ knows how to handle variants
995 return
997 if not os.access('svnversion.h', os.R_OK):
998 def post_run(self):
999 sg = Utils.h_file(self.outputs[0].abspath(self.env))
1000 #print sg.encode('hex')
1001 Build.bld.node_sigs[self.env.variant()][self.outputs[0].id] = sg
1003 script = bld.path.find_resource('svnversion_regenerate.sh')
1004 script = script.abspath()
1006 bld(
1007 rule = '%s ${TGT}' % script,
1008 name = 'svnversion',
1009 runnable_status = Task.RUN_ME,
1010 before = 'c cxx',
1011 color = 'BLUE',
1012 post_run = post_run,
1013 source = ['svnversion_regenerate.sh'],
1014 target = [bld.path.find_or_declare('svnversion.h')]
1017 if bld.env['BUILD_JACKD']:
1018 build_jackd(bld)
1020 build_drivers(bld)
1022 bld.recurse('example-clients')
1023 if bld.env['IS_LINUX']:
1024 bld.recurse('man')
1025 if not bld.env['IS_WINDOWS']:
1026 bld.recurse('tests')
1027 if bld.env['BUILD_JACKDBUS']:
1028 bld.recurse('dbus')
1030 if bld.env['BUILD_DOXYGEN_DOCS']:
1031 html_build_dir = bld.path.find_or_declare('html').abspath()
1033 bld(
1034 features = 'subst',
1035 source = 'doxyfile.in',
1036 target = 'doxyfile',
1037 HTML_BUILD_DIR = html_build_dir,
1038 SRCDIR = bld.srcnode.abspath(),
1039 VERSION = VERSION
1042 # There are two reasons for logging to doxygen.log and using it as
1043 # target in the build rule (rather than html_build_dir):
1044 # (1) reduce the noise when running the build
1045 # (2) waf has a regular file to check for a timestamp. If the directory
1046 # is used instead waf will rebuild the doxygen target (even upon
1047 # install).
1048 def doxygen(task):
1049 doxyfile = task.inputs[0].abspath()
1050 logfile = task.outputs[0].abspath()
1051 cmd = '%s %s &> %s' % (task.env['DOXYGEN'][0], doxyfile, logfile)
1052 return task.exec_command(cmd)
1054 bld(
1055 rule = doxygen,
1056 source = 'doxyfile',
1057 target = 'doxygen.log'
1060 # Determine where to install HTML documentation. Since share_dir is the
1061 # highest directory the uninstall routine should remove, there is no
1062 # better candidate for share_dir, but the requested HTML directory if
1063 # --htmldir is given.
1064 if bld.env['HTMLDIR']:
1065 html_install_dir = bld.options.destdir + bld.env['HTMLDIR']
1066 share_dir = html_install_dir
1067 else:
1068 share_dir = bld.options.destdir + bld.env['PREFIX'] + '/share/jack-audio-connection-kit'
1069 html_install_dir = share_dir + '/reference/html/'
1071 if bld.cmd == 'install':
1072 if os.path.isdir(html_install_dir):
1073 Logs.pprint('CYAN', 'Removing old doxygen documentation installation...')
1074 shutil.rmtree(html_install_dir)
1075 Logs.pprint('CYAN', 'Removing old doxygen documentation installation done.')
1076 Logs.pprint('CYAN', 'Installing doxygen documentation...')
1077 shutil.copytree(html_build_dir, html_install_dir)
1078 Logs.pprint('CYAN', 'Installing doxygen documentation done.')
1079 elif bld.cmd =='uninstall':
1080 Logs.pprint('CYAN', 'Uninstalling doxygen documentation...')
1081 if os.path.isdir(share_dir):
1082 shutil.rmtree(share_dir)
1083 Logs.pprint('CYAN', 'Uninstalling doxygen documentation done.')
1084 elif bld.cmd =='clean':
1085 if os.access(html_build_dir, os.R_OK):
1086 Logs.pprint('CYAN', 'Removing doxygen generated documentation...')
1087 shutil.rmtree(html_build_dir)
1088 Logs.pprint('CYAN', 'Removing doxygen generated documentation done.')
1090 def dist(ctx):
1091 # This code blindly assumes it is working in the toplevel source directory.
1092 if not os.path.exists('svnversion.h'):
1093 os.system('./svnversion_regenerate.sh svnversion.h')
1095 from waflib import TaskGen
1096 @TaskGen.extension('.mm')
1097 def mm_hook(self, node):
1098 """Alias .mm files to be compiled the same as .cpp files, gcc will do the right thing."""
1099 return self.create_compiled_task('cxx', node)