1 import glob, os, subprocess, sys
2 from waflib import Build, Task, TaskGen, Utils
4 APPNAME = 'VapourSynth'
10 class preproc(Task.Task):
11 "Preprocess Cython source files"
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"
40 subprocess.Popen('make html BUILDDIR={0}'.format(os.path.join(os.pardir, OUT)),
43 stdout = subprocess.PIPE).wait()
45 @TaskGen.feature('docs')
46 @TaskGen.before_method('process_source')
51 for x in self.to_nodes(self.source):
52 if x.name.endswith('.rst'):
57 self.source = no_nodes
59 inst = getattr(self, 'install_path', '${DOCDIR}')
60 mod = getattr(self, 'chmod', Utils.O644)
65 for node in rst_nodes:
66 n = self.path.find_node(OUT).make_node('html')
71 while not cur is self.path.find_node('doc'):
75 for dir in reversed(dirs):
76 n = n.make_node(dir.name)
78 n = n.make_node(node.name).change_ext('.html')
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))
92 self.rst_task = self.create_task('docs', rst_nodes, bld_nodes)
95 opt.load('compiler_c')
96 opt.load('compiler_cxx')
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)')
113 def add_options(flags, options):
115 conf.env.append_unique(flag, options)
117 conf.load('compiler_c')
118 conf.load('compiler_cxx')
121 # Load Yasm explicitly, then the Nasm module which
122 # supports both Nasm and Yasm.
123 conf.find_program('yasm', var = 'AS', mandatory = True)
126 conf.find_program('python3', var = 'PYTHON', mandatory = True)
128 if conf.env.DEST_OS == 'darwin':
129 if conf.env.CXX_NAME == 'gcc':
130 add_options(['ASFLAGS'],
133 if conf.env.CXX_NAME == 'gcc':
134 add_options(['CFLAGS', 'CXXFLAGS'],
137 elif conf.env.CXX_NAME == 'msvc':
138 add_options(['CFLAGS', 'CXXFLAGS'],
143 add_options(['ASFLAGS'],
146 '-Wunrecognized-char'])
148 if conf.env.DEST_CPU in ['x86_64', 'amd64', 'x64']:
149 add_options(['ASFLAGS'],
152 if conf.env.DEST_OS == 'darwin':
154 elif conf.env.DEST_OS == 'win32':
159 add_options(['ASFLAGS'],
162 if conf.env.DEST_OS == 'darwin':
164 elif conf.env.DEST_OS == 'win32':
169 add_options(['ASFLAGS'],
170 ['-f{0}'.format(fmt)])
172 if conf.options.mode == 'debug':
173 if conf.env.CXX_NAME == 'gcc':
174 add_options(['CFLAGS', 'CXXFLAGS'],
179 elif conf.env.CXX_NAME == 'msvc':
180 add_options(['CFLAGS', 'CXXFLAGS'],
184 add_options(['ASFLAGS'],
186 elif conf.options.mode == 'release':
187 if conf.env.CXX_NAME == 'gcc':
188 add_options(['CFLAGS', 'CXXFLAGS'],
190 elif conf.env.CXX_NAME == 'msvc':
191 add_options(['CFLAGS', 'CXXFLAGS'],
194 conf.fatal('--mode must be either debug or release.')
196 # Waf always uses gcc/g++ for linking when using a GCC
197 # compatible C/C++ compiler.
198 if conf.env.CXX_NAME == 'gcc':
199 if not conf.env.DEST_OS in ['darwin', 'win32']:
200 add_options(['LINKFLAGS_cshlib',
201 'LINKFLAGS_cprogram',
202 'LINKFLAGS_cxxshlib',
203 'LINKFLAGS_cxxprogram'],
206 def check_feature(name, desc):
207 val = conf.options.__dict__[name]
209 if not val in ['true', 'false']:
210 conf.fatal('--{0} must be either true or false.'.format(name))
215 conf.define('FEATURE_' + u, 1 if val == 'true' else 0)
216 conf.msg("Enabling {0}?".format(desc), 'yes' if conf.env[u] == 'true' else 'no')
218 check_feature('shared', 'shared library')
219 check_feature('static', 'static library')
220 check_feature('filters', 'included filters')
221 check_feature('cython', 'Cython wrapper')
222 check_feature('avisynth', 'Avisynth compatibility')
223 check_feature('docs', 'documentation')
224 check_feature('examples', 'SDK examples')
226 conf.define('PATH_PREFIX', conf.env.PREFIX)
227 conf.msg("Setting PREFIX to", conf.env.PREFIX)
229 for dir in ['libdir', 'plugindir', 'docdir', 'includedir']:
232 conf.env[u] = Utils.subst_vars(conf.options.__dict__[dir], conf.env)
233 conf.define('PATH_' + u, conf.env[u])
234 conf.msg("Setting {0} to".format(u), conf.env[u])
236 conf.check_cxx(use = ['QTCORE'], header_name = 'QtCore/QtCore')
237 conf.check_cxx(use = ['QTCORE'], header_name = 'QtCore/QtCore', type_name = 'QAtomicInt')
239 conf.check_cc(lib = 'avutil')
240 conf.check_cc(use = ['AVUTIL'], header_name = 'libavutil/avutil.h')
241 conf.check_cc(use = ['AVUTIL'], header_name = 'libavutil/avutil.h', function_name = 'avutil_license')
243 conf.check_cc(lib = 'swscale')
244 conf.check_cc(use = ['SWSCALE'], header_name = 'libswscale/swscale.h')
245 conf.check_cc(use = ['SWSCALE'], header_name = 'libswscale/swscale.h', function_name = 'swscale_license')
249 if not conf.env.DEST_OS in ['darwin', 'freebsd', 'netbsd', 'openbsd']:
252 conf.env.LIBS = libs.strip()
255 def search_paths(paths):
259 srcpaths += [os.path.join(path, '*.c'),
260 os.path.join(path, '*.cpp'),
261 os.path.join(path, '*.asm')]
265 sources = search_paths([os.path.join('src', 'core'),
266 os.path.join('src', 'core', 'asm')])
268 if bld.env.DEST_OS == 'win32' and bld.env.AVISYNTH == 'true':
269 sources += search_paths([os.path.join('src', 'avisynth')])
271 bld(features = 'c qxx asm',
272 includes = 'include',
273 use = ['QTCORE', 'SWSCALE', 'AVUTIL'],
274 source = bld.path.ant_glob(sources),
277 if bld.env.SHARED == 'true':
278 bld(features = 'c qxx asm cxxshlib',
280 target = 'vapoursynth',
281 install_path = '${LIBDIR}')
283 if bld.env.STATIC == 'true':
284 bld(features = 'c qxx asm cxxstlib',
285 use = ['objs', 'QTCORE', 'SWSCALE', 'AVUTIL'],
286 target = 'vapoursynth',
287 install_path = '${LIBDIR}')
289 if bld.env.FILTERS == 'true':
290 bld(features = 'c qxx asm cxxshlib',
291 includes = 'include',
292 source = bld.path.ant_glob(search_paths([os.path.join('src', 'filters', 'eedi3')])),
294 install_path = '${PLUGINDIR}')
296 bld(features = 'c qxx asm cxxshlib',
297 includes = 'include',
298 source = bld.path.ant_glob(search_paths([os.path.join('src', 'filters', 'vivtc')])),
300 install_path = '${PLUGINDIR}')
302 if bld.env.CYTHON == 'true':
303 bld(features = 'preproc',
304 source = bld.path.ant_glob([os.path.join('src', 'cython', '*.pyx')]))
306 if bld.env.DOCS == 'true':
307 bld(features = 'docs',
308 source = bld.path.ant_glob([os.path.join('doc', '*.rst'),
309 os.path.join('doc', '**', '*.rst')]),
310 install_path = '${DOCDIR}')
312 if bld.env.EXAMPLES == 'true':
313 bld(features = 'c cxxshlib',
314 includes = 'include',
315 source = os.path.join('sdk', 'filter_skeleton.c'),
316 target = 'example_skeleton',
319 bld(features = 'c cxxshlib',
320 includes = 'include',
321 source = os.path.join('sdk', 'invert_example.c'),
322 target = 'example_invert',
325 bld.install_files('${DOCDIR}/examples',
326 bld.path.ant_glob([os.path.join('sdk', '*')]))
328 bld.install_files('${INCLUDEDIR}', [os.path.join('include', 'VapourSynth.h'),
329 os.path.join('include', 'VSHelper.h')])
331 bld(source = 'vapoursynth.pc.in',
332 install_path = '${LIBDIR}/pkgconfig',
333 PREFIX = bld.env.PREFIX,
334 LIBDIR = bld.env.LIBDIR,
335 INCLUDEDIR = bld.env.INCLUDEDIR,
340 '''runs the Cython tests'''
342 for name in glob.glob(os.path.join('test', '*.py')):
343 if subprocess.Popen([ctx.env.PYTHON, name]).wait() != 0:
344 ctx.fatal('Test {0} failed'.format(name))
346 class TestContext(Build.BuildContext):