xref: /illumos-gate/usr/src/cmd/make/bin/rep.cc (revision 4c28a617e3922d92a58e813a5b955eb526b9c386)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *	rep.c
28  *
29  *	This file handles the .nse_depinfo file
30  */
31 
32 /*
33  * Included files
34  */
35 #include <mk/defs.h>
36 #include <mksh/misc.h>		/* retmem() */
37 #include <vroot/report.h>	/* NSE_DEPINFO */
38 
39 /*
40  * Static variables
41  */
42 static	Recursive_make	recursive_list;
43 static	Recursive_make	*bpatch = &recursive_list;
44 static	Boolean		changed;
45 
46 /*
47  * File table of contents
48  */
49 
50 
51 /*
52  *	report_recursive_init()
53  *
54  *	Read the .nse_depinfo file and make a list of all the
55  *	.RECURSIVE entries.
56  *
57  *	Parameters:
58  *
59  *	Static variables used:
60  *		bpatch		Points to slot where next cell should be added
61  *
62  *	Global variables used:
63  *		recursive_name	The Name ".RECURSIVE", compared against
64  */
65 
66 void
67 report_recursive_init(void)
68 {
69 	char		*search_dir;
70 	char		nse_depinfo[MAXPATHLEN];
71 	FILE		*fp;
72 	int		line_size, line_index;
73 	wchar_t		*line;
74 	wchar_t		*bigger_line;
75 	wchar_t		*colon;
76 	wchar_t		*dollar;
77 	Recursive_make	rp;
78 
79 	/*
80 	 * This routine can be called more than once,  don't do
81 	 * anything after the first time.
82 	 */
83 	if (depinfo_already_read) {
84 		return;
85 	} else {
86 		depinfo_already_read = true;
87 	}
88 
89 	search_dir = getenv("NSE_DEP");
90 	if (search_dir == NULL) {
91 		return;
92 	}
93 	(void) sprintf(nse_depinfo, "%s/%s", search_dir, NSE_DEPINFO);
94 	fp = fopen(nse_depinfo, "r");
95 	if (fp == NULL) {
96 		return;
97 	}
98 	line_size = MAXPATHLEN;
99 	line_index = line_size - 1;
100 	line = ALLOC_WC(line_size);
101 	Wstring rns(recursive_name);
102 	wchar_t * wcb = rns.get_string();
103 	while (fgetws(line, line_size, fp) != NULL) {
104 		while (wcslen(line) == line_index) {
105 			if (line[wcslen(line) - 1] == '\n') {
106 				continue;
107 			}
108 			bigger_line = ALLOC_WC(2 * line_size);
109 			wcscpy(bigger_line, line);
110 			retmem(line);
111 			line = bigger_line;
112 			if (fgetws(&line[line_index], line_size, fp) == NULL)
113 				continue;
114 			line_index = 2 * line_index;
115 			line_size = 2 * line_size;
116 		}
117 
118 		colon = (wchar_t *) wcschr(line, (int) colon_char);
119 		if (colon == NULL) {
120 			continue;
121 		}
122 		dollar = (wchar_t *) wcschr(line, (int) dollar_char);
123 		line[wcslen(line) - 1] = (int) nul_char;
124 		if (IS_WEQUALN(&colon[2], wcb,
125 	            (int) recursive_name->hash.length)) {
126 			/*
127 			 * If this entry is an old entry, ignore it
128 			 */
129 			MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
130 			if (dollar == NULL ||
131 			    !IS_WEQUALN(wcs_buffer, (dollar+1) - VER_LEN, VER_LEN)){
132 				continue;
133 			    }
134 			rp = ALLOC(Recursive_make);
135 			(void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
136 			/*
137 			 * set conditional_macro_string if string is present
138 			 */
139 			rp->oldline = (wchar_t *) wcsdup(line);
140 			if ( dollar != NULL ){
141 				rp->cond_macrostring =
142 				    (wchar_t *) wcsdup(dollar - VER_LEN + 1);
143 			}
144 			/*
145 			 * get target name into recursive struct
146 			 */
147 			*colon = (int) nul_char;
148 			rp->target = (wchar_t *) wcsdup(line);
149 			*bpatch = rp;
150 			bpatch = &rp->next;
151 		}
152 	}
153 	(void) fclose(fp);
154 }
155 
156 /*
157  *	report_recursive_dep(target, line)
158  *
159  *	Report a target as recursive.
160  *
161  *	Parameters:
162  *		line		Dependency line reported
163  *
164  *	Static variables used:
165  *		bpatch		Points to slot where next cell should be added
166  *		changed		Written if report set changed
167  */
168 void
169 report_recursive_dep(Name target, wchar_t *line)
170 {
171 	Recursive_make	rp;
172 	wchar_t		rec_buf[STRING_BUFFER_LENGTH];
173 	String_rec	string;
174 
175 	INIT_STRING_FROM_STACK(string, rec_buf);
176 	cond_macros_into_string(target, &string);
177 	/*
178 	 * find an applicable recursive entry, if there isn't one, create it
179 	 */
180 	rp = find_recursive_target(target);
181 	if (rp == NULL) {
182 		rp = ALLOC(Recursive_make);
183 		(void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
184 		wchar_t * wcb = get_wstring(target->string_mb); // XXX Tolik: needs retmem
185                 rp->target = wcb;
186 		rp->newline = (wchar_t *) wcsdup(line);
187 		rp->cond_macrostring = (wchar_t *) wcsdup(rec_buf);
188 		*bpatch = rp;
189 		bpatch = &rp->next;
190 		changed = true;
191 	} else {
192 		if ((rp->oldline != NULL) && !IS_WEQUAL(rp->oldline, line)) {
193 			rp->newline = (wchar_t *) wcsdup(line);
194 			changed = true;
195 		}
196 		rp->removed = false;
197 	}
198 }
199 
200 /*
201  *	find_recursive_target(target)
202  *
203  *	Search the list for a given target.
204  *
205  *	Return value:
206  *				The target cell
207  *
208  *	Parameters:
209  *		target		The target we need
210  *		top_level_target more info used to determinde the
211  *				 target we need
212  *
213  *	Static variables used:
214  *		recursive_list	The list of targets
215  */
216 Recursive_make
217 find_recursive_target(Name target)
218 {
219 	Recursive_make	rp;
220 	String_rec	string;
221 	wchar_t		rec_buf[STRING_BUFFER_LENGTH];
222 
223 	INIT_STRING_FROM_STACK(string, rec_buf);
224 	cond_macros_into_string(target, &string);
225 
226 	Wstring tstr(target);
227 	wchar_t * wcb = tstr.get_string();
228 	for (rp = recursive_list; rp != NULL; rp = rp->next) {
229 		/*
230 		 * If this entry has already been removed, ignore it.
231 		 */
232 		if (rp->removed)
233 			continue;
234 		/*
235 		 * If this target, and the target on the list are the same
236 		 * and if one of them contains conditional macro info, while
237 		 * the other doesn't,  remove this entry from the list of
238 		 * recursive entries.  This can only happen if the Makefile
239 		 * has changed to no longer contain conditional macros.
240 		 */
241 		if (IS_WEQUAL(rp->target, wcb)) {
242 			if (rp->cond_macrostring[VER_LEN] == '\0' &&
243 			    string.buffer.start[VER_LEN] != '\0'){
244 				rp->removed = true;
245 				continue;
246 			} else if (rp->cond_macrostring[VER_LEN] != '\0' &&
247 			    string.buffer.start[VER_LEN] == '\0'){
248 				rp->removed = true;
249 				continue;
250 			}
251 		}
252 		/*
253 		 * If this is not a VERS2 entry,  only need to match
254 		 * the target name.  toptarg information from VERS1 entries
255 		 * are ignored.
256 		 */
257 		MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
258 		if (IS_WEQUALN(wcs_buffer, string.buffer.start, VER_LEN)) {
259 			if (IS_WEQUAL(rp->cond_macrostring,
260 			    string.buffer.start) &&
261 			    IS_WEQUAL(rp->target, wcb)) {
262 				return rp;
263 			}
264 		} else {
265 			if (IS_WEQUAL(rp->target, wcb)) {
266 				return rp;
267 			}
268 		}
269 	}
270 	return NULL;
271 }
272 
273 /*
274  *	remove_recursive_dep(target, top_level_target)
275  *
276  *	Mark a target as no longer recursive.
277  *
278  *	Parameters:
279  *		target		The target we want to remove
280  *		top_level_target target we want to remove must be built from
281  *				 the same top level target
282  *
283  *	Static variables used:
284  *		changed		Written if report set changed
285  */
286 void
287 remove_recursive_dep(Name target)
288 {
289 	Recursive_make	rp;
290 
291 	rp = find_recursive_target(target);
292 
293 	if ( rp != NULL ) {
294 		rp->removed = true;
295 		changed = true;
296 		if(rp->target) {
297 			retmem(rp->target);
298 			rp->target = NULL;
299 		}
300 		if(rp->newline) {
301 			retmem(rp->newline);
302 			rp->newline = NULL;
303 		}
304 		if(rp->oldline) {
305 			retmem(rp->oldline);
306 			rp->oldline = NULL;
307 		}
308 		if(rp->cond_macrostring) {
309 			retmem(rp->cond_macrostring);
310 			rp->cond_macrostring = NULL;
311 		}
312 	}
313 }
314 
315 
316 /* gather_recursive_deps()
317  *
318  *	Create or update list of recursive targets.
319  */
320 void
321 gather_recursive_deps(void)
322 {
323 	Name_set::iterator	np, e;
324 	String_rec		rec;
325 	wchar_t			rec_buf[STRING_BUFFER_LENGTH];
326 	register Property	lines;
327 	Boolean			has_recursive;
328 	Dependency		dp;
329 
330 	report_recursive_init();
331 
332 	/* Go thru all targets and dump recursive dependencies */
333 	for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
334 		if (np->has_recursive_dependency){
335 			has_recursive = false;
336 			/*
337 			 * start .RECURSIVE line with target:
338 			 */
339 			INIT_STRING_FROM_STACK(rec, rec_buf);
340 			APPEND_NAME(np, &rec, FIND_LENGTH);
341 			append_char((int) colon_char, &rec);
342 			append_char((int) space_char, &rec);
343 
344 			for (lines = get_prop(np->prop,recursive_prop);
345 			    lines != NULL;
346 			    lines = get_prop(lines->next, recursive_prop)) {
347 				/*
348 				 * if entry is already in depinfo
349 				 * file or entry was not built, ignore it
350 				 */
351 				if (lines->body.recursive.in_depinfo)
352 					continue;
353 				if (!lines->body.recursive.has_built)
354 					continue;
355 				has_recursive = true;
356 				lines->body.recursive.in_depinfo=true;
357 
358 				/*
359 				* Write the remainder of the
360 				* .RECURSIVE line
361 				*/
362 				APPEND_NAME(recursive_name, &rec,
363 				    FIND_LENGTH);
364 				append_char((int) space_char, &rec);
365 				APPEND_NAME(lines->body.recursive.directory,
366 					&rec, FIND_LENGTH);
367 				append_char((int) space_char, &rec);
368 				APPEND_NAME(lines->body.recursive.target,
369 					&rec, FIND_LENGTH);
370 				append_char((int) space_char, &rec);
371 
372 				/* Complete list of makefiles used */
373 				for (dp = lines->body.recursive.makefiles;
374 				    dp != NULL;
375 				    dp = dp->next) {
376 					APPEND_NAME(dp->name, &rec,  FIND_LENGTH);
377 					append_char((int) space_char, &rec);
378 				}
379 			}
380 			/*
381 			 * dump list of conditional targets,
382 			 * and report recursive entry, if needed
383 			 */
384 			cond_macros_into_string(np, &rec);
385 			if (has_recursive){
386 				report_recursive_dep(np, rec.buffer.start);
387 			}
388 
389 		} else if ( np->has_built ) {
390 			remove_recursive_dep(np);
391 		}
392 	}
393 }
394 
395