diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a0dd12a35fc..3ee3b4091ae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2000-06-30 Nathan Sidwell + + * cpp.texi: Document #pragma GCC dependency + * cppfiles.c (open_include_file): Set date to unknown. + (_cpp_compare_file_date): New function. + (read_include_file): Set file date. + * cpphash.h (struct include_file): Add date member. + (_cpp_compare_file_date): Prototype. + * cpplib.c (parse_include): Add trail parameter. Adjust. + (do_include): Adjust parse_include call. + (do_import): Likewise. + (do_include_next): Likewise. + (gcc_pragmas): Add dependency pragma. + (do_pragma_dependancy): New pragma. + 2000-06-29 Jason Merrill * dwarf2out.c (output_loc_operands): Don't abort on codes that have diff --git a/gcc/cpp.texi b/gcc/cpp.texi index 6413eec5420..47647025bcc 100644 --- a/gcc/cpp.texi +++ b/gcc/cpp.texi @@ -2664,6 +2664,20 @@ the text is ignored and this directive has no effect. Typically @samp{#ident} is only used in header files supplied with those systems where it is meaningful. +@findex #pragma GCC dependency +The @samp{#pragma GCC dependency} allows you to check the relative dates +of the current file and another file. If the other file is more +recent than the current file, a warning is issued. This is useful if the +include file is derived from the other file, and should be regenerated. +The other file is searched for using the normal include search path. +Optional trailing text can be used to give more information in the +warning message. + +@smallexample +#pragma GCC dependency "parse.y" +#pragma GCC dependency "/usr/include/time.h" rerun /path/to/fixincludes +@end smallexample + @node Output, Invocation, Other Directives, Top @section C Preprocessor Output diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index 35d1aa6b0ae..4e14aae102f 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -227,6 +227,7 @@ open_include_file (pfile, filename) } file->fd = fd; + file->date = (time_t) -1; return file; } @@ -465,6 +466,60 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start) cpp_error_from_errno (pfile, fname); } +/* Locate file F, and determine whether it is newer than PFILE. Return -1, + if F cannot be located or dated, 1, if it is newer and 0 if older. */ + +int +_cpp_compare_file_date (pfile, f, len, search_start) + cpp_reader *pfile; + U_CHAR *f; + unsigned int len; + struct file_name_list *search_start; +{ + char *fname = (char *)f; + int angle_brackets = fname[0] == '<'; + struct include_file *inc; + struct include_file *current_include = cpp_file_buffer (pfile)->inc; + + if (!search_start) + { + if (angle_brackets) + search_start = CPP_OPTION (pfile, bracket_include); + else if (CPP_OPTION (pfile, ignore_srcdir)) + search_start = CPP_OPTION (pfile, quote_include); + else + search_start = CPP_BUFFER (pfile)->actual_dir; + } + + /* Remove quote marks. */ + fname++; + len -= 2; + fname[len] = '\0'; + + inc = find_include_file (pfile, fname, search_start); + + if (!inc) + return -1; + if (inc->fd >= 0) + { + struct stat source; + + if (fstat (inc->fd, &source) < 0) + { + close (inc->fd); + inc->fd = -1; + return -1; + } + inc->date = source.st_mtime; + close (inc->fd); + inc->fd = -1; + } + if (inc->date == (time_t)-1 || current_include->date == (time_t)-1) + return -1; + return inc->date > current_include->date; +} + + /* Push an input buffer and load it up with the contents of FNAME. If FNAME is "" or NULL, read standard input. */ int @@ -502,6 +557,8 @@ read_include_file (pfile, inc) if (fstat (fd, &st) < 0) goto perror_fail; + + inc->date = st.st_mtime; /* If fd points to a plain file, we might be able to mmap it; we can definitely allocate the buffer all at once. If fd is a pipe or diff --git a/gcc/cpphash.h b/gcc/cpphash.h index f3e19d3ecca..ec9204a0e9e 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -64,6 +64,7 @@ struct include_file int fd; /* file descriptor possibly open on file */ unsigned short include_count; /* number of times file has been read */ unsigned short sysp; /* file is a system header */ + time_t date; /* modification date of file, if known */ }; /* The cmacro works like this: If it's NULL, the file is to be @@ -193,6 +194,9 @@ extern void _cpp_simplify_pathname PARAMS ((char *)); extern void _cpp_execute_include PARAMS ((cpp_reader *, U_CHAR *, unsigned int, int, struct file_name_list *)); +extern int _cpp_compare_file_date PARAMS ((cpp_reader *, U_CHAR *, + unsigned int, + struct file_name_list *)); extern void _cpp_init_include_table PARAMS ((cpp_reader *)); extern const char *_cpp_fake_include PARAMS ((cpp_reader *, const char *)); diff --git a/gcc/cpplib.c b/gcc/cpplib.c index f6cbd90932c..26396df8e29 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -52,7 +52,7 @@ struct if_stack /* Forward declarations. */ static void validate_else PARAMS ((cpp_reader *, const U_CHAR *)); -static unsigned int parse_include PARAMS ((cpp_reader *, const U_CHAR *)); +static unsigned int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int)); static void push_conditional PARAMS ((cpp_reader *, int, int, const cpp_hashnode *)); static void pass_thru_directive PARAMS ((const U_CHAR *, size_t, @@ -398,9 +398,10 @@ do_define (pfile) /* Handle #include and #import. */ static unsigned int -parse_include (pfile, name) +parse_include (pfile, name, trail) cpp_reader *pfile; const U_CHAR *name; + int trail; { long old_written = CPP_WRITTEN (pfile); enum cpp_ttype token; @@ -420,7 +421,7 @@ parse_include (pfile, name) return 0; } - if (_cpp_get_directive_token (pfile) != CPP_VSPACE) + if (!trail && _cpp_get_directive_token (pfile) != CPP_VSPACE) { cpp_error (pfile, "junk at end of #%s", name); _cpp_skip_rest_of_line (pfile); @@ -441,7 +442,7 @@ do_include (pfile) unsigned int len; U_CHAR *token; - len = parse_include (pfile, dtable[T_INCLUDE].name); + len = parse_include (pfile, dtable[T_INCLUDE].name, 0); if (len == 0) return 0; token = (U_CHAR *) alloca (len + 1); @@ -470,7 +471,7 @@ do_import (pfile) "#import is obsolete, use an #ifndef wrapper in the header file"); } - len = parse_include (pfile, dtable[T_IMPORT].name); + len = parse_include (pfile, dtable[T_IMPORT].name, 0); if (len == 0) return 0; token = (U_CHAR *) alloca (len + 1); @@ -492,7 +493,7 @@ do_include_next (pfile) U_CHAR *token; struct file_name_list *search_start = 0; - len = parse_include (pfile, dtable[T_INCLUDE_NEXT].name); + len = parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0); if (len == 0) return 0; token = (U_CHAR *) alloca (len + 1); @@ -803,6 +804,7 @@ static int do_pragma_poison PARAMS ((cpp_reader *)); static int do_pragma_system_header PARAMS ((cpp_reader *)); static int do_pragma_default PARAMS ((cpp_reader *)); static int do_pragma_gcc PARAMS ((cpp_reader *)); +static int do_pragma_dependency PARAMS ((cpp_reader *)); static const struct pragma_entry top_pragmas[] = { @@ -819,6 +821,7 @@ static const struct pragma_entry gcc_pragmas[] = {"implementation", do_pragma_implementation}, {"poison", do_pragma_poison}, {"system_header", do_pragma_system_header}, + {"dependency", do_pragma_dependency}, {NULL, do_pragma_default} }; @@ -1033,7 +1036,44 @@ do_pragma_system_header (pfile) return 1; } - + +/* Check the modified date of the current include file against a specified + file. Issue a diagnostic, if the specified file is newer. We use this to + determine if a fixed header should be refixed. */ +static int +do_pragma_dependency (pfile) + cpp_reader *pfile; +{ + U_CHAR *original_name, *name; + unsigned len; + int ordering; + + len = parse_include (pfile, (const U_CHAR *)"pragma dependency", 1); + original_name = (U_CHAR *) alloca (len + 1); + name = (U_CHAR *) alloca (len + 1); + memcpy (original_name, CPP_PWRITTEN (pfile), len); + memcpy (name, CPP_PWRITTEN (pfile), len); + original_name[len] = name[len] = 0; + + ordering = _cpp_compare_file_date (pfile, name, len, 0); + if (ordering < 0) + cpp_warning (pfile, "cannot find source %s", original_name); + else if (ordering > 0) + { + const U_CHAR *text, *limit; + _cpp_skip_hspace (pfile); + text = CPP_BUFFER (pfile)->cur; + _cpp_skip_rest_of_line (pfile); + limit = CPP_BUFFER (pfile)->cur; + + cpp_warning (pfile, "current file is older than %s", original_name); + if (limit != text) + cpp_warning (pfile, "%.*s", (int)(limit - text), text); + } + _cpp_skip_rest_of_line (pfile); + return 1; +} + /* Just ignore #sccs, on systems where we define it at all. */ #ifdef SCCS_DIRECTIVE static int