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.
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.
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]
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 * This file contains various unclassified routines. Some main groups:
34 * Error message handling
35 * Make internal state dumping
36 * main routine support
44 #include <mksh/macro.h> /* SETVAR() */
45 #include <mksh/misc.h> /* enable_interrupt() */
46 #include <stdarg.h> /* va_list, va_start(), va_end() */
47 #include <vroot/report.h> /* SUNPRO_DEPENDENCIES */
50 extern void job_adjust_fini();
65 * File table of contents
67 static void print_rule(register Name target
);
68 static void print_target_n_deps(register Name target
);
70 /*****************************************
75 /*****************************************
83 * frees a chain of Name_vector's
86 * ptr Pointer to the first element in the chain
89 * Global variables used:
92 free_chain(Name_vector ptr
)
95 if (ptr
->next
!= NULL
) {
96 free_chain(ptr
->next
);
102 /*****************************************
104 * String manipulation
107 /*****************************************
109 * Nameblock property handling
112 /*****************************************
114 * Error message handling
118 * fatal(format, args...)
120 * Print a message and die
123 * format printf type format string
124 * args Arguments to match the format
126 * Global variables used:
127 * fatal_in_progress Indicates if this is a recursive call
128 * parallel_process_cnt Do we need to wait for anything?
129 * report_pwd Should we report the current path?
133 fatal(const char *message
, ...)
137 va_start(args
, message
);
138 (void) fflush(stdout
);
139 (void) fprintf(stderr
, gettext("%s: Fatal error: "), getprogname());
140 (void) vfprintf(stderr
, message
, args
);
141 (void) fprintf(stderr
, "\n");
144 (void) fprintf(stderr
,
145 gettext("Current working directory %s\n"),
148 (void) fflush(stderr
);
149 if (fatal_in_progress
) {
153 fatal_in_progress
= true;
154 /* Let all parallel children finish */
155 if ((dmake_mode_type
== parallel_mode
) &&
156 (parallel_process_cnt
> 0)) {
157 (void) fprintf(stderr
,
158 gettext("Waiting for %d %s to finish\n"),
159 parallel_process_cnt
,
160 parallel_process_cnt
== 1 ?
161 gettext("job") : gettext("jobs"));
162 (void) fflush(stderr
);
165 while (parallel_process_cnt
> 0) {
166 await_parallel(true);
167 finish_children(false);
177 * warning(format, args...)
179 * Print a message and continue.
182 * format printf type format string
183 * args Arguments to match the format
185 * Global variables used:
186 * report_pwd Should we report the current path?
190 warning(char * message
, ...)
194 va_start(args
, message
);
195 (void) fflush(stdout
);
196 (void) fprintf(stderr
, gettext("%s: Warning: "), getprogname());
197 (void) vfprintf(stderr
, message
, args
);
198 (void) fprintf(stderr
, "\n");
201 (void) fprintf(stderr
,
202 gettext("Current working directory %s\n"),
205 (void) fflush(stderr
);
209 * time_to_string(time)
211 * Take a numeric time value and produce
212 * a proper string representation.
215 * The string representation of the time
218 * time The time we need to translate
220 * Global variables used:
223 time_to_string(const timestruc_t
&time
)
228 if (time
== file_doesnt_exist
) {
229 return gettext("File does not exist");
231 if (time
== file_max_time
) {
232 return gettext("Younger than any file");
234 tm
= localtime(&time
.tv_sec
);
235 strftime(buf
, sizeof (buf
), "%c %Z", tm
);
236 buf
[127] = (int) nul_char
;
243 * Stuff current_path with the current path if it isnt there already.
247 * Global variables used:
250 get_current_path(void)
252 char pwd
[(MAXPATHLEN
* MB_LEN_MAX
)];
253 static char *current_path
;
255 if (current_path
== NULL
) {
256 getcwd(pwd
, sizeof(pwd
));
257 if (pwd
[0] == (int) nul_char
) {
258 pwd
[0] = (int) slash_char
;
259 pwd
[1] = (int) nul_char
;
261 current_path
= strdup(pwd
);
266 /*****************************************
268 * Make internal state dumping
270 * This is a set of routines for dumping the internal make state
271 * Used for the -p option
277 * Dump make's internal state to stdout
281 * Global variables used:
282 * svr4 Was ".SVR4" seen in makefile?
283 * svr4_name The Name ".SVR4", printed
284 * posix Was ".POSIX" seen in makefile?
285 * posix_name The Name ".POSIX", printed
286 * default_rule Points to the .DEFAULT rule
287 * default_rule_name The Name ".DEFAULT", printed
288 * default_target_to_build The first target to print
289 * dot_keep_state The Name ".KEEP_STATE", printed
290 * dot_keep_state_file The Name ".KEEP_STATE_FILE", printed
291 * hashtab The make hash table for Name blocks
292 * ignore_errors Was ".IGNORE" seen in makefile?
293 * ignore_name The Name ".IGNORE", printed
294 * keep_state Was ".KEEP_STATE" seen in makefile?
295 * percent_list The list of % rules
296 * precious The Name ".PRECIOUS", printed
297 * sccs_get_name The Name ".SCCS_GET", printed
298 * sccs_get_posix_name The Name ".SCCS_GET_POSIX", printed
299 * get_name The Name ".GET", printed
300 * get_posix_name The Name ".GET_POSIX", printed
301 * sccs_get_rule Points to the ".SCCS_GET" rule
302 * silent Was ".SILENT" seen in makefile?
303 * silent_name The Name ".SILENT", printed
304 * suffixes The suffix list from ".SUFFIXES"
305 * suffixes_name The Name ".SUFFIX", printed
308 dump_make_state(void)
310 Name_set::iterator p
, e
;
311 register Property prop
;
312 register Dependency dep
;
313 register Cmd_line rule
;
314 Percent percent
, percent_depe
;
317 if (default_target_to_build
!= NULL
) {
318 print_rule(default_target_to_build
);
324 (void) printf("%s:\n", posix_name
->string_mb
);
328 if (default_rule
!= NULL
) {
329 (void) printf("%s:\n", default_rule_name
->string_mb
);
330 for (rule
= default_rule
; rule
!= NULL
; rule
= rule
->next
) {
331 (void) printf("\t%s\n", rule
->command_line
->string_mb
);
337 (void) printf("%s:\n", ignore_name
->string_mb
);
342 (void) printf("%s:\n\n", dot_keep_state
->string_mb
);
346 (void) printf("%s:", precious
->string_mb
);
347 for (p
= hashtab
.begin(), e
= hashtab
.end(); p
!= e
; p
++) {
348 if ((p
->stat
.is_precious
) || (all_precious
)) {
349 (void) printf(" %s", p
->string_mb
);
355 if (sccs_get_rule
!= NULL
) {
356 (void) printf("%s:\n", sccs_get_name
->string_mb
);
357 for (rule
= sccs_get_rule
; rule
!= NULL
; rule
= rule
->next
) {
358 (void) printf("\t%s\n", rule
->command_line
->string_mb
);
364 (void) printf("%s:\n", silent_name
->string_mb
);
368 (void) printf("%s:", suffixes_name
->string_mb
);
369 for (dep
= suffixes
; dep
!= NULL
; dep
= dep
->next
) {
370 (void) printf(" %s", dep
->name
->string_mb
);
371 build_suffix_list(dep
->name
);
373 (void) printf("\n\n");
376 for (percent
= percent_list
;
378 percent
= percent
->next
) {
380 percent
->name
->string_mb
);
382 for (percent_depe
= percent
->dependencies
;
383 percent_depe
!= NULL
;
384 percent_depe
= percent_depe
->next
) {
385 (void) printf(" %s", percent_depe
->name
->string_mb
);
390 for (rule
= percent
->command_template
;
393 (void) printf("\t%s\n", rule
->command_line
->string_mb
);
398 for (p
= hashtab
.begin(), e
= hashtab
.end(); p
!= e
; p
++) {
400 if (wcb
.get_string()[0] == (int) period_char
) {
405 /* Macro assignments */
406 for (p
= hashtab
.begin(), e
= hashtab
.end(); p
!= e
; p
++) {
407 if (((prop
= get_prop(p
->prop
, macro_prop
)) != NULL
) &&
408 (prop
->body
.macro
.value
!= NULL
)) {
409 (void) printf("%s", p
->string_mb
);
410 print_value(prop
->body
.macro
.value
,
411 (Daemon
) prop
->body
.macro
.daemon
);
416 /* Conditional macro assignments */
417 for (p
= hashtab
.begin(), e
= hashtab
.end(); p
!= e
; p
++) {
418 for (prop
= get_prop(p
->prop
, conditional_prop
);
420 prop
= get_prop(prop
->next
, conditional_prop
)) {
421 (void) printf("%s := %s",
423 prop
->body
.conditional
.name
->
425 if (prop
->body
.conditional
.append
) {
431 print_value(prop
->body
.conditional
.value
,
437 /* All other dependencies */
438 for (p
= hashtab
.begin(), e
= hashtab
.end(); p
!= e
; p
++) {
439 if (p
->colons
!= no_colon
) {
449 * Print the rule for one target
452 * target Target we print rule for
454 * Global variables used:
457 print_rule(register Name target
)
459 register Cmd_line rule
;
460 register Property line
;
461 register Dependency dependency
;
463 if (target
->dependency_printed
||
464 ((line
= get_prop(target
->prop
, line_prop
)) == NULL
) ||
465 ((line
->body
.line
.command_template
== NULL
) &&
466 (line
->body
.line
.dependencies
== NULL
))) {
469 target
->dependency_printed
= true;
471 (void) printf("%s:", target
->string_mb
);
473 for (dependency
= line
->body
.line
.dependencies
;
475 dependency
= dependency
->next
) {
476 (void) printf(" %s", dependency
->name
->string_mb
);
481 for (rule
= line
->body
.line
.command_template
;
484 (void) printf("\t%s\n", rule
->command_line
->string_mb
);
489 dump_target_list(void)
491 Name_set::iterator p
, e
;
494 for (p
= hashtab
.begin(), e
= hashtab
.end(); p
!= e
; p
++) {
496 wchar_t * wcb
= str
.get_string();
497 if ((p
->colons
!= no_colon
) &&
498 ((wcb
[0] != (int) period_char
) ||
499 ((wcb
[0] == (int) period_char
) &&
500 (wcschr(wcb
, (int) slash_char
))))) {
501 print_target_n_deps(p
);
507 print_target_n_deps(register Name target
)
509 register Cmd_line rule
;
510 register Property line
;
511 register Dependency dependency
;
513 if (target
->dependency_printed
) {
516 target
->dependency_printed
= true;
518 (void) printf("%s\n", target
->string_mb
);
520 if ((line
= get_prop(target
->prop
, line_prop
)) == NULL
) {
523 for (dependency
= line
->body
.line
.dependencies
;
525 dependency
= dependency
->next
) {
526 if (!dependency
->automatic
) {
527 print_target_n_deps(dependency
->name
);
532 /*****************************************
538 * load_cached_names()
540 * Load the vector of cached names
544 * Global variables used:
545 * Many many pointers to Name blocks.
548 load_cached_names(void)
553 /* Load the cached_names struct */
554 MBSTOWCS(wcs_buffer
, ".BUILT_LAST_MAKE_RUN");
555 built_last_make_run
= GETNAME(wcs_buffer
, FIND_LENGTH
);
556 MBSTOWCS(wcs_buffer
, "@");
557 c_at
= GETNAME(wcs_buffer
, FIND_LENGTH
);
558 MBSTOWCS(wcs_buffer
, " *conditionals* ");
559 conditionals
= GETNAME(wcs_buffer
, FIND_LENGTH
);
561 * A version of make was released with NSE 1.0 that used
562 * VERSION-1.1 but this version is identical to VERSION-1.0.
563 * The version mismatch code makes a special case for this
564 * situation. If the version number is changed from 1.0
565 * it should go to 1.2.
567 MBSTOWCS(wcs_buffer
, "VERSION-1.0");
568 current_make_version
= GETNAME(wcs_buffer
, FIND_LENGTH
);
569 MBSTOWCS(wcs_buffer
, ".SVR4");
570 svr4_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
571 MBSTOWCS(wcs_buffer
, ".POSIX");
572 posix_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
573 MBSTOWCS(wcs_buffer
, ".DEFAULT");
574 default_rule_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
575 MBSTOWCS(wcs_buffer
, "$");
576 dollar
= GETNAME(wcs_buffer
, FIND_LENGTH
);
577 MBSTOWCS(wcs_buffer
, ".DONE");
578 done
= GETNAME(wcs_buffer
, FIND_LENGTH
);
579 MBSTOWCS(wcs_buffer
, ".");
580 dot
= GETNAME(wcs_buffer
, FIND_LENGTH
);
581 MBSTOWCS(wcs_buffer
, ".KEEP_STATE");
582 dot_keep_state
= GETNAME(wcs_buffer
, FIND_LENGTH
);
583 MBSTOWCS(wcs_buffer
, ".KEEP_STATE_FILE");
584 dot_keep_state_file
= GETNAME(wcs_buffer
, FIND_LENGTH
);
585 MBSTOWCS(wcs_buffer
, "");
586 empty_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
587 MBSTOWCS(wcs_buffer
, " FORCE");
588 force
= GETNAME(wcs_buffer
, FIND_LENGTH
);
589 MBSTOWCS(wcs_buffer
, "HOST_ARCH");
590 host_arch
= GETNAME(wcs_buffer
, FIND_LENGTH
);
591 MBSTOWCS(wcs_buffer
, "HOST_MACH");
592 host_mach
= GETNAME(wcs_buffer
, FIND_LENGTH
);
593 MBSTOWCS(wcs_buffer
, ".IGNORE");
594 ignore_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
595 MBSTOWCS(wcs_buffer
, ".INIT");
596 init
= GETNAME(wcs_buffer
, FIND_LENGTH
);
597 MBSTOWCS(wcs_buffer
, ".LOCAL");
598 localhost_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
599 MBSTOWCS(wcs_buffer
, ".make.state");
600 make_state
= GETNAME(wcs_buffer
, FIND_LENGTH
);
601 MBSTOWCS(wcs_buffer
, "MAKEFLAGS");
602 makeflags
= GETNAME(wcs_buffer
, FIND_LENGTH
);
603 MBSTOWCS(wcs_buffer
, ".MAKE_VERSION");
604 make_version
= GETNAME(wcs_buffer
, FIND_LENGTH
);
605 MBSTOWCS(wcs_buffer
, ".NO_PARALLEL");
606 no_parallel_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
607 MBSTOWCS(wcs_buffer
, ".NOT_AUTO");
608 not_auto
= GETNAME(wcs_buffer
, FIND_LENGTH
);
609 MBSTOWCS(wcs_buffer
, ".PARALLEL");
610 parallel_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
611 MBSTOWCS(wcs_buffer
, "PATH");
612 path_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
613 MBSTOWCS(wcs_buffer
, "+");
614 plus
= GETNAME(wcs_buffer
, FIND_LENGTH
);
615 MBSTOWCS(wcs_buffer
, ".PRECIOUS");
616 precious
= GETNAME(wcs_buffer
, FIND_LENGTH
);
617 MBSTOWCS(wcs_buffer
, "?");
618 query
= GETNAME(wcs_buffer
, FIND_LENGTH
);
619 MBSTOWCS(wcs_buffer
, "^");
620 hat
= GETNAME(wcs_buffer
, FIND_LENGTH
);
621 MBSTOWCS(wcs_buffer
, ".RECURSIVE");
622 recursive_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
623 MBSTOWCS(wcs_buffer
, ".SCCS_GET");
624 sccs_get_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
625 MBSTOWCS(wcs_buffer
, ".SCCS_GET_POSIX");
626 sccs_get_posix_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
627 MBSTOWCS(wcs_buffer
, ".GET");
628 get_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
629 MBSTOWCS(wcs_buffer
, ".GET_POSIX");
630 get_posix_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
631 MBSTOWCS(wcs_buffer
, "SHELL");
632 shell_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
633 MBSTOWCS(wcs_buffer
, ".SILENT");
634 silent_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
635 MBSTOWCS(wcs_buffer
, ".SUFFIXES");
636 suffixes_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
637 MBSTOWCS(wcs_buffer
, SUNPRO_DEPENDENCIES
);
638 sunpro_dependencies
= GETNAME(wcs_buffer
, FIND_LENGTH
);
639 MBSTOWCS(wcs_buffer
, "TARGET_ARCH");
640 target_arch
= GETNAME(wcs_buffer
, FIND_LENGTH
);
641 MBSTOWCS(wcs_buffer
, "TARGET_MACH");
642 target_mach
= GETNAME(wcs_buffer
, FIND_LENGTH
);
643 MBSTOWCS(wcs_buffer
, "VIRTUAL_ROOT");
644 virtual_root
= GETNAME(wcs_buffer
, FIND_LENGTH
);
645 MBSTOWCS(wcs_buffer
, "VPATH");
646 vpath_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
647 MBSTOWCS(wcs_buffer
, ".WAIT");
648 wait_name
= GETNAME(wcs_buffer
, FIND_LENGTH
);
650 wait_name
->state
= build_ok
;
652 /* Mark special targets so that the reader treats them properly */
653 svr4_name
->special_reader
= svr4_special
;
654 posix_name
->special_reader
= posix_special
;
655 built_last_make_run
->special_reader
= built_last_make_run_special
;
656 default_rule_name
->special_reader
= default_special
;
657 dot_keep_state
->special_reader
= keep_state_special
;
658 dot_keep_state_file
->special_reader
= keep_state_file_special
;
659 ignore_name
->special_reader
= ignore_special
;
660 make_version
->special_reader
= make_version_special
;
661 no_parallel_name
->special_reader
= no_parallel_special
;
662 parallel_name
->special_reader
= parallel_special
;
663 localhost_name
->special_reader
= localhost_special
;
664 precious
->special_reader
= precious_special
;
665 sccs_get_name
->special_reader
= sccs_get_special
;
666 sccs_get_posix_name
->special_reader
= sccs_get_posix_special
;
667 get_name
->special_reader
= get_special
;
668 get_posix_name
->special_reader
= get_posix_special
;
669 silent_name
->special_reader
= silent_special
;
670 suffixes_name
->special_reader
= suffixes_special
;
672 /* The value of $$ is $ */
673 (void) SETVAR(dollar
, dollar
, false);
674 dollar
->dollar
= false;
676 /* Set the value of $(SHELL) */
678 MBSTOWCS(wcs_buffer
, "/usr/xpg4/bin/sh");
680 MBSTOWCS(wcs_buffer
, "/bin/sh");
682 (void) SETVAR(shell_name
, GETNAME(wcs_buffer
, FIND_LENGTH
), false);
685 * Use " FORCE" to simulate a FRC dependency for :: type
686 * targets with no dependencies.
688 (void) append_prop(force
, line_prop
);
689 force
->stat
.time
= file_max_time
;
691 /* Make sure VPATH is defined before current dir is read */
692 if ((cp
= getenv(vpath_name
->string_mb
)) != NULL
) {
693 MBSTOWCS(wcs_buffer
, cp
);
694 (void) SETVAR(vpath_name
,
695 GETNAME(wcs_buffer
, FIND_LENGTH
),
699 /* Check if there is NO PATH variable. If not we construct one. */
700 if (getenv(path_name
->string_mb
) == NULL
) {
702 add_dir_to_path(".", &vroot_path
, -1);
703 add_dir_to_path("/bin", &vroot_path
, -1);
704 add_dir_to_path("/usr/bin", &vroot_path
, -1);
709 * iterate on list of conditional macros in np, and place them in
710 * a String_rec starting with, and separated by the '$' character.
713 cond_macros_into_string(Name np
, String_rec
*buffer
)
715 Macro_list macro_list
;
718 * Put the version number at the start of the string
720 MBSTOWCS(wcs_buffer
, DEPINFO_FMT_VERSION
);
721 append_string(wcs_buffer
, buffer
, FIND_LENGTH
);
723 * Add the rest of the conditional macros to the buffer
725 if (np
->depends_on_conditional
){
726 for (macro_list
= np
->conditional_macro_list
;
727 macro_list
!= NULL
; macro_list
= macro_list
->next
){
728 append_string(macro_list
->macro_name
, buffer
,
730 append_char((int) equal_char
, buffer
);
731 append_string(macro_list
->value
, buffer
, FIND_LENGTH
);
732 append_char((int) dollar_char
, buffer
);