Call cuda library on windows - c++

I am trying to use cuda to parallelize a Go project.
I've read Golang calling CUDA library many times.
I'm trying to do the same thing on Windows and having trouble. (I'm assuming this OP was using Linux because of the .so files)
I have successfully compiled/run the following test program involving no cuda code to make sure I have CGO working correctly.
test.cpp
extern "C"{
int testfunc(){
return 1000;
}
}
compiled with g++
g++ test.cpp -o test.dll --shared
callC.go
package main
//int testfunc();
//#cgo LDFLAGS: -L. -ltest
import "C"
import "fmt"
func main() {
fmt.Println(C.testfunc())
}
prints 1000 - great!
now I try the same thing with nvcc and I get an error from ld that theres an undefined reference to testfunc.
test.cu
extern "C"
{
int testfunc()
{
return 1 + 1;
}
}
compiled with
nvcc test.cu -o testcuda.dll --shared --compiler-options -fPIC ... I always get:
cl : Command line warning D9002 : ignoring unknown option '-fPIC'
cl : Command line warning D9002 : ignoring unknown option '-fPIC'
cl : Command line warning D9002 : ignoring unknown option '-fPIC'
Creating library testcuda.lib and object testcuda.exp
callCudaC.go
package main
//int testfunc();
//#cgo LDFLAGS: -L. -ltestcuda
//#cgo LDFLAGS: -LC:\temppath\CUDA\v11.2\ -lcudart
import "C"
import "fmt"
func main() {
fmt.Println(C.testfunc())
}
running this go code results in
C:\Users\MICHAE~1\AppData\Local\Temp\go-build045526290\b001\_x002.o: In function `_cgo_701f531a6502_Cfunc_testfunc': /tmp/go-build/cgo-gcc-prolog:52: undefined reference to `testfunc' collect2.exe: error: ld returned 1 exit status
you'll note that my "cuda" code doesn't involve any cuda, just one exported function and that I tried moving the cuda installation to a simpler path so I could actually pass it as a directory to the linker - I'm not sure if it's even needed since there is no use of cuda syntax etc.
Would be appreciative of debugging tips or hints if anyone has seen this before.

Thanks to the direction from #talonmies comments I found that at least in simple cases I could call the dlls created by cl.exe and nvcc.exe from cgo by defining a header file that looks like this:
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
#endif
__declspec(dllexport) int testfunc();
#ifdef __cplusplus
}
#endif
this code was created referencing these two MSDN articles:
https://learn.microsoft.com/en-us/cpp/build/exporting-cpp-functions-for-use-in-c-language-executables?view=msvc-160
https://learn.microsoft.com/en-us/cpp/build/exporting-c-functions-for-use-in-c-or-cpp-language-executables?view=msvc-160

Related

C++ std::thread compilation error on simple thread [duplicate]

