Commit | Line | Data |
---|---|---|
aace9be8 MB |
1 | Make GCC respect SOURCE_DATE_EPOCH in __DATE__ and __TIME__ macros. |
2 | ||
3 | Cherry-picked from upstream commit: | |
4 | ||
5 | https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=e3e8c48c4a494d9da741c1c8ea6c4c0b7c4ff934 | |
6 | ||
7 | diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c | |
8 | index 6cf8c610b4e..b5daea65ba7 100644 | |
9 | --- a/gcc/c-family/c-common.c | |
10 | +++ b/gcc/c-family/c-common.c | |
11 | @@ -12750,4 +12750,37 @@ valid_array_size_p (location_t loc, tree type, tree name) | |
12 | return true; | |
13 | } | |
14 | ||
15 | +/* Read SOURCE_DATE_EPOCH from environment to have a deterministic | |
16 | + timestamp to replace embedded current dates to get reproducible | |
17 | + results. Returns -1 if SOURCE_DATE_EPOCH is not defined. */ | |
18 | +time_t | |
19 | +get_source_date_epoch () | |
20 | +{ | |
21 | + char *source_date_epoch; | |
22 | + long long epoch; | |
23 | + char *endptr; | |
24 | + | |
25 | + source_date_epoch = getenv ("SOURCE_DATE_EPOCH"); | |
26 | + if (!source_date_epoch) | |
27 | + return (time_t) -1; | |
28 | + | |
29 | + errno = 0; | |
30 | + epoch = strtoll (source_date_epoch, &endptr, 10); | |
31 | + if ((errno == ERANGE && (epoch == LLONG_MAX || epoch == LLONG_MIN)) | |
32 | + || (errno != 0 && epoch == 0)) | |
33 | + fatal_error (UNKNOWN_LOCATION, "environment variable $SOURCE_DATE_EPOCH: " | |
34 | + "strtoll: %s\n", xstrerror(errno)); | |
35 | + if (endptr == source_date_epoch) | |
36 | + fatal_error (UNKNOWN_LOCATION, "environment variable $SOURCE_DATE_EPOCH: " | |
37 | + "no digits were found: %s\n", endptr); | |
38 | + if (*endptr != '\0') | |
39 | + fatal_error (UNKNOWN_LOCATION, "environment variable $SOURCE_DATE_EPOCH: " | |
40 | + "trailing garbage: %s\n", endptr); | |
41 | + if (epoch < 0) | |
42 | + fatal_error (UNKNOWN_LOCATION, "environment variable $SOURCE_DATE_EPOCH: " | |
43 | + "value must be nonnegative: %lld \n", epoch); | |
44 | + | |
45 | + return (time_t) epoch; | |
46 | +} | |
47 | + | |
48 | #include "gt-c-family-c-common.h" | |
49 | diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h | |
50 | index dd74d0dd62e..c6e0ed12b55 100644 | |
51 | --- a/gcc/c-family/c-common.h | |
52 | +++ b/gcc/c-family/c-common.h | |
53 | @@ -1467,4 +1467,9 @@ extern bool reject_gcc_builtin (const_tree, location_t = UNKNOWN_LOCATION); | |
54 | extern void warn_duplicated_cond_add_or_warn (location_t, tree, vec<tree> **); | |
55 | extern bool valid_array_size_p (location_t, tree, tree); | |
56 | ||
57 | +/* Read SOURCE_DATE_EPOCH from environment to have a deterministic | |
58 | + timestamp to replace embedded current dates to get reproducible | |
59 | + results. Returns -1 if SOURCE_DATE_EPOCH is not defined. */ | |
60 | +extern time_t get_source_date_epoch (void); | |
61 | + | |
62 | #endif /* ! GCC_C_COMMON_H */ | |
63 | diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c | |
64 | index 96da4fc974e..bf1db6c0252 100644 | |
65 | --- a/gcc/c-family/c-lex.c | |
66 | +++ b/gcc/c-family/c-lex.c | |
67 | @@ -385,6 +385,9 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, | |
68 | enum cpp_ttype type; | |
69 | unsigned char add_flags = 0; | |
70 | enum overflow_type overflow = OT_NONE; | |
71 | + time_t source_date_epoch = get_source_date_epoch (); | |
72 | + | |
73 | + cpp_init_source_date_epoch (parse_in, source_date_epoch); | |
74 | ||
75 | timevar_push (TV_CPP); | |
76 | retry: | |
77 | diff --git a/gcc/doc/cppenv.texi b/gcc/doc/cppenv.texi | |
78 | index 22c8cb37624..e958e93e97e 100644 | |
79 | --- a/gcc/doc/cppenv.texi | |
80 | +++ b/gcc/doc/cppenv.texi | |
81 | @@ -79,4 +79,21 @@ main input file is omitted. | |
82 | @ifclear cppmanual | |
83 | @xref{Preprocessor Options}. | |
84 | @end ifclear | |
85 | + | |
86 | +@item SOURCE_DATE_EPOCH | |
87 | + | |
88 | +If this variable is set, its value specifies a UNIX timestamp to be | |
89 | +used in replacement of the current date and time in the @code{__DATE__} | |
90 | +and @code{__TIME__} macros, so that the embedded timestamps become | |
91 | +reproducible. | |
92 | + | |
93 | +The value of @env{SOURCE_DATE_EPOCH} must be a UNIX timestamp, | |
94 | +defined as the number of seconds (excluding leap seconds) since | |
95 | +01 Jan 1970 00:00:00 represented in ASCII, identical to the output of | |
96 | +@samp{@command{date +%s}}. | |
97 | + | |
98 | +The value should be a known timestamp such as the last modification | |
99 | +time of the source or package and it should be set by the build | |
100 | +process. | |
101 | + | |
102 | @end vtable | |
103 | diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h | |
104 | index 35b0375c09c..4998b3a8ab8 100644 | |
105 | --- a/libcpp/include/cpplib.h | |
106 | +++ b/libcpp/include/cpplib.h | |
107 | @@ -784,6 +784,9 @@ extern void cpp_init_special_builtins (cpp_reader *); | |
108 | /* Set up built-ins like __FILE__. */ | |
109 | extern void cpp_init_builtins (cpp_reader *, int); | |
110 | ||
111 | +/* Initialize the source_date_epoch value. */ | |
112 | +extern void cpp_init_source_date_epoch (cpp_reader *, time_t); | |
113 | + | |
114 | /* This is called after options have been parsed, and partially | |
115 | processed. */ | |
116 | extern void cpp_post_options (cpp_reader *); | |
117 | diff --git a/libcpp/init.c b/libcpp/init.c | |
118 | index 4343075ba85..f5ff85b3bae 100644 | |
119 | --- a/libcpp/init.c | |
120 | +++ b/libcpp/init.c | |
121 | @@ -533,8 +533,15 @@ cpp_init_builtins (cpp_reader *pfile, int hosted) | |
122 | _cpp_define_builtin (pfile, "__OBJC__ 1"); | |
123 | } | |
124 | ||
125 | +/* Initialize the source_date_epoch value. */ | |
126 | +void | |
127 | +cpp_init_source_date_epoch (cpp_reader *pfile, time_t source_date_epoch) | |
128 | +{ | |
129 | + pfile->source_date_epoch = source_date_epoch; | |
130 | +} | |
131 | + | |
132 | /* Sanity-checks are dependent on command-line options, so it is | |
133 | - called as a subroutine of cpp_read_main_file (). */ | |
134 | + called as a subroutine of cpp_read_main_file. */ | |
135 | #if CHECKING_P | |
136 | static void sanity_checks (cpp_reader *); | |
137 | static void sanity_checks (cpp_reader *pfile) | |
138 | diff --git a/libcpp/internal.h b/libcpp/internal.h | |
139 | index 9ce870738cc..e3eb26b1f27 100644 | |
140 | --- a/libcpp/internal.h | |
141 | +++ b/libcpp/internal.h | |
142 | @@ -502,6 +502,10 @@ struct cpp_reader | |
143 | const unsigned char *date; | |
144 | const unsigned char *time; | |
145 | ||
146 | + /* Externally set timestamp to replace current date and time useful for | |
147 | + reproducibility. */ | |
148 | + time_t source_date_epoch; | |
149 | + | |
150 | /* EOF token, and a token forcing paste avoidance. */ | |
151 | cpp_token avoid_paste; | |
152 | cpp_token eof; | |
153 | diff --git a/libcpp/macro.c b/libcpp/macro.c | |
154 | index c2515534504..c2a83764660 100644 | |
155 | --- a/libcpp/macro.c | |
156 | +++ b/libcpp/macro.c | |
157 | @@ -357,13 +357,20 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node, | |
158 | time_t tt; | |
159 | struct tm *tb = NULL; | |
160 | ||
161 | - /* (time_t) -1 is a legitimate value for "number of seconds | |
162 | - since the Epoch", so we have to do a little dance to | |
163 | - distinguish that from a genuine error. */ | |
164 | - errno = 0; | |
165 | - tt = time(NULL); | |
166 | - if (tt != (time_t)-1 || errno == 0) | |
167 | - tb = localtime (&tt); | |
168 | + /* Set a reproducible timestamp for __DATE__ and __TIME__ macro | |
169 | + usage if SOURCE_DATE_EPOCH is defined. */ | |
170 | + if (pfile->source_date_epoch != (time_t) -1) | |
171 | + tb = gmtime (&pfile->source_date_epoch); | |
172 | + else | |
173 | + { | |
174 | + /* (time_t) -1 is a legitimate value for "number of seconds | |
175 | + since the Epoch", so we have to do a little dance to | |
176 | + distinguish that from a genuine error. */ | |
177 | + errno = 0; | |
178 | + tt = time (NULL); | |
179 | + if (tt != (time_t)-1 || errno == 0) | |
180 | + tb = localtime (&tt); | |
181 | + } | |
182 | ||
183 | if (tb) | |
184 | { | |
185 | -- | |
186 | 2.14.1 | |
187 |