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) {
}
}
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?
Here are the files:
https://gist.github.com/ReneHollander/85b6dd2416363d003a33073ac50514df
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!
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:
I have to figure out a better way to normalize type names...