One interesting thing of using chroots to check things out is that often enough you stumble across different corner cases when you get to test one particular aspect of packages.
It might some funky, but it has been common knowledge for a while that
gcc -O0 sometimes produced bad code, and sometimes it failed to build some packages. Unfortunately it’s difficult to track it down to specific problems when you’re “training” somebody in handling the compiler. Today, I found one of these cases.
I was going to merge sys-block/unieject in my flagstesting chroot so I could make sure it worked properly, for this, it needed dev-libs/confuse, which I use for configuration files parsing. All at once, I found this failure:
i686-pc-linux-gnu-gcc -DLOCALEDIR="/usr/share/locale" -DHAVE_CONFIG_H -I. -I. -I.. -Wall -pipe -include /var/tmp/portage/dev-libs/confuse-2.6-r1/temp/flagscheck.h -MT confuse.lo -MD -MP -MF .deps/confuse.Tpo -c confuse.c -fPIC -DPIC -o .libs/confuse.o confuse.c: In function 'cfg_init': confuse.c:1112: warning: implicit declaration of function 'setlocale' confuse.c:1112: error: 'LC_MESSAGES' undeclared (first use in this function) confuse.c:1112: error: (Each undeclared identifier is reported only once confuse.c:1112: error: for each function it appears in.) confuse.c:1113: error: 'LC_CTYPE' undeclared (first use in this function) make: *** [confuse.lo] Error 1 make: Leaving directory `/var/tmp/portage/dev-libs/confuse-2.6-r1/work/confuse-2.6/src' make: *** [all-recursive] Error 1 make: Leaving directory `/var/tmp/portage/dev-libs/confuse-2.6-r1/work/confuse-2.6' make: *** [all] Error 2
This was funny to see as I did merge confuse lately on my main system on Yamato, and I do have nls enabled there, too. It didn’t fail, so it’s not even a glibc cleanup-related failure.
Time to dig into the code, where is
setlocale used in confuse?
#if defined(ENABLE_NLS) && defined(HAVE_GETTEXT) setlocale(LC_MESSAGES, ""); setlocale(LC_CTYPE, ""); bindtextdomain(PACKAGE, LOCALEDIR); #endif
As I used this before, I know that
setlocale() function, but usually it’s included through gettext’s own
libintl.h header file, so where is that included? A common problem here would be to have different preprocessor tests between the include and the use so that one is applied but not the other.
#if defined(ENABLE_NLS) && defined(HAVE_GETTEXT) # include # define _(str) dgettext(PACKAGE, str) #else # define _(str) str #endif #define N_(str) str
It seems to be entirely fine, the only problem would be if
libintl.h didn’t include
locale.h, but why would it then work on the rest of the rest of the system?
The focal point here is to check why
locale.h in one place and not the other. Let’s then look at the file itself:
/* Optimized version of the function above. */ #if defined __OPTIMIZE__ && !defined __cplusplus [...] /* We need LC_MESSAGES for `dgettext'. */ # include [...] #endif /* Optimizing. */
So not for any kind of assurance, but just because there’s a technical need,
libintl.h brings in the declaration of
setlocale(), and only if you have optimisations enabled. Guess what? my chroot has no optimisations enabled, as I don’t need to execute the code, but just build it.
The fix here is very easy, just include
locale.h explicitly; I’ll be sending a patch upstream and submitting one to Gentoo, but it puts an important shadow over the correctness of Free Software when building with optimisations disabled. I suppose this is one other thing that I’ll be testing for in the future, in my checklist.