• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

Exe Size Comparisons With Different Compilers

Started by Frederick J. Harris, September 11, 2009, 04:57:47 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Frederick J. Harris

About a year ago I downloaded, installed, and started using and experimenting with the new GNU CodeBlocks C++ application suite.  I was really surprised to find that by setting various compiler optimazition switches I could create smaller executables than I could with PowerBASIC Windows compilers.  This is something I always noted with various compilers I used.  The Dev-Cpp compier suite is another popular C / C++ development environment written mostly by Colin Laplace.  It uses the GNU compiler too.  Its executables were always way larger than PowerBASIC's.  Microsoft Visual C++ 6 also produced files considerably larger than PowerBASIC's.

Here about a month ago I finally broke down and bought myself Visual Studio 2008 Pro; mostly because I need it to do the Windows CE programming which occupies about half my time.  I'll tell 'ya, the exes are really small.  I have a neat little ODBC demo I put together the past couple weeks and I coded a C++ version and a PowerBASIC version and the VC9 (Visual Studio 2008 Pro) comes in around 36K and I think the PB one is in the mid to high 40s.  CodeBlocks is in around there too.  Dev-C++ is way up around a 100K.

I'm just surprised about it, thats all.  I'm wondering if anyone knows why?  What I think the issue is, but I'm not sure, is that these newer C++ compilers dropped support for non NT operating systems, that is, their exes don't support Win 95-98 anymore.  And I also seem to remember reading something about the msvcrt (Microsoft Visual C++ Runtime Library) being considered a part of the operating system now, whereas it wasn't with Win 95-98, etc.  So I'm guessing the PowerBASIC compilers are adding content to the exes that VC9 and CodeBlocks aren't?  Any thoughts?


Patrice Terrier

Frederick,

C and C++ have always been able to produce smaller EXE files than PB.

However did you use DDT or plain SDK?

Older version of the compiler will also produce smaller EXE files.

...

Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Frederick J. Harris

Makes me look dumb!  I think you're right Patrice.  I just looked at it real close, checked all the compiler optimazations on my various C++ compilers, and they are all (I didn't check Dev-Cpp) coming in a good bit smaller than the PowerBASIC 9 compiler.

