I am trying to build a way to use extern C++ functions in my LLVM code - for example:
extern "C" DLLEXPORT double printd(double X) {
fprintf(stderr, "%f\n", X);
return 0;
}
I would like to be able to call printd in my LLVM IR code.
I know that I have to implement a JIT to get this working, but I am not exactly sure what elements of a JIT enable calling functions from C++ code or how to link that code to my IR code.
Edit
IR Code (out.ll)
declare double #printd(double)
define double #__anon_expr() {
entry:
%calltmp = call double #printd(double 1.000000e+01)
ret double %calltmp
}
define i32 #main() {
call double #__anon_expr()
ret i32 0
}
I generate the above code using C++:
IR->print(llvm::errs());
Finally I run it using:
$ lli out.ll
And I get this error:
LLVM ERROR: Program used external function '_printd' which could not be resolved!
Edit 2
When I run clang out.ll -lmylib -o a.out
warning: overriding the module target triple with x86_64-apple-macosx10.12.0 [-Woverride-module]
1 warning generated.
ld: library not found for -lmylib
clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation)
Edit 3
$ clang out
Undefined symbols for architecture x86_64:
"_printd", referenced from:
___anon_expr in out
ld: symbol(s) not found for architecture x86_64
clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation)
$ lli out
lli: out:1:1: error: expected top-level entity
���� �� �__text__TEXT ��__literal8__TEXT#__compact_unwind__LD(#H�__eh_frame__TEXThX�
h$
C++ functions that are declared as extern "C" can be called just like regular C functions (that's what extern "C" does), so all you need to is a declaration and then a regular call instruction. So that'd be:
; At the top-level:
declare double #printd(double)
; Somewhere inside the definition of a function that calls printd:
%42 = call double #printd(double %23)
Then all you need is to link against your library when creating the final executable.
I know that I have to implement a JIT to get this working
Calling external functions works perfectly well in AOT-compiled code. You don't need to JIT-compile in order to call external functions.
Related
I am new to C++, and trying to use get_string, but I am not sure what I writing wrong that is creating an error.
The code I have is the following:
#include <stdio.h>
#include <cs50.h>
int main(void)
{
string name = get_string("What's your name? ");
printf("hello, %s\n", name);
}
and it keeps saying the following error:
Undefined symbols for architecture arm64:
"_get_string", referenced from:
_main in hello-890d43.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [hello] Error 1
Does any one know what I am doing wrong?
I expected the code take an input and print out hello, (your input).
The same thing happened to me when trying to use the cs50 C library on my local Mac with M1 chip.
Even after installing the library as described here: https://cs50.readthedocs.io/libraries/cs50/c/
It still didn't work.
The problem is coming from the fact that the make command here doesn't include the link command by default.
Assuming your source file is named hello.c instead of just doing:
make hello
You have to enter the following in your terminal in order to compile:
clang hello.c -o hello -lcs50
Afterwards, when running the executable, it works as expected:
./hello
make hello LDLIBS="-lcs50"
LDLIBS to include the cs50 library
I'm currently learning this quantum computing C/C++ library called libquantum. After performing a successful installation and confirming it by trying some demos that came along the source code, I tried writing my own program (main.cpp).
#include<quantum.h>
int main(){
quantum_reg qr;
quantum_delete_qureg(&qr);
}
I tried to compile this program with:
g++ main.cpp -lquantum
but it failed:
/usr/bin/ld: /tmp/cc6aR9vu.o: in function main': main.cpp:(.text+0x23): undefined reference to quantum_delete_qureg(quantum_reg_struct*)' collect2: error: ld
returned 1 exit status
I also tried:
g++ main.cpp -L/usr/local/lib -lquantum
considering libquantum.so is there, but same error
What is happening here?
The library is C and seems to have no awareness of C++. The link error has a type in it, which suggests that the linker is trying to link it in C++ mode.
Try putting a extern "C" around the include:
extern "C" {
#include<quantum.h>
}
int main(){
quantum_reg qr;
quantum_delete_qureg(&qr);
}
What is going on? To implement function overloading, C++ encodes type information in function symbol names so they no longer match up with the C function names in the binary library, see https://en.wikipedia.org/wiki/Name_mangling
How to fix the fact that external hidden global and internal global declarations do not merge?
I have been working on flow to extract a function from LLVM IR, link it back again and compile to binary. However, in the last step, the compilation from the Linked IR to binary fails with the following message:
/tmp/real-linked-fbcc7e.o: In function `__cxx_global_var_init':
real-linked.ll:(.text.startup+0x2fa): undefined reference to `std::__ioinit'
real-linked.ll:(.text.startup+0x313): undefined reference to `std::__ioinit'
/usr/bin/ld: out: hidden symbol `_ZStL8__ioinit' isn't defined
/usr/bin/ld: final link failed: Bad value
clang: error: linker command failed with exit code 1 (use -v to see invocation)
My flow to extract and re-link the function __cxx_global_var_init goes as follows:
llvm-extract-4.0 -func __cxx_global_var_init original.ll -S -o extracted_f.ll
llvm-link-4.0 code01.ll -override extract_f.ll -S -o linked.ll
clang++-4.0 linked.ll -o out
Where:
__cxx_global_var_init is the function to be extracted from original.ll;
original.ll is the source file;
extracted_f.ll is a file that contains only the function and declarations of its dependencies;
linked.ll is the output file before compilation to binary
out is the final binary
The undefined reference is declared on:
extracted_f.ll as:
#_ZStL8__ioinit=external hidden global %"class.std::ios_base::Init", align 1
original.ll as:
#_ZStL8__ioinit = internal global %"class.std::ios_base::Init" zeroinitializer, align 1
linked.ll as:
#_ZStL8__ioinit.6 = internal global %"class.std::allocator" zeroinitializer, align 1
#_ZStL8__ioinit = external hidden global %"class.std::allocator", align 1
As you may suspect, the linked function on linked.ll calls the wrong version of the declared: #_ZStL8__ioinit.6.
Questions:
Is there any command line option that I am missing?
Is there a way to replace the function using the declarations of the original file?
NOTE:
I am able to re-link and compile functions with no calls to other functions.
I am trying to use libotr but I have the following problem when attempting to compile a very basic library initialisation.
#include <libotr/proto.h>
int main(int argc, char const *argv[])
{
OTRL_INIT;
// OtrlUserState userstate = otrl_userstate_create();
return 0;
}
I am compiling it with the following command:
g++ main.cpp -o main -L /usr/local/lib/ -lotr
But for some reason I am getting:
Undefined symbols for architecture x86_64:
"otrl_init(unsigned int, unsigned int, unsigned int)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/bin] Error 1
I explicitly checked and the library does indeed has the following symbols.
After a quick observation I noticed that libotr is using the C type name mangling and the problem is resolved just by adding the following lines to the library's include clause:
extern "C" {
#include <libotr/proto.h>
}
If you have similar problem just list the symbols of a library with the nm utility and check whether the symbol names begin with one or two underscores: _foo is C style, while __foo is C++ style.
P.S. I posted this since it took me a while to figure it out. I hope this question + answer would save you some time.
Here is my make file output:
nvcc -c -arch=sm_35 src/kmeans_cuda.cu
nvcc -c -arch=sm_35 src/sequence.c
nvcc -c -arch=sm_35 src/io.c
nvcc -c -arch=sm_35 src/main.c
nvcc -g -o cuda-means kmeans_cuda.o sequence.o io.o main.o
Undefined symbols for architecture x86_64:
"_kmeans", referenced from:
_main in main.o
(maybe you meant: cudaError (anonymous namespace)::cudaLaunch<char>(char*))
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [all] Error 1
On my main function i call kmeans();, kmeans, is a C function defined in kmeans_cuda.cu
void kmeans() {
long i,h,j,k; //counters
long delta; //Number of objects has diverged in current iteration
long nearest; //Nearest centroid
unsigned int distance,min_distance; //distance calculated by relation point-cluster
int *count,*recv_count;
int *send_label;
double begin,end,trans_init,trans_end;
// should call kernel, but is not calling yet, because it's not implemented ...
I already try to added __host__ on kmeans() declaration, but dind't fixed the problem.
I have now idea why i'm getting this error, because i'm linking the object with the function.
nvcc treats .cu files as C++ and you have your host code in .c files (i.e. in C, not C++).
The easiest solution is to simply rename your .c files to .cpp and treat your app as a C++ app instead of C. You could also declare kmeans() as extern "C" {...} to force the compiler to use a C binding instead of C++ binding for the function, but then you'd have to do that for every future function which is probably unnecessarily inelegant.