Hi all,
Below is how to compile C/C++ executables for Windows (both console or GUI) in a very stripped-down, no frills manner.. more or less like you would do with an assembler. In plain English, without the IDE, without including "Windows.H", without any standard C/C++ library.. but instead manually adding the libs to link with, and the extern "C" int TheWin32FunctionYouWantToUse(int,char*)-like statements for each function you need to import.

All you need is the linker, the compiler EXE (and the DLL's it requires to run), in the example that I'm providing it will be VisualC, and some more stuff.. which are:

1) The following batch file to produce both the .EXE and a .LST assembly output to look at:

CL.EXE /c /nologo /Ogtyb2 /Gs /G6 /Gz /Zp1 /FAs /Fa%1.LST /Fo%1.OBJ %1.CPP

Add /FI YourIncludeFile.HPP to the CL.EXE line above if you want a file to be always included by default.

In the LINK.EXE line instead:
Change /SUBSYSTEM:Console to /SUBSYSTEM:Windows if you want to produce a GUI type Win32 EXE, rather than a CUI one.
Change /LIBPATH:D:\MyLibs to the right path where your EXE libs (such as e.g. KERNEL32.LIB or DDRAW.LIB) are stored.
Add after USER32.LIB other libs you may want to use.
The /SECTION:*,RWE means that self-modifying code is allowed by default, for your hacking pleasure. :grin:

Your void MyEntry() C function gets called immediately.. there's no setup done anymore for you. Don't forget that you have a very naked C/C++ environment now.. so you must initialize the FPU and all.. just like if it was a lean and mean assembly program. No printf() & Co., unless you explicitly link it.

Now a test CPP file:

// --------------------------------------------------------------------------

extern "C" char* _stdcall GetCommandLineA();
extern "C" int _stdcall MessageBoxA(int,char*,char*,int);

// --------------------------------------------------------------------------

void MyEntry() {
MessageBoxA(0,GetCommandLineA(),"Command line is:",0);

// --------------------------------------------------------------------------

The purpose to use a very stripped-down but operative C/C++ compiler may be several.. one may be that all your work environment may fit into a floppy, rather than into the 900 MB of DevStudio. Another reason may be that you like simple things with no frills. :)

Using LoadLibrary() and GetProcAddress() rather than statically linking with DLL's will result in faster load times, thus a more responsive tool/application. If you really need the standard C library, link against MSVCRT.LIB, not LIBC.LIB.. expecially in NT systems this will mean improved performance.
Posted on 2002-11-20 15:36:11 by Maverick
Awesome! Thanks man :alright: :alright:

Add some error checking? I'm not 100% sure this is the correct way to do it for all machines ... works on mine though

CL.EXE /c /nologo /Ogtyb2 /Gs /G6 /Gz /Zp1 /FAs /Fa%1.LST /Fo%1.OBJ %1.CPP

IF errorlevel 1 GOTO errCompile


IF errorlevel 1 GOTO errLink
goto end

echo "Error(s) occured during compile"
GOTO end

echo "Error(s) occured during linking"
GOTO end

Posted on 2002-11-20 15:54:22 by gorshing
I use something similar too... with some variants.
I rather use #pragmas in a configuration header file to tell the linker against what libraries to link and things like that.
I don't have the VC IDE or package installed for weeks now since all the langages I use are integrated in only one IDE.
I've made compilers package separatly that can be installed by sfx rar and that set up environmental variables after the setup so the IDE know where to find them.

It may tremendously reduce the required hard drive space for VC++ and the memory required by the IDE...
The only thing I miss is the integrated debugger that is really cool.
Posted on 2002-11-20 16:30:06 by JCP
Hi gorshing :)
Great idea to add the error checking.. thank you. :alright:

Hi Readiosys :)
#pragmas are good too, but I'm not using them because they aren't really ANSI, and I won't use only VisualC to compile the sources (I'll use it only if the target is Win32).
The only thing I miss is the integrated debugger that is really cool.
Indeed.. let's wait for FAsm's one for now.. finally a great source debugger also for asm, on the x86. :)
Posted on 2002-11-20 17:30:12 by Maverick
Hi Mav' :)

As far as I know (I don't have my C99 ISO draft here to check), #pragma keyword is defined by C ANSI/ISO but its behavior is "implementation defined" :

Pragmas are used to introduce machine-dependent code in a controlled way. Obviously, pragmas should be treated as machine dependencies. Unfortunately, the syntax of ANSI pragmas makes it impossible to isolate them in machine-dependent headers.

and I won't use only VisualC to compile the sources (I'll use it only if the target is Win32).

Sure, but if I recall correctly, any #pragma that is unrecognized by the compiler has no effect. (VC #pragmas are ignored when I compile with GCC).
You can limit the range of action of this #pragma "section" to any compiler you use with something like #ifdef(_MSC_) or something like that.

In fact, there is three advantages that makes me use this method.
You can set up the compiler from the sources (a la FASM).
If you give your sources to a friend and/or coworker he will be able to get the same thing as you. Otherwise, you have to give him the whole commandline. Something that one can easily forget.
The IDE doesn't have to bother with much commandline arguments you have to customize each time if a single source doesn't need these commandline arguments.
Posted on 2002-11-21 01:11:17 by JCP
Salut Readiosys :)
I know that #pragma is a standard keyword :grin: .. and I even saw #pragma comment (the one you'd use for passing options to the linker) supported on most++ compilers.. on all those I use at least. But being these solutions compiler-specific (although it's often a unofficial standard), I prefer not to resort to them and, following the "keep it as simple as possible" philosophy that made me write this post (i.e. get rid of all the "not my code" that one can get rid of, including standard C libs), I prefer to control the linker separately, from a batch file.

