0

I want to code a c++ win32 application without msvc dll dependency using Visual Studio.

I tried the /NODEFAULTLIB option but after that I get an unresolved external error, even with a "empty" program, because of no library. How can I correct this? What libraries do I have to link?

Here is a simple code i tried to compile with /NODEFAULTLIB option and failed.

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {

}
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
kenarsuleyman
  • 920
  • 1
  • 6
  • 26
  • You probably created the wrong project type in your IDE. What project type did you create? –  Jan 28 '17 at 19:44
  • @NeilButterworth I created Win32/Empty Win32 Project under c++ tab. – kenarsuleyman Jan 28 '17 at 19:46
  • @RawN It's not only about disk size today everyone has at least a few terabytes but why i'm unable to do this? – kenarsuleyman Jan 28 '17 at 19:47
  • 2
    Doing this is just setting yourself up for a really bad time. The compiler generates code and data which the CRT acts on. This includes initializing and destroying global objects, handling exceptions, etc. All of those unresolved linker errors are part of the functionality you will need to supply yourself or in another library. You'll have a bad time doing both since most of the internals you are seeking to replace are undocumented. – Captain Obvlious Jan 28 '17 at 19:48
  • @Captain Win32 applications which can be written in C don't necessarily use exceptions. –  Jan 28 '17 at 19:49
  • @CaptainObvlious There is an option in Visual Studio called "Ignore Specific Default Libraries" which library i need to ignore for get rid of msvc dependency? – kenarsuleyman Jan 28 '17 at 19:50
  • @NeilButterworth Post is tagged C++ so what's your point? – Captain Obvlious Jan 28 '17 at 19:51
  • @Süleyman Kenar Why an empty project? It's worth creating an ordinary Win32 project,which won't use MFC, and then subtracting from it. –  Jan 28 '17 at 19:55
  • @Captain Win32 C++ programs don't need to use exceptions either. Your original comment is simply wrong. The base program generated by VC++ for a Win32 program has _no_ exception handling in it. –  Jan 28 '17 at 19:57
  • first of all your entry point must be `void somefunc()` and set this in linker options `/ENTRY:somefunc` and libs - depended from what api you using, for example `kernel32.lib` – RbMm Jan 28 '17 at 19:57
  • @RustyX - we can develop this easy, if have enough knowledge – RbMm Jan 28 '17 at 20:02
  • @RbMm I'm sure that we can. If you know any knowledge about it can you share? – kenarsuleyman Jan 28 '17 at 20:05
  • As @RbMm notes if you want to do without the runtime library entirely, then you need to have a valid entry point. The signature is AFAIK undocumented but `void foo()` will do. You need to link with `kernel.dll`, in Visual C++ that's done via `kernel32.lib`, in order to get `ExitProcess`, which you must call unless this process should run foreever. That's about it. Due to the page size, equals segment granularity, the smallest formally correct executable you can make is about 4KB. You can rely "it works", but it will still be about 2K, IIRC. In Unix-land you can get down to a few hundred bytes. – Cheers and hth. - Alf Jan 28 '17 at 20:12
  • 1
    @SüleymanKenar - yes, i have knowledge and huge experience in this. but for what is this for you ? begin from your program entry point `WinMain` - who must call it ?! if you not want use `CRT` - you entry must be `void somefunc()` and need set `somefunc` as exe entry point. then many depended from your c++ compiler options(say runtime checks, etc) and what feature you use in code. are you ready use `ntdllp.lib` as runtime (say exception handlers) ?you need have enough knowledge and reason for do this – RbMm Jan 28 '17 at 20:12
  • There's some discussion of the entry point signature [here](http://stackoverflow.com/q/34937953/886887). The short version is that the details don't matter much in this context, so long as you don't take any parameters you should be fine. There are other complications; you have to change a few project settings from the default, and none of your functions can have more than one page's worth of local variables. Also see [this](http://stackoverflow.com/questions/30659232/why-do-my-crt-free-applications-intermittently-crash-on-startup). – Harry Johnston Jan 28 '17 at 20:48
  • @NeilButterworth: Win32 applications written in C **do** use exceptions, e.g. `void main() { *(int*)0=42; }` certainly does raise an exception. Part of that exception handling is implemented in the CRT. Now if you look into the CRT implementation that ships with VC (and now with Windows), you will see that even an empty program has a `__try`/`__except` filter around the user-provided entry points (`main` and `WinMain`). – IInspectable Jan 28 '17 at 21:10
  • @HarryJohnston - `and none of your functions can have more than one page's worth of local variables` only if we not link with `ntdllp.lib` or any lib containing `__chkstk` and `_alloca_probe_16`, etc.. implementation – RbMm Jan 28 '17 at 21:25

1 Answers1

2
#undef UNICODE
#define UNICODE
#include <windows.h>

void startup()
{
    MessageBox( 0, L"Click the OK button, please.", L"Hi!", MB_SETFOREGROUND );
    ExitProcess( 0 );
}
[C:\my\forums\so\279]
> cl minimal.cpp /link /nodefaultlib /entry:startup /subsystem:console kernel32.lib user32.lib
minimal.cpp

[C:\my\forums\so\279]
> dir
 Volume in drive C is OS
 Volume Serial Number is 58BC-07CA

 Directory of C:\my\forums\so\279

28.01.2017  21:43    <DIR>          .
28.01.2017  21:43    <DIR>          ..
28.01.2017  21:43               215 minimal.cpp
28.01.2017  21:43             2 560 minimal.exe
28.01.2017  21:43               860 minimal.obj
               3 File(s)          3 635 bytes
               2 Dir(s)  274 278 531 072 bytes free

[C:\my\forums\so\279]
> _

cl is the Visual C++ compiler. My default options (via the CL environment variable) are /nologo /EHsc /GR /W4 /FI "iso646.h", but I believe only the exception handling option affects anything here, if it all. The user32.lib library is linked because I used the MessageBox function.


Do note that the runtime library takes care of parts of the C++ core language infra-structure. That includes dynamic initialization of namespace scope variables, and depending on the compiler it might include some of the support for exceptions. I don't know the details about Visual C++ in this regard, but it's necessary to be very, very careful: one is operating in a regime where the basic assumptions of the tools, don't hold.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • You may also need `/DYNAMICBASE:NO` and `/FIXED:YES` to make small programs work reliably, though I think that problem [only affects 64-bit applications](http://stackoverflow.com/questions/30659232/why-do-my-crt-free-applications-intermittently-crash-on-startup). Another proviso is that none of your functions can have more than one page's worth of local variables. – Harry Johnston Jan 28 '17 at 20:49
  • @HarryJohnston: I'm not sure I agree with your two first point. The last one about page size having anything to do with the allocation of local variables, is news to me. Do you have a reference? – Cheers and hth. - Alf Jan 28 '17 at 20:54
  • No reference. I just know that if you use too much stack space on local variables the build fails, with a missing function named something along the lines of __chkstk IIRC? (It is just an educated guess that the limit is one page, but I think a good one; the reason for the missing function has to do with the way the virtual memory allocated for the stack is handled, and virtual memory is allocated in pages.) As for the need to disable relocation for very small executables, that's another practical observation, though it's conceivable that Microsoft have fixed the bug in question. – Harry Johnston Jan 28 '17 at 20:59
  • Thanks! It is indeed dire straits this. Care needed. – Cheers and hth. - Alf Jan 28 '17 at 21:00
  • I've always wished the Visual Studio team would turn this into a supported scenario, taking care of all these little sharp edges, but I fear that's a pipe dream. :-) – Harry Johnston Jan 28 '17 at 21:01
  • With Visual Studio, stack unwinding for exception handling is implemented in the CRT (at least for x86, not sure about x64). @HarryJohnston: This used to be desirable. With the Universal CRT being part of the OS there is no longer a valid reason to avoid it. It's no more of a dependency than kernel32.dll or ntdll.dll. – IInspectable Jan 28 '17 at 21:17
  • @IInspectable: has the UCRT been backported into Windows Vista and Windows 7? I know it's available, but I thought it still had to be explicitly installed. (In practice, I personally would still have to be very cautious about depending on it unless MS released a new service pack for Windows 7 that included it, and that's not going to happen. On the other hand, that'll be moot in three years time.) ... oh, and plus, I'd have to talk my boss into paying to upgrade Visual Studio. :-) – Harry Johnston Jan 28 '17 at 21:22
  • @HarryJohnston: The UCRT is [available as a download for Vista SP2 and Windows 7 SP1](https://www.microsoft.com/en-us/download/details.aspx?id=48234). You cannot rely on it until Windows 10 (I think). Now that I read my previous comment again, it didn't quite convey what I was trying to say: The CRT will no longer be a dependency you have to ship alongside your application when targeting Windows 10 and above. In those cases there is no longer a real reason to avoid the CRT, and given this, I doubt the compiler team will consider making that a supported scenario. – IInspectable Jan 28 '17 at 21:30
  • for `__chkstk` and related stack allocation we can use `ntdllp.lib` or link with `chkstk.obj`+`alloca16.obj` (from `VC`) c exception handling full implemented and exported from `ntdll.dll` - so quit possible build application (any complex, not simply demo) without crt and without need installing something - all begin from xp how minimum – RbMm Jan 28 '17 at 21:33
  • @IInspectable: agreed, but I doubt they'd have considered it anyway. – Harry Johnston Jan 28 '17 at 21:37
  • @HarryJohnston - and about relocation - why you think that need disable it ? really no any problems with relocs at all – RbMm Jan 28 '17 at 21:39
  • @RbMm: theoretically, there shouldn't be a problem, but in practice, there is, or at least was. As far as I could tell, this was caused by a bug in the module loader. Unfortunately it only happens on rare occasions, I never found a reliable way to reproduce it on demand. Some technical details [here](http://stackoverflow.com/questions/30659232/why-do-my-crt-free-applications-intermittently-crash-on-startup). – Harry Johnston Jan 28 '17 at 21:44
  • @HarryJohnston - i think (almost sure) this problem is related to `Superfetch` service when it worked, and when you *rebuild* same app with same name in system. what you describe - invalid file mapping in memory (this not only not related to `CRT` but even to any usermode code) look like system partially use pages from old exe and partially from new, rebuild-ed. i be say this is only developer-s problem (who rebuild apps in runtime) – RbMm Jan 28 '17 at 21:58
  • look like i also have something like this problems may be 10 years ago. after this i disable `Superfetch` and after this - never happened this errors – RbMm Jan 28 '17 at 22:02
  • 1
    There are other invisible dependencies on the runtime libraries. E.g., helper functions for multiword arithmetic, GS checks, purecall stubs, RTTI, exceptions, try/catch, __try/__except, magic statics, atexit, _initterm... – Raymond Chen Jan 28 '17 at 22:04
  • @RaymondChen - in general yes, and all this can be solved, and not so hard how can look like at first – RbMm Jan 28 '17 at 22:26
  • 1
    @IInspectable - RTTI - i not use at all, this is not mandatory. `magic statics` - you mean `_Init_thread_header`, `_Init_thread_footer` functions and `_Init_thread_epoch` var ? i implement it yourself when need – RbMm Jan 28 '17 at 22:38
  • If you are willing to implement all the missing things, then more power to you. – Raymond Chen Jan 29 '17 at 02:02
  • @RbMm: no, I don't think so. The problem didn't occur on the build system, it occurred on other machines at random. Might still be Superfetch related, except that doesn't explain why the problem went away when I disabled relocation. I'm still inclined to blame ASLR. – Harry Johnston Jan 29 '17 at 10:07
  • @HarryJohnston - but ASLR absolute not related to use or not use `CRT` hard say exactly without stable catch error. but permanent build and run own apps, all it without any `CRT` and not disable ASLR on it. and never this kind of errors. but many years ago, on win7 may be I also catch something look like you describe.. already forget exactly details – RbMm Jan 29 '17 at 11:03
  • @RbMm: the problem only occurred for 64-bit executables less than 4096 bytes in size, so an unusual combination, and yes this was on Windows 7. I suspect that it wasn't anything to do with the CRT as such, but perhaps linking with the CRT changed the memory layout enough that the problem no longer exhibited? Or perhaps executables linked with the CRT are just less likely to be that small? (Your observation the other week that the CRT entry point is always statically linked into the executable might be relevant there.) – Harry Johnston Jan 29 '17 at 11:19
  • ... I almost always statically link the CRT anyway, so in my case using the CRT meant a *big* executable, which I guess means I wouldn't have noticed if a very small dynamically-linked application had the same problem. @RbMm – Harry Johnston Jan 29 '17 at 11:21
  • hard to say, my executable was usually not too big, but almost always > 4096. however possible build without `CRT` not only small demos, but complex, large UI application with almost all features. `__try/__except` support implemented in `ntdll`, [`initterm`](https://msdn.microsoft.com/en-us/library/bb918180.aspx) and `atexit` need [implement](https://msdn.microsoft.com/en-us/library/partnercenter/7977wcck(v=vs.80)) yourself, but this small. as and `__security_check_cookie`, `purecall` must not be - simply need declare class with pure virtuals with `__declspec(novtable)`, and so on.. – RbMm Jan 29 '17 at 11:46
  • @RbMm: Your proposed solution to using RTTI without the CRT is to not use RTTI. Doesn't sound like much of a solution to me. – IInspectable Jan 30 '17 at 08:57
  • @IInspectable: I would find it difficult to emulate `dynamic_cast` in its full generality, but mostly I just use it to check whether an object implements a given interface, or, given an interface, whether it is of a given most derived class. And this functionality was implemented in a great many different ways before the standardization of C++ (I'm not sure if `dynamic_cast` was in the ARM, I think not). For example, MFC used a macro-based scheme for this. I think that dynamic downcast, plus an is-a function, which also is easy to make, serves 99.9999...% of RTTI needs. At least for me. :) – Cheers and hth. - Alf Jan 30 '17 at 09:32
  • @IInspectable - i not view big sense use `dynamic_cast` in own code and not use it. so even not try implement and disable rtti info generated in options. – RbMm Jan 30 '17 at 09:43
  • @Cheersandhth.-Alf: MFC's homegrown dynamic cast relies on global state. Participating classes must register a `CRuntimeClass` object in a global registry. To implement this, you'll have to implement initializers for objects with static storage duration. Not impossible, but it is harder than it looks at first. Besides, I was commenting on *"the solution to using RTTI without the CRT is to not use RTTI"*, which totally isn't a solution. – IInspectable Jan 30 '17 at 09:44