Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiling code in Visual Studio that does not require .net to be installed C++

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";
}
like image 868
user99545 Avatar asked Dec 22 '22 05:12

user99545


2 Answers

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:

  • Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)
  • Microsoft Visual C++ 2010 SP1 Redistributable Package (x64)

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.

like image 87
In silico Avatar answered Dec 24 '22 01:12

In silico


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:

  1. Download and install the Windows Driver Kit.

  2. 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-)

  3. Rebuild.

  4. ...

  5. Profit.*

* Duck and cover as people yell at you for using the WDK to build applications. :P


Note:

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.

like image 25
user541686 Avatar answered Dec 24 '22 03:12

user541686