remove unused files dbus/audio_reserve.[ch]
[jackdbus.git] / wscript
blobeaa16a9f24759bce88298155eacc8f3bcffaa566
1 #! /usr/bin/python3
2 # encoding: utf-8
4 # Copyright (C) 2015-2018 Karl Linden <karl.j.linden@gmail.com>
5 # Copyleft (C) 2008-2022 Nedko Arnaudov
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 from __future__ import print_function
23 import os
24 import shutil
25 import sys
27 from waflib import Logs, Options, TaskGen
28 from waflib import Context
29 from waflib.Build import BuildContext, CleanContext, InstallContext, UninstallContext
31 VERSION = "2.22.1"
32 APPNAME = 'jackdbus'
34 # these variables are mandatory ('/' are converted automatically)
35 top = '.'
36 out = 'build'
38 def display_feature(conf, msg, build):
39     if build:
40         conf.msg(msg, 'yes', color='GREEN')
41     else:
42         conf.msg(msg, 'no', color='YELLOW')
45 def options(opt):
46     # options provided by the modules
47     opt.load('compiler_cxx')
48     opt.load('compiler_c')
49     opt.load('autooptions')
51     # install directories
52     opt.add_option(
53         '--htmldir',
54         type='string',
55         default=None,
56         help='HTML documentation directory [Default: <prefix>/share/jack-audio-connection-kit/reference/html/',
57     )
58     opt.add_option('--libdir', type='string', help='Library directory [Default: <prefix>/lib]')
59     opt.add_option('--pkgconfigdir', type='string', help='pkg-config file directory [Default: <libdir>/pkgconfig]')
60     opt.add_option('--mandir', type='string', help='Manpage directory [Default: <prefix>/share/man/man1]')
62     # options affecting binaries
63     opt.add_option(
64         '--platform',
65         type='string',
66         default=sys.platform,
67         help='Target platform for cross-compiling, e.g. cygwin or win32',
68     )
69     opt.add_option('--debug', action='store_true', default=False, dest='debug', help='Build debuggable binaries')
71     #opt.set_auto_options_define('HAVE_%s')
72     #opt.set_auto_options_style('yesno_and_hack')
74     # options with third party dependencies
75     #doxygen = opt.add_auto_option(
76     #        'doxygen',
77     #        help='Build doxygen documentation',
78     #        conf_dest='BUILD_DOXYGEN_DOCS',
79     #        default=False)
80     #doxygen.find_program('doxygen')
82     # dbus options
83     opt.recurse('dbus')
85     # this must be called before the configure phase
86     #opt.apply_auto_options_hack()
89 def detect_platform(conf):
90     # GNU/kFreeBSD and GNU/Hurd are treated as Linux
91     platforms = [
92         # ('KEY, 'Human readable name', ['strings', 'to', 'check', 'for'])
93         ('IS_LINUX',   'Linux',   ['gnu0', 'gnukfreebsd', 'linux', 'posix']),
94         ('IS_FREEBSD', 'FreeBSD', ['freebsd']),
95         ('IS_MACOSX',  'MacOS X', ['darwin']),
96         ('IS_SUN',     'SunOS',   ['sunos']),
97         ('IS_WINDOWS', 'Windows', ['cygwin', 'msys', 'win32'])
98     ]
100     for key, name, strings in platforms:
101         conf.env[key] = False
103     conf.start_msg('Checking platform')
104     platform = Options.options.platform
105     for key, name, strings in platforms:
106         for s in strings:
107             if platform.startswith(s):
108                 conf.env[key] = True
109                 conf.end_msg(name, color='CYAN')
110                 break
112 class WafToolchainFlags:
113     """
114     Waf helper class for handling set of CFLAGS
115     and related. The flush() method will
116     prepend so to allow supplied by (downstream/distro/builder) waf caller flags
117     to override the upstream flags in wscript.
118     TODO: upstream this or find alternative easy way of doing the same
119     """
120     def __init__(self, conf):
121         """
122         :param conf: Waf configuration object
123         """
124         self.conf = conf
125         self.flags = {}
126         for x in ('CPPFLAGS', 'CFLAGS', 'CXXFLAGS', 'LINKFLAGS'):
127             self.flags[x] = []
129     def flush(self):
130         """
131         Flush flags to the configuration object
132         Prepend is used so to allow supplied by
133         (downstream/distro/builder) waf caller flags
134         to override the upstream flags in wscript.
135         """
136         for key, val in self.flags.items():
137             self.conf.env.prepend_value(key, val)
139     def add(self, key, val):
140         """
141         :param key: Set to add flags to. 'CPPFLAGS', 'CFLAGS', 'CXXFLAGS' or 'LINKFLAGS'
142         :param val: string or list of strings
143         """
144         flags = self.flags[key]
145         if isinstance(val, list):
146             #flags.extend(val)
147             for x in val:
148                 if not isinstance(x, str):
149                     raise Exception("value must be string or list of strings. ", type(x))
150                 flags.append(x)
151         elif isinstance(val, str):
152             flags.append(val)
153         else:
154             raise Exception("value must be string or list of strings")
156     def add_cpp(self, value):
157         """
158         Add flag or list of flags to CPPFLAGS
159         :param value: string or list of strings
160         """
161         self.add('CPPFLAGS', value)
163     def add_c(self, value):
164         """
165         Add flag or list of flags to CFLAGS
166         :param value: string or list of strings
167         """
168         self.add('CFLAGS', value)
170     def add_cxx(self, value):
171         """
172         Add flag or list of flags to CXXFLAGS
173         :param value: string or list of strings
174         """
175         self.add('CXXFLAGS', value)
177     def add_candcxx(self, value):
178         """
179         Add flag or list of flags to CFLAGS and CXXFLAGS
180         :param value: string or list of strings
181         """
182         self.add_c(value)
183         self.add_cxx(value)
185     def add_link(self, value):
186         """
187         Add flag or list of flags to LINKFLAGS
188         :param value: string or list of strings
189         """
190         self.add('LINKFLAGS', value)
192 def configure(conf):
193     conf.load('compiler_cxx')
194     conf.load('compiler_c')
196     detect_platform(conf)
197     flags = WafToolchainFlags(conf)
199     conf.check_cfg(package='jackserver', uselib_store='JACKSERVER', args=["--cflags", "--libs"])
201     conf.check_cfg(package='expat', args='--cflags --libs')
203     flags.add_c('-Wall')
204     flags.add_cxx(['-Wall', '-Wno-invalid-offsetof'])
205     flags.add_cxx('-std=gnu++11')
207     if conf.env['IS_FREEBSD']:
208         conf.check(lib='execinfo', uselib='EXECINFO', define_name='EXECINFO')
209         conf.check_cfg(package='libsysinfo', args='--cflags --libs')
211     if not conf.env['IS_MACOSX']:
212         conf.env.append_unique('LDFLAGS', '-Wl,--no-undefined')
213     else:
214         conf.check(lib='aften', uselib='AFTEN', define_name='AFTEN')
215         conf.check_cxx(
216             fragment=''
217             + '#include <aften/aften.h>\n'
218             + 'int\n'
219             + 'main(void)\n'
220             + '{\n'
221             + 'AftenContext fAftenContext;\n'
222             + 'aften_set_defaults(&fAftenContext);\n'
223             + 'unsigned char *fb;\n'
224             + 'float *buf=new float[10];\n'
225             + 'int res = aften_encode_frame(&fAftenContext, fb, buf, 1);\n'
226             + '}\n',
227             lib='aften',
228             msg='Checking for aften_encode_frame()',
229             define_name='HAVE_AFTEN_NEW_API',
230             mandatory=False)
232         # TODO
233         flags.add_cxx('-Wno-deprecated-register')
235     conf.load('autooptions')
237     conf.env['LIB_PTHREAD'] = ['pthread']
238     conf.env['LIB_DL'] = ['dl']
239     conf.env['LIB_RT'] = ['rt']
240     conf.env['LIB_M'] = ['m']
241     conf.env['LIB_STDC++'] = ['stdc++']
242     conf.env['JACK_VERSION'] = VERSION
244     conf.env['BINDIR'] = conf.env['PREFIX'] + '/bin'
246     if Options.options.htmldir:
247         conf.env['HTMLDIR'] = Options.options.htmldir
248     else:
249         # set to None here so that the doxygen code can find out the highest
250         # directory to remove upon install
251         conf.env['HTMLDIR'] = None
253     if Options.options.libdir:
254         conf.env['LIBDIR'] = Options.options.libdir
255     else:
256         conf.env['LIBDIR'] = conf.env['PREFIX'] + '/lib'
258     if Options.options.pkgconfigdir:
259         conf.env['PKGCONFDIR'] = Options.options.pkgconfigdir
260     else:
261         conf.env['PKGCONFDIR'] = conf.env['LIBDIR'] + '/pkgconfig'
263     if Options.options.mandir:
264         conf.env['MANDIR'] = Options.options.mandir
265     else:
266         conf.env['MANDIR'] = conf.env['PREFIX'] + '/share/man/man1'
268     if conf.env['BUILD_DEBUG']:
269         flags.add_candcxx('-g')
270         flags.add_link('-g')
272     conf.define('JACK_VERSION', conf.env['JACK_VERSION'])
273     conf.write_config_header('config.h', remove=False)
275     conf.recurse('dbus')
277     flags.flush()
279     print()
280     version_msg = APPNAME + "-" + VERSION
281     if os.access('version.h', os.R_OK):
282         data = open('version.h').read()
283         m = re.match(r'^#define GIT_VERSION "([^"]*)"$', data)
284         if m != None:
285             version_msg += " exported from " + m.group(1)
286     elif os.access('.git', os.R_OK):
287         version_msg += " git revision will be checked and eventually updated during build"
288     print(version_msg)
290     conf.msg('Install prefix', conf.env['PREFIX'], color='CYAN')
291     conf.msg('Library directory', conf.all_envs['']['LIBDIR'], color='CYAN')
292     display_feature(conf, 'Build debuggable binaries', conf.env['BUILD_DEBUG'])
294     tool_flags = [
295         ('C compiler flags',   ['CFLAGS', 'CPPFLAGS']),
296         ('C++ compiler flags', ['CXXFLAGS', 'CPPFLAGS']),
297         ('Linker flags',       ['LINKFLAGS', 'LDFLAGS'])
298     ]
299     for name, vars in tool_flags:
300         flags = []
301         for var in vars:
302             flags += conf.all_envs[''][var]
303         conf.msg(name, repr(flags), color='NORMAL')
305     #conf.summarize_auto_options()
307     conf.msg('D-Bus service install directory', conf.env['DBUS_SERVICES_DIR'], color='CYAN')
309     if conf.env['DBUS_SERVICES_DIR'] != conf.env['DBUS_SERVICES_DIR_REAL']:
310         print()
311         print(Logs.colors.RED + 'WARNING: D-Bus session services directory as reported by pkg-config is')
312         print(Logs.colors.RED + 'WARNING:', end=' ')
313         print(Logs.colors.CYAN + conf.env['DBUS_SERVICES_DIR_REAL'])
314         print(Logs.colors.RED + 'WARNING: but service file will be installed in')
315         print(Logs.colors.RED + 'WARNING:', end=' ')
316         print(Logs.colors.CYAN + conf.env['DBUS_SERVICES_DIR'])
317         print(
318             Logs.colors.RED + 'WARNING: You may need to adjust your D-Bus configuration after installing jackdbus'
319             )
320         print('WARNING: You can override dbus service install directory')
321         print('WARNING: with --enable-pkg-config-dbus-service-dir option to this script')
322         print(Logs.colors.NORMAL, end=' ')
323     print()
325 def git_ver(self):
326     bld = self.generator.bld
327     header = self.outputs[0].abspath()
328     if os.access('./version.h', os.R_OK):
329         header = os.path.join(os.getcwd(), out, "version.h")
330         shutil.copy('./version.h', header)
331         data = open(header).read()
332         m = re.match(r'^#define GIT_VERSION "([^"]*)"$', data)
333         if m != None:
334             self.ver = m.group(1)
335             Logs.pprint('BLUE', "tarball from git revision " + self.ver)
336         else:
337             self.ver = "tarball"
338         return
340     if bld.srcnode.find_node('.git'):
341         self.ver = bld.cmd_and_log("LANG= git rev-parse HEAD", quiet=Context.BOTH).splitlines()[0]
342         if bld.cmd_and_log("LANG= git diff-index --name-only HEAD", quiet=Context.BOTH).splitlines():
343             self.ver += "-dirty"
345         Logs.pprint('BLUE', "git revision " + self.ver)
346     else:
347         self.ver = "unknown"
349     fi = open(header, 'w')
350     fi.write('#define GIT_VERSION "%s"\n' % self.ver)
351     fi.close()
353 def build(bld):
354     bld(rule=git_ver, target='version.h', update_outputs=True, always=True, ext_out=['.h'])
356     # process subfolders from here
358     if bld.env['IS_LINUX'] or bld.env['IS_FREEBSD']:
359         bld.recurse('man')
360     bld.recurse('dbus')
362     if bld.env['BUILD_DOXYGEN_DOCS']:
363         html_build_dir = bld.path.find_or_declare('html').abspath()
365         bld(
366             features='subst',
367             source='doxyfile.in',
368             target='doxyfile',
369             HTML_BUILD_DIR=html_build_dir,
370             SRCDIR=bld.srcnode.abspath(),
371             VERSION=VERSION
372         )
374         # There are two reasons for logging to doxygen.log and using it as
375         # target in the build rule (rather than html_build_dir):
376         # (1) reduce the noise when running the build
377         # (2) waf has a regular file to check for a timestamp. If the directory
378         #     is used instead waf will rebuild the doxygen target (even upon
379         #     install).
380         def doxygen(task):
381             doxyfile = task.inputs[0].abspath()
382             logfile = task.outputs[0].abspath()
383             cmd = '%s %s &> %s' % (task.env['DOXYGEN'][0], doxyfile, logfile)
384             return task.exec_command(cmd)
386         bld(
387             rule=doxygen,
388             source='doxyfile',
389             target='doxygen.log'
390         )
392         # Determine where to install HTML documentation. Since share_dir is the
393         # highest directory the uninstall routine should remove, there is no
394         # better candidate for share_dir, but the requested HTML directory if
395         # --htmldir is given.
396         if bld.env['HTMLDIR']:
397             html_install_dir = bld.options.destdir + bld.env['HTMLDIR']
398             share_dir = html_install_dir
399         else:
400             share_dir = bld.options.destdir + bld.env['PREFIX'] + '/share/jack-audio-connection-kit'
401             html_install_dir = share_dir + '/reference/html/'
403         if bld.cmd == 'install':
404             if os.path.isdir(html_install_dir):
405                 Logs.pprint('CYAN', 'Removing old doxygen documentation installation...')
406                 shutil.rmtree(html_install_dir)
407                 Logs.pprint('CYAN', 'Removing old doxygen documentation installation done.')
408             Logs.pprint('CYAN', 'Installing doxygen documentation...')
409             shutil.copytree(html_build_dir, html_install_dir)
410             Logs.pprint('CYAN', 'Installing doxygen documentation done.')
411         elif bld.cmd == 'uninstall':
412             Logs.pprint('CYAN', 'Uninstalling doxygen documentation...')
413             if os.path.isdir(share_dir):
414                 shutil.rmtree(share_dir)
415             Logs.pprint('CYAN', 'Uninstalling doxygen documentation done.')
416         elif bld.cmd == 'clean':
417             if os.access(html_build_dir, os.R_OK):
418                 Logs.pprint('CYAN', 'Removing doxygen generated documentation...')
419                 shutil.rmtree(html_build_dir)
420                 Logs.pprint('CYAN', 'Removing doxygen generated documentation done.')
423 @TaskGen.extension('.mm')
424 def mm_hook(self, node):
425     """Alias .mm files to be compiled the same as .cpp files, gcc will do the right thing."""
426     return self.create_compiled_task('cxx', node)