Tclobj - Using C++ Objects with Tcl =================================== This text addresses the configuration and compilation of the `tclobj' package and various system-specific aspects. For an introduction to and tutorial of its interfaces, see the Postscript document in the doc/ subdirectory. Requirements ------------ o A fully installed and operative installation of Tcl, Version 7.5 or above. o An ANSI-compatible C compiler and a ``matching'' C++ compiler. Both compilers should be fom the same vendor, using gcc but a custom C++ compiler will probably fail. o gcc and g++ are highly recommended. o The package makes much more fun on a system that supports dynamic loading. See below. Supported Systems ----------------- Unfortunately, dynamic loading is quite system-dependent. See below for an extensive discussion. Static linking is possible on all systems. Dynamic loading has so far been tested to work on: o Linux/Elf, i386, gcc/g++ o Digital Unix, DECalpha, gcc/g++ o SunOS 5.x, Sparc, gcc/g++ o HP-UX 10.x, HPpa, gcc/g++ or c89/CC o Ultrix 4.x, MIPS, gcc/g++ I hope you can make this list grow ... Configuration ------------- The package comes with an autoconf script that tries to determine the system configuration. The script needs to know some details, in particular of your Tcl installation. There are various parameters to the configuration script if it doesn't manage to find the various files by itself. --with-tclsh=dir Gives the location of an executable tclsh. Can either point to a directory to find the program in, or the executable itself. --with-tcl-include=dir The directory where to find --with-tcl-lib=dir The directory where to find the static or shared Tcl library. --with-tcl-config=file The tclConfig.sh file with Tcl's configuration data (created during Tcl's ./configure run and usually installed in the lib directory). --with-tcl-appinit=file The tclAppInit.c sourcecode. Needed in some cases to build a custom tclsh. --with-tcl=dir Find all of the above below this directory. You can just point this parameter to the Tcl distri- bution directory, but the script also looks for the `bin', `include' and `lib' directory below this dir (for example: --with-tcl=/usr/local). --disable-hacks The script knows a few tricks to make dynamic loading work on various systems. This option stops the script from trying them. See below. --disable-dynamic If the configuration script completely freaks out on you while checking for dynamic linking support, you can use this option to enforce static linking. You can also set the following environment variables to override the script's selection. CC Your C compiler CXX Your C++ compiler LDSO How to link shared libraries LDLIBS Linker options when linking shared libraries. CPICFLAGS Flags to the compiler when compiling files into shared libraries. The script first tries to configure tclobj for build into a dynamically loadable library, and whether such a configuration would work. Yet this is a highly system-dependent task. The configuration script has a few tricks to play, especially if you are running gcc and g++, but the author only has access to a limited number of systems, and no doubt the script will fail to determine the correct parameters on many others. As last resort, there is always the possibility to compile the package as static library; this would force you to later statically link the package and all of your classes into a custom tclsh. And this would be a pity, because dynamic loading of new classes is a very desirable feature. But what's the catch? On many systems, code must be compiled for position-independence in order to be dynamically loadable. Unlike an executable, which always loads to the same fixed address in memory, the position a dynamic module is loaded to depends on the other memory already used by the same process. This is not yet a problem, there is always a compiler option to do the job (-fPIC for gcc). The problems start when we compile C++ code into dynamically loadable modules. C++ code needs a few external hooks, which are usually provided by some external library. For example, when using g++, the `new' operator invokes the external procedure __builtin_new, which is linked to an exe- cutable from the `libgcc.a' library from your gcc distribution. If you do not use g++ but some custom compiler, chances are that this step is just the same: the names of the hooks will be different, and they are provided by some system-specific libraries. This business is usually hidden from your view, but it becomes relevant now, because the libraries which provide the hooks are usually not com- piled for position-independance! So if you have a C++ module, you can either link it into a shared library together with the hooks, meaning that the module won't be loadable due to non-PIC code, or you can not link it with the hooks, in which case the module won't be loadable due to unresolved references. Duh. Fine alternative. However, there are a few workarounds, which the configuration script checks for. Yet the problem it faces is a substantial one, and the script's knowledge is limited. If it fails to find the optimal solution for your system, you may either have to live with static linking, or to hack the Makefile yourself. The author is no expert on shared libraries. What I know, I have learned from experience. I only have experience on a limited number of systems, and do not know about the many problems that this package has to face on others. If you think you can improve the behaviour on some system, let me know. Strategies ---------- The script tries to categorize your system. At the end of its run, it emits a ``warning'' stating the strategy it tries to use. It knows of the following strategies: 1.) No hooks necessary On some systems, the C++ hooks are available by default and need not be linked in from an external library. This saves us of the bother of finding out how to provide the functions to a shared library ourselves, and makes our job as straight- forward as can be. Examples: Linux/ELF 2.) Using gcc/g++ When working with g++, we can cheat by linking in the two object files _eprintf.o and _builtin.o, which provide the necessary functions, mirroring the behaviour of the originals. These two files we can compile for position-independence, thus having all we need. All other subsequently loaded modules can also profit from these exported hooks and don't need to link them in again (making the build of classes as easy as in the first case). Examples: Digital Unix, SunOS 5.x, Ultrix, HP-UX using gcc/g++ 3.) Using gcc/g++, if _builtin.o does not seem to help. Another solution is to statically link the necessary hokks with the ``parent application'', the tclsh. This strategy extracts the complete contents of libgcc.a, and forces a custom tclsh (branded ``tclobjsh'' to link with all of them. The hooks are then available to all loaded modules. A drawback is that you will have to perform the same trick manually with your wish, should you want to work with X-based applications. A different solution would be to recompile libgcc.a as a shared library. You can hack gcc's Makefile to make it build only this library, compiling the files for position-independence. I have tried this option myself, and it works, but you need to know the right places where to tweak the Makefile ... (this option is not supported) Examples: none known at the moment 99.) Special HP-UX hack On HP-UX, we can work around the problem using the native compilers `c89' and `CC', because their necessary C++ hooks are available as shared library. The trick is that some additional data is required (the cxxhead.o module from /lib/libcxx.a), which we link with the tclobj code. However, the CC compiler, at least in our installation, sucks and can't even compile most example programs. If you prefer living with gcc (and a custom tclsh), use ``configure --disable-hacks'' 0.) Other Systems On other systems, you still have the option of dropping the support for dynamic loading. It hurts, but the main features of the package (using C++ objects from Tcl, remember) still works. Tclobj and all classes will be built into plain old-style libraries (`libtclobj.a'). You will then have to set up your own main function, following the template in tclAppInit.c (from the Tcl distribution), calling the necessary Initialization procedures of all required classes. Then, compile your main file, and link it statically with libtclobj.a and your classes. Examples: none known at the moment The last is the option the configuration script escapes to if it can't make sense of your system with its limited knowledge. But by reading the information about the other strategies, and by some experimentation, you may still get dynamic loading to work. For example, if you do not run gcc/g++, the library that defines the C++ hooks is named differently, but the general trick may still work, so you could just find out what the library is, and then follow the above instructions. With some `hacking', you can still make it work! Good luck! Installation ------------ No installation necessary. There is no ``make install'' yet. If you insist on a global installation, copy the files `tclobjconf.sh', `libtclobj.so' and `tclobj.h' to a directory of your choice. Notes ----- o Mixing code from different C++ compilers will usually not work, because they may implement some internal behaviour differently, for example v-tables. o If you keep receiving "unresolved external" messages when trying to load a class in Tcl, but do not get a list of _what_ symbols are missing, you may want to modify Tcl's module loading code. For example on HP-UX, you can add BIND_VERBOSE to the shl_load() call in unix/tclLoadShl.c o There seems to be a bug in libg++ 2.7.0. If you get an unresolved external of `strchr', you should upgrade libg++ to at least 2.7.1, or you can work around the problem by changing #include at the top of tclobj.cc to `#include "/usr/include/string.h"'. o You will have some fun if you try to use external non-shared libraries. You will either have to recompile them with the proper options for position-independence, or you can perform the same trick as in strategy #3, statically linking the library's contents with a custom tclsh (growing it beyond measure). o ELF systems seem to be able to load shared libraries that have not been compiled for position-independence. However, it seems that this may cause problems if the shared library is mapped more than once, hence this option is discouraged and not supported by default. o I have not yet managed to make the package work on AIX using gcc/g++. Neither dynamic loading nor static linking wants to work; the linker cannot resolve Tcl_Object's virtual table. Maybe the native compiler works, but we have no license to try it. Mailing List ------------ I have set up a mailing list for tclobj, intended to provide a means of information exchange, or for announcements, should you want to make your Tcl-supporting classes publicly available. To subscribe, send mail to `tclobj-request@belle.fpp.tm.informatik.uni-frankfurt.de' with a subject of `subscribe'. This mailing list is operated on an offline system that polls mail roughly twice a day, so don't be surprised if response time is slow. Examples -------- After compiling the Tclobj module, you can run configure and make in the `example' subdirectory. It uses the pre-determined configuration values stored in tclobjconf.sh and should work quite effortlessly. On systems that do not support dynamic loading (strategy `0' above), the files are built into static libraries, and you will have to link them into an executable tclsh in order to test them. The last example, `tclftp' is not built by default, because you probably don't have the socket++ library installed (which also needs the patch from the end of tclftp.c). You will also run into the problem that libsocket++ is usually not compiled for position-independence. You will have to recompile the library as PIC to make tclftp loadable. Credits ------- Thanks to Jan Nijtmans for hints and advice and his implementations of gcc's internal functions (_eprintf.c, _builtin.c). ------------------------------------------------------------ Frank Pilhofer fp@informatik.uni-frankfurt.de