block Core() class constructor
[vapoursynth-svn.git] / wscript
blob60816a3489d8c78f31cf6144e1b5bdc2678f64ad
1 import glob, os, subprocess, sys
2 from waflib import Build, Task, TaskGen, Utils
4 APPNAME = 'VapourSynth'
5 VERSION = '19'
7 TOP = os.curdir
8 OUT = 'build'
10 class preproc(Task.Task):
11     "Preprocess Cython source files"
13     ext_out = ['.pyx']
14     inst_to = None
15     color = 'CYAN'
17     def run(self):
18         if self.env.CXX_NAME == 'gcc':
19             params = ['-E', '-x', 'c']
20         elif self.env.CXX_NAME == 'msvc':
21             params = ['/nologo', '/E']
23         args = [Utils.subst_vars('${CC}', self.env)] + params + [self.inputs[0].abspath()]
25         with open(self.outputs[0].abspath(), 'w') as f:
26             subprocess.Popen(args, stdout = f).wait()
28 @TaskGen.extension('.pyx')
29 def add_pyx_file(self, node):
30     self.create_task('preproc', node, node.get_bld().change_ext('.pyx'))
32 class docs(Task.Task):
33     "Build Sphinx documentation"
35     ext_out = ['.html']
36     inst_to = None
37     color = 'PINK'
39     def run(self):
40         subprocess.Popen('make html BUILDDIR={0}'.format(os.path.join(os.pardir, OUT)),
41                          shell = True,
42                          cwd = 'doc',
43                          stdout = subprocess.PIPE).wait()
45 @TaskGen.feature('docs')
46 @TaskGen.before_method('process_source')
47 def apply_rst(self):
48     rst_nodes = []
49     no_nodes = []
51     for x in self.to_nodes(self.source):
52         if x.name.endswith('.rst'):
53             rst_nodes.append(x)
54         else:
55             no_nodes.append(x)
57     self.source = no_nodes
59     inst = getattr(self, 'install_path', '${DOCDIR}')
60     mod = getattr(self, 'chmod', Utils.O644)
62     bld_nodes = []
63     i = 0
65     for node in rst_nodes:
66         n = self.path.find_node(OUT).make_node('html')
68         cur = node.parent
69         dirs = []
71         while not cur is self.path.find_node('doc'):
72             dirs.append(cur)
73             cur = cur.parent
75         for dir in reversed(dirs):
76             n = n.make_node(dir.name)
78         n = n.make_node(node.name).change_ext('.html')
80         bld_nodes.append(n)
82         if inst:
83             path = inst
85             for dir in reversed(dirs):
86                 path = os.path.join(path, dir.name)
88             setattr(self, 'install_task_{0}'.format(i), self.bld.install_files(path, n, env = self.env, chmod = mod))
90         i += 1
92     self.rst_task = self.create_task('docs', rst_nodes, bld_nodes)
94 def options(opt):
95     opt.load('compiler_c')
96     opt.load('compiler_cxx')
97     opt.load('qt4')
99     opt.add_option('--libdir', action = 'store', default = '${PREFIX}/lib', help = 'library installation directory')
100     opt.add_option('--plugindir', action = 'store', default = '${LIBDIR}/vapoursynth', help = 'plugin installation directory')
101     opt.add_option('--docdir', action = 'store', default = '${PREFIX}/share/doc/vapoursynth', help = 'documentation installation directory')
102     opt.add_option('--includedir', action = 'store', default = '${PREFIX}/include/vapoursynth', help = 'header installation directory')
103     opt.add_option('--mode', action = 'store', default = 'release', help = 'the mode to compile in (debug/release)')
104     opt.add_option('--shared', action = 'store', default = 'true', help = 'build a shared library (true/false)')
105     opt.add_option('--static', action = 'store', default = 'false', help = 'build a static library (true/false)')
106     opt.add_option('--filters', action = 'store', default = 'true', help = 'build included filters (true/false)')
107     opt.add_option('--cython', action = 'store', default = 'true', help = 'build Cython wrapper (true/false)')
108     opt.add_option('--avisynth', action = 'store', default = 'true', help = 'build Avisynth compatibility layer (true/false)')
109     opt.add_option('--docs', action = 'store', default = 'false', help = 'build the documentation (true/false)')
110     opt.add_option('--examples', action = 'store', default = 'false', help = 'install SDK examples (true/false)')
112 def configure(conf):
113     def add_options(flags, options):
114         for flag in flags:
115             conf.env.append_unique(flag, options)
117     conf.load('compiler_c')
118     conf.load('compiler_cxx')
119     conf.load('qt4')
121     if conf.env.DEST_CPU in ['x86', 'x86_64', 'x64', 'amd64', 'x86_amd64']:
122         # Load Yasm explicitly, then the Nasm module which
123         # supports both Nasm and Yasm.
124         conf.find_program('yasm', var = 'AS', mandatory = True)
125         conf.load('nasm')
127     conf.find_program(['python3', 'python'], var = 'PYTHON', mandatory = True)
129     if conf.env.DEST_OS == 'darwin':
130         if conf.env.CXX_NAME == 'gcc':
131             add_options(['ASFLAGS'],
132                         ['-DPREFIX=1'])
134     if conf.env.CXX_NAME == 'gcc':
135         add_options(['CFLAGS', 'CXXFLAGS'],
136                     ['-DVSCORE_EXPORTS',
137                      '-fPIC'])
138     elif conf.env.CXX_NAME == 'msvc':
139         add_options(['CFLAGS', 'CXXFLAGS'],
140                     ['/DVSCORE_EXPORTS',
141                      '/EHsc',
142                      '/Zc:wchar_t-'])
144     add_options(['ASFLAGS'],
145                 ['-w',
146                  '-Worphan-labels',
147                  '-Wunrecognized-char',
148                  '-Dprogram_name=vs'])
150     if conf.env.DEST_CPU in ['x86_64', 'x64', 'amd64', 'x86_amd64']:
151         add_options(['ASFLAGS'],
152                     ['-DARCH_X86_64=1',
153                      '-DPIC=1'])
155         if conf.env.DEST_OS == 'darwin':
156             fmt = 'macho64'
157         elif conf.env.DEST_OS in ['win32', 'cygwin', 'msys', 'uwin']:
158             fmt = 'win64'
159         else:
160             fmt = 'elf64'
161     elif conf.env.DEST_CPU == 'x86':
162         add_options(['ASFLAGS'],
163                     ['-DARCH_X86_64=0'])
165         if conf.env.DEST_OS == 'darwin':
166             fmt = 'macho32'
167         elif conf.env.DEST_OS in ['win32', 'cygwin', 'msys', 'uwin']:
168             fmt = 'win32'
169         else:
170             fmt = 'elf32'
172     if conf.env.DEST_CPU in ['x86', 'x86_64', 'x64']:
173         add_options(['ASFLAGS'],
174                     ['-f{0}'.format(fmt)])
176     if conf.options.mode == 'debug':
177         if conf.env.CXX_NAME == 'gcc':
178             add_options(['CFLAGS', 'CXXFLAGS'],
179                         ['-DVSCORE_DEBUG',
180                          '-g',
181                          '-ggdb',
182                          '-ftrapv'])
183         elif conf.env.CXX_NAME == 'msvc':
184             add_options(['CFLAGS', 'CXXFLAGS'],
185                         ['/DVSCORE_DEBUG',
186                          '/Z7'])
188         add_options(['ASFLAGS'],
189                     ['-DVSCORE_DEBUG'])
191         if conf.env.DEST_OS in ['win32', 'cygwin', 'msys', 'uwin']:
192             dbgfmt = 'cv8'
193         else:
194             dbgfmt = 'dwarf2'
196         add_options(['ASFLAGS'],
197                     ['-g{0}'.format(dbgfmt)])
198     elif conf.options.mode == 'release':
199         if conf.env.CXX_NAME == 'gcc':
200             add_options(['CFLAGS', 'CXXFLAGS'],
201                         ['-O3'])
202         elif conf.env.CXX_NAME == 'msvc':
203             add_options(['CFLAGS', 'CXXFLAGS'],
204                         ['/Ox'])
205     else:
206         conf.fatal('--mode must be either debug or release.')
208     # Waf always uses gcc/g++ for linking when using a GCC
209     # compatible C/C++ compiler.
210     if conf.env.CXX_NAME == 'gcc':
211         if not conf.env.DEST_OS in ['darwin', 'win32', 'cygwin', 'msys', 'uwin']:
212             add_options(['LINKFLAGS_cshlib',
213                          'LINKFLAGS_cprogram',
214                          'LINKFLAGS_cxxshlib',
215                          'LINKFLAGS_cxxprogram'],
216                         ['-Wl,-Bsymbolic',
217                          '-Wl,-z,noexecstack'])
219     conf.msg("Setting DEST_OS to", conf.env.DEST_OS)
220     conf.msg("Setting DEST_CPU to", conf.env.DEST_CPU)
221     conf.msg("Setting DEST_BINFMT to", conf.env.DEST_BINFMT)
223     def check_feature(name, desc):
224         val = conf.options.__dict__[name]
226         if not val in ['true', 'false']:
227             conf.fatal('--{0} must be either true or false.'.format(name))
228         else:
229             u = name.upper()
231             conf.env[u] = val
232             conf.define('FEATURE_' + u, 1 if val == 'true' else 0)
233             conf.msg("Enabling {0}?".format(desc), 'yes' if conf.env[u] == 'true' else 'no')
235     check_feature('shared', 'shared library')
236     check_feature('static', 'static library')
237     check_feature('filters', 'included filters')
238     check_feature('cython', 'Cython wrapper')
239     check_feature('avisynth', 'Avisynth compatibility')
240     check_feature('docs', 'documentation')
241     check_feature('examples', 'SDK examples')
243     conf.define('PATH_PREFIX', conf.env.PREFIX)
244     conf.msg("Setting PREFIX to", conf.env.PREFIX)
246     for dir in ['libdir', 'plugindir', 'docdir', 'includedir']:
247         u = dir.upper()
249         conf.env[u] = Utils.subst_vars(conf.options.__dict__[dir], conf.env)
250         conf.define('PATH_' + u, conf.env[u])
251         conf.msg("Setting {0} to".format(u), conf.env[u])
253     conf.check_cxx(use = ['QTCORE'], header_name = 'QtCore/QtCore')
254     conf.check_cxx(use = ['QTCORE'], header_name = 'QtCore/QtCore', type_name = 'QAtomicInt')
256     conf.check_cc(lib = 'swscale')
257     conf.check_cc(use = ['SWSCALE'], header_name = 'libswscale/swscale.h')
258     conf.check_cc(use = ['SWSCALE'], header_name = 'libswscale/swscale.h', function_name = 'swscale_license')
260     conf.check_cc(lib = 'avutil')
261     conf.check_cc(use = ['AVUTIL'], header_name = 'libavutil/avutil.h')
262     conf.check_cc(use = ['AVUTIL'], header_name = 'libavutil/avutil.h', function_name = 'avutil_license')
264     conf.check_cc(lib = 'avcodec')
265     conf.check_cc(use = ['AVCODEC'], header_name = 'libavcodec/avcodec.h')
266     conf.check_cc(use = ['AVCODEC'], header_name = 'libavcodec/avcodec.h', function_name = 'avcodec_license')
268     conf.check_cc(lib = 'ass', mandatory = False)
269     conf.check_cc(use = ['ASS'], header_name = 'ass/ass.h', mandatory = False)
270     conf.check_cc(use = ['ASS'], header_name = 'ass/ass.h', function_name = 'ass_library_init', mandatory = False)
272     libs = '-lm '
274     if not conf.env.DEST_OS in ['darwin', 'freebsd', 'netbsd', 'openbsd']:
275         libs += '-ldl '
277     conf.env.LIBS = libs.strip()
279 def build(bld):
280     def search_paths(paths):
281         srcpaths = []
283         for path in paths:
284             srcpaths += [os.path.join(path, '*.c'),
285                          os.path.join(path, '*.cpp'),
286                          os.path.join(path, '*.asm')]
288         return srcpaths
290     sources = search_paths([os.path.join('src', 'core'),
291                             os.path.join('src', 'core', 'asm')])
293     if bld.env.DEST_OS in ['win32', 'cygwin', 'msys', 'uwin'] and bld.env.AVISYNTH == 'true':
294         sources += search_paths([os.path.join('src', 'avisynth')])
296     bld(features = 'c qxx asm',
297         includes = 'include',
298         use = ['QTCORE', 'SWSCALE', 'AVUTIL', 'AVCODEC'],
299         source = bld.path.ant_glob(sources),
300         target = 'objs')
302     if bld.env.SHARED == 'true':
303         bld(features = 'c qxx asm cxxshlib',
304             use = ['objs'],
305             target = 'vapoursynth',
306             install_path = '${LIBDIR}')
308     if bld.env.STATIC == 'true':
309         bld(features = 'c qxx asm cxxstlib',
310             use = ['objs', 'QTCORE', 'SWSCALE', 'AVUTIL'],
311             target = 'vapoursynth',
312             install_path = '${LIBDIR}')
314     if bld.env.FILTERS == 'true':
315         bld(features = 'c qxx asm cxxshlib',
316             includes = 'include',
317             source = bld.path.ant_glob(search_paths([os.path.join('src', 'filters', 'eedi3')])),
318             target = 'eedi3',
319             install_path = '${PLUGINDIR}')
321         bld(features = 'c qxx asm cxxshlib',
322             includes = 'include',
323             source = bld.path.ant_glob(search_paths([os.path.join('src', 'filters', 'vivtc')])),
324             target = 'vivtc',
325             install_path = '${PLUGINDIR}')
327         if bld.env.LIB_ASS:
328             bld(features = 'c cxxshlib',
329                 includes = 'include',
330                 use = ['ASS'],
331                 source = bld.path.ant_glob(search_paths([os.path.join('src', 'filters', 'assvapour')])),
332                 target = 'assvapour',
333                 install_path = '${PLUGINDIR}')
335     if bld.env.CYTHON == 'true':
336         bld(features = 'preproc',
337             source = bld.path.ant_glob([os.path.join('src', 'cython', '*.pyx')]))
339     if bld.env.DOCS == 'true':
340         bld(features = 'docs',
341             source = bld.path.ant_glob([os.path.join('doc', '*.rst'),
342                                         os.path.join('doc', '**', '*.rst')]),
343             install_path = '${DOCDIR}')
345     if bld.env.EXAMPLES == 'true':
346         bld(features = 'c cxxshlib',
347             includes = 'include',
348             source = os.path.join('sdk', 'filter_skeleton.c'),
349             target = 'example_skeleton',
350             install_path = None)
352         bld(features = 'c cxxshlib',
353             includes = 'include',
354             source = os.path.join('sdk', 'invert_example.c'),
355             target = 'example_invert',
356             install_path = None)
358         bld.install_files('${DOCDIR}/examples',
359                           bld.path.ant_glob([os.path.join('sdk', '*')]))
361     bld.install_files('${INCLUDEDIR}', [os.path.join('include', 'VapourSynth.h'),
362                                         os.path.join('include', 'VSHelper.h')])
364     bld(source = 'vapoursynth.pc.in',
365         install_path = '${LIBDIR}/pkgconfig',
366         PREFIX = bld.env.PREFIX,
367         LIBDIR = bld.env.LIBDIR,
368         INCLUDEDIR = bld.env.INCLUDEDIR,
369         LIBS = bld.env.LIBS,
370         VERSION = VERSION)
372 def test(ctx):
373     '''runs the Cython tests'''
375     for name in glob.glob(os.path.join('test', '*.py')):
376         if subprocess.Popen([ctx.env.PYTHON, name]).wait() != 0:
377             ctx.fatal('Test {0} failed'.format(name))
379 class TestContext(Build.BuildContext):
380     cmd = 'test'
381     fun = 'test'