首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将C#和C++程序集链接到单个可执行文件?

如何将C#和C++程序集链接到单个可执行文件?
EN

Stack Overflow用户
提问于 2010-04-09 16:17:04
回答 3查看 7.9K关注 0票数 10

我有一个VS2008解决方案,该项目生成一个C#可执行文件,该项目引用一个生成包含C++/CLI和非托管C++的dll的项目。

我想将它们合并到单个可执行文件中,因为C++ dll包含我希望嵌入到主可执行文件中的安全代码。

我不能使用ILMerge,因为dll包含托管和非托管代码。建议的解决方案似乎是使用link.exe将C#程序集与C++对象文件链接起来。这就是我想要做的。

我手动编辑了c#可执行文件的项目文件以生成netmodule。我在可执行项目中添加了post构建步骤,以运行link.exe将c# netmodule和已编译的C++对象文件链接在一起,然后运行mt.exe来合并两个项目创建的程序集清单。这将成功运行,但exe仍然包含对c++项目正常生成过程生成的dll中定义的C++类型的引用并使用这些类型。

然后,我在/NOASSEMBLY dll的项目设置中指定了C++,因此它也会生成一个C++模块。在C#项目中,我删除了对C++项目的引用,但在解决方案中添加了一个项目依赖项。我手动编辑了C#项目文件,使其包括以下内容:

代码语言:javascript
复制
<ItemGroup>
    <AddModules Include="..\Debug\librarycode.netmodule" />
</ItemGroup>

即引用现在由C++项目生成的C++ netmodule。

但是,现在post build事件中的链接器步骤失败了,原因是:

代码语言:javascript
复制
error LNK2027: unresolved module reference 'librarycode.netmodule'
fatal error LNK1311: 1 unresolved module references: 

这是完全可以理解的,因为我不是在图书代码netmodule中链接,而是在用于生成netmodule的C++对象文件中进行链接。

总之,如何将c#可执行文件和C++对象文件合并到单个程序集中?我错过了什么?

到目前为止,我的引用源(来自MSDN上的link.exe命令、链接、引用等)是以下两篇文章:

  • http://blogs.msdn.com/texblog/archive/2007/04/05/linking-native-c-into-c-applications.aspx
  • http://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlesslyWithILMergeAndMSBuild.aspx我有一个演示解决方案,如果这有帮助的话,它可以显示我目前的工作情况。

先谢谢你。

Update1

我跟在的博客上做了正确的例子,并证实了它的作用。使用反射器,我可以看到得到的可执行文件包含两个netmodules。c# netmodule包含对另一个netmodule的引用,但没有名称?!如果将程序集移动到新目录,则第二个netmodule将变为未引用(显然),但可执行文件仍然运行,因为c# netmodule中存在具有正确定义的类型。

请注意,原始c# netmodule确实包含对c++ netmodule的命名引用,因此必须是删除名称的链接器步骤。

为了在示例项目中遵循这个示例,我在post构建链接器步骤中添加了一个/ASSEMBLYMODULE参数。链接器现在出现故障。

代码语言:javascript
复制
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

我猜是链接器魔法移除了我所缺少的模块引用名。

任何想法都欢迎。

Update2

我已经将我的项目简化为最简单的项目,并且正在尝试从命令行编译。以下批处理文件成功地构建了Steve博客中的示例:

代码语言:javascript
复制
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的示例代码:

代码语言:javascript
复制
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

找出差异的时间:-(

EN

回答 3

Stack Overflow用户

发布于 2012-10-19 03:22:33

下面是一个Nant脚本,它完全符合您(和我)的要求(如果我读到您想要的内容,也就是xD)。

其中一些是缺失的(比如一些变量,并不是真正需要的),但事实证明,这是相当容易实现的。

这显示了cl/csc和链接器标志,您需要能够合并混合程序集和托管程序集。另外,作为额外的“奖励”,所有内部类/方法/字段等在整个新程序集中都是可见的,这意味着它们跨越了项目的边界。

代码语言:javascript
复制
    <delete file="${tmp.cpp}" />
    <foreach item="File" property="filename">
        <in>
            <items basedir="${basedir}/SpotiFire.LibSpotify">
                <include name="**.h" />
            </items>
        </in>
        <do>
            <echo message="#include &quot;${filename}&quot;&#10;" 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>
票数 3
EN

Stack Overflow用户

发布于 2010-04-12 08:40:19

您的业务案例非常类似于SQLite,因此同样的方法应该适用于您。基本上,它们将托管程序集作为单独的数据部分插入到非托管dll中。然后,它们能够正常地从托管dll中调用非托管dll。还可以动态链接到dll中的非托管代码。

票数 0
EN

Stack Overflow用户

发布于 2014-08-14 01:42:27

为了正确地合并,program.netmodule应该在链接器中指定两次,在输入列表中,并作为ASSEMBLYMODULE选项中的参数。

因此,整个命令行将如下:

代码语言:javascript
复制
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泰勒克 )检查结果程序集中的内容。

编码愉快。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2609056

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档