3

I want to call Rust from GnuCOBOL. I've copied the code from the first example in Can GnuCOBOL interface with Rust? from Brian Tiffin's GNUCobol FAQ as a test but got an error when running it.

Expected:

$ make -B
rustc --crate-type=dylib called.rs
LD_RUN_PATH=. cobc -xj caller.cob -L. -lcalled
:Hello, world:

Actual:

$ make -B
rustc --crate-type=dylib called.rs
LD_RUN_PATH=. cobc -xj caller.cob -L. -lcalled
libcob: error: module 'hello_rust' not found
make: *** [makefile:5: caller] Error 1

I get the same error after compiling both files from the command line, then using $ ./caller.

The syntax seems correct based on the cobc man page and the linkage sections of the GnuCOBOL manual and Rust reference. I've tried $ ./caller COB_LIBRARY_PATH=. as described in the GnuCOBOL manual, but it doesn't make a difference. The Rust source compiles to a library as expected, but the COBOL doesn't find it.

Using $ cobcrun caller instead displays libcob: error: module 'caller' not found.

This question about a similar error is about statically linking multiple COBOL source files, which works fine, and this question about a similar error seems to be an issue with X"AF", which isn't used here. Statically linking C source with Jay Moseley's C Wrapper for Calling Library Function example works as expected. Statically linking Rust source isn't supported.

Software Versions:

  • Ubuntu 22.04.1 LTS
  • cobc (GnuCOBOL) 3.1.2.0
  • rustc 1.64.0
Joseph E
  • 33
  • 7

1 Answers1

5

The issue seems to be that the COBOL caller executable is trying to dynamically load a library named hello_rust.so instead of libcalled.so at runtime.

  • The easy fix without modifying anything is to just create a symlink:

    $ ln -s libcalled.so hello_rust.so
    
  • Alternatively, adding -fstatic to the cobc command should statically link the Rust library at compilation, eliminating the dynamic library runtime calls.

    The example Makefile can be updated to look like this:

    # GnuCOBOL and Rust
    .RECIPEPREFIX = >
    
    caller: caller.cob libcalled.so
    > LD_RUN_PATH=. cobc -fstatic -xj caller.cob -L. -lcalled
    
    libcalled.so: called.rs
    > rustc --crate-type=dylib called.rs
    

For reference, we can investigate what the executable is doing via strace to see what system calls the COBOL runtime is making -- and in our case -- what files it's failing to find.

$ strace ./caller 2>&1 | grep hello_rust                                                                                                                                         
access("./hello_rust.so", R_OK)         = -1 ENOENT (No such file or directory)
access("/usr/lib64/gnucobol/hello_rust.so", R_OK) = -1 ENOENT (No such file or directory)
write(2, "module 'hello_rust' not found", 29module 'hello_rust' not found) = 29
Josh Bowden
  • 5,735
  • 2
  • 25
  • 36
  • 1
    Perfect answer. Two additions for static calls/linking: you can make any specific call static if doing `CALL STATIC "prog"` - this has the benefit that you can decide in the code what's done. And _very likely_ that whole part would not be needed - because the library was specified at link time - if you tell the system linker to not drop references that are not directly used, which should be `-Q -Wl,--no-as-needed`. Another option would be to let the COBOL runtime pre-load the module with `COB_PRE_LOAD=libcalled ./hello_rust`. – Simon Sobisch Oct 15 '22 at 09:31