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