Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1# We have tests for PCRE and PHP-FPM in nixos/tests/php/ or
2# both in the same attribute named nixosTests.php
3
4let
5 generic =
6 { callPackage
7 , lib
8 , stdenv
9 , nixosTests
10 , tests
11 , fetchurl
12 , makeWrapper
13 , symlinkJoin
14 , writeText
15 , autoconf
16 , automake
17 , bison
18 , flex
19 , libtool
20 , pkg-config
21 , re2c
22 , apacheHttpd
23 , libargon2
24 , libxml2
25 , pcre2
26 , systemd
27 , system-sendmail
28 , valgrind
29 , xcbuild
30
31 , version
32 , sha256
33 , extraPatches ? [ ]
34 , packageOverrides ? (final: prev: { })
35 , phpAttrsOverrides ? (attrs: { })
36
37 # Sapi flags
38 , cgiSupport ? true
39 , cliSupport ? true
40 , fpmSupport ? true
41 , pearSupport ? true
42 , pharSupport ? true
43 , phpdbgSupport ? true
44
45 # Misc flags
46 , apxs2Support ? !stdenv.isDarwin
47 , argon2Support ? true
48 , cgotoSupport ? false
49 , embedSupport ? false
50 , ipv6Support ? true
51 , systemdSupport ? stdenv.isLinux
52 , valgrindSupport ? !stdenv.isDarwin && lib.meta.availableOn stdenv.hostPlatform valgrind
53 , ztsSupport ? apxs2Support
54 }@args:
55
56 let
57 # Compose two functions of the type expected by 'overrideAttrs'
58 # into one where changes made in the first are available to the second.
59 composeOverrides =
60 f: g: attrs:
61 let
62 fApplied = f attrs;
63 attrs' = attrs // fApplied;
64 in
65 fApplied // g attrs';
66
67 # buildEnv wraps php to provide additional extensions and
68 # configuration. Its usage is documented in
69 # doc/languages-frameworks/php.section.md.
70 #
71 # Create a buildEnv with earlier overridden values and
72 # extensions functions in its closure. This is necessary for
73 # consecutive calls to buildEnv and overrides to work as
74 # expected.
75 mkBuildEnv = prevArgs: prevExtensionFunctions: lib.makeOverridable (
76 { extensions ? ({ enabled, ... }: enabled), extraConfig ? "", ... }@innerArgs:
77 let
78 allArgs = args // prevArgs // innerArgs;
79 filteredArgs = builtins.removeAttrs allArgs [ "extensions" "extraConfig" ];
80 php = generic filteredArgs;
81
82 php-packages = (callPackage ../../../top-level/php-packages.nix {
83 phpPackage = phpWithExtensions;
84 }).overrideScope' packageOverrides;
85
86 allExtensionFunctions = prevExtensionFunctions ++ [ extensions ];
87 enabledExtensions =
88 builtins.foldl'
89 (enabled: f:
90 f { inherit enabled; all = php-packages.extensions; })
91 [ ]
92 allExtensionFunctions;
93
94 getExtName = ext: lib.removePrefix "php-" (builtins.parseDrvName ext.name).name;
95
96 # Recursively get a list of all internal dependencies
97 # for a list of extensions.
98 getDepsRecursively = extensions:
99 let
100 deps = lib.concatMap
101 (ext: (ext.internalDeps or [ ]) ++ (ext.peclDeps or [ ]))
102 extensions;
103 in
104 if ! (deps == [ ]) then
105 deps ++ (getDepsRecursively deps)
106 else
107 deps;
108
109 # Generate extension load configuration snippets from the
110 # extension parameter. This is an attrset suitable for use
111 # with textClosureList, which is used to put the strings in
112 # the right order - if a plugin which is dependent on
113 # another plugin is placed before its dependency, it will
114 # fail to load.
115 extensionTexts =
116 lib.listToAttrs
117 (map
118 (ext:
119 let
120 extName = getExtName ext;
121 phpDeps = (ext.internalDeps or [ ]) ++ (ext.peclDeps or [ ]);
122 type = "${lib.optionalString (ext.zendExtension or false) "zend_"}extension";
123 in
124 lib.nameValuePair extName {
125 text = "${type}=${ext}/lib/php/extensions/${extName}.so";
126 deps = map getExtName phpDeps;
127 })
128 (enabledExtensions ++ (getDepsRecursively enabledExtensions)));
129
130 extNames = map getExtName enabledExtensions;
131 extraInit = writeText "php-extra-init-${version}.ini" ''
132 ${lib.concatStringsSep "\n"
133 (lib.textClosureList extensionTexts extNames)}
134 ${extraConfig}
135 '';
136
137 phpWithExtensions = symlinkJoin {
138 name = "php-with-extensions-${version}";
139 inherit (php) version;
140 nativeBuildInputs = [ makeWrapper ];
141 passthru = php.passthru // {
142 buildEnv = mkBuildEnv allArgs allExtensionFunctions;
143 withExtensions = mkWithExtensions allArgs allExtensionFunctions;
144 overrideAttrs =
145 f:
146 let
147 newPhpAttrsOverrides = composeOverrides (filteredArgs.phpAttrsOverrides or (attrs: { })) f;
148 php = generic (filteredArgs // { phpAttrsOverrides = newPhpAttrsOverrides; });
149 in
150 php.buildEnv { inherit extensions extraConfig; };
151 phpIni = "${phpWithExtensions}/lib/php.ini";
152 unwrapped = php;
153 # Select the right php tests for the php version
154 tests = {
155 nixos = lib.recurseIntoAttrs nixosTests."php${lib.strings.replaceStrings [ "." ] [ "" ] (lib.versions.majorMinor php.version)}";
156 package = tests.php;
157 };
158 inherit (php-packages) extensions buildPecl mkExtension;
159 packages = php-packages.tools;
160 meta = php.meta // {
161 outputsToInstall = [ "out" ];
162 };
163 };
164 paths = [ php ];
165 postBuild = ''
166 ln -s ${extraInit} $out/lib/php.ini
167
168 if test -e $out/bin/php; then
169 wrapProgram $out/bin/php --set PHP_INI_SCAN_DIR $out/lib
170 fi
171
172 if test -e $out/bin/php-fpm; then
173 wrapProgram $out/bin/php-fpm --set PHP_INI_SCAN_DIR $out/lib
174 fi
175
176 if test -e $out/bin/phpdbg; then
177 wrapProgram $out/bin/phpdbg --set PHP_INI_SCAN_DIR $out/lib
178 fi
179 '';
180 };
181 in
182 phpWithExtensions
183 );
184
185 mkWithExtensions = prevArgs: prevExtensionFunctions: extensions:
186 mkBuildEnv prevArgs prevExtensionFunctions { inherit extensions; };
187 in
188 stdenv.mkDerivation (
189 let
190 attrs = {
191 pname = "php";
192
193 inherit version;
194
195 enableParallelBuilding = true;
196
197 nativeBuildInputs = [ autoconf automake bison flex libtool pkg-config re2c ]
198 ++ lib.optional stdenv.isDarwin xcbuild;
199
200 buildInputs =
201 # PCRE extension
202 [ pcre2 ]
203
204 # Enable sapis
205 ++ lib.optional pearSupport [ libxml2.dev ]
206
207 # Misc deps
208 ++ lib.optional apxs2Support apacheHttpd
209 ++ lib.optional argon2Support libargon2
210 ++ lib.optional systemdSupport systemd
211 ++ lib.optional valgrindSupport valgrind
212 ;
213
214 CXXFLAGS = lib.optionalString stdenv.cc.isClang "-std=c++11";
215
216 configureFlags =
217 # Disable all extensions
218 [ "--disable-all" ]
219
220 # PCRE
221 ++ lib.optionals (lib.versionAtLeast version "7.4") [ "--with-external-pcre=${pcre2.dev}" ]
222 ++ [ "PCRE_LIBDIR=${pcre2}" ]
223
224
225 # Enable sapis
226 ++ lib.optional (!cgiSupport) "--disable-cgi"
227 ++ lib.optional (!cliSupport) "--disable-cli"
228 ++ lib.optional fpmSupport "--enable-fpm"
229 ++ lib.optional pearSupport [ "--with-pear" "--enable-xml" "--with-libxml" ]
230 ++ lib.optionals (pearSupport && (lib.versionOlder version "7.4")) [
231 "--enable-libxml"
232 "--with-libxml-dir=${libxml2.dev}"
233 ]
234 ++ lib.optional pharSupport "--enable-phar"
235 ++ lib.optional (!phpdbgSupport) "--disable-phpdbg"
236
237
238 # Misc flags
239 ++ lib.optional apxs2Support "--with-apxs2=${apacheHttpd.dev}/bin/apxs"
240 ++ lib.optional argon2Support "--with-password-argon2=${libargon2}"
241 ++ lib.optional cgotoSupport "--enable-re2c-cgoto"
242 ++ lib.optional embedSupport "--enable-embed"
243 ++ lib.optional (!ipv6Support) "--disable-ipv6"
244 ++ lib.optional systemdSupport "--with-fpm-systemd"
245 ++ lib.optional valgrindSupport "--with-valgrind=${valgrind.dev}"
246 ++ lib.optional (ztsSupport && (lib.versionOlder version "8.0")) "--enable-maintainer-zts"
247 ++ lib.optional (ztsSupport && (lib.versionAtLeast version "8.0")) "--enable-zts"
248
249
250 # Sendmail
251 ++ [ "PROG_SENDMAIL=${system-sendmail}/bin/sendmail" ]
252 ;
253
254 hardeningDisable = [ "bindnow" ];
255
256 preConfigure =
257 # Don't record the configure flags since this causes unnecessary
258 # runtime dependencies
259 ''
260 for i in main/build-defs.h.in scripts/php-config.in; do
261 substituteInPlace $i \
262 --replace '@CONFIGURE_COMMAND@' '(omitted)' \
263 --replace '@CONFIGURE_OPTIONS@' "" \
264 --replace '@PHP_LDFLAGS@' ""
265 done
266
267 export EXTENSION_DIR=$out/lib/php/extensions
268 ''
269 # PKG_CONFIG need not be a relative path
270 + lib.optionalString (!lib.versionAtLeast version "7.4") ''
271 for i in $(find . -type f -name "*.m4"); do
272 substituteInPlace $i \
273 --replace 'test -x "$PKG_CONFIG"' 'type -P "$PKG_CONFIG" >/dev/null'
274 done
275 '' + ''
276 ./buildconf --copy --force
277
278 if test -f $src/genfiles; then
279 ./genfiles
280 fi
281 '' + lib.optionalString stdenv.isDarwin ''
282 substituteInPlace configure --replace "-lstdc++" "-lc++"
283 '';
284
285 postInstall = ''
286 test -d $out/etc || mkdir $out/etc
287 cp php.ini-production $out/etc/php.ini
288 '';
289
290 postFixup = ''
291 mkdir -p $dev/bin $dev/share/man/man1
292 mv $out/bin/phpize $out/bin/php-config $dev/bin/
293 mv $out/share/man/man1/phpize.1.gz \
294 $out/share/man/man1/php-config.1.gz \
295 $dev/share/man/man1/
296 '';
297
298 src = fetchurl {
299 url = "https://www.php.net/distributions/php-${version}.tar.bz2";
300 inherit sha256;
301 };
302
303 patches = [ ./fix-paths-php7.patch ] ++ extraPatches;
304
305 separateDebugInfo = true;
306
307 outputs = [ "out" "dev" ];
308
309 passthru = {
310 buildEnv = mkBuildEnv { } [ ];
311 withExtensions = mkWithExtensions { } [ ];
312 overrideAttrs =
313 f:
314 let
315 newPhpAttrsOverrides = composeOverrides phpAttrsOverrides f;
316 php = generic (args // { phpAttrsOverrides = newPhpAttrsOverrides; });
317 in
318 php;
319 inherit ztsSupport;
320 };
321
322 meta = with lib; {
323 description = "An HTML-embedded scripting language";
324 homepage = "https://www.php.net/";
325 license = licenses.php301;
326 maintainers = teams.php.members;
327 platforms = platforms.all;
328 outputsToInstall = [ "out" "dev" ];
329 };
330 };
331 in
332 attrs // phpAttrsOverrides attrs
333 );
334in
335generic