[Buildroot] [PATCH] toolchain/wrapper: fake __DATE_ and __TIME__ for older gcc

Yann E. MORIN yann.morin.1998 at free.fr
Sat Oct 21 20:38:52 UTC 2017


Arnout, All,

On 2017-10-21 22:31 +0200, Arnout Vandecappelle (Essensium/Mind) spake thusly:
> From: "Yann E. MORIN" <yann.morin.1998 at free.fr>
> 
> Starting with version 7, gcc automatically recognises and enforces the
> environment variable SOURCE_DATE_EPOCH, and fakes __DATE__ and __TIME__
> accordingly, to produce reproducible builds (at least in regards to date
> and time).
> 
> However, older gcc versions do not offer this feature.
> 
> So, we use our toolchain wrapper to force-feed __DATE__ and __TIME__ as
> macros, which will take precedence over those that gcc may compute
> itself. We compute them according to the specs:
>     https://reproducible-builds.org/specs/source-date-epoch/
>     https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
> 
> Since we define macros otherwise internal to gcc, we have to tell it not
> to warn about that. The -Wno-builtin-macro-redefined flag was introduced
> in gcc-4.4.0. Therefore, we make BR2_REPRODUCIBLE depend on GCC >= 4.4.
> 
> gcc-7 will ignore SOURCE_DATE_EPOCH when __DATE__ and __TIME__ are
> user-defined. Anyway, this is of no consequence: whether __DATE__ and
> __TIME__ or SOURCE_DATE_EPOCH takes precedence, it would yield the
> exact same end result since we use the same logic to compute it. Note
> that we didn't copy the code for it from gcc so using the same logic
> doesn't imply that we're inheriting GPL-3.0.

Thnaks for re-spinning this! :-)

> Signed-off-by: "Yann E. MORIN" <yann.morin.1998 at free.fr>
> Cc: Jérôme Pouiller <jezz at sysmic.org>
> Cc: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
> Cc: Arnout Vandecappelle <arnout at mind.be>
> Cc: Peter Korsgaard <peter at korsgaard.com>
> [Arnout: rewrite commit message]
> Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout at mind.be>

Reviewed-by: "Yann E. MORIN" <yann.morin.1998 at free.fr>

Regards,
Yann E. MORIN.

