.netmodule files as linker input
link.exe accepts MSIL .obj
and .netmodule
files as input. The output file produced by the linker is an assembly or a .netmodule
file with no run-time dependency on any of the .obj
or .netmodule
files that were input to the linker.
Remarks
.netmodule
files are created by the MSVC compiler with /LN (Create MSIL module) or by the linker with /NOASSEMBLY (Create a MSIL Module). .obj
files are always created in a C++ compilation. For other Visual Studio compilers, use the /target:module compiler option.
The linker must be passed the .obj
file from the C++ compilation that created the .netmodule
. Passing in a .netmodule
is no longer supported because the /clr:pure and /clr:safe compiler options are deprecated in Visual Studio 2015 and unsupported in Visual Studio 2017 and later.
For information on how to invoke the linker from the command line, see Linker command-line syntax and Use the MSVC toolset from the command line.
Passing a .netmodule
or .dll
file to the linker that was compiled by the MSVC compiler with /clr can result in a linker error. For more information, see Choosing the format of .netmodule input files.
The linker accepts both native .obj
files and MSIL .obj
files compiled with /clr. You can pass mixed .obj
files in the same build. The resulting output file's default verifiability is the same as the lowest input module's verifiability.
You can change an application that's composed of two or more assemblies to be contained in one assembly. Recompile the assemblies' sources, and then link the .obj
files or .netmodule
files to produce a single assembly.
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. You'll see an informational message that the link is restarting. You can ignore this message, but to improve linker performance, explicitly specify /LTCG.
MSIL .obj
or .netmodule
files can also be passed to cl.exe.
Input MSIL .obj
or .netmodule
files can't have embedded resources. Embed resources in an output module or assembly file by using the /ASSEMBLYRESOURCE (Embed a managed resource) linker option. Or, use the /resource compiler option in other Visual Studio compilers.
Examples
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 C++ and non-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() {
MCPP::Test();
}
*/
By changing the Boolean
value of the WrapNonExceptionThrows
attribute, you modify the ability of the 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
[assembly:RuntimeCompatibility(WrapNonExceptionThrows=false)]
class MLinkTest {
public static void Main() {
try {
MCPP.Test();
}
catch (RuntimeWrappedException) {
System.Console.WriteLine("caught a wrapped exception in C#");
}
}
}
caught non System exception in C++ source code file