1From 33e9867758e830e19d181d5a0aa7f2f3cc4a08b3 Mon Sep 17 00:00:00 2001 2From: Khem Raj <raj.khem@gmail.com> 3Date: Wed, 18 Mar 2015 01:33:49 +0000 4Subject: [PATCH] eglibc: Forward port cross locale generation support 5 6Upstream-Status: Pending 7 8Signed-off-by: Khem Raj <raj.khem@gmail.com> 9--- 10 locale/Makefile | 1 + 11 locale/catnames.c | 46 +++++++++++++++++++++++++++ 12 locale/localeinfo.h | 2 +- 13 locale/programs/charmap-dir.c | 6 ++++ 14 locale/programs/ld-collate.c | 17 +++++----- 15 locale/programs/ld-ctype.c | 27 ++++++++-------- 16 locale/programs/ld-time.c | 31 ++++++++++++------ 17 locale/programs/linereader.c | 2 +- 18 locale/programs/localedef.c | 8 +++++ 19 locale/programs/locfile.c | 5 ++- 20 locale/programs/locfile.h | 59 +++++++++++++++++++++++++++++++++-- 21 locale/setlocale.c | 29 ----------------- 22 12 files changed, 166 insertions(+), 67 deletions(-) 23 create mode 100644 locale/catnames.c 24 25diff --git a/locale/Makefile b/locale/Makefile 26index 2810f28605..05f847f9a6 100644 27--- a/locale/Makefile 28+++ b/locale/Makefile 29@@ -30,6 +30,7 @@ headers = \ 30 locale.h \ 31 # headers 32 routines = \ 33+ catnames \ 34 duplocale \ 35 findlocale \ 36 freelocale \ 37diff --git a/locale/catnames.c b/locale/catnames.c 38new file mode 100644 39index 0000000000..538f3f5edb 40--- /dev/null 41+++ b/locale/catnames.c 42@@ -0,0 +1,46 @@ 43+/* Copyright (C) 2006 Free Software Foundation, Inc. 44+ This file is part of the GNU C Library. 45+ 46+ The GNU C Library is free software; you can redistribute it and/or 47+ modify it under the terms of the GNU Lesser General Public 48+ License as published by the Free Software Foundation; either 49+ version 2.1 of the License, or (at your option) any later version. 50+ 51+ The GNU C Library is distributed in the hope that it will be useful, 52+ but WITHOUT ANY WARRANTY; without even the implied warranty of 53+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 54+ Lesser General Public License for more details. 55+ 56+ You should have received a copy of the GNU Lesser General Public 57+ License along with the GNU C Library; if not, write to the Free 58+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 59+ 02111-1307 USA. */ 60+ 61+#include "localeinfo.h" 62+ 63+/* Define an array of category names (also the environment variable names). */ 64+const struct catnamestr_t _nl_category_names attribute_hidden = 65+ { 66+#define DEFINE_CATEGORY(category, category_name, items, a) \ 67+ category_name, 68+#include "categories.def" 69+#undef DEFINE_CATEGORY 70+ }; 71+ 72+const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = 73+ { 74+#define DEFINE_CATEGORY(category, category_name, items, a) \ 75+ [category] = offsetof (struct catnamestr_t, CATNAMEMF (__LINE__)), 76+#include "categories.def" 77+#undef DEFINE_CATEGORY 78+ }; 79+ 80+/* An array of their lengths, for convenience. */ 81+const uint8_t _nl_category_name_sizes[] attribute_hidden = 82+ { 83+#define DEFINE_CATEGORY(category, category_name, items, a) \ 84+ [category] = sizeof (category_name) - 1, 85+#include "categories.def" 86+#undef DEFINE_CATEGORY 87+ [LC_ALL] = sizeof ("LC_ALL") - 1 88+ }; 89diff --git a/locale/localeinfo.h b/locale/localeinfo.h 90index f7efc288a5..6ef082eb25 100644 91--- a/locale/localeinfo.h 92+++ b/locale/localeinfo.h 93@@ -246,7 +246,7 @@ __libc_tsd_define (extern, locale_t, LOCALE) 94 unused. We can manage this playing some tricks with weak references. 95 But with thread-local locale settings, it becomes quite ungainly unless 96 we can use __thread variables. So only in that case do we attempt this. */ 97-#ifndef SHARED 98+#if !defined SHARED && !defined IN_GLIBC_LOCALEDEF 99 # include <tls.h> 100 # define NL_CURRENT_INDIRECT 1 101 #endif 102diff --git a/locale/programs/charmap-dir.c b/locale/programs/charmap-dir.c 103index 36504f238d..56ee97e61b 100644 104--- a/locale/programs/charmap-dir.c 105+++ b/locale/programs/charmap-dir.c 106@@ -18,7 +18,9 @@ 107 #include <errno.h> 108 #include <fcntl.h> 109 #include <libintl.h> 110+#ifndef NO_UNCOMPRESS 111 #include <spawn.h> 112+#endif 113 #include <stdio.h> 114 #include <stdlib.h> 115 #include <string.h> 116@@ -154,6 +156,7 @@ charmap_closedir (CHARMAP_DIR *cdir) 117 return closedir (dir); 118 } 119 120+#ifndef NO_UNCOMPRESS 121 /* Creates a subprocess decompressing the given pathname, and returns 122 a stream reading its output (the decompressed data). */ 123 static 124@@ -202,6 +205,7 @@ fopen_uncompressed (const char *pathname, const char *compressor) 125 } 126 return NULL; 127 } 128+#endif 129 130 /* Opens a charmap for reading, given its name (not an alias name). */ 131 FILE * 132@@ -224,6 +228,7 @@ charmap_open (const char *directory, const char *name) 133 if (stream != NULL) 134 return stream; 135 136+#ifndef NO_UNCOMPRESS 137 memcpy (p, ".gz", 4); 138 stream = fopen_uncompressed (pathname, "gzip"); 139 if (stream != NULL) 140@@ -233,6 +238,7 @@ charmap_open (const char *directory, const char *name) 141 stream = fopen_uncompressed (pathname, "bzip2"); 142 if (stream != NULL) 143 return stream; 144+#endif 145 146 return NULL; 147 } 148diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c 149index 5048adbd9f..4232834ead 100644 150--- a/locale/programs/ld-collate.c 151+++ b/locale/programs/ld-collate.c 152@@ -352,7 +352,7 @@ new_element (struct locale_collate_t *collate, const char *mbs, size_t mbslen, 153 } 154 if (wcs != NULL) 155 { 156- size_t nwcs = wcslen ((wchar_t *) wcs); 157+ size_t nwcs = wcslen_uint32 (wcs); 158 uint32_t zero = 0; 159 /* Handle <U0000> as a single character. */ 160 if (nwcs == 0) 161@@ -1776,8 +1776,7 @@ symbol `%s' has the same encoding as"), (*eptr)->name); 162 163 if ((*eptr)->nwcs == runp->nwcs) 164 { 165- int c = wmemcmp ((wchar_t *) (*eptr)->wcs, 166- (wchar_t *) runp->wcs, runp->nwcs); 167+ int c = wmemcmp_uint32 ((*eptr)->wcs, runp->wcs, runp->nwcs); 168 169 if (c == 0) 170 { 171@@ -2004,9 +2003,9 @@ add_to_tablewc (uint32_t ch, struct element_t *runp) 172 one consecutive entry. */ 173 if (runp->wcnext != NULL 174 && runp->nwcs == runp->wcnext->nwcs 175- && wmemcmp ((wchar_t *) runp->wcs, 176- (wchar_t *)runp->wcnext->wcs, 177- runp->nwcs - 1) == 0 178+ && wmemcmp_uint32 (runp->wcs, 179+ runp->wcnext->wcs, 180+ runp->nwcs - 1) == 0 181 && (runp->wcs[runp->nwcs - 1] 182 == runp->wcnext->wcs[runp->nwcs - 1] + 1)) 183 { 184@@ -2030,9 +2029,9 @@ add_to_tablewc (uint32_t ch, struct element_t *runp) 185 runp = runp->wcnext; 186 while (runp->wcnext != NULL 187 && runp->nwcs == runp->wcnext->nwcs 188- && wmemcmp ((wchar_t *) runp->wcs, 189- (wchar_t *)runp->wcnext->wcs, 190- runp->nwcs - 1) == 0 191+ && wmemcmp_uint32 (runp->wcs, 192+ runp->wcnext->wcs, 193+ runp->nwcs - 1) == 0 194 && (runp->wcs[runp->nwcs - 1] 195 == runp->wcnext->wcs[runp->nwcs - 1] + 1)); 196 197diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c 198index eb6e7e145c..14736d1cac 100644 199--- a/locale/programs/ld-ctype.c 200+++ b/locale/programs/ld-ctype.c 201@@ -914,7 +914,7 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap, 202 allocate_arrays (ctype, charmap, ctype->repertoire); 203 204 default_missing_len = (ctype->default_missing 205- ? wcslen ((wchar_t *) ctype->default_missing) 206+ ? wcslen_uint32 (ctype->default_missing) 207 : 0); 208 209 init_locale_data (&file, nelems); 210@@ -1926,7 +1926,7 @@ read_translit_entry (struct linereader *ldfile, struct locale_ctype_t *ctype, 211 ignore = 1; 212 else 213 /* This value is usable. */ 214- obstack_grow (ob, to_wstr, wcslen ((wchar_t *) to_wstr) * 4); 215+ obstack_grow (ob, to_wstr, wcslen_uint32 (to_wstr) * 4); 216 217 first = 0; 218 } 219@@ -2460,8 +2460,8 @@ with character code range values one must use the absolute ellipsis `...'")); 220 } 221 222 handle_tok_digit: 223- class_bit = _ISwdigit; 224- class256_bit = _ISdigit; 225+ class_bit = BITw (tok_digit); 226+ class256_bit = BIT (tok_digit); 227 handle_digits = 1; 228 goto read_charclass; 229 230@@ -3876,8 +3876,7 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap, 231 232 while (idx < number) 233 { 234- int res = wcscmp ((const wchar_t *) sorted[idx]->from, 235- (const wchar_t *) runp->from); 236+ int res = wcscmp_uint32 (sorted[idx]->from, runp->from); 237 if (res == 0) 238 { 239 replace = 1; 240@@ -3914,11 +3913,11 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap, 241 for (size_t cnt = 0; cnt < number; ++cnt) 242 { 243 struct translit_to_t *srunp; 244- from_len += wcslen ((const wchar_t *) sorted[cnt]->from) + 1; 245+ from_len += wcslen_uint32 (sorted[cnt]->from) + 1; 246 srunp = sorted[cnt]->to; 247 while (srunp != NULL) 248 { 249- to_len += wcslen ((const wchar_t *) srunp->str) + 1; 250+ to_len += wcslen_uint32 (srunp->str) + 1; 251 srunp = srunp->next; 252 } 253 /* Plus one for the extra NUL character marking the end of 254@@ -3942,18 +3941,18 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap, 255 ctype->translit_from_idx[cnt] = from_len; 256 ctype->translit_to_idx[cnt] = to_len; 257 258- len = wcslen ((const wchar_t *) sorted[cnt]->from) + 1; 259- wmemcpy ((wchar_t *) &ctype->translit_from_tbl[from_len], 260- (const wchar_t *) sorted[cnt]->from, len); 261+ len = wcslen_uint32 (sorted[cnt]->from) + 1; 262+ wmemcpy_uint32 (&ctype->translit_from_tbl[from_len], 263+ sorted[cnt]->from, len); 264 from_len += len; 265 266 ctype->translit_to_idx[cnt] = to_len; 267 srunp = sorted[cnt]->to; 268 while (srunp != NULL) 269 { 270- len = wcslen ((const wchar_t *) srunp->str) + 1; 271- wmemcpy ((wchar_t *) &ctype->translit_to_tbl[to_len], 272- (const wchar_t *) srunp->str, len); 273+ len = wcslen_uint32 (srunp->str) + 1; 274+ wmemcpy_uint32 (&ctype->translit_to_tbl[to_len], 275+ srunp->str, len); 276 to_len += len; 277 srunp = srunp->next; 278 } 279diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c 280index 1abff3cf53..8a2f2b820a 100644 281--- a/locale/programs/ld-time.c 282+++ b/locale/programs/ld-time.c 283@@ -219,8 +219,10 @@ No definition for %s category found"), "LC_TIME"); 284 } 285 else 286 { 287+ static const uint32_t wt_fmt_ampm[] 288+ = { '%','I',':','%','M',':','%','S',' ','%','p',0 }; 289 time->t_fmt_ampm = "%I:%M:%S %p"; 290- time->wt_fmt_ampm = (const uint32_t *) L"%I:%M:%S %p"; 291+ time->wt_fmt_ampm = wt_fmt_ampm; 292 } 293 } 294 295@@ -230,7 +232,7 @@ No definition for %s category found"), "LC_TIME"); 296 const int days_per_month[12] = { 31, 29, 31, 30, 31, 30, 297 31, 31, 30, 31 ,30, 31 }; 298 size_t idx; 299- wchar_t *wstr; 300+ uint32_t *wstr; 301 302 time->era_entries = 303 (struct era_data *) xmalloc (time->num_era 304@@ -456,18 +458,18 @@ No definition for %s category found"), "LC_TIME"); 305 } 306 307 /* Now generate the wide character name and format. */ 308- wstr = wcschr ((wchar_t *) time->wera[idx], L':');/* end direction */ 309- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end offset */ 310- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end start */ 311- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end end */ 312+ wstr = wcschr_uint32 (time->wera[idx], L':'); /* end direction */ 313+ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end offset */ 314+ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end start */ 315+ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end end */ 316 if (wstr != NULL) 317 { 318- time->era_entries[idx].wname = (uint32_t *) wstr + 1; 319- wstr = wcschr (wstr + 1, L':'); /* end name */ 320+ time->era_entries[idx].wname = wstr + 1; 321+ wstr = wcschr_uint32 (wstr + 1, L':'); /* end name */ 322 if (wstr != NULL) 323 { 324 *wstr = L'\0'; 325- time->era_entries[idx].wformat = (uint32_t *) wstr + 1; 326+ time->era_entries[idx].wformat = wstr + 1; 327 } 328 else 329 time->era_entries[idx].wname = 330@@ -526,7 +528,16 @@ No definition for %s category found"), "LC_TIME"); 331 if (time->date_fmt == NULL) 332 time->date_fmt = "%a %b %e %H:%M:%S %Z %Y"; 333 if (time->wdate_fmt == NULL) 334- time->wdate_fmt = (const uint32_t *) L"%a %b %e %H:%M:%S %Z %Y"; 335+ { 336+ static const uint32_t wdate_fmt[] = 337+ { '%','a',' ', 338+ '%','b',' ', 339+ '%','e',' ', 340+ '%','H',':','%','M',':','%','S',' ', 341+ '%','Z',' ', 342+ '%','Y',0 }; 343+ time->wdate_fmt = wdate_fmt; 344+ } 345 } 346 347 348diff --git a/locale/programs/linereader.c b/locale/programs/linereader.c 349index 61373d2657..7ec5726377 100644 350--- a/locale/programs/linereader.c 351+++ b/locale/programs/linereader.c 352@@ -776,7 +776,7 @@ get_string (struct linereader *lr, const struct charmap_t *charmap, 353 { 354 int return_widestr = lr->return_widestr; 355 struct lr_buffer lrb; 356- wchar_t *buf2 = NULL; 357+ uint32_t *buf2 = NULL; 358 359 lr_buffer_init (&lrb); 360 361diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c 362index 907bb5fb25..3106529043 100644 363--- a/locale/programs/localedef.c 364+++ b/locale/programs/localedef.c 365@@ -108,6 +108,7 @@ void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; 366 #define OPT_NO_WARN 402 367 #define OPT_WARN 403 368 #define OPT_NO_HARD_LINKS 404 369+#define OPT_UINT32_ALIGN 405 370 371 /* Definitions of arguments for argp functions. */ 372 static const struct argp_option options[] = 373@@ -152,6 +153,8 @@ static const struct argp_option options[] = 374 N_("Generate little-endian output") }, 375 { "big-endian", OPT_BIG_ENDIAN, NULL, 0, 376 N_("Generate big-endian output") }, 377+ { "uint32-align", OPT_UINT32_ALIGN, "ALIGNMENT", 0, 378+ N_("Set the target's uint32_t alignment in bytes (default 4)") }, 379 { NULL, 0, NULL, 0, NULL } 380 }; 381 382@@ -242,12 +245,14 @@ main (int argc, char *argv[]) 383 ctype locale. (P1003.2 4.35.5.2) */ 384 setlocale (LC_CTYPE, "POSIX"); 385 386+#ifndef NO_SYSCONF 387 /* Look whether the system really allows locale definitions. POSIX 388 defines error code 3 for this situation so I think it must be 389 a fatal error (see P1003.2 4.35.8). */ 390 if (sysconf (_SC_2_LOCALEDEF) < 0) 391 record_error (3, 0, _("\ 392 FATAL: system does not define `_POSIX2_LOCALEDEF'")); 393+#endif 394 395 /* Process charmap file. */ 396 charmap = charmap_read (charmap_file, verbose, 1, be_quiet, 1); 397@@ -399,6 +404,9 @@ parse_opt (int key, char *arg, struct argp_state *state) 398 /* Do not hard link to other locales. */ 399 hard_links = false; 400 break; 401+ case OPT_UINT32_ALIGN: 402+ uint32_align_mask = strtol (arg, NULL, 0) - 1; 403+ break; 404 case 'c': 405 force_output = 1; 406 break; 407diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c 408index 6c6ebf2dd6..cc02ab82bf 100644 409--- a/locale/programs/locfile.c 410+++ b/locale/programs/locfile.c 411@@ -543,6 +543,9 @@ compare_files (const char *filename1, const char *filename2, size_t size, 412 machine running localedef. */ 413 bool swap_endianness_p; 414 415+/* The target's value of __align__(uint32_t) - 1. */ 416+unsigned int uint32_align_mask = 3; 417+ 418 /* When called outside a start_locale_structure/end_locale_structure 419 or start_locale_prelude/end_locale_prelude block, record that the 420 next byte in FILE's obstack will be the first byte of a new element. 421@@ -620,7 +623,7 @@ add_locale_string (struct locale_file *file, const char *string) 422 void 423 add_locale_wstring (struct locale_file *file, const uint32_t *string) 424 { 425- add_locale_uint32_array (file, string, wcslen ((const wchar_t *) string) + 1); 426+ add_locale_uint32_array (file, string, wcslen_uint32 (string) + 1); 427 } 428 429 /* Record that FILE's next element is the 32-bit integer VALUE. */ 430diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h 431index 3afb0a8d29..46785374e8 100644 432--- a/locale/programs/locfile.h 433+++ b/locale/programs/locfile.h 434@@ -70,6 +70,8 @@ extern void write_all_categories (struct localedef_t *definitions, 435 436 extern bool swap_endianness_p; 437 438+extern unsigned int uint32_align_mask; 439+ 440 /* Change the output to be big-endian if BIG_ENDIAN is true and 441 little-endian otherwise. */ 442 static inline void 443@@ -88,7 +90,8 @@ maybe_swap_uint32 (uint32_t value) 444 } 445 446 /* Likewise, but munge an array of N uint32_ts starting at ARRAY. */ 447-static inline void 448+static void 449+__attribute__ ((unused)) 450 maybe_swap_uint32_array (uint32_t *array, size_t n) 451 { 452 if (swap_endianness_p) 453@@ -98,7 +101,8 @@ maybe_swap_uint32_array (uint32_t *array, size_t n) 454 455 /* Like maybe_swap_uint32_array, but the array of N elements is at 456 the end of OBSTACK's current object. */ 457-static inline void 458+static void 459+__attribute__ ((unused)) 460 maybe_swap_uint32_obstack (struct obstack *obstack, size_t n) 461 { 462 maybe_swap_uint32_array ((uint32_t *) obstack_next_free (obstack) - n, n); 463@@ -275,4 +279,55 @@ extern void identification_output (struct localedef_t *locale, 464 const struct charmap_t *charmap, 465 const char *output_path); 466 467+static size_t wcslen_uint32 (const uint32_t *str) __attribute__ ((unused)); 468+static uint32_t * wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n) __attribute__ ((unused)); 469+static uint32_t * wcschr_uint32 (const uint32_t *s, uint32_t ch) __attribute__ ((unused)); 470+static int wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2) __attribute__ ((unused)); 471+static int wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n) __attribute__ ((unused)); 472+ 473+static size_t 474+wcslen_uint32 (const uint32_t *str) 475+{ 476+ size_t len = 0; 477+ while (str[len] != 0) 478+ len++; 479+ return len; 480+} 481+ 482+static int 483+wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n) 484+{ 485+ while (n-- != 0) 486+ { 487+ int diff = *s1++ - *s2++; 488+ if (diff != 0) 489+ return diff; 490+ } 491+ return 0; 492+} 493+ 494+static int 495+wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2) 496+{ 497+ while (*s1 != 0 && *s1 == *s2) 498+ s1++, s2++; 499+ return *s1 - *s2; 500+} 501+ 502+static uint32_t * 503+wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n) 504+{ 505+ return memcpy (s1, s2, n * sizeof (uint32_t)); 506+} 507+ 508+static uint32_t * 509+wcschr_uint32 (const uint32_t *s, uint32_t ch) 510+{ 511+ do 512+ if (*s == ch) 513+ return (uint32_t *) s; 514+ while (*s++ != 0); 515+ return 0; 516+} 517+ 518 #endif /* locfile.h */ 519diff --git a/locale/setlocale.c b/locale/setlocale.c 520index 7bd27e5398..2f194bad7c 100644 521--- a/locale/setlocale.c 522+++ b/locale/setlocale.c 523@@ -63,35 +63,6 @@ static char *const _nl_current_used[] = 524 525 #endif 526 527- 528-/* Define an array of category names (also the environment variable names). */ 529-const struct catnamestr_t _nl_category_names attribute_hidden = 530- { 531-#define DEFINE_CATEGORY(category, category_name, items, a) \ 532- category_name, 533-#include "categories.def" 534-#undef DEFINE_CATEGORY 535- }; 536- 537-const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = 538- { 539-#define DEFINE_CATEGORY(category, category_name, items, a) \ 540- [category] = offsetof (struct catnamestr_t, CATNAMEMF (__LINE__)), 541-#include "categories.def" 542-#undef DEFINE_CATEGORY 543- }; 544- 545-/* An array of their lengths, for convenience. */ 546-const uint8_t _nl_category_name_sizes[] attribute_hidden = 547- { 548-#define DEFINE_CATEGORY(category, category_name, items, a) \ 549- [category] = sizeof (category_name) - 1, 550-#include "categories.def" 551-#undef DEFINE_CATEGORY 552- [LC_ALL] = sizeof ("LC_ALL") - 1 553- }; 554- 555- 556 #ifdef NL_CURRENT_INDIRECT 557 # define WEAK_POSTLOAD(postload) weak_extern (postload) 558 #else 559