Avoid using non-standard minmax.h.
[vapoursynth-svn.git] / wscript
blob5eac709fe82f4418ea6f446f9496c994e578b685
1 import glob, os, subprocess, sys
2 from waflib import Build, Task, TaskGen, Utils
4 APPNAME = 'VapourSynth'
5 VERSION = '14'
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     # Load Yasm explicitly, then the Nasm module which
122     # supports both Nasm and Yasm.
123     conf.find_program('yasm', var = 'AS', mandatory = True)
124     conf.load('nasm')
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'],
131                         ['-DPREFIX'])
133     if conf.env.CXX_NAME == 'gcc':
134         add_options(['CFLAGS', 'CXXFLAGS'],
135                     ['-DVSCORE_EXPORTS',
136                      '-fPIC'])
137     elif conf.env.CXX_NAME == 'msvc':
138         add_options(['CFLAGS', 'CXXFLAGS'],
139                     ['/DVSCORE_EXPORTS',
140                      '/EHsc',
141                      '/Zc:wchar_t-'])
143     add_options(['ASFLAGS'],
144                 ['-w',
145                  '-Worphan-labels',
146                  '-Wunrecognized-char'])
148     if conf.env.DEST_CPU in ['x86_64', 'amd64', 'x64']:
149         add_options(['ASFLAGS'],
150                     ['-DARCH_X86_64=1'])
152         if conf.env.DEST_OS == 'darwin':
153             fmt = 'macho64'
154         elif conf.env.DEST_OS == 'win32':
155             fmt = 'win64'
156         else:
157             fmt = 'elf64'
158     else:
159         add_options(['ASFLAGS'],
160                     ['-DARCH_X86_64=0'])
162         if conf.env.DEST_OS == 'darwin':
163             fmt = 'macho32'
164         elif conf.env.DEST_OS == 'win32':
165             fmt = 'win32'
166         else:
167             fmt = 'elf32'
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'],
175                         ['-DVSCORE_DEBUG',
176                          '-g',
177                          '-ggdb',
178                          '-ftrapv'])
179         elif conf.env.CXX_NAME == 'msvc':
180             add_options(['CFLAGS', 'CXXFLAGS'],
181                         ['/DVSCORE_DEBUG',
182                          '/Z7'])
184         add_options(['ASFLAGS'],
185                     ['-DVSCORE_DEBUG'])
186     elif conf.options.mode == 'release':
187         if conf.env.CXX_NAME == 'gcc':
188             add_options(['CFLAGS', 'CXXFLAGS'],
189                         ['-O3'])
190         elif conf.env.CXX_NAME == 'msvc':
191             add_options(['CFLAGS', 'CXXFLAGS'],
192                         ['/Ox'])
193     else:
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'],
204                         ['-Wl,-Bsymbolic'])
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))
211         else:
212             u = name.upper()
214             conf.env[u] = val
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']:
230         u = dir.upper()
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')
247     libs = '-lm '
249     if not conf.env.DEST_OS in ['darwin', 'freebsd', 'netbsd', 'openbsd']:
250         libs += '-ldl '
252     conf.env.LIBS = libs.strip()
254 def build(bld):
255     def search_paths(paths):
256         srcpaths = []
258         for path in paths:
259             srcpaths += [os.path.join(path, '*.c'),
260                          os.path.join(path, '*.cpp'),
261                          os.path.join(path, '*.asm')]
263         return srcpaths
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),
275         target = 'objs')
277     if bld.env.SHARED == 'true':
278         bld(features = 'c qxx asm cxxshlib',
279             use = ['objs'],
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')])),
293             target = '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')])),
299             target = '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',
317             install_path = None)
319         bld(features = 'c cxxshlib',
320             includes = 'include',
321             source = os.path.join('sdk', 'invert_example.c'),
322             target = 'example_invert',
323             install_path = None)
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,
336         LIBS = bld.env.LIBS,
337         VERSION = VERSION)
339 def test(ctx):
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):
347     cmd = 'test'
348     fun = 'test'