Linux, JNA: UnsatisfiedLinkError on liblo second method call - java

I like to control 'sooperlooper' from java, a sound looper. This uses the OSC protocol. First try was the Java OSC lib, but this doesn't do anything. Now I'm trying JNA to wrap liblo.so
The program I'm trying to replicate in JAVA is very simple (of course with different commands from "record"):
static lo_address addr;
int main(int argc, char *argv[])
{
addr = lo_address_new(<IP>, "9951");
lo_send(addr, "/sl/-1/down", "s", "record");
}
The C declaration of the failing method is (https://github.com/radarsat1/liblo/blob/master/lo/lo.h.in):
int lo_send(lo_address targ, const char *path, const char *type, ...);
If I understand correctly, the lo_address is some void pointer type declared elsewhere.
My library interface is:
public interface LibLo extends Library {
Pointer lo_address_new(String host, String port);
int lo_send(Pointer address, String command, String a, String... params);
}
And my caller code is this:
System.setProperty("jna.debug_load", "true");
System.setProperty("jna.debug_load.jna", "true");
LibLo libLo = Native.loadLibrary("liblo", LibLo.class);
Pointer pointer = libLo.lo_address_new(<IP>, "9951");
libLo.lo_send(pointer, "/sl/-1/down","s", "record");
It perfectly gets through the lo_address_new call. 'pointer' does have some value. I think my arguments are correct.
And I discovered even with incorrect arguments, it gets past the lo_address_new call.
My stdout is:
...
Found library 'liblo' at /usr/lib/x86_64-linux-gnu/liblo.so.7.3.0
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'lo_send': /usr/lib/x86_64-linux-gnu/liblo.so.7.3.0: undefined symbol: lo_send
at com.sun.jna.Function.<init>(Function.java:245)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:566)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:542)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:528)
at com.sun.jna.Library$Handler.invoke(Library.java:228)
at com.sun.proxy.$Proxy0.lo_send(Unknown Source)
at nl.ronaldteune.coverdownloader.Main.main(Main.java:30)
Other questions about UnsatisfiedLinkError point to more thorough problems. I can't find 'lo_send' when opening the lib with vim, I can find lo_send_message though - but it's more low level. However, I think my C program is using the same lib (compiled with -llo) and it doesn't have problems to run.
So... I'm stuck. Anyone know how I can debug further?

You can't map lo_send() to JNA (and it doesn't appear in your vim output) because it's a macro:
#define lo_send(targ, path, types...) \
lo_send_internal(targ, __FILE__, __LINE__, path, types, \
LO_MARKER_A, LO_MARKER_B)
You could, in theory, map lo_send_internal() but the source code comments for it say:
/* Don't call lo_send_internal directly, use lo_send, a macro wrapping this
* function with appropriate values for file and line */
Which makes sense as it needs to know the source code __FILE__ and __LINE__ number at compile time, and any hack you'd make in JNA for these values would have to assume you have the correct source code used to compile your binary .so. You'd also need the markers but they are at least constants, amusing words spelled out in hex code.
You could probably just toss in dummy values for the file and line to make your code work, but otherwise, your C wrapper function calling lo_send() looks like the best workaround in this case.

OK, I worked around it... With a wrapper lib:
#include <lo/lo.h>
static lo_address addr;
lo_address slGetAddress() {
return lo_address_new("IP", "9951");
}
void slSendFull(lo_address addr, const char *command) {
lo_send(addr, "/sl/-1/down", "s", command);
}
void slSendSimple(const char *command) {
addr = slGetAddress();
lo_send(addr, "/sl/-1/down", "s", command);
}
and this compile script:
#!/bin/bash
# sudo ln -s /usr/lib/arm-linux-gnueabihf/liblo.so.7 /usr/local/lib/liblo.so
# sudo ln -s /usr/lib/x86_64-linux-gnu/liblo.so.7 /usr/local/lib/liblo.so
gcc -c -Wall -O2 -fPIC lowrapper.c -llo
ld -shared lowrapper.o /usr/local/lib/liblo.so -o lowrapper.so
sudo cp lowrapper.so /usr/local/lib/
It's working now. Still interested in a real answer, but not in a hurry for that anymore :)

Related

