1{ stdenv, fetchurl, self, callPackage
2, bzip2, openssl, gettext
3
4, includeModules ? false
5
6, db, gdbm, ncurses, sqlite, readline
7
8, tcl ? null, tk ? null, x11 ? null, libX11 ? null, x11Support ? !stdenv.isCygwin
9, zlib ? null, zlibSupport ? true
10, expat, libffi
11
12, CF, configd
13}:
14
15assert zlibSupport -> zlib != null;
16assert x11Support -> tcl != null
17 && tk != null
18 && x11 != null
19 && libX11 != null;
20
21with stdenv.lib;
22
23let
24 majorVersion = "2.7";
25 version = "${majorVersion}.10";
26
27 src = fetchurl {
28 url = "http://www.python.org/ftp/python/${version}/Python-${version}.tar.xz";
29 sha256 = "1h7zbrf9pkj29hlm18b10548ch9757f75m64l47sy75rh43p7lqw";
30 };
31
32 patches =
33 [ # Look in C_INCLUDE_PATH and LIBRARY_PATH for stuff.
34 ./search-path.patch
35
36 # Python recompiles a Python if the mtime stored *in* the
37 # pyc/pyo file differs from the mtime of the source file. This
38 # doesn't work in Nix because Nix changes the mtime of files in
39 # the Nix store to 1. So treat that as a special case.
40 ./nix-store-mtime.patch
41
42 # patch python to put zero timestamp into pyc
43 # if DETERMINISTIC_BUILD env var is set
44 ./deterministic-build.patch
45
46 ./properly-detect-curses.patch
47 ] ++ optionals stdenv.isCygwin [
48 ./2.5.2-ctypes-util-find_library.patch
49 ./2.5.2-tkinter-x11.patch
50 ./2.6.2-ssl-threads.patch
51 ./2.6.5-export-PySignal_SetWakeupFd.patch
52 ./2.6.5-FD_SETSIZE.patch
53 ./2.6.5-ncurses-abi6.patch
54 ./2.7.3-dbm.patch
55 ./2.7.3-dylib.patch
56 ./2.7.3-getpath-exe-extension.patch
57 ./2.7.3-no-libm.patch
58 ];
59
60 preConfigure = ''
61 # Purity.
62 for i in /usr /sw /opt /pkg; do
63 substituteInPlace ./setup.py --replace $i /no-such-path
64 done
65 '' + optionalString (stdenv ? cc && stdenv.cc.libc != null) ''
66 for i in Lib/plat-*/regen; do
67 substituteInPlace $i --replace /usr/include/ ${stdenv.cc.libc}/include/
68 done
69 '' + optionalString stdenv.isDarwin ''
70 substituteInPlace configure --replace '`/usr/bin/arch`' '"i386"'
71 '';
72
73 configureFlags = [
74 "--enable-shared"
75 "--with-threads"
76 "--enable-unicode=ucs4"
77 ] ++ optionals stdenv.isCygwin [
78 "--with-system-ffi"
79 "--with-system-expat"
80 "ac_cv_func_bind_textdomain_codeset=yes"
81 ] ++ optionals stdenv.isDarwin [
82 "--disable-toolbox-glue"
83 ];
84
85 postConfigure = if stdenv.isCygwin then ''
86 sed -i Makefile -e 's,PYTHONPATH="$(srcdir),PYTHONPATH="$(abs_srcdir),'
87 '' else null;
88
89 buildInputs =
90 optional (stdenv ? cc && stdenv.cc.libc != null) stdenv.cc.libc ++
91 [ bzip2 openssl ]
92 ++ optionals stdenv.isCygwin [ expat libffi ]
93 ++ optionals includeModules (
94 [ db gdbm ncurses sqlite readline
95 ] ++ optionals x11Support [ tcl tk x11 libX11 ]
96 )
97 ++ optional zlibSupport zlib
98
99 # depend on CF and configd only if purity is an issue
100 # the impure bootstrap compiler can't build CoreFoundation currently. it requires
101 # <mach-o/dyld.h> which is in our pure bootstrapTools, but not in the system headers.
102 ++ optionals (stdenv.isDarwin && !stdenv.cc.nativeLibc) [ CF configd ];
103
104 # Build the basic Python interpreter without modules that have
105 # external dependencies.
106 python = stdenv.mkDerivation {
107 name = "python-${version}";
108 pythonVersion = majorVersion;
109
110 inherit majorVersion version src patches buildInputs preConfigure
111 configureFlags;
112
113 LDFLAGS = stdenv.lib.optionalString (!stdenv.isDarwin) "-lgcc_s";
114 C_INCLUDE_PATH = concatStringsSep ":" (map (p: "${p}/include") buildInputs);
115 LIBRARY_PATH = concatStringsSep ":" (map (p: "${p}/lib") buildInputs);
116
117 NIX_CFLAGS_COMPILE = optionalString stdenv.isDarwin "-msse2";
118 DETERMINISTIC_BUILD = 1;
119
120 setupHook = ./setup-hook.sh;
121
122 postInstall =
123 ''
124 # needed for some packages, especially packages that backport
125 # functionality to 2.x from 3.x
126 for item in $out/lib/python${majorVersion}/test/*; do
127 if [[ "$item" != */test_support.py* ]]; then
128 rm -rf "$item"
129 else
130 echo $item
131 fi
132 done
133 touch $out/lib/python${majorVersion}/test/__init__.py
134 ln -s $out/lib/python${majorVersion}/pdb.py $out/bin/pdb
135 ln -s $out/lib/python${majorVersion}/pdb.py $out/bin/pdb${majorVersion}
136 ln -s $out/share/man/man1/{python2.7.1.gz,python.1.gz}
137
138 paxmark E $out/bin/python${majorVersion}
139
140 ${ optionalString includeModules "$out/bin/python ./setup.py build_ext"}
141 '';
142
143 passthru = rec {
144 inherit zlibSupport;
145 isPy2 = true;
146 isPy27 = true;
147 buildEnv = callPackage ../wrapper.nix { python = self; };
148 libPrefix = "python${majorVersion}";
149 executable = libPrefix;
150 sitePackages = "lib/${libPrefix}/site-packages";
151 interpreter = "${self}/bin/${executable}";
152 };
153
154 enableParallelBuilding = true;
155
156 meta = {
157 homepage = "http://python.org";
158 description = "a high-level dynamically-typed programming language";
159 longDescription = ''
160 Python is a remarkably powerful dynamic programming language that
161 is used in a wide variety of application domains. Some of its key
162 distinguishing features include: clear, readable syntax; strong
163 introspection capabilities; intuitive object orientation; natural
164 expression of procedural code; full modularity, supporting
165 hierarchical packages; exception-based error handling; and very
166 high level dynamic data types.
167 '';
168 license = stdenv.lib.licenses.psfl;
169 platforms = stdenv.lib.platforms.all;
170 maintainers = with stdenv.lib.maintainers; [ simons chaoflow iElectric ];
171 };
172 };
173
174
175 # This function builds a Python module included in the main Python
176 # distribution in a separate derivation.
177 buildInternalPythonModule =
178 { moduleName
179 , internalName ? "_" + moduleName
180 , deps
181 }:
182 if includeModules then null else stdenv.mkDerivation rec {
183 name = "python-${moduleName}-${python.version}";
184
185 inherit src patches preConfigure postConfigure configureFlags;
186
187 buildInputs = [ python ] ++ deps;
188
189 C_INCLUDE_PATH = concatStringsSep ":" (map (p: "${p}/include") buildInputs);
190 LIBRARY_PATH = concatStringsSep ":" (map (p: "${p}/lib") buildInputs);
191
192 # non-python gdbm has a libintl dependency on i686-cygwin, not on x86_64-cygwin
193 buildPhase = (if (stdenv.system == "i686-cygwin" && moduleName == "gdbm") then ''
194 sed -i setup.py -e "s:libraries = \['gdbm'\]:libraries = ['gdbm', 'intl']:"
195 '' else '''') + ''
196 substituteInPlace setup.py --replace 'self.extensions = extensions' \
197 'self.extensions = [ext for ext in self.extensions if ext.name in ["${internalName}"]]'
198
199 python ./setup.py build_ext
200 [ -z "$(find build -name '*_failed.so' -print)" ]
201 '';
202
203 installPhase =
204 ''
205 dest=$out/lib/${python.libPrefix}/site-packages
206 mkdir -p $dest
207 cp -p $(find . -name "*.${if stdenv.isCygwin then "dll" else "so"}") $dest/
208 '';
209 };
210
211
212 # The Python modules included in the main Python distribution, built
213 # as separate derivations.
214 modules = {
215
216 bsddb = buildInternalPythonModule {
217 moduleName = "bsddb";
218 deps = [ db ];
219 };
220
221 curses = buildInternalPythonModule {
222 moduleName = "curses";
223 deps = [ ncurses ];
224 };
225
226 curses_panel = buildInternalPythonModule {
227 moduleName = "curses_panel";
228 deps = [ ncurses modules.curses ];
229 };
230
231 crypt = buildInternalPythonModule {
232 moduleName = "crypt";
233 internalName = "crypt";
234 deps = optional (stdenv ? glibc) stdenv.glibc;
235 };
236
237 gdbm = buildInternalPythonModule {
238 moduleName = "gdbm";
239 internalName = "gdbm";
240 deps = [ gdbm ] ++ stdenv.lib.optional stdenv.isCygwin gettext;
241 };
242
243 sqlite3 = buildInternalPythonModule {
244 moduleName = "sqlite3";
245 deps = [ sqlite ];
246 };
247
248 } // optionalAttrs x11Support {
249
250 tkinter = if stdenv.isCygwin then null else (buildInternalPythonModule {
251 moduleName = "tkinter";
252 deps = [ tcl tk x11 libX11 ];
253 });
254
255 } // {
256
257 readline = buildInternalPythonModule {
258 moduleName = "readline";
259 internalName = "readline";
260 deps = [ readline ];
261 };
262
263 };
264
265in python // { inherit modules; }