I am trying to compile an application in C++ that works without the .net framework or visual studio run times having to be installed. I have done some research and found this article from MSDN showing how to compile native C++ code. However when I followed this example, after running the generated executable on a computer without the visual studio run times, I get an error MSVCP100D.dll
is missing from your computer. I know that it is possible to fix a similar error with GCC by typing -static-libgcc -static-libstdc++
to generate a static binary. Is it possible to do this using Visual Studio 2010? The reason I wish to do this is that I enjoy working with Visual Studio IDE, but I would like my code to be portable to other OS's like UNIX. Thank you!
Note: I thought it might be helpful to post the code I am compiling for testing purposes.
#include <iostream>
int main()
{
std::cout << "Hello world";
}
MSVCP100D.dll
is the debug version of MSVCP100.dll
. They are the dynamic link libraries that implements the C run-time libraries. This is needed to implement the C++ standard libraries in Visual C++ 2010.
The compiler links against MSVCP100D.dll
in debug mode. There should be a MSVCP100D.dll
on your development machine when you installed the compilers that came with Visual Studio 2010. If this isn't so then something went wrong with the installation.
The compiler links against MSVCP100.dll
in release mode. If you plan to deploy your application, you need to compile in release mode and distribute the release versions of the binary. Do not distribute the debug versions of the binary.
If even after doing that you still get errors, you may need to install the Visual C++ 2010 runtimes.
The installers are available to download:
If you rather not link against the dynamic library, you can statically link the C run-time libraries into your application by specifying the /MT
compiler switch as described here.
Note that static linking will increase the size of the application binary, and if the C run-time libraries are updated (e.g. security/performance improvements) the application will not use them unless you recompile the application.
I highly recommend that you install the redistributable package anyway since lots of other applications you may use might need the libraries.
If you feel like hacking around and want to get the best of both worlds (i.e. a small executable and the C runtime) in release mode only:
Download and install the Windows Driver Kit.
In your project Properties, select Release and:
Add the following to C/C++ -> General -> Include Directories:
C:\WinDDK\7600.16385.1\inc\crt
C:\WinDDK\7600.16385.1\inc\api
C:\WinDDK\7600.16385.1\inc\atl71
C:\WinDDK\7600.16385.1\inc\mfc42
Set C/C++ -> Code Generation -> Runtime Library to Multi-threaded DLL (/MD)
.
Add the following to Linker -> General -> Additional Library Directories (choose the architecture/version as appropriate):
C:\WinDDK\7600.16385.1\lib\Crt\i386
C:\WinDDK\7600.16385.1\lib\wxp\i386
(use wnet
instead of wxp
for 64-bit)C:\WinDDK\7600.16385.1\lib\ATL\i386
C:\WinDDK\7600.16385.1\lib\Mfc\i386
Add BufferOverflowU.lib
and msvcrt_winxp.obj
under Linker -> Input -> Additional Dependencies.
You might need to disable buffer overflow checking (/GS-
)
Rebuild.
...
Profit.*
* Duck and cover as people yell at you for using the WDK to build applications. :P
If you use C++ exception handling, you will run into trouble.
You will get an unresolved reference to __CxxFrameHandler3
, because msvcrt
only exports __CxxFrameHandler
, which uses a different version of the frame handlers than VS 2008.
It turns out Microsoft already has a hack for this in the WDK (msvcrt_winxp.obj
), but it's a little bloated, so I just ("just") made a trimmed-down version instead (it took days).
Long story short, you can fix it by including this assembly file in your project (make sure to define _WIN64
for 64-bit -- the custom build step below does this for you):
; Custom build step (use for x64 only):
; ml64.exe /Fo"$(IntDir)\$(InputName).obj" /D_WIN64 /c /nologo /W3 /Zi /Ta "$(InputPath)"
; Custom build output: $(IntDir)\$(InputName).obj
;
; Relevant links:
; http://kobyk.wordpress.com/2007/07/20/dynamically-linking-with-msvcrtdll-using-visual-c-2005/
; http://www.openrce.org/articles/full_view/21
; http://blogs.msdn.com/b/freik/archive/2006/01/04/509372.aspx
ifndef _WIN64
.386
.model flat, c
endif
option dotname
extern __CxxFrameHandler: PROC
ifdef _WIN64
extern __imp___CxxFrameHandler: PROC
extern __imp_VirtualProtect: PROC
extern __imp_Sleep: PROC
extern __imp_GetVersion: PROC
endif
.data
ifdef _WIN64
;ProtectFlag EQU ?ProtectFlag@?1??__CxxFrameHandler3@@9@9
ProtectFlag dd ?
endif
ifdef _WIN64
endif
.code
ifdef _WIN64
includelib kernel32.lib
endif
includelib msvcrt.lib
public __CxxFrameHandler3
ifdef _WIN64
__CxxFrameHandler3 proc frame
else
__CxxFrameHandler3 proc
endif
ifndef _WIN64
push ebp
mov ebp,esp
sub esp,28h
push ebx
push esi
push edi
cld
mov dword ptr [ebp-4],eax
mov esi,dword ptr [ebp-4]
push 9
pop ecx
lea edi,[ebp-28h]
rep movs dword ptr es:[edi],dword ptr [esi]
mov eax,dword ptr [ebp-28h]
and eax,0F9930520h
or eax,019930520h
mov dword ptr [ebp-28h],eax
lea eax,[ebp-28h]
mov dword ptr [ebp-4],eax
push dword ptr [ebp+14h]
push dword ptr [ebp+10h]
push dword ptr [ebp+0Ch]
push dword ptr [ebp+8]
mov eax,dword ptr [ebp-4]
call __CxxFrameHandler
add esp,10h
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
else
mov rax,rsp
mov qword ptr [rax+8],rbx
.savereg rbx, 50h
mov qword ptr [rax+10h],rbp
.savereg rbp, 58h
mov qword ptr [rax+18h],rsi
.savereg rsi, 60h
push rdi
.pushreg rdi
push r12
.pushreg r12
push r13
.pushreg r13
sub rsp,30h
.allocstack 30h
.endprolog
mov dword ptr [rax+20h],40h
mov rax,qword ptr [r9+38h]
mov rdi,r9
mov ebx,dword ptr [rax]
mov rsi,r8
mov rbp,rdx
add rbx,qword ptr [r9+8]
mov r12,rcx
mov eax,dword ptr [rbx]
and eax,1FFFFFFFh
cmp eax,19930520h
je L140001261
mov r13d,1
mov eax,r13d
lock xadd dword ptr [ProtectFlag],eax
add eax,r13d
cmp eax,r13d
je L140001217
L1400011F0:
lock add dword ptr [ProtectFlag],0FFFFFFFFh
mov ecx,0Ah
call qword ptr [__imp_Sleep]
mov r11d,r13d
lock xadd dword ptr [ProtectFlag],r11d
add r11d,r13d
cmp r11d,r13d
jne L1400011F0
L140001217:
mov r8d,dword ptr [rsp+68h]
mov r13d,4
lea r9,[rsp+20h]
mov rdx,r13
mov rcx,rbx
call qword ptr [__imp_VirtualProtect]
test eax,eax
je L140001259
and dword ptr [rbx],0F9930520h
or dword ptr [rbx],19930520h
mov r8d,dword ptr [rsp+20h]
lea r9,[rsp+68h]
mov rdx,r13
mov rcx,rbx
call qword ptr [__imp_VirtualProtect]
L140001259:
lock add dword ptr [ProtectFlag],0FFFFFFFFh
L140001261:
mov r9,rdi
mov r8,rsi
mov rdx,rbp
mov rcx,r12
call qword ptr [__imp___CxxFrameHandler]
mov rbx,qword ptr [rsp+50h]
mov rbp,qword ptr [rsp+58h]
mov rsi,qword ptr [rsp+60h]
add rsp,30h
pop r13
pop r12
pop rdi
ret
endif
__CxxFrameHandler3 endp
end
(Note: You can't implement this in C or C++, because the calling convention is different from the ones that C/C++ uses -- it seems to be an undocumented format that assumes registers are set a certain way.)
If you get unresolved references to _chkstk
or _alloca
or whatever, just find a version of alloca16.asm
in your CRT (should be in Visual Studio's CRT) and use that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With