Search code examples
javacudaprocessbuilder

How to call a CUDA C app in Java through ProcessBuilder?


I have a very complex application that uses CUDA and was write in C. This application is command-line only and now I want to build a GUI using Java Swing.

I don't want to rewrite C code, so I'm calling the command-line version using a ProcessBuilder object. This way I can read messages from it and show on a console inside the GUI.

This is the code I'm using:

String command = "myApp";
pb = new ProcessBuilder("bash", "-c",command);
pb.redirectErrorStream(true);
Process shell;
try {
        shell = pb.start();
        InputStream shellIn = shell.getInputStream();
        Drawer.writeToLog(convertStreamToStr(shellIn));
        shellIn.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

public String convertStreamToStr(InputStream is) throws IOException{
    if(is != null){
        Writer writer = new StringWriter();

        char[] buffer = new char[1024];
        Reader reader = new BufferedReader(new InputStreamReader(is,"UTF-8"));
        int n;
        while((n = reader.read(buffer)) != -1){
            writer.write(buffer,0,n);
        }
        is.close();
        return writer.toString();
    }else{
        return "";
    }
}

If I try something like "ls" command it works fine. However, for my app I get this error:

./myApp: error while loading shared libraries: libcudart.so.5.0: cannot open shared object file: No such file or directory

CUDA is installed and properly configured in my machine, I can execute this app correctly from Terminal. I imagine that the error is from Java Virtual Machine.

How can I fix it?


Solution

  • This code works for me, I just tested it:

    System.out.printf("[Starter#main] !\n");
    final ProcessBuilder builder = new ProcessBuilder("absolute/path_to/your/executable");
    builder.redirectErrorStream(true);
    builder.environment().put("LD_LIBRARY_PATH",
        "/usr/local/cuda/lib64:/usr/local/cuda/lib");
    final Process start = builder.start();
    final InputStream outputStream = start.getInputStream();
    final BufferedReader reader = new BufferedReader(new InputStreamReader(outputStream));
    String s;
    while ((s = reader.readLine()) != null) {
        System.out.printf("[Starter#main] %s\n", s);
    }
    

    Gotchas:

    1. Make sure your application bitness matches your toolkit.
    2. Mac OS X variable is called "DYLD_LIBRARY_PATH"

    Also note:

    1. Spawned process will inherit environment from your Java process, that is it should work fine if you run Java application with PATH and LD_LIBRARY_PATH configured as advised by CUDA toolkit installer.
    2. You may externalize variables setting and launching your app in a shell script - then all you have to do is just running shell with a given script.