I am using pthread.h in a *.cc file. when I try to use pthread_exit(0); or pthread_join(mythrds[yy],NULL); it says:
.cc:(.text+0x3e): undefined reference to `pthread_exit'
when complied very similar code in a *.c file with gcc it work perfect. How Can I use pthread's in c++.. (I also added -lpthread)
..
void *myThreads ( void *ptr )
{
...
pthread_exit(0);
}
..
flags:
g++ -lpthread -Wall -static -W -O9 -funroll-all-loops -finline -ffast-math
You might try using the -pthread option to g++.
-pthread
Adds support for multithreading with the pthreads library. This
option sets flags for both the preprocessor and linker.
Do your pthread header files have extern "C" { ... } around the function prototypes? That's the usual case for the linker not being able to link in C++.
It occurs because C++ generally does name-mangling so that it can encode parameter details into symbols (allowing polymorphism). For example, the functions:
void x(int);
void x(void);
void x(char,int,float,double);
all get different linker symbols.
If the header files don't have the extern "C" { ... }, you may need to do it yourself:
extern "C" {
#include <pthread.h>
}
Hopefully that will work.

Using Go in C++

linux Debian Buster
go version go1.11.6 linux/amd64
gcc version 8.3.0 (Debian 8.3.0-6)
libmylib.go
package main
import "C"
import (
"fmt"
)
func say(text string) {
fmt.Println(text)
}
func main(){}
mylib.h
#ifndef MY_LIB_H
#define MY_LIB_H
#include <string>
void say(std::string text);
#endif
main.cpp
#include <string>
#include "mylib.h"
using namespace std;
int main() {
string text = "Hello, world!";
say(text);
return 0;
}
CGO_ENABLED=1 go build -o libmylib.so -buildmode=c-shared libmylib.go
g++ -L/path/to/lib/ -lmylib main.cpp -o my-test-program
/usr/bin/ld: /tmp/ccu4fXFB.o: in function 'main':
main.cpp:(.text+0x53): undefined reference to `say(std::__cxx11::basic_string<char, std::char_traits, std::allocator >)' collect2: error: ld returned 1 exit status
with change: package main -> package mylib
CGO_ENABLED=1 go build -o libmylib.so -buildmode=c-shared libmylib.go
-buildmode=c-shared requires exactly one main package
You have to use GoString rather than std::string in the C++ version. The error message you are getting is because of the type mismatch, manifesting as a link-time error.
See the cgo reference.
Here's a working example. There's a few differences from yours. The //export directive is needed to include the function in the generated header file, the argument is *C.char rather than string or GoString. The C++ code uses the header generated by cgo, and there has to be a const-removing cast from the static string (because go doesn't have C-like const).
libmylib.go
package main
import "C"
import (
"fmt"
)
//export say
func say(text *C.char) {
fmt.Println(C.GoString(text))
}
func main() {}
main.cpp
#include "libmylib.h"
int main(void) {
say(const_cast<char*>("hello world"));
return 0;
}
commands
This compiles to go file, generating libmylib.so and libmylib.h in the current directory.
go build -o libmylib.so -buildmode=c-shared libmylib.go
The compiles the C++ program, linking it to the shared library above:
g++ -L. main.cpp -lmylib -o hello_program
To run the program, LD_LIBRARY_PATH needs to be set to the current directory. That would be different if program was installed and the shared library put in a sensible place.
LD_LIBRARY_PATH=. ./hello_program
g++ -L/path/to/lib/ -lmylib main.cpp -o test
is probably wrong. Read the invoking GCC chapter of the GCC documentation. Order of arguments to g++ matters a lot.
Also, test(1) could be some existing executable. I recommend to use some other name.
So consider compiling with
g++ -Wall -g -O main.cpp -L/path/to/lib/ -lmylib -o my-test-program
You probably want debugging information (-g), warnings (-Wall) and some optimization (-O)
You did comment
I need to use some functions from a Go file in my C ++ project.
This is curious. I assume your operating system is some Linux. Then, can't you just use inter-process communication facilities between a process running a Go program and another process running your C++ program? Consider perhaps using JSONRPC or HTTP between them. There exist several open source libraries in Go and in C++ to help you.
PS. As I commented, calling C++ code from a Go program could be much simpler. Of course you do need to read the Go documentation and the blog about cgo and probably the C++ dlopen minihowto and some C++ reference.

C wrapper around C++ library without unnecessary header files

