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