Build Settings
Recode works directly with the MSVC compiler to generate code for Recode patching. This requires that your build system is correctly configured for Recode and generates the correct compiler and linker options for Recoding.
VC Toolsets
Recode requires access to a full VC toolset for compilation and linking. The VC toolset can either be installed with Visual Studio, or it may be located in a custom folder relative to the codebase you are building.
Local VC Toolsets
If you use a local VC toolset directory with Recode then you need to make sure it conforms to this basic layout:
- /bin
One dir per architecture as needed (or same as standard VC installation)
- /include
Same layout as standard VC installation
- /lib
Same layout as standard VC installation
Important
It is highly recommended that your installed version of Visual Studio’s Visual C++ is the same or higher than the version of any local toolset directory. Or in other words: Keep your Visual Studio installation up-to-date.
Compiler Settings
Recommended compiler option for Recode builds (best results with this set):
Hotpatch (
/hotpatch
) for 32-bit only
Incompatible compiler options for Recode builds (ensure these are disabled):
Static Run-Time Library (
/MT
or/MTd
)
If /GL
present when Recoding the following error is emitted:
recode error: cl.exe /GL cannot be used for Recode builds. Ensure Whole Program Optimization is disabled.
Compilation for Recode requires use of the DLL based runtime library using /MD
or /MDd
.
The static version of the library (specified via /MT
or /MTd
) can’t be supported as it would result in
duplicated runtime library state and could lead to heap conflicts and worse.
If you attempt to compile for Recode with /MT
or /MTd
you will see the following error:
recode error: /MD or /MDd required for Recode compilation. /MT or /MTd are unsupported.
Managed (C++/CLI) binaries (compiled with /clr
) are not supported by Recode.
Exception Settings For Recode Protect
Recode Protect requires the compiler to be configured to disable exception handling or to explicitly support structured exceptions. Exception handling settings are not overridden automatically by Recode as it could unexpectedly alter program behavior if you rely on exception handling.
Required exception handling compiler options for compatibility with Recode Protect:
- No exception handling (no
/EH*
options are set) The default option used by most high-performance code.
Catch blocks will catch both structured exceptions and C++ exceptions.
No stack unwind will occur and any objects in scope will not be destructed.
- No exception handling (no
- Structured and C++ exception handling (
/EHa
or/EHac
) The slowest option for performance, particularity on x86.
Catch blocks catch both structured exceptions and C++ exceptions.
Only C++ exceptions will unwind the stack and call destructors.
- Structured and C++ exception handling (
Incompatible exception handling compiler options that will disable Recode Protect:
- C++ exception handling only (
/EHs
or/EHsc
) Slow performance, particularity on x86.
Catch only standard C++ exceptions.
C++ exceptions will unwind the stack and call destructors.
- C++ exception handling only (
Linker Settings
Required linker option for Recode builds (ensure this is set):
Debug Information (
/DEBUG
)
Recommended linker option for Recode builds (best results with this set):
Incremental Linking (
/INCREMENTAL
)Create Hot Patchable Image (
/FUNCTIONPADMIN:14
)
Incompatible linker options for Recode builds (ensure these are disabled):
Reference Optimization (
/OPT:REF
)COMDAT Folding (
/OPT:ICF
)Link-Time Code Generation (
/LTCG
)
Warning
Any obj files compiled with /GL
prevent incremental linking causing Recode to fail when patching.
Third-party lib files may also cause this problem if they contain obj files compiled with /GL
.
See Whole Program Optimization for more details.
FastLink
Since VS2015 the Microsoft linker has included the /DEBUG:FASTLINK
option to reduce link times by
skipping debug type merging during the link. This does improve link times but will cause slower debugging performance and
significantly longer Recode times since the missing debug information must be generated before Recoding.
Tip
Prefer using lld-link.exe before resorting to /DEBUG:FASTLINK
usage as it will avoid the Recode and debugging
performance issues.
Hotpatching
If a module is not linked with /INCREMENTAL
or something prevents incremental linking (see below)
then Recode will attempt to use the hotpatching technique to inject code changes.
Tip
If incremental linking is disabled, use /hotpatch
and /FUNCTIONPADMIN:16
for reliable Recoding.
While hotpatching works well most of the time there are a few side-effects to consider. When stepping into Recoded files from unmodified code you may receive the following warning:

This is a result of the debugger having to jump through the old function to get to the new function. Since the changed code file only matches the new version of the function, Visual Studio warns about the unmatched source code. This is a side-effect of the trampoline jump that Recode inserts to move to the new function. Stepping in a second time will enter the new code from the modified file:
Unmodified.cpp
Main()
Steps into…
Foo.cpp
MyFunc()
[old version - source no longer matches]
Steps into…
Foo.cpp
MyFunc()
[new version - matches modified source]
Visual Studio will remember you choice, so if you step into a modified file a second time you shouldn’t see the warning dialog again.
If incremental linking is disabled, enable VC++ hotpatching to help ensure Recode has enough space available
in small functions to be able to redirect them properly.
To enable VC++ hotpatching for Recode, set the /hotpatch
compiler option (32-bit only) and
the /FUNCTIONPADMIN:16
linker option (32-bit & 64-bit).
Note
/FUNCTIONPADMIN:16
adds padding between functions for hotpatching. This will increase the size of your
modules although it should have little impact on performance. Disable it for final production builds.
Incremental Linking
Using Incremental Linking (/INCREMENTAL
)
will provide an improved debugging experience since stepping into functions will be seamless.
Tip
Use incremental linking (if possible) to ensure reliable Recoding and avoid debugging issues.
Lib Project Dependencies
Until VS2015, the Microsoft linker did not support incremental linking for any code linked from within a lib. For a smoother debugging experience incremental linking is recommended, so if you’re using VS2012/VS2013, you should try to ensure that that any user code normally stored in a lib file is directly linked to the executable and DLL projects.
In MSBuild this is achieved by enabling both of these options on the executable and DLL projects:
Warning
Care must be taken to ensure any libs produced by projects within the solution are not passed to the
linker on the command-line (via Additional Dependencies
in the project settings). If they are you may
see error recode : conflicting global variable
due to variables from the old lib conflicting with new
stubs generated by Recode.
Tip
Even without Recode enabled, if you are frequently modifying code within a lib it is best to enable
Use Library Dependency Inputs
to keep your link times as short as possible.
These options require that any lib projects be added as a Project References on any exe and DLL projects that use them. For example, here the BasicLib project has been added as a Project Reference for the BasicTests project:

Important
Visual Studio’s Project -> Project Dependencies
dialog cannot be used to setup Project References to lib
projects - it is merely use to determine build order for projects built within Visual Studio.
Ensure you setup Project References via the References
heading under the Project Properties dialog.
Whole Program Optimization
Any lib/obj files that were compiled with
Whole Program Optimization (/GL
)
enabled will cause linking to restart with
Link-Time Code Generation
(/LTCG
) enabled with the message:
foo.lib(bar.obj) : MSIL .netmodule or module compiled with /GL found; restarting link with /LTCG; add /LTCG to the link command line to improve linker performance
LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/LTCG' specification
In this case please ensure /INCREMENTAL, /OPT:NOREF and /OPT:NOICF are set for the linker. Also remember that external libs may implicitly disable /INCREMENTAL - check linker logs for LNK4075.
As lib files supplied by third parties may contain obj files built with /GL this problem can be hard to diagnose until Recode patching fails. The best approach is to check the linker logs for each project to ensure LNK4074 doesn’t occur.
Tip
Enable linker.exe Treat Warnings As Errors
(/WX
) to help identify LNK4075 more easily.
Module Base Address Requirements
The address that a module (exe or DLL) is loaded at can be important for successful Recoding. Recode has to find space to inject patches somewhere ±2GB from the original module base address. If Recode cannot find enough contiguous free space in the 4GB region around the base module to accommodate the patched code it will fail with:
Failed to find an unreserved memory region for patching c:\path\to\module.exe load address: 0x0 VA dump:
[... dump of address space around module ...]
This can occur due to one or more factors reducing the available virtual address space:
Module loaded too close to the start of the address space (0x0) reducing the search window.
Modules and allocations clustered together due to ASLR and default OS allocation strategy.
Mapping large files to memory will often consume large amounts of address space.
Windows has a tendency of clustering loaded modules towards the bottom of the address space. This is especially true of modules
that fail to load at their preferred base addresses (this can be seen by checking in the Visual Studio Modules
window during a debug session).
This will also occur if
Address Space Layout Randomization (/DYNAMICBASE) is enabled
(which it is by default). For Recode it can make finding suitable address space hard, especially for a multi-module game engine
with a very busy address space.
Since 64-bit processes have
vast amounts of usable virtual address space,
the easiest workaround is to force the module to load at a higher base address. You can try setting an explicit base address
via the linker option /BASE
(and also make sure you set /DYNAMICBASE:NO
). Something like /BASE:0x400000000
will usually
shift the module somewhere less crowded in the address space.
Finally, check to see if the base modules are actually being loaded at their assigned base addresses in the Modules debug window -
there will be a x
symbol next to the module icon and a *
to the right of the address range for any module that failed to load
at the assigned base address.
LLD-Link Compatibility
The LLVM project’s LLD linker (lld-link.exe) is supported by Recode as a drop-in replacement for Microsoft’s link.exe.
LLD generally offers faster linking than Microsoft’s linker (even if the problematic /DEBUG:FASTLINK
is used).
Unity Splitting
Recode will attempt to optimize compilation for unity files when it detects them. These #include
multiple C/C++ source files into a single unified
file that can then be compiled in a single compiler invocation. This technique reduces overall compilation time by reducing
preprocessing and IO overhead by sharing the overhead between formally separate files. They also allows the compiler to inline
more and reduce the load on the linker (and thus link times).
The downside to unity files is they increase compilation times for small changes and often lead to implicit dependencies appearing between files. As Recode has to analyse and compile the entire compiland, naively compiling the original unity file can lead to much longer Recode times. Recode supports splitting unity files to help reduce this overhead.