使用 VC++ 标准版创建静态链接可执行文件





5.00/5 (1投票)
2000年1月17日

183938

791
VC++ 标准版仅支持动态链接的可执行文件。本文将向您展示如何绕过此限制。
因为穷没钱,我买了最便宜的 VC++(“标准”版),后来发现我只能构建依赖于共享库的新应用程序。即,没有静态链接的可执行文件。这意味着如果我使用了 MFC,我将不得不将 MFC*.dll 与我的应用程序一起分发。您拥有更昂贵版本的读者可能认为静态链接的可执行文件是理所当然的。当我学习 VC++、编译示例、阅读书籍时,我注意到 MFCIE 示例具有静态构建的配置,所以我静态地编译了它,结果——没有 MFC 依赖项!!哇,我想,这毕竟是可能的。于是我把它放在脑子里一年左右,然后继续学习如何编写代码。一天,我想拥有一个静态构建,并且想知道如何做到这一点,绕过微软的版本控制。
首先要做的就是获取一个项目,或者开始一个新项目,编译它,然后导出 makefile(并编写依赖项)。
接下来我检查了 .mak 文件,比较了 MFCIE 和我的项目的 .mak 文件。我还检查了 .clw、.dsp、.dep 和 .dsw 文件。嗯,真有趣,我想。我注意到 .dsp 和 .dep 文件最有趣。所以我拿出了我最喜欢的编辑器之一(在 emacs、ultra edit、text edit、joe 或 Visual Studio 之间选择——我选择了 Ultra Edit),关闭了 VC++ 中的 myProject,然后在编辑器中打开了 mfcie.dsp、mfcie.dep、myProject.dsp 和 myProject.dep。
我将 `!MESSAGE` 行从 mfcie.dsp 文件复制到 myProject.dsp 文件,其中包含“static”一词,并像这样更改了名称为“myProject”:(前两行是原始行)
!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")我改变了
# PROP AllowPerConfigDependencies 0
to# PROP AllowPerConfigDependencies 1
然后我复制了
!ELSEIF "$(CFG)" == "mfcie - Win32 Static Release"和
!ELSEIF "$(CFG)" == "mfcie - Win32 Static Debug"部分到 myProject.dsp,将“mfcie”更改为“myProject”,并将 Output_Dir 和 Intermediate_Dir 改为合理的值。看起来像这样
!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在 Debug 部分的最后一条目和 `!ENDIF` 语句之间。我还将我的名字添加到了 ` # Begin Target ` 部分
# Name "myProject - Win32 Release" # Name "myProject - Win32 Debug" # Name "myProject - Win32 Static Release" # Name "myProject - Win32 Static Debug"我还添加了行
!IF "$(CFG)" == "myProject - Win32 Release" !ELSEIF "$(CFG)" == "myProject - Win32 Debug" !ELSEIF "$(CFG)" == "myProject - Win32 Static Release" !ELSEIF "$(CFG)" == "myProject - Win32 Static Debug" !ENDIF在行之后
SOURCE=.\myProject.rc和之前
# End Source File
我还用编辑器打开了 mfcie.dep 和 myProject.dep 文件。这里有有趣的差异。虽然我不确定这在多大程度上取决于此文件。我认为大部分内容都在 .dsp 文件中。
我删除了每一行是
".\StdAfx.h"\从那里列出的文件中。将行
.\StdAfx.cpp : \
".\StdAfx.h"\
移至最后一行,并将其更改为类似于 mfcie.dep 文件中的行,该行是".\StdAfx.h"\ .\StdAfx.cpp : \ "..\vc98\include\basetsd.h"\ ".\StdAfx.h"\显然改变了 basetsd.h 的位置,因为它在此实例中有所不同。
只需确保 C++ 预处理器设置正确,并且输送目录已设置。
我在 VC++6 中打开了 myProject.dsp,更改了活动配置,然后进行了编译。我忽略了链接器警告
LINK : warning LNK4089: all references to "SHELL32.dll" discarded by /OPT:REF
与我预期的结果相反,它成功编译并链接了。我使用我最喜欢的依赖项检查器检查了依赖项,没有列出 MFC*.dll,并且可执行文件大了 2 倍,所以据我所知,它是静态构建的。
在尝试了几次之后,向导创建了新项目,并编辑了文件,我成功了 7/8 次,包括将静态链接的可执行文件(就 MFC*.DLL 而言)添加到几个已经成熟的、正在进行中的项目中。没有成功的那次,我没有提前编译并导出 makefile。几次,我不得不摆弄链接器设置等,但最终它们被编译/链接了。
附录
写这篇文章以来,我找到了一个新方法
- 将整个 Visual C++ 目录结构套件和所有东西移到别处。(您不需要移动 MSDN,最好将其保留,否则帮助和 MSDN 将无法工作,除非您重新安装 MSDN)
从 D:\Program Files\Microsoft Visual Studio
到 D:\VC - 编辑(Win2k)中的环境变量(控制面板->系统->高级->环境变量),只需替换
D:\Program Files\Microsoft Visual Studio
为 D:\VC对于下面列出的所有变量。(我不确定它们在 Win9x 中的位置)。对变量执行此操作
- include
- lib
- MSDevDir
- 路径
- 编辑您用于打开 VC++ 的链接。打开 VC++6。它会通知您找不到宏和插件。别担心,我们会很快解决的。
- 以及从 VC++6 本身(工具->选项->目录),替换
D:\Program Files\Microsoft Visual Studio
为 D:\VC对于下面列出的所有变量。
- 包含文件
- 库文件
- 可执行文件
- 源文件
- 转到插件和宏路径(工具->自定义->插件和宏文件)。重新选择您使用的。这将自动重新注册 dll。
- 您可能还想编辑并重新链接“开始”菜单中的所有 VC++ 工具。
- 现在,试试看。转到文件->新建->MFC 应用程序向导。在第 3 步,您现在应该看到
How would you like to use the MFC library? o As a shared library o As a statically linked library
选择静态链接库。现在构建它。启动 Depends 以查看它是否确实不依赖于 MFC.dll。我相信在计算机上移动文件是完全合法的。
或者,我编写了一个宏,它将使用我之前关于同一主题的文章中的方法,为您的当前项目添加静态链接配置。此方法耗时更少。
只需将此内容复制粘贴到宏文件中,然后在您的项目上运行它。
============================================================== 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