.netmodule Files as Linker Input

link.exe now accepts MSIL .obj and .netmodules as input. The output file produced by the linker will be an assembly or a .netmodule with no run-time dependency on any of the .obj or .netmodules that were input to the linker.

.netmodules are created by the Visual C++ compiler with /LN (Create MSIL Module) or by the linker with /NOASSEMBLY (Create a MSIL Module). .objs are always created in a Visual C++ compilation. For other Visual Studio compilers, use the /target:module compiler option.

In most cases, you will need to pass to the linker the .obj file from the Visual C++ compilation that created the .netmodule, unless the .netmodule was created with /clr (Common Language Runtime Compilation). MSIL .netmodules used as input to the linker must be pure MSIL, which can be produced by the Visual C++ compiler using /clr:safe. Other Visual Studio compilers produce pure MSIL modules by default.

For information on how to invoke the linker from the command line, see Linker Command-Line Syntax and Setting the Path and Environment Variables for Command-Line Builds.

Passing a .netmodule or .dll file to the linker that was compiled by the Visual C++ compiler with /clr or with /clr:pure can result in a linker error. For more information, see Choosing the Format of .netmodule Input Files.

The linker accepts native .obj files as well as MSIL .obj files compiled with /clr, /clr:pure, or /clr:safe. When passing mixed .objs in the same build, the verifiability of the resulting output file will, by default, be equal to the lowest level of verifiability of the input modules. For example, if you pass a safe and pure .obj to the linker, the output file will be pure. /CLRIMAGETYPE (Specify Type of CLR Image) lets you specify a lower level of verifiability, if that is what you need.

If you currently have an application that is composed of two or more assemblies and you want the application to be contained in one assembly, you must recompile the assemblies and then link the .objs or .netmodules to produce a single assembly.

You must specify an entry point using /ENTRY (Entry-Point Symbol) when creating an executable image.

When linking with an MSIL .obj or .netmodule file, use /LTCG (Link-time Code Generation), otherwise when the linker encounters the MSIL .obj or .netmodule, it will restart the link with /LTCG.

MSIL .obj or .netmodule files can also be passed to cl.exe.

Input MSIL .obj or .netmodule files cannot have embedded resources. A resource is embedded in an output file (module or assembly) with /ASSEMBLYRESOURCE (Embed a Managed Resource) linker option or with the /resource compiler option in other Visual Studio compilers.

When performing MSIL linking, and if you do not also specify /LTCG (Link-time Code Generation), you will see an informational message reporting that the link is restarting. This message can be ignored, but to improve linker performance with MSIL linking, explicitly specify /LTCG.


In C++ code the catch block of a corresponding try will be invoked for a non System exception. However, by default, the CLR wraps non System exceptions with RuntimeWrappedException. When an assembly is created from Visual C++ and non Visual C++ modules and you want a catch block in C++ code to be invoked from its corresponding try clause when the try block throws a non System exception, you must add the

[assembly:System::Runtime::CompilerServices::RuntimeCompatibility(WrapNonExceptionThrows=false)] attribute to the source code for the non C++ modules.

// MSIL_linking.cpp
// compile with: /c /clr
value struct V {};

ref struct MCPP {
   static void Test() {
      try {
         throw (gcnew V);
      catch (V ^) {
         System::Console::WriteLine("caught non System exception in C++ source code file");

int main() {

By changing the Boolean value of the WrapNonExceptionThrows attribute, you modify the ability of the Visual C++ code to catch a non System exception.

// MSIL_linking_2.cs
// compile with: /target:module /addmodule:MSIL_linking.obj
// post-build command: link /LTCG MSIL_linking.obj MSIL_linking_2.netmodule /entry:MLinkTest.Main /out:MSIL_linking_2.exe /subsystem:console
using System.Runtime.CompilerServices;

// enable non System exceptions

class MLinkTest {
   public static void Main() {
      try {
      catch (RuntimeWrappedException) {
         System.Console.WriteLine("caught a wrapped exception in C#");
caught non System exception in C++ source code file

See Also


LINK Input Files

Linker Options