> ---
>  Config.in                     |  2 ++
>  toolchain/toolchain-wrapper.c | 75 +++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 75 insertions(+), 2 deletions(-)
> 
> diff --git a/Config.in b/Config.in
> index 9bdb0b857a..8920b727ce 100644
> --- a/Config.in
> +++ b/Config.in
> @@ -712,6 +712,8 @@ config BR2_COMPILER_PARANOID_UNSAFE_PATH
>  
>  config BR2_REPRODUCIBLE
>  	bool "Make the build reproducible (experimental)"
> +	# SOURCE_DATE_EPOCH support in toolchain-wrapper requires GCC 4.4
> +	depends on BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
>  	help
>  	  This option will remove all sources of non-reproducibility
>  	  from the build process. For a given Buildroot configuration,
> diff --git a/toolchain/toolchain-wrapper.c b/toolchain/toolchain-wrapper.c
> index dd77c11131..2928ea42d0 100644
> --- a/toolchain/toolchain-wrapper.c
> +++ b/toolchain/toolchain-wrapper.c
> @@ -22,12 +22,19 @@
>  #include <unistd.h>
>  #include <stdlib.h>
>  #include <errno.h>
> +#include <time.h>
> +#include <stdbool.h>
>  
>  #ifdef BR_CCACHE
>  static char ccache_path[PATH_MAX];
>  #endif
>  static char path[PATH_MAX];
>  static char sysroot[PATH_MAX];
> +/* As would be defined by gcc:
> + *   https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
> + * sizeof() on string literals includes the terminating \0. */
> +static char _time_[sizeof("-D__TIME__=\"HH:MM:SS\"")];
> +static char _date_[sizeof("-D__DATE__=\"MMM DD YYYY\"")];
>  
>  /**
>   * GCC errors out with certain combinations of arguments (examples are
> @@ -35,12 +42,15 @@ static char sysroot[PATH_MAX];
>   * that we only pass the predefined one to the real compiler if the inverse
>   * option isn't in the argument list.
>   * This specifies the worst case number of extra arguments we might pass
> - * Currently, we have:
> + * Currently, we may have:
>   * 	-mfloat-abi=
>   * 	-march=
>   * 	-mcpu=
> + * 	-D__TIME__=
> + * 	-D__DATE__=
> + * 	-Wno-builtin-macro-redefined
>   */
> -#define EXCLUSIVE_ARGS	3
> +#define EXCLUSIVE_ARGS	6
>  
>  static char *predef_args[] = {
>  #ifdef BR_CCACHE
> @@ -160,6 +170,60 @@ static void check_unsafe_path(const char *arg,
>  	}
>  }
>  
> +/* Returns false if SOURCE_DATE_EPOCH was not defined in the environment.
> + *
> + * Returns true if SOURCE_DATE_EPOCH is in the environment and represent
> + * a valid timestamp, in which case the timestamp is formatted into the
> + * global variables _date_ and _time_.
> + *
> + * Aborts if SOURCE_DATE_EPOCH was set in the environment but did not
> + * contain a valid timestamp.
> + *
> + * Valid values are defined in the spec:
> + *     https://reproducible-builds.org/specs/source-date-epoch/
> + * but we further restrict them to be positive or null.
> + */
> +bool parse_source_date_epoch_from_env(void)
> +{
> +	char *epoch_env, *endptr;
> +	time_t epoch;
> +	struct tm epoch_tm;
> +
> +	if ((epoch_env = getenv("SOURCE_DATE_EPOCH")) == NULL)
> +		return false;
> +	errno = 0;
> +	epoch = (time_t) strtoll(epoch_env, &endptr, 10);
> +	/* We just need to test if it is incorrect, but we do not
> +	 * care why it is incorrect.
> +	 */
> +	if ((errno != 0) || !*epoch_env || *endptr || (epoch < 0)) {
> +		fprintf(stderr, "%s: invalid SOURCE_DATE_EPOCH='%s'\n",
> +			program_invocation_short_name,
> +			epoch_env);
> +		exit(1);
> +	}
> +	tzset(); /* For localtime_r(), below. */
> +	if (localtime_r(&epoch, &epoch_tm) == NULL) {
> +		fprintf(stderr, "%s: cannot parse SOURCE_DATE_EPOCH=%s\n",
> +				program_invocation_short_name,
> +				getenv("SOURCE_DATE_EPOCH"));
> +		exit(1);
> +	}
> +	if (!strftime(_time_, sizeof(_time_), "-D__TIME__=\"%T\"", &epoch_tm)) {
> +		fprintf(stderr, "%s: cannot set time from SOURCE_DATE_EPOCH=%s\n",
> +				program_invocation_short_name,
> +				getenv("SOURCE_DATE_EPOCH"));
> +		exit(1);
> +	}
> +	if (!strftime(_date_, sizeof(_date_), "-D__DATE__=\"%b %e %Y\"", &epoch_tm)) {
> +		fprintf(stderr, "%s: cannot set date from SOURCE_DATE_EPOCH=%s\n",
> +				program_invocation_short_name,
> +				getenv("SOURCE_DATE_EPOCH"));
> +		exit(1);
> +	}
> +	return true;
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	char **args, **cur, **exec_args;
> @@ -289,6 +353,13 @@ int main(int argc, char **argv)
>  	}
>  #endif /* ARCH || CPU */
>  
> +	if (parse_source_date_epoch_from_env()) {
> +		*cur++ = _time_;
> +		*cur++ = _date_;
> +		/* This has existed since gcc-4.4.0. */
> +		*cur++ = "-Wno-builtin-macro-redefined";
> +	}
> +
>  	paranoid_wrapper = getenv("BR_COMPILER_PARANOID_UNSAFE_PATH");
>  	if (paranoid_wrapper && strlen(paranoid_wrapper) > 0)
>  		paranoid = 1;
> -- 
> 2.15.0.rc1
> 

-- 
.-----------------.--------------------.------------------.--------------------.
|  Yann E. MORIN  | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: |
| +33 662 376 056 | Software  Designer | \ / CAMPAIGN     |  ___               |
| +33 223 225 172 `------------.-------:  X  AGAINST      |  \e/  There is no  |
| http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL    |   v   conspiracy.  |
'------------------------------^-------^------------------^--------------------'


More information about the buildroot mailing list