locked
Linking in Mixed assembly RRS feed

  • Question

  • Hi everyone.

     

    I'm trying to write an API wrapper in c++ (which exposes some classes publicly), and then also write some utility classes in C# (since it's more productive to write C# than C++/CLI), and link them together.  I followed the instructions by Steve Tei at https://blogs.msdn.com/texblog/archive/2007/04/05/linking-native-c-into-c-applications.aspx.  I found that even his instructions don't work if the underlying C++/CLI class is made public.  I get metadata errors such as:

     

    LINK : error LNK2022: metadata operation failed (80040427) : Public type 'CPPClass' is defined in multiple places in this assembly: 'test.exe' and 'test.netmodule'
    LINK : fatal error LNK1255: link failed because of metadata errors

     

    for every single public exposed class in my C++/CLI netmodule.  I'm guessing this is because i'm linking in both the netmodule as well as the .obj file.

     

    Does anyone know how i can link this successfully?  The C# classes will reference the C++/CLI classes, but not vice versa.

     

    Thank you

    atanamir

    Tuesday, October 9, 2007 12:44 AM

Answers

  • Hi,

     

    Yes, ILMerge only works for pure assemblies.  Because this is IJW (mix of managed/unamnaged), ILmerge doesn't work.  It took me a long time, but i finall figured out a solution: instead of compiling the C++ code into a netmodule, just make obj files, and add those at compile time for CSC. 

     

    However, another problem becomes apparent, then: if multiple classes exist, and you add in the obj for each one of them, CSC's linker will complain that objects are defined multiple times as well.

     

    I found that I can just put a single .obj as a module for CSC; i think it contains metadata for every single class in it.  Then, when linking with link.exe, link all the obj files then. 

     

    It seems to work for me. 

    Does this process look good to you?

     

    Thanks!

    stephen

     

    In summary:

     

        cl.exe /MD /c /clr [other options] [all your cpp files] --> one .obj file for each cpp file.

        csc.exe /target:module /addmodule:[ONE obj file from the output for cl -- it can be any one] cscode.cs

        link.exe /DLL /LTCG /NOENTRY /CLRIMAGETYPE:IJW [ALL the obj files] cscode.netmodule

        ----> outputs a single assembly!

     

    I think this works.

    Tuesday, October 9, 2007 8:47 AM

All replies

  • Did you try ILMerge as suggested in the comment on that page?
    Tuesday, October 9, 2007 7:57 AM
  • Hi,

     

    Yes, ILMerge only works for pure assemblies.  Because this is IJW (mix of managed/unamnaged), ILmerge doesn't work.  It took me a long time, but i finall figured out a solution: instead of compiling the C++ code into a netmodule, just make obj files, and add those at compile time for CSC. 

     

    However, another problem becomes apparent, then: if multiple classes exist, and you add in the obj for each one of them, CSC's linker will complain that objects are defined multiple times as well.

     

    I found that I can just put a single .obj as a module for CSC; i think it contains metadata for every single class in it.  Then, when linking with link.exe, link all the obj files then. 

     

    It seems to work for me. 

    Does this process look good to you?

     

    Thanks!

    stephen

     

    In summary:

     

        cl.exe /MD /c /clr [other options] [all your cpp files] --> one .obj file for each cpp file.

        csc.exe /target:module /addmodule:[ONE obj file from the output for cl -- it can be any one] cscode.cs

        link.exe /DLL /LTCG /NOENTRY /CLRIMAGETYPE:IJW [ALL the obj files] cscode.netmodule

        ----> outputs a single assembly!

     

    I think this works.

    Tuesday, October 9, 2007 8:47 AM
  • Hi - probably a bit late but anyways for the benefit of others:

    Thanks first for posting this - really made my life easier and was a great starting point!

    I had a similar problem: a mixed mode C++/IJW originated DLL I needed to merge with c# code and not having to mess with COM and separate DLLs for redistribution - just a simple and clean single file was my objective. And of cause I wanted debugging capability through all code parts - c# and c++ (managed and unmanaged).

    Somewhere I found ilmerge would not work on mixed mode assemblies, so I skipped that try.

    Somewhere it also says VS2005 wasn't supporting the building of multi-file assemblies but here's how I (think I) managed it:

    Step 1:

    While on the c# project side VS2005 indeed seems to only support application or library type projects but - why not - use a post build step to produce the required .netmodule. C# Project - Properties - Build Events - Post-Buid command line:

    csc /outEmbarrassed(TargetName).netmodule /target:module /r:"C:\path_to_additional_reference.dll" /debug:full ..\*.cs [>NUL]

    NOTES:
    - you need to add /debug - otherwise the .pdb file step 2 will create won't be visible to the debugger
    - you need to manually add any non system references - and possibly more stuff if your project is more complex
    - a little annoying: you get 2x the output from csc, if that disturbs you: add ">NUL" as above, or dump into a file if you need to see whats being output

    Step2:

    On the C++/IJW project - go to Property pages - Linker - CommandLine and add Additional Options:

    /LTCG /CLRIMAGETYPE:IJW "C:\path_to_the_c#_module_generated_in_step1\csprojectname.netmodule"

    NOTES:
    I added the above to modify a project that before would build correctly for IJW (mixed managed & unmanaged code), compiling to /clr etc. So - just in case I am missing some config details, thats where you should start from.

    Well - this worked for me - probably I am still missing something, so any feedback is welcome! Cheers 4 now!

    tb
    Friday, March 21, 2008 5:23 PM