Javacpp-presets: Problems with presets for annoy

Created on 29 May 2016  Â·  14Comments  Â·  Source: bytedeco/javacpp-presets

I am trying to implement presets for the annoy header-only library.
The C++ classes AnnoyIndexInterface and AnnoyIndex from annoylib.h heavily rely on templates and I just can't figure out how to handle those.
This is the preset that I currently have. It successfully generates the classes RandRandom, Angular and Euclidean but doesn't output anything else into annoy.java.

@Properties(target="org.bytedeco.javacpp.annoy", value={@Platform(include="annoylib.h", link="[email protected]")})
public class annoy implements InfoMapper {
    public void map(InfoMap infoMap) {
    }
}
bug question

Most helpful comment

Ah, I see the problem. It's matching types in a very dumb way, and we can't have whitespaces after the commas. So this works:

@Properties(target="org.bytedeco.javacpp.annoy", value={@Platform(include="annoylib.h", link="[email protected]")})
public class annoy implements InfoMapper {
    public void map(InfoMap infoMap) {
      infoMap
        .put(new Info("AnnoyIndexInterface<int,float>").pointerTypes("AnnoyIndexInterface"))
        .put(new Info("AnnoyIndex<int,float,Euclidean,Kiss64Random>").pointerTypes("AnnoyIndex").base("AnnoyIndexInterface"))
        ;
    }
}

I have to figure out a better way to normalize type names...

All 14 comments

For templates, we need to create instances. Here's a few simple examples in the case of OpenCV:
https://github.com/bytedeco/javacpp-presets/blob/master/opencv/src/main/java/org/bytedeco/javacpp/presets/opencv_core.java#L198
Try something like that!

Thank You! At least it generates now. But during compilation many errors occur.
I think it has something todo with the namespace. How can I set it to nothing?

Here are some of the compiler errors:

