Welcome to my GitHub

https://github.com/zq2599/blog_demos

Content: Classification and summary of all original articles and supporting source code, involving Java, Docker, Kubernetes, DevOPS, etc.;

About JavaCPP

  • JavaCPP enables Java applications to efficiently access local C++ methods. The bottom layer of JavaCPP uses JNI technology, which can be widely used in Java SE applications (including Android). The following two features are the key to JavaCPP, which we will use later :
  • Provide some annotations to map Java code to C++ code
  • Provide a jar, and use the <font color="blue">java -jar</font> command to convert C++ code into a dynamic link library file that can be accessed by java applications;
  • At present, the JavaCPP team has used JavaCPP to generate complete interfaces for many well-known C++ projects, which means that our java applications can easily use these C++ libraries. Here are some of the projects as shown in the figure below. For a more detailed list, please visit: https ://github.com/bytedeco/javacpp-presets

在这里插入图片描述

Overview of this article

  • Today, let’s write the C++ function first, and then write the Java class. The Java class uses JavaCPP to call the C++ function;
  • Summarize the basic steps of JavaCPP development in advance as shown below, and follow these steps later:

在这里插入图片描述

Differences from the official demo

  • Smart, you should think: The introductory demo is also available from the official (16179e80b31d02 https://github.com/bytedeco/javacpp). Is Xinchen better than the official one?
  • The official introductory demo must be the best. There is no doubt about this. The difference between me and the official is that I have added the following content not mentioned by the official, which is more in line with my own development habits (the official does not have these reasons, I think Should be more concerned about JavaCPP itself, rather than some other details):
  1. As shown in the figure below, the official C++ code has only one <font color="blue">NativeLibrary.h</font> file, and the function function is also in this file. Finally, a jni so file is generated, but in fact, it should be the header The file is separated from the function code, so the header file and the source code of the C++ function in this article are separated. First generate the function function so, and then generate the jni so in java. There will be a total of two so files. As for these two so How to configure and access is also one of the focuses of this article:

在这里插入图片描述

  1. The java source code of the official demo is shown in the figure below. There is no package information, but there will always be packages in the actual java projects. The path problems caused by this, such as where to put the header files? When compiling and generating the so file, how the command line handles package information, etc. is not mentioned by the official, but in this article, our java class has a package, and the related path problem will be solved:

在这里插入图片描述

  1. The dependency library used by the official demo at runtime is <font color="blue">org.bytedeco:javacpp:1.5.5</font>. The following warning message will be output during runtime. This article will solve this warning problem:
Warning: Could not load Loader: java.lang.UnsatisfiedLinkError: no jnijavacpp in java.library.path

Environmental information

  • Here is my environmental information, you can use it as a reference:
  1. Operating system: Ubuntu 16.04.5 LTS (server version, 64-bit)
  2. g++:(Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
  3. JDK:1.8.0_291
  4. JavaCPP:1.5.5
  5. Operating account: root

javacpp-1.5.5.jar file download

  • This article will not use maven or gradle, so the required jar file needs to be prepared by yourself. You can download it from the official website, the maven central warehouse, etc., or you can download one of the following two places:
  1. CSDN (without points): https://download.csdn.net/download/boling_cavalry/20189395
  2. GitHub:https://raw.githubusercontent.com/zq2599/blog_download_files/master/files/javacpp-1.5.5.jar

Complete source code and related file download

  • All the source code and related files of this actual combat are packaged and uploaded to the server according to the actual directory location. If necessary, you can choose one of the following two places to download for reference.
  1. CSDN (without integration): https://download.csdn.net/download/boling_cavalry/20189692
  2. GitHub:https://raw.githubusercontent.com/zq2599/blog_download_files/master/files/javacpp-project.tar
  • Next enter the actual combat link

C++ development

  • Create a new folder, my side is <font color="blue">/root/javacpp/cpp</font>, C++ development is carried out in this folder
  • There are three files to be written in the C++ part, namely:
  1. Source code of C++ function: NativeLibrary.cpp
  2. Header file: NativeLibrary.h
  3. File for testing function function: test.cpp (this file is only used to test whether the C++ function is normally available, and has nothing to do with JavcCPP)
  • Next, write separately, the first is NativeLibrary.cpp, as follows, only the addition method:
#include "NativeLibrary.h" 

namespace NativeLibrary { 

    int MyFunc::add(int a, int b) {
        return a + b;
    }
}
  • head File:
#include<iostream>

namespace NativeLibrary {

    class MyFunc{
    public:
        MyFunc(){};
        ~MyFunc(){};
        int add(int a, int b);
    };
}
  • The test file test.cpp can be seen to verify whether the method of the MyFunc class is normal:
#include<iostream>
#include"NativeLibrary.h"

using namespace NativeLibrary;

int main(){
    MyFunc myFunc;
    int value = myFunc.add(1, 2);
    std::cout << "add value " << value << std::endl;
    return 0;
}
  • Execute the following command to compile NativeLibrary.cpp and get the so file <font color="blue">libMyFunc.so</font>:
g++ -std=c++11 -fPIC -shared NativeLibrary.cpp -o libMyFunc.so
  • Execute the following commands to compile and link test.cpp to get the executable file <font color="blue">test</font>:
g++ test.cpp -o test ./libMyFunc.so
  • Try running the executable file, the command is <font color="blue">./test</font>:
root@docker:~/javacpp/cpp# ./test
add value 3
  • Copy the <font color="red">libMyFunc.so</font> file to the <font color="blue">/usr/lib/</font> directory
  • The execution result of test meets expectations, which proves that the so file was created successfully. Remember the following two key information, which will be used later:
  1. The header file is <font color="blue">NativeLibrary.h</font>
  2. The so file is <font color="blue">libMyFunc.so</font>
  • Next is the java part

Java development

  • For simplicity, let's write java files by hand instead of creating maven projects
  • Create a new folder, my side is <font color="blue">/root/javacpp/java</font>, java development is carried out in this folder
  • Copy the file <font color="red">javacpp-1.5.5.jar</font> to the <font color="blue">/root/javacpp/java/</font> directory
  • Out of personal habit, I like to put the java class under the packgage, so create the package directory, I am here <font color="blue">com/bolingcavalry/javacppdemo</font>, the absolute path here is <font color="blue">/root/javacpp/java/com/bolingcavalry/javacppdemo</font>
  • Copy the file <font color="red">NativeLibrary.h</font> to the directory of <font color="blue">com/bolingcavalry/javacppdemo</font>
  • Create a new Test.java in the <font color="blue">com/bolingcavalry/javacppdemo</font> directory. There are several points to note that will be mentioned later:
package com.bolingcavalry.javacppdemo;

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

@Platform(include="NativeLibrary.h",link="MyFunc")
@Namespace("NativeLibrary")
public class Test {
    public static class MyFunc extends Pointer {
        static { Loader.load(); }
        public MyFunc() { allocate(); }
        private native void allocate();

        // to call add functions
        public native int add(int a, int b);
    }

    public static void main(String[] args) {
        MyFunc myFunc = new MyFunc();
        System.out.println(myFunc .add(111,222));
    }
}
  • Test.java has the following points to note:
  • The value of the Namespace annotation is the namespace, which should be consistent with the previous C++ code
  • The static class name is <font color="red">MyFunc</font>, which should be consistent with the class declared in C++
  • The include attribute of the Platform annotation is NativeLibrary.h, which is used to specify the header file
  • The value of the link attribute of the Platform annotation is <font color="red">MyFunc</font>. Compared with the so file name libMyFunc.so, the lib prefix and so suffix are missing. This is an error-prone place. Be very careful, you need to follow this rule to set the value of the link attribute
  • Use the native keyword to declare the add method in so, and then it can be used
  • Now that the development work has been completed, start to compile and run

Compile and run

  • The first is to compile the java file, enter the directory <font color="blue">/root/javacpp/java</font>, and execute the following command to generate the class file:
javac -cp javacpp-1.5.5.jar com/bolingcavalry/javacppdemo/Test.java
  • Next, use javacpp-1.5.5.jar to complete the creation and compilation of the c++ file, and generate the so file under linux:
java \
-jar javacpp-1.5.5.jar \
com/bolingcavalry/javacppdemo/Test.java
  • The console outputs the following information, the table name so file has been generated, and the temporary files generated in the intermediate process have been cleaned up:
root@docker:~/javacpp/java# java \
> -jar javacpp-1.5.5.jar \
> com/bolingcavalry/javacppdemo/Test.java
Info: javac -cp javacpp-1.5.5.jar:/root/javacpp/java com/bolingcavalry/javacppdemo/Test.java 
Info: Generating /root/javacpp/java/jnijavacpp.cpp
Info: Generating /root/javacpp/java/com/bolingcavalry/javacppdemo/jniTest.cpp
Info: Compiling /root/javacpp/java/com/bolingcavalry/javacppdemo/linux-x86_64/libjniTest.so
Info: g++ -I/usr/lib/jvm/jdk1.8.0_291/include -I/usr/lib/jvm/jdk1.8.0_291/include/linux /root/javacpp/java/com/bolingcavalry/javacppdemo/jniTest.cpp /root/javacpp/java/jnijavacpp.cpp -march=x86-64 -m64 -O3 -s -Wl,-rpath,$ORIGIN/ -Wl,-z,noexecstack -Wl,-Bsymbolic -Wall -fPIC -pthread -shared -o libjniTest.so -lMyFunc 
Info: Deleting /root/javacpp/java/com/bolingcavalry/javacppdemo/jniTest.cpp
Info: Deleting /root/javacpp/java/jnijavacpp.cpp
  • At this time, a new folder named <font color="red">linux-x86_64</font> is added to the <font color="blue">com/bolingcavalry/javacppdemo</font> directory, and the < font color="red">libjniTest.so</font> is generated by javacpp-1.5.5.jar
  • You can move the <font color="red">libMyFunc.so</font> file in the <font color="blue">/usr/lib/</font> directory to <font color="blue">linux -x86_64</font> directory (you don’t need to move it, but I personally feel that it’s not appropriate for business so files to be placed in a public directory like /usr/lib/)
  • Run the java application:
java -cp javacpp-1.5.5.jar:. com.bolingcavalry.javacppdemo.Test
  • The information output by the console is as follows, 333 means that the method in so is called successfully:
root@docker:~/javacpp/java# java -cp javacpp-1.5.5.jar:. com.bolingcavalry.javacppdemo.Test
Warning: Could not load Loader: java.lang.UnsatisfiedLinkError: no jnijavacpp in java.library.path
333
  • Finally, I will list the folder and file information of c++ and java here in detail, you can refer to:
root@docker:~# tree /root/javacpp
/root/javacpp
├── cpp
│   ├── libMyFunc.so
│   ├── NativeLibrary.cpp
│   ├── NativeLibrary.h
│   ├── test
│   └── test.cpp
└── java
    ├── com
    │   └── bolingcavalry
    │       └── javacppdemo
    │           ├── linux-x86_64
    │           │   ├── libjniTest.so
    │           │   └── libMyFunc.so
    │           ├── NativeLibrary.h
    │           ├── Test.class
    │           ├── Test.java
    │           └── Test$MyFunc.class
    └── javacpp-1.5.5.jar

6 directories, 12 files

A little problem

  • Let's review the output of the java application, as shown below, there is a warning message:
root@docker:~/javacpp/java# java -cp javacpp-1.5.5.jar:. com.bolingcavalry.javacppdemo.Test
Warning: Could not load Loader: java.lang.UnsatisfiedLinkError: no jnijavacpp in java.library.path
333
  • The above warning information will not affect the function. If you want to eliminate it, you can’t just use the <font color="blue">org.bytedeco:javacpp:1.5.5</font> library, but <font color="blue ">org.bytedeco:javacpp-platform:1.5.5</font>, <font color="red"> and its dependent library </font>
  • Since this article does not use maven or gradle, it is difficult to gather <font color="blue">org.bytedeco:javacpp-platform:1.5.5</font> and its dependent libraries. I have already collected all the jars here. The files are packaged and uploaded, you can choose any of the following methods to download:
  1. CSDN (without points): https://download.csdn.net/download/boling_cavalry/20188764
  2. GitHub:https://raw.githubusercontent.com/zq2599/blog_download_files/master/files/javacpp-platform155.tar
  • After downloading, unzip it, it is a folder named <font color="blue">lib</font>, put this folder in <font color="blue">/root/javacpp/java/</font> Under contents
  • The jar in the lib folder is only used at runtime, not at compile time, so now you can run the java application again. The command is as follows:
java -cp lib/*:. com.bolingcavalry.javacppdemo.Test
  • Looking at the console output as shown below, there is no warning this time:

在这里插入图片描述

  • The final file and directory information of this actual combat is as follows for your reference:
root@docker:~/javacpp# tree /root/javacpp
/root/javacpp
├── cpp
│   ├── libMyFunc.so
│   ├── NativeLibrary.cpp
│   ├── NativeLibrary.h
│   ├── test
│   └── test.cpp
└── java
    ├── com
    │   └── bolingcavalry
    │       └── javacppdemo
    │           ├── linux-x86_64
    │           │   ├── libjniTest.so
    │           │   └── libMyFunc.so
    │           ├── NativeLibrary.h
    │           ├── Test.class
    │           ├── Test.java
    │           └── Test$MyFunc.class
    ├── javacpp-1.5.5.jar
    └── lib
        ├── javacpp-1.5.5-android-arm64.jar
        ├── javacpp-1.5.5-android-arm.jar
        ├── javacpp-1.5.5-android-x86_64.jar
        ├── javacpp-1.5.5-android-x86.jar
        ├── javacpp-1.5.5-ios-arm64.jar
        ├── javacpp-1.5.5-ios-x86_64.jar
        ├── javacpp-1.5.5.jar
        ├── javacpp-1.5.5-linux-arm64.jar
        ├── javacpp-1.5.5-linux-armhf.jar
        ├── javacpp-1.5.5-linux-ppc64le.jar
        ├── javacpp-1.5.5-linux-x86_64.jar
        ├── javacpp-1.5.5-linux-x86.jar
        ├── javacpp-1.5.5-macosx-arm64.jar
        ├── javacpp-1.5.5-macosx-x86_64.jar
        ├── javacpp-1.5.5-windows-x86_64.jar
        ├── javacpp-1.5.5-windows-x86.jar
        └── javacpp-platform-1.5.5.jar

7 directories, 29 files
  • At this point, the JavaCPP introductory experience has been completed, let’s make a summary and list the key points

Summary of key points

  • In today's actual combat, we use JavaCPP to use C++ functions in Java applications. The following points need to be focused on:
  1. In the Java code, there must be a static class with the same name as in C++
  2. Note that the Namespace annotation in the Java code is consistent with the namespace in C++
  3. The C++ header file should be placed in the same directory as the Java class
  4. When using the so library, the library name is <font color="blue">libMyFunc.so</font>, and the value of the link parameter in the Platform annotation is the library name with the <font color="red">lib</font> prefix removed And <font color="red">.so</font> suffix
  5. The so file of the C++ function can be placed in the /usr/lib directory or moved to the linux-x86_64 directory
  • At this point, the JavaCPP Quick Start is complete. If you are learning JavaCPP technology, I hope this article can give you some reference;

You are not alone, Xinchen and original are with you all the way

  1. Java series
  2. Spring series
  3. Docker series
  4. kubernetes series
  5. Database + Middleware Series
  6. DevOps series

Welcome to pay attention to the public account: programmer Xin Chen

Search "Programmer Xin Chen" on WeChat, I am Xin Chen, and I look forward to traveling the Java world with you...
https://github.com/zq2599/blog_demos

程序员欣宸
147 声望24 粉丝

热爱Java和Docker