This notice presents an example of utilisation of some code written in C language from julia.
More exactly, we consider a small project with the following structure:
![Figure 1: Folder structure and project files](https://lmbp.uca.fr/~cindea/blog/ox-hugo/project-c-julia.png)
Figure 1: Folder structure and project files
In the C part of the project we have the file cc/nc.c
# include "nc.h"
void initmystr(mystr* s){
(*s).a = 0;
(*s).p[0]=0;
}
void initmyvec(int* p){
p[0] = 77;
}
and the corresponding header (cc/include/nc.h
):
#include <stdio.h>
// A C struct containing a pointer.
typedef struct mystr {
int a;
int* p;
} mystr;
void initmystr(mystr* s);
void initmyvec(int* p);
I build this code in a shared library using the following make file. If you have a look at the makefile, you will observe that I firstly build a static library (for fun) and then linked this library into a shared one.
CC=gcc
CFLAGS=-I./include -fPIC
DEPS = nc.h
all: libnc test
UNAME_S := $(shell uname -s)
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
libnc.a: nc.o
ar rcs $@ $^
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
LIBEXT=so
SHARED_BEGIN=-Wl,-whole-archive
SHARED_END=-Wl,-no-whole-archive
endif
ifeq ($(UNAME_S),Darwin)
LIBEXT=dylib
SHARED_BEGIN=-all_load
SHARED_END=
endif
libnc: libnc.a
$(CC) -shared $(SHARED_BEGIN) $^ $(SHARED_END) -o $@.$(LIBEXT)
test: libnc
+$(MAKE) -C test
.PHONY: clean
clean:
rm *.o *.$(LIBEXT) *.a test/testnc.o test/testnc
A first test is to execute the code in the library from C. This is
the purpose of the file test/testnc.c
:
#include "nc.h"
#include <stdio.h>
int main(int argc, char *argv[])
{
int tmp[3];
tmp[0] = 1;
tmp[1] = 2;
tmp[2] = 3;
mystr s;
s.a =3;
s.p = tmp;
printf("Call initmystr...\n");
initmystr(&s);
printf("Data in struct: %d %d %d %d\n", s.a, s.p[0], s.p[1], s.p[2]);
printf("Data in tmp: %d %d %d\n", tmp[0], tmp[1], tmp[2]);
printf("Call initmyvec...\n");
initmyvec(tmp);
printf("Data in tmp: %d %d %d\n", tmp[0], tmp[1], tmp[2]);
printf("Data in struct: %d %d %d %d\n", s.a, s.p[0], s.p[1], s.p[2]);
return 0;
}
After compiling and linking this file we get:
Call initmystr..
Data in struct: 0 0 2 3
Data in tmp: 0 2 3
Call initmyvec...
Data in tmp: 77 2 3
Data in struct: 0 77 2 3
Let us have a look to the julia code (file testloadnc.hjl
) for doing the same thing:
using Libdl
push!(DL_LOAD_PATH, "./cc")
mutable struct Mystr
a::Int32
p::Ptr{Int32}
end
p = convert(Array{Int32, 1}, [1, 2, 3])
A = Mystr(1, pointer(p))
print("Call initmystr...\n")
ccall((:initmystr, :libnc), Cvoid, (Ref{Mystr},), A)
print("Data in A: ", A.a, "\n")
print("Data in p: ", p, "\n\n")
print("Call initmyvec...\n")
ccall((:initmyvec, :libnc), Cvoid, (Ref{Int32},), p)
print("Data in A: ", A.a, "\n")
print("Data in p: ", p, "\n")
and to the output produced by its execution:
Call initmystr...
Data in A: 0
Data in p: Int32[0, 2, 3]
Call initmyvec...
Data in A: 0
Data in p: Int32[77, 2, 3]
Everything is working as expected. The only tricky part was the way to pass a pointer inside the structure.
comments powered by Disqus