TCL extensions that are interdependent

My question is a bit like this , but this is about TCL extensions.

I use C on Linux (gcc), and I have a package with three modules A, B and C. Module A contains functions and also defines (not only declare) global variables. I compile and link module A with a dynamic library (libA.so).

Now I want B and C to be TCL extensions. Both use functions and global variables from A, and C also uses functions from B. I created a common library B and C (B.so and C.so), but without using "-Wl -soname". I made B.so dependent on A.so, while C.so has no dependencies between users. Although this is strange, bot extensions are loaded and working correctly. Here is what I have (A = libbiddy.so, B = bddscout.so, C = bddscoutIFIP.so):

meolic@meolic :/usr/lib/bddscout$ ldd *.so bddscout.so: linux-gate.so.1 => (0x00177000) libbiddy.so.1 => /usr/lib/libbiddy.so.1 (0x00eca000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00342000) /lib/ld-linux.so.2 (0x0061f000) bddscoutIFIP.so: linux-gate.so.1 => (0x00fc2000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000) /lib/ld-linux.so.2 (0x00c75000) meolic@meolic :/usr/lib/bddscout$ wish % puts $tcl_patchLevel 8.5.8 % load ./bddscout.so % load ./bddscoutIFIP.so % info loaded {./bddscoutIFIP.so Bddscoutifip} {./bddscout.so Bddscout} {{} Tk} 

The problem is that the exact same package does not work everywhere. The C.so extension does not load on the new computer.

 meolic@altair :/usr/lib/bddscout$ ldd *.so bddscout.so: linux-gate.so.1 => (0xb76ef000) libbiddy.so.1 => /usr/lib/libbiddy.so.1 (0xb76c9000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb754d000) /lib/ld-linux.so.2 (0xb76f0000) bddscoutIFIP.so: linux-gate.so.1 => (0xb7780000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75e8000) /lib/ld-linux.so.2 (0xb7781000) meolic@altair :/usr/lib/bddscout$ wish % puts $tcl_patchLevel 8.5.10 % load ./bddscout.so % load ./bddscoutIFIP.so couldn't load file "./bddscoutIFIP.so": ./bddscoutIFIP.so: undefined symbol: biddy_termFalse 

The reported undefined character is one of the global variables from A. Question1: is my approach correct because it works on some systems? Question2: why it does not work in the new system?

+4
source share
1 answer

The Tcl load command uses dlopen() under covers (on Linux, it differs on other platforms, of course) and uses it with the RTLD_LOCAL flag; characters in the library are not exported to other applications. Because of this, unrelated characters in one dynamically loaded library will not resolve against another; it improves isolation, but makes you do more work so that everything does the right thing, where you want it to really exist.

Your options:

  • If libscoutIFIP.so depends on libbiddy.so characters, notify the linker when creating the library, and the dynamic linker mechanism sorts everything so that the dependency does not load several times. That is, if a library depends on a symbol in another library, it must explicitly indicate this library as a dependency.
  • Arrange libbiddy.so to export its characters as a stub table (i.e., function / variable pointer structures) via the Tcl package API ( Tcl_PkgProvide() ). Then, when libscoutIFIP.so does Tcl_PkgRequireEx() in the biddy package, it will get a pointer to this stub table and can use the links inside it instead of the direct link. This is how the Tcl jamming mechanism works, its awesome and portable interface and makes it pretty difficult to control API versions (if necessary). It is a bit more work to set up, though. The Tcler Wiki goes much deeper in this matter.

If option 1 works for you, go with it; for Linux code, which should be fine, since the system dynamic linker is not desperately tight (unlike the situation on Windows).


[EDIT]: Note that older versions of Tcl (prior to 8.5.9) used RTLD_GLOBAL . It seems that this change should be marked as ***POTENTIAL INCOMPATIBILITY*** in the release notes and is more widespread. Apologies on behalf of the Tcl developers.

+6
source

Source: https://habr.com/ru/post/1383943/


All Articles