Download demo project - 14 Kb
Being cheap and having no money, I bought the cheapest VC++ (the "Standard" version) and found out later
that I could only build new applications dependent on shared libraries. i.e. no statically linked
executables. Which means if I used MFC I would have to distribute the MFC*.dll with my app. Those of you
with the more expensive versions might take statically linked executables for granted. As I learned VC++,
compiling the examples, reading books, I noticed that the MFCIE example has configurations for static
builds, so I compiled it statically and, lo and behold - no MFC dependencies!! Wow, I thought,
it IS possible after all. So I put it in the back of my mind for a year or so, and went on learning
how to write code. And so one day I decided that I wanted a static build, and would be nice to know
how to do such a thing, by-passing Microsoft's version of crippleware.
First thing to do is grab a project, or start a new project, compile it, and export the makefile
(and write the dependencies).
Next thing I did was to examine the .mak files, comparing the MFCIE and
my projects .mak files. I also examined the .clw,.dsp, .dep and .dsw files.
Hmm, interesting, I thought. I noticed that the .dsp, and .dep files were most
interesting. So I grabbed one of the many favorite editors I use (deciding
between emacs, ultra edit, text edit, joe, or Visual Studio - I chose Ultra Edit),
closed the myProject in VC++, and opened up mfcie.dsp, mfcie.dep, and myProject.dsp,
myProject.dep, in the editor.
I copied the !MESSAGE
lines from the file mfcie.dsp to the file myProject.dsp
that contained the word "static" and changed the name to "myProject" like this: (the first
two are the original lines)
!MESSAGE "myProject - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "myProject - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE "myProject - Win32 Static Release" (based on "Win32 (x86) Application")
!MESSAGE "myProject - Win32 Static Debug" (based on "Win32 (x86) Application")
I Changed
# PROP AllowPerConfigDependencies 0
to
# PROP AllowPerConfigDependencies 1
I then copied the
!ELSEIF "$(CFG)" == "mfcie - Win32 Static Release"
and
!ELSEIF "$(CFG)" == "mfcie - Win32 Static Debug"
sections to myProject.dsp changing "mfcie" to "myProject", and the Output_Dir and Intermediate_Dir
to something reasonable. Which look like this:
!ELSEIF "$(CFG)" == "myProject - Win32 Static Release"
# PROP BASE Use_MFC 6
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "StaticRelease"
# PROP BASE Intermediate_Dir "StaticRelease"
# PROP BASE Target_Dir ""
# PROP Use_MFC 6
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "StaticRelease"
# PROP Intermediate_Dir "StaticRelease"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
# ADD LINK32 /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "myProject - Win32 Static Debug"
# PROP BASE Use_MFC 6
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "StaticDebug"
# PROP BASE Intermediate_Dir "StaticDebug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 6
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "StaticDebug"
# PROP Intermediate_Dir "StaticDebug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /Gm /GX /Zi /O2 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "NDEBUG" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /D "NDEBUG" /mktyplib203 /o "NUL" /win32 /win32
# ADD MTL /nologo /D "_DEBUG" /D "NDEBUG" /mktyplib203 /o "NUL" /win32 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" /d "NDEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
between the last entry of the Debug section, and the
!ENDIF
statement. I also added my names in the
# Begin Target
section:
# Name "myProject - Win32 Release"
# Name "myProject - Win32 Debug"
# Name "myProject - Win32 Static Release"
# Name "myProject - Win32 Static Debug"
I also added the lines
!IF "$(CFG)" == "myProject - Win32 Release"
!ELSEIF "$(CFG)" == "myProject - Win32 Debug"
!ELSEIF "$(CFG)" == "myProject - Win32 Static Release"
!ELSEIF "$(CFG)" == "myProject - Win32 Static Debug"
!ENDIF
after the line
SOURCE=.\myProject.rc
and before
# End Source File
I also opened mfcie.dep, and myProject.dep files in the editor. Interesting differences here. Although
I am not sure how much it depends on this file. I think most of it is in the .dsp file.
I took out every line that was
".\StdAfx.h"\
from the files listed there. Moved the line that is
.\StdAfx.cpp : \
".\StdAfx.h"\
to the last line and changed it to resemble the one in the mfcie.dep file, which is
".\StdAfx.h"\
.\StdAfx.cpp : \
"..\vc98\include\basetsd.h"\
".\StdAfx.h"\
obviously changing where basetsd.h is located, because it was different in this instance.
Just make sure that the C++ pre-processor settings are correct and that the
Output directories are set.
I opened up myProject.dsp in VC++6, changed the Active configuration, and compiled. I ignored the
linker warning
LINK : warning LNK4089: all references to "SHELL32.dll" discarded by /OPT:REF
Contrary to what I thought would happen, it compiled and linked successfully. I checked the
dependencies using my favorite dependency checker, and no MFC*.dll's were listed, and the executable
was 2x as big, so as far as I KNOW, it was statically built.
After trying this a few times, wizarding up new projects, and editing the files, I have been successful
7/8 of the time, including adding statically linked executable (as far as MFC*.DLL is concerned) to
a couple of already matured, projects-in-progress. The time it didn't work, I didn't compile and export
the makefile beforehand. A few times, I had to mess around with linker settings and such, but they
eventually compiled/linked.
Addenda
Since writing this article I have found a new way of doing this:
- Move the whole Visual C++ directory structure kit and kabootle somewhere else. (You do not need to move MSDN,
its better to leave that, otherwise help & MSDN will not work, unless you reinstall MSDN)
From D:\Program Files\Microsoft Visual Studio
To D:\VC
- Edit the environmental variables in (Win2k) (Control Panel->System ->Advanced->Environmental Variables)
just replace
D:\Program Files\Microsoft Visual Studio
with D:\VC
for all the variables listed below. (I'm not sure where they are in Win9x). Do this for the variables:
- include
- lib
- MSDevDir
- path
- Edit the link you use to open VC++. Open VC++6. It will inform you that it can't find your
macros and add-ins. Don't worry, we will fix this, lickity-split.
- And from VC++6 itself (Tools->Options->Directories), replace
D:\Program Files\Microsoft Visual Studio
with D:\VC
for all the variables listed below.
- include files
- lib files
- executables
- source files
- Go to Add-ins and macros paths (Tools->Customize->Add-ins and Macro Files). Reselect the ones you use.
This will automatically re-register the dll's
- You might also want to edit and relink all the VC++ tools in the Start Menu.
- Now, try it out. Go to File->New->MFC AppWizard. On step 3, you should now see
How would you like to use the MFC library?
o As a shared library
o As a statically linked library
Pick statically linked library. Now build it. Start up Depends to see if it is actually
not dependant on MFC.dll. I am quite sure it is perfectly legal to move files around your computer.
Alternatively, I have written a macro that will use the method in my previous article, on the same subject
to add statically linked configurations to your current project. This method is less time consuming.
Just cut-n-paste this to a macro file, and run it on your project.
==============================================================
Sub StaticLink()
'DESCRIPTION: Makes a statically linked project
Dim projectName
projectName = ActiveProject.Name
Msganswer = MsgBox ("Do you really want to edit the Developer Studio Project file? " &_
"It will be backed up to "+projectName+".dsp.bak",260, "llornkcor VC++ Macro")
if Msganswer = vbNo then
Exit Sub
end if
Dim fso, filespec
Set fso = CreateObject("Scripting.FileSystemObject")
filespec = ActiveProject.Name+".dsp.bak"
If (fso.FileExists( filespec)) Then
Msganswer = MsgBox ("It looks like it has already been edited. " &_
Do you really want to do this?",260, "llornkcor VC++ Macro")
if Msganswer = vbNo then
Exit Sub
end if
End If
Stat()
End Sub
Sub Stat()
'DESCRIPTION: Worker for statically linked project function
Dim fso
Dim dspFileName
Dim projectName
Dim dspFile
Dim appDev
Set appDev = GetObject(,"MSDev.Application")
dspFileName = ActiveProject.Name + ".dsp"
projectName = ActiveProject.Name
Set fso = CreateObject("Scripting.FileSystemObject")
Set dspFile = fso.GetFile( dspFileName)
dspFile.Copy( dspFileName+".bak")
Documents.Open ( dspFileName), "Text"
ActiveDocument.Selection.FindText "Win32 Debug"" (based on ""Win32 (x86) Application"")", dsMatchForward + dsMatchFromStart + dsMatchCase
ActiveDocument.Selection.EndOfLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!MESSAGE """+projectName+" - Win32 Static Debug"" (based on ""Win32 (x86) Application"")"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!MESSAGE """+projectName+" - Win32 Static Release"" (based on ""Win32 (x86) Application"")"
ActiveDocument.Selection.FindText "# PROP AllowPerConfigDependencies"
ActiveDocument.Selection.EndOfLine
ActiveDocument.Selection.WordLeft 1
Dim strVersion4
strVersion4 = ActiveDocument.Selection.Text
ActiveDocument.Selection.ReplaceText strVersion4 , "1"
ActiveDocument.Selection.FindText "!ENDIF"
ActiveDocument.Selection.StartOfLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!ELSEIF ""$(CFG)"" == """+projectName+" - Win32 Static Debug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Use_MFC 6"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Use_Debug_Libraries 0"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Output_Dir ""StaticDebug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Intermediate_Dir ""StaticDebug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Target_Dir """""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Use_MFC 6"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Use_Debug_Libraries 0"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Output_Dir ""StaticDebug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Intermediate_Dir ""StaticDebug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Ignore_Export_Lib 0"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Target_Dir """""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE CPP /nologo /MD /W3 /Gm /GX /Zi /O2 /D ""WIN32"" /D ""_DEBUG"" /D ""_WINDOWS"" /D ""_AFXDLL"" /D ""NDEBUG"" /Yu""stdafx.h"" /FD /c"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD CPP /nologo /MT /W3 /GX /O2 /D ""WIN32"" /D ""_DEBUG"" /D ""_WINDOWS"" /Yu""stdafx.h"" /FD /c"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE MTL /nologo /D ""_DEBUG"" /D ""NDEBUG"" /mktyplib203 /o ""NUL"" /win32 /win32"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD MTL /nologo /D ""_DEBUG"" /D ""NDEBUG"" /mktyplib203 /o ""NUL"" /win32 /win32"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE RSC /l 0x409 /d ""_DEBUG"" /d ""_AFXDLL"" /d ""NDEBUG"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD RSC /l 0x409 /d ""_DEBUG"" /d ""NDEBUG"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "BSC32=bscmake.exe"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE BSC32 /nologo"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BSC32 /nologo"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "LINK32=link.exe"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# SUBTRACT LINK32 /nodefaultlib"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!ELSEIF ""$(CFG)"" == """+projectName+" - Win32 Static Release"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Use_MFC 6"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Use_Debug_Libraries 0"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Output_Dir ""StaticRelease"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Intermediate_Dir ""StaticRelease"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP BASE Target_Dir """""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Use_MFC 6"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Use_Debug_Libraries 0"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Output_Dir ""StaticRelease"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Intermediate_Dir ""StaticRelease"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Ignore_Export_Lib 0"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# PROP Target_Dir """""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D ""WIN32"" /D ""NDEBUG"" /D ""_WINDOWS"" /D ""_AFXDLL"" /Yu""stdafx.h"" /FD /c"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD CPP /nologo /MT /W3 /GX /O2 /D ""WIN32"" /D ""NDEBUG"" /D ""_WINDOWS"" /Yu""stdafx.h"" /FD /c"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE MTL /nologo /D ""NDEBUG"" /mktyplib203 /o ""NUL"" /win32"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD MTL /nologo /D ""NDEBUG"" /mktyplib203 /o ""NUL"" /win32"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE RSC /l 0x409 /d ""NDEBUG"" /d ""_AFXDLL"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD RSC /l 0x409 /d ""NDEBUG"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "BSC32=bscmake.exe"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE BSC32 /nologo"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BSC32 /nologo"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "LINK32=link.exe"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# ADD LINK32 /nologo /subsystem:windows /machine:I386 /out:""StaticRelease/"+projectName+".exe"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# SUBTRACT LINK32 /pdb:none"
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.FindText "# Name """+projectName+" - Win32 Debug"""
ActiveDocument.Selection.EndOfLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# Name """+projectName+" - Win32 Static Debug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "# Name """+projectName+" - Win32 Static Release"""
ActiveDocument.Selection.FindText"SOURCE=.\"+projectName+".rc"
ActiveDocument.Selection.EndOfLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!IF ""$(CFG)"" == """+projectName+" - Win32 Release"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!ELSEIF ""$(CFG)"" == """+projectName+" - Win32 Debug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!ELSEIF ""$(CFG)"" == """+projectName+" - Win32 Static Debug"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!ELSEIF ""$(CFG)"" == """+projectName+" - Win32 Static Release"""
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.NewLine
ActiveDocument.Selection.Text = "!ENDIF"
ActiveDocument.Selection.NewLine
ActiveDocument.Save (ActiveProject.Name + ".dsp")
ActiveDocument.Close()
'App.WorkspaceClose()
End Sub