diff --git a/gettext-runtime-mini.spec b/gettext-runtime-mini.spec index 882295c..d70cebf 100644 --- a/gettext-runtime-mini.spec +++ b/gettext-runtime-mini.spec @@ -70,6 +70,8 @@ Patch5: gettext-initialize_vars.patch # PATCH-FIX-OPENSUSE gettext-dont-test-gnulib.patch -- coolo@suse.de Patch6: gettext-dont-test-gnulib.patch Patch9: gettext-needlessly_init_vars.patch +# PATCH-FIX-UPSTREAM https://savannah.gnu.org/bugs/?49654 -- bmwiedemann@opensuse.org +Patch10: msgfmt-remove-pot-creation-date.patch # PATCH-FIX-UPSTREAM boo#941629 -- pth@suse.com Patch11: boo941629-unnessary-rpath-on-standard-path.patch @@ -131,6 +133,7 @@ as well as project examples. %patch5 %patch6 -p1 %patch9 +%patch10 -p1 %patch11 -p1 %build diff --git a/gettext-runtime.changes b/gettext-runtime.changes index 82e4826..7877ce1 100644 --- a/gettext-runtime.changes +++ b/gettext-runtime.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Fri May 5 14:46:50 UTC 2017 - bwiedemann@suse.com + +- Add msgfmt-remove-pot-creation-date.patch + to enable reproducible builds of packages using gettext-runtime + such as dfc, e2fsprogs and acl + ------------------------------------------------------------------- Sun Jun 19 15:42:15 UTC 2016 - astieger@suse.com diff --git a/gettext-runtime.spec b/gettext-runtime.spec index c53c7a4..0e16cda 100644 --- a/gettext-runtime.spec +++ b/gettext-runtime.spec @@ -70,6 +70,8 @@ Patch5: gettext-initialize_vars.patch # PATCH-FIX-OPENSUSE gettext-dont-test-gnulib.patch -- coolo@suse.de Patch6: gettext-dont-test-gnulib.patch Patch9: gettext-needlessly_init_vars.patch +# PATCH-FIX-UPSTREAM https://savannah.gnu.org/bugs/?49654 -- bmwiedemann@opensuse.org +Patch10: msgfmt-remove-pot-creation-date.patch # PATCH-FIX-UPSTREAM boo#941629 -- pth@suse.com Patch11: boo941629-unnessary-rpath-on-standard-path.patch @@ -131,6 +133,7 @@ as well as project examples. %patch5 %patch6 -p1 %patch9 +%patch10 -p1 %patch11 -p1 %build diff --git a/msgfmt-remove-pot-creation-date.patch b/msgfmt-remove-pot-creation-date.patch new file mode 100644 index 0000000..9c13dc2 --- /dev/null +++ b/msgfmt-remove-pot-creation-date.patch @@ -0,0 +1,759 @@ +commit d13f165b83701dffc14f7151419e0c00c00c0d1b +Author: John Darrington +Date: Thu Dec 15 21:56:44 2016 +0100 + + msgfmt: Remove POT-Creation-Date field from the header in the output. + + This helps reproducible builds. + Reported at . + * gettext-tools/src/msgl-header.h (message_list_delete_header_field): New + declaration. + * gettext-tools/src/msgl-header.c (known_fields): New variable, extracted from + msgdomain_list_set_header_field. + (message_list_delete_header_field): New function. + * gettext-tools/src/write-mo.c: Include msgl-header.h. + (msgdomain_write_mo): Delete the POT-Creation-Date field. + * gettext-tools/src/write-java.c: Include msgl-header.h. + (msgdomain_write_java): Delete the POT-Creation-Date field. + * gettext-tools/src/write-csharp.c: Include msgl-header.h. + (msgdomain_write_csharp): Delete the POT-Creation-Date field. + * gettext-tools/src/write-resources.c: Include msgl-header.h. + (msgdomain_write_csharp_resources): Delete the POT-Creation-Date field. + * gettext-tools/src/write-tcl.c: Include msgl-header.h. + (msgdomain_write_tcl): Delete the POT-Creation-Date field. + * gettext-tools/src/write-qt.c: Include msgl-header.h. + (msgdomain_write_qt): Delete the POT-Creation-Date field. + * gettext-tools/src/write-desktop.c: Include msgl-header.h. + (msgdomain_write_desktop): Delete the POT-Creation-Date field. + * gettext-tools/src/write-xml.c: Include msgl-header.h. + (msgdomain_write_xml): Delete the POT-Creation-Date field. + * gettext-tools/tests/msgfmt-19: New file, based on + gettext-tools/tests/msgfmt-18. + * gettext-tools/tests/Makefile.am (TESTS): Add it. + +diff --git a/gettext-tools/src/msgl-header.c b/gettext-tools/src/msgl-header.c +index 987c1c47e..25ae33af3 100644 +--- a/gettext-tools/src/msgl-header.c ++++ b/gettext-tools/src/msgl-header.c +@@ -30,16 +30,12 @@ + #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) + + +-void +-msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, +- const char *field, const char *value) ++/* The known fields in their usual order. */ ++static const struct + { +- /* The known fields in their usual order. */ +- static const struct +- { +- const char *name; +- size_t len; +- } ++ const char *name; ++ size_t len; ++} + known_fields[] = + { + { "Project-Id-Version:", sizeof ("Project-Id-Version:") - 1 }, +@@ -54,6 +50,11 @@ msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, + { "Content-Transfer-Encoding:", + sizeof ("Content-Transfer-Encoding:") - 1 } + }; ++ ++void ++msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, ++ const char *field, const char *value) ++{ + size_t field_len; + int field_index; + size_t k, i; +@@ -168,3 +169,71 @@ msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, + } + } + } ++ ++ ++void ++message_list_delete_header_field (message_list_ty *mlp, ++ const char *field) ++{ ++ size_t j; ++ int field_index; ++ size_t k; ++ ++ /* Search the field in known_fields[]. */ ++ field_index = -1; ++ for (k = 0; k < SIZEOF (known_fields); k++) ++ if (strcmp (known_fields[k].name, field) == 0) ++ { ++ field_index = k; ++ break; ++ } ++ ++ size_t field_len; ++ field_len = strlen (field); ++ ++ /* Search the header entry. */ ++ for (j = 0; j < mlp->nitems; j++) ++ if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete) ++ { ++ message_ty *mp = mlp->item[j]; ++ ++ /* Modify the header entry. */ ++ const char *header = mp->msgstr; ++ char *new_header = ++ XCALLOC (strlen (header) + 1, ++ char); ++ ++ /* Test whether the field already occurs in the header entry. */ ++ const char *h; ++ ++ for (h = header; *h != '\0'; ) ++ { ++ if (strncmp (h, field, field_len) == 0) ++ break; ++ h = strchr (h, '\n'); ++ if (h == NULL) ++ break; ++ h++; ++ } ++ if (h != NULL && *h != '\0') ++ { ++ /* Replace the field. */ ++ char *p = new_header; ++ memcpy (p, header, h - header); ++ p += h - header; ++ h = strchr (h, '\n'); ++ if (h != NULL) ++ { ++ h++; ++ stpcpy (p, h); ++ } ++ } ++ else ++ { ++ char *p = new_header; ++ p = stpcpy (p, header); ++ } ++ ++ mp->msgstr = new_header; ++ } ++} +diff --git a/gettext-tools/src/msgl-header.h b/gettext-tools/src/msgl-header.h +index 968515711..34726e7b0 100644 +--- a/gettext-tools/src/msgl-header.h ++++ b/gettext-tools/src/msgl-header.h +@@ -34,6 +34,9 @@ extern void + msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, + const char *field, const char *value); + ++extern void ++ message_list_delete_header_field (message_list_ty *mlp, const char *field); ++ + + #ifdef __cplusplus + } +diff --git a/gettext-tools/src/write-csharp.c b/gettext-tools/src/write-csharp.c +index 5cf573a0f..30e8411cc 100644 +--- a/gettext-tools/src/write-csharp.c ++++ b/gettext-tools/src/write-csharp.c +@@ -78,6 +78,7 @@ + #include "message.h" + #include "msgfmt.h" + #include "msgl-iconv.h" ++#include "msgl-header.h" + #include "plural-exp.h" + #include "po-charset.h" + #include "xalloc.h" +@@ -645,6 +646,8 @@ msgdomain_write_csharp (message_list_ty *mlp, const char *canon_encoding, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + /* Create a temporary directory where we can put the C# file. + A simple temporary file would also be possible but would require us to + define our own variant of mkstemp(): On one hand the functions mktemp(), +diff --git a/gettext-tools/src/write-desktop.c b/gettext-tools/src/write-desktop.c +index 898ac3024..e568d47fb 100644 +--- a/gettext-tools/src/write-desktop.c ++++ b/gettext-tools/src/write-desktop.c +@@ -29,6 +29,7 @@ + #include + #include "error.h" + #include "msgl-iconv.h" ++#include "msgl-header.h" + #include "po-charset.h" + #include "read-catalog.h" + #include "read-po.h" +@@ -203,6 +204,8 @@ msgdomain_write_desktop (message_list_ty *mlp, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + /* Create a single-element operands and run the bulk operation on it. */ + operand.language = (char *) locale_name; + operand.mlp = mlp; +diff --git a/gettext-tools/src/write-java.c b/gettext-tools/src/write-java.c +index eef8c79d2..039ed94d9 100644 +--- a/gettext-tools/src/write-java.c ++++ b/gettext-tools/src/write-java.c +@@ -61,6 +61,7 @@ + #include "message.h" + #include "msgfmt.h" + #include "msgl-iconv.h" ++#include "msgl-header.h" + #include "plural-exp.h" + #include "po-charset.h" + #include "xalloc.h" +@@ -1066,6 +1067,8 @@ msgdomain_write_java (message_list_ty *mlp, const char *canon_encoding, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + if (output_source) + { + tmpdir = NULL; +diff --git a/gettext-tools/src/write-mo.c b/gettext-tools/src/write-mo.c +index b4a789494..b99dece02 100644 +--- a/gettext-tools/src/write-mo.c ++++ b/gettext-tools/src/write-mo.c +@@ -48,6 +48,9 @@ + #include "binary-io.h" + #include "fwriteerror.h" + #include "gettext.h" ++#include "read-catalog.h" ++#include "read-stringtable.h" ++#include "msgl-header.h" + + #define _(str) gettext (str) + +@@ -804,6 +807,7 @@ msgdomain_write_mo (message_list_ty *mlp, + + if (output_file != NULL) + { ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); + write_table (output_file, mlp); + + /* Make sure nothing went wrong. */ +diff --git a/gettext-tools/src/write-qt.c b/gettext-tools/src/write-qt.c +index 978bf0938..4a47d241f 100644 +--- a/gettext-tools/src/write-qt.c ++++ b/gettext-tools/src/write-qt.c +@@ -35,6 +35,7 @@ + #include "message.h" + #include "po-charset.h" + #include "msgl-iconv.h" ++#include "msgl-header.h" + #include "hash-string.h" + #include "unistr.h" + #include "xalloc.h" +@@ -742,6 +743,7 @@ strings, not in the untranslated strings\n"))); + + if (output_file != NULL) + { ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); + write_qm (output_file, mlp); + + /* Make sure nothing went wrong. */ +diff --git a/gettext-tools/src/write-resources.c b/gettext-tools/src/write-resources.c +index e5103c4b0..ec74eadcd 100644 +--- a/gettext-tools/src/write-resources.c ++++ b/gettext-tools/src/write-resources.c +@@ -38,6 +38,7 @@ + #include "message.h" + #include "msgfmt.h" + #include "msgl-iconv.h" ++#include "msgl-header.h" + #include "po-charset.h" + #include "xalloc.h" + #include "concat-filename.h" +@@ -114,6 +115,8 @@ msgdomain_write_csharp_resources (message_list_ty *mlp, + const char *domain_name, + const char *file_name) + { ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + /* If no entry for this domain don't even create the file. */ + if (mlp->nitems != 0) + { +diff --git a/gettext-tools/src/write-tcl.c b/gettext-tools/src/write-tcl.c +index 0dbe3aa88..04b62d9c8 100644 +--- a/gettext-tools/src/write-tcl.c ++++ b/gettext-tools/src/write-tcl.c +@@ -34,6 +34,7 @@ + #include "xerror.h" + #include "message.h" + #include "msgl-iconv.h" ++#include "msgl-header.h" + #include "po-charset.h" + #include "xalloc.h" + #include "xmalloca.h" +@@ -216,6 +217,7 @@ but the Tcl message catalog format doesn't support plural handling\n"))); + return 1; + } + ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); + write_msg (output_file, mlp, frobbed_locale_name); + + /* Make sure nothing went wrong. */ +diff --git a/gettext-tools/src/write-xml.c b/gettext-tools/src/write-xml.c +index 79b7b5dbc..f6cd6c003 100644 +--- a/gettext-tools/src/write-xml.c ++++ b/gettext-tools/src/write-xml.c +@@ -29,6 +29,7 @@ + #include + #include "error.h" + #include "msgl-iconv.h" ++#include "msgl-header.h" + #include "po-charset.h" + #include "read-catalog.h" + #include "read-po.h" +@@ -94,6 +95,8 @@ msgdomain_write_xml (message_list_ty *mlp, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + /* Create a single-element operands and run the bulk operation on it. */ + operand.language = (char *) locale_name; + operand.mlp = mlp; +diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am +index 0dfb4d867..38b47b922 100644 +--- a/gettext-tools/tests/Makefile.am ++++ b/gettext-tools/tests/Makefile.am +@@ -46,7 +46,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \ + msgfilter-sr-latin-1 msgfilter-quote-1 \ + msgfmt-1 msgfmt-2 msgfmt-3 msgfmt-4 msgfmt-5 msgfmt-6 msgfmt-7 \ + msgfmt-8 msgfmt-9 msgfmt-10 msgfmt-11 msgfmt-12 msgfmt-13 msgfmt-14 \ +- msgfmt-15 msgfmt-16 msgfmt-17 msgfmt-18 \ ++ msgfmt-15 msgfmt-16 msgfmt-17 msgfmt-18 msgfmt-19 \ + msgfmt-properties-1 \ + msgfmt-qt-1 msgfmt-qt-2 \ + msgfmt-desktop-1 msgfmt-desktop-2 \ +diff --git a/gettext-tools/tests/msgfmt-19 b/gettext-tools/tests/msgfmt-19 +new file mode 100755 +index 000000000..88574c817 +--- /dev/null ++++ b/gettext-tools/tests/msgfmt-19 +@@ -0,0 +1,66 @@ ++#! /bin/sh ++. "${srcdir=.}/init.sh"; path_prepend_ . ../src ++ ++# Test accelerators. ++ ++cat <<\EOF > mf-19-1.po ++# SOME DESCRIPTIVE TITLE. ++# Copyright (C) YEAR Free Software Foundation, Inc. ++# FIRST AUTHOR , YEAR. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: GNU bison\n" ++"POT-Creation-Date: 2017-04-05 19:47+0200\n" ++"PO-Revision-Date: 2017-06-07 09:07+0000\n" ++"Last-Translator: ABC DEF \n" ++"Language-Team: test \n" ++"Language: test\n" ++"MIME-Version: 1.0\n" ++"Content-Type: text/plain; charset=UTF-8\n" ++"Content-Transfer-Encoding: 8bit\n" ++ ++msgid "pen &File" ++msgstr "pen File" ++ ++msgid "how _Help" ++msgstr "how Help" ++EOF ++ ++ ++cat <<\EOF > mf-19-2.po ++# SOME DESCRIPTIVE TITLE. ++# Copyright (C) YEAR Free Software Foundation, Inc. ++# FIRST AUTHOR , YEAR. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: GNU bison\n" ++"POT-Creation-Date: 2016-03-04 18:46+0100\n" ++"PO-Revision-Date: 2017-06-07 09:07+0000\n" ++"Last-Translator: ABC DEF \n" ++"Language-Team: test \n" ++"Language: test\n" ++"MIME-Version: 1.0\n" ++"Content-Type: text/plain; charset=UTF-8\n" ++"Content-Transfer-Encoding: 8bit\n" ++ ++msgid "pen &File" ++msgstr "pen File" ++ ++msgid "how _Help" ++msgstr "how Help" ++EOF ++ ++ ++: ${MSGFMT=msgfmt} ++${MSGFMT} -o mf-19-1.mo mf-19-1.po 2>/dev/null ++test $? = 0 || { Exit 1; } ++ ++: ${MSGFMT=msgfmt} ++${MSGFMT} -o mf-19-2.mo mf-19-2.po 2>/dev/null ++test $? = 0 || { Exit 1; } ++ ++: ${DIFF=diff} ++${DIFF} mf-19-1.mo mf-19-2.mo ++test $? = 0 || { Exit 1; } +commit dea676293993e16ae50119ce1edfcc18e586c3f7 +Author: Bruno Haible +Date: Thu Dec 15 22:51:00 2016 +0100 + + Polish the last commit. + +diff --git a/gettext-tools/src/msgl-header.c b/gettext-tools/src/msgl-header.c +index 25ae33af3..219b412ab 100644 +--- a/gettext-tools/src/msgl-header.c ++++ b/gettext-tools/src/msgl-header.c +@@ -36,20 +36,20 @@ static const struct + const char *name; + size_t len; + } +- known_fields[] = +- { +- { "Project-Id-Version:", sizeof ("Project-Id-Version:") - 1 }, +- { "Report-Msgid-Bugs-To:", sizeof ("Report-Msgid-Bugs-To:") - 1 }, +- { "POT-Creation-Date:", sizeof ("POT-Creation-Date:") - 1 }, +- { "PO-Revision-Date:", sizeof ("PO-Revision-Date:") - 1 }, +- { "Last-Translator:", sizeof ("Last-Translator:") - 1 }, +- { "Language-Team:", sizeof ("Language-Team:") - 1 }, +- { "Language:", sizeof ("Language:") - 1 }, +- { "MIME-Version:", sizeof ("MIME-Version:") - 1 }, +- { "Content-Type:", sizeof ("Content-Type:") - 1 }, +- { "Content-Transfer-Encoding:", +- sizeof ("Content-Transfer-Encoding:") - 1 } +- }; ++known_fields[] = ++ { ++ { "Project-Id-Version:", sizeof ("Project-Id-Version:") - 1 }, ++ { "Report-Msgid-Bugs-To:", sizeof ("Report-Msgid-Bugs-To:") - 1 }, ++ { "POT-Creation-Date:", sizeof ("POT-Creation-Date:") - 1 }, ++ { "PO-Revision-Date:", sizeof ("PO-Revision-Date:") - 1 }, ++ { "Last-Translator:", sizeof ("Last-Translator:") - 1 }, ++ { "Language-Team:", sizeof ("Language-Team:") - 1 }, ++ { "Language:", sizeof ("Language:") - 1 }, ++ { "MIME-Version:", sizeof ("MIME-Version:") - 1 }, ++ { "Content-Type:", sizeof ("Content-Type:") - 1 }, ++ { "Content-Transfer-Encoding:", sizeof ("Content-Transfer-Encoding:") - 1 } ++ }; ++ + + void + msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, +@@ -175,21 +175,8 @@ void + message_list_delete_header_field (message_list_ty *mlp, + const char *field) + { ++ size_t field_len = strlen (field); + size_t j; +- int field_index; +- size_t k; +- +- /* Search the field in known_fields[]. */ +- field_index = -1; +- for (k = 0; k < SIZEOF (known_fields); k++) +- if (strcmp (known_fields[k].name, field) == 0) +- { +- field_index = k; +- break; +- } +- +- size_t field_len; +- field_len = strlen (field); + + /* Search the header entry. */ + for (j = 0; j < mlp->nitems; j++) +@@ -199,11 +186,8 @@ message_list_delete_header_field (message_list_ty *mlp, + + /* Modify the header entry. */ + const char *header = mp->msgstr; +- char *new_header = +- XCALLOC (strlen (header) + 1, +- char); + +- /* Test whether the field already occurs in the header entry. */ ++ /* Test whether the field occurs in the header entry. */ + const char *h; + + for (h = header; *h != '\0'; ) +@@ -217,7 +201,9 @@ message_list_delete_header_field (message_list_ty *mlp, + } + if (h != NULL && *h != '\0') + { +- /* Replace the field. */ ++ /* Delete the field. */ ++ char *new_header = XCALLOC (strlen (header) + 1, char); ++ + char *p = new_header; + memcpy (p, header, h - header); + p += h - header; +@@ -225,15 +211,12 @@ message_list_delete_header_field (message_list_ty *mlp, + if (h != NULL) + { + h++; +- stpcpy (p, h); ++ strcpy (p, h); + } ++ else ++ *p = '\0'; ++ ++ mp->msgstr = new_header; + } +- else +- { +- char *p = new_header; +- p = stpcpy (p, header); +- } +- +- mp->msgstr = new_header; + } + } +diff --git a/gettext-tools/src/msgl-header.h b/gettext-tools/src/msgl-header.h +index 34726e7b0..35524a37f 100644 +--- a/gettext-tools/src/msgl-header.h ++++ b/gettext-tools/src/msgl-header.h +@@ -34,8 +34,11 @@ extern void + msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, + const char *field, const char *value); + ++/* Remove the given field from the header. ++ The FIELD name ends in a colon. */ + extern void +- message_list_delete_header_field (message_list_ty *mlp, const char *field); ++ message_list_delete_header_field (message_list_ty *mlp, ++ const char *field); + + + #ifdef __cplusplus +diff --git a/gettext-tools/src/write-csharp.c b/gettext-tools/src/write-csharp.c +index 30e8411cc..161cd4f45 100644 +--- a/gettext-tools/src/write-csharp.c ++++ b/gettext-tools/src/write-csharp.c +@@ -646,8 +646,10 @@ msgdomain_write_csharp (message_list_ty *mlp, const char *canon_encoding, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ + message_list_delete_header_field (mlp, "POT-Creation-Date:"); +- ++ + /* Create a temporary directory where we can put the C# file. + A simple temporary file would also be possible but would require us to + define our own variant of mkstemp(): On one hand the functions mktemp(), +diff --git a/gettext-tools/src/write-desktop.c b/gettext-tools/src/write-desktop.c +index e568d47fb..657620dcb 100644 +--- a/gettext-tools/src/write-desktop.c ++++ b/gettext-tools/src/write-desktop.c +@@ -204,8 +204,10 @@ msgdomain_write_desktop (message_list_ty *mlp, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ + message_list_delete_header_field (mlp, "POT-Creation-Date:"); +- ++ + /* Create a single-element operands and run the bulk operation on it. */ + operand.language = (char *) locale_name; + operand.mlp = mlp; +diff --git a/gettext-tools/src/write-java.c b/gettext-tools/src/write-java.c +index 039ed94d9..9ddfac868 100644 +--- a/gettext-tools/src/write-java.c ++++ b/gettext-tools/src/write-java.c +@@ -1067,6 +1067,8 @@ msgdomain_write_java (message_list_ty *mlp, const char *canon_encoding, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ + message_list_delete_header_field (mlp, "POT-Creation-Date:"); + + if (output_source) +diff --git a/gettext-tools/src/write-mo.c b/gettext-tools/src/write-mo.c +index b99dece02..69196550c 100644 +--- a/gettext-tools/src/write-mo.c ++++ b/gettext-tools/src/write-mo.c +@@ -45,12 +45,10 @@ + #include "xsize.h" + #include "xalloc.h" + #include "xmalloca.h" ++#include "msgl-header.h" + #include "binary-io.h" + #include "fwriteerror.h" + #include "gettext.h" +-#include "read-catalog.h" +-#include "read-stringtable.h" +-#include "msgl-header.h" + + #define _(str) gettext (str) + +@@ -789,6 +787,10 @@ msgdomain_write_mo (message_list_ty *mlp, + /* If no entry for this domain don't even create the file. */ + if (mlp->nitems != 0) + { ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + if (strcmp (domain_name, "-") == 0) + { + output_file = stdout; +@@ -807,7 +809,6 @@ msgdomain_write_mo (message_list_ty *mlp, + + if (output_file != NULL) + { +- message_list_delete_header_field (mlp, "POT-Creation-Date:"); + write_table (output_file, mlp); + + /* Make sure nothing went wrong. */ +diff --git a/gettext-tools/src/write-qt.c b/gettext-tools/src/write-qt.c +index 4a47d241f..b3cca5a8e 100644 +--- a/gettext-tools/src/write-qt.c ++++ b/gettext-tools/src/write-qt.c +@@ -725,6 +725,10 @@ strings, not in the untranslated strings\n"))); + } + } + ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + if (strcmp (domain_name, "-") == 0) + { + output_file = stdout; +@@ -743,7 +747,6 @@ strings, not in the untranslated strings\n"))); + + if (output_file != NULL) + { +- message_list_delete_header_field (mlp, "POT-Creation-Date:"); + write_qm (output_file, mlp); + + /* Make sure nothing went wrong. */ +diff --git a/gettext-tools/src/write-resources.c b/gettext-tools/src/write-resources.c +index ec74eadcd..8cc33cc13 100644 +--- a/gettext-tools/src/write-resources.c ++++ b/gettext-tools/src/write-resources.c +@@ -115,8 +115,6 @@ msgdomain_write_csharp_resources (message_list_ty *mlp, + const char *domain_name, + const char *file_name) + { +- message_list_delete_header_field (mlp, "POT-Creation-Date:"); +- + /* If no entry for this domain don't even create the file. */ + if (mlp->nitems != 0) + { +@@ -161,6 +159,10 @@ but the C# .resources format doesn't support plural handling\n"))); + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + /* Execute the WriteResource program. */ + { + const char *args[2]; +diff --git a/gettext-tools/src/write-tcl.c b/gettext-tools/src/write-tcl.c +index 04b62d9c8..b61608e76 100644 +--- a/gettext-tools/src/write-tcl.c ++++ b/gettext-tools/src/write-tcl.c +@@ -185,6 +185,10 @@ but the Tcl message catalog format doesn't support plural handling\n"))); + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ ++ message_list_delete_header_field (mlp, "POT-Creation-Date:"); ++ + /* Now create the file. */ + { + size_t len; +@@ -217,7 +221,6 @@ but the Tcl message catalog format doesn't support plural handling\n"))); + return 1; + } + +- message_list_delete_header_field (mlp, "POT-Creation-Date:"); + write_msg (output_file, mlp, frobbed_locale_name); + + /* Make sure nothing went wrong. */ +diff --git a/gettext-tools/src/write-xml.c b/gettext-tools/src/write-xml.c +index f6cd6c003..5c719f92e 100644 +--- a/gettext-tools/src/write-xml.c ++++ b/gettext-tools/src/write-xml.c +@@ -95,8 +95,10 @@ msgdomain_write_xml (message_list_ty *mlp, + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + ++ /* Support for "reproducible builds": Delete information that may vary ++ between builds in the same conditions. */ + message_list_delete_header_field (mlp, "POT-Creation-Date:"); +- ++ + /* Create a single-element operands and run the bulk operation on it. */ + operand.language = (char *) locale_name; + operand.mlp = mlp; +diff --git a/gettext-tools/tests/msgfmt-19 b/gettext-tools/tests/msgfmt-19 +index 88574c817..76d4a739d 100755 +--- a/gettext-tools/tests/msgfmt-19 ++++ b/gettext-tools/tests/msgfmt-19 +@@ -1,7 +1,8 @@ + #! /bin/sh + . "${srcdir=.}/init.sh"; path_prepend_ . ../src + +-# Test accelerators. ++# Test that PO files that differ only in the POT-Creation-Date yield the ++# exact same .mo file. + + cat <<\EOF > mf-19-1.po + # SOME DESCRIPTIVE TITLE. +@@ -20,14 +21,13 @@ msgstr "" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + +-msgid "pen &File" +-msgstr "pen File" ++msgid "Open &File" ++msgstr "Open File" + +-msgid "how _Help" +-msgstr "how Help" ++msgid "Show _Help" ++msgstr "Show Help" + EOF + +- + cat <<\EOF > mf-19-2.po + # SOME DESCRIPTIVE TITLE. + # Copyright (C) YEAR Free Software Foundation, Inc. +@@ -45,14 +45,13 @@ msgstr "" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + +-msgid "pen &File" +-msgstr "pen File" ++msgid "Open &File" ++msgstr "Open File" + +-msgid "how _Help" +-msgstr "how Help" ++msgid "Show _Help" ++msgstr "Show Help" + EOF + +- + : ${MSGFMT=msgfmt} + ${MSGFMT} -o mf-19-1.mo mf-19-1.po 2>/dev/null + test $? = 0 || { Exit 1; }