2016-05-25 17 views
2

Ich benutze swig, um C# -Wrapper für einige C-Code-Basis zu generieren, die von C# verwendet werden. Wenn ich swig laufen, erzeugt er eine Wrapper c-Datei, die auf die erzeugte PInvoke C# Datei alle Funktionen macht ... Zum Beispiel:Unmanaged C# ruft eine statische Bibliothek auf

// 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")] 

Dies funktioniert gut, wenn ich ein dynamisches bin Gebäude Bibliothek. Allerdings muss ich jetzt iOS unterstützen, also habe ich eine statische Bibliothek vorbereitet und die Option -dllimport '__Internal' an swig übergeben, damit das funktioniert.

Leider erhalte ich Fehler Verknüpfung wie:

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

der Tat, ich habe meine „CSharp_DMGameMode_timeLimit_set“, aber das ist der Punkt des „Einstiegspunkt“ Argument?

Also, da dieser Fehler durch das Xcode-Projekt Unity ausgelöst wird, bin ich nicht ganz sicher, was die Ursache des Fehlers ist. Schlägt es für statische Bibliotheken fehl? Ist das etwas, das auf der Seite Unity oder swig festgelegt wird?

Update: Nach mehr in diesen Graben, ich glaube, ich habe eine Ahnung von dem, was hier los ist ..

Das Hauptproblem scheint aus dem AOT-Compiler zu sein, die die CS alle zu kompilieren versucht Code zu einer ARM-Assembly. Dies scheint für iOS erforderlich zu sein, daher generiert es während der Unity-AOT-Kompilierung eine Datei RegisterMonoModules.cpp, die versucht, Zugriffsfunktionen auf den nativen Code zu definieren. RegisterMonoModules.cpp berücksichtigt nicht den entrepoint-Parameter, der verursacht, dass undefinierte Symbolfehler ausgelöst werden ...

Immer noch versucht, einen richtigen Workaround zu finden.

Antwort

2

Das Hauptproblem scheint von der Einheit zu sein, und nicht Swig oder Mono. Wie oben erwähnt, führt Unity eine AOT-Kompilierung durch, die das Einstiegspunktargument nicht berücksichtigt. Dies erzeugt cpp-Code, der den Funktionsnamen aufruft, nicht den Namen des Einstiegspunkts.

Ich habe dies bestätigt, indem ich das Skript-Backend auf IL2cpp umgestellt habe, und der Name des Einstiegspunkts wurde dort berücksichtigt.


Lassen Sie uns auf Rückrufe umschalten. Nicht genau auf die Frage bezogen, aber es passt definitiv zum Kontext von Unity + Native Plugins + iOS.

AFAIK, Sie können nicht eine verwaltete Methode auf iOS-Basis mit Mono 2x auf iOS-Basis gemarshallt haben. Vorher musste ich alle String-Callback- und Exception-Handler aus den swig-generierten Dateien löschen.Glücklicherweise unterstützt IL2Cpp Rückrufe, nach ein wenig Feintuning:

  1. using AOT;
  2. Dekorieren Rückrufe hinzufügen mit [MonoPInvokeCallback(typeof(method_signature))]

Sie dieses Skript verwenden können, nur um es verwenden, um die erzeugten swig Dateien zu verarbeiten:

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) 

Für alle, die Hilfe bei der Konvertierung suchen ihre generierten Swig CSharp PInvoke-Datei zu etwas Mono 2x Scripting-Backend wird erlauben, stecken Sie dies irgendwo in Ihrem Build-Prozess, nachdem die CSharp-Dateien generiert werden:

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)