I'm trying to link a library in a JNI project I have. I'm running into a strange bug where the console output tells me that there was a "symbol not found for x86 64 architecture". I'm kinda stumped on what could be going wrong. There are other classes but they're way too many to put here. Here's my code:
EDIT: I'll include the entire console debug log. It doesn't mention which symbol is the one in question.
EDIT 2: I fixed a static variable that was a problem, but it's still giving an error. Updated the code to reflect changes
Console Debug Log:
14:24:05 **** Build of configuration Debug for project HPA* Program ****
make all
cc -v -c -stdlib=libstdc++ -fPIC -I/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/ HPAProgram.c++ -o libhpaprogram.o
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.9.0 -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name HPAProgram.c++ -mrelocation-model pic -pic-level 2 -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 224.1 -v -coverage-file "/Users/zalbhathena/Documents/workspace/Thesis-Test-Application/HPA* Program/jni/libhpaprogram.o" -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/5.0 -I /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/ -stdlib=libstdc++ -fdeprecated-macro -fdebug-compilation-dir "/Users/zalbhathena/Documents/workspace/Thesis-Test-Application/HPA* Program/jni" -ferror-limit 19 -fmessage-length 0 -stack-protector 1 -mstackrealign -fblocks -fobjc-runtime=macosx-10.9.0 -fobjc-dispatch-method=mixed -fobjc-default-synthesize-properties -fencode-extended-block-signature -fcxx-exceptions -fexceptions -fdiagnostics-show-option -o libhpaprogram.o -x c++ HPAProgram.c++
clang -cc1 version 5.0 based upon LLVM 3.3svn default target x86_64-apple-darwin13.0.0
ignoring nonexistent directory "/usr/include/c++/4.2.1/i686-apple-darwin10/x86_64"
ignoring nonexistent directory "/usr/include/c++/4.0.0"
ignoring nonexistent directory "/usr/include/c++/4.0.0/i686-apple-darwin8/"
ignoring nonexistent directory "/usr/include/c++/4.0.0/backward"
ignoring nonexistent directory "/usr/local/include"
#include "..." search starts here:
#include <...> search starts here:
/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers
/usr/include/c++/4.2.1
/usr/include/c++/4.2.1/backward
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/5.0/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
/usr/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)
End of search list.
libtool -dynamic -lSystem libhpaprogram.o -o libhpaprogram.dylib
ld: warning: -macosx_version_min not specified, assuming 10.8
Undefined symbols for architecture x86_64:
"__Z11create_dcdtv", referenced from:
_Java_HPAProgram_sayHello in libhpaprogram.o
ld: symbol(s) not found for architecture x86_64
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: internal link edit command failed
make: *** [libhpaprogram.dylib] Error 1
14:24:05 Build Finished (took 162ms)
HPAProgram.c++
#include <stdio.h>
#include "HPAProgram.h"
#include "DCDTWrapper.h"
extern void create_dcdt();
JNIEXPORT void JNICALL Java_HPAProgram_sayHello (JNIEnv *env, jobject obj) {
printf("Hello World!\n");
create_dcdt();
}
DCDTWrapper.h
# include "DCDTsrc/se_dcdt.h"
# include "DCDTsrc/gs_polygon.h"
# include <stdlib.h>
void create_dcdt ();
DCDTWrapper.c++
# define END 12345.6
# define FIRST_EXAMPLE Example1
//# include "DCDTsrc/se_dcdt.h"
//# include "DCDTsrc/gs_polygon.h"
//# include <stdlib.h>
# include "DCDTWrapper.h"
static double Example1[] =
{ -10, -10, 10, -10, 10, 10, -10, 10, END,
1, 1, 7, 3, 3, 8, END,
END };
static const double* CurExample = FIRST_EXAMPLE;
static SeDcdt *TheDcdt;
static GsPolygon CurPath;
static GsPolygon CurChannel;
static float CurX1=0, CurY1=0, CurX2=0, CurY2=0;
static int CurSelection=0; // -2,-1: moving point, >0: moving polygon
void create_dcdt ()
{
const double* data = CurExample;
GsPolygon pol;
// domain:
while ( *data!=END ) { pol.push().set((float)data[0],(float)data[1]); data+=2; }
TheDcdt->init ( pol, 0.00001f );
while ( *++data!=END )
{ pol.size(0);
while ( *data!=END ) { pol.push().set((float)data[0],(float)data[1]); data+=2; }
TheDcdt->insert_polygon ( pol );
}
}
makefile:
# Define a variable for classpath
CLASS_PATH = ../bin
# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)
all: libhpaprogram.dylib
# $# matches the target, $< matches the first dependancy
libhpaprogram.dylib:
cc -v -c -stdlib=libstdc++ -fPIC -I/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/ HPAProgram.c++ -o libhpaprogram.o
libtool -dynamic -lSystem libhpaprogram.o -o libhpaprogram.dylib
HPAProgram.h : HPAProgram.class
javah -classpath $(CLASS_PATH) $*
clean:
rm HPAProgram.h libhpaprogram.o libhpaprogram.dylib
This is your problem:
static void create_dcdt ();
When you declare a global object static in a header file, every single translation unit (ie: cpp file) that includes it will want to create their own version of that object.
You probably want to qualify create_dcdt() with extern:
extern void create_dcdt();
Then in the file DCDTWrapper.c++ remove the static qualifier.
This will tell the compiler to allow all versions of the undefined object to be resolved at link time, to a single version that lives in one cpp file.
(the extern keyword is probably optional but you certainly do not want to use static here)
The second part of your problem is that you are not including the DCDTWrapper.c++ file in your build project.
Modify your makefile like this:
libhpaprogram.dylib:
cc -v -c -stdlib=libstdc++ -fPIC -I/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/ HPAProgram.c++ -o libhpaprogram.o
cc -v -c -stdlib=libstdc++ -fPIC -I/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/ DCDTWrapper.c++ -o DCDTWrapper.o
libtool -dynamic -lSystem libhpaprogram.o DCDTWrapper.o -o libhpaprogram.dylib
I fixed my problem, here's the updated makefile:
SRC=DCDTsrc
TGT=obj
INCLUDES=-IDCDTsrc DCDTWrapper.h SearchAlgorithms.h
FLAGS=-stdlib=libstdc++ -std=c++0x -D GS_SYSTEM_RAND_LIBS -lm -fPIC -I/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/ -v
SOURCES=$(wildcard $(SRC)/*.cpp) DCDTWrapper.cpp SearchAlgorithms.cpp
OBJS=$(addprefix $(TGT)/, $(notdir $(SOURCES:.cpp=.o)))
CC=g++
# Define a variable for classpath
CLASS_PATH = ../bin
# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)
$(TGT)/%.o: $(SRC)/%.cpp
$(CC) $(FLAGS) -c $< -o $#
$(TGT)/%.o: %.cpp
$(CC) $(FLAGS) -c $< -o $#
# $# matches the target, $< matches the first dependancy
libsearchalgorithms.dylib: $(OBJS)
libtool -lc -lstdc++ -ldl -macosx_version_min 10.9 -lm -dynamic -lSystem $(OBJS) -o libsearchalgorithms.dylib
SearchAlgorithms.h : SearchAlgorithms.class
javah -classpath $(CLASS_PATH) $*
clean:
rm -rf $(TGT)
mkdir $(TGT)
if [ -a SearchAlgorithms.h ] ; \
then \
rm SearchAlgorithms.h ; \
fi;
if [ -a libsearchalgorithms.o ] ; \
then \
rm libsearchalgorithms.o ; \
fi;
if [ -a libsearchalgorithms.dylib ] ; \
then \
rm libsearchalgorithms.dylib ; \
fi;
all:clean SearchAlgorithms.h libsearchalgorithms.dylib
Related
I am trying to include a C++ library with my swing project..
When I compile the jnilib/so, with stdio.h it works fine for this:
gcc -shared -o libhello.jnilib hello.c -fPIC -I/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/include/darwin
I am trying to import and need to use gnu-libstdc++/4.9
How do I link my java project?
When I try to build the jni file:
It will throw this:
test.c:5:10: fatal error: 'string' file not found
#include <string>
EDIT
Now when I link to this:
-I /Users/tnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86_64/include
It throws this error:
...
/Users/tnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86_64/include/bits/ctype_base.h:69:37: error: use of undeclared identifier '_U'
static const mask graph = _P | _U | _L | _N;
^
/Users/tnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86_64/include/bits/ctype_base.h:69:42: error: use of undeclared identifier '_L'
static const mask graph = _P | _U | _L | _N;
^
/Users/tnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86_64/include/bits/ctype_base.h:69:47: error: use of undeclared identifier '_N'
static const mask graph = _P | _U | _L | _N;
^
/Users/tnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86_64/include/bits/ctype_base.h:70:32: error: use of undeclared identifier '_C'
static const mask cntrl = _C;
^
/Users/tnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86_64/include/bits/ctype_base.h:71:32: error: use of undeclared identifier '_P'
static const mask punct = _P;
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
EDIT2
After adding -I /Users/timnuwin/Documents/ndk/android-ndk-r12b/platforms/android-17/arch-x86/usr/include now it throws:
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cwchar:164:11: error: no member named 'vfwscanf' in the global namespace
using ::vfwscanf;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cwchar:170:11: error: no member named 'vswscanf' in the global namespace
using ::vswscanf;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cwchar:174:11: error: no member named 'vwscanf' in the global namespace
using ::vwscanf;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cwchar:191:11: error: no member named 'wcstof' in the global namespace
using ::wcstof;
~~^
In file included from hello.cpp:6:
In file included from /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/sstream:38:
In file included from /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/istream:38:
In file included from /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/ios:44:
In file included from /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/basic_ios.h:37:
In file included from /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/locale_facets.h:39:
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cwctype:89:11: error: no member named 'iswblank' in the global namespace; did you
mean 'isblank'?
using ::iswblank;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/platforms/android-17/arch-x86/usr/include/ctype.h:88:5: note: 'isblank' declared here
int isblank(int);
^
1 warning and 5 errors generated.
EDIT3
Okay I think I'm a little closer here's the updated includes...
gcc -shared -o libhello.jnilib hello.cpp -fPIC
-I/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/include
-I/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/include/darwin
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/backward
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/debug
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/decimal
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/experimental
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/ext
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/parallel
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/profile
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/tr1
-I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/tr2
But now it throws:
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/tr1/stdio.h:8:10: fatal error: 'tr1/cstdio' file not found
#include
EDIT
Alrighty, setting the include to be the base dir include -I /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include now throws:
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cstdio:98:11: error: no member named 'FILE' in the global namespace
using ::FILE;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cstdio:99:11: error: no member named 'fpos_t' in the global namespace
using ::fpos_t;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cstdio:101:11: error: no member named 'clearerr' in the global namespace
using ::clearerr;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cstdio:102:11: error: no member named 'fclose' in the global namespace
using ::fclose;
~~^
/Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/cstdio:103:11: error: no member named 'feof' in the global namespace
using ::feof;
~~^
clang++ -shared -o libhello.jnilib hello.cpp -fPIC -funwind-tables -no-canonical-prefixes -fexceptions -frtti -Os -g -DNDEBUG -DNDEBUG -fPIC -std=gnu++11 -I/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/include/darwin -isystem /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include -isystem /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86/include -isystem /Users/timnuwin/Documents/ndk/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/backward -I /Users/timnuwin/Documents/ndk/android-ndk-r12b/platforms/android-17/arch-x86/usr/include
That cmd was able to create my jnilib file. :D 3 days later hehe
Facing following error in makefile
Makefile:54: *** multiple target patterns. Stop.
Full source code of makefile as below
MINGW_HOME ?= C:/mingw
PRODUCTNAME ?= Jitsi
COMPANYNAME ?= jitsi.org
PRODUCTBUILDVERSION ?= 1.0.0.0
PRODUCTBUILDVERSION_COMMA ?= 1,0,0,0
TARGET_BASENAME ?= run
TARGET_DIR ?= ../../../../release/windows/tmp
ifeq ($(wildcard /bin/cygpath.*),/bin/cygpath.exe)
target.dir := $(shell cygpath --mixed "$(TARGET_DIR)")
cygwin.target.dir := $(shell cygpath --unix "$(TARGET_DIR)")
else
target.dir := $(TARGET_DIR)
cygwin.target.dir := $(TARGET_DIR)
endif
CC = $(MINGW_HOME)/bin/gcc.exe
CPPFLAGS := $(CPPFLAGS) \
-Wall -Wreturn-type \
-DPSAPI_VERSION=1 \
-DWINVER=0x0502 -D_WIN32_WINNT=0x0502 \
-I$(target.dir) \
-I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32"
LDFLAGS = -mwindows
LIBS = -ladvapi32 -lpsapi
MACHINE = $(shell $(CC) -dumpmachine)
WINDRES = $(MINGW_HOME)/bin/windres.exe
ifneq ("x$(MACHINE)","x")
ifeq ($(wildcard $(MINGW_HOME)/bin/$(MACHINE)-windres.*),$(MINGW_HOME)/bin/$(MACHINE)-windres.exe)
WINDRES = $(MINGW_HOME)/bin/$(MACHINE)-windres.exe
endif
endif
$(cygwin.target.dir)/$(TARGET_BASENAME).exe: $(cygwin.target.dir)/config.h registry.c run.c $(cygwin.target.dir)/run.res ../setup/nls.c
**$(CC) $(CPPFLAGS) registry.c run.c $(target.dir)/run.res ../setup/nls.c $(LDFLAGS) -o $(target.dir)/$(TARGET_BASENAME).exe $(LIBS)**
-$(MINGW_HOME)/$(MACHINE)/bin/strip.exe $(target.dir)/$(TARGET_BASENAME).exe
.PHONY: $(cygwin.target.dir)/config.h
$(cygwin.target.dir)/config.h:
-rm.exe -f ../../../../resources/install/windows/config.h
echo #define PRODUCTNAME "$(PRODUCTNAME)" > $(cygwin.target.dir)/config.h
echo #define COMPANYNAME "$(COMPANYNAME)" >> $(cygwin.target.dir)/config.h
echo #define PRODUCTBUILDVERSION "$(PRODUCTBUILDVERSION)" >> $(cygwin.target.dir)/config.h
echo #define PRODUCTBUILDVERSION_COMMA $(PRODUCTBUILDVERSION_COMMA) >> $(cygwin.target.dir)/config.h
echo #define TARGET_BASENAME "$(TARGET_BASENAME)" >> $(cygwin.target.dir)/config.h
echo #define TARGET_BASENAME_EXE "$(TARGET_BASENAME).exe" >> $(cygwin.target.dir)/config.h
$(cygwin.target.dir)/run.res: $(cygwin.target.dir)/config.h run.rc
$(WINDRES) -I../../../../resources/install/windows -I$(target.dir) run.rc -O coff -o $(target.dir)/run.res
and the line number 54 is given below.
$(CC) $(CPPFLAGS) registry.c run.c $(target.dir)/run.res ../setup/nls.c $(LDFLAGS) -o $(target.dir)/$(TARGET_BASENAME).exe $(LIBS)
what could be the possible cause for this.
Actually Had a silly mistake instead of Tab space there was spaces which was causing an issue.
I had this happen because I had a : in a filename.
Specifically, I had this crap
./lib/libwww-perl-5.837/share/man/man3/HTTP::Daemon.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Date.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Headers.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Headers::Util.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Message.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Negotiate.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Request.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Request::Common.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Response.3pm
./lib/libwww-perl-5.837/share/man/man3/HTTP::Status.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::Authen::Ntlm.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::ConnCache.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::Debug.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::MediaTypes.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::MemberMixin.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::Protocol.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::RobotUA.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::Simple.3pm
./lib/libwww-perl-5.837/share/man/man3/LWP::UserAgent.3pm
./lib/libwww-perl-5.837/share/man/man3/Net::HTTP.3pm
I have the following difficult to read script consisting of a single command:
#!/bin/sh
/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java \
-classpath /Users/afarber/src/jetty-newbie/EmbeddedWebsocket/target/classes:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-server/9.3.9.v20160517/jetty-server-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-http/9.3.9.v20160517/jetty-http-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-util/9.3.9.v20160517/jetty-util-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-io/9.3.9.v20160517/jetty-io-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-servlet/9.3.9.v20160517/jetty-servlet-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-security/9.3.9.v20160517/jetty-security-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-api/9.3.9.v20160517/websocket-api-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-server/9.3.9.v20160517/websocket-server-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-common/9.3.9.v20160517/websocket-common-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-client/9.3.9.v20160517/websocket-client-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-servlet/9.3.9.v20160517/websocket-servlet-9.3.9.v20160517.jar \
de.afarber.MyServlet
As slight readability improvement I would like to list all the paths after the -classpath in a separate variable, each aligned after the other:
PATHS= /Users/afarber/src/jetty-newbie/EmbeddedWebsocket/target/classes \
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-server/9.3.9.v20160517/jetty-server-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-http/9.3.9.v20160517/jetty-http-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-util/9.3.9.v20160517/jetty-util-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-io/9.3.9.v20160517/jetty-io-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-servlet/9.3.9.v20160517/jetty-servlet-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-security/9.3.9.v20160517/jetty-security-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-api/9.3.9.v20160517/websocket-api-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-server/9.3.9.v20160517/websocket-server-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-common/9.3.9.v20160517/websocket-common-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-client/9.3.9.v20160517/websocket-client-9.3.9.v20160517.jar \
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-servlet/9.3.9.v20160517/websocket-servlet-9.3.9.v20160517.jar
This way I can easier add and remove the paths, and sort them in Vim.
My question is: how to join them back for my command?
UPDATE:
If all JAR-files would be located in the same dir, I could have used the new Java 8 wildcard syntax java -classpath "/that/dir/*" de.afarber.MyServlet - but that wasn't the case here.
I suggest using heredoc for easy maintenance of this long list of class paths:
#!/bin/bash
# populate array cpath with all the the classpaths each one on different lines
read -d '' -ra cpath<<'EOF'
/Users/afarber/src/jetty-newbie/EmbeddedWebsocket/target/classes
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-server/9.3.9.v20160517/jetty-server-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-http/9.3.9.v20160517/jetty-http-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-util/9.3.9.v20160517/jetty-util-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-io/9.3.9.v20160517/jetty-io-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-servlet/9.3.9.v20160517/jetty-servlet-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-security/9.3.9.v20160517/jetty-security-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-api/9.3.9.v20160517/websocket-api-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-server/9.3.9.v20160517/websocket-server-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-common/9.3.9.v20160517/websocket-common-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-client/9.3.9.v20160517/websocket-client-9.3.9.v20160517.jar
/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-servlet/9.3.9.v20160517/websocket-servlet-9.3.9.v20160517.jar
EOF
# merge them with : as separator in classpath
printf -v classpath "%s:" "${cpath[#]}"
# execute the java command line
/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java \
-classpath "${classpath%:}" de.afarber.MyServlet
Since you are using bash, you can store the directory names in an array (with some refactoring just to make this example more readable):
repo=/Users/afarber/.m2/repository
jetty="$repo/org/eclipse/jetty"
websocket="$jetty/websocket"
paths=(
/Users/afarber/src/jetty-newbie/EmbeddedWebsocket/target/classes
"$jetty"/jetty-server/9.3.9.v20160517/jetty-server-9.3.9.v20160517.jar
$repo/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar
"$jetty"/jetty-http/9.3.9.v20160517/jetty-http-9.3.9.v20160517.jar
"$jetty"/jetty-util/9.3.9.v20160517/jetty-util-9.3.9.v20160517.jar
"$jetty"/jetty-io/9.3.9.v20160517/jetty-io-9.3.9.v20160517.jar
"$jetty"/jetty-servlet/9.3.9.v20160517/jetty-servlet-9.3.9.v20160517.jar
"$jetty"/jetty-security/9.3.9.v20160517/jetty-security-9.3.9.v20160517.jar
"$websocket"/websocket-api/9.3.9.v20160517/websocket-api-9.3.9.v20160517.jar
"$websocket"/websocket-server/9.3.9.v20160517/websocket-server-9.3.9.v20160517.jar
"$websocket"/websocket-common/9.3.9.v20160517/websocket-common-9.3.9.v20160517.jar
"$websocket"/websocket-client/9.3.9.v20160517/websocket-client-9.3.9.v20160517.jar
"$websocket"/websocket-servlet/9.3.9.v20160517/websocket-servlet-9.3.9.v20160517.jar
)
Note you don't need to end each line with a backslash; whitespace (including newlines) separate elements of the array. Once you have the array, you can join the elements with a colon using parameter expansion with a modified value of the IFS parameter.
/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java \
-classpath "$(IFS=:; echo "${paths[*]}")" de.afarber.MyServlet
A sed should do the trick:
colonPATHS=$(echo "$PATHS" | sed -r 's/\s+/:/g')
echo "$colonPATHS"
The sed turns sequences of whitespace into a ":".
Simple sed can do this
pathwithcolons=`echo $PATHS|sed 's/ \+\\ \+/:/g'`
I've ended up using the following script:
#!/bin/sh
REPO=/Users/afarber/.m2/repository
VERSION=9.3.9.v20160517
CPATHS=/Users/afarber/src/jetty-newbie/WebsocketServlet/target/classes
CPATHS=$CPATHS:$REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/jetty-http/$VERSION/jetty-http-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/jetty-io/$VERSION/jetty-io-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/jetty-security/$VERSION/jetty-security-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/jetty-server/$VERSION/jetty-server-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/jetty-servlet/$VERSION/jetty-servlet-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/jetty-util/$VERSION/jetty-util-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/websocket/websocket-api/$VERSION/websocket-api-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/websocket/websocket-client/$VERSION/websocket-client-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/websocket/websocket-common/$VERSION/websocket-common-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/websocket/websocket-server/$VERSION/websocket-server-$VERSION.jar
CPATHS=$CPATHS:$REPO/org/eclipse/jetty/websocket/websocket-servlet/$VERSION/websocket-servlet-$VERSION.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java \
-classpath $CPATHS de.afarber.MyServlet
I like it better than other solutions, because it does not spawn additional processes (like sed), is easier to read and can be translated to Windows CMD batch file:
#echo off
set REPO="C:\Users\user1\.m2\repository"
set VERSION=9.3.9.v20160517
set CPATHS=C:\Users\user1\jetty-newbie\WebsocketServlet\target\classes
set CPATHS=%CPATHS%;%REPO%\javax\servlet\javax.servlet-api\3.1.0\javax.servlet-api-3.1.0.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\jetty-http\%VERSION%\jetty-http-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\jetty-io\%VERSION%\jetty-io-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\jetty-security\%VERSION%\jetty-security-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\jetty-server\%VERSION%\jetty-server-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\jetty-servlet\%VERSION%\jetty-servlet-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\jetty-util-ajax\%VERSION%\jetty-util-ajax-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\jetty-util\%VERSION%\jetty-util-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\websocket\websocket-api\%VERSION%\websocket-api-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\websocket\websocket-client\%VERSION%\websocket-client-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\websocket\websocket-common\%VERSION%\websocket-common-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\websocket\websocket-server\%VERSION%\websocket-server-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\eclipse\jetty\websocket\websocket-servlet\%VERSION%\websocket-servlet-%VERSION%.jar
set CPATHS=%CPATHS%;%REPO%\org\postgresql\postgresql\9.4.1208.jre7\postgresql-9.4.1208.jre7.jar
"C:\Program Files\Java\jdk1.8.0_66\bin\java.exe" -cp %CPATHS% de.afarber.MyServlet
I wrote a C++ code that compiles in a standard environment. But when I try to translate it towards android shared library, with Swig utility, though I get the source_wrapp.cpp generated, the Android NDK fails to generate the library.
jni/ is the jni subfolder that i created for the purpose (when I remove it -build file for example-, the file is at the choosen project root)
Here is jni/goodComptSolver.h
#include <vector>
#include <string>
#ifndef GOOD_COMPT_SOLVER_H_
#define GOOD_COMPT_SOLVER_H_
class Solutions {
private:
std::vector<std::string> collection;
int maxSize;
public:
Solutions(int size = 5) : maxSize(size) {};
void push_back(const std::string &str);
int size() const;
const std::string& operator[](int index) const; // does not perform index cheching !!!
};
#endif
Here is jni/goodComptSolver.cpp
#include <iostream>
#include "goodComptSolver.h"
using std::cout;
using std::endl;
using std::vector;
using std::string;
void Solutions::push_back(const string &str)
{
if (collection.size() < maxSize)
collection.push_back(str);
}
int Solutions::size() const
{
return collection.size();
}
const string& Solutions::operator[](int index) const
{
return collection[index];
}
Here is jni/goodComptSolver.i
%module goodComptSolver
%rename(bracketOperator) operator[];
%{
#include "goodComptSolver.h"
%}
%include <std_string.i>
%include <std_vector.i>
%template(stringVector) std::vector<std::string>;
%include "goodComptSolver.h"
Here is my build file
swig -c++ -java -package com.loloof64.android_native.good_compt_solver -outdir . -o jni/goodComptSolver_wrap.cpp jni/goodComptSolver.i
echo "-------------------------------------------"
echo "Done with swig"
echo "-------------------------------------------"
ndk-build -B V=1
Here is my jni/Android.mk
# Sets the local path to current dir
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := goodComptSolver
LOCAL_SRC_FILES := goodComptSolver_wrap.cpp goodComptSolver.cpp
LOCAL_CFLAGS := -frtti
include $(BUILD_SHARED_LIBRARY)
Here is jni/Application.mk
APP_ABI := all
APP_STL := gnustl_static
Here is my build output :
$ ./build
-------------------------------------------
Done with swig
-------------------------------------------
rm -f ./libs/armeabi/lib*.so ./libs/armeabi-v7a/lib*.so ./libs/mips/lib*.so ./libs/x86/lib*.so
rm -f ./libs/armeabi/gdbserver ./libs/armeabi-v7a/gdbserver ./libs/mips/gdbserver ./libs/x86/gdbserver
rm -f ./libs/armeabi/gdb.setup ./libs/armeabi-v7a/gdb.setup ./libs/mips/gdb.setup ./libs/x86/gdb.setup
Compile++ thumb : goodComptSolver <= goodComptSolver_wrap.cpp
/home/laurent-bernabe/Programmes/android-ndk-r8e/toolchains/arm-linux-androideabi- 4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ -MMD -MP -MF ./obj/local/armeabi- v7a/objs/goodComptSolver/goodComptSolver_wrap.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 - fno-exceptions -fno-rtti -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing - finline-limit=64 -I/home/laurent-bernabe/Programmes/android-ndk-r8e/sources/cxx-stl/gnu- libstdc++/4.6/include -I/home/laurent-bernabe/Programmes/android-ndk-r8e/sources/cxx- stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include -Ijni -DANDROID -Wa,--noexecstack -frtti -I/home/laurent-bernabe/Programmes/android-ndk-r8e/platforms/android-3/arch-arm/usr/include -c jni/goodComptSolver_wrap.cpp -o ./obj/local/armeabi- v7a/objs/goodComptSolver/goodComptSolver_wrap.o
jni/goodComptSolver_wrap.cpp: In function 'const std::basic_string<char>& std_vector_Sl_std_string_Sg__get(std::vector<std::basic_string<char> >*, int)':
jni/goodComptSolver_wrap.cpp:231:72: error: exception handling disabled, use - fexceptions to enable
jni/goodComptSolver_wrap.cpp: In function '_jstring* Java_com_loloof64_android_1native_good_1compt_1solver_goodComptSolverJNI_stringVector_1get(J NIEnv*, jclass, jlong, jobject, jint)':
jni/goodComptSolver_wrap.cpp:376:73: error: '_e' was not declared in this scope
jni/goodComptSolver_wrap.cpp: In function 'void Java_com_loloof64_android_1native_good_1compt_1solver_goodComptSolverJNI_stringVector_1set(J NIEnv*, jclass, jlong, jobject, jint, jstring)':
jni/goodComptSolver_wrap.cpp:408:73: error: '_e' was not declared in this scope
make: *** [obj/local/armeabi-v7a/objs/goodComptSolver/goodComptSolver_wrap.o] Error 1
I can't post the generated jniCalls file, because it is at least about 400 lines.
I was inspired by this answer in my attempt : and extended in to a vector of string, instead of a native type. But it seems that i misunderstood something : what ?
My environement :
Ubuntu 13.04 64 bits
gcc 4.7.3
Swig 2.0.10
Android NDK recent
Thanks in advance.
Thanks to Chad comment, and a bit of searching in order to understand why, I solved the issue.
The fact is that vector use C++ exceptions, and in order to make them active, I replace, in the Android.mk, the line
LOCAL_CFLAGS := -frtti
with the line
LOCAL_CFLAGS := -frtti -fexceptions
And this time, I had no compilation error.
i'm compiling a jni project.here is detail of the problem i encountering:
r
oot#kaiwiiho:/home/kaiwii/svn# make
gcc -shared build/utimebufClass.o build/contextClass.o build/fsClass.o build/javafuse_jni.o build/statClass.o build/statvfsClass.o build/fileinfoClass.o build/conninfoClass.o -o build/libjavafuse.so
gcc -g -Wall `pkg-config --cflags fuse` -Iinclude -I/usr/java/jdk1.6.0_31/include -I/usr/java/jdk1.6.0_31/include/linux `pkg-config --libs fuse` -L/usr/java/packages/lib/i386 -L/lib -L/usr/lib -ljvm -Lbuild -ljavafuse src/javafuse.c -o javafuse
src/javafuse.c: In function ‘javafuse_readdir’:
src/javafuse.c:2194:22: warning: cast from pointer to integer of different size
src/javafuse.c:2195:25: warning: cast from pointer to integer of different size
src/javafuse.c:2207:15: warning: cast to pointer from integer of different size
src/javafuse.c:2208:18: warning: cast to pointer from integer of different size
src/javafuse.c:2256:16: warning: cast from pointer to integer of different size
src/javafuse.c:2257:19: warning: cast from pointer to integer of different size
src/javafuse.c:2271:15: warning: cast to pointer from integer of different size
src/javafuse.c:2272:18: warning: cast to pointer from integer of different size
src/javafuse.c: In function ‘javafuse_releasedir’:
src/javafuse.c:2332:12: warning: assignment from incompatible pointer type
src/javafuse.c: In function ‘javafuse_fsyncdir’:
src/javafuse.c:2420:12: warning: assignment from incompatible pointer type
/usr/bin/ld: cannot find -ljvm
collect2: ld returned 1 exit status
make: *** [javafuse] 错误 1
root#kaiwiiho:/home/kaiwii/svn# ldconfig
root#kaiwiiho:/home/kaiwii/svn# gedit /etc/ld.so.conf
root#kaiwiiho:/home/kaiwii/svn# make
gcc -shared build/utimebufClass.o build/contextClass.o build/fsClass.o build/javafuse_jni.o build/statClass.o build/statvfsClass.o build/fileinfoClass.o build/conninfoClass.o -o build/libjavafuse.so
gcc -g -Wall `pkg-config --cflags fuse` -Iinclude -I/usr/java/jdk1.6.0_31/include -I/usr/java/jdk1.6.0_31/include/linux `pkg-config --libs fuse` -L/usr/java/packages/lib/i386 -L/lib -L/usr/lib -ljvm -Lbuild -ljavafuse src/javafuse.c -o javafuse
src/javafuse.c: In function ‘javafuse_readdir’:
src/javafuse.c:2194:22: warning: cast from pointer to integer of different size
src/javafuse.c:2195:25: warning: cast from pointer to integer of different size
src/javafuse.c:2207:15: warning: cast to pointer from integer of different size
src/javafuse.c:2208:18: warning: cast to pointer from integer of different size
src/javafuse.c:2256:16: warning: cast from pointer to integer of different size
src/javafuse.c:2257:19: warning: cast from pointer to integer of different size
src/javafuse.c:2271:15: warning: cast to pointer from integer of different size
src/javafuse.c:2272:18: warning: cast to pointer from integer of different size
src/javafuse.c: In function ‘javafuse_releasedir’:
src/javafuse.c:2332:12: warning: assignment from incompatible pointer type
src/javafuse.c: In function ‘javafuse_fsyncdir’:
src/javafuse.c:2420:12: warning: assignment from incompatible pointer type
/usr/bin/ld: cannot find -ljvm
collect2: ld returned 1 exit status
make: *** [javafuse] 错误 1
And for sake that the the libjvm.so have aready exisited in the /usr/lib,i directly make a conf file,/etc/ld.so.conf.d/my.conf:
/usr/lib
/usr/local/lib
and then i use command ldconfig.
but unfortunately,i still encounter the same problem yet.
Any idea?thx
This command:
gcc -g -Wall `pkg-config --cflags fuse` -Iinclude \
-I/usr/java/jdk1.6.0_31/include \
-I/usr/java/jdk1.6.0_31/include/linux `pkg-config --libs fuse` \
-L/usr/java/packages/lib/i386 -L/lib -L/usr/lib -ljvm -Lbuild -ljavafuse \
src/javafuse.c -o javafuse
is incorrect. The order of libraries and sources on the link line matters, and your order is wrong.
But that's not what your problem is right now. You insist that libjvm.so exists in /usr/lib, but have shown no evidence that it does. What does ls -l /usr/lib/libjvm.so actually print?
Note that it would be highly unusual to find libjvm.so in /usr/lib. Usually one would expect to find it in e.g. /usr/java/packages/lib/i386/server, and you are not searching that directory.
Update:
well. libjvm.so is not actually in the /usr/lib but in /usr/java/jdk1.6.0_31/jre/lib/i386/server
In that case, you need to add -L/usr/java/jdk1.6.0_31/jre/lib/i386/server to your link line.
And i gedit a conf file ...
Obviously that's not sufficient.
The error is coming because JAVA_HOME & LD_LIBRARY_PATH is not consistent for Linux.So after analysis i discover that JAVA_HOME and LD_LIBRARY_PATH is resetting everytime whenever the terminal window is closed.
So setting the JAVA_HOME permanently resolved the error like:-
JAVA_HOME=/usr/java/latest
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/java/latest/bin:/bin:/sbin:/usr/lib64/qt-3.3/bin
LD_LIBRARY_PATH=/usr/java/jdk1.8.0_111/jre/lib/amd64/server:/usr/local/lib:/usr/lib64:/usr/lib:/usr/local/lib64: