I have VS2008 solution containg a project that generates a C# executable that references a project that generates a dll containing both C++/CLI and unmanaged C++.
I would like to merge these into a single executable, as the C++ dll contains security code that I want to embed in the main executable.
I cannot use ILMerge, as the dll contains both managed and unmanaged code. The suggested solution seems to be to use link.exe to link the C# assembly with the C++ object files. This is what I am trying to do.
I manually edited the project file for the c# executable to generate a netmodule. I added a post build step to the executable project to run link.exe to link the c# netmodule and the compiled C++ object files together, then run mt.exe to merge the assembly manifests created by both projects. This runs successfully, but the exe still contains a reference to and uses the c++ types defined in the dll generated by the normal build process for the C++ project.
I then specified /NOASSEMBLY in the project settings for the C++ dll, so it also generates a netmodule. In the C# project, I removed the reference to the C++ project, but added a project dependancy in the solution. I manually edited the C# project file to include similar to:
<ItemGroup>
<AddModules Include="..Debuglibrarycode.netmodule" />
</ItemGroup>
i.e. to reference the C++ netmodule that is now generated by the C++ project.
However, now the linker step in my post build event fails with:
error LNK2027: unresolved module reference 'librarycode.netmodule'
fatal error LNK1311: 1 unresolved module references:
This is entirely understandable, as I am not linking in the librarycode netmodule; I am linking in the C++ object files used to generate the netmodule instead.
So in short, how do I merge a c# executable and C++ object files into a single assembly? What have I missed?
My source of reference so far (appart from the link.exe command link reference etc on MSDN) are the two following articles:
Thank you very much in advance.
Update1
I have followed exactly the example in Steve Teixeira's blog, and verified it works. Using reflector, I can see the resulting executable contains two netmodules. The c# netmodule contains a reference to another netmodule but with no name?! If you move the assembly to a new directory, the second netmodule becomes unreferenced (obviously), but the executable still runs, as types with the correct definition exist in the c# netmodule.
Note that the original c# netmodule does contain a named reference to the c++ netmodule, so it must be the linker step that removes the name.
Trying to follow this example in my sample project, I have added an /ASSEMBLYMODULE argument to my post build linker step. The linker now fails with
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
I guess that it is the linker magic that removes the module reference name that I am missing.
Any ideas welcome.
Update2
I have reduced my project to the simplest possible, and am trying to compile is from the command line. The following batch file successfully builds the example in Steve Teixeira's blog:
setlocal
call "C:Program FilesMicrosoft Visual Studio 9.0VCvcvarsall.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
The following batch file fails to build my example code with linker error LNK2022:
setlocal
call "C:Program FilesMicrosoft Visual Studio 9.0VCvcvarsall.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
Time for spot the difference :-(
See Question&Answers more detail:
os