Setting up the compiler from the sources is good++, but I've generally a bad feeling with C/C++ and their compilers, so for me it would only be a half-feature.. and anyway optimization settings aren't so "unofficially standard" like #pragma comment, so my sources would become a mess once I use #if's to see what compiler is in use. I prefer to keep as much as possible out of it. :)
Posted on 2002-11-21 02:48:27 by Maverick

CL.EXE /c /nologo /Ogtyb2 /Gs /G6 /Gz /Zp1 /FAs /Fa%1.LST /Fo%1.OBJ %1.CPP
/NODEFAULTLIB should be added to the Link.EXE line above.
Posted on 2002-11-21 04:20:20 by Maverick
I forgot to add that #pragma comment(link,"xxx") doesn't work when you link separately (i.e. AFAIK it works only if CL produces the final EXE, which is not desiderable when you want to link with other OBJ or LIB files).
Posted on 2002-11-21 06:21:40 by Maverick
Thank you Maverick!

Your idea is really very very brilliant! Very smart approach! :alright: :alright: :alright:


Posted on 2002-11-21 10:57:38 by Vortex

Add /OPT:NOWIN98 to the link.exe line.

You will see how you can drop the exe size.

Posted on 2002-11-21 12:16:47 by KSA
Thank you Vortex :)
..but "my" idea is nothing brilliant.. it's just something certainly made by many, many others here already ;)
..that I just thought could be useful to share here with some other fellows. The .LST part may also be very interesting. :)

The famous C -> ASM source converter. ;)

KSA: EXE size can already be reduced with MERGE:.text=. MERGE:.rdata=. MERGE:.data=. but I omitted them because they have some side effect, so they should be a personal choice instead. /FILEALIGN:512 is a cleaner way to express the /OPT:NOWIN98 flag, and works with older linkers as well.

By the way, does anybody know of the best way to locate (to call them) the static objects' constructors? This is something normally taken care by the C++ startup code, that we skip.
Posted on 2002-11-21 15:51:44 by Maverick
maverick, static object initialization == compiler specific. Have a look at http://www.wheaty.net/downloads.htm for libctiny, matt pietrek figured it out.

Also, I advice against manual LoadLibrary+GetProcAddress. It's errorprone and stuff. The /DELAYLOAD linker switch is much better if you're doing LL+GPA only for delayed loading and not eg plugin interfaces.
Posted on 2003-03-31 06:49:11 by f0dder

Tak for the link f0dder.

Ain't /DELAYLOAD uncompatible with OS's older than Win2000, or I recall wrong?
Not sure where/when, but I think I've read something like that.
Posted on 2003-03-31 07:10:49 by Maverick
I doubt it. As far as I can see, all it does is some stub action aroung LoadLibrary/GetProcAddress. But this happens transparently to you, so your applications is written normally - it becomes a link-time setting whether to do normal importing or delay-load, and it's less error-prone than manual importing.

Also, one interesting use would be things like toolhelp32 vs. psapi. You can link "statically" to both, and use the correct one with if/else sentence, and you wont get runtime "this DLL could not be loaded" errors. (Might still be better to use manual-load approach here, though).
Posted on 2003-03-31 07:14:54 by f0dder
I tried to merge sections:

link /SUBSYSTEM:WINDOWS /merge:.rdata=. /merge:.text=. /merge:.data=. /LIBPATH:c:\masm32\lib wnd.obj
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

LINK : warning LNK4078: multiple "." sections found with different attributes (60000020)
LINK : warning LNK4078: multiple "." sections found with different attributes (C0000040)

Is there any method to solve this attrib. problem?
What are the side effects of merging sections?


Posted on 2003-03-31 07:34:01 by Vortex
Vortex, it's only a warning, not a problem.

Side effects of merging sections... for most sections, there aren't any problems (just stay away from .rsrc). Making your code writable (which is a requirement for merging code+data) means you can't trap code overwriting bugs, but I guess normally this wont be much of a problem - you'd have to write some pretty fubar code to end up overwriting your code.

Another side effect is that, in a low memory situation, you might end up paging out maximally 4095 code bytes that wouldn't have been paged out if you hadn't merged sections, but I guess most people can live with that.

For "normal" (and "normally sized") applications, I would suggest keeping the sections separate, and stick with 4096 byte filealign. Keeping code readonly *can* trap a few bugs, and it is said somewhere that 4096-aligned sections perform a bit better wrt paging. For "normal size" applications, the gains from merging are minimal anyway.
Posted on 2003-03-31 07:57:38 by f0dder

Many thanks for the infos.:alright:


Posted on 2003-03-31 09:57:02 by Vortex
np. and again, be vary careful when messing with .rsrc. I would recommend strongly against merging with other sections, be careful if messing with flags, and you probably shouldn't even change the name (some libraries here and there depends on the string, rumor has it even some microsoft code in some versions of <whatever>).
Posted on 2003-03-31 10:00:28 by f0dder

Which are the libraries depending on the string name?


Posted on 2003-04-01 00:16:20 by Vortex
Hei f0dd,
do you know if/where Matt has released the full source of LIBCTINY? e.g. of the wvsprintf function that is missing.

Or do you know of another good LIBC complete with full source?

Posted on 2003-04-01 01:09:48 by Maverick