fixed exceptionally stupid mem leak
[swftools.git] / setup.py
1 #!/usr/bin/env python
2
3 from distutils import ccompiler
4 from distutils.core import CompileError
5
6 try:
7     from setuptools import setup, Extension
8 except ImportError:
9     from distutils.core import setup, Extension
10
11 cc = ccompiler.new_compiler()
12
13 # leave it to gcc to detect c/c++ files. we'll be linking against -lstdc++
14 # later on to ensure we do have all the c++ libraries, so we don't need to
15 # compile *everything* as c++ just because of the few .cc files.
16 cc.language_map[".cc"] = "c"
17
18 import os
19 import sys
20 import stat
21 import re
22
23 DATADIR = "/usr/share/swftools/"
24
25 def update_dirs(list1, list2):
26     for v in list2:
27         if v not in list1 and os.path.isdir(v):
28             list1.append(v)
29
30 def update_list(list1, list2):
31     for v in list2:
32         if v not in list1:
33             list1.append(v)
34
35 COMPILER_OPTIONS = ['-fPIC', '-Wparentheses', '-Wimplicit', '-Wreturn-type',
36                     '-O3', '-fomit-frame-pointer', '-Winline', 
37                     '-Wno-unused', '-Wno-strict-prototypes','-DHAVE_CONFIG_H',
38                     '-DSWFTOOLS_DATADIR="'+DATADIR+'"']
39 INCLUDE=['lib/lame/', 'lib/pdf/xpdf', 'lib/pdf']
40
41 if 'library_dirs' in os.environ:
42     update_dirs(cc.library_dirs, [path.strip() for path in os.environ.get('library_dirs').strip().split(":")])
43 else:
44     update_dirs(cc.library_dirs, [os.path.join(sys.prefix, 'lib'), 
45                                   os.path.join(sys.prefix, 'local/lib')])
46     if sys.platform == "darwin":
47         update_list(cc.library_dirs, ["/sw/lib", "/opt/local/lib"])
48
49 if 'include_dirs' in os.environ:
50     update_dirs(cc.include_dirs, [path.strip() for path in os.environ.get('include_dirs').strip().split(":")])
51 else:
52     update_dirs(cc.include_dirs, [os.path.join(sys.prefix, 'include'), 
53                                   os.path.join(sys.prefix, 'include/freetype2'),
54                                   os.path.join(sys.prefix, 'include/fontconfig')])
55     if sys.platform == "darwin":
56         update_dirs(cc.include_dirs, ["/sw/include/freetype2", "/sw/lib/freetype2/include", "/sw/include", "/opt/local/include"])
57
58
59 class ConfigScript:
60     def __init__(self):
61         self.defines = []
62         self.includefiles = []
63         self.libraries = []
64
65     def unlink(self, filename):
66         try:
67             os.unlink(filename)
68         except OSError: 
69             pass
70
71     def test_code(self, head, body, stdh=1):
72         fi = open("setup_test.c", "wb")
73         if stdh:
74             fi.write("#include <stdlib.h>\n")
75             fi.write("#include <stdio.h>\n")
76             for i in self.includefiles:
77                 fi.write("#include <%s>\n" % i)
78         for d in self.defines:
79             fi.write("%s;\n" % d)
80         fi.write(head)
81         fi.write("\nint main()\n")
82         fi.write("{\n")
83         fi.write(body)
84         fi.write("\n}\n")
85         fi.close()
86         #fi = open("setup_test.c", "rb")
87         #print fi.read()
88         #fi.close()
89
90         quiet = 1
91         if quiet:
92             try:
93                 # redirect stderr
94                 sys.stderr.flush()
95                 err = open('/dev/null', 'a+', 0)
96                 olderr = open('/dev/null', 'a+', 0)
97                 os.dup2(2, olderr.fileno())
98                 os.dup2(err.fileno(), 2)
99             except:
100                 pass
101
102         error = 0
103         try:
104             cc.compile(["setup_test.c"], include_dirs=cc.include_dirs)
105         except CompileError:
106             error = 1
107
108         if quiet:
109             try:
110                 # unredirect stderr
111                 sys.stderr.flush()
112                 err = open('/dev/null', 'a+', 0)
113                 os.dup2(olderr.fileno(), 2)
114                 olderr.close()
115                 err.close()
116             except:
117                 pass
118
119         self.unlink("setup_test.o")
120         self.unlink("setup_test.obj")
121         self.unlink("setup_test.c")
122         if error:
123             return None
124         else:
125             return 1
126
127     def system_has_property(self,name):
128         if name.startswith("STD"):
129             return 1
130         elif name.startswith("INTERNAL"):
131             return 1
132         elif name == "PACKAGE":
133             return "\"swftools\""
134         elif name == "VERSION":
135             fi = open("configure.in", "rb")
136             for line in fi.readlines():
137                 if line.startswith("VERSION="):
138                     return '"'+line[8:].strip()+'"'
139             return "unknown"
140         elif "POPPLER" in name:
141             return None
142         elif name.startswith("HAVE_") and name.endswith("_H"):
143             header = name[5:].lower()
144             c = header.rfind("_")
145             if c>=0:
146                 header = header[0:c]+"."+header[c+1]
147             header = header.replace("_","/")
148             ok = 0
149             for dir in cc.include_dirs:
150                 if os.path.isfile(os.path.join(dir,header)):
151                     ok = 1
152                     break
153             if ok and self.test_code("#include <"+header+">", ""):
154                 if header.startswith("sys"):
155                     self.includefiles += [header]
156                 return 1
157         elif name.startswith("HAVE_LIB") \
158           or name.startswith("HAVE_FONTCONFIG") \
159           or name.startswith("HAVE_FREETYPE"):
160             if name.startswith("HAVE_LIB"):
161                 libname = name[8:].lower()
162             else:
163                 libname = name[5:].lower()
164             if cc.find_library_file(cc.library_dirs, libname):
165                 update_list(self.libraries, [libname])
166                 return 1
167         elif name.startswith("HAVE_LAME"):
168             return None
169         elif name.startswith("O_BINARY"):
170             if sys.platform.startswith("win"):
171                 return None
172             else:
173                 return 0
174         elif name == "boolean":
175             if self.test_code("", "boolean b;"):
176                 return None
177             else:
178                 self.defines += ["typedef int boolean"]
179                 return "int"
180         elif name.startswith("SIZEOF_"):
181             t = name[7:].lower().replace("_", " ")
182             if t == "voidp":
183                 t = "void*"
184             for i in [1,2,4,8]:
185                 s = "static int test_array [%d+1-sizeof(%s)*2];\ntest_array [0] = 0;" % (i*2,t)
186                 if self.test_code("", s):
187                     return i
188             return None
189         elif name.startswith("USE_FREEETYPE"):
190             # TODO: run a test here?
191             return 1 
192         elif name.startswith("HAVE_"):
193             function = name[5:].lower()
194             params=""
195             if function=="bcopy":
196                 params = "0,0,0"
197             elif function=="bzero":
198                 params = "0,0"
199             return self.test_code("", "%s(%s);" % (function,params), stdh=0)
200         return None
201
202     def create_config(self):
203         print "Creating config.h..."
204
205         fi = open("config.h.in", "rb")
206         fo = open("config.h", "wb")
207         for line in fi.readlines():
208             if line.startswith("#undef "):
209                 line = line.strip()
210                 name = line[7:]
211                 if " " in name:
212                     name = name.split(" ")[0]
213                 value = self.system_has_property(name)
214                 if value is None:
215                     fo.write("// %s is not set\n" % (name))
216                 else:
217                     fo.write("#define %s %s\n" % (name, value))
218             else:
219                 fo.write(line)
220         fo.write("// python:lib "+(" ".join(self.libraries))+"\n")
221         fo.close()
222         fi.close()
223
224     def load(self):
225         if not os.path.isfile("config.h"):
226             return 0
227         fi = open("config.h", "rb")
228         for line in fi.readlines():
229             if line.startswith("// python: lib "):
230                 self.libraries = line[15:].split(" ")
231         fi.close()
232         return
233
234 config = ConfigScript()
235 # if either setup.py or config.h.in were modfied, rebuild config.h
236 if not config.load() or \
237    os.stat("setup.py")[stat.ST_MTIME] > os.stat("config.h")[stat.ST_MTIME] or \
238    os.stat("config.h.in")[stat.ST_MTIME] > os.stat("config.h")[stat.ST_MTIME]:
239     config.create_config()
240 #print dir(cc)
241 #sys.exit(0)
242
243 if "jpeg" not in config.libraries:
244     print "Error: Couldn't find jpeg library on your system"
245     sys.exit(1)
246
247 if "freetype" not in config.libraries:
248     print "Error: Couldn't find freetype library on your system"
249     sys.exit(1)
250
251 base_sources = [
252 "lib/q.c", "lib/utf8.c", "lib/png.c", "lib/jpeg.c", "lib/wav.c", "lib/mp3.c", "lib/os.c", "lib/bitio.c", "lib/log.c", "lib/mem.c",
253 ]
254 rfxswf_sources = [
255 "lib/modules/swfaction.c", "lib/modules/swfbits.c", "lib/modules/swfbutton.c",
256 "lib/modules/swfcgi.c", "lib/modules/swfdraw.c", "lib/modules/swfdump.c", "lib/modules/swffilter.c",
257 "lib/modules/swffont.c", "lib/modules/swfobject.c", "lib/modules/swfrender.c", "lib/modules/swfshape.c",
258 "lib/modules/swfsound.c", "lib/modules/swftext.c", "lib/modules/swftools.c",
259 "lib/rfxswf.c", "lib/drawer.c", "lib/MD5.c", "lib/h.263/dct.c", "lib/h.263/h263tables.c",
260 "lib/h.263/swfvideo.c", "lib/action/assembler.c", "lib/action/compile.c",
261 "lib/action/lex.swf4.c", "lib/action/lex.swf5.c", "lib/action/libming.c",
262 "lib/action/swf4compiler.tab.c", "lib/action/swf5compiler.tab.c", "lib/action/actioncompiler.c",
263 "lib/as3/abc.c", "lib/as3/code.c", "lib/as3/pool.c", "lib/as3/files.c", "lib/as3/opcodes.c", 
264 "lib/as3/scripts.c", "lib/as3/common.c", "lib/as3/builtin.c", "lib/as3/compiler.c", "lib/as3/expr.c", "lib/as3/import.c",
265 "lib/as3/initcode.c", "lib/as3/parser.tab.c", "lib/as3/registry.c", "lib/as3/tokenizer.yy.c",
266 ]
267 libpdf_sources = [
268 "lib/pdf/GFXOutputDev.cc", "lib/pdf/InfoOutputDev.cc", "lib/pdf/BitmapOutputDev.cc",
269 "lib/pdf/FullBitmapOutputDev.cc", "lib/pdf/pdf.cc", "lib/pdf/fonts.c", "lib/pdf/xpdf/GHash.cc",
270 "lib/pdf/xpdf/GList.cc", "lib/pdf/xpdf/GString.cc", "lib/pdf/xpdf/gmem.cc", "lib/pdf/xpdf/gfile.cc",
271 "lib/pdf/xpdf/FoFiTrueType.cc", "lib/pdf/xpdf/FoFiType1.cc", "lib/pdf/xpdf/FoFiType1C.cc",
272 "lib/pdf/xpdf/FoFiBase.cc", "lib/pdf/xpdf/FoFiEncodings.cc", "lib/pdf/xpdf/OutputDev.cc", "lib/pdf/xpdf/PDFDoc.cc",
273 "lib/pdf/xpdf/Error.cc", "lib/pdf/xpdf/Stream.cc", "lib/pdf/xpdf/Object.cc", "lib/pdf/xpdf/Decrypt.cc",
274 "lib/pdf/xpdf/Array.cc", "lib/pdf/xpdf/XRef.cc", "lib/pdf/xpdf/Dict.cc", "lib/pdf/xpdf/Parser.cc",
275 "lib/pdf/xpdf/Lexer.cc", "lib/pdf/xpdf/Outline.cc", "lib/pdf/xpdf/PDFDocEncoding.cc", "lib/pdf/xpdf/Catalog.cc",
276 "lib/pdf/xpdf/Link.cc", "lib/pdf/xpdf/GlobalParams.cc", "lib/pdf/xpdf/JBIG2Stream.cc", "lib/pdf/xpdf/Page.cc",
277 "lib/pdf/xpdf/JPXStream.cc", "lib/pdf/xpdf/JArithmeticDecoder.cc", "lib/pdf/xpdf/Gfx.cc", "lib/pdf/xpdf/GfxFont.cc",
278 "lib/pdf/xpdf/CMap.cc", "lib/pdf/xpdf/CharCodeToUnicode.cc", "lib/pdf/xpdf/PSTokenizer.cc", "lib/pdf/xpdf/FontEncodingTables.cc",
279 "lib/pdf/xpdf/BuiltinFont.cc", "lib/pdf/xpdf/BuiltinFontTables.cc", "lib/pdf/xpdf/GfxState.cc", "lib/pdf/xpdf/Function.cc",
280 "lib/pdf/xpdf/Annot.cc", "lib/pdf/xpdf/NameToCharCode.cc", "lib/pdf/xpdf/UnicodeMap.cc", "lib/pdf/xpdf/SecurityHandler.cc",
281 "lib/pdf/xpdf/SplashOutputDev.cc", "lib/pdf/xpdf/SplashFont.cc", "lib/pdf/xpdf/SplashState.cc", "lib/pdf/xpdf/Splash.cc",
282 "lib/pdf/xpdf/SplashBitmap.cc", "lib/pdf/xpdf/SplashClip.cc", "lib/pdf/xpdf/SplashPattern.cc", "lib/pdf/xpdf/SplashFontEngine.cc",
283 "lib/pdf/xpdf/SplashFontFile.cc", "lib/pdf/xpdf/SplashFontFileID.cc", "lib/pdf/xpdf/SplashScreen.cc", "lib/pdf/xpdf/SplashPath.cc",
284 "lib/pdf/xpdf/SplashXPath.cc", "lib/pdf/xpdf/SplashXPathScanner.cc", "lib/pdf/xpdf/SplashFTFontEngine.cc",
285 "lib/pdf/xpdf/SplashFTFontFile.cc", "lib/pdf/xpdf/SplashFTFont.cc"]
286
287 libgfx_sources = [
288 "lib/gfxtools.c", "lib/gfxfont.c", "lib/gfxpoly.c",
289 "lib/devices/dummy.c", "lib/devices/file.c", "lib/devices/render.c", "lib/devices/text.c", "lib/devices/record.c",
290 "lib/devices/ops.c", "lib/devices/polyops.c", "lib/devices/bbox.c", "lib/devices/rescale.c",
291 "lib/art/art_affine.c", "lib/art/art_alphagamma.c", "lib/art/art_bpath.c", "lib/art/art_gray_svp.c",
292 "lib/art/art_misc.c", "lib/art/art_pixbuf.c", "lib/art/art_rect.c", "lib/art/art_rect_svp.c",
293 "lib/art/art_rect_uta.c", "lib/art/art_render.c", "lib/art/art_render_gradient.c", "lib/art/art_render_mask.c",
294 "lib/art/art_render_svp.c", "lib/art/art_rgb.c", "lib/art/art_rgb_a_affine.c", "lib/art/art_rgb_affine.c",
295 "lib/art/art_rgb_affine_private.c", "lib/art/art_rgb_bitmap_affine.c", "lib/art/art_rgb_pixbuf_affine.c",
296 "lib/art/art_rgb_rgba_affine.c", "lib/art/art_rgb_svp.c", "lib/art/art_rgba.c", "lib/art/art_svp.c",
297 "lib/art/art_svp_intersect.c", "lib/art/art_svp_ops.c", "lib/art/art_svp_point.c",
298 "lib/art/art_svp_render_aa.c", "lib/art/art_svp_vpath.c", "lib/art/art_svp_vpath_stroke.c",
299 "lib/art/art_svp_wind.c", "lib/art/art_uta.c", "lib/art/art_uta_ops.c", "lib/art/art_uta_rect.c",
300 "lib/art/art_uta_svp.c", "lib/art/art_uta_vpath.c", "lib/art/art_vpath.c", "lib/art/art_vpath_bpath.c",
301 "lib/art/art_vpath_dash.c", "lib/art/art_vpath_svp.c", "lib/gocr/box.c", 
302 "lib/gocr/database.c", "lib/gocr/detect.c", "lib/gocr/job.c", "lib/gocr/lines.c", "lib/gocr/list.c", 
303 "lib/gocr/ocr0.c", "lib/gocr/ocr0n.c", "lib/gocr/ocr1.c", "lib/gocr/otsu.c", "lib/gocr/output.c", 
304 "lib/gocr/pgm2asc.c", "lib/gocr/pixel.c", "lib/gocr/progress.c", "lib/gocr/remove.c", "lib/gocr/unicode.c",
305 "lib/devices/ocr.c",
306 ]
307 gfxswf_sources = ["lib/devices/swf.c", "lib/readers/swf.c", "lib/readers/image.c"]
308
309 swf_module = Extension(
310     name='SWF', 
311     include_dirs=cc.include_dirs+INCLUDE,
312     sources=['lib/python/SWF.c', 'lib/python/taglist.c', 'lib/python/tag.c', 'lib/python/image.c', 
313              'lib/python/tags.c', 'lib/python/tagmap.c', 'lib/python/action.c', 'lib/python/primitives.c', 
314              'lib/python/pyutils.c'] + base_sources + rfxswf_sources,
315     library_dirs=cc.library_dirs,
316     libraries=config.libraries,
317     extra_objects=['%s/lib/python%s/site-packages/PIL/_imaging.so' % (sys.prefix, sys.version[:3])],
318     extra_compile_args=COMPILER_OPTIONS,
319     )
320
321 gfx_module = Extension(
322     name='gfx',
323     sources=['lib/python/gfx.c'] + base_sources + libgfx_sources + rfxswf_sources + libpdf_sources + gfxswf_sources,
324     include_dirs=cc.include_dirs+INCLUDE,
325     library_dirs=cc.library_dirs,
326     libraries=config.libraries + ["stdc++"],
327     extra_objects=[],
328     extra_compile_args=COMPILER_OPTIONS,
329     )    
330
331 setup(name='SWFTools',
332       version='0.9dev',
333       description='Python wrapper for SWFTools',
334       author='Matthias Kramm',
335       author_email='kramm@quiss.org',
336       url='http://www.swftools.org/',
337       ext_modules=[swf_module, gfx_module],
338 )