1. 先編寫一個標頭檔
// bigint.h
#ifndef big_integer_h
#define big_integer_h
#include "gmp.h"
#include "malloc.h"
#include "stdio.h"
char *testgmp(char *str);
void freegmp(void);
#endif
2. 編寫 c 程式碼, 主要呼叫 gmp 去計算大數, 傳入字串, 計算完答案, 轉成字串再回傳
// bigint.c
#include "bigint.h"
char *hexdigit;
char *testgmp(char *str) {
mpz_t z;
mpz_init(z);
mpz_set_str(z, str, 16);
gmp_printf("Receive: %s, GMP caculate: 0x%Zx * 3: \n", str, z);
mpz_mul_si(z, z, 3);
hexdigit = malloc( mpz_sizeinbase(z, 16) * sizeof(char) + 1 );// string buffer = new char[mpz_sizeinbase(z, base) + 1], include EOS
sprintf(hexdigit, "%s", mpz_get_str(NULL, 16, z)); // string copy
if (z) mpz_clear(z);
return hexdigit;
}
void freegmp(void) { if (hexdigit) free(hexdigit); }
3. c 主程式呼叫測試碼
// testbig.c
#include "bigint.h"
int main(){
printf("return: %s\n", testgmp("123"));
freegmp();
}
4. 編譯 c 程式, 做成程式庫, 將測試程式與程式庫連結, 看是否成功:
gcc -c bigint.c -o bigint.o
ar rcs libbigint.a bigint.o
gcc testbig.c -L . -l bigint -o testbig && ./testbig
5. 準備讓 kotlin 來呼叫, 先連接好所需要的相關程式庫:
ln -sf /usr/local/lib/libgmp.a libgmp.a
ln -sf /usr/local/include/gmp.h gmp.h
ln -sf libbigint.a bigint.a
6. 編輯橋接檔案 bigint.def, 將以下內容存檔:
headers = bigint.h
compilerOpts.linux = -I.
linkerOpts.linux = -L. bigint.a libgmp.a
7.用 cinterop 分析上述標頭檔, 產生程式庫:
cinterop -def bigint.def -o bigint.klib
8. 編寫 Kotlin 程式碼導入程式庫,呼叫由 c 所寫的副程式:
// main.kt
import bigint.*
import kotlinx.cinterop.*
fun main(args: Array) {
var digit = "123"
val test = testgmp(digit.cstr)!!.toKString()
println("testgmp return $test")
freegmp();
}
9. 編譯 main.kt 連結程式庫, 執行看是否成功呼叫並回傳答案, 結果應該要與步驟 4 答案一致:
konanc main.kt -l bigint.klib -o bigint && ./bigint.kexe
10 後記:
1. 若將 gmp 直接做成(klib), 從 kotlin 呼叫會產生不明錯誤訊息, 只好接間接透過 c 呼叫 GMP.
2. 不能用 g++ 去編譯 c 程式, 否則會產生找不到符號的錯誤訊息
3. Kotlin native compiler (konanc)編譯的速度很慢, 因此在寫 c 程式的階段,就應該用 c 程式碼去測試該程式碼的完整性,最後才整合至 kotlin 程式庫,以節省寶貴時間
沒有留言:
張貼留言