dlsym ends in infinite loop

I am trying to build a Linux library(*.so) to use it in a Java application. This library itself loads an dll-file with native functions.
This is my C++ code:
__delspec(dllexport) void __cdecl GetDllVersion(void){
typedef int(*GetDllVersion)(int*,int*,int*,int*);
void* lib = dlopen("~/lib.dll",RTLD_NOW);
cout << "Loading Symbol..." << endl;
GetDllVersion getVer= (GetDllVersion) dlsym(lib,"GetDllVersion");
dlclose(lib);
}
The code was compiled with wineg++ -shared lib.cpp -o libexports.so -Wl,--no-as-needed -ldl without errors.
The Java application prints out "Loading Symbol..." in a loop and then terinates without any message. I could determine that this has to do something with dlsym().
With nm -D lib.so I could look inside the lib.so. The function GetDllVersion() is indeed a symbol inside this library.
Can somebody tell me why there is a infinite loop and wyh the Java VM is terminating?
Regards Wurmi
This line:
void* lib = dlopen("~/lib.dll",RTLD_NOW);
will always fail, because dlopen does not do tilde-expansion (in general, only shell does). You really should check dlopen return value.
This line:
GetDllVersion getVer= (GetDllVersion) dlsym(lib,"GetDllVersion");
is equivalent to dlsym(RTLD_DEFAULT, ...) (because RTLD_DEFAULT == 0 and lib == NULL) and as such returns you a pointer to the function you are already in, resulting in infinite recursion, and eventual crash due to stack exhaustion.

Passing pre-escaped command-line arguments to ProcessBuilder

