Java call C++ class code implementation
1. Write C++ programs
Now, let’s write a function that reads the contents of the /etc/profile file in Linux and prints it out.
1.1. Establish PrintProfile project
Here, Eclipse tool is used to establish a PrintProfile project, including SRC, obj, bin three subdirectories, respectively used to store source code, object file, the final output of the dynamic library file.
The project is shown as follows:
1.2, write a const definition header file constdef.h in the SRC directory
The contents of the constdef.h file are as follows:
#ifndef CONST_DEF_H #define CONST_DEF_H
const int MAX_LINE_LENGTH = 1024; const int MAX_PROGRAM_NAME_LENGTH = 64; const int MAX_PROGRAM_VERSION_LENGTH = 32; const char* PROGRAM_NAME = “PrintProfile”; const char* PROGRAM_VERSION = “0.8.1”;
#endif//CONST_DEF_H
1.3. Write the class definition header printprofile.h in the SRC directory
The contents of the printprofile.h file are as follows:
#ifndef PRINT_PROFILE_H #define PRINT_PROFILE_H
class PrintProfile { public: PrintProfile(); int OpenProfile(); int ReadLine(char* pcLine, int iMaxLineLength); void CloseProfile(); void GetProgramName(char* pcProgramName, int iMaxProgramNameLength); void GetProgramVersion(char* pcProgramVersion, int iMaxProgramVersionLength); private: FILE* m_fpProfile; };
extern “C” int OpenProfile(); extern “C” int ReadLine(char* pcLine, int iMaxLineLength); extern “C” void CloseProfile(); extern “C” void GetProgramName(char* pcProgramName, int iMaxProgramNameLength); extern “C” void GetProgramVersion(char* pcProgramVersion, int iMaxProgramVersionLength);
#endif//PRINT_PROFILE_H Now works like this:
1.4. Write the class implementation file printprofile.cpp in the SRC directory
The printprofile.cpp file has the following contents:
#include <string.h> #include <stdio.h> #include “ConstDef.h” #include “PrintProfile.h”
PrintProfile::PrintProfile() { m_fpProfile = NULL; }
int PrintProfile::OpenProfile() { m_fpProfile = fopen(“/etc/profile”, “r”); if (m_fpProfile == NULL) { return -1; }
return 0;
Copy the code
}
int PrintProfile::ReadLine(char* pcLine, int iMaxLineLength) { if (m_fpProfile == NULL) { return -1; }
if (feof(m_fpProfile))
{
return -1;
}
memset(pcLine, 0, iMaxLineLength);
fgets(pcLine, iMaxLineLength-1, m_fpProfile);
int iLineLen = strlen(pcLine);
if (iLineLen > 0 && pcLine[iLineLen-1]=='\n')
{
pcLine[iLineLen-1] = '\0';
}
return 0;
Copy the code
}
void PrintProfile::CloseProfile() { fclose(m_fpProfile); m_fpProfile = NULL; }
void PrintProfile::GetProgramName(char* pcProgramName, int iMaxProgramNameLength) { memset(pcProgramName, 0, iMaxProgramNameLength); strncpy(pcProgramName, PROGRAM_NAME, iMaxProgramNameLength-1); }
void PrintProfile::GetProgramVersion(char* pcProgramVersion, int iMaxProgramVersionLength) { memset(pcProgramVersion, 0, iMaxProgramVersionLength); strncpy(pcProgramVersion, PROGRAM_VERSION, iMaxProgramVersionLength-1); }
static PrintProfile s_PrintProfile;
extern “C” int OpenProfile() { return s_PrintProfile.OpenProfile(); }
extern “C” int ReadLine(char* pcLine, int iMaxLineLength) { return s_PrintProfile.ReadLine(pcLine, iMaxLineLength); }
extern “C” void CloseProfile() { s_PrintProfile.CloseProfile(); }
extern “C” void GetProgramName(char* pcProgramName, int iMaxProgramNameLength) { s_PrintProfile.GetProgramName(pcProgramName, iMaxProgramNameLength); }
extern “C” void GetProgramVersion(char* pcProgramVersion, int iMaxProgramVersionLength) { s_PrintProfile.GetProgramVersion(pcProgramVersion, iMaxProgramVersionLength); } Now the structure of the project becomes:
1.5. An explanation of printprofile. h and printprofile. CPP implementations
Each member function of the PrintProfile class is wrapped by a global C function, since C++ code generates C functions when compiled, but the function names are too long to be easily used.
For example, here is the output function name of the dynamic library that was queried using the nm command after this article was written:
#nm -D libPrintProfile.so 00000000000014d2 T CloseProfile w __cxa_finalize U fclose U feof U fgets U fopen 00000000000014e9 T GetProgramName 0000000000001515 T GetProgramVersion w gmon_start w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable U memset 0000000000001491 T OpenProfile 0000000000004088 D PROGRAM_NAME 0000000000004090 D PROGRAM_VERSION 00000000000014a7 T ReadLine U strlen U strncpy 00000000000012b4 T _ZN12PrintProfile11OpenProfileEv 00000000000013bc T _ZN12PrintProfile12CloseProfileEv 00000000000013ea T _ZN12PrintProfile14GetProgramNameEPci 000000000000143e T _ZN12PrintProfile17GetProgramVersionEPci 00000000000012f8 T _ZN12PrintProfile8ReadLineEPci 000000000000129a T _ZN12PrintProfileC1Ev In the interface of dynamic libraries provide, turned into a function called _ZN12PrintProfile11OpenProfileEv.
1.6. Write the Makefile in the SRC directory
Now, to prepare for compilation, make the Makefile. The contents of the Makefile are as follows:
CC = g++
TARGETFILE = bin/libPrintProfile.so
OBJFILES = obj/PrintProfile.o
INCLUDEDIRS = -I src
INCLUDEFILES = src/ConstDef.h
src/PrintProfile.h
.PHONY: build
build: $(TARGETFILE) @echo “build successfully.”
clean: rm -f obj/*.o
(TARGETFILE):(TARGETFILE): (TARGETFILE):(OBJFILES) (CC)(CC) (CC)(CC) (INCLUDEDIRS) -g-shared-fpic <− O < -o <− O @
obj/PrintProfile.o: CPP (INCLUDEFILES)(INCLUDEFILES) (INCLUDEFILES)(CC) (INCLUDEDIRS)− C −shared−fPIC(INCLUDEDIRS) -c-shared -FPIC (INCLUDEDIRS)− C − Shared −fPIC< -o $@
2. Compile C++ programs
2.1. Copy the file to the Linux environment
Copy all files to Linux except the.project files generated by Eclipse:
2.2. Perform compilation
On Linux, run the make command to generate the libprintprofile. so file:
3. Write Java programs
3.1. Establish Java project
Using the IDEA development tool, create an empty JavaProject. Create the rear view as follows:
3.2. Establish SpringBoot project call-CPP under JavaProject
Create a SpringBoot project named call-cpp under JavaProject and create a rear view as follows:
The program’s POM.xml file uses the following three dependencies:
The code for the PrintProfile interface is as follows:
package com.flying.call.cpp; import com.sun.jna.Library; public interface PrintProfile extends Library { public static final int MAX_LINE_LENGTH = 1024; public static final int MAX_PROGRAM_NAME_LENGTH = 64; public static final int MAX_PROGRAM_VERSION_LENGTH = 32;
int OpenProfile();
int ReadLine(byte[] pcLine, int iMaxLineLength);
void CloseProfile();
void GetProgramName(byte[] pcProgramName, int iMaxProgramNameLength);
void GetProgramVersion(byte[] pcProgramVersion, int iMaxProgramVersionLength);
Copy the code
} Now the view changes to:
3.4. Modify the CallCppApplication class
Modify the CallCppApplication class to add a call to PrintProfile. The modified code is as follows:
package com.flying.call.cpp; import com.sun.jna.Native; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@Slf4j @SpringBootApplication public class CallCppApplication {
/ / program entry method public static void main (String [] args) throws the Exception {SpringApplication. Run (CallCppApplication. Class, args); PrintProfile printProfile = Native.load("PrintProfile", PrintProfile.class); byte[] programName = new byte[PrintProfile.MAX_PROGRAM_NAME_LENGTH]; byte[] programVersion = new byte[PrintProfile.MAX_PROGRAM_VERSION_LENGTH]; byte[] profileLine = new byte[PrintProfile.MAX_LINE_LENGTH]; printProfile.GetProgramName(programName, PrintProfile.MAX_PROGRAM_NAME_LENGTH); printProfile.GetProgramVersion(programVersion, PrintProfile.MAX_PROGRAM_VERSION_LENGTH); String programNameString = new String(programName, "UTF-8"); String programVersionString = new String(programVersion, "UTF-8"); System.out.println("Program name: " + programNameString); System.out.println("Program version: " + programVersionString); if (printProfile.OpenProfile() ! = 0){ System.err.println("Open profile failed."); return; } System.out.println("Content of /etc/profile is : "); while (printProfile.ReadLine(profileLine, PrintProfile.MAX_LINE_LENGTH) == 0) { String profileLineString = new String(profileLine, "UTF-8"); System.out.println(profileLineString); } printProfile.CloseProfile(); }Copy the code
} 4. Compile and run
4.1. Run the compile command
Run the MVN clean package-dskiptests command to compile:
After compiling, you will get the Target directory.
4.2. Copy programs to Linux
Copy cpp_call_lib, resources, and ccp-call. jar files from target to Linux:
4.3. Copy the libprintprofile. so library file to the Java program directory
Copy the libprintprofile. so library file to the Java program running directory.
4.4. Execute the program
To add the directory for the dynamic library to the LD_LIBRARY_PATH environment variable, run the following command:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/call-cpp