C++混合編程之idlcpp教程Lua篇(2)

 

    在上一篇 C++混合編程之idlcpp教程(一) 中介紹了 idlcpp 工具的使用。如今對 idlcpp 所帶的示例教程進行講解,這裏針對的 Lua 語言的例子。首先看第一個示例程序 LuaTutorial0。像不少語言的第一個例子同樣,是一個打印 Hello world 的程序。用Visual Studio 2015打開解決方案文件 tutorials\LuaTutorials\LuaTutorials.sln,其下已經有多個工程文件。html

 

 

在工程LuaTutorial0中,已經加入了三個文件,分別是 LuaTutorial0.cpp, Tutorial0.i, tutorial0.lua。首先看Tutorial0.i內容以下:編程

 

//tutorial

###include <stdio.h>

namespace tutorial
{
    struct Test
    {
        static void Run();
    };
    #{
    inline void Test::Run()
    {
        printf("Hello World!");
    }
    #}
}

 

看起來和C++代碼較爲類似。編譯Tutorial0.i,將會生成Tutorial0.h,Tutorial0.mh,Tutorial0.ic,Tutorial0.mc四個文件。其中Tutorial0.h內容以下:windows

 

//DO NOT EDIT THIS FILE, it is generated by idlcpp
//http://www.idlcpp.org

#pragma once


#include <stdio.h>


#line 4 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
namespace tutorial

#line 5 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
{

#line 6 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
    struct Test

#line 7 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
    {
    public:


#line 8 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
        static void Run();

#line 9 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
    };

    inline void Test::Run()
    {
        printf("Hello World!");
    }
    

#line 16 "D:/GitHub/idlcpp/tutorials/Common/Tutorial0.i"
}

 

由於在編譯.i文件時指定了-ld選項,因此生成的.h文件中其中有許多#line指令,這是爲下一步C++編譯時可以定位錯誤到.i中的位置,而不是定位到.h上。修改編譯選項,去掉-ld選項,從新編譯,獲得的結果以下:app

 

//DO NOT EDIT THIS FILE, it is generated by idlcpp
//http://www.idlcpp.org

#pragma once


#include <stdio.h>

namespace tutorial
{
    struct Test
    {
    public:

        static void Run();
    };

    inline void Test::Run()
    {
        printf("Hello World!");
    }
    
}

 

這樣看起來比較清爽了,請和上面的Tutorial0.i內容對照一下,基本上內容差很少。下面詳細解釋一下,首先是第一行函數

 //tutorial工具

這是註釋,idlcpp和C++同樣用//表示單行註釋,用/**/表示一塊註釋。 post

###include <stdio.h>lua

idlcpp只分析接口的聲明,而C++頭文件中通常還會出現其餘的內容。此處idlcpp提供了將.i文件中的部份內容直接複製到.h的方法,一共有三種url

  1. ##,表示將後續的一整行復制到.h的相應位置上,相似C++中的//註釋一行。
  2. #{ 和 #},將在這兩個符號之間的內容複製到.h的相應位置上,相似C++中的/*和*/註釋一大塊。
  3. #,表示將後續的一個標識符或整數複製到相應的位置。

這一行表示將#include <stdio.h>複製到.h中,下面的printf要用到這個頭文件。spa

namespace tutorial 以及對應的{}。

namespace 和C++中的概念是同樣的,會原樣輸出到.h中。

 

struct Test 以及對應的{}; 。

這個也和C++中概念相似,會原樣輸出到.h中。

 

下面.h文件中多了一行

public:

在idlcpp中聲明的數據成員以及成員函數都被認爲是public的,因此此處無腦加了這一行。

 

static void Run(); 這一行兩邊也是同樣的,聲明一個靜態成員函數。

 

#{

inline void Test::Run()

{

  printf("Hello World!");

}

#}

如上所述,idlcpp將#{和#}之間的內容複製到.h中。由於idlcpp只處理函數聲明,不能處理其實現代碼,因此沒法向C++同樣將其實現代碼放在類的聲明中,只能寫在外面。此處爲了少寫一個.cpp文件,就用內聯函數的方式寫在頭文件中。

文件Tutorial0.ic中沒有實質性的內容。

文件Tutorial0.mh和Tutorial0.mc用於構建對應的元數據信息,具體內容牽涉太多,暫時不作解釋。

再來看一下LuaTutorial0.cpp的內容

#include <tchar.h>
#include <string>
#include <windows.h>

#include "lua.hpp"
#include "../../../paf/src/paflua/LuaWrapper.h"
#include "../../Common/Tutorial0.h"
#include "../../Common/Tutorial0.mh"
#include "../../Common/Tutorial0.ic"
#include "../../Common/Tutorial0.mc"

#if defined(_DEBUG)
#pragma comment(lib,"pafcore_d.lib")
#pragma comment(lib,"paflua_d.lib")
#pragma comment(lib,"lua53_d.lib")
#else
#pragma comment(lib,"pafcore.lib")
#pragma comment(lib,"paflua.lib")
#pragma comment(lib,"lua53.lib")
#endif


void GetExePath(std::string& path)
{
    char fileName[MAX_PATH];
    GetModuleFileName(0, fileName, sizeof(fileName));
    const char* end = _tcsrchr(fileName, '\\');
    path.assign(fileName, end + 1);
}

int _tmain(int argc, _TCHAR* argv[])
{
    int error;
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaopen_paflua(L);
    std::string path;
    GetExePath(path);
    path += "tutorial0.lua";
    error = luaL_loadfile(L, path.c_str()) || lua_pcall(L, 0, 0, 0);
    if (error) 
    {
        fprintf(stderr, "%s\n", lua_tostring(L, -1));
        lua_pop(L, 1);
    }
    lua_close(L);
    return 0;
}

#include "lua.hpp"

這一行引入lua頭文件

 

#include "../../../paf/src/paflua/LuaWrapper.h"

這一行引入lua插件頭文件

 

#include "../../Common/Tutorial0.h"

#include "../../Common/Tutorial0.mh"

#include "../../Common/Tutorial0.ic"

#include "../../Common/Tutorial0.mc"

這幾行將由Tutorial0.i編譯的結果包含進來,這樣編譯後就會將對應的元數據信息註冊到系統中,從而可以讓腳步語言訪問到。

 main()函數中是一個運行一個lua腳步的基本過程。其中

luaopen_paflua(L);

這一行在lua虛擬機中加載插件。

最後看一下tutorial0.lua文件的內容

 

paf.tutorial.Test.Run();

 

這句代碼表示調用C++中的::tutorial::Test::Run();

全部由idlcpp生成的數據類型都是在paf名字下,能夠理解爲lua中的名字paf等價於C++中的全局名字空間。在C++中,Run函數的全名能夠認爲是::tutorial::Test::Run,在lua中即爲paf.tutorial.Test.Run。

編譯連接後,執行結果以下圖:

 

 

能夠看到Lua正確調用了C++中的函數。

相關文章
相關標籤/搜索