收到“警告:字符串到字体集转换中缺少字符集”

收到“警告:字符串到字体集转换中缺少字符集”

我通过 SSH 连接使用 X 应用程序到某台机器。当我运行 X 应用程序时,xclock为了简单起见,我收到一条控制台消息,内容是:

Warning: Missing charsets in String to FontSet conversion

...但应用程序可以运行。我的语言环境是:

$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

现在我发现这个老建议只需设置export LC_ALL=C。这样就行了,错误消息消失了。但是,我真的不想这样更改我的语言环境!

我可以做些什么来避免错误并保持我的语言环境?

附加信息:

  • X 服务器是 MobaXterm 在 Windows 上集成的 X 服务器。
  • 远程机器是 SLES GNU/Linux 11(由 SUSE 提供)。

答案1

你说得对,你不想这样更改你的语言环境!我发现了类似的建议,并选择了兔子洞。

单个语言环境变量可以改变是LC_CTYPE=C(这是字符分类设置,请参见POSIX第七条,区域设置了解详情)。

我认为这里的主要问题是旧的 X 程序与当代的多字节/多语言环境系统存在一些与字体相关的小问题。

我自己的语言环境,在桌面 X Org 上(Mobaterm 在后台使用 X Org)是(通过en_IE.utf映射到文件)。在en_US.UTF-8/XLC_LOCALE/usr/share/X11/locale/locale.dirXLC_LOCALE 文件字体集字符集定义,其中一些定义的存在(往往)会触发警告(特别是对于我不使用且字体覆盖范围不广的西里尔字母和亚洲编码)。

我从一些程序中得到几个错误,例如xfig

Warning: Missing charsets in String to FontSet conversion
Warning: Missing charsets in String to FontSet conversion
Warning: Unable to load any usable fontset

注释掉各种不需要的fsNcsN条目将解决这个问题(每个索引 N 定义一个匹配的字体集/字符集对,保持这种配对注意每对相隔约 200 行)。这可能会影响某些文本的呈现。或者,LC_CTYPE=C在开始之前进行设置xfig会删除所有警告。

这些警告是由XtCvtStringToFontSet()(libXt) 发出的,原因是XCreateFontSet()报告缺少的字符集(即语言环境使用/要求的字符集,但在符合请求的规范的字体中未找到)。

XCreateFontSet()返回缺失字符集列表,但 libXt 不会输出请求或缺失字符集的详细信息来帮助您进行追踪。(我使用LD_PRELOAD包装器.soXCreateFontSet()查找罪魁祸首,见下文。)

真正的问题是字体规范(例如“--helvetica-medium-r-normal--16-------“) 会检查文件中设置的所有编码XLC_LOCALE,如果找不到某些编码,则会看到这些警告。如果根本找不到任何编码,您也会看到“警告:无法加载任何可用的字体集”。

然后进行一些修复:

  1. 设置LC_CTYPE=C(或其他“简单”编码,例如en_US)错误程序
  2. 从有效的 XLC_LOCALE 文件(语言环境)中删除不需要的字体集/字符集对,此操作无需重新启动 X 或桌面即可生效
  3. 安装更多字体和编码(有点像打地鼠游戏)
  4. 设置更宽容的应用程序字体规格(通过 xrdb 或命令行)
  5. 设置更宽松的默认字体规格(通过 xrdb)

您可能需要最后两个修复,因为如果任何默认字体在检查时与编码不匹配,就会发出警告,即使后续字体足够。

最后一个问题是,某些后备字体规范可能会继续引发该问题。具体来说,硬编码的 Xt 默认值为:

-*-*-*-R-*-*-*-120-*-*-*-*,*

可能会完全失败并触发相同的警告。一些快速测试表明,不包含系列(仅包含单个“*”)的字体规范可能无法匹配任何内容,即使预期匹配也是如此,即:

xlsfonts -fn "*-*-*-R-*-*-*-120-*-*-*-*"

并且添加结尾的“,*”作为完整通配符可能会破坏原本可以正常工作的字体规范。在 X Org 1.18.3 上观察到。

我在我的中使用它.Xdefaults

XtDefaultFontSet: -*-fixed-medium-r-normal--16-*-*-*-*-*-*-*,-*-fixed-*-*-*--16-*,-*-*-medium-*-*--16-*

这似乎让我的大多数事情都保持安静,不需要XLC_LOCALE进行任何更改。此回退设法匹配我不知何故积累的各种字体中请求的每个编码...


这是我用来帮助追踪请求的内容(因为它通常只在应用程序源中定义)和未找到的内容的非常简单的包装器(带有最少的错误检查)。在 x86_64 Slackware 上测试,其他发行版/系统可能需要进行微小调整。

gcc -fPIC -shared -Wl,-soname,xfontset.so -ldl -o xfontset.so xfontset.c

然后

LD_PRELOAD=$PWD/xfontset.so xfig

从编译它的目录中运行它。

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <link.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
    
#include <X11/Xlib.h>
    
#define DEBUG 1
#define dfprintf(fmt, ...) \
    do { if (DEBUG) fprintf(stderr, "[%14s#%04d:%8s()] " fmt, \
          __FILE__, __LINE__, __func__,##__VA_ARGS__); } while (0)
    
// gcc -fPIC -shared -Wl,-soname,xfontset.so -ldl -o xfontset.so xfontset.c

// see X11/Xlib.h
typedef XFontSet XCreateFontSet_fp(
  Display *display,
  _Xconst char *base_font_name_list, 
  char ***missing_charset_list_return, 
  int *missing_charset_count_return, 
  char **def_string_return
);
    
static XCreateFontSet_fp *real_XCreateFontSet;
    
void myinit(void) __attribute__((constructor));
    
void myinit(void)
{
    void *dl;
    if ((dl=dlopen(NULL,RTLD_NOW))) {
        dfprintf("found dl at %p ()\n", dl);
    
        real_XCreateFontSet=dlsym(RTLD_NEXT,"XCreateFontSet");
        if (!real_XCreateFontSet) dfprintf("error: %s\n",dlerror());
        dfprintf("found fn() at %p\n", (void *)real_XCreateFontSet);
    } else {
        dfprintf("dlopen() failed...\n");
    }
}
    
// https://www.debian.org/doc/manuals/intro-i18n/ch-examples.en.html
// https://invisible-island.net/xterm/xtoolkit/intrinsics.html
    
XFontSet XCreateFontSet(Display *display, _Xconst char *base_font_name_list, char ***missing_charset_list_return, int *missing_charset_count_return, char **def_string_return)
{
     XFontSet rc;
     int fnum,ii;
     XFontStruct **xfonts;
     char **font_names;
    
     dfprintf("wrapped XCreateFontSet()\n");
     dfprintf(" base_font_name_list: <%s>\n",base_font_name_list);
    
     rc=real_XCreateFontSet(display, base_font_name_list, missing_charset_list_return,missing_charset_count_return, def_string_return);
    
    if (*missing_charset_count_return) {
        int ii=0;
        dfprintf(" #missing charsets: %i\n",*missing_charset_count_return);
    
        for (ii=0; ii<*missing_charset_count_return; ii++) {
            dfprintf(" %2i: <%s>\n",ii, (*missing_charset_list_return)[ii]);
        }
    }
    if (rc) {
        fnum=XFontsOfFontSet(rc,&xfonts,&font_names);
        for (ii=0; ii<fnum; ii++) {
            dfprintf(" XFontSet[%2i]=<%s>\n",ii,font_names[ii]);  
        }
    } else {
        dfprintf("no FontSet found...\n");
    }
    return rc;
}

相关内容