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 module is a unit of compilation, comparable to .obj
files in C++. 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
Anonymous
i can’t understand anything.Could you explain it better. where I should put this xml code?
Cazurro!!!
Thomas Freudenberg
Save the XMl as a .proj file and pass it to MSBuild
Anonymous
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
Anonymous
The command of tag not found. ¿link.exe is a external file? My system doesn't have this executable. ¿I should download it anywhere?
Thomas Freudenberg
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.
Leave a Comment
Your email address will not be published. Required fields are marked *