C++ newbie here. I'm creating a C wrapper around C++ library which expose just foo() function.
wrapper.h
#include "SomeLibrary.h"
#include "SomeAnotherLibrary.h"
#ifdef __cplusplus
extern "C" {
#endif
void foo();
#ifdef __cplusplus
}
#endif
wrapper.cpp
#include "wrapper.h"
void foo() {
// calls to `SomeLibrary.h` and `SomeAnotherLibrary.h` functions...
}
I would like to compile this code just to be able to call foo() from a different C code. Note that I care just about the foo() function. I would like to completely ignore SomeLibrary.h and SomeAnotherLibrary.h header files.
So I tried to compilethe wrapper into object file wrapper.o as follows:
g++ -c wrapper.cpp -o wrapper.o -I../some_library/include -I../some_other_library/include -L../some_library/lib -lSomeFirstLibrary -lSomeSecondLibrary
Problem:
When I used wrapper.o in my C project, it still require me to load bunch of header files from SomeLibrary.h and SomeAnotherLibrary.h (which I do not care about at all). Here is my C project code:
my_project.c:
#include "wrapper.h"
void main() {
foo();
}
And compile it:
gcc my_project.c wrapper.o -o my_project
Which yields following error:
my_program.c:3:28: fatal error: SomeLibrary.h: No such file or directory
Question:
How I should compile the wrapper to ignore all other header files except wrapper.h?
Remove
#include "SomeLibrary.h"
#include "SomeAnotherLibrary.h"
from wrapper.h and put those lines in wrapper.cpp next to #include "wrapper.h".
Then remove the -L../some_library/lib -lSomeFirstLibrary -lSomeSecondLibrary linker related flags from the
g++ -c wrapper.cpp -o wrapper.o -I../some_library/include -I../some_other_library/include
command (-c means no linking is done here so there's no point in passing linker flags)
and move it to the
gcc my_project.c wrapper.o -o my_project -L../some_library/lib -lSomeFirstLibrary -lSomeSecondLibrary
command like this.
Then it should work.
When you get undefined reference to... messages, it means that you are declaring functions, and calling them, but never defining them. The error is coming from the fact that you are linking your libraries in the wrong place. You do not need to link libraries to the .o file, you need to link them to the executable file.

How to change the entry point of a g++ generated Linux shared library compiled from multiple source files?

Today, I read the web blog article, How to make executable shared libraries . In this article it states that if one types at a Linux command prompt:
gcc -shared service.c -o libservice.so -Wl,-soname,libservice.so -W1,-e lib_entry
followed by
./libservice.so, then we can directly executer the lib_entry function.
However, when I run a similar g++ command:
g++ -shared one.cpp two.cpp three.cpp -o libservice.so -Wl,-soname,libservice.so -W1,-e lib_entry
where lib_entry is a C function defined in two.cpp I get the warning message:
No entry point lib_entry point found.
How do I fix this warning message so I can directly run the entry point, lib_entry? Should I enclose the implementation of the C function foo with extern "C" linkage to resolve this problem?
This is my answer:
Missing include "bits/c++config.h" when cross compiling 64 bit program on 32 bit in Ubuntu
sudo apt-get install gcc-4.9-multilib g++-4.9-multilib
Please disregard the previous answer. The answer below was tested successfully. Thank you for your patience.
Step 1
#include <stdio.h>
#include <unistd.h>
#ifdef __LP64__
const char service_interp[] __attribute__((section(".interp"))) = "/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2";
#else
const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
#endif
void lib_service(void)
{
printf("This is a service of the shared library\n");
} // lib_service
void lib_entry(void)
{
printf("Entry point of the service library\n");
_exit(0);
}
Step 2.
vendor#clickit:~/Downloads/DataServerLib$ g++ -shared -fPIC -DLINUX -Wl,-soname,libdataserver.so -efunc -I /home/vendor/Downloads/waitForMultipleObjects -I /home/vendor/development/Test/Include DataServer.cpp DataServerLib.cpp DataTransferClient.cpp CWinEventHandle.cpp WinEvent.cpp -o libDataServer.so -lpthread -lrt
maryych#uwash.edu:~/Downloads/DataServerLib$ chmod 777 libDataServer.so
maryych#uwash.edu:~/Downloads/DataServerLib$ ./libDataServer.so
Inside entry point tester 1
AddUser

Using c library in c++ code with makefile

I have a C library made by cluster.h and cluster.c. I compiled that with gcc -c cluster.c.
I have to use a method of this library in the main class of a C++ project. This is the makefile i use:
abundancebin: main.o profileManager.o myHash.o myMalloc.o myStack.o myStringHash.o
g++ -o abundancebin main.o profileManager.o myHash.o myMalloc.o myStack.o myStringHash.o
main.o: main.cpp
g++ -c main.cpp
profileManager.o: profileManager.cpp
g++ -c profileManager.cpp
myHash.o: myHash.cpp
g++ -c myHash.cpp
myMalloc.o: myMalloc.cpp
g++ -c myMalloc.cpp
myStack.o: myStack.cpp
g++ -c myStack.cpp
myStringHash.o: myStringHash.cpp
g++ -c myStringHash.cpp
clean:
-rm *.o abundancebin
I tried to import the C library in main.cpp using after other imports:
#ifdef __cplusplus
extern "C" {
#endif
#include <cluster.h>
#ifdef __cplusplus
}
#endif
but when i compile with make i have this response:
main.cpp:29:21: fatal error: cluster.h: No such file or directory
#include <cluster.h>
^
compilation terminated.
make: *** [main.o] Error 1
if i use "cluster.h" instead of i have this error:
main.o:main.cpp:(.text+0xf68): riferimento non definito a "kmedoids"
main.o:main.cpp:(.text+0xf68): rilocazione adattata per troncamento: R_X86_64_PC32 contro il simbolo non definito "kmedoids"
/usr/bin/ld: main.o: bad reloc address 0x18 in section.xdata'
collect2: error: ld returned 1 exit status
make: * [abundancebin] Error 1`
I also tried to copy the code part i need from C library to C++ project but the compiler reports many errors like this:
error: invalid conversion from ‘void*’ to ‘int*’ [-fpermissive]
vector = malloc(nnodes*sizeof(int));
The library files are in the same folder of the project files. Can someone help?
Thank you
If you want to add some code which is wrote in c language, you have to #include it like:
extern "C" {
#include "x264.h"
}
which tell compiler to deal with it differently, and its not necessary to change your code to c++
1: you add your code as: #include <cluster.h>
its better to change it to: #include "cluster.h"
the different is, the second one tell the compiler to first search for your header in the current directory and then in the main c++ libraries directory
your error:
main.cpp:29:21: fatal error: cluster.h: No such file or directory
is because it can't find the header, so, if cluster.h is in the same directory as main.cpp, use #include "cluster.h"
or you can use -I. (which tell its in the current directory) or -I/address to tell compiler where to look for your header
when you correct it, you get the second error, which I believe its because of your code, and I think its because of your code in main.cpp, and do not have anything with your cluster code, I suggest, try to post your code to find out what's the problem
In answer to your question, I would approach it something like this in the makefile:
all: cfile.o
g++ main.cpp -o app
cfile.o: cluster.c cluster.h
gcc -c cluster.c
Note: This assumes that everything is in the same directory, so take care to specify paths if not.
Let me know of any further errors.