mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-21 15:50:50 +08:00
libcpp: Provide date routine
Joseph pointed me at cb_get_source_date_epoch, which allows repeatable builds and solves a FIXME I had on the modules branch. Unfortunately it's used exclusively to generate __DATE__ and __TIME__ values, which fallback to using a time(2) call. It'd be nicer if the preprocessor made whatever time value it determined available to the rest of the compiler. So this patch adds a new cpp_get_date function, which abstracts the call to the get_source_date_epoch hook, or uses time directly. The value is cached. Thus the timestamp I end up putting on CMI files matches __DATE__ and __TIME__ expansions. That seems worthwhile. libcpp/ * include/cpplib.h (enum class CPP_time_kind): New. (cpp_get_date): Declare. * internal.h (struct cpp_reader): Replace source_date_epoch with time_stamp and time_stamp_kind. * init.c (cpp_create_reader): Initialize them. * macro.c (_cpp_builtin_macro_text): Use cpp_get_date. (cpp_get_date): Broken out from _cpp_builtin_macro_text and genericized.
This commit is contained in:
parent
6c3ce63b04
commit
4b5f564a5d
@ -1040,6 +1040,15 @@ inline location_t cpp_macro_definition_location (cpp_hashnode *node)
|
||||
{
|
||||
return node->value.macro->line;
|
||||
}
|
||||
/* Return an idempotent time stamp (possibly from SOURCE_DATE_EPOCH). */
|
||||
enum class CPP_time_kind
|
||||
{
|
||||
FIXED = -1, /* Fixed time via source epoch. */
|
||||
DYNAMIC = -2, /* Dynamic via time(2). */
|
||||
UNKNOWN = -3 /* Wibbly wobbly, timey wimey. */
|
||||
};
|
||||
extern CPP_time_kind cpp_get_date (cpp_reader *, time_t *);
|
||||
|
||||
extern void _cpp_backup_tokens (cpp_reader *, unsigned int);
|
||||
extern const cpp_token *cpp_peek_token (cpp_reader *, int);
|
||||
|
||||
|
@ -273,8 +273,9 @@ cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
|
||||
/* Do not force token locations by default. */
|
||||
pfile->forced_token_location = 0;
|
||||
|
||||
/* Initialize source_date_epoch to -2 (not yet set). */
|
||||
pfile->source_date_epoch = (time_t) -2;
|
||||
/* Note the timestamp is unset. */
|
||||
pfile->time_stamp = time_t (-1);
|
||||
pfile->time_stamp_kind = 0;
|
||||
|
||||
/* The expression parser stack. */
|
||||
_cpp_expand_op_stack (pfile);
|
||||
|
@ -512,10 +512,9 @@ struct cpp_reader
|
||||
const unsigned char *date;
|
||||
const unsigned char *time;
|
||||
|
||||
/* Externally set timestamp to replace current date and time useful for
|
||||
reproducibility. It should be initialized to -2 (not yet set) and
|
||||
set to -1 to disable it or to a non-negative value to enable it. */
|
||||
time_t source_date_epoch;
|
||||
/* Time stamp, set idempotently lazily. */
|
||||
time_t time_stamp;
|
||||
int time_stamp_kind; /* Or errno. */
|
||||
|
||||
/* A token forcing paste avoidance, and one demarking macro arguments. */
|
||||
cpp_token avoid_paste;
|
||||
|
@ -606,29 +606,21 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
|
||||
at init time, because time() and localtime() are very
|
||||
slow on some systems. */
|
||||
time_t tt;
|
||||
struct tm *tb = NULL;
|
||||
auto kind = cpp_get_date (pfile, &tt);
|
||||
|
||||
/* Set a reproducible timestamp for __DATE__ and __TIME__ macro
|
||||
if SOURCE_DATE_EPOCH is defined. */
|
||||
if (pfile->source_date_epoch == (time_t) -2
|
||||
&& pfile->cb.get_source_date_epoch != NULL)
|
||||
pfile->source_date_epoch = pfile->cb.get_source_date_epoch (pfile);
|
||||
|
||||
if (pfile->source_date_epoch >= (time_t) 0)
|
||||
tb = gmtime (&pfile->source_date_epoch);
|
||||
if (kind == CPP_time_kind::UNKNOWN)
|
||||
{
|
||||
cpp_errno (pfile, CPP_DL_WARNING,
|
||||
"could not determine date and time");
|
||||
|
||||
pfile->date = UC"\"??? ?? ????\"";
|
||||
pfile->time = UC"\"??:??:??\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (time_t) -1 is a legitimate value for "number of seconds
|
||||
since the Epoch", so we have to do a little dance to
|
||||
distinguish that from a genuine error. */
|
||||
errno = 0;
|
||||
tt = time (NULL);
|
||||
if (tt != (time_t)-1 || errno == 0)
|
||||
tb = localtime (&tt);
|
||||
}
|
||||
struct tm *tb = (kind == CPP_time_kind::FIXED
|
||||
? gmtime : localtime) (&tt);
|
||||
|
||||
if (tb)
|
||||
{
|
||||
pfile->date = _cpp_unaligned_alloc (pfile,
|
||||
sizeof ("\"Oct 11 1347\""));
|
||||
sprintf ((char *) pfile->date, "\"%s %2d %4d\"",
|
||||
@ -640,14 +632,6 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
|
||||
sprintf ((char *) pfile->time, "\"%02d:%02d:%02d\"",
|
||||
tb->tm_hour, tb->tm_min, tb->tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpp_errno (pfile, CPP_DL_WARNING,
|
||||
"could not determine date and time");
|
||||
|
||||
pfile->date = UC"\"??? ?? ????\"";
|
||||
pfile->time = UC"\"??:??:??\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (node->value.builtin == BT_DATE)
|
||||
@ -688,6 +672,51 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Get an idempotent date. Either the cached value, the value from
|
||||
source epoch, or failing that, the value from time(2). Use this
|
||||
during compilation so that every time stamp is the same. */
|
||||
CPP_time_kind
|
||||
cpp_get_date (cpp_reader *pfile, time_t *result)
|
||||
{
|
||||
if (!pfile->time_stamp_kind)
|
||||
{
|
||||
int kind = 0;
|
||||
if (pfile->cb.get_source_date_epoch)
|
||||
{
|
||||
/* Try reading the fixed epoch. */
|
||||
pfile->time_stamp = pfile->cb.get_source_date_epoch (pfile);
|
||||
if (pfile->time_stamp != time_t (-1))
|
||||
kind = int (CPP_time_kind::FIXED);
|
||||
}
|
||||
|
||||
if (!kind)
|
||||
{
|
||||
/* Pedantically time_t (-1) is a legitimate value for
|
||||
"number of seconds since the Epoch". It is a silly
|
||||
time. */
|
||||
errno = 0;
|
||||
pfile->time_stamp = time (nullptr);
|
||||
/* Annoyingly a library could legally set errno and return a
|
||||
valid time! Bad library! */
|
||||
if (pfile->time_stamp == time_t (-1) && errno)
|
||||
kind = errno;
|
||||
else
|
||||
kind = int (CPP_time_kind::DYNAMIC);
|
||||
}
|
||||
|
||||
pfile->time_stamp_kind = kind;
|
||||
}
|
||||
|
||||
*result = pfile->time_stamp;
|
||||
if (pfile->time_stamp_kind >= 0)
|
||||
{
|
||||
errno = pfile->time_stamp_kind;
|
||||
return CPP_time_kind::UNKNOWN;
|
||||
}
|
||||
|
||||
return CPP_time_kind (pfile->time_stamp_kind);
|
||||
}
|
||||
|
||||
/* Convert builtin macros like __FILE__ to a token and push it on the
|
||||
context stack. Also handles _Pragma, for which a new token may not
|
||||
be created. Returns 1 if it generates a new token context, 0 to
|
||||
|
Loading…
x
Reference in New Issue
Block a user