lol

Merge pull request #26974 from obsidiansystems/response-file-parsing-speed

cc-wrapper: improve response file parsing speed

authored by

Ryan Trinkle and committed by
GitHub
70046415 c23dcd72

+134 -53
+16 -3
pkgs/build-support/cc-wrapper/default.nix
··· 10 10 , zlib ? null, extraPackages ? [], extraBuildCommands ? "" 11 11 , dyld ? null # TODO: should this be a setup-hook on dyld? 12 12 , isGNU ? false, isClang ? cc.isClang or false, gnugrep ? null 13 - , hostPlatform, targetPlatform 13 + , buildPackages ? {}, hostPlatform, targetPlatform 14 14 , runCommand ? null 15 15 }: 16 16 ··· 119 119 "Don't know the name of the dynamic linker for platform ${targetPlatform.config}, so guessing instead." 120 120 null) 121 121 else ""; 122 + 123 + expand-response-params = if buildPackages.stdenv.cc or null != null && buildPackages.stdenv.cc != "/dev/null" 124 + then buildPackages.stdenv.mkDerivation { 125 + name = "expand-response-params"; 126 + src = ./expand-response-params.c; 127 + buildCommand = '' 128 + # Work around "stdenv-darwin-boot-2 is not allowed to refer to path /nix/store/...-expand-response-params.c" 129 + cp "$src" expand-response-params.c 130 + "$CC" -std=c99 -O3 -o "$out" expand-response-params.c 131 + ''; 132 + } else ""; 122 133 123 134 in 124 135 ··· 368 379 + '' 369 380 substituteAll ${preWrap ./add-flags.sh} $out/nix-support/add-flags.sh 370 381 substituteAll ${preWrap ./add-hardening.sh} $out/nix-support/add-hardening.sh 371 - cp -p ${preWrap ./utils.sh} $out/nix-support/utils.sh 382 + substituteAll ${preWrap ./utils.sh} $out/nix-support/utils.sh 372 383 '' 373 384 + extraBuildCommands; 374 385 375 - inherit dynamicLinker; 386 + inherit dynamicLinker expand-response-params; 387 + 388 + expandResponseParams = expand-response-params; # for substitution in utils.sh 376 389 377 390 crossAttrs = { 378 391 shell = shell.crossDrv + shell.crossDrv.shellPath;
+84
pkgs/build-support/cc-wrapper/expand-response-params.c
··· 1 + #include <assert.h> 2 + #include <ctype.h> 3 + #include <stdio.h> 4 + #include <stdlib.h> 5 + #include <string.h> 6 + 7 + typedef struct { char *data; size_t len, cap; } String; 8 + 9 + void resize(String *s, size_t len) { 10 + s->len = len; 11 + if (s->cap < s->len) { 12 + s->cap = s->len * 2; 13 + s->data = (char *)realloc(s->data, s->cap); 14 + assert(s->data); 15 + } 16 + } 17 + 18 + void append(String *s, const char *data, size_t len) { 19 + resize(s, s->len + len); 20 + memcpy(s->data + s->len - len, data, len); 21 + } 22 + 23 + typedef enum { space = 0, other = 1, backslash = 2, apostrophe = 3, quotation_mark = 4 } CharClass; 24 + typedef enum { outside, unq, unq_esc, sq, sq_esc, dq, dq_esc } State; 25 + 26 + // current State -> CharClass -> next State 27 + const State transitions[][5] = { 28 + [outside] = {outside, unq, unq_esc, sq, dq}, 29 + [unq] = {outside, unq, unq_esc, sq, dq}, 30 + [unq_esc] = {unq, unq, unq, unq, unq}, 31 + [sq] = {sq, sq, sq_esc, unq, sq}, 32 + [sq_esc] = {sq, sq, sq, sq, sq}, 33 + [dq] = {dq, dq, dq_esc, dq, unq}, 34 + [dq_esc] = {dq, dq, dq, dq, dq}, 35 + }; 36 + 37 + CharClass charClass(int c) { 38 + return c == '\\' ? backslash : c == '\'' ? apostrophe : c == '"' ? quotation_mark : 39 + isspace(c) ? space : other; 40 + } 41 + 42 + // expandArg writes NULL-terminated expansions of `arg', a NULL-terminated 43 + // string, to stdout. If arg does not begin with `@' or does not refer to a 44 + // file, it is written as is. Otherwise the contents of the file are 45 + // recursively expanded. On unexpected EOF in malformed response files an 46 + // incomplete final argument is written, even if it is empty, to parse like GCC. 47 + void expandArg(String *arg) { 48 + FILE *f; 49 + if (arg->data[0] != '@' || !(f = fopen(&arg->data[1], "r"))) { 50 + fwrite(arg->data, 1, arg->len, stdout); 51 + return; 52 + } 53 + 54 + resize(arg, 0); 55 + State cur = outside; 56 + int c; 57 + do { 58 + c = fgetc(f); 59 + State next = transitions[cur][charClass(c)]; 60 + if ((cur == unq && next == outside) || (cur != outside && c == EOF)) { 61 + append(arg, "", 1); 62 + expandArg(arg); 63 + resize(arg, 0); 64 + } else if (cur == unq_esc || cur == sq_esc || cur == dq_esc || 65 + (cur == outside ? next == unq : cur == next)) { 66 + char s = c; 67 + append(arg, &s, 1); 68 + } 69 + cur = next; 70 + } while (c != EOF); 71 + 72 + fclose(f); 73 + } 74 + 75 + int main(int argc, char **argv) { 76 + String arg = { 0 }; 77 + while (*++argv) { 78 + resize(&arg, 0); 79 + append(&arg, *argv, strlen(*argv) + 1); 80 + expandArg(&arg); 81 + } 82 + free(arg.data); 83 + return EXIT_SUCCESS; 84 + }
+11 -45
pkgs/build-support/cc-wrapper/utils.sh
··· 23 23 "${p:0:${#NIX_BUILD_TOP}}" != "$NIX_BUILD_TOP" 24 24 } 25 25 26 - # @args.rsp parser. 27 - # Char classes: space, other, backslash, single quote, double quote. 28 - # States: 0 - outside, 1/2 - unquoted arg/slash, 3/4 - 'arg'/slash, 5/6 - "arg"/slash. 29 - # State transitions: 30 - rspT=(01235 01235 11111 33413 33333 55651 55555) 31 - # Push (a) arg or (c) char on transition: 32 - rspP[10]=a rspP[01]=c rspP[11]=c rspP[21]=c rspP[33]=c rspP[43]=c rspP[55]=c rspP[65]=c 33 - 34 - rspParse() { 35 - rsp=() 36 - local state=0 37 - local arg='' 38 - local c 39 - 40 - while read -r -N1 c; do 41 - local cls=1 42 - case "$c" in 43 - ' ' | $'\t' | $'\r' | $'\n') cls=0 ;; 44 - '\') cls=2 ;; 45 - "'") cls=3 ;; 46 - '"') cls=4 ;; 47 - esac 48 - local nextstates="${rspT[$state]}" 49 - local nextstate="${nextstates:$cls:1}" 50 - case "${rspP[$state$nextstate]}" in 51 - 'c') arg+="$c" ;; 52 - 'a') rsp+=("$arg"); arg='' ;; 53 - esac 54 - state="$nextstate" 55 - done 56 - 57 - if [ "$state" -ne 0 ]; then 58 - rsp+=("$arg") 59 - fi 60 - } 61 - 62 26 expandResponseParams() { 63 - params=() 64 - while [ $# -gt 0 ]; do 65 - local p="$1" 66 - shift 67 - if [ "${p:0:1}" = '@' -a -e "${p:1}" ]; then 68 - rspParse <"${p:1}" 69 - set -- "${rsp[@]}" "$@" 70 - else 71 - params+=("$p") 27 + params=("$@") 28 + local arg 29 + for arg in "$@"; do 30 + if [[ "$arg" == @* ]]; then 31 + if [ -n "@expandResponseParams@" ]; then 32 + readarray -d '' params < <("@expandResponseParams@" "$@") 33 + return 0 34 + else 35 + echo "Response files aren't supported during bootstrapping" >&2 36 + return 1 37 + fi 72 38 fi 73 39 done 74 40 }
+4 -2
pkgs/os-specific/darwin/ios-cross/default.nix
··· 6 6 , stdenv 7 7 , coreutils 8 8 , gnugrep 9 - , hostPlatform, targetPlatform 9 + , buildPackages 10 + , hostPlatform 11 + , targetPlatform 10 12 }: 11 13 12 14 /* As of this writing, known-good prefix/arch/simulator triples: ··· 29 31 sdk = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhone${sdkType}.platform/Developer/SDKs/iPhone${sdkType}${sdkVer}.sdk"; 30 32 31 33 in (import ../../../build-support/cc-wrapper { 32 - inherit stdenv coreutils gnugrep runCommand; 34 + inherit stdenv coreutils gnugrep runCommand buildPackages; 33 35 nativeTools = false; 34 36 nativeLibc = false; 35 37 inherit binutils;
+13 -3
pkgs/stdenv/darwin/default.nix
··· 54 54 __sandboxProfile = binShClosure + libSystemProfile; 55 55 }; 56 56 57 - stageFun = step: last: {shell ? "${bootstrapTools}/bin/sh", 57 + stageFun = step: last: {shell ? "${bootstrapTools}/bin/bash", 58 58 overrides ? (self: super: {}), 59 59 extraPreHook ? "", 60 60 extraBuildInputs, 61 61 allowedRequisites ? null}: 62 62 let 63 63 thisStdenv = import ../generic { 64 - inherit config shell extraBuildInputs allowedRequisites; 64 + inherit config shell extraBuildInputs; 65 + allowedRequisites = if allowedRequisites == null then null else allowedRequisites ++ [ 66 + thisStdenv.cc.expand-response-params 67 + ]; 65 68 66 69 name = "stdenv-darwin-boot-${toString step}"; 67 70 ··· 73 76 nativeTools = true; 74 77 nativePrefix = bootstrapTools; 75 78 nativeLibc = false; 79 + buildPackages = lib.optionalAttrs (last ? stdenv) { 80 + inherit (last) stdenv; 81 + }; 76 82 hostPlatform = localSystem; 77 83 targetPlatform = localSystem; 78 84 libc = last.pkgs.darwin.Libsystem; ··· 80 86 cc = { name = "clang-9.9.9"; outPath = bootstrapTools; }; 81 87 }; 82 88 83 - preHook = stage0.stdenv.lib.optionalString (shell == "${bootstrapTools}/bin/sh") '' 89 + preHook = stage0.stdenv.lib.optionalString (shell == "${bootstrapTools}/bin/bash") '' 84 90 # Don't patch #!/interpreter because it leads to retained 85 91 # dependencies on the bootstrapTools in the final stdenv. 86 92 dontPatchShebangs=1 ··· 297 303 inherit shell; 298 304 nativeTools = false; 299 305 nativeLibc = false; 306 + buildPackages = { 307 + inherit (prevStage) stdenv; 308 + }; 300 309 hostPlatform = localSystem; 301 310 targetPlatform = localSystem; 302 311 inherit (pkgs) coreutils binutils gnugrep; ··· 319 328 gzip ncurses.out ncurses.dev ncurses.man gnused bash gawk 320 329 gnugrep llvmPackages.clang-unwrapped patch pcre.out binutils-raw.out 321 330 binutils-raw.dev binutils gettext 331 + cc.expand-response-params 322 332 ]) ++ (with pkgs.darwin; [ 323 333 dyld Libsystem CF cctools ICU libiconv locale 324 334 ]);
+6
pkgs/stdenv/linux/default.nix
··· 76 76 else lib.makeOverridable (import ../../build-support/cc-wrapper) { 77 77 nativeTools = false; 78 78 nativeLibc = false; 79 + buildPackages = lib.optionalAttrs (prevStage ? stdenv) { 80 + inherit (prevStage) stdenv; 81 + }; 79 82 hostPlatform = localSystem; 80 83 targetPlatform = localSystem; 81 84 cc = prevStage.gcc-unwrapped; ··· 241 244 nativeTools = false; 242 245 nativeLibc = false; 243 246 isGNU = true; 247 + buildPackages = { 248 + inherit (prevStage) stdenv; 249 + }; 244 250 hostPlatform = localSystem; 245 251 targetPlatform = localSystem; 246 252 cc = prevStage.gcc-unwrapped;