libcpp: Provide date routine
authorNathan Sidwell <nathan@acm.org>
Fri, 6 Nov 2020 16:53:31 +0000 (08:53 -0800)
committerNathan Sidwell <nathan@acm.org>
Fri, 6 Nov 2020 16:59:20 +0000 (08:59 -0800)
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.

libcpp/include/cpplib.h
libcpp/init.c
libcpp/internal.h
libcpp/macro.c

index 8e398863cf6e8695b21b3d7eea708d114b82ec64..c4d7cc520d1d8741b0ed33f31b93c9de5942206a 100644 (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);
 
index 6c52f50de398b0990abcb695ac474d7b91b01a29..dcf1d4be58724bd452aa67d3b77d5a74fe0212d8 100644 (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);
index 4759961a33a57f2d76573688653950dff87e3a6e..d7780e49d275f4eb4c6eca5e07e10ecd8890879e 100644 (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;
index e304f67c2e06f5b1c9f192861038ad200090d980..e2cb89e4c4379708234bff98c71edda71fa53505 100644 (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);
-         else
+         if (kind == CPP_time_kind::UNKNOWN)
            {
-             /* (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);
+             cpp_errno (pfile, CPP_DL_WARNING,
+                        "could not determine date and time");
+               
+             pfile->date = UC"\"??? ?? ????\"";
+             pfile->time = UC"\"??:??:??\"";
            }
-
-         if (tb)
+         else
            {
+             struct tm *tb = (kind == CPP_time_kind::FIXED
+                              ? gmtime : localtime) (&tt);
+
              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