最近一直在学习练习题中的几个语言,shell、python主要作为脚本语言来使用,函数功能方面的话不会特别复杂,java和c++的主要是用做功能代码开发,结合项目、还有自己的小练习,梳理一下他们之间可能会用到的调用方式。
shell语言我理解实质上是linux指令的合集,更像是对我们经常手动的执行命令集成在文件中,来进行顺序执行,这样可以更好的增加效率。当然shell本身也可以实现函数功能,有常用的循环、条件等结构。
python语言主要用的话,Web、数据处理、脚本这三个方面使用的比较多。比如Web开发的Django框架的后端开发、数据处理上比如机器学习、数据分析、数据可视化、脚本编写如项目的执行脚本什么的。
C++和JAVA语言的话就不用赘述了,这两种语言在现在的行业使用还是很广泛的。
写这个最主要的目的就是整理一下这几种语言之间的练习和跨语言调用的方式,这个算是多语言无法避免的问题。
1、从shell、python中看
经常遇到sh脚本中包含python脚本,python脚本中又使用包含sh的cmd指令调用,这个其实就算他们之间的交互。
shell----->python
1、通过python可执行文件和python脚本直接执行
例如:
#!/bin/bash python3 online.py /home/liulei/下载/111.txt
2、通过python模块调用python脚本中的函数调用
LUJING="/home/liulei/下载/111.txt" echo $LUJING python3 -c 'import online;online.out();online.online_out("'${LUJING}'")' function out(){ python3 -c 'import online;online.online_out("'$1'")' } out /home/liulei/下载/111.txt
其中的txt是数据文件、py的话就是数据处理脚本文件
python----->shell
1、这个很好理解。python中subprocess模块,使用这个模块的相关函数就可以实现sh脚本的调用,类似的c++、java中也有对应的函数来这样处理,不一定是shell脚本,也可以直接是shell指令
cmd = 'bash liulei.sh'
#cmd = 'cp dir dir_cpy -rf' subprocess.call(cmd, shell=True)
2 从shell、C++、Java来看
1、shell------>C++、Java
经常遇到shell脚本中直接执行可执行程序
C++:
g++ -o lujing lujing.cpp
./lujing
Java:
javac com/example/GameControl/TestJNI.java java com.example.GameControl.TestJNI
2、C++、Java-------->shell
C++实质上使用的是system函数
#include <stdlib.h> using namespace std; int main() { system("time");//system("bash liulei.sh") return 0; }
Java实质上使用Runtime中exec(String command)函数,这个需要同时使用InputStreamReader来实现指令结果的输出,直接类似c++的调用不能直接输出对应结果。具体使用如下
import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.util.ArrayList; import java.util.List; public class Exec { public static List<String> runshell(){ List<String> stringList = new ArrayList<String>(); String cmd = "bash liulei.sh"; try { Process process = Runtime.getRuntime().exec(cmd); InputStreamReader ir = new InputStreamReader(process.getInputStream()); LineNumberReader input = new LineNumberReader(ir); String Line; while((Line = input.readLine()) != null){ stringList.add(Line); } System.out.println("liulei"); } catch (IOException e) { e.printStackTrace(); } return stringList; } public static void main(String[] args){ System.out.println(runshell()); } }
3、从python 看C++
python------->C++ ,使用ctypes模块,的loadlibrary
# coding = utf-8 from ctypes import * import ctypes so = ctypes.cdll.LoadLibrary lib = so("/home/liulei/commonsiq/jni/liblujing.so") print ("lujing(int a,int b)") lib.gu(2130,4567) lib.gu2()
其中c++这边要使用extern去声明调用的函数,不声明会出现找不到的问题
#include<iostream> using namespace std; class lujing { private: string image_pics_dir; public: lujing(); void lujing1(int a,int b); ~lujing(); }; lujing::lujing() { } void lujing::lujing1(int a,int b) { int w = a; int h = b; image_pics_dir = "multi_back_" + to_string(w) + "x" + to_string(h); cout<< image_pics_dir.c_str() <<endl; } lujing::~lujing() { } extern "C"{ lujing lu = lujing(); void gu(int a,int b){ lu.lujing1(a,b); } void gu2(){ int a; int b; cin>>a; cin>>b; lu.lujing1(a,b); } } int main(){ lujing lu = lujing(); int a,b; cin>>a; cin>>b; lu.lujing1(a,b); return 0; }
4、从Java看C++
Java-------->C++
Java调用C++的代码是基于JNI的,也有基于JNA的,JNA后面做了解.主要接口是使用System.loadlibrary()
Java调用C++动态库首先要在Java层代码定义native函数接口 public native void lujing(int a,int b);
package com.example.GameControl; public class TestJNI { static{ System.loadLibrary("lujingjni"); } public native void lujing(int a,int b); public static void main(String[] args){ TestJNI test = new TestJNI(); test.lujing(1280,720); } }
然后使用
javac com/example/GameControl/TestJNI.java javah com.example.GameControl.TestJNI
产生com_example_GameControl_TestJNI.h文件
通常函数不带参数,需要修改具体参数JNIEXPORT void JNICALL Java_com_example_GameControl_TestJNI_lujing (JNIEnv *env, jobject jc, jint a, jint b);
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_GameControl_TestJNI */ #ifndef _Included_com_example_GameControl_TestJNI #define _Included_com_example_GameControl_TestJNI #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_GameControl_TestJNI * Method: lujing * Signature: (II)V */ JNIEXPORT void JNICALL Java_com_example_GameControl_TestJNI_lujing (JNIEnv *env, jobject jc, jint a, jint b); #ifdef __cplusplus } #endif #endif
然后依据h文件生成cpp文件,其中使用dlpen又调用了一层动态库函数,动态库使用的是上边python的动态库代码。
#include "com_example_GameControl_TestJNI.h" #include <dlfcn.h> typedef long (*PFN_TEST)(int a, int b); PFN_TEST g_Test = nullptr; JNIEXPORT void JNICALL Java_com_example_GameControl_TestJNI_lujing (JNIEnv *env, jobject jc, jint a, jint b){ void *siq_handle = nullptr; siq_handle = dlopen("/home/liulei/commonsiq/jni/liblujing.so", RTLD_LAZY | RTLD_NODELETE); if(!siq_handle) { printf("error\n"); } else { printf("g_TEST\n"); g_Test = (PFN_TEST)dlsym(siq_handle, "gu"); if(g_Test != NULL) { printf("g_TEST\n"); g_Test(1280,720); } dlclose(siq_handle); } g_Test = nullptr; printf("liulei %d %d\n",a,b); }
之后需要使用so编译命令,包含具体的头文件路径,主要是jni.h和jvm.h的
g++ -fPIC -shared -I/usr/java/jdk1.8.0_311/include -I /usr/java/jdk1.8.0_311/include/linux TestJNI.cpp -o liblujingjni.so
最后使用命令执行就可以实现功能的调用了
java com.example.GameControl.TestJNI
5.对于Java调用C++动态库的代码过程学习
主要是System.loadlibrary()函数的过程
加载对应库文件入口函数loadlibrary()
private static native int native_api(); //定义函数本地接口,load库中编译了对应jni格式的接口函数 static{ System.loadlibrary(libname);//lib名要类似libtest.so的格式 }
使用Runtime.getRuntime().loadlibrary0()
@CallerSensitive public static void loadLibrary(String libname) { Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname); }
调用ClassLoader.loadlibrary()
void loadLibrary0(Class<?> fromClass, String libname) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkLink(libname); } if (libname.indexOf(File.separatorChar) != -1) { throw new UnsatisfiedLinkError("Directory separator should not appear in library name: " + libname); } else { ClassLoader.loadLibrary(fromClass, libname, false); } }
调用loadlibrary0()
static void loadLibrary(Class<?> fromClass, String name, boolean isAbsolute) { ClassLoader loader = fromClass == null ? null : fromClass.getClassLoader(); assert sys_paths != null : "should be initialized at this point"; assert usr_paths != null : "should be initialized at this point"; if (isAbsolute) { if (!loadLibrary0(fromClass, new File(name))) { throw new UnsatisfiedLinkError("Can't load library: " + name); } } else { if (loader != null) { String libfilename = loader.findLibrary(name); if (libfilename != null) { File libfile = new File(libfilename); if (!libfile.isAbsolute()) { throw new UnsatisfiedLinkError("ClassLoader.findLibrary failed to return an absolute path: " + libfilename); } if (loadLibrary0(fromClass, libfile)) { return; } throw new UnsatisfiedLinkError("Can't load " + libfilename); } } String[] var9 = sys_paths; int var5 = var9.length; int var6; String usr_path; File libfile; for(var6 = 0; var6 < var5; ++var6) { usr_path = var9[var6]; libfile = new File(usr_path, System.mapLibraryName(name)); if (loadLibrary0(fromClass, libfile)) { return; } libfile = ClassLoaderHelper.mapAlternativeName(libfile); if (libfile != null && loadLibrary0(fromClass, libfile)) { return; } } if (loader != null) { var9 = usr_paths; var5 = var9.length; for(var6 = 0; var6 < var5; ++var6) { usr_path = var9[var6]; libfile = new File(usr_path, System.mapLibraryName(name)); if (loadLibrary0(fromClass, libfile)) { return; } libfile = ClassLoaderHelper.mapAlternativeName(libfile); if (libfile != null && loadLibrary0(fromClass, libfile)) { return; } } } throw new UnsatisfiedLinkError("no " + name + " in java.library.path: " + Arrays.toString(usr_paths)); } }View Code
调用ClassLoader.Nativelibrary.loadlbrary()
private static boolean loadLibrary0(Class<?> fromClass, final File file) { String name = findBuiltinLib(file.getName()); boolean isBuiltin = name != null; if (!isBuiltin) { name = (String)AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { try { return file.exists() ? file.getCanonicalPath() : null; } catch (IOException var2) { return null; } } }); if (name == null) { return false; } } return ClassLoader.NativeLibrary.loadLibrary(fromClass, name, isBuiltin); }View Code
调用ClassLoader.NativeLibrary.load()
static boolean loadLibrary(Class<?> fromClass, String name, boolean isBuiltin) { ClassLoader loader = fromClass == null ? null : fromClass.getClassLoader(); synchronized(ClassLoader.loadedLibraryNames) { Map<String, ClassLoader.NativeLibrary> libs = loader != null ? loader.nativeLibraries() : ClassLoader.systemNativeLibraries(); if (libs.containsKey(name)) { return true; } else if (ClassLoader.loadedLibraryNames.contains(name)) { throw new UnsatisfiedLinkError("Native Library " + name + " already loaded in another classloader"); } else { Iterator var6 = nativeLibraryContext.iterator(); while(var6.hasNext()) { ClassLoader.NativeLibrary lib = (ClassLoader.NativeLibrary)var6.next(); if (name.equals(lib.name)) { if (loader == lib.fromClass.getClassLoader()) { return true; } throw new UnsatisfiedLinkError("Native Library " + name + " is being loaded in another classloader"); } } ClassLoader.NativeLibrary lib = new ClassLoader.NativeLibrary(fromClass, name, isBuiltin); nativeLibraryContext.push(lib); try { if (!lib.load()) { boolean var15 = false; return var15; } } finally { nativeLibraryContext.pop(); } ClassLoader.loadedLibraryNames.add(name); libs.put(name, lib); return true; } } }View Code
调用load0()
boolean load() { if (this.handle != 0L) { throw new InternalError("Native library " + this.name + " has been loaded"); } else if (!this.load0(this.name, this.isBuiltin)) { return false; } else { ClassLoader loader = this.fromClass.getClassLoader(); if (loader != null && loader != ClassLoader.getBuiltinPlatformClassLoader() && loader != ClassLoader.getBuiltinAppClassLoader()) { CleanerFactory.cleaner().register(loader, new ClassLoader.NativeLibrary.Unloader(this.name, this.handle, this.isBuiltin)); } return true; } }View Code
实质上load0()也是一个本地函数,需要连接到对应的c库来使用对应的接口
native boolean load0(String var1, boolean var2);