首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

KVM 從原始碼編譯到 Native API 擴充完整實戰教程

     編輯:J2ME

前言

KVM (K Virtual Machine) 是 J2ME CLDC 參考實作的核心 VM,體積小、可移植性強,適合嵌入式裝置。本文記錄在 Windows + Cygwin + VC6 環境下,從原始碼編譯 KVM、新增系統呼叫 API、並以標準 KNI (KVM Native Interface) 擴充功能的完整流程。

一、編譯環境準備

工具版本/來源用途
J2ME CLDC 原始碼Sun 官網 (cldc 1.1)KVM 核心碼、類庫、建構腳本
Cygwincygwin.com (含 gcc, make, grep, find)提供 Unix-like 建構環境
JDK1.4.2 / JBuilder 2005 附帶javac 編譯類庫、JCC 工具運行
VC6Visual C++ 6.0編譯連結最終 kvm.exe

二、命令列編譯步驟

# 1. 設定 PATH (Cygwin bin 優先,避免 Windows find.exe 衝突)
export PATH=/cygdrive/d/cygwin/bin:/cygdrive/d/JBuilder2005/jdk1.4/bin:$PATH

# 2. 進入建構目錄
cd /cygdrive/d/J2ME_cldc/build/win32

# 3. 執行 make (會依序:javac 編譯 api/ → 打包 classes.zip → JCC 產生 ROMJavaWin.c/nativeFunctionTableWin.c → gcc 編譯 C 碼 → 產生 .o)
make

# 4. 若報 "Java 找不到",確認 Cygwin bin 在 PATH 最前端
# 5. 編譯成功產生 VmWin.exe / kvm.exe
# 6. 測試:無需 preverify,直接運行
kvm -cp . HelloWorld

三、VC6 專案編譯 (可選,方便除錯)

  1. 先完成上述 make (產生 JCC 產出檔)。
  2. 開啟 J2ME_cldc/kvm/VmWin/build/kvm.dsw。
  3. 建構 → 產生 kvm.exe (約 200KB,含 CLDC 核心類庫)。

四、新增 Native 系統呼叫 API (三步走)

1. 定義 Java 端 Native 方法

// 新增檔案:J2ME_cldc/api/org/test/MiniTest.java
package org.test;
public class MiniTest {
    public static native int TestInt(); // 回傳 9999
}

2. 第一次 make (產生 JCC 存根)

執行 make,連結階段會報 undefined symbol _Java_org_test_MiniTest_TestInt,此為預期現象。

3. 在 nativeCore.c 實作 Native 函式

#include "kni.h"   // 若使用 KNI 輔助 API
#include "nativeCore.h"

void Java_org_test_MiniTest_TestInt(void) {
    // KVM 運算棧為 cell 型別,pushStack 宏將 int 壓入棧頂作為返回值
    pushStack(9999);
}

4. 第二次 make → 產生含新 API 的 kvm.exe

5. Java 端測試

import org.test.MiniTest;
public class Test {
    public static void main(String[] args) {
        System.out.println("Result = " + MiniTest.TestInt()); // 輸出 9999
    }
}
javac -cp ../classes.zip Test.java
kvm -cp . Test

五、使用標準 KNI 擴充 (推薦做法)

KNI 提供型別安全、例外處理、物件存取等完整 API,對應 JNI 但無動態載入 DLL 能力 (KVM 燒錄 ROM)。

關鍵型別對照

Java          KNI (C)
boolean       jboolean (unsigned char)
byte          jbyte    (signed char)
char          jchar    (unsigned short)
short         jshort   (short)
int           jint     (long)
float         jfloat   (float)
double        jdouble  (double)
Object        jobject  (cell**)
Class         jclass   (jobject)
String        jstring  (jobject)
int[]         jintArray (jarray)

常用輔助函式 (kni.h/kni.c)

  • KNI_FindClass(const char*, jclass*)
  • KNI_GetFieldID(jclass, const char* name, const char* sig)
  • KNI_GetIntField(jobject, jfieldID) / KNI_SetIntField(...)
  • KNI_NewObject(jclass, jmethodID)
  • KNI_ThrowNew(jclass, const char* msg)

實作範例:以 KNI 寫入靜態欄位

// Java 端
package org.test;
public class KniDemo {
    static int counter = 0;
    public static native void inc();
}

// C 端 (nativeCore.c)
#include "kni.h"
void Java_org_test_KniDemo_inc(void) {
    jclass cls;
    KNI_FindClass("org/test/KniDemo", &cls);
    jfieldID fid = KNI_GetFieldID(cls, "counter", "I");
    jint val = KNI_GetStaticIntField(cls, fid);
    KNI_SetStaticIntField(cls, fid, val + 1);
}

六、常見坑點與對策

現象原因解法
make 階段找不到 javacJDK bin 未在 PATHexport PATH 含 JDK bin
Windows find.exe 衝突系統 PATH 靠前Cygwin bin 置 PATH 最前
VC6 專案找不到 ROMJavaWin.c未先跑 make 產生 JCC 輸出必須先 make 成功
Native 回傳值錯誤未正確操作運算棧改用 KNI API 或參考現有 nativeCore.c 範例
KNI 編譯找不到 kni.hinclude 路徑未加專案屬性 → C/C++ → Additional Include 加入 KVM 根目錄

結語

掌握 KVM 編譯鏈與 KNI 擴充,即可為嵌入式 Java 裝置注入專屬硬體存取、專有協議、高效能演算法等能力。建議優先使用 KNI 而非直接操作運算棧,代碼更安全、可維護,且符合 Sun 規範。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved