Ocaml/C interop using bigarray: 'undefined symbol: caml_ba_alloc' - c

I'm trying to compile a 'Hello World'-level Ocaml/C interop program that uses bigarray. I'm getting an error about undefined symbol: caml_ba_alloc (details below). It seems like it should be provided by bigarray.h.
Here are my files:
wrap_mylib.c:
#include <caml/bigarray.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
CAMLprim value caml_fn(value x) {
float* result = malloc(sizeof(float));
long dims[] = {1, 1};
return caml_ba_alloc(CAML_BA_NATIVE_INT, 2, result, dims);
}
mylib.ml:
external ext_caml_fn : int -> (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array2.t
= "caml_fn" ;;
Makefile:
wrap_mylib.o: wrap_mylib.c
gcc -c wrap_mylib.c
another_wrapper.so: wrap_mylib.o
cc -shared -o another_wrapper.so wrap_mylib.o
mylib.mli: mylib.ml
ocamlc -i $< > $#
mylib.cmi: mylib.mli
ocamlc -c $<
mylib.cmo: mylib.ml mylib.cmi
ocamlc -c $<
mylib_test: mylib.cmo another_wrapper.so
ocamlc -linkall -o mylib_test mylib.cmo another_wrapper.so
clean:
rm *.cma *.cmo *.cmi *.cmx *.cmxa *.mli *.o *.a *.so
Here is the output when I try to compile mylib_test:
$ make mylib_test
ocamlc -i mylib.ml > mylib.mli
ocamlc -c mylib.mli
ocamlc -c mylib.ml
gcc -c wrap_mylib.c
cc -shared -o another_wrapper.so wrap_mylib.o
ocamlc -linkall -o mylib_test mylib.cmo another_wrapper.so
File "_none_", line 1:
Error: Error on dynamically loaded library: ./another_wrapper.so: ./another_wrapper.so: undefined symbol: caml_ba_alloc
Makefile:17: recipe for target 'mylib_test' failed
make: *** [mylib_test] Error 2
Environment
OS: Ubuntu 18.04.2 LTS (Bionic Beaver)
$ ocaml --version
The OCaml toplevel, version 4.05.0
Thank you!

Files like bigarray.h define things that are useful at compile time. But your problem is a link-time problem. You need to find the library that contains the function you're looking for and include it in the link step.
If I use ocamlopt (native code implementation) and use ordinary object files (OCaml .cmx and C .o) rather than a shared library, I can get things to link up like this:
$ ocamlopt -c mylib.ml
$ gcc -I $(ocamlc -where) -c wrap_mylib.c
$ ocamlopt -o mylib_test wrap_mylib.o mylib.cmx
This produces an executable mylib_test that I can run:
$ ./mylib_test
$
Of course nothing happens when I run the executable because there is no top-level code in your file mylib.ml. So this is just testing whether things will link up OK.
I hope this is helpful.

Answering my own question. Here's how I was able to get it to work. Compile mylib_test by linking bigarray.cma:
ocamlc -linkall -o mylib_test mylib.cmo another_wrapper.so bigarray.cma
Then run with:
LD_LIBRARY_PATH=. ./mylib_test
The LD_LIBRARY_PATH=. is necessary for it to find the shared library another_wrapper.so in the same directory.
According to https://caml.inria.fr/pub/docs/manual-ocaml/libbigarray.html bigarray is now part of the standard library and so linking bigarray.cma should only be necessary when using the legacy compatibility library. Possibly my version of the standard library is old.

Related

Undefined reference when using ta-lib/ta_lib.h file and Makefile

I want to use the ta_lib functions in my C code and am trying to import the ta_lib functions. The header file gets imported correctly but i cannot get the linker to find the actual library.
I want to do the compiling process with MAKE and gcc.
Firstly I import the header
#include <ta-lib/ta_libc.h>
And then when i need to use a function
TA_ADOSC(0, CSV_LENGTH - 1, temp_high, temp_low, temp_close, temp_volume, 3, 10, &beginIdx, &endIdx, tmp_adosc);
The program compiles fine using my makefile
# create CC variable
CC = gcc
# create CFLAGS variable
CFLAGS = -L/usr/local/lib -Wall -g
LDLIBS = -lta_lib -I/usr/local/include -lm
output: main.o
$(CC) $(CFLAGS) -o output main.o
main.o: main.c
$(CC) $(LDLIBS) -c main.c
# target: dependencies
# action
clean:
rm -f \*.o output
Once I try to run make i get the following
gcc -L/usr/local/lib -Wall -g -o output main.o
/usr/bin/ld: main.o: in function `calculate_indicators': main.c:(.text+0x226): undefined reference to `TA_ADOSC'
collect2: error: ld returned 1 exit status
make: \*\*\* \[Makefile:10: output\] Error 1
From my understanding I need to fix the linking to the shared library.
The library is installed:
ldconfig -p | grep libta_lib.so
Returns the following
libta_lib.so.0 (libc6,x86-64) => /usr/local/lib/libta_lib.so.0
libta_lib.so.0 (libc6,x86-64) => /lib/libta_lib.so.0
libta_lib.so (libc6,x86-64) => /usr/local/lib/libta_lib.so
libta_lib.so (libc6,x86-64) => /lib/libta_lib.so
Since i am fairly new to C and using external libraries I can't find what seems to be the problem
You are adding the libraries to the compile line. They need to be added to the link line. And preprocessor options like -I are used by the compiler, and "where to find libraries" options like -L are used by the linker.
Also, libraries always must come at the end of the link line, after all the object files. And, the -L "where to search" option should come before the -l "what library to find" option.
Write your rules like this:
CFLAGS = -I/usr/local/include -Wall -g
LDFLAGS = -L/usr/local/lib
LDLIBS = -lta_lib -lm
output: main.o
$(CC) $(CFLAGS) $(LDFLAGS) -o output main.o $(LDLIBS)
main.o: main.c
$(CC) $(CFLAGS) -c main.c
However, it's better to just let make do the work for you; it knows how to correctly compile things (as long as you set the standard variables). You don't need to include a rule to build main.o at all.

Shared library disparity between Linux CentOS 7 and Ubuntu 20.04.1 LTS

I am porting a project written in C from a CentOS 7 (Core) to an Ubuntu 20.04.1 LTS (Focal Fossa) system. The project relies heavily on the <cpuset.h> library, and compiles and executes correctly on the CentOS system. However, when I try to use functions from cpuset.h on the Ubuntu system, I get 'undefined reference' errors.
The following code, stored in file test.c, compiles and runs correctly on CentOS:
#define _GNU_SOURCE
#include<stdio.h>
#include <cpuset.h>
int main(){
int x = cpuset_version();
printf("cpuset lib version: %d\n",x );
return 0;
}
How I compile:
gcc -Wall -O2 -std=gnu99 -g -lcpuset test.c -o test
Output:
[xxxx#CentOS]$ ./test
cpuset lib version: 3
However, when I try to compile the same test.c file on the Ubuntu system, I get this error:
xxxx#Ubuntu:$ gcc -Wall -O2 -std=gnu99 -g -lcpuset test.c -o test
/usr/bin/ld: /tmp/ccpxlk4F.o: in function `main':
test.c:8: undefined reference to `cpuset_version'
collect2: error: ld returned 1 exit status
Furthermore, this is not limited to the <cpuset.h> library. I tried to use a simple function from <pthread.h> and it also gave me the same error. Can anyone help with identifying why I cannot use shared libraries on the Ubuntu system? Thanks in advance
Since OP's issue is wrong order of parameters to GCC (many guides do show an incorrect order!), as discussed in the comments to the question, I believe showing a minimal Makefile to handle these is warranted:
CC := gcc
CFLAGS := -Wall -O2 -g
LDFLAGS := -lcpuset
TARGETS := test
.PHONY: all clean
all: $(TARGETS)
clean:
rm -f *.o $(TARGETS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
test: test.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
Note that the indentation in Makefiles must use Tabs and not spaces. Since this forum converts Tabs to spaces, you will need to fix the above makefile, for example by running sed -e 's|^ *|\t|' -i Makefile.
If you want to compile say foo.c directly to an executable, the recipe is
foo: foo.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
You only need to run make (it defaults to using the Makefile in the current directory, and the default target is the first one, above the one named all), to recompile the TARGETS (here, test, but you can supply more by just adding them space-separated to the line).
You can also run make clean test to rebuild test from "scratch", i.e. removing all temporary files and all targets first.
You can override variables like CFLAGS by simply supplying them on the command line; for example, make CFLAGS="-Wall -Wextra -Os" clean all to recompile everything with different compilation flags.

Compiling on RaspberryPi by using make

When I use make to compile the RaspberryPi's source code, the error happens like this:
"bmp180.c:(.text+0xe8): undefined reference to `bcm2835_i2c_write'"
However, I have used the "-l bcm2835", the makefile as follow:
#makefile
bmp: main.o bmp180.o
gcc -o bmp main.o bmp180.o
main.o: main.c bmp180.h
gcc -c main.c -l bcm2835.h
bmp180.o: bmp180.c bmp180.h
gcc -c bmp180.c -l bcm2835.h
clear:
rm -f main.o bmp180.o
You have -l bcm2835.h in your Makefile. The name of the library is simply bcm2835. Files ending with .h are files meant to be #include'd in your C source; they are not dynamic shared libraries.
Additionally, shared libraries are required at the link stage, not the compile stage; you will need to add -l bcm2835 to the linking step:
bmp: main.o bmp180.o
gcc -o bmp main.o bmp180.o -l bcm2835
The -l arguments in your compile steps are effectively no-ops (but they won't hurt anything).

GCC compile with mysql library

when I try to compile a self written project in C with includes the mysql libraries I get this error:
gcc -c src/oDAO.c
src/oDAO.c:4:23: fatal error: my_global.h: No such file or directory
I included the my_global.h as following:
#include <my_global.h>
The error comes up, because my system copied the header files to /usr/include/mysql/ and gcc is searching for system header files only in /usr/include (without subdirectories). How can I call gcc with adding /usr/include/mysql as additional shared library root?
Here is my acutal Makefile:
all: main.o oDAO.o FileUtils.o DVDDAO.o
gcc -Llib -o oDAO main.o oDAO.o FileUtils.o DVDDAO.o -llinkedlist -lncurses `mysql_config --cflags --libs`
main.o:
gcc -c src/main.c
oDAO.o:
gcc -c src/oDAO.c
FileUtils.o:
gcc -c src/FileUtils.c
DVDDAO.o:
gcc -c src/DVDDAO.c
clean:
rm -f *.o
rm -f oDAO
rm -f *.bak
rm -f *.~
I've got the answer on my own:
Everytime i try to compile a .c file that includes a mysql library into an object file I have to compile it like that:
gcc -c DVDDAO.c `mysql_config --cflags`
Then everything works fine
Try the option -I for adding a include directory and -L for adding a libary directory.

[C]undefined reference while compiling openCL program

I'm trying to compile something to try out openCl, but i'm having a few problems..
Here the code
prova.c
#include <stdio.h>
#include <CL/opencl.h>
#include "Utils\util.h"
#include <malloc.h>
int main(){
cl_int error = 0; // Used to handle error codes
cl_int max_platforms = 1; // The maximum number of platforms
cl_uint adviable_platforms = 0; //The adviable number of platforms
cl_platform_id* platform;
error = clGetPlatformIDs(0, NULL, &adviable_platforms);
if(adviable_platforms == 0)
{
printf("No adviable platforms.\n");
return -1;
} else {
platform = (cl_platform_id*)malloc(adviable_platforms * sizeof(cl_platform_id));
}
error = clGetPlatformIDs(adviable_platforms, platform, NULL);
printf("clGetPlatformIDs: %s\n", clErrorString(error));
return 0;
}
I'm compiling on win 7 64 with mingw32. The opencl headers are in the include directory of mingw while utils.h(inside the directory Utils inside the directory of prova.c) defines clErrorString(that simply convert the error into a more human readable string).
To compile i use
gcc -L\Utils prova.c
But i always get
C:\[stuff]\ccEjYQbj.o:prova.c:(.text+0x42): undefined reference to 'clGetPlatformIDs#12'
C:\[stuff]\ccEjYQbj.o:prova.c:(.text+0x8d): undefined reference to 'clGetPlatformIDs#12'
C:\[stuff]\ccEjYQbj.o:prova.c:(.text+0x9e): undefined reference to 'clErrorString'
I'm not so good with compilers, so i image i'm missing something, but i really don't know what..
EDIT:
Sincerely, i tried every command come to my mind. using -L to include directories, -l to link to files, using ar..
This is the last "script" i tried
set PATH=%PATH%;C:\Python26;C:\MinGW\bin;C:\MinGW\lib
cd Utils
gcc -c util.c -l"C:\Program Files (x86)\AMD APP\lib\x86_64\libOpenCL.a" -o util.o
ar rcs libutil.a util.o
cd..
pause
gcc -c prova.c -l"Utils\libutil.a" -o prova.exe
pause
EDIT2:
#echo off
set PATH=%PATH%;C:\Python26;C:\MinGW\bin;C:\MinGW\lib
cd Utils
gcc -Wall -c util.c -L"C:\Program Files (x86)\AMD APP\lib\x86_64\" -o util.o
ar rcs libutil.a util.o
cd..
pause
gcc -Wall -c prova.c -L"C:\Program Files (x86)\AMD APP\lib\x86_64\" -l"Utils\libutil.a" -o prova.exe
pause
No errors, the only warning is max_platform is unused. Then i find util.o and libutil.a(size 5kb) in Utils and prova.o(size 1kb). If i try to run prova.o, it says that the file version is not compatible with the current windows version, check the system version (x86 or x64) and contact the software distributor
Try something like this:
set PATH=%PATH%;C:\Python26;C:\MinGW\bin;C:\MinGW\lib
cd Utils
gcc -W -Wall -c util.c -o util.o
ar rcs libutil.a util.o
cd..
gcc -W -Wall -c prova.c -o prova.o
gcc -o prova.exe prova.o Utils\libutil.a
# Using a standard library
gcc -o prog.exe myprog.o -lzip # e.g. /usr/lib/libz.a
# Using a nonstandard library
gcc -o prog.exe myprog.o -lfoo -L/tmp/libfoo # uses /tmp/libfoo/libfoo.a
gcc -o prog.exe myprog.o /tmp/libfoo/libfoo.a # same effect
In general:
Compile single source files with -c:gcc -c myfile.c -o myfile.o.This creates object files.
Link all the object files to an executable (or shared library):gcc -o prog.exe myfile.o yourstuff.o sha257.o
You can combine object files into a static library, which you treat just like a single object file when linking:ar rcs libcoolstuff.a yourstuff.o sha257.ogcc -o prog.exe myfile.o libcoolstuff.aAlternatively:gcc -o prog.exe myfile.o -lcoolstuffThe latter syntax (automatic library linking with -l) requires either libcoolstuff.a or libcoolstuff.so to be findable in the library path (which you can amend with -L at linktime).

Resources