diff options
author | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
---|---|---|
committer | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
commit | e0463df9c3d2ee6155221cc443c571d5da47098a (patch) | |
tree | 5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/nse.cc | |
download | sunmake-orig.tar.gz |
Initial import of DevPro make sourcesorig
Downloaded from http://dlc.sun.com/osol/devpro/downloads/current/
Licensed under CDDL http://www.opensource.org/licenses/CDDL-1.0
Diffstat (limited to 'usr/src/make_src/Make/bin/make/common/nse.cc')
-rw-r--r-- | usr/src/make_src/Make/bin/make/common/nse.cc | 610 |
1 files changed, 610 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/nse.cc b/usr/src/make_src/Make/bin/make/common/nse.cc new file mode 100644 index 0000000..4cc75e4 --- /dev/null +++ b/usr/src/make_src/Make/bin/make/common/nse.cc @@ -0,0 +1,610 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1994 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)nse.cc 1.15 06/12/12 + */ + +#pragma ident "@(#)nse.cc 1.15 06/12/12" + +#ifdef NSE + +/* + * Included files + */ +#include <mk/defs.h> +#include <mksh/macro.h> /* expand_value() */ +#include <mksh/misc.h> /* get_prop() */ + +/* + * This file does some extra checking on behalf of the NSE. + * It does some stuff that is analogous to lint in that it + * looks for things which may be legal but that give the NSE + * trouble. Currently it looks for: + * 1) recursion by cd'ing to a directory specified by a + * make variable that is defined from the shell environment. + * 2) recursion by cd'ing to a directory specified by a + * make variable that has backquotes in it. + * 3) recursion to another makefile in the same directory. + * 4) a dependency upon an SCCS file (SCCS/s.*) + * 5) backquotes in a file name + * 6) a make variable being defined on the command-line that + * ends up affecting dependencies + * 7) wildcards (*[) in dependencies + * 8) recursion to the same directory + * 9) potential source files on the left-hand-side so + * that they appear as derived files + * + * Things it should look for: + * 1) makefiles that are symlinks (why are these a problem?) + */ + +#define TARG_SUFX "/usr/nse/lib/nse_targ.sufx" + +typedef struct _Nse_suffix *Nse_suffix, Nse_suffix_rec; +struct _Nse_suffix { + wchar_t *suffix; /* The suffix */ + struct _Nse_suffix *next; /* Linked list */ +}; +static Nse_suffix sufx_hdr; +static int our_exit_status; + +static void nse_warning(void); +static Boolean nse_gettoken(wchar_t **, wchar_t *); + +/* + * Given a command that has just recursed to a sub make + * try to determine if it cd'ed to a directory that was + * defined by a make variable imported from the shell + * environment or a variable with backquotes in it. + * This routine will find something like: + * cd $(DIR); $(MAKE) + * where DIR is imported from the shell environment. + * However it well not find: + * CD = cd + * $(CD) $(DIR); $(MAKE) + * or + * CD = cd $(DIR) + * $(CD); $(MAKE) + * + * This routine also checks for recursion to the same + * directory. + */ +void +nse_check_cd(Property prop) +{ + wchar_t tok[512]; + wchar_t *p; + wchar_t *our_template; + int len; + Boolean cd; +#ifdef SUNOS4_AND_AFTER + String_rec string; +#else + String string; +#endif + Name name; + Name target; + struct Line *line; + struct Recursive *r; + Property recurse; + wchar_t strbuf[STRING_BUFFER_LENGTH]; + wchar_t tmpbuf[STRING_BUFFER_LENGTH]; + +#ifdef LTEST + printf("In nse_check_cd, nse = %d, nse_did_recursion = %d\n", nse, nse_did_recursion); +#endif +#ifdef SUNOS4_AND_AFTER + if (!nse_did_recursion || !nse) { +#else + if (is_false(nse_did_recursion) || is_false(flag.nse)) { +#endif +#ifdef LTEST + printf ("returning, nse = %d, nse_did_recursion = %d\n", nse, nse_did_recursion); +#endif + return; + } + line = &prop->body.line; +#ifdef LTEST + printf("string = %s\n", line->command_template->command_line->string_mb); +#endif + + wscpy(tmpbuf, line->command_template->command_line->string); + our_template = tmpbuf; + cd = false; + while (nse_gettoken(&our_template, tok)) { +#ifdef LTEST + printf("in gettoken loop\n"); +#endif +#ifdef SUNOS4_AND_AFTER + if (IS_WEQUAL(tok, (wchar_t *) "cd")) { +#else + if (is_equal(tok, "cd")) { +#endif + cd = true; + } else if (cd && tok[0] == '$') { + nse_backquote_seen = NULL; + nse_shell_var_used = NULL; + nse_watch_vars = true; +#ifdef SUNOS4_AND_AFTER + INIT_STRING_FROM_STACK(string, strbuf); + name = GETNAME(tok, FIND_LENGTH); +#else + init_string_from_stack(string, strbuf); + name = getname(tok, FIND_LENGTH); +#endif + expand_value(name, &string, false); + nse_watch_vars = false; + +#ifdef LTEST + printf("cd = %d, tok = $\n", cd); +#endif + /* + * Try to trim tok to just + * the variable. + */ + if (nse_shell_var_used != NULL) { + nse_warning(); + fprintf(stderr, "\tMake invoked recursively by cd'ing to a directory\n\tdefined by the shell environment variable %s\n\tCommand line: %s\n", + nse_shell_var_used->string_mb, + line->command_template->command_line->string_mb); + } + if (nse_backquote_seen != NULL) { + nse_warning(); + fprintf(stderr, "\tMake invoked recursively by cd'ing to a directory\n\tdefined by a variable (%s) with backquotes in it\n\tCommand line: %s\n", + nse_backquote_seen->string_mb, + line->command_template->command_line->string_mb); + } + cd = false; + } else if (cd && nse_backquotes(tok)) { + nse_warning(); + fprintf(stderr, "\tMake invoked recursively by cd'ing to a directory\n\tspecified by a command in backquotes\n\tCommand line: %s\n", + line->command_template->command_line->string_mb); + cd = false; + } else { + cd = false; + } + } + + /* + * Now check for recursion to ".". + */ + if (primary_makefile != NULL) { + target = prop->body.line.target; + recurse = get_prop(target->prop, recursive_prop); + while (recurse != NULL) { + r = &recurse->body.recursive; +#ifdef SUNOS4_AND_AFTER + if (IS_WEQUAL(r->directory->string, (wchar_t *) ".") && + !IS_WEQUAL(r->makefiles->name->string, + primary_makefile->string)) { +#else + if (is_equal(r->directory->string, ".") && + !is_equal(r->makefiles->name->string, + primary_makefile->string)) { +#endif + nse_warning(); + fprintf(stderr, "\tRecursion to makefile `%s' in the same directory\n\tCommand line: %s\n", + r->makefiles->name->string_mb, + line->command_template->command_line->string_mb); + } + recurse = get_prop(recurse->next, recursive_prop); + } + } +} + +/* + * Print an NSE make warning line. + * If the -P flag was given then consider this a fatal + * error, otherwise, just a warning. + */ +static void +nse_warning(void) +{ +#ifdef SUNOS4_AND_AFTER + if (report_dependencies_level > 0) { +#else + if (is_true(flag.report_dependencies)) { +#endif + our_exit_status = 1; + } + if (primary_makefile != NULL) { + fprintf(stderr, "make: NSE warning from makefile %s/%s:\n", + get_current_path(), primary_makefile->string_mb); + } else { + fprintf(stderr, "make: NSE warning from directory %s:\n", + get_current_path()); + } +} + +/* + * Get the next whitespace delimited token pointed to by *cp. + * Return it in tok. + */ +static Boolean +nse_gettoken(wchar_t **cp, wchar_t *tok) +{ + wchar_t *to; + wchar_t *p; + + p = *cp; + while (*p && iswspace(*p)) { + p++; + } + if (*p == '\0') { + return false; + } + to = tok; + while (*p && !iswspace(*p)) { + *to++ = *p++; + } + if (*p == '\0') { + return false; + } + *to = '\0'; + *cp = p; + return true; +} + +/* + * Given a dependency and a target, see if the dependency + * is an SCCS file. Check for the last component of its name + * beginning with "s." and the component before that being "SCCS". + * The NSE does not consider a source file to be derived from + * an SCCS file. + */ +void +nse_check_sccs(wchar_t *targ, wchar_t *dep) +{ + wchar_t *slash; + wchar_t *p; + +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } +#ifdef SUNOS4_AND_AFTER + slash = wsrchr(dep, (int) slash_char); +#else + slash = rindex(dep, '/'); +#endif + if (slash == NULL) { + return; + } + if (slash[1] != 's' || slash[2] != '.') { + return; + } + + /* + * Find the next to last filename component. + */ + for (p = slash - 1; p >= dep; p--) { + if (*p == '/') { + break; + } + } + p++; +#ifdef SUNOS4_AND_AFTER + MBSTOWCS(wcs_buffer, "SCCS/"); + if (IS_WEQUALN(p, wcs_buffer, wslen(wcs_buffer))) { +#else + if (is_equaln(p, "SCCS/", 5)) { +#endif + nse_warning(); + WCSTOMBS(mbs_buffer, targ); + WCSTOMBS(mbs_buffer2, dep); + fprintf(stderr, "\tFile `%s' depends upon SCCS file `%s'\n", + mbs_buffer, mbs_buffer2); + } + return; +} + +/* + * Given a filename check to see if it has 2 backquotes in it. + * Complain about this because the shell expands the backquotes + * but make does not so the files always appear to be out of date. + */ +void +nse_check_file_backquotes(wchar_t *file) +{ +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } + if (nse_backquotes(file)) { + nse_warning(); + WCSTOMBS(mbs_buffer, file); + fprintf(stderr, "\tFilename \"%s\" has backquotes in it\n", + mbs_buffer); + } +} + +/* + * Return true if the string has two backquotes in it. + */ +Boolean +nse_backquotes(wchar_t *str) +{ + wchar_t *bq; + +#ifdef SUNOS4_AND_AFTER + bq = wschr(str, (int) backquote_char); + if (bq) { + bq = wschr(&bq[1], (int) backquote_char); +#else + bq = index(str, '`'); + if (bq) { + bq = index(&bq[1], '`'); +#endif + if (bq) { + return true; + } + } + return false; +} + +/* + * A macro that was defined on the command-line was found to affect the + * set of dependencies. The NSE "target explode" will not know about + * this and will not get the same set of dependencies. + */ +void +nse_dep_cmdmacro(wchar_t *macro) +{ +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } + nse_warning(); + WCSTOMBS(mbs_buffer, macro); + fprintf(stderr, "\tVariable `%s' is defined on the command-line and\n\taffects dependencies\n", + mbs_buffer); +} + +/* + * A macro that was defined on the command-line was found to + * be part of the argument to a cd before a recursive make. + * This make cause the make to recurse to different places + * depending upon how it is invoked. + */ +void +nse_rule_cmdmacro(wchar_t *macro) +{ +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } + nse_warning(); + WCSTOMBS(mbs_buffer, macro); + fprintf(stderr, "\tMake invoked recursively by cd'ing to a directory\n\tspecified by a variable (%s) defined on the command-line\n", + mbs_buffer); +} + +/* + * A dependency has been found with a wildcard in it. + * This causes the NSE problems because the set of dependencies + * can change without changing the Makefile. + */ +void +nse_wildcard(wchar_t *targ, wchar_t *dep) +{ +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } + nse_warning(); + WCSTOMBS(mbs_buffer, targ); + WCSTOMBS(mbs_buffer2, dep); + fprintf(stderr, "\tFile `%s' has a wildcard in dependency `%s'\n", + mbs_buffer, mbs_buffer2); +} + +/* + * Read in the list of suffixes that are interpreted as source + * files. + */ +void +nse_init_source_suffixes(void) +{ + FILE *fp; + wchar_t suffix[100]; + Nse_suffix sufx; + Nse_suffix *bpatch; + + fp = fopen(TARG_SUFX, "r"); + if (fp == NULL) { + return; + } + bpatch = &sufx_hdr; + while (fscanf(fp, "%s %*s", suffix) == 1) { +#ifdef SUNOS4_AND_AFTER + sufx = ALLOC(Nse_suffix); + sufx->suffix = wscpy(ALLOC_WC(wslen(suffix) + 1), suffix); +#else + sufx = alloc(Nse_suffix); + sufx->suffix = strcpy(malloc(strlen(suffix) + 1), suffix); +#endif + sufx->next = NULL; + *bpatch = sufx; + bpatch = &sufx->next; + } + fclose(fp); +} + +/* + * Check if a derived file (something with a dependency) appears + * to be a source file (by its suffix) but has no rule to build it. + * If so, complain. + * + * This generally arises from the old-style of make-depend that + * produces: + * foo.c: foo.h + */ +void +nse_check_derived_src(Name target, wchar_t *dep, Cmd_line command_template) +{ + Nse_suffix sufx; + wchar_t *suffix; + wchar_t *depsufx; + +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } +#ifdef SUNOS4_AND_AFTER + if (target->stat.is_derived_src) { +#else + if (is_true(target->stat.is_derived_src)) { +#endif + return; + } + if (command_template != NULL) { + return; + } +#ifdef SUNOS4_AND_AFTER + suffix = wsrchr(target->string, (int) period_char ); +#else + suffix = rindex(target->string, '.'); +#endif + if (suffix != NULL) { + for (sufx = sufx_hdr; sufx != NULL; sufx = sufx->next) { +#ifdef SUNOS4_AND_AFTER + if (IS_WEQUAL(sufx->suffix, suffix)) { +#else + if (is_equal(sufx->suffix, suffix)) { +#endif + nse_warning(); + WCSTOMBS(mbs_buffer, dep); + fprintf(stderr, "\tProbable source file `%s' appears as a derived file\n\tas it depends upon file `%s', but there is\n\tno rule to build it\n", + target->string_mb, mbs_buffer); + break; + } + } + } +} + +/* + * See if a target is a potential source file and has no + * dependencies and no rule but shows up on the right-hand + * side. This tends to occur from old "make depend" output. + */ +void +nse_check_no_deps_no_rule(Name target, Property line, Property command) +{ + Nse_suffix sufx; + wchar_t *suffix; + +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } +#ifdef SUNOS4_AND_AFTER + if (target->stat.is_derived_src) { +#else + if (is_true(target->stat.is_derived_src)) { +#endif + return; + } + if (line != NULL && line->body.line.dependencies != NULL) { + return; + } +#ifdef SUNOS4_AND_AFTER + if (command->body.line.sccs_command) { +#else + if (is_true(command->body.line.sccs_command)) { +#endif + return; + } +#ifdef SUNOS4_AND_AFTER + suffix = wsrchr(target->string, (int) period_char); +#else + suffix = rindex(target->string, '.'); +#endif + if (suffix != NULL) { + for (sufx = sufx_hdr; sufx != NULL; sufx = sufx->next) { +#ifdef SUNOS4_AND_AFTER + if (IS_WEQUAL(sufx->suffix, suffix)) { +#else + if (is_equal(sufx->suffix, suffix)) { +#endif + if (command->body.line.command_template == NULL) { + nse_warning(); + fprintf(stderr, "\tProbable source file `%s' appears as a derived file because\n\tit is on the left-hand side, but it has no dependencies and\n\tno rule to build it\n", + target->string_mb); + } + } + } + } +} + +/* + * Detected a situation where a recursive make derived a file + * without using a makefile. + */ +void +nse_no_makefile(Name target) +{ +#ifdef SUNOS4_AND_AFTER + if (!nse) { +#else + if (is_false(flag.nse)) { +#endif + return; + } + nse_warning(); + fprintf(stderr, "Recursive make to derive %s did not use a makefile\n", + target->string_mb); +} + +/* + * Return the NSE exit status. + * If the -P flag was given then a warning is considered fatal + */ +int +nse_exit_status(void) +{ + return our_exit_status; +} +#endif |