[英]How to link C# and C++ assemblies into a single executable?
我有VS2008解決方案包含一個項目,該項目生成一個C#可執行文件,該項目引用一個生成包含C ++ / CLI和非托管C ++的DLL的項目。
我想將這些合並到一個可執行文件中,因為C ++ DLL包含我想要嵌入主可執行文件的安全代碼。
我不能使用ILMerge,因為dll包含托管代碼和非托管代碼。 建議的解決方案似乎是使用link.exe將C#程序集與C ++目標文件鏈接起來。 這就是我想要做的。
我手動編輯了c#可執行文件的項目文件以生成netmodule。 我在可執行項目中添加了一個構建后步驟,以運行link.exe將c#netmodule和已編譯的C ++目標文件鏈接在一起,然后運行mt.exe來合並兩個項目創建的程序集清單。 這運行成功,但是exe仍然包含對C ++項目的正常構建過程生成的dll中定義的c ++類型的引用和使用。
然后我在C ++ dll的項目設置中指定了/ NOASSEMBLY,因此它還生成了一個netmodule。 在C#項目中,我刪除了對C ++項目的引用,但在解決方案中添加了項目依賴性。 我手動編輯了C#項目文件,包含類似於:
<ItemGroup>
<AddModules Include="..\Debug\librarycode.netmodule" />
</ItemGroup>
即引用現在由C ++項目生成的C ++ netmodule。
但是,現在我的post build事件中的鏈接器步驟失敗了:
error LNK2027: unresolved module reference 'librarycode.netmodule'
fatal error LNK1311: 1 unresolved module references:
這完全可以理解,因為我沒有鏈接到librarycode netmodule; 我鏈接在用於生成netmodule的C ++目標文件中。
簡而言之,如何將ac#executable和C ++目標文件合並到一個程序集中? 我錯過了什么?
到目前為止我的引用源(來自MSDN上的link.exe命令鏈接引用等)是以下兩篇文章:
非常感謝你提前。
我在Steve Teixeira的博客中完全遵循了這個例子,並證實它有效。 使用反射器,我可以看到生成的可執行文件包含兩個netmodule。 c#netmodule包含對另一個netmodule的引用但沒有名稱?! 如果將程序集移動到新目錄,則第二個netmodule變為未引用(顯然),但可執行文件仍然運行,因為c#netmodule中存在具有正確定義的類型。
請注意,原始c#netmodule確實包含對c ++ netmodule的命名引用,因此它必須是刪除名稱的鏈接器步驟。
試圖在我的示例項目中遵循此示例,我已將/ ASSEMBLYMODULE參數添加到我的后期構建鏈接器步驟中。 鏈接器現在失敗了
LNK2022: metadata operation failed (80040427) : Public type 'MixedLanguageLibrary.Class1' is defined in multiple places in this assembly: 'MixedLanguageDemo.exe' and 'mixedlanguagelibrary.netmodule'
LINK : fatal error LNK1255: link failed because of metadata errors
我猜這是鏈接器魔術刪除我缺少的模塊引用名稱。
歡迎任何想法。
我已經盡可能簡化了我的項目,我試圖從命令行編譯。 以下批處理文件在Steve Teixeira的博客中成功構建了示例:
setlocal
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
if errorlevel 1 goto End
cl /c /MD nativecode.cpp
if errorlevel 1 goto End
cl /clr /LN /MD clrcode.cpp nativecode.obj
if errorlevel 1 goto End
csc /target:module /addmodule:clrcode.netmodule Program.cs
if errorlevel 1 goto End
link /LTCG /CLRIMAGETYPE:IJW /ENTRY:ConsoleApplication1.Program.Main /SUBSYSTEM:CONSOLE /ASSEMBLYMODULE:clrcode.netmodule /OUT:MixedApp.exe clrcode.obj nativecode.obj program.netmodule
:End
以下批處理文件無法使用鏈接器錯誤LNK2022構建我的示例代碼:
setlocal
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
if errorlevel 1 goto End
cl /c /MD messageprovider.cpp
if errorlevel 1 goto End
cl /clr /LN /MD managedmessageprovider.cpp messageprovider.obj
if errorlevel 1 goto End
csc /target:module /addmodule:managedmessageprovider.netmodule Program.cs Form1.cs Form1.Designer.cs
if errorlevel 1 goto End
link /LTCG /CLRIMAGETYPE:IJW /ENTRY:MixedLanguageDemo.Program.Main /SUBSYSTEM:WINDOWS /ASSEMBLYMODULE:managedmessageprovider.netmodule /OUT:MixedLanguageDemo.exe managedmessageprovider.obj messageprovider.obj program.netmodule
:End
時間點差異:-(
以下是一個Nant構建腳本,它完全符合您(和我)的要求(如果我讀到你想要的權利,那就是xD)。
其中一些缺失(就像一些變量,實際上並不需要),但事實證明它實際上很容易實現。
這顯示了您需要能夠合並混合和托管程序集的cl / csc和鏈接器標志。 此外,作為添加的“獎勵”,所有內部類/方法/字段等在整個新程序集中都是可見的,這意味着它們跨越項目的邊界。
<delete file="${tmp.cpp}" />
<foreach item="File" property="filename">
<in>
<items basedir="${basedir}/SpotiFire.LibSpotify">
<include name="**.h" />
</items>
</in>
<do>
<echo message="#include "${filename}" " append="true" file="${tmp.cpp}" />
</do>
</foreach>
<cl outputdir="${build.obj}" options="/clr /LN">
<sources basedir="${basedir}/SpotiFire.LibSpotify">
<include name="*.cpp" />
<include name="${tmp.cpp}" asis="true" />
<exclude name="AssemblyInfo.cpp" />
</sources>
</cl>
<csc target="module" output="${build.obj}/SpotiFire.netmodule">
<modules basedir="${build.obj}">
<include name="tmp.obj" />
</modules>
<references refid="all_refs" />
<sources basedir="${basedir}/SpotiFire.SpotifyLib">
<include name="**.cs" />
</sources>
</csc>
<link output="${build.dir}/${name}.dll" options="/LTCG /FIXED /CLRIMAGETYPE:IJW /NOENTRY /DLL">
<sources basedir="${build.obj}">
<include name="*.obj" />
<include name="*.netmodule" />
<include name="${basedir}/libspotify.lib" asis="true" />
</sources>
<arg value="/DEBUG" if="${build.debug == 'true'}" />
</link>
為了正確合並,program.netmodule應該在鏈接器中指示兩次,在輸入列表中,並作為ASSEMBLYMODULE選項中的參數。
所以整個命令行將如下:
link /LTCG /CLRIMAGETYPE:IJW /ENTRY:MixedLanguageDemo.Program.Main /SUBSYSTEM:WINDOWS /ASSEMBLYMODULE:program.netmodule /OUT:MixedLanguageDemo.exe managedmessageprovider.obj messageprovider.obj program.netmodule
在此命令行之后,program.module類型應合並到MixedLanguageDemo.exe中。 您始終可以使用.NET反射器(如ILSpy或Telerik)檢查生成的程序集中的內容 。
快樂的編碼。
您的業務案例與SQLite非常相似,因此相同的方法應該適合您。 基本上,他們將托管程序集作為單獨的數據部分插入到非托管dll中。 然后,他們能夠以正常方式從托管dll調用非托管dll。 也可以動態鏈接到dll中的非托管代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.