Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set 2 byte wchar_t output?

The GCC uses a 4-byte wchar_t by default. I can set the option -fshort-wchar to get 2 bytes per wchar_t in the L"string constants". But when I set the compiler option to my source file I get the famous warning message

foo.o uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail

Since I really want 2-byte wchar_t I also want the output to use this variant. Is there any linker option to tell it what I want?

Edit

This warning doesn't inhibit the linker to produce a valid output. But the dozens of false warnings cover other messages.

like image 701
harper Avatar asked Oct 21 '13 08:10

harper


2 Answers

In binutils you can find this error message in bfd/elf32-arm.c as:

"warning: %B uses %u-byte wchar_t yet the output is to use %u-byte wchar_t; use of wchar_t values across objects may fail"

However, if you look further at binutils, you'd realize that the output's wchar_t size is not initialized to 4 anywhere. So what determines the "output wchar_t size"? Actually, the first object given to ld initializes the output attributes. The next objects merge their attributes into it. If you link with gcc/g++, it executes ld internally, so try gcc -v and see how ld is executed. This will give you insight into what internal object files (in addition to your own) it implicitly links into your executable.

For example, linking with gcc (e.g. gcc -v -shared -o libfoobar.so foo.o bar.o) results in invocation of:

ld ... crtbegin_so.o foo.o bar.o crtend_so.o ...

i.e. the following objects are actually linked (in order):

  • crtbegin_so.o (implicitly)
  • foo.o
  • bar.o
  • crtend_so.o (implicitly)

Here's what ld does:

  1. The output attributes set starts off empty.
  2. Merging crtbegin_so.o attributes. Now output attributes contain out_attr[Tag_ABI_PCS_wchar_t] == 4
  3. Merging foo.o attributes. If foo.o was built with -fshort-wchar, then in_attr[Tag_ABI_PCS_wchar_t] == 2 and this will result in a conflict and the warning you're seeing.

If you were to swap crtbegin_so.o and foo.o on the ld command line, you'd get the following warning instead:

ld: warning: android-ndk-r9d/platforms/android-16/arch-arm/usr/lib/crtbegin_so.o uses 4-byte wchar_t yet the output is to use 2-byte wchar_t; use of wchar_t values across objects may fail

As you can see, it's not a matter of incompatibility of the input with the output, but rather (perceived) incompatibility between two object files linked together.

What can we do about it?

  • As of 2008, ld supports the --no-wchar-size-warning flag to suppress this warning. But as you said, indiscriminately suppressing warnings has its drawbacks.

  • You can rebuild your toolchain with -fshort-wchar.

  • You can strip the Tag_ABI_PCS_wchar_t tags from your internal gcc object binaries if you truly believe they're sizeof(wchar_t)-agnostic. This might be easier than rebuilding your toolchain. For that, you can use this utility I once wrote. (You might need to unpack libgcc.a, change its object files and repack it.)

like image 177
Ilya Avatar answered Nov 15 '22 11:11

Ilya


That's a warning, not error. You can ignore it but that will cause problems if you link against others libraries that were compiled with 4-byte wchar_t. If you must use 2-byte wchar_t then you'll have to find a replacement for those libraries or recompile them

You may also try -fwide-exec-charset=UTF-16

  • -fwide-exec-charset=charset
    • Set the wide execution character set, used for wide string and character constants. The default is UTF-32 or UTF-16, whichever corresponds to the width of wchar_t. As with -fexec-charset, charset can be any encoding supported by the system's iconv library routine; however, you will have problems with encodings that do not fit exactly in wchar_t.

If you have C11 support you can just use char16_t (with the u prefix for string literals) and convert to wchar_t when necessary

like image 37
phuclv Avatar answered Nov 15 '22 10:11

phuclv