2016-05-25 131 views
2

我使用痛飲生成C#包裝爲從C#中使用一些C代碼庫。當我運行痛飲,它會生成一個公開的所有功能,所生成的PInvoke C#文件的包裝C文件...例如:非託管C#調用靜態庫

// This is in KodLogic_wrap.c 
SWIGEXPORT void SWIGSTDCALL CSharp_DMGameMode_timeLimit_set(void * jarg1, unsigned short jarg2) { ... } 

// This is in KodLogicPInvoke.cs 
[global::System.Runtime.InteropServices.DllImport("KodLogic", EntryPoint="CSharp_DMGameMode_timeLimit_set")] 

這時候我建立一個動態的偉大工程圖書館。不過,我需要現在支持iOS,所以我已經準備好了一個靜態庫,並且通過了-dllimport '__Internal'選項來讓它工作。

不幸的是,我收到鏈接錯誤,如:

"_DMGameMode_timeLimit_set", referenced from: 
    RegisterMonoModules() in RegisterMonoModules.o 
    (maybe you meant: _CSharp_DMGameMode_timeLimit_set) 

事實上,我確實意味着「CSharp_DMGameMode_timeLimit_set」,但是這就是「入口點」的說法的呢?

所以,因爲這個錯誤是由Unity產生的Xcode項目拋出,我不太清楚什麼是失敗的根源。它是否對靜態庫失敗?這是否需要在統一方或瑞格方面進行修正?

更新:挖掘更多的進入在此之後,我想我怎麼在這裏上的輕微想法..

的主要問題似乎是從AOT編譯器,它會嘗試編譯所有的CS代碼到ARM程序集。這似乎是iOS所必需的,因此在Unity的AOT編譯期間,它會生成一個文件RegisterMonoModules.cpp,該文件嘗試爲本機代碼定義訪問函數。 RegisterMonoModules.cpp不尊重入口點參數,這將導致未定義的符號錯誤被拋出...

仍嘗試找到適當的解決方法。

回答

2

的主要問題似乎是從團結,而不是痛飲,也不單。如上所述,Unity執行AOT編譯,不支持入口點參數。這產生了調用該函數的名稱,而不是入口點名稱cpp的代碼..

我已經通過腳本後端切換到IL2cpp證實了這一點,和入口點名稱很榮幸在那裏。


讓我們切換到回調。與問題不完全相關,但它絕對適合Unity + Native插件+ iOS的上下文。

AFAIK,你不能封送到故土上使用單2X iOS的一個管理方法。我以前必須從swig生成的文件中刪除所有的字符串回調和異常處理程序。幸運的是,IL2Cpp支持回調,稍加調整後:

  1. 添加using AOT;
  2. 裝飾回調與[MonoPInvokeCallback(typeof(method_signature))]

你可以使用這個腳本,只是用它來處理生成的痛飲文件:

def process_csharp_callbacks(pinvoke_file): 
    """Process PInvoke file by fixing the decorators for callback methods to use: 
    [MonoPInvokeCallback(typeof(method_signature))] 
    """ 
    # prepare requirements 
    with open(pinvoke_file) as f: 
    content = f.read() 

    callback_methods_regex = re.compile(r"(+)static (?:void|string) (?:SetPending|CreateString)\w*\([\s\w\,]+\)") 
    callback_decorator = "[MonoPInvokeCallback(typeof(ExceptionDelegate))]" 
    callback_arg_decorator = "[MonoPInvokeCallback(typeof(ExceptionArgumentDelegate))]" 
    callback_str_decorator = "[MonoPInvokeCallback(typeof(SWIGStringDelegate))]" 
    # add use AOT 
    content = content.replace("\n\n", "\nusing AOT;\n", 1) 
    # fix callback methods 
    def method_processor(match): 

    match_string = match.group() 
    indentation = match.captures(1)[0] 

    if match_string.find(",") != -1: 
     fix = callback_arg_decorator 
    elif match_string.find("static string") != -1: 
     fix = callback_str_decorator 
    else: 
     fix = callback_decorator 

    return indentation + fix + "\n" + match_string 

    content = callback_methods_regex.sub(method_processor, content) 
    # write it back 
    with open(pinvoke_file, "w+") as f: 
    f.write(content) 

對於任何正在尋找幫助的人他們生成的swig CSharp PInvoke文件到單聲道2x腳本後端將允許的地方,在生成CSharp文件之後,將其粘貼到構建過程的某個位置:

pinvoke_template = """{extern_prefix} CSharp_{method_signature}; 
    {normal_prefix} {method_signature} {{ 
    {return_statement}CSharp_{method_name}({method_args}); 
    }}""" 

def process_csharp_wrapper(csharp_dir): 
    """Reads the PINVOKE csharp file, and performs the following: 
    1. Remove EntryPoint="xxx" from the decorators 
    2. Make the methods match their native counterpart name 
    3. Add a C# method with the original name, for compatability 
    """ 
    # prepare requirements 
    pinvoke_file = os.path.join(csharp_dir, "KodLogicPINVOKE.cs") 
    with open(pinvoke_file) as f: 
    content = f.read() 

    decorator_regex = re.compile(r', EntryPoint=".*?"') 
    method_regex = re.compile(r"(public static extern \w+[\w:\.]+)\s(([^S]\w+)\((?:([\w:\. ]+)\,?)*\));") 
    # fix decorators 
    content = decorator_regex.sub("", content) 
    # fix method definitions 
    def method_processor(match): 
    extern_prefix = match.captures(1)[0] 
    return pinvoke_template.format(
     extern_prefix=extern_prefix, 
     normal_prefix=extern_prefix.replace("extern ", ""), 
     method_signature=match.captures(2)[0], 
     return_statement=("return " if extern_prefix.find("void") == -1 else ""), 
     method_name=match.captures(3)[0], 
     method_args=", ".join(map(lambda s: s.strip().split()[1], match.captures(4))) 
    ) 

    content = method_regex.sub(method_processor, content) 
    # write it back 
    with open(pinvoke_file, "w+") as f: 
    f.write(content)