/*
 * This program checks to see if a Tcl extension shared lib
 * stub enabled, which means the extension uses functions
 * from the stub table and does not reference any global
 * Tcl variables. This is important since we want to
 * be able to load Tcl and its extensions into another
 * process space without having to link the extension to
 * a specific version of Tcl or use RTLD_GLOBAL when
 * opening the Tcl shared library. Note that this checker
 * could return a false positive if the extension
 * is linked to a specific Tcl shared library.
 *
 * Example:
 *     % ./tcl_stub_checker /build/tcl/libtcl8.3g.so \
 *         /build/thread/libthread2.4g.so
 *     /build/thread/libthread2.4g.so: dlopen:
 *       `/build/thread/libthread2.4g.so: undefined symbol: tclEmptyStringRep'
 *
 * The above result indicates that the extension is not
 * fully stub enabled since it makes use of the global
 * symbol "tclEmptyStringRep" defined in the Tcl shared library.
 */

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <dlfcn.h>
#include <ctype.h>

main (int argc, char **argv)
{
  void *handle;
  char *tcllib, *extlib;
  int mode = RTLD_NOW;

  if (argc != 3) {
    fprintf (stderr, "usage: %s tcllib extlib\n", argv[0]);
  }

  tcllib = argv[1];
  extlib = argv[2];

  handle = dlopen (tcllib, mode);
  if (handle == NULL)
  {
    fprintf (stderr, "%s: dlopen: `%s'\n", tcllib, dlerror ());
    exit (1);
  }

  handle = dlopen (extlib, mode);
  if (handle == NULL)
  {
    fprintf (stderr, "%s: dlopen: `%s'\n", extlib, dlerror ());
    exit (1);
  }

  dlclose (handle);

  printf("Extension lib %s is ok\n", extlib);
  return 0;
}
