没有实现 class 程序定义

No realize class procedure defined

我只想分享我是如何找到错误的解决方案的

No realize class procedure defined

当 运行 一个 X/Motif C 应用程序时。我发布这个是因为我在网上搜索时只找到一个关于这个问题的参考,而且它没有包含解决方案。

我设法解决了这个问题,如果您再次遇到这个问题,我想分享我的发现(注意:我并不是说我的解决方案会 总是解决这类错误)。

问题

我在 运行 使用 Motif 和 X Intrinsics 工具包的简单 C 程序时发现了这个问题。

$ gcc -Wall -c push.c
$ gcc -Wall -o push push.o -lXt -lXm
$ ./push
Error: No realize class procedure defined

C 源代码如下:

#include <stdio.h>
#include <Xm/Xm.h>
#include <Xm/PushB.h>

/* Prototype Callback function */
void pushed_fn(Widget, XtPointer, XmPushButtonCallbackStruct *);

int main(int argc, char **argv)
{
  Widget top_wid, button;
  XtAppContext  app;
  Display* display;

  XtToolkitInitialize();
  app = XtCreateApplicationContext();
  display = XtOpenDisplay(app, "localhost:10.0","push","push", NULL,0, &argc,argv);
  top_wid = XtAppCreateShell(NULL, "Form", applicationShellWidgetClass, display, NULL, 0);

  button = XmCreatePushButton(top_wid, "Push_me", NULL, 0);

  /* tell Xt to manage button */
  XtManageChild(button);

  /* attach fn to widget */
  XtAddCallback(button, XmNactivateCallback, (XtCallbackProc) pushed_fn, NULL);

  XtRealizeWidget(top_wid); /* display widget hierarchy */
  XtAppMainLoop(app); /* enter processing loop */
  return 0;
}

void pushed_fn(Widget w, XtPointer client_data, XmPushButtonCallbackStruct *cbs)
{
  printf("Don't Push Me!!\n");
}

我怀疑问题可能出在 libXt 上,因为 XtRealizeWidget 符号是在该库中定义的。我用 nm 查看了它,但一切似乎都很好:

$ nm -D /usr/lib/libXt.so |grep XtRealizeWidget
02b39870 T XtRealizeWidget

"T"表示符号在组成libXt库的目标文件的文本(代码)部分,所以定义了这个符号。系统库的路径也是正确的,我只有一个版本的 libXt。

然后我认为库传递给 gcc 链接器的顺序可能是原因并开始阅读它,最后看到这个 Whosebug thread

将库的顺序切换为:

$ gcc -Wall -o push push.o -lXm -lXt

问题已解决。

注意库和传递给链接器的顺序!

Martin Simmons的回答(摘自LessTif FAQ):

The linking order problems are caused by these two symbols:

vendorShellClassRec
vendorShellWidgetClass

which are defined AND referenced in both -lXm and -lXt. Somehow you have to convince the linker to use the -lXm definitions to satisfy the references in both -lXm and -lXt. The -lXt definitions should not be used. For typical elf-based dynamic loaders (Linux, Solaris etc), this is done by passing '-lXm -lXt' to the linker, which adds them both as SO_NEEDED sections to the executable. At runtime, the dynamic loader collects symbols from each SO_NEEDED section in the order it finds them, discarding symbols it already knows, and then fixes the references in all the loaded libraries using that combined symbol table. For typical static linkers, it is also done by specifying '-lXm -lXt' to the linker. In this case, the linker extracts some .o's from -lXm which contain user-referenced symbols and eventually ends up extracting -lXm:Vendor.o due to internal references in -lXm. It then does the same for -lXt, but doesn't need to extract -lXt:Vendor.o because it doesn't define anything that is still undefined.