/home/rene/repositories/javacpp-presets/annoy/target/classes/org/bytedeco/javacpp/jniannoy.cpp:480:93: error: expected class-name before ‘{’ token
 class JavaCPP_hidden JavaCPP__0003a_0003aAnnoyIndexInterface : public ::AnnoyIndexInterface {
                                                                                             ^
/home/rene/repositories/javacpp-presets/annoy/target/classes/org/bytedeco/javacpp/jniannoy.cpp:495:13: error: ‘template<class S, class T> class AnnoyIndexInterface’ used without template parameters
     using ::AnnoyIndexInterface::verbose;
             ^
/home/rene/repositories/javacpp-presets/annoy/target/classes/org/bytedeco/javacpp/jniannoy.cpp: In constructor ‘JavaCPP__0003a_0003aAnnoyIndexInterface::JavaCPP__0003a_0003aAnnoyIndexInterface()’:
/home/rene/repositories/javacpp-presets/annoy/target/classes/org/bytedeco/javacpp/jniannoy.cpp:525:70: error: expected class-name before ‘(’ token
     JavaCPP__0003a_0003aAnnoyIndexInterface() : ::AnnoyIndexInterface(), obj(NULL) { }
                                                                      ^
/home/rene/repositories/javacpp-presets/annoy/target/classes/org/bytedeco/javacpp/jniannoy.cpp: In function ‘jint JNI_OnLoad(JavaVM*, void*)’:
/home/rene/repositories/javacpp-presets/annoy/target/classes/org/bytedeco/javacpp/jniannoy.cpp:623:34: error: missing template arguments before ‘)’ token
             { sizeof(::AnnoyIndex) },
                                  ^
/home/rene/repositories/javacpp-presets/annoy/target/classes/org/bytedeco/javacpp/jniannoy.cpp:624:43: error: missing template arguments before ‘)’ token
             { sizeof(::AnnoyIndexInterface) },
                                           ^

Preset:

@Properties(target="org.bytedeco.javacpp.annoy", value={@Platform(include="annoylib.h", link="[email protected]")})
public class annoy implements InfoMapper {
    public void map(InfoMap infoMap) {
      infoMap
        .put(new Info("AnnoyIndexInterface<int, float>").pointerTypes("AnnoyIndexInterface").virtualize())
        .put(new Info("AnnoyIndex<int, float, Euclidean, Kiss64Random>").pointerTypes("AnnoyIndex").base("AnnoyIndexInterface"));
    }
}

You're trying to use "AnnoyIndexInterface" as a base class, but it's not a class, it's a class template.

But it should still be working... What does the generated target class look like?

The @Name annotations are missing... Does the same thing happen if you use different names for the Java Pointer subclasses?

Is the issue with the @Name annotation on my side? Did I forget anything?
You mean like so?

package org.bytedeco.javacpp.presets;

import org.bytedeco.javacpp.annotation.*;
import org.bytedeco.javacpp.tools.*;

@Properties(target="org.bytedeco.javacpp.annoy", value={@Platform(include="annoylib.h", link="[email protected]")})
public class annoy implements InfoMapper {
    public void map(InfoMap infoMap) {
      infoMap
        .put(new Info("AnnoyIndexInterface<int, float>").pointerTypes("TestAnnoyIndexInterface"))
        .put(new Info("AnnoyIndex<int, float, Euclidean, Kiss64Random>").pointerTypes("TestAnnoyIndex").base("TestAnnoyIndexInterface"))
        ;
    }
}

No you didn't forget anything. It should be appended by the Parser.

Yes, something like that. Any better?

No, pretty much the same compiler errors occur.
Here is the current code:
https://gist.github.com/ReneHollander/bd18366ae1a924803725f59f4c235910

Ah, I see the problem. It's matching types in a very dumb way, and we can't have whitespaces after the commas. So this works:

@Properties(target="org.bytedeco.javacpp.annoy", value={@Platform(include="annoylib.h", link="[email protected]")})
public class annoy implements InfoMapper {
    public void map(InfoMap infoMap) {
      infoMap
        .put(new Info("AnnoyIndexInterface<int,float>").pointerTypes("AnnoyIndexInterface"))
        .put(new Info("AnnoyIndex<int,float,Euclidean,Kiss64Random>").pointerTypes("AnnoyIndex").base("AnnoyIndexInterface"))
        ;
    }
}

I have to figure out a better way to normalize type names...

It works now! Thank you for your help!

Great! (I want to keep this issue opened to remind me to fix this though...)

Hi,

I am trying to link the very same lib with the very same preset.
Unfortunately i get a crash during compilation:

g++ -I/...path.../jniannoy_preset.cpp -march=x86-64 -m64 -O3 -s -ffast-math -Wl,-rpath,$ORIGIN/ -Wl,-z,noexecstack -Wl,-Bsymbolic -Wall -fPIC -shared -o libjniannoy_preset.so -lz 
In file included from /...path.../jniannoy_preset.cpp:101:0:
/...path.../jniannoy_preset.cpp: In function ‘jint Java_org_bytedeco_javacpp_annoy_ANNOY_1NODE_1ATTRIBUTE(JNIEnv*, jclass)’:
/...path.../cpp/annoylib.h:52:32: error: expected primary-expression before ‘__attribute__’
   #define ANNOY_NODE_ATTRIBUTE __attribute__((__packed__))
                                ^
/...path.../jniannoy_preset.cpp:3693:18: note: in expansion of macro ‘ANNOY_NODE_ATTRIBUTE’
     int rvalue = ANNOY_NODE_ATTRIBUTE;
                  ^~~~~~~~~~~~~~~~~~~~

The lib has slightly evolved.
The new file is here: https://github.com/spotify/annoy/blob/master/src/annoylib.h

I am using the javacpp-sbt plugin.

Does it make any sense to you? @saudet

Kind regards,
Michaël

@ReneHollander @pommedeterresautee These issues and current workarounds with the Parser are now well documented in the Mapping Recipes for C/C++ Libraries so I don't need to leave this issue open to remind me of this. :) However, we still need to figure out a better way to parse header files. The more I think about it, the more I feel it's going to be a hybrid of libclang (see issue https://github.com/bytedeco/javacpp/issues/51) and the current Parser.

/cc @Arcnor

As for Annoy itself, we still have pull #399 open and looking for help!

Was this page helpful?
0 / 5 - 0 ratings