syclintel-oneapidpc++

Create a static or shared library from sycl program using dpc++


I am trying to create a static or shared library from a sycl program and use it from a main application build using gcc/g++/clang++. Everything is fine if I use dpcpp to build my main application, but I need to use g++.

For example, my sample sycl_lib.cpp and the main program are as follows.

//sycl_lib.cpp
#include<CL/sycl.hpp>
int func() {
  q.submit([&](sycl::handler &h) {
    sycl::stream os(1024, 768, h);
    h.parallel_for(32, [=](sycl::id<1> i) {
      os<<i<<"\n";
    });
  });
}

//main.cpp
void func();
int main() {
  func();
  return 0;
}

To create a static library and use it:

dpcpp -c sycl_lib.cpp -fPIC
ar rvs sycl_lib.a sycl_lib.o
dpcpp main.cpp sycl_lib.a
./a.out

This works fine. But I want to use g++ to build main.cpp, it is causing runtime error.

g++ main.cpp sycl_lib.a -L$SYSL_DIR/lib -lsycl
./a.out

which is giving the following error

terminate called after throwing an instance of 'cl::sycl::runtime_error'
  what():  No kernel named _ZTSZZ4funcvENKUlRN2cl4sycl7handlerEE6_12clES2_EUlNS0_2idILi1EEEE8_24 was found -46 (CL_INVALID_KERNEL_NAME)
Aborted

Is it possible for an executable created with g++ to use a sycl library created using dpc++?

Thank you


Solution

  • The short answer is: while any compiler can be used for the host code, dpcpp must be used to create the final binary (do the link) because only dpcpp knows this is a SYCL program.

    We do this by replacing:

    $ g++ main.cpp sycl_lib.a -L$SYSL_DIR/lib -lsycl
    

    with

    $ g++ -c main.cpp
    $ dpcpp main.o sycl_lib.a -L$SYSL_DIR/lib -lsycl
    

    We definitely need to document this better - sorry about that. I'll see what we can do there (suggestions would be appreciated).

    Here is why: You can compile any host code with g++, but there is finalization required to finish the SYCL program and create the final binary (to bring together host and non-host code) that g++ knows nothing about. dpcpp invokes “sycl-post-link” - which we get by just using dpcpp to build the final binary

    Here are the files and Makefile to illustrate:

    //main.cpp
    void func();
    int main() {
      func();
      return 0;
    }
    
    
    //sycl_lib.cpp
    #include<CL/sycl.hpp>
    using namespace sycl;
    void func() {
      queue q;
      q.submit([&](sycl::handler &h) {
          sycl::stream os(1024, 768, h);
          h.parallel_for(32, [=](sycl::id<1> i) {
              os<<i<<"\n";
            });
        });
    }
    
    
    # Makefile
    runG: sycl_lib.a
            g++ -c main.cpp
            dpcpp -o runG main.o sycl_lib.a -L$SYSL_DIR/lib -lsycl
            ./runG
    
    FAILrunG: sycl_lib.a
            g++ -o runG main.cpp sycl_lib.a -L$SYSL_DIR/lib -lsycl
            ./runG
    
    sycl_lib.a: sycl_lib.cpp
            dpcpp -c sycl_lib.cpp -fPIC
            ar rvs sycl_lib.a sycl_lib.o
            dpcpp -o runD main.cpp sycl_lib.a
            ./runD
    

    Thank you for pointing this out. I've added a general note to the book errata, and I'll talk with the dpcpp compiler documentation team about how we can document this clearly.