From 030d8f8ea9d4c2a896efad2b327a3308f7fd8c1b Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 17 Oct 2024 11:27:35 +0100 Subject: make: improve chaining of implicit rules Running 'make thing.z' with the following makefile: .SUFFIXES: .x .y .z .x.y: cp $< $@ .y.x: cp $< $@ .y.z: cp $< $@ resulted in infinite recursion and a segfault. Follow GNU make and don't allow any implicit rule to appear more than once in a chain. Adds 16-32 bytes. --- miscutils/make.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'miscutils') diff --git a/miscutils/make.c b/miscutils/make.c index 868cab5e2..4a8643a83 100644 --- a/miscutils/make.c +++ b/miscutils/make.c @@ -1016,14 +1016,30 @@ dyndep(struct name *np, struct rule *imprule) newsuff = dp->d_name->n_name; sp = findname(auto_concat(newsuff, suff)); if (sp && sp->n_rule) { + struct name *ip; + int got_ip; + + // Has rule already been used in this chain? + if ((sp->n_flag & N_MARK)) + continue; + // Generate a name for an implicit prerequisite - struct name *ip = newname(auto_concat(base, newsuff)); + ip = newname(auto_concat(base, newsuff)); if ((ip->n_flag & N_DOING)) continue; + if (!ip->n_tim.tv_sec) modtime(ip); - if (!chain ? ip->n_tim.tv_sec || (ip->n_flag & N_TARGET) : - dyndep(ip, NULL) != NULL) { + + if (!chain) { + got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET); + } else { + sp->n_flag |= N_MARK; + got_ip = dyndep(ip, NULL) != NULL; + sp->n_flag &= ~N_MARK; + } + + if (got_ip) { // Prerequisite exists or we know how to make it if (imprule) { dp = NULL; -- cgit v1.2.3-55-g6feb