Clean up the wscript in preparation for supporting non-x86 platforms.
[vapoursynth-svn.git] / wscript
bloba8aea6597db56d92f17b957fb4fea4f8f085b922
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     if conf.env.DEST_CPU in ['x86', 'x86_64', 'x64']:
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', var = 'PYTHON', mandatory = True)
129     if conf.env.DEST_OS == 'darwin':
130         if conf.env.CXX_NAME == 'gcc':
131             add_options(['ASFLAGS'],
132                         ['-DPREFIX'])
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'])
149     if conf.env.DEST_CPU in ['x86_64', 'x64']:
150         add_options(['ASFLAGS'],
151                     ['-DARCH_X86_64=1'])
153         if conf.env.DEST_OS == 'darwin':
154             fmt = 'macho64'
155         elif conf.env.DEST_OS in ['win32', 'cygwin', 'msys', 'uwin']:
156             fmt = 'win64'
157         else:
158             fmt = 'elf64'
159     elif conf.env.DEST_CPU == 'x86':
160         add_options(['ASFLAGS'],
161                     ['-DARCH_X86_64=0'])
163         if conf.env.DEST_OS == 'darwin':
164             fmt = 'macho32'
165         elif conf.env.DEST_OS in ['win32', 'cygwin', 'msys', 'uwin']:
166             fmt = 'win32'
167         else:
168             fmt = 'elf32'
170     if conf.env.DEST_CPU in ['x86', 'x86_64', 'x64']:
171         add_options(['ASFLAGS'],
172                     ['-f{0}'.format(fmt)])
174     if conf.options.mode == 'debug':
175         if conf.env.CXX_NAME == 'gcc':
176             add_options(['CFLAGS', 'CXXFLAGS'],
177                         ['-DVSCORE_DEBUG',
178                          '-g',
179                          '-ggdb',
180                          '-ftrapv'])
181         elif conf.env.CXX_NAME == 'msvc':
182             add_options(['CFLAGS', 'CXXFLAGS'],
183                         ['/DVSCORE_DEBUG',
184                          '/Z7'])
186         add_options(['ASFLAGS'],
187                     ['-DVSCORE_DEBUG'])
188     elif conf.options.mode == 'release':
189         if conf.env.CXX_NAME == 'gcc':
190             add_options(['CFLAGS', 'CXXFLAGS'],
191                         ['-O3'])
192         elif conf.env.CXX_NAME == 'msvc':
193             add_options(['CFLAGS', 'CXXFLAGS'],
194                         ['/Ox'])
195     else:
196         conf.fatal('--mode must be either debug or release.')
198     # Waf always uses gcc/g++ for linking when using a GCC
199     # compatible C/C++ compiler.
200     if conf.env.CXX_NAME == 'gcc':
201         if not conf.env.DEST_OS in ['darwin', 'win32', 'cygwin', 'msys', 'uwin']:
202             add_options(['LINKFLAGS_cshlib',
203                          'LINKFLAGS_cprogram',
204                          'LINKFLAGS_cxxshlib',
205                          'LINKFLAGS_cxxprogram'],
206                         ['-Wl,-Bsymbolic'])
208     def check_feature(name, desc):
209         val = conf.options.__dict__[name]
211         if not val in ['true', 'false']:
212             conf.fatal('--{0} must be either true or false.'.format(name))
213         else:
214             u = name.upper()
216             conf.env[u] = val
217             conf.define('FEATURE_' + u, 1 if val == 'true' else 0)
218             conf.msg("Enabling {0}?".format(desc), 'yes' if conf.env[u] == 'true' else 'no')
220     check_feature('shared', 'shared library')
221     check_feature('static', 'static library')
222     check_feature('filters', 'included filters')
223     check_feature('cython', 'Cython wrapper')
224     check_feature('avisynth', 'Avisynth compatibility')
225     check_feature('docs', 'documentation')
226     check_feature('examples', 'SDK examples')
228     conf.define('PATH_PREFIX', conf.env.PREFIX)
229     conf.msg("Setting PREFIX to", conf.env.PREFIX)
231     for dir in ['libdir', 'plugindir', 'docdir', 'includedir']:
232         u = dir.upper()
234         conf.env[u] = Utils.subst_vars(conf.options.__dict__[dir], conf.env)
235         conf.define('PATH_' + u, conf.env[u])
236         conf.msg("Setting {0} to".format(u), conf.env[u])
238     conf.check_cxx(use = ['QTCORE'], header_name = 'QtCore/QtCore')
239     conf.check_cxx(use = ['QTCORE'], header_name = 'QtCore/QtCore', type_name = 'QAtomicInt')
241     conf.check_cc(lib = 'avutil')
242     conf.check_cc(use = ['AVUTIL'], header_name = 'libavutil/avutil.h')
243     conf.check_cc(use = ['AVUTIL'], header_name = 'libavutil/avutil.h', function_name = 'avutil_license')
245     conf.check_cc(lib = 'swscale')
246     conf.check_cc(use = ['SWSCALE'], header_name = 'libswscale/swscale.h')
247     conf.check_cc(use = ['SWSCALE'], header_name = 'libswscale/swscale.h', function_name = 'swscale_license')
249     libs = '-lm '
251     if not conf.env.DEST_OS in ['darwin', 'freebsd', 'netbsd', 'openbsd']:
252         libs += '-ldl '
254     conf.env.LIBS = libs.strip()
256 def build(bld):
257     def search_paths(paths):
258         srcpaths = []
260         for path in paths:
261             srcpaths += [os.path.join(path, '*.c'),
262                          os.path.join(path, '*.cpp'),
263                          os.path.join(path, '*.asm')]
265         return srcpaths
267     sources = search_paths([os.path.join('src', 'core'),
268                             os.path.join('src', 'core', 'asm')])
270     if bld.env.DEST_OS in ['win32', 'cygwin', 'msys', 'uwin'] and bld.env.AVISYNTH == 'true':
271         sources += search_paths([os.path.join('src', 'avisynth')])
273     bld(features = 'c qxx asm',
274         includes = 'include',
275         use = ['QTCORE', 'SWSCALE', 'AVUTIL'],
276         source = bld.path.ant_glob(sources),
277         target = 'objs')
279     if bld.env.SHARED == 'true':
280         bld(features = 'c qxx asm cxxshlib',
281             use = ['objs'],
282             target = 'vapoursynth',
283             install_path = '${LIBDIR}')
285     if bld.env.STATIC == 'true':
286         bld(features = 'c qxx asm cxxstlib',
287             use = ['objs', 'QTCORE', 'SWSCALE', 'AVUTIL'],
288             target = 'vapoursynth',
289             install_path = '${LIBDIR}')
291     if bld.env.FILTERS == 'true':
292         bld(features = 'c qxx asm cxxshlib',
293             includes = 'include',
294             source = bld.path.ant_glob(search_paths([os.path.join('src', 'filters', 'eedi3')])),
295             target = 'eedi3',
296             install_path = '${PLUGINDIR}')
298         bld(features = 'c qxx asm cxxshlib',
299             includes = 'include',
300             source = bld.path.ant_glob(search_paths([os.path.join('src', 'filters', 'vivtc')])),
301             target = 'vivtc',
302             install_path = '${PLUGINDIR}')
304     if bld.env.CYTHON == 'true':
305         bld(features = 'preproc',
306             source = bld.path.ant_glob([os.path.join('src', 'cython', '*.pyx')]))
308     if bld.env.DOCS == 'true':
309         bld(features = 'docs',
310             source = bld.path.ant_glob([os.path.join('doc', '*.rst'),
311                                         os.path.join('doc', '**', '*.rst')]),
312             install_path = '${DOCDIR}')
314     if bld.env.EXAMPLES == 'true':
315         bld(features = 'c cxxshlib',
316             includes = 'include',
317             source = os.path.join('sdk', 'filter_skeleton.c'),
318             target = 'example_skeleton',
319             install_path = None)
321         bld(features = 'c cxxshlib',
322             includes = 'include',
323             source = os.path.join('sdk', 'invert_example.c'),
324             target = 'example_invert',
325             install_path = None)
327         bld.install_files('${DOCDIR}/examples',
328                           bld.path.ant_glob([os.path.join('sdk', '*')]))
330     bld.install_files('${INCLUDEDIR}', [os.path.join('include', 'VapourSynth.h'),
331                                         os.path.join('include', 'VSHelper.h')])
333     bld(source = 'vapoursynth.pc.in',
334         install_path = '${LIBDIR}/pkgconfig',
335         PREFIX = bld.env.PREFIX,
336         LIBDIR = bld.env.LIBDIR,
337         INCLUDEDIR = bld.env.INCLUDEDIR,
338         LIBS = bld.env.LIBS,
339         VERSION = VERSION)
341 def test(ctx):
342     '''runs the Cython tests'''
344     for name in glob.glob(os.path.join('test', '*.py')):
345         if subprocess.Popen([ctx.env.PYTHON, name]).wait() != 0:
346             ctx.fatal('Test {0} failed'.format(name))
348 class TestContext(Build.BuildContext):
349     cmd = 'test'
350     fun = 'test'