I bumped into this problem today when setting up a local set of communicating programs. Basically one of my applications is sending some data to another, and part of this data is a string containing a command to execute (like you would from the command-line). Let's say, for example:
g++ foo.cc bar.cc -o foobar
is the command sent by my first application. The second application, which receives the command (amongst other things), needs to execute this command after doing some other processing.
Now, at first I thought this would be trivial using a ProcessBuilder:
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
ProcessBuilder builder = new ProcessBuilder(exampleCommand);
builder.start().waitFor();
However this is where the problem occurs.
CreateProcess error=2, The system cannot find the file specified
Okay, no worries I guess I can't just dump the whole thing into the builder. The first part of the command is usually a trivial string so I thought I could probably get away with a split around the first ' ' to separate the program name and arguments.
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
String[] parts = exampleCommand.split(" ", 2);
ProcessBuilder builder = new ProcessBuilder(parts[0], parts[1]);
builder.start().waitFor();
And this brought me a little closer, the g++ file could now be found correctly, however after examining the stderr of g++ I found that the following error had occurred:
g++.exe: error: foo.cc bar.cc -o foobar: No such file or directory
At this point I realised that the ProcessBuilder class must be escaping all arguments passed to it in preparation for the command-line (hence the reason it usually takes arguments as an array of individual arguments rather than just a predefined argument string).
My question is, "Is there any way to pass a raw string of arguments to a ProcessBuilder and say THERE, execute EXACTLY this?"
Because the command comes from another application and is in no way static I can't just break the arguments down into an array beforehand and pass them to the ProcessBuilder constructor properly. The arguments are not so trivial that simply splitting the string around a ' ' will work properly either; arguments might contain spaces escaped with double quotes. For example:
g++ "..\my documents\foo.cpp" bar.cpp -o foobar
Could be a command coming from the application and splitting that string around ' ' and passing it to the ProcessBuilder will result in corrupt arguments.
If there is no proper way to do this can someone please point me to a standalone command line argument parser (in Java) that can turn a command-line string into a valid String[]?
Okay I feel rather foolish now but I achieved my desired result by simply reverting back to the good old Runtime.getRuntime().exec(...). I'll leave the question up in case anyone is as silly as me and find it useful.
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
Runtime sys = Runtime.getRuntime();
sys.exec(exampleCommand);
Easy.
A comment to the Runtime.getRuntime().exec(...) solution:
The Runtime.getRuntime().exec(...) is not good anymore. In java executed on OSX El Capitan, 'Runtime.getRuntime().exec(...)' contains an error that sometimes closes the opened process when the java program exits. It works fine on previous OSX versions. However, ProcessBuilder works on all OSX versions.
(Haven't posted enough to have a enough rep points to make this as a normal comment.)

Constness error in SWIG-generated wrapper code for a Director

So, I'm trying to use swig to wrap a c++ library to make JNI calls to it. But, the _wrap.cxx file that swig is creating for me won't compile cleanly in g++. What am I doing wrong?
Here's a simple test case that will reproduce the error, along with a couple of other cases that don't error. My header file:
class MyClass {
};
class MyDirectored {
public:
virtual void Overridable (MyClass const clz);
virtual ~MyDirectored();
};
and here's my .i file:
%module("directors="1") swigtest
%{
#include "swig.h"
%}
%feature("director") MyDirectored
%include "swig.h"
I'm attempting to build via the following:
swig -c++ -package gen -java -outdir gen swig.i
g++ -c swig_wrap.cxx -o swig_wrap.o
And the g++ step yields the following error:
swig_wrap.cxx: In member function 'virtual void SwigDirector_MyDirectored::Overridable(MyClass)':
swig_wrap.cxx:436: error: invalid conversion from 'const MyClass*' to 'MyClass*'
Which appears to be a legitimate complaint - the resulting swig_wrap.cxx file looks like (lots of snippage)
void SwigDirector_MyDirectored::Overridable (MyClass const clz) {
//...
jlong jclz;
//...
*((MyClass **)&jclz) = &clz; //Error on this line
//...
}
I get the same error in both swig 2.0.4 and 1.3.40, Linux and Windows. Any suggestions? Any g++ trick I could use to ignore the constness error?
Random notes: I can't control the input header, so changing the function signature is a no-go. It doesn't appear to matter what type the input parameter is - class or struct. Making it a const reference instead of a const value parameter does "fix" the error by causing SWIG to explicitly cast away the constness (but again, I can't change the input header).
Thanks in advance!

Calling Haskell from Java with C in between

This probably sounds like a nightmare, but I'd really like to get this working. I am using this example for the most part: Calling C from Haskell and am trying to get this working on ubuntu.
I am running this in java:
package test;
public class JniTest {
public native int fib(int x);
}
this in c after creating the .h file with javah: (test_JniTest.c)
#include "test_JniTest.h"
#include "Safe_stub.h"
JNIEXPORT jint JNICALL Java_test_JniTest_fib(JNIEnv * e, jobject o, jint f)
{
return fibonacci_hs(f);
}
and then for reference in haskell (before stub): (Safe.hs)
module Safe where
import Foreign.C.Types
fibonacci :: Int -> Int
fibonacci n = fibs !! n
where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibonacci_hs :: CInt -> CInt
fibonacci_hs = fromIntegral . fibonacci . fromIntegral
foreign export ccall fibonacci_hs :: CInt -> CInt
and this is what i'm trying to compile it with:
ghc -c -O Safe.hs
followed by:
ghc -shared -o libTest.jnilib -optc-O test_JniTest.c
-I/usr/lib/jvm/java-6-sun-1.6.0.26/include -I/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux
and I am getting this error:
/usr/bin/ld: test_JniTest.o: relocation R_X86_64_PC32 against
undefined symbol `fibonacci_hs' can not be used when making a shared
object; recompile with -fPIC /usr/bin/ld: final link failed: Bad value
collect2: ld returned 1 exit status
I am not a c expert by any means and have no idea what to do about this. I tried compiling various ways with -fPIC, but I kept on getting the same error. Any idea what I might be doing wrong?
Thanks!
Although I've pretty much answered this question here: Communication between Java and Haskell, since this issue is more about the error itself, I will be adding the details for that here. The issue stems from Haskell not supporting shared libraries very well, while Java requires them.
Buildings plugins as Haskell shared libs gives us this insight and workaround:
In principle you can use -shared without -dynamic in the link step. That would mean to statically link the rts all the base libraries into your new shared library. This would make a very big, but standalone shared library. However that would require all the static libraries to have been built with -fPIC so that the code is suitable to include into a shared library and we don't do that at the moment.
If we use ldd again to look at the libfoo.so that we've made we will notice that it is missing a dependency on the rts library. This is problem that we've yet to sort out, so for the moment we can just add the dependency ourselves:
$ ghc --make -dynamic -shared -fPIC Foo.hs -o libfoo.so \
-lHSrts-ghc6.11 -optl-Wl,-rpath,/opt/ghc/lib/ghc-6.11/
This is a workaround because it requires us to know the version of the rts library at build time.
If your goal is to actually get something done (as opposed to just playing around with JNI) I suggest tackling this as a garden variety RPC problem and utilizing one of the many framework/protocols for it:
Protocol Buffers from Google
Thrift from Facebook
Avro (well this is mostly a wire protocol)
From what you are trying to do, Thrift might be your best bet since it describes a full client/server RPC stack but I'm pretty sure any of them would pretty much work over a simple socket.

How do I find my PID in Java or JRuby on Linux?

I need to find the PID of the current running process on a Linux platform (it can be a system dependent solution). Java does not support getting the process ID, and JRuby currently has a bug with the Ruby method, Process.pid.
Is there another way to obtain the PID?
If you have procfs installed, you can find the process id via the /proc/self symlink, which points to a directory whose name is the pid (there are also files here with other pertinent information, including the PID, but the directory is all you need in this case).
Thus, with Java, you can do:
String pid = new File("/proc/self").getCanonicalFile().getName();
In JRuby, you can use the same solution:
pid = java.io.File.new("/proc/self").canonical_file.name
Special thanks to the #stackoverflow channel on free node for helping me solve this! (specifically, Jerub, gregh, and Topdeck)
Only tested in Linux using Sun JVM. Might not work with other JMX implementations.
String pid = ManagementFactory.getRuntimeMXBean().getName().split("#")[0];
You can use the JNI interface to call the POSIX function getpid(). It is quite straight forward. You start with a class for the POSIX functions you need. I call it POSIX.java:
import java.util.*;
class POSIX
{
static { System.loadLibrary ("POSIX"); }
native static int getpid ();
}
Compile it with
$ javac POSIX.java
After that you generate a header file POSIX.h with
$ javah -jni POSIX
The header file contains the C prototype for the function with wraps the getpid function. Now you have to implement the function, which is quite easy. I did it in POSIX.c:
#include "POSIX.h"
#include <sys/types.h>
#include <unistd.h>
JNIEXPORT jint JNICALL Java_POSIX_getpid (JNIEnv *env, jclass cls)
{
return getpid ();
}
Now you can compile it using gcc:
$ gcc -Wall -I/usr/lib/jvm/java-1.6.0-sun-1.6.0.21/include -I/usr/lib/jvm/java-1.6.0-sun-1.6.0.21/include/linux -o libPOSIX.so -shared -Wl,-soname,libPOSIX.so POSIX.c -static -lc
You have to specify the location where your Java is installed. That's all. Now you can use it. Create a simple getpid program:
public class getpid
{
public static void main (String argv[])
{
System.out.println (POSIX.getpid ());
}
}
Compile it with javac getpid.java and run it:
$ java getpid &
[1] 21983
$ 21983
The first pid is written by the shell and the second is written by the Java program after shell prompt has returned. ∎
Spawn a shell process that will read its parent's pid. That must be our pid. Here is the running code, without exception and error handling.
import java.io.*;
import java.util.Scanner;
public class Pid2
{
public static void main(String sArgs[])
throws java.io.IOException, InterruptedException
{
Process p = Runtime.getRuntime().exec(
new String[] { "sh", "-c", "ps h -o ppid $$" });
p.waitFor();
Scanner sc = new Scanner(p.getInputStream());
System.out.println("My pid: " + sc.nextInt());
Thread.sleep(5000);
}
}
This solution seems to be the best if the PID is to be obtained only to issue another shell command. It's enough to wrap the command in back quotes to pass it as an argument to another command, for example:
nice `ps h -o ppid $$`
This may substitue the last string in the array given to exec call.
Java 9 finally offers an official way to do so with ProcessHandle:
ProcessHandle.current().pid();
This:
First gets a ProcessHandle reference for the current process.
In order to access its pid.
No import necessary as ProcessHandle is part of java.lang.
You can try getpid() in JNR-Posix.
It also has a Windows POSIX wrapper that calls getpid() off of libc. No JNI needed.

Categories