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:
Nathan Sidwell 2020-11-06 08:53:31 -08:00
parent 6c3ce63b04
commit 4b5f564a5d
4 changed files with 71 additions and 33 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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