commit 1dbb521
shrub
·
2026-05-30 12:21:31 +0000 UTC
parent 32cdfd6
fix subgraph target with no recipe emission and fix pattern/suffix rule precendence, add new test
8 files changed,
+51,
-21
+0,
-14
1@@ -196,18 +196,6 @@ rulecmd(const struct Target *t)
2 return escaped;
3 }
4
5-static int
6-issubgraphparent(const struct Graph *graph, const char *name)
7-{
8- size_t i;
9-
10- for (i = 0; i < graph->nsubs; i++) {
11- if (hasword(&graph->subs[i].parents, name))
12- return 1;
13- }
14- return 0;
15-}
16-
17 static int
18 findrule(struct Rule *rules, size_t n, const char *cmd)
19 {
20@@ -256,8 +244,6 @@ genninjafile(const struct Graph *graph, const char *path, const char *prefix, in
21 for (i = 0; i < graph->n; i++) {
22 if (!targetownedby(&graph->v[i], prefix))
23 continue;
24- if (issubgraphparent(graph, graph->v[i].name) && graph->v[i].recipes.n == 0)
25- continue;
26 if (graph->v[i].recipes.n > 0) {
27 char *cmd;
28 int id;
+1,
-1
1@@ -167,7 +167,7 @@ loadimppatrules(struct PatRules *rules, const char *src)
2
3 if (node->kind != NODE_RULE)
4 continue;
5- collectpat(rules, &node->data.rule);
6+ collectpat(rules, &node->data.rule, 1);
7 }
8 freeast(&ast);
9 return 0;
+5,
-2
1@@ -106,7 +106,7 @@ patmatches(const char *pat, const char *name)
2 }
3
4 void
5-collectpat(struct PatRules *rules, const struct RuleNode *rule)
6+collectpat(struct PatRules *rules, const struct RuleNode *rule, int builtin)
7 {
8 size_t i;
9
10@@ -122,6 +122,7 @@ collectpat(struct PatRules *rules, const struct RuleNode *rule)
11 addwords(&p->prereqs, &rule->prereqs);
12 addwords(&p->order_only, &rule->order_only);
13 addrecipes(&p->recipes, &rule->recipes);
14+ p->builtin = builtin;
15 }
16 }
17
18@@ -157,13 +158,15 @@ patruleviable(const struct PatRule *rule, const struct Graph *graph, const char
19 }
20
21 int
22-instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct EvalCtx *ctx)
23+instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct EvalCtx *ctx, int allow_builtin)
24 {
25 size_t i, j;
26
27 for (i = 0; i < rules->n; i++) {
28 char *stem;
29
30+ if (rules->v[i].builtin && !allow_builtin)
31+ continue;
32 stem = patmatchstem(rules->v[i].target, t->name);
33 if (!stem)
34 continue;
+3,
-2
1@@ -8,6 +8,7 @@ struct PatRule {
2 struct StrList prereqs;
3 struct StrList order_only;
4 struct RecipeList recipes;
5+ int builtin;
6 };
7
8 struct PatRules {
9@@ -20,8 +21,8 @@ int patmatches(const char *pat, const char *name);
10 char *patmatchstem(const char *pat, const char *name);
11 char *patapplystem(const char *s, const char *stem);
12 char *patexpandstem(const char *s, const char *stem);
13-void collectpat(struct PatRules *rules, const struct RuleNode *rule);
14-int instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct EvalCtx *ctx);
15+void collectpat(struct PatRules *rules, const struct RuleNode *rule, int builtin);
16+int instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct EvalCtx *ctx, int allow_builtin);
17 void freepatrule(struct PatRules *rules);
18
19 #endif
+11,
-2
1@@ -346,7 +346,7 @@ buildgraph(const struct RuleSet *ruleset, const struct StrList *goals, struct Gr
2 continue;
3 /* pattern rules (%.o: %.c) are a gnu extension */
4 if (gs.mode == MODE_GNU)
5- collectpat(&gs.patterns, &gs.rules[i]);
6+ collectpat(&gs.patterns, &gs.rules[i], 0);
7 for (k = 0; k < gs.rules[i].targets.n; k++) {
8 if (!ispat(gs.rules[i].targets.v[k]))
9 addrule(&gs, gs.rules[i].targets.v[k], &gs.rules[i]);
10@@ -417,11 +417,20 @@ buildgraph(const struct RuleSet *ruleset, const struct StrList *goals, struct Gr
11 targetctx.env = &env;
12 targetctx.mode = gs.mode;
13 targetenv(&gs, &targetctx, &t->env, t->name);
14+ /* rule precedence in GNU mode:
15+ * 1) user defined pattern rules
16+ * 2) suffix rules
17+ * 3) builtin pattern rules
18+ *
19+ * we make sure local suffix compile recipes dont get overshadowed
20+ * by GNU builtins like %.o: %.c (dropbear fails without this). */
21 if (gs.mode == MODE_GNU)
22- instpatrule(&gs.patterns, graph, t, &targetctx);
23+ instpatrule(&gs.patterns, graph, t, &targetctx, 0);
24 matched = t->recipes.n > 0;
25 if (!matched) {
26 instsufrule(&gs.sufs, graph, t, &targetctx);
27+ if (gs.mode == MODE_GNU && t->recipes.n == 0)
28+ instpatrule(&gs.patterns, graph, t, &targetctx, 1);
29 if (t->recipes.n == 0)
30 instdefaultrule(&gs, t, &targetctx);
31 }
+6,
-0
1@@ -0,0 +1,6 @@
2+.SUFFIXES: .o .c
3+
4+all: x.o
5+
6+.c.o:
7+ @echo suffix-rule $<
+1,
-0
1@@ -0,0 +1 @@
2+suffix-rule x.c
+24,
-0
1@@ -0,0 +1,24 @@
2+{
3+ "case": "t001",
4+ "category": "suffixrules",
5+ "compare_output": true,
6+ "description": "user .c.o suffix rule should beat builtin %.o: %.c rule",
7+ "details": "",
8+ "env": {},
9+ "expected_exit": 0,
10+ "options": "",
11+ "options_mode": "argv",
12+ "output_mode": "exact",
13+ "setup": [
14+ {
15+ "content": "#include \"missing-header-for-regression-test.h\"\n",
16+ "kind": "file",
17+ "mode": "0644",
18+ "mtime": 1778707209,
19+ "path": "x.c"
20+ }
21+ ],
22+ "stdin": "",
23+ "suite": "shin",
24+ "timeout_seconds": 60
25+}