雖然 AIX 和 IBM i 構(gòu)建在共同的處理器 PowerPC 架構(gòu)之上,并且 IBM i 上的 PASE 應(yīng)用是以 AIX 模式運(yùn)行的,但兩者內(nèi)存管理和地址空間分配有較大差異。在很多情況下,PASE 上的應(yīng)用需要調(diào)用 IBM i 操作系統(tǒng) Integrated Language Environment® (ILE) 中的程序(PGM),服務(wù)程序(Service Program)或者命令行程序(CL)獲取系統(tǒng)信息。同樣也存在 IBM i 程序使用 PASE 提供的功能這樣的情況。這樣的互相調(diào)用方式跨越了 PASE 和 ILE 兩種運(yùn)行環(huán)境,程序中需要特殊的代碼來完成。本文以下章節(jié)將分別介紹如何處理這兩種情況。
ILE 和 PASE 的介紹
在討論跨越運(yùn)行環(huán)境進(jìn)行調(diào)用之前,本節(jié)將簡要介紹這兩種環(huán)境。
ILE
ILE 是 Integrated Language Environment 的縮寫,意思為集成語言環(huán)境。ILE 是被設(shè)計(jì)用來提升 IBM i 上程序開發(fā)的一系列工具和相關(guān)的系統(tǒng)支持。在 IBM i 平臺(tái) ILE 環(huán)境下,C/C++、CL、RPG、COBOL 語言編寫的程序可以編譯成 Module Object。Module Object 可以直接鏈接成可執(zhí)行的 Program Object。
ILE 中有如下幾個(gè)重要概念:
- Procedure
一段高級(jí)語言編寫的源代碼,它可以詳細(xì)地完成某項(xiàng)任務(wù),然后返回給調(diào)用者。對(duì) C 語言而言,Procedure 就是一個(gè)函數(shù);對(duì) CL 而言,Procedure 其實(shí)就是一個(gè) CL 程序的源代碼。
- Module
Module 是由 ILE 編譯器編譯出來的,不可以執(zhí)行的對(duì)象。Module 包含有一個(gè)或多個(gè) Procedure 和一些數(shù)據(jù)信息,以及在這個(gè) Module 中一些 Procedure 和數(shù)據(jù)導(dǎo)出導(dǎo)入信息。當(dāng)然,有些 Module 還包含調(diào)試信息,這取決于如何編譯程序。
- Program
Program 是 ILE 鏈接器把一個(gè)或者多個(gè) Module 對(duì)象綁定鏈接而成的可以執(zhí)行的程序。即 ILE 應(yīng)用程序。
- Service Program
Service Program 是 ILE 下的外部可調(diào)用歷程(函數(shù)或過程)的封裝。可供其它的 ILE 程序或 Service Program 引用和鏈接。
PASE
IBM i Portable Application Solutions Environment(PASE) 是為運(yùn)行在 IBM i 操作系統(tǒng)上的 AIX 應(yīng)用而開發(fā)的一個(gè)集成運(yùn)行時(shí)環(huán)境,該運(yùn)行時(shí)環(huán)境在 IBM i 操作系統(tǒng)的 Licensed Internal Code 內(nèi)核之上。引入 PASE 的目的是不改變或只需要微小的改動(dòng)就可以將已有的 AIX 程序移植到 IBM i 操作系統(tǒng)上運(yùn)行。PASE 支持 AIX 的 application binary interface (ABI),支持標(biāo)準(zhǔn)的 C 和 C++ 運(yùn)行時(shí)和 pthreads 線程庫,很大程度上能夠兼容 AIX 的共享庫,腳本,實(shí)用程序和系統(tǒng)調(diào)用。PASE 的應(yīng)用以 IBM i job 方式運(yùn)行和管理,并且可以使用 IBM i 操作系統(tǒng)提供的功能,如文件服務(wù),安全和 sockets 通信機(jī)制。
如何在 ILE 環(huán)境調(diào)用 PASE 應(yīng)用程序?
我們可以將 PASE 應(yīng)用程序集成到已有的 ILE 系統(tǒng)中,這樣用戶就可以重用已有的 ILE 代碼,使 PASE 應(yīng)用獲得在 ILE 系統(tǒng)中才有的特性。因?yàn)橹挥?ILE 才能充分發(fā)揮 IBM i 操作系統(tǒng)的獨(dú)特優(yōu)勢。
我們可以通過以下幾種方式在 ILE 端調(diào)用 PASE 應(yīng)用程序:
在 ILE 綠屏命令行直接調(diào)用 PASE 端可執(zhí)行應(yīng)用程序
- QSH CMD('pase_command parameters')
pase_command 為 PASE 端的可執(zhí)行應(yīng)用程序,它可以是該可執(zhí)行應(yīng)用程序的絕對(duì)路徑,
也可以是當(dāng)前 session 環(huán)境變量 PATH 下的可執(zhí)行的應(yīng)用程序。
清單 1. 使用 QSH CMD
QSH CMD('ps -ef') QSH CMD('/QOpenSys/usr/bin/ls') |
- CALL QP2SHELL PARM('pase_command''parameters)
pase_command 為 PASE 端的可執(zhí)行應(yīng)用程序的絕對(duì)路徑 , parameters 為該命令的命令行
參數(shù)。例如 :
清單 2. 在命令行使用 QP2SHELL
CALL QP2SHELL PARM('/QOpenSys/usr/bin/ls' '/QOpenSys/QIBM') |
在 ILE 程序中調(diào)用 PASE 端應(yīng)用程序
在 ILE 程序中調(diào)用 PASE 端可執(zhí)行應(yīng)用程序 , 我們可以使用以下三個(gè) API 實(shí)現(xiàn)在 ILE 程序中調(diào)用 PASE 端應(yīng)用程序。
QP2SHELL 和 QP2SHELL2 這兩個(gè) API 提供了一個(gè)非常簡單的使用 IBM i PASE 程序的
接口,直接使用要運(yùn)行的 IBM i PASE 程序名字和輸入?yún)?shù)作為 API 的輸入,就可以調(diào)用 PASE 應(yīng)用。
這兩個(gè) API 參數(shù)相同,差別在于 QP2SHELL()函數(shù)會(huì)創(chuàng)建新的激活組并在其中運(yùn)行 PASE 程序。而 QP2SHELL2()函數(shù)會(huì)在調(diào)用者相同的激活組中運(yùn)行 PASE 程序。這兩個(gè) API 都沒有指示錯(cuò)誤狀態(tài)的返回值,也不會(huì)返回 PASE 程序的返回值。
程序示例:
清單 3. 在程序中使用 QP2SHELL
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <qp2usr.h> #include <qp2shell.h> void main(int argc, char* argv[]) { char* parm = “/”; char* pasePgm = “/QOpenSys/bin/ls”; QP2SHELL(pasePGM, parm); } |
Qp2RunPase 允許用戶提供更多的參數(shù)來對(duì) PASE 程序的運(yùn)行進(jìn)行控制。它可以指定程
序名和運(yùn)行參數(shù),還可以定義 PASE 程序運(yùn)行環(huán)境變量,以及 PASE 程序初始運(yùn)行的 CCSID。Qp2RunPase 的返回值可以得到 PASE 程序執(zhí)行的狀態(tài)。PASE 程序結(jié)束返回時(shí),導(dǎo)致 Qp2RunPase 返回并將控制權(quán)返還給 ILE 代碼。下面是 Qp2RunPase 函數(shù)的原型:
清單 4. Qp2RunPase 函數(shù)聲明
int Qp2RunPase( const char* pathname, const char* symbolName, const void* symbolData, unsigned int symbolDataLen, int ccsid, const char* const* argv, const char* const* envp); |
參數(shù)說明:
- pathName 輸入?yún)?shù):
表明 PASE 程序在 IFS 文件系統(tǒng)中的路徑,可以使絕對(duì)路徑,也可以是相對(duì)于作業(yè)當(dāng)前路徑的相對(duì)路徑。
- symbolName、symbolData、symbolDataLen 輸入?yún)?shù)
symbolName 參數(shù)必須定義為為一個(gè)空指針; symbolData 和 symbolDataLen 參數(shù)通常被忽略。
- CCSID 輸入?yún)?shù):
這個(gè)參數(shù)確定 PASE 程序初始運(yùn)行的 CCSID。系統(tǒng)會(huì)將參數(shù)數(shù)據(jù)從作業(yè)默認(rèn)的 CCSID 轉(zhuǎn)換為對(duì)應(yīng)的編碼。例如,CCSID 設(shè)定為 1208,表明使用 UTF-8 編碼。
- argv 參數(shù):
argv 指向一個(gè)指針數(shù)組,該指針數(shù)組為 IBM i PASE 程序的參數(shù)表。第一個(gè)參數(shù)是 PASE 程序的路徑名,該參數(shù)的值與參數(shù) pathName 的值相同。
- envp 參數(shù):
envp 參數(shù)指向一個(gè)指針數(shù)組,該指針數(shù)組用來定義 IBM i PASE 程序的環(huán)境變量。
Qp2RunPase 的返回值能夠提供更多的信息,以便用戶對(duì) PASE 程序的運(yùn)行狀態(tài)進(jìn)行處理。通常情況下,“0”表示正常返回,非零值表明錯(cuò)誤返回,如“QP2RUNPASE_ERROR(-1)”或“QP2RUNPASE_RETURN_NOEXIT(-2)”這兩個(gè)值表明函數(shù)本身的異常返回。IBM i 還提供了一些宏來處理返回值,如下表所示:
表 1. 使用宏處理 Qp2RunPase 返回值
宏 | 含義 |
WIFEXITED(stat_val) | 如果返回非零值,表明 Qp2RunPase 函數(shù)的執(zhí)行過程有錯(cuò)誤,需要調(diào)用下面的宏獲得錯(cuò)誤的細(xì)節(jié)信息 |
WEXITSTATUS(stat_val) | 當(dāng)宏 WIFEXITED(stat_val) 返回非零值時(shí),表明執(zhí)行過程有錯(cuò)誤。該宏會(huì)返回 PASE 程序的返回值 |
WIFSIGNALED(stat_val) | 檢查 PASE 程序是否被 signal 異常終止 |
WTERMSIG(stat_val) | 當(dāng)宏 WIFSIGNALED(stat_val) 返回非零值時(shí),表明執(zhí)行過程被 signal 終止。這個(gè)宏確認(rèn)具體收到的 signal number |
程序示例:
清單 5. Qp2RunPase 函數(shù)使用實(shí)例
int rc = Qp2RunPase(“program/path/in/PASE”, NULL, NULL, 0, 819, (char**)&argv, NULL); if (rc == QP2RUNPASE_ERROR || rc == QP2RUNPASE_RETURN_NOEXIT) { printf (“internal error”); } if (WIFEXITED(rc) != 0) { // Command exited normally, check its return code paseRC = WEXITSTATUS(rc); printf (“pase program exit with none zero return: %d”, paseRC); } |
在 ILE 程序中調(diào)用 PASE 函數(shù)
以上介紹了在 ILE 中調(diào)用 PASE 環(huán)境中的應(yīng)用程序 IBM i 還提供了一組支持直接調(diào)用 PASE 共享庫的 API。調(diào)用過程需要用到以下函數(shù):
- Qp2ptrsize: 獲取 PASE 的指針長度。PASE 支持 32 位模式和 64 位模式。
- Qp2dlopen: 類似于 UNIX 下的 dlopen() 函數(shù),用于打開 PASE 共享庫。
- Qp2dlsym: 類似于 UNIX 下的 dlsym() 函數(shù),用于查找對(duì)應(yīng)的函數(shù)入口。
- Qp2dlclose: 類似于 UNIX 下的 dlclose() 函數(shù),用于關(guān)閉 PASE 共享庫。
- Qp2dlerror: 如果 Qp2dlopen、Qp2dlsym 或 Qp2dlclose 函數(shù)在執(zhí)行過程出錯(cuò),用戶可以使用這個(gè)函數(shù)獲取錯(cuò)誤信息。
- Qp2malloc: 在 PASE 中分配一塊內(nèi)存,共 ILE 與 PASE 之間進(jìn)行數(shù)據(jù)交互。
- Qp2free: 用于釋放 Qp2mallloc 函數(shù)分配的內(nèi)存。
Qp2CallPase
Qp2CallPase 使得用戶可以在 ILE 程序中調(diào)用 PASE 共享庫中的函數(shù)。Qp2CallPase 不會(huì)產(chǎn)生新的任務(wù),只會(huì)在當(dāng)前任務(wù)中執(zhí)行 PASE 函數(shù)。
清單 6. Qp2CallPase 函數(shù)原型
#include <qp2user.h> int Qp2CallPase( const void* target, const void* arglist, const QP2_arg_type_t* signature, QP2_result_type_t result_type, void* result); |
參數(shù)說明:
- target
PASE 函數(shù)的描述符。
- arglist:
IBM i PASE 函數(shù)的參數(shù)列表。
- signature
參數(shù)的具體類型。QP2_ARG_END 表示 Signature 列表的結(jié)尾,QP2_ARG_WORD 表示 4-byte 數(shù)據(jù),QP2_ARG_FLOAT32 表示 4-byte 浮點(diǎn)型數(shù)據(jù),QP2_ARG_FLOAT64 表示 8-byte 浮點(diǎn)型數(shù)據(jù)。
- result_type
調(diào)用的 PASE 函數(shù)的返回值的類型,在頭文件 qp2user.h 中定義。QP2_RESULT_VOID 表明 PASE 函數(shù)沒有返回值,QP2_RESULT_WORD 表示 4-byte 數(shù)據(jù),QP2_RESULT_DWORD 表示 8-byte 數(shù)據(jù),QP2_RESULT_FLOAT64 表示 8-byte 浮點(diǎn)型數(shù)據(jù)。
- result
PASE 函數(shù)的返回值。
下面介紹 Qp2CallPase 函數(shù)的使用方法和步驟:
- 初始化:調(diào)用 IBM i PASE 環(huán)境之前必須對(duì)其進(jìn)行初始化。IBM i PASE 環(huán)境提供了兩個(gè)工具用來完成初始化,一個(gè)是 /usr/bin/start32,用來激活 32 位 IBM i PASE 環(huán)境,另一個(gè)是 /usr/bin/start64,用來激活 64 位 IBM i PASE 環(huán)境。每個(gè) IBM i 進(jìn)程必須且只能運(yùn)行一個(gè)獨(dú)立的 IBM i PASE 環(huán)境。
- 檢查:調(diào)用 Qp2ptrsize() 來確定 IBM i PASE 環(huán)境是否正常運(yùn)行。返回值:
0,表示沒有完成初始化。
4,表示 PASE 環(huán)境運(yùn)行在 32 位模式下
8,表示 PASE 環(huán)境運(yùn)行在 64 位模式下。 - 加載庫:用 Qp2dlopen 和 Qp2dlsym 將被調(diào)用的庫加載至內(nèi)存中,然后就可以定位被調(diào)用函數(shù)的入口。
- 調(diào)用 Qp2CallPase:使用 Qp2CallPase() API 激活 PASE 共享庫函數(shù),被調(diào)用的函數(shù)參數(shù)列表以指針數(shù)組的方式傳遞給 Qp2CallPase。ILE 代碼還需要提供一種方式來描述參數(shù)列表的類型,通常稱為 Signature。用戶可以在頭文件 qsysinc/qp2usr.h 中找到這些類型定義。
- 終止 IBM i PASE 進(jìn)程:需要先調(diào)用 Qp2dlclose() 來卸載 IBM i PASE 共享庫,然后調(diào)用 Qp2EndPase() 函數(shù)來終止 start64 或 start32 程序啟動(dòng)的 PASE 環(huán)境。
清單 7. Qp2CallPase 函數(shù)使用實(shí)例
#include <stdio.h> #include <qp2shell2.h> #include <qp2user.h> #define JOB_CCSID 0 int main(int argc, char* argv[]) { QP2_ptr64_t id; void* getpid_pase; const QP2_arg_type_t signature[] = {QP2_ARG_END}; QP2_word_t result; QP2SHELL2(“/usr/lib/start32”); id = Qp2dlopen(NULL, QP2_RTLD_NOW, JOB_CCSID); getpid_pase = Qp2dlsym(id, “getpid”, JOB_CCSID, NULL); int rc = Qp2CallPase(getpid_pase, NULL,// no argument list signature, QP2_RESULT_WORD, &result) printf (“IBM i PASE getpid() = &i\n”, result); if (result == -1) printf (“IBM i errno = %i\n”, *Qp2errnop()); Qp2dlclose(id); Qp2EndPase(); return 0; } |
編譯 ILE 端程序生成可執(zhí)行的 PGM
在 ILE 端我們通常通過 CRTCMOD(如果源程序文件是由 ILE C 語言編寫)或者 CRTCPPMOD(如果源程序文件是由 ILE C++ 語言編寫)命令來將 ILE 端的程序編譯成 MODULE,然后用 CRTPGM 來將編譯好的 MODULE(s) 以及 Service Program 鏈接生成可執(zhí)行的 PGM。
清單 8. 在 ILE 編譯和鏈接程序
CRTCMOD MODULE(QYOURLIB/YOURMOD) SRCFILE(QYOURLIB/QCSRC) 或者:÷ CRTCPPMOD MODULE(QYOURLIB/YOURMOD) SRCSTMF('/qopensys/myprogram/myprogram.cpp') INCDIR('/qopensys/myprogram/include') CRTPGM PGM(QYOURLIB/YOURPGM) MODULE(QYOURLIB/YOURMOD) BNDSVRPGM(QSYS/QP2USER) |
如何在 PASE 端調(diào)用 ILE ?
PASE 程序調(diào)用 ILE command line
ILE 命令行是指在 IBM i 的終端窗口內(nèi)使用的命令,類似 AIX 的 shell 命令。例如: CRTUSRPRF USRPRF(USER1) 用來創(chuàng)建一個(gè) IBM i 系統(tǒng)賬號(hào)。如果希望在 PASE 應(yīng)用中調(diào)用上面的命令行提供創(chuàng)建賬號(hào)功能,就需要使用 systemCL API 來完成。systemCL 提供了 PASE 程序運(yùn)行 ILE Commnad Line 命令的功能。函數(shù)聲明:
清單 9. systemCL 聲明
#include <as400_protos.h> int systemCL(const char *command, int lags); |
<as400_protos.h> 頭文件是 PASE 專有的,包含了支持 PASE 調(diào)用 ILE 的 API。
清單 10. 使用 systemCL 調(diào)用 ILE 命令
int retval = systemCL("CRTUSRPRF USRPRF(USER1)", SYSTEMCL_MSG_STDOUT); |
調(diào)用 ILE 下的 PGM 對(duì)象
Program 是 ILE 下的可執(zhí)行程序,對(duì)象類型為 *PGM。 例如通過 WRKOBJ OBJ(QSYS/*ALL) OBJTYPE(*PGM) 來查看 QSYS 庫下的所有 Program。Program 可以在 ILE 的終端下使用 CALL 命令直接引用。
由于要在 PASE 中使用 ILE 對(duì)象涉及到地址轉(zhuǎn)換,先介紹 PASE 中的 ILE 對(duì)象指針也就是地址,即 ILEpointer 結(jié)構(gòu) :
清單 11. ILEpointer 對(duì)象聲明
typedef union _ILEpointer { #if !(defined(_AIX) || defined(KERNEL)) #pragma pack(1,16,_ILEpointer) /* Force sCC quadword alignment */ #endif long double align; /* Force xlc quadword alignment (with -qldbl128 -qalign=natural) */ #ifndef _AIX void *openPtr; /* MI open pointer (tagged quadword) */ #endif struct { char filler[16-sizeof(uint64)]; address64_t addr;/* (PASE) memory address */ } s; } ILEpointer; |
可以看出 ILE 下對(duì)象指針長度是 16 字節(jié),而 PASE 的地址保存在 8 字節(jié)的 addr 中。
調(diào)用 PGM 對(duì)象使用到的函數(shù):
清單 12. _RSLOBJ 和 _RSLOBJ2 函數(shù)聲明
#include <as400_protos.h> int _RSLOBJ(ILEpointer *sysptr const char *path, char *objtype); int _RSLOBJ2(ILEpointer *sysptr, unsigned short type_subtype, const char *objname, const char *libname); |
這兩個(gè)函數(shù)用來解析和提取 ILE 下 Program 對(duì)象的地址,接收參數(shù)為對(duì)象路徑或?qū)ο竺麕烀祷?16 字節(jié)指向 Program 的系統(tǒng)指針。
清單 13. _PGMCALL 函數(shù)聲明
int _PGMCALL(const ILEpointer *target, void **argv, unsigned flags); |
_PGMCALL 函數(shù)調(diào)用指定的 Program。參數(shù)為 _RSLOBJ() 和 _RSLOBJ2() 函數(shù)返回的對(duì)象指針。參數(shù) flags 指定如何控制被調(diào)的 ILE 程序,通常情況下,如果調(diào)用者希望 _PGMCALL 通過返回值的方式來判斷調(diào)用出錯(cuò),可以使用 PGMCALL_EXCP_NOSIGNAL,否則 _PGMCALL 將出錯(cuò)轉(zhuǎn)化為 PASE 的信號(hào),在未安裝信號(hào)處理函數(shù)的情況下,這可能導(dǎo)致程序直接退出。
例子:在 PASE 下調(diào)用 ILE 的 TESTLIB 庫文件系統(tǒng) TESTPGM(*PGM 類型 )
清單 14. _PGMCALL 使用實(shí)例
ILEpointer PGM_pointer; const char* arglist[] = { "parm1", "parm2",NULL}; int retval1 = _RSLOBJ2(&PGM_pointer, RSLOBJ_TS_PGM, "TESTLIB", "TESTPGM"); int retval2 = _PGMCALL(&PGM_pointer,(void**)arglist, PGMCALL_EXCP_NOSIGNAL); |
調(diào)用 Service Program
ILE 下的 Service Program 類似于共享庫或者動(dòng)態(tài)鏈接庫,包含一系列的函數(shù)或過程為其他 Service Program 或程序使用。Service Program 區(qū)別于 PGM 的地方是沒有程序入口函數(shù)即 main 函數(shù)。通常這些函數(shù)被一個(gè)或多個(gè)應(yīng)用頻繁使用,將這些函數(shù)打包到 Service Program 可以提高重用性,簡化維護(hù)開銷和減少內(nèi)存消耗。Service Program 可以做到運(yùn)行時(shí)綁定。
調(diào)用 Service Program 需要使用到的函數(shù):
清單 15. _ILELOAD 函數(shù)聲明
unsigned long long _ILELOADX(const void *id, unsigned int flags); int _ILELOAD(const void *id, unsigned int flags); |
上面兩個(gè)函數(shù)加載 ILE 的 Service Program,返回 Service Program 的唯一激活標(biāo)識(shí)。
清單 16. _ILESYMX 和 _ILESYM 函數(shù)聲明
int _ILESYMX(ILEpointer *export, unsigned long long actmark, const char *symbol); int _ILESYM(ILEpointer *export, int actmark, const char *symbol); |
這兩個(gè)函數(shù)使用 _ILELOADX() 和 _ILELOAD() 返回的激活標(biāo)識(shí)作為輸入?yún)?shù),在 Service Program 尋找被調(diào)用函數(shù)或過程的符號(hào),對(duì)返回指向該函數(shù)的 16 字節(jié)指針。
清單 17. _ILECALLX 和 _ILECALL 函數(shù)聲明
int _ILECALLX(const ILEpointer *target, ILEarglist_base *ILEarglist, const arg_type_t *signature, result_type_t result_type, int flags); int _ILECALL(const ILEpointer *target, ILEarglist_base *ILEarglist, const arg_type_t *signature, result_type_t result_type); |
以上兩個(gè)函數(shù)調(diào)用 Service Program,傳遞 16 字節(jié)的指向被調(diào) ILE 函數(shù)指針,以及參數(shù)列表,參數(shù)類型列表等。由于 ILE 的程序要求參數(shù)有一定的對(duì)齊方式,PASE 提供了兩個(gè)函數(shù)幫助構(gòu)造參數(shù)列表。
清單 18. size_ILEarglist 函數(shù)聲明
size_t size_ILEarglist(const arg_type_t *signature); |
size_ILEarglist() 用來計(jì)算參數(shù)字節(jié)數(shù)。由于參數(shù)按字節(jié)對(duì)齊,參數(shù)的順序?qū)⒂绊憛?shù)空間的大小。
清單 19. build_ILEarglist 函數(shù)聲明
int build_ILEarglist(ILEarglist_base *ILEarglist, const void *PASEarglist, const arg_type_t *signature); |
build_ILEarglist() 根據(jù)參數(shù)類型構(gòu)造參數(shù)列表。
調(diào)用 Service Program 程序示例:
TESTLIB 庫下的 TESTSRV Service Program 里的 TESTSRV 過程,聲明如下:
清單 20. TESTSRV 函數(shù)聲明
int TESTSRV(int a, float b,char c); |
需要定義一個(gè)和被調(diào)函數(shù)有同樣參數(shù)的轉(zhuǎn)換函數(shù),調(diào)用過程封裝在轉(zhuǎn)換函數(shù)中完成。對(duì) PASE 開發(fā)者來說這個(gè)轉(zhuǎn)換函數(shù)是必要的,因?yàn)榫幾g器會(huì)根據(jù)轉(zhuǎn)換函數(shù)的參數(shù)類型和順序自動(dòng)構(gòu)造參數(shù)列表并進(jìn)行參數(shù)字節(jié)對(duì)齊,Service Program 可以直接使用編譯器生成的參數(shù)列表。否則開發(fā)人員需要自己實(shí)現(xiàn)參數(shù)的字節(jié)對(duì)齊。
清單 21. PASE 下調(diào)用 ILE Service Program 實(shí)例
int TESTSRVWrapper(int arg1, double arg2, char arg3) { // 加載 Service Program int actmark = _ILELOAD("TESTLIB/TESTSRV", ILELOAD_LIBOBJ); ILEPointer* ILEtarget = (ILEPointer*)malloc(sizeof(ILEPointer)); // 定位被調(diào)過程的符號(hào) int rc = _ILESYMX(ILEtarget, actmark, "TESTSRV"); // 指定調(diào)用參數(shù)類型列表 static short signature[] = { ARG_INT32, ARG_FLOAT64, ARG_UINT8, ARG_END }; ILEarglist_base *ILEarglist; // 計(jì)算參數(shù)列表空間 ILEarglist = (ILEarglist_base*)malloc( size_ILEarglist(signature) ); // 構(gòu)造參數(shù)列表,只需第一個(gè)參數(shù)的地址 build_ILEarglist(ILEarglist, &arg1, signature); // 傳入?yún)?shù)并調(diào)用 _ILECALL(ILEtarget, ILEarglist, signature, RESULT_INT32); free(ILEarglist); free(ILEtarget); |
}
在 PASE 環(huán)境下編譯和鏈接程序
PASE 支持 AIX 的編譯器 IBM XL C/C++ for AIX,該編譯器是單獨(dú)提供的。PASE 也包含了許多 AIX 的開發(fā)工具,如 ld,ar,make,yacc。XLC 編譯器要注意的問題是指針的處理。因?yàn)?ILEpointer 類型代表了訪問底層機(jī)器接口的指針,在結(jié)構(gòu)體中它要求 16 字節(jié)對(duì)齊,XLC 通過編譯選項(xiàng) -qlngdbl128 和 -qalign=natural 為 long double 類型的數(shù)據(jù)保持 16 字節(jié)對(duì)齊提供了有限的支持。
編譯命令示例:
清單 22. PASE 下進(jìn)行編譯
xlC_r -o test -qlngdbl128 -qalign=natural – H16 – lc128 -qrtti=dyna -qlanglvl=newexcp -Wl,,-brtl -Wl,-bhalt:8 -bI:/usr/lib/as400_libc.exp test.cpp |
xlC_r 是編譯命令,用來編譯多線程程序以確保和線程安全庫鏈接。
-qrtti 可以為 dynamic_cast 產(chǎn)生運(yùn)行時(shí)類型識(shí)別信息。
-qlanglvl 指定 new 或 new[] 在不能分配請求的內(nèi)存時(shí)拋出異常
-Wl 提供了一組鏈接選項(xiàng):-brtl 默認(rèn)值會(huì)先搜尋 .so 類型的文件進(jìn)行鏈接,再搜尋 .a 類型的文件;-bhalt 確保當(dāng)鏈接程序返回的錯(cuò)誤值大于指定值時(shí)鏈接器掛起。
編譯命令會(huì)將 -bI 后面的參數(shù)傳遞給鏈接器 ld,as400_libc.exp 文件包含了來自 libc.a 的 IBM i 系統(tǒng)特有的接口。
如果生成鏈接文件而非可執(zhí)行程序則需使用 -qmkshrobj 參數(shù)。
總結(jié)
通常,PASE 應(yīng)用可以利用 IBM i 操作系統(tǒng)環(huán)境提供的服務(wù),如安全,消息處理,通信,備份和恢復(fù),同時(shí)也可以使用繼承自 AIX 的應(yīng)用接口。運(yùn)行在 PASE 下的應(yīng)用可以集成 ILE 文件系統(tǒng)和 DB2 for IBM i,也可以調(diào)用 Java 和 ILE 應(yīng)用。Java 和 ILE 應(yīng)用也可以調(diào)用 PASE 應(yīng)用。這種相互調(diào)用方便了開發(fā)人員進(jìn)行跨平臺(tái)程序移植,提高了資源使用率并有助于節(jié)約投資和維護(hù)成本。