X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=wscript;h=86c65ad74da8f49aae7321d3d45694f879c1f8d1;hp=02030306bdb923ebf79fc553adec811e9aa72969;hb=e81c5eb9e8ff875240dde9fdaaab0a46f99af615;hpb=bbab1b7af29584d336648dcb713c83e0f09d8923 diff --git a/wscript b/wscript index 02030306b..86c65ad74 100644 --- a/wscript +++ b/wscript @@ -1,5 +1,5 @@ # -# Copyright (C) 2012-2017 Carl Hetherington +# Copyright (C) 2012-2019 Carl Hetherington # # This file is part of DCP-o-matic. # @@ -17,6 +17,8 @@ # along with DCP-o-matic. If not, see . # +from __future__ import print_function + import subprocess import os import shlex @@ -24,10 +26,29 @@ import sys import glob import distutils import distutils.spawn +try: + # python 2 + from urllib import urlencode +except ImportError: + # python 3 + from urllib.parse import urlencode from waflib import Logs, Context APPNAME = 'dcpomatic' -VERSION = '2.11.54' + +this_version = subprocess.Popen(shlex.split('git tag -l --points-at HEAD'), stdout=subprocess.PIPE).communicate()[0] +last_version = subprocess.Popen(shlex.split('git describe --tags --abbrev=0'), stdout=subprocess.PIPE).communicate()[0] + +# Python 2/3 compatibility; I don't really understand what's going on here +if not isinstance(this_version, str): + this_version = this_version.decode('utf-8') +if not isinstance(last_version, str): + last_version = last_version.decode('utf-8') + +if this_version == '': + VERSION = '%sdevel' % last_version[1:].strip() +else: + VERSION = this_version[1:].strip() def options(opt): opt.load('compiler_cxx') @@ -51,9 +72,13 @@ def options(opt): opt.add_option('--static-curl', action='store_true', default=False, help='link statically to libcurl') opt.add_option('--workaround-gssapi', action='store_true', default=False, help='link to gssapi_krb5') opt.add_option('--force-cpp11', action='store_true', default=False, help='force use of C++11') + opt.add_option('--variant', help='build variant (swaroop-studio, swaroop-theater)', choices=['swaroop-studio', 'swaroop-theater']) + opt.add_option('--use-lld', action='store_true', default=False, help='use lld linker') + opt.add_option('--enable-disk', action='store_true', default=False, help='build dcpomatic2_disk tool; requires Boost process, lwext4 and nanomsg libraries') def configure(conf): conf.load('compiler_cxx') + conf.load('clang_compilation_database', tooldir=['waf-tools']) if conf.options.target_windows: conf.load('winres') @@ -66,6 +91,7 @@ def configure(conf): conf.env.VERSION = VERSION conf.env.DEBUG = conf.options.enable_debug conf.env.STATIC_DCPOMATIC = conf.options.static_dcpomatic + conf.env.ENABLE_DISK = conf.options.enable_disk if conf.options.install_prefix is None: conf.env.INSTALL_PREFIX = conf.env.PREFIX else: @@ -78,25 +104,47 @@ def configure(conf): '-msse', '-fno-strict-aliasing', '-Wall', - '-Wno-attributes', '-Wextra', + '-Wwrite-strings', # Remove auto_ptr warnings from libxml++-2.6 '-Wno-deprecated-declarations', + '-Wno-ignored-qualifiers', + '-Wno-parentheses', '-D_FILE_OFFSET_BITS=64']) if conf.options.force_cpp11: conf.env.append_value('CXXFLAGS', ['-std=c++11', '-DBOOST_NO_CXX11_SCOPED_ENUMS']) - gcc = conf.env['CC_VERSION'] - if int(gcc[0]) >= 4 and int(gcc[1]) > 1: - conf.env.append_value('CXXFLAGS', ['-Wno-unused-result']) - have_c11 = int(gcc[0]) >= 4 and int(gcc[1]) >= 8 and int(gcc[2]) >= 1 + if conf.env['CXX_NAME'] == 'gcc': + gcc = conf.env['CC_VERSION'] + if int(gcc[0]) >= 4 and int(gcc[1]) > 1: + conf.env.append_value('CXXFLAGS', ['-Wno-unused-result']) + if int(gcc[0]) >= 9: + conf.env.append_value('CXXFLAGS', ['-Wno-deprecated-copy']) + have_c11 = int(gcc[0]) >= 4 and int(gcc[1]) >= 8 and int(gcc[2]) >= 1 + else: + have_c11 = False if conf.options.enable_debug: conf.env.append_value('CXXFLAGS', ['-g', '-DDCPOMATIC_DEBUG', '-fno-omit-frame-pointer']) else: conf.env.append_value('CXXFLAGS', '-O2') + if conf.options.variant is not None: + conf.env.VARIANT = conf.options.variant + if conf.options.variant.startswith('swaroop-'): + conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_VARIANT_SWAROOP') + + if conf.options.enable_disk: + conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_DISK') + + if conf.options.use_lld: + try: + conf.find_program('ld.lld') + conf.env.append_value('LINKFLAGS', '-fuse-ld=lld') + except conf.errors.ConfigurationError: + pass + # # Windows/Linux/OS X specific # @@ -110,6 +158,7 @@ def configure(conf): conf.env.append_value('CXXFLAGS', '-DBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN') conf.env.append_value('CXXFLAGS', '-mfpmath=sse') conf.env.append_value('CXXFLAGS', '-std=c++11') + conf.env.append_value('CXXFLAGS', '-Wcast-align') wxrc = os.popen('wx-config --rescomp').read().split()[1:] conf.env.append_value('WINRCFLAGS', wxrc) if conf.options.enable_debug: @@ -123,8 +172,9 @@ def configure(conf): conf.check(lib='dsound', uselib_store='DSOUND', msg="Checking for library dsound") conf.check(lib='winmm', uselib_store='WINMM', msg="Checking for library winmm") conf.check(lib='ksuser', uselib_store='KSUSER', msg="Checking for library ksuser") + conf.check(lib='setupapi', uselib_store='SETUPAPI', msg="Checking for library setupapi") boost_lib_suffix = '-mt' - boost_thread = 'boost_thread_win32-mt' + boost_thread = 'boost_thread-mt' conf.check_cxx(fragment=""" #include \n int main() { std::locale::global (boost::locale::generator().generate ("")); }\n @@ -147,6 +197,8 @@ def configure(conf): conf.env.append_value('CXXFLAGS', '-DLINUX_LOCALE_PREFIX="%s/share/locale"' % conf.env['INSTALL_PREFIX']) conf.env.append_value('CXXFLAGS', '-DLINUX_SHARE_PREFIX="%s/share/dcpomatic2"' % conf.env['INSTALL_PREFIX']) conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_LINUX') + conf.env.append_value('CXXFLAGS', ['-Wlogical-op', '-Wcast-align']) + conf.check(lib='dl', uselib_store='DL', msg='Checking for library dl') if not conf.env.DISABLE_GUI: conf.check_cfg(package='gtk+-2.0', args='--cflags --libs', uselib_store='GTK', mandatory=True) @@ -154,6 +206,9 @@ def configure(conf): if conf.env.TARGET_OSX: conf.env.append_value('CXXFLAGS', ['-DDCPOMATIC_OSX', '-Wno-unused-function', '-Wno-unused-parameter', '-Wno-unused-local-typedef', '-Wno-potentially-evaluated-expression']) conf.env.append_value('LINKFLAGS', '-headerpad_max_install_names') + else: + # Avoid the endless warnings about _t uninitialized in optional<> + conf.env.append_value('CXXFLAGS', '-Wno-maybe-uninitialized') # # Dependencies. @@ -194,79 +249,6 @@ def configure(conf): # glib conf.check_cfg(package='glib-2.0', args='--cflags --libs', uselib_store='GLIB', mandatory=True) - # ImageMagick / GraphicsMagick - if distutils.spawn.find_executable('Magick++-config'): - conf.check_cfg(package='', path='Magick++-config', args='--cppflags --cxxflags --libs', uselib_store='MAGICK', mandatory=True) - conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_IMAGE_MAGICK') - else: - image = conf.check_cfg(package='ImageMagick++', args='--cflags --libs', uselib_store='MAGICK', mandatory=False) - graphics = None - if image is None: - graphics = conf.check_cfg(package='GraphicsMagick++', args='--cflags --libs', uselib_store='MAGICK', mandatory=False) - if image is None and graphics is None: - Logs.pprint('RED', 'Neither ImageMagick++ nor GraphicsMagick++ found: one or the other is required') - if image is not None: - conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_IMAGE_MAGICK') - if graphics is not None: - conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_GRAPHICS_MAGICK') - - # See if we are using the MagickCore or MagickLib namespaces - conf.check_cxx(fragment=""" - #include \n - using namespace MagickCore;\n - int main () { return 0; }\n - """, - mandatory=False, - msg='Checking for MagickCore namespace', - okmsg='yes', - includes=conf.env['INCLUDES_MAGICK'], - define_name='DCPOMATIC_HAVE_MAGICKCORE_NAMESPACE') - - conf.check_cxx(fragment=""" - #include \n - using namespace MagickLib;\n - int main () { return 0; }\n - """, - mandatory=False, - msg='Checking for MagickLib namespace', - okmsg='yes', - includes=conf.env['INCLUDES_MAGICK'], - define_name='DCPOMATIC_HAVE_MAGICKLIB_NAMESPACE') - - # See where MagickCore.h is - conf.check_cxx(fragment=""" - #include \n - int main() { return 0; }\n - """, - mandatory=False, - msg='Checking for MagickCore.h location', - okmsg='magick', - errmsg='not magick', - includes=conf.env['INCLUDES_MAGICK'], - define_name='DCPOMATIC_MAGICKCORE_MAGICK') - - conf.check_cxx(fragment=""" - #include \n - int main() { return 0; }\n - """, - mandatory=False, - msg='Checking for MagickCore.h location', - okmsg='MagickCore', - errmsg='not MagickCore', - includes=conf.env['INCLUDES_MAGICK'], - define_name='DCPOMATIC_MAGICKCORE_MAGICKCORE') - - # See if we have advanced compare() methods in Magick - conf.check_cxx(fragment=""" - #include \n - int main() { Magick::Image a; Magick::Image b; a.compare(b, Magick::RootMeanSquaredErrorMetric); } - """, - mandatory=False, - msg='Checking for advanced compare() method in {Image/Graphics}Magick', - uselib='MAGICK', - define_name='DCPOMATIC_ADVANCED_MAGICK_COMPARE' - ) - # libzip conf.check_cfg(package='libzip', args='--cflags --libs', uselib_store='ZIP', mandatory=True) conf.check_cxx(fragment=""" @@ -288,6 +270,9 @@ def configure(conf): # cairomm conf.check_cfg(package='cairomm-1.0', args='--cflags --libs', uselib_store='CAIROMM', mandatory=True) + # leqm_nrt + conf.check_cfg(package='leqm_nrt', args='--cflags --libs', uselib_store='LEQM_NRT', mandatory=True) + test_cxxflags = '' if have_c11: test_cxxflags = '-std=c++11' @@ -327,10 +312,10 @@ def configure(conf): # libcxml if conf.options.static_cxml: - conf.check_cfg(package='libcxml', atleast_version='0.15.1', args='--cflags', uselib_store='CXML', mandatory=True) + conf.check_cfg(package='libcxml', atleast_version='0.16.0', args='--cflags', uselib_store='CXML', mandatory=True) conf.env.STLIB_CXML = ['cxml'] else: - conf.check_cfg(package='libcxml', atleast_version='0.15.1', args='--cflags --libs', uselib_store='CXML', mandatory=True) + conf.check_cfg(package='libcxml', atleast_version='0.16.0', args='--cflags --libs', uselib_store='CXML', mandatory=True) # libssh if conf.options.static_ssh: @@ -352,21 +337,21 @@ def configure(conf): # libdcp if conf.options.static_dcp: - conf.check_cfg(package='libdcp-1.0', atleast_version='1.4.1', args='--cflags', uselib_store='DCP', mandatory=True) + conf.check_cfg(package='libdcp-1.0', atleast_version='1.6.7', args='--cflags', uselib_store='DCP', mandatory=True) conf.env.DEFINES_DCP = [f.replace('\\', '') for f in conf.env.DEFINES_DCP] - conf.env.STLIB_DCP = ['dcp-1.0', 'asdcp-cth', 'kumu-cth', 'openjp2'] - conf.env.LIB_DCP = ['glibmm-2.4', 'ssl', 'crypto', 'bz2', 'xslt'] + conf.env.STLIB_DCP = ['dcp-1.0', 'asdcp-carl', 'kumu-carl', 'openjp2'] + conf.env.LIB_DCP = ['glibmm-2.4', 'ssl', 'crypto', 'bz2', 'xslt', 'xerces-c'] else: - conf.check_cfg(package='libdcp-1.0', atleast_version='1.4.1', args='--cflags --libs', uselib_store='DCP', mandatory=True) + conf.check_cfg(package='libdcp-1.0', atleast_version='1.6.7', args='--cflags --libs', uselib_store='DCP', mandatory=True) conf.env.DEFINES_DCP = [f.replace('\\', '') for f in conf.env.DEFINES_DCP] # libsub if conf.options.static_sub: - conf.check_cfg(package='libsub-1.0', atleast_version='1.2.1', args='--cflags', uselib_store='SUB', mandatory=True) + conf.check_cfg(package='libsub-1.0', atleast_version='1.4.7', args='--cflags', uselib_store='SUB', mandatory=True) conf.env.DEFINES_SUB = [f.replace('\\', '') for f in conf.env.DEFINES_SUB] conf.env.STLIB_SUB = ['sub-1.0'] else: - conf.check_cfg(package='libsub-1.0', atleast_version='1.2.1', args='--cflags --libs', uselib_store='SUB', mandatory=True) + conf.check_cfg(package='libsub-1.0', atleast_version='1.4.7', args='--cflags --libs', uselib_store='SUB', mandatory=True) conf.env.DEFINES_SUB = [f.replace('\\', '') for f in conf.env.DEFINES_SUB] # libxml++ @@ -388,6 +373,31 @@ def configure(conf): # nettle conf.check_cfg(package="nettle", args='--cflags --libs', uselib_store='NETTLE', mandatory=True) + # libpng + conf.check_cfg(package='libpng', args='--cflags --libs', uselib_store='PNG', mandatory=True) + + # lwext4 + if conf.options.enable_disk: + conf.check_cxx(fragment=""" + #include \n + int main() { ext4_mount("ext4_fs", "/mp/", false); }\n + """, + msg='Checking for lwext4 library', + libpath='/usr/local/lib', + lib=['lwext4', 'blockdev'], + uselib_store='LWEXT4') + + if conf.env.TARGET_LINUX and conf.options.enable_disk: + conf.check_cfg(package='polkit-gobject-1', args='--cflags --libs', uselib_store='POLKIT', mandatory=True) + + # nanomsg + if conf.options.enable_disk: + if conf.check_cfg(package='nanomsg', args='--cflags --libs', uselib_store='NANOMSG', mandatory=False) is None: + conf.check_cfg(package='libnanomsg', args='--cflags --libs', uselib_store='NANOMSG', mandatory=True) + if conf.env.TARGET_LINUX: + # We link with nanomsg statically on Centos 8 so we need to link this as well + conf.env.LIB_NANOMSG.append('anl') + # FFmpeg if conf.options.static_ffmpeg: names = ['avformat', 'avfilter', 'avcodec', 'avutil', 'swscale', 'postproc', 'swresample'] @@ -429,9 +439,7 @@ def configure(conf): int main () { av_ebur128_get_true_peaks (0); }\n """, msg='Checking for EBUR128-patched FFmpeg', - libpath=conf.env['LIBPATH_AVFORMAT'], - lib='avfilter avutil swresample', - includes=conf.env['INCLUDES_AVFORMAT'], + uselib='AVCODEC AVFILTER', define_name='DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG', mandatory=False) @@ -445,9 +453,7 @@ def configure(conf): """, msg='Checking for AVSubtitleRect::pict', cxxflags='-Wno-unused-result -Wno-unused-value -Wdeprecated-declarations -Werror', - libpath=conf.env['LIBPATH_AVCODEC'], - lib='avcodec', - includes=conf.env['INCLUDES_AVCODEC'], + uselib='AVCODEC', define_name='DCPOMATIC_HAVE_AVSUBTITLERECT_PICT', mandatory=False) @@ -461,17 +467,18 @@ def configure(conf): """, msg='Checking for AVComponentDescriptor::depth_minus1', cxxflags='-Wno-unused-result -Wno-unused-value -Wdeprecated-declarations -Werror', - libpath=conf.env['LIBPATH_AVUTIL'], - lib='avutil', - includes=conf.env['INCLUDES_AVUTIL'], + uselib='AVUTIL', define_name='DCPOMATIC_HAVE_AVCOMPONENTDESCRIPTOR_DEPTH_MINUS1', mandatory=False) # Hack: the previous two check_cxx calls end up copying their (necessary) cxxflags - # to these variables. We don't want to use these for the actual build, so clearn them out. + # to these variables. We don't want to use these for the actual build, so clean them out. conf.env['CXXFLAGS_AVCODEC'] = [] conf.env['CXXFLAGS_AVUTIL'] = [] + if conf.env.TARGET_LINUX: + conf.env.LIB_X11 = ['X11'] + # Boost if conf.options.static_boost: conf.env.STLIB_BOOST_THREAD = ['boost_thread'] @@ -535,6 +542,21 @@ def configure(conf): lib=['boost_regex%s' % boost_lib_suffix], uselib_store='BOOST_REGEX') + # Really just checking for the header here (there's no associated library) but the test + # program has to link with boost_system so I'm doing it this way. + if conf.options.enable_disk: + deps = ['boost_system%s' % boost_lib_suffix] + if conf.env.TARGET_WINDOWS: + deps.append('ws2_32') + deps.append('boost_filesystem%s' % boost_lib_suffix) + conf.check_cxx(fragment=""" + #include \n + int main() { boost::process::child* c = new boost::process::child("foo"); }\n + """, + msg='Checking for boost process library', + lib=deps, + uselib_store='BOOST_PROCESS') + # libxml++ requires glibmm and versions of glibmm 2.45.31 and later # must be built with -std=c++11 as they use c++11 # features and c++11 is not (yet) the default in gcc. @@ -547,6 +569,7 @@ def configure(conf): # Other stuff conf.find_program('msgfmt', var='MSGFMT') + conf.check(header_name='valgrind/memcheck.h', mandatory=False) datadir = conf.env.DATADIR if not datadir: @@ -588,12 +611,24 @@ def configure(conf): Logs.pprint('YELLOW', '') -def download_supporters(): - os.system('curl https://dcpomatic.com/supporters.cc > build/supporters.cc') +def download_supporters(can_fail): + r = os.system('curl -m 2 -s -f https://dcpomatic.com/supporters.cc > src/wx/supporters.cc') + if (r >> 8) == 0: + r = os.system('curl -s -f https://dcpomatic.com/subscribers.cc > src/wx/subscribers.cc') + if (r >> 8) != 0: + if can_fail: + raise Exception("Could not download supporters lists (%d)" % (r >> 8)) + else: + f = open('src/wx/supporters.cc', 'w') + print('supported_by.Add(wxT("Debug build - no supporters lists available"));', file=f) + f.close() + f = open('src/wx/subscribers.cc', 'w') + print('subscribers.Add(wxT("Debug build - no subscribers lists available"));', file=f) + f.close() def build(bld): create_version_cc(VERSION, bld.env.CXXFLAGS) - download_supporters() + download_supporters(not bld.env.DEBUG) bld.recurse('src') bld.recurse('graphics') @@ -629,13 +664,13 @@ def dist(ctx): r = git_revision() if r is not None: f = open('.git_revision', 'w') - print >>f,r - f.close() + print(r, file=f) + f.close() ctx.excl = """ TODO core *~ src/wx/*~ src/lib/*~ builds/*~ doc/manual/*~ src/tools/*~ *.pyc .waf* build .git deps alignment hacks sync *.tar.bz2 *.exe .lock* *build-windows doc/manual/pdf doc/manual/html - GRSYMS GRTAGS GSYMS GTAGS + GRSYMS GRTAGS GSYMS GTAGS compile_commands.json """ def create_version_cc(version, cxx_flags): @@ -667,8 +702,18 @@ def create_version_cc(version, cxx_flags): sys.exit(-1) def post(ctx): - if ctx.cmd == 'install': + if ctx.cmd == 'install' and ctx.env.TARGET_LINUX: ctx.exec_command('/sbin/ldconfig') + # setuid root executables + for e in ['dcpomatic2_uuid', 'dcpomatic2_disk_writer']: + # I can't find anything which tells me where things have been installed to, + # so here's some nasty hacks to guess. + debian = os.path.join(ctx.out_dir, '../debian/dcpomatic/usr/bin/%s' % e) + prefix = os.path.join(ctx.env['INSTALL_PREFIX'], 'bin/%s' % e) + if os.path.exists(debian): + os.chmod(debian, 0o4755) + if os.path.exists(prefix): + os.chmod(prefix, 0o4755) def pot(bld): bld.recurse('src')