First attempt to link to C code - what am I doing wrong?

Hello everyone,
I’m trying to learn more about Crystal and I’m attempting to use a very simple function from some C code. The C part is adapted from Shared libraries with GCC on Linux - Cprogramming.com

This is on Linux Mint - Crystal 1.11.2

Here’s what I’ve done so far:

My hello.h file:

#ifndef hello_h__
#define hello_h__
 
extern void hello(void);
 
#endif

My hello.c file:

#include <stdio.h>
 
void hello(void)
{
    puts("Hello, I am a test function");
}

My main.c:

#include <stdio.h>
#include "hello.h"
 
int main(void)
{
    puts("This is coming from main");
    hello();
    return 0;
}

All of the above works fine with gcc, etc:

gcc -c -Wall -Werror -fpic hello.c
gcc -shared -o libhello.so hello.o
export LD_LIBRARY_PATH=/tmp:$LD_LIBRARY_PATH
gcc -L/tmp/ -Wall -o test main.c -lhello

Test:

./test 
This is coming from main
Hello, I am a test function

Great! Now the Crystal part - I have the file: use_c_function.cr

@[Link(ldflags: "-L/tmp/")]

lib Hello 
  fun hello : Void
end

Hello.hello

I try to build:

crystal build use_c_function.cr

And get the error:

crystal build use_c_function.cr 
/usr/bin/ld: _main.o0.o: in function `__crystal_main':
/tmp/use_c_function.cr:7: undefined reference to `hello'
collect2: error: ld returned 1 exit status
Error: execution of command failed with exit status 1: cc "${@}" -o /tmp/use_c_function  -rdynamic -L/usr/bin/../lib/crystal -L/tmp/ -lpcre2-8 -lgc -lpthread -levent  -lrt -lpthread -ldl

in my Crystal code I tried using lib hello as well, but that gave me a different error:

crystal build use_c_function.cr 
In use_c_function.cr:3:5

 3 | lib hello 
         ^
Error: expecting token 'CONST', not 'hello'

What am I doing wrong here? Thanks in advance!

@[Link(ldflags: "-L/tmp/")] tells the linker where to look for libraries, but not which library to load for the hello symbol.
It’s customary to call library types with a Lib prefix and in that case the compiler should be able to derive that LibHello relates to -lhello.
So it’ll probably work if you rename Hello to LibHello.
Alternatively, you can explicitly add -lhello to the ldflags.

1 Like

thank you!

For completeness this is what ended up working for me:

@[Link(ldflags: "-L/tmp/ -lhello")]

lib Hello
  fun hello : Void
end

Hello.hello

Unfortunately this did not work:

@[Link(ldflags: "-L/tmp/")]

lib LibHello
  fun hello : Void
end

LibHello.hello

Error:

crystal build use_c_function.cr 
/usr/bin/ld: _main.o0.o: in function `__crystal_main':
/tmp/use_c_function.cr:7: undefined reference to `hello'
collect2: error: ld returned 1 exit status
Error: execution of command failed with exit status 1: cc "${@}" -o /tmp/use_c_function  -rdynamic -L/usr/bin/../lib/crystal -L/tmp/ -lpcre2-8 -lgc -lpthread -levent  -lrt -lpthread -ldl
2 Likes