The program is around 1500 lines of PB code that I wrote, and about 2500 for the C++ app.  The reason the C++ app has so many more lines (its virtually an exact line by line translation) is that I did my best to follow C++ file organization standards with a header file containing prototypes, etc., for every source code file, and so on.  Also, since they are both Sdk style programs (I'd have a real hard time writing a Hello, World! in DDT) I included my home made String class in the C++ program so I could have easier string handling.  I think that added four or five hundred lines.  Of course, with PB the string handling is part of the compiler and we get it for free, so to speak.

Anyway, VC6 is now giving me around 32K, VC9 about 33K, CodeBlocks 46k, and PowerBASIC around 63K.  Now I'm wondering how I ever came up with the conclusions I voiced in my first post.  Probably I wasn't checking that I had optimazitions turned on for smaller size, and of course there are several gradations there.

In any case, its a neat little program.  I wanted to do something to get myself acclamated to the new Visual Studio 2008 I just bought, and so I picked doing an ODBC demo.  I'll probably post it soon, both the C++ and PowerBASIC version.  It has a main form with four buttons.  The top button scours the registry for ODBC drivers and dumps them and their attributes to a little scrollable output screen.

The second button uses the MS Jet ODBC Driver to dump an Excel spreadsheet to an instance of the output screen.     

The 3rd button creates an Access Database, a table within the database, inserts a few records, then dumps the records to another instance of the output screen.

The fourth button does the same with Sql Server Express or MSDE.

The output screens all handle their own memory allocations/deallocations and so you can keep clicking buttons to your hearts content filling up your screen with output windows.  When you click a button the 2nd, 3rd time, etc, records are just added to the database you already created on your first click.  Also, the program uses threads in the database processing routines.

Actually, even though I've played around quite a bit with PowerBASIC's new class capabilities, this is the first time I've really created something with it that I'll actually be able to use in my 'production' programs.  I've been kind of slow to adapt.  Guess I'm mostly a procedural coder.  My wrapper class for the ODBC functionality turned out really neat though.  I enjoyed doing it and seeing it work.

Edwin Knoppert

I just wrote me an empty app and it was 6kb.
I know that when you add certain functionality like CURDIR$ it will add 2kb.
It comes in 'run-time' blocks.
Dialog new makes the exe 22kb
I don't really mind but i usually start of with about 70kb for tiny apps, would be nice to have less then 40kb though

Frederick J. Harris

#4
How did you get the 6K Edwin?  Using %NOMDI (or something like that) and %USEMACROS  ?
Be curious to see what a Hello, World Sdk GUI app using the Console Compiler would be???

José Roca

 
Easy:


#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN () AS LONG

   ? "Hello Word"

END FUNCTION


6 Kb.

With PBCC, 7Kb (PRINT uses more code that MSGBOX).

Frederick J. Harris

Ha!  No, I meant just using Sdk code for a CreateWindow() and WndProc() in a CC50 program to see what effect that had.  Its certainly no big deal.  The idea just occurred to me though to see if leaving out a lot of the GUI machinery in PB Win90 would make the exe smaller.  I didn't know it could be trimmed down to the size Edwin got.  Mine bare bones tests were a little bigger.

José Roca

This compiles at a size of 9 KB, both in PBWIN 9.x and PBCC 5.x.


#COMPILE EXE
#DIM ALL

%NULL            = 0
%WHITE_BRUSH     = 0
%ANSI_VAR_FONT   = 12
%CS_VREDRAW      = &H0001???
%CS_HREDRAW      = &H0002???
%IDC_ARROW       = 32512???
%COLOR_BTNFACE   = 15&
%COLOR_3DFACE    = %COLOR_BTNFACE
%IDI_APPLICATION = 32512???
%SPI_GETWORKAREA = &H0030???
%WM_SETFONT      = &H0030???
%DT_CENTER       = &H00000001???
%DT_VCENTER      = &H00000004???
%DT_SINGLELINE   = &H00000020???

TYPE WNDCLASSEXA
   cbSize        AS DWORD        ' UINT        cbSize
   ' /* Win 3.x */
   style         AS DWORD        ' UINT        style
   lpfnWndProc   AS DWORD        ' WNDPROC     lpfnWndProc
   cbClsExtra    AS LONG         ' int         cbClsExtra
   cbWndExtra    AS LONG         ' int         cbWndExtra
   hInstance     AS DWORD        ' HINSTANCE   hInstance
   hIcon         AS DWORD        ' HICON       hIcon
   hCursor       AS DWORD        ' HCURSOR     hCursor
   hbrBackground AS DWORD        ' HBRUSH      hbrBackground
   lpszMenuName  AS ASCIIZ PTR   ' LPCSTR      lpszMenuName
   lpszClassName AS ASCIIZ PTR   ' LPCSTR      lpszClassName
   ' /* Win 4.0 */
   hIconSm       AS DWORD        ' HICON       hIconSm
END TYPE

MACRO WNDCLASSEX = WNDCLASSEXA

TYPE tagMSG
   hwnd    AS DWORD   ' HWND        hwnd
   message AS DWORD   ' UINT        message
   wParam  AS DWORD   ' WPARAM      wParam
   lParam  AS LONG    ' LPARAM      lParam
   time    AS DWORD   ' DWORD       time
   pt      AS POINT   ' POINT       pt
END TYPE

TYPE RECT
   nLeft   AS LONG   ' LONG
   nTop    AS LONG   ' LONG
   nRight  AS LONG   ' LONG
   nBottom AS LONG   ' LONG
END TYPE

TYPE PAINTSTRUCT
   hDC              AS DWORD   ' HDC         hdc
   fErase           AS LONG    ' BOOL        fErase
   rcPaint          AS RECT    ' RECT        rcPaint
   fRestore         AS LONG    ' BOOL        fRestore
   fIncUpdate       AS LONG    ' BOOL        fIncUpdate
   rgbReserved (31) AS BYTE    ' BYTE        rgbReserved[32]
END TYPE

DECLARE SUB PostQuitMessage LIB "USER32.DLL" ALIAS "PostQuitMessage" ( _
   BYVAL nExitCode AS LONG _                            ' __in int nExitCode
)                                                      ' VOID

DECLARE FUNCTION DefWindowProc LIB "USER32.DLL" ALIAS "DefWindowProcA" ( _
   BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
, BYVAL Msg AS DWORD _                                 ' __in UINT Msg
, BYVAL wParam AS DWORD _                              ' __in WPARAM wParam
, BYVAL lParam AS LONG _                               ' __in LPARAM lParam
) AS LONG                                              ' LRESULT

DECLARE FUNCTION DrawText LIB "USER32.DLL" ALIAS "DrawTextA" ( _
   BYVAL hdc AS DWORD _                                 ' __in HDC hdc
, BYREF lpchText AS ASCIIZ _                           ' __in LPCSTR lpchText
, BYVAL cchText AS LONG _                              ' __in int cchText
, BYREF lprc AS RECT _                                 ' __in_out LPRECT lprc
, BYVAL format AS DWORD _                              ' __in UINT format
) AS LONG                                              ' int

DECLARE FUNCTION EndPaint LIB "USER32.DLL" ALIAS "EndPaint" ( _
   BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
, BYREF lpPaint AS PAINTSTRUCT _                       ' __in CONST PAINTSTRUCT *lpPaint
) AS LONG                                              ' BOOL

DECLARE FUNCTION GetStockObject LIB "GDI32.DLL" ALIAS "GetStockObject" ( _
   BYVAL i AS LONG _                                    ' __in int i
) AS DWORD                                             ' HGDIOBJ

DECLARE FUNCTION RegisterClassEx LIB "USER32.DLL" ALIAS "RegisterClassExA" ( _
   BYREF lpwcx AS WNDCLASSEXA _                         ' __in CONST WNDCLASSEXA *lpwcx
) AS WORD                                              ' ATOM

DECLARE FUNCTION LoadCursor LIB "USER32.DLL" ALIAS "LoadCursorA" ( _
   BYVAL hInstance AS DWORD _                           ' __in_opt HINSTANCE hInstance
, BYREF lpCursorName AS ASCIIZ _                       ' __in LPCSTR lpCursorName
) AS DWORD                                             ' HCURSOR

DECLARE FUNCTION LoadIcon LIB "USER32.DLL" ALIAS "LoadIconA" ( _
   BYVAL hInstance AS DWORD _                           ' __in_opt HINSTANCE hInstance
, BYREF lpIconName AS ASCIIZ _                         ' __in LPCSTR lpIconName
) AS DWORD                                             ' HICON

DECLARE FUNCTION SystemParametersInfo LIB "USER32.DLL" ALIAS "SystemParametersInfoA" ( _
   BYVAL uiAction AS DWORD _                            ' __in UINT uiAction
, BYVAL uiParam AS DWORD _                             ' __in UINT uiParam
, BYREF pvParam AS ANY _                               ' __in_out_opt PVOID pvParam
, BYVAL fWinIni AS DWORD _                             ' __in UINT fWinIni
) AS LONG                                              ' BOOL

DECLARE FUNCTION CreateWindowEx LIB "USER32.DLL" ALIAS "CreateWindowExA" ( _
   BYVAL dwExStyle AS DWORD _                           ' __in DWORD dwExStyle
, BYREF lpClassName AS ASCIIZ _                        ' __in_opt LPCSTR lpClassName
, BYREF lpWindowName AS ASCIIZ _                       ' __in_opt LPCSTR lpWindowName
, BYVAL dwStyle AS DWORD _                             ' __in DWORD dwStyle
, BYVAL X AS LONG _                                    ' __in int X
, BYVAL Y AS LONG _                                    ' __in int Y
, BYVAL nWidth AS LONG _                               ' __in int nWidth
, BYVAL nHeight AS LONG _                              ' __in int nHeight
, BYVAL hWndParent AS DWORD _                          ' __in_opt HWND hWndParent
, BYVAL hMenu AS DWORD _                               ' __in_opt HMENU hMenu
, BYVAL hInstance AS DWORD _                           ' __in_opt HINSTANCE hInstance
, BYREF lpParam AS ANY _                               ' __in_opt LPVOID lpParam
) AS DWORD                                             ' HWND

DECLARE FUNCTION SendMessage LIB "USER32.DLL" ALIAS "SendMessageA" ( _
   BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
, BYVAL Msg AS DWORD _                                 ' __in UINT Msg
, BYVAL wParam AS DWORD _                              ' __in WPARAM wParam
, BYVAL lParam AS LONG _                               ' __in LPARAM lParam
) AS LONG                                              ' LRESULT

DECLARE FUNCTION ShowWindow LIB "USER32.DLL" ALIAS "ShowWindow" ( _
   BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
, BYVAL nCmdShow AS LONG _                             ' __in int nCmdShow
) AS LONG                                              ' BOOL

DECLARE FUNCTION UpdateWindow LIB "USER32.DLL" ALIAS "UpdateWindow" ( _
   BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
) AS LONG                                              ' BOOL

DECLARE FUNCTION GetMessage LIB "USER32.DLL" ALIAS "GetMessageA" ( _
   BYREF lpMsg AS tagMSG _                              ' __out LPMSG lpMsg
, BYVAL hWnd AS DWORD _                                ' __in_opt HWND hWnd
, BYVAL wMsgFilterMin AS DWORD _                       ' __in UINT wMsgFilterMin
, BYVAL wMsgFilterMax AS DWORD _                       ' __in UINT wMsgFilterMax
) AS LONG                                              ' BOOL

DECLARE FUNCTION IsDialogMessage LIB "USER32.DLL" ALIAS "IsDialogMessageA" ( _
   BYVAL hDlg AS DWORD _                                ' __in HWND hDlg
, BYREF lpMsg AS tagMSG _                              ' __in LPMSG lpMsg
) AS LONG                                              ' BOOL

DECLARE FUNCTION TranslateMessage LIB "USER32.DLL" ALIAS "TranslateMessage" ( _
   BYREF lpMsg AS tagMSG _                              ' __in CONST MSG *lpMsg
) AS LONG                                              ' BOOL

DECLARE FUNCTION DispatchMessage LIB "USER32.DLL" ALIAS "DispatchMessageA" ( _
   BYREF lpMsg AS tagMSG _                              ' __in CONST MSG *lpMsg
) AS LONG                                              ' LRESULT

DECLARE FUNCTION GetClientRect LIB "USER32.DLL" ALIAS "GetClientRect" ( _
   BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
, BYREF lpRect AS RECT _                               ' __out LPRECT lpRect
) AS LONG                                              ' BOOL

DECLARE FUNCTION BeginPaint LIB "USER32.DLL" ALIAS "BeginPaint" ( _
   BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
, BYREF lpPaint AS PAINTSTRUCT _                       ' __out LPPAINTSTRUCT lpPaint
) AS DWORD                                             ' HDC

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   LOCAL hWndMain    AS DWORD
   LOCAL hCtl        AS DWORD
   LOCAL hFont       AS DWORD
   LOCAL wcex        AS WNDCLASSEX
   LOCAL szClassName AS ASCIIZ * 80
   LOCAL rc          AS RECT
   LOCAL szCaption   AS ASCIIZ * 255
   LOCAL nLeft       AS LONG
   LOCAL nTop        AS LONG
   LOCAL nWidth      AS LONG
   LOCAL nHeight     AS LONG

   hFont = GetStockObject(%ANSI_VAR_FONT)

   ' Register the window class
   szClassName        = "MyClassName"
   wcex.cbSize        = SIZEOF(wcex)
   wcex.style         = %CS_HREDRAW OR %CS_VREDRAW
   wcex.lpfnWndProc   = CODEPTR(WndProc)
   wcex.cbClsExtra    = 0
   wcex.cbWndExtra    = 0
   wcex.hInstance     = hInstance
   wcex.hCursor       = LoadCursor (%NULL, BYVAL %IDC_ARROW)
   wcex.hbrBackground = GetStockObject(%WHITE_BRUSH)
   wcex.lpszMenuName  = %NULL
   wcex.lpszClassName = VARPTR(szClassName)
   wcex.hIcon         = LoadIcon (%NULL, BYVAL %IDI_APPLICATION) ' Sample, if resource icon: LoadIcon(hInst, "APPICON")
   wcex.hIconSm       = LoadIcon (%NULL, BYVAL %IDI_APPLICATION) ' Remember to set small icon too..
   RegisterClassEx wcex

   ' Window caption
   szCaption = "SDK Main Window"

   ' Retrieve the size of the working area
   SystemParametersInfo %SPI_GETWORKAREA, 0, BYVAL VARPTR(rc), 0

   ' Calculate the position and size of the window
   nWidth  = (((rc.nRight - rc.nLeft)) + 2) * 0.75   ' 75% of the client screen width
   nHeight = (((rc.nBottom - rc.nTop)) + 2) * 0.70   ' 70% of the client screen height
   nLeft   = ((rc.nRight - rc.nLeft) \ 2) - nWidth \ 2
   nTop    = ((rc.nBottom - rc.nTop) \ 2) - (nHeight \ 2)

   ' Create a window using the registered class
   hWndMain = CreateWindowEx(%WS_EX_CONTROLPARENT, _           ' extended style
                             szClassName, _                    ' window class name
                             szCaption, _                      ' window caption
                             %WS_OVERLAPPEDWINDOW OR _
                             %WS_CLIPCHILDREN, _               ' window styles
                             nLeft, _                          ' initial x position
                             nTop, _                           ' initial y position
                             nWidth, _                         ' initial x size
                             nHeight, _                        ' initial y size
                             %NULL, _                          ' parent window handle
                             0, _                              ' window menu handle
                             hInstance, _                      ' program instance handle
                             BYVAL %NULL)                      ' creation parameters

   hCtl = CreateWindowEx(0, "BUTTON", "&Ok", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_FLAT, _
          0, 0, 0, 0, hWndMain, %IDOK, hInstance, BYVAL %NULL)
   IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0

   hCtl = CreateWindowEx(0, "BUTTON", "&Close", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_FLAT, _
          0, 0, 0, 0, hWndMain, %IDCANCEL, hInstance, BYVAL %NULL)
   IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0

   ' Show the window
   ShowWindow hWndMain, nCmdShow
   UpdateWindow hWndMain

   ' Message handler loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      IF ISFALSE IsDialogMessage(hWndMain, uMsg) THEN
         TranslateMessage uMsg
         DispatchMessage uMsg
      END IF
   WEND

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main dialog callback.
' ========================================================================================
FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL message AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   LOCAL hdc AS DWORD
   LOCAL ps  AS PAINTSTRUCT
   LOCAL rc  AS RECT

   SELECT CASE message

      CASE %WM_PAINT
         hdc = BeginPaint(hWnd, ps)
         GetClientRect hWnd, rc
         DrawText hdc, "Hello, Windows!", -1, rc, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
         EndPaint(hWnd, ps)
         FUNCTION = 0
         EXIT FUNCTION

     CASE %WM_DESTROY
         PostQuitMessage 0
         FUNCTION = 0
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProc(hWnd, message, wParam, lParam)

END FUNCTION
' ========================================================================================


Patrice Terrier

Could be reduced to 7680 bytes, the smallest size possible with PB9.
and 7168 bytes with PB8  :)

