Thomas Freudenberg

Confessions of a caffeine addict

Mixing C# and VB.NET in one assembly

A couple of weeks ago Jayson Knight invited me to join the CSMVP's' CSModules package. This project was created to incorporate several CSModules written by CS MVP's. So I bought into that project by bringing along my Akismet spam rule.

At that point in time, for each CSModule there was a single Visual Studio project, all bound together in a Visual Studio solution. But our goal was to incorporate all modules into a single assembly, so the user only has to copy one DLL to his /bin web folder.

My first idea was to put all sources into a single project. However, since every CS MVP wrote his module in his favorite language, there were both C# and VB.NET projects. Unfortunately, in Visual Studio projects have a certain type supporting only a single language.

But luckily, even if there's no support by the IDE, you still can compile different .NET languages into one assembly. The solution are modules. A modules is a unit of compilation, comparable to .obj files. It can't stand by its own, but must be linked into an assembly before it can be used. Basically, a module is an assembly without a manifest. You can get more details on MSDN at .netmodule Files as Linker Input. Additionally I recommend reading Junfeng Zhang's Netmodule vs. Assembly and Multimodule Assemblies.

Knowing the concept of modules, I was able to write a MSBuild project file to compile all CSModules into a single assembly. Here's an (extremely) simplified version:

<Project
    DefaultTargets="build"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    
    <!-- Target folders -->
    <PropertyGroup>
        <SourcePath>src</SourcePath>
    </PropertyGroup>
 
    <!-- Specify the sources to include, excluding any assembly info's -->
    <ItemGroup>
        <CSFiles
            Include="$(SourcePath)/**/*.cs"
            Exclude="$(SourcePath)/**/assemblyinfo.cs"/>
        <VBFiles
            Include="$(SourcePath)/**/*.vb"
            Exclude="$(SourcePath)/**/assemblyinfo.vb;$(SourcePath)/**/My Project/*"/>
    </ItemGroup>
    
    <!-- Specify all referenced assembly -->
    <ItemGroup>
        <References Include="lib/2.1 RTM/*.dll" />
    </ItemGroup>
    
    <!-- Target files -->
    <PropertyGroup>
        <OutputModule>MyModule</OutputModule>
    </PropertyGroup>
    
    <!-- builds the CSMVPs.CSModules assembly -->
    <Target
        Name="build"
        Inputs="@(CSFiles);@(VBFiles);@(References)"
        Outputs="$(OutputModule).dll">
    
        <!-- compile C# sources -->
        <CSC
            Sources="@(CSFiles)"
            References="@(References)"
            OutputAssembly="$(OutputModule).CS.netmodule"
            TargetType="module">
        </CSC>
    
        <!-- compile VB.NET sources -->
        <VBC
            Sources="@(VBFiles)"
            References="@(References)"
            OutputAssembly="$(OutputModule).VB.netmodule"
            TargetType="module">
        </VBC>
    
        <!-- link the C# and VB.NET modules -->
        <Exec
            Command="link /dll /ltcg /out:$(OutputModule).dll *.netmodule" />
 
    </Target>
</Project

Comments

Thomas Freudenberg's Blog said:

I just want to note that my last post was brought to you by Windows Live Writer and Code Syntax Highlighter

# August 21, 2006 6:33 PM

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# August 29, 2006 2:37 PM

Peter Bucher said:

Ich dachte lange, wenn ich ein VB.NET- und ein C#-Projekt habe, geht es nicht, daraus eine einzige Assembly

# April 8, 2008 11:57 AM

Chiquilicuatre said:

i can't understand anything.Could you explain it better. where I should put this xml code?

Cazurro!!!

# May 27, 2008 5:00 AM

Thomas Freudenberg said:

Save the XMl as a .proj file and pass it to MSBuild

# May 27, 2008 5:34 AM

Chicho Terremoto said:

The command of tag <exec> not found. ¿link.exe is a external file? My system doesn't have this executable. ¿I should download it anywhere?

# May 28, 2008 6:26 AM

Thomas Freudenberg said:

link.exe is an external tool, which is installed with Visual Studio. To execute the script you have to either open the Visual Studio 2008 Command Prompt or set the PATH environment variable manually.

# May 31, 2008 12:01 AM

tb2000 said:

Thanks - that was great help.

Not being a MSBuild guru I just (proudly) managed to integrate several c# based projects in a single file assembly - after modifying parts of the central build and .csproj xmls to ensure I would actually get netmodules from VS2005.

I am still struggling to remove the external references from the assembly which I need for the VS IDE - not sure it matters, maybe for purity only. The code works as csc when adding netmodules that implement the same types as ref'd projects/dlls apparently overwrites the external reference - at least it issues a warning.

I would hope sometime this to be supported by VS.

Again - thanks for posting this!

tb

# July 30, 2008 2:42 AM

Kombination von VB und C# said:

Pingback from  Kombination von VB und C#

# August 30, 2012 11:43 AM