1. 程式人生 > 程式設計 >Live-Server-7-bsdiff動態庫的編譯以及差分包的生成

Live-Server-7-bsdiff動態庫的編譯以及差分包的生成

bsdiff和bspatch是用來生成和應用二進位制補丁的工具,也就是bsdiff通過新舊檔案生成差分包,bspatch通過舊檔案和差分包生成新檔案,通過差分包的傳輸,能有效減少網路間傳輸的流量和時間。bsdiff和bspatch都是基於bzip2,並預設其位置在於/usr/bin。 bsdiff和bspatch在執行時都需要消耗大量的記憶體空間和時間,假設n是舊檔案的大小,m是新檔案的大小,那麼bsdiff需要的記憶體空間為max(17n,9n+m)+O(1)位元組;而bspatch需要n+m+O(1)位元組。

首先在bsdiff的官網中,可以直接下載bsdiff-4.3這個版本的原始碼,但是這個版本的原始碼僅僅支援Linux系統,不支援Windows系統的編譯,就需要找到windows版本。

windows下bsdiff的編譯

步驟如下:

  1. 檢視main()函式需要什麼引數
  2. 通過Java類,構建JNI標頭檔案
  3. 將bsdiff原始碼匯入VS中並修改
  4. 通過VS將其編譯成動態庫

1. 檢視main()函式需要什麼引數

來看下bsdiff windows版本的檔案目錄:

圖片.png

首先來看下bsdiff.cpp檔案中main()函式有這麼一行程式碼:

if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
複製程式碼

表明main()函式需要傳入4個引數,而第一個引數任意填,接著繼續讀main()函式的方法,可以得知剩餘的3個引數分別是舊檔案路徑、新檔案路徑和差分包路徑。

2. 通過Java類,構建JNI標頭檔案

於是我們就可以編寫Java程式碼和JNI程式碼。

public class BsDiff {

    public native static void diff(String oldFile,String newFile,String patchFile);

    static {
//        LibLoader.loadLib("Bsdiff.dll");
        LibLoader.loadLib("Bsdiff.so");
    }
}
複製程式碼

編譯,生成class檔案後,通過Idea IDE生成jni標頭檔案。在setting設定中,自定義如下工具

javah工具.png
隨後呼叫該工具,就可以生成BsDiff這個類的JNI標頭檔案。
生成JNI標頭檔案.png
標頭檔案如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ljh_jni_BsDiff */

#ifndef _Included_com_ljh_jni_BsDiff
#define _Included_com_ljh_jni_BsDiff
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ljh_jni_BsDiff
 * Method:    diff
 * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_ljh_jni_BsDiff_diff
  (JNIEnv *,jclass,jstring,jstring);

#ifdef __cplusplus
}
#endif
#endif
複製程式碼

3. 將bsdiff原始碼匯入VS中並修改

在VS中新建空白專案,將bsdiff windows的原始碼、jni.h、jni_md.h和剛剛編譯出來的JNI標頭檔案匯入到專案中。專案目錄如下:

圖片.png
隨後就要修改原始碼,使得整體呼叫邏輯變成通過JNI方法,呼叫bsdiff中原有的main()函式,生成差分包。 將JNI標頭檔案(com_ljh_jni_BsDiff.h)中的標頭檔案引用修改為本地:

#include <jni.h>     ->    #include "jni.h"
複製程式碼

在bsdiff.cpp原始檔中,新增JNI標頭檔案、修改main()函式名、新增JNI函式的實現。

1. #include "com_ljh_jni_BsDiff.h"

2.  int main(int argc,char *argv[]){ ... }  -> int bsdiff_main(int argc,char *argv[]){...}

3. 
//JNI呼叫
JNIEXPORT void JNICALL Java_com_ljh_jni_BsDiff_diff
(JNIEnv* env,jclass jcls,jstring oldfile_jstr,jstring newfile_jstr,jstring patchfile_jstr) {
	int argc = 4;
	char* oldfile = (char*)env->GetStringUTFChars(oldfile_jstr,NULL);
	char* newfile = (char*)env->GetStringUTFChars(newfile_jstr,NULL);
	char* patchfile = (char*)env->GetStringUTFChars(patchfile_jstr,NULL);

	//引數(第一個引數無效)
	char* argv[4];
	argv[0] = (char *)"bsdiff";
	argv[1] = oldfile;
	argv[2] = newfile;
	argv[3] = patchfile;

	bsdiff_main(argc,argv);

	env->ReleaseStringUTFChars(oldfile_jstr,oldfile);
	env->ReleaseStringUTFChars(newfile_jstr,newfile);
	env->ReleaseStringUTFChars(patchfile_jstr,patchfile);
}
複製程式碼

4. 通過VS將其編譯成動態庫

在專案屬性中,新增編譯的命令列來取消安全性檢查之類的異常

-D _CRT_SECURE_NO_WARNINGS -D _CRT_NONSTDC_NO_DEPRECATE 
複製程式碼

圖片.png
然後在常規設定中,將配置型別配置為動態庫(.dll),即可編譯。編譯成功後,呼叫JNI中的
圖片.png

Linux下bsdiff的編譯

在Linux中編譯bsdiff的步驟與在windows中類似:

  1. 編譯環境配置
  2. 通過Java類,構建JNI標頭檔案
  3. 修改JNI標頭檔案、原始碼
  4. 編譯成.so動態庫

1. 編譯環境配置

編譯需要gcc和bzip2,通過如下指令安裝bzip2

sudo apt-get install libbz2-dev
複製程式碼

2.通過Java類,構建JNI標頭檔案 3. 修改JNI標頭檔案、原始碼 參考windows編譯

4. 編譯成.so動態庫

gcc bsdiff.c -lbz2 -fPIC -shared -o bsdiff.so
複製程式碼