Blob
1 # awkward make3 function strip(s) {4 sub(/^[[:space:]]*/, "", s);5 sub(/[[:space:]]*$/, "", s);6 return s;7 }9 function find(name) {10 for (i = 1; i <= length(data);) {11 if (data[i] == name)12 return i;13 i += data[++i] + 1;14 i += data[i] + 1;15 }16 return 0;17 }19 function isnewer(a, b) {20 cmd = sprintf("ls -1t '%s' '%s' 2>&1", a, b);21 cmd | getline file;22 close(cmd);23 regex = "^" a "\*?$";24 return file ~ regex;25 }27 function exists(f) {28 cmd = sprintf("ls '%s' > /dev/null 2>&1", f);29 return system(cmd) == 0;30 }32 function expand(s, rulename, i, out, name, ch, chars) {33 out = "";34 split(s, chars, "");35 for (i = 1; i <= length(chars);) {36 ch = chars[i++];37 if (ch != "$") {38 out = out ch;39 continue;40 }42 ch = chars[i++];44 if (ch == "{") {45 name = "";46 while (1) {47 ch = chars[i++];48 if (ch == "}")49 break;50 name = name ch;51 }53 out = out macros[name];54 } else if (ch == "$") {55 out = out "$";56 } else if (ch == "@") {57 out = out rulename;58 } else {59 print "ERROR: invalid replacement";60 exit 1;61 }62 }63 return out;64 }66 function run(pos, name, updated, num, i, dep, cmd) {67 name = data[pos];68 num = data[++pos];69 ++pos;71 updated = !exists(name);73 for (i = 1; i <= num; ++i) {74 dep = data[pos++];75 rule = find(dep);77 if (exists(dep)) {78 if (isnewer(dep, name))79 updated = 1;80 }82 if (rule != 0) {83 if (run(rule))84 updated = 1;85 } else if (!exists(dep)) {86 print "ERROR: No rule for", dep;87 exit 1;88 }89 }91 if (updated == 0)92 return 0;94 num = data[pos++];95 for (i = 1; i <= num; ++i) {96 cmd = data[pos++];97 print cmd;98 cmd = expand(cmd, name);99 if (system(cmd) != 0) {100 print "ERROR: Command failed";101 exit 1;102 }103 }104 return 1;105 }107 BEGIN {108 pos = 1;109 saved = -1;110 }112 # Empty lines and comments113 /^[[:space:]]*(#.*)?$/ { next; }115 # Macro Definitions116 /^[a-zA-Z_][a-zA-Z_0-9]*[[:space:]]*=.*$/ {117 split($0, x, "=");118 macros[strip(x[1])] = strip(x[2]);119 next;120 }122 # Rule Declarations123 /^[^:]+:[^:]*$/ {124 split($0, x, ":");125 split(strip(x[1]), targets, "[[:space:]]+");126 if (length(targets) != 1) {127 print "ERROR: no multi-targets supported";128 exit 1;129 }130 target = targets[1];131 split(strip(x[2]), deps, "[[:space:]]+");133 if (target ~ /^\..*$/) {134 if (target == ".POSIX")135 next;136 print "ERROR: invalid directive" target;137 exit 1;138 }140 data[pos++] = target;141 data[pos++] = length(deps);142 for (i = 1; i <= length(deps); ++i) {143 data[pos++] = deps[i];144 }145 saved = pos++;146 data[saved] = 0;147 next;148 }150 # Rule Commands151 /^\t.*$/ {152 if (saved == -1) {153 print "ERROR: no rule declaration";154 exit 1;155 }156 gsub(/^\t/, "");157 data[saved]++;158 data[pos++] = $0;159 }161 END {162 split(args, argv, "[[:space:]]+");164 k = 1;166 for (i = 1; i <= length(argv); ++i) {167 arg = argv[i];168 if (arg ~ /^[^=]+=.*$/) {169 split(arg, m, "=");170 macros[m[1]] = m[2];171 } else {172 rules[k++] = arg;173 }174 }176 if (length(rules) != 0) {177 for (k = 1; k <= length(rules); ++k) {178 name = rules[k];179 rule = find(name);180 if (rule == 0) {181 print "No such rule:", name;182 exit 1;183 }184 run(rule);185 }186 } else {187 run(1);188 }189 }