i am unable to check with PBWIN7 and PBDLL6 because they won't run on VISTA 64 (16-bit compiler), but they will probably produce something around 6500 bytes.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Charles Pegge

The PE format imposes a lower limit (practically speaking) of aoround 2.5 k, Even if it is mostly empty space. Almost all the remainder is run-time library. The zip below contains 3 test progs created with the thinBasic/Oxygen assembler. The Hello_box is 2.5k, the HelloWin with message loop is 3.5k and the 4 Port Opengl viewer is 8.5K. These programs have no run-time extras to carry. You can see these 3 progs together zip down to 5.7K :)

Edwin Knoppert

PB by default is small enough but 'grows rapidly' when you use its BASIC features.
This is no real complaint, sizes < 100KB suits me fine.
Though i made the request for optimized static linking and should have impact on BASIC features imo.

Carlo Pagani

Quotei am unable to check with PBWIN7 and PBDLL6 because they won't run on VISTA 64 (16-bit compiler), but they will probably produce something around 6500 bytes.

Hey Patrice, have you tried XPMode and PB7?

Patrice Terrier

Carlo,

Even when using the compatibility mode, you can't run 16-bit code on VISTA/W7 64-bit

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Edwin Knoppert

#13
he did not say "compatibility mode"

Added:
I may be confused as well, i assumed XPMode for Windows 7 but then.. there is no retail of w7 yet :)
(XP on virtual pc)

Patrice Terrier

#14
Here is the smallest one  ;D

6656 bytes


#COMPILE EXE
DECLARE FUNCTION MessageBox LIB "USER32.DLL" ALIAS "MessageBoxA" (BYVAL hWnd AS DWORD, lpText AS ASCIIZ, lpCaption AS ASCIIZ, BYVAL dwType AS DWORD) AS LONG
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   MessageBox (0, "Hello world!", "SDK MessageBox", 0)

END FUNCTION


...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com