链接器警告LNK4221,和一些提示,以避免它

大家好,我叫Chandler Shen,是Visual C++上海团队的开发人员。

null

关于警告有些混乱 LNK4221型 以及忽略它是否安全。我想解释一下什么时候您可能会遇到这个警告,并为一些典型的场景和解决方法提供提示。

在构建静态/导入库时,链接器可能会发出以下消息:

“警告LNK4221:未找到公共符号;存档成员将不可访问”(VS2010中的消息将改进为“警告LNK4221:此对象文件未定义任何以前未定义的公共符号,因此任何使用此库的链接操作都不会使用它)。

正如消息所说,当对象文件添加到存档库时,如果没有任何以前未定义的公共符号,则会出现此警告,因此在随后的链接器命令中无法访问该文件。

尽管这个警告有时可以被安全地忽略,但用户应该知道在地表下发生了什么。

例子

创建两个源文件a.cpp和b.cpp,包含以下内容

//a.cpp公司

#包括

//b.cpp公司

#包括

int func1()

{

返回0; }

在“VisualStudio2008命令提示符”中,输入以下命令(注意:我们在这里使用命令行来指定.obj文件的顺序;VisualStudio2008将为链接器提供按字母顺序排列的.obj文件)

1. 信用证a.cpp b.cpp

2. 链接/库/out:test.lib a.obj b、 目标

将为a.obj抛出LNK4221,如下所示。

a、 obj:警告LNK4221:未找到公共符号;存档成员将不可访问

对于上述情况,atlbase.h(随VisualStudio提供)包含一些符号定义,这些定义将包含在a.obj和b.obj中。此外,在b.obj中还定义了一个函数func1。链接器将在中处理OBJ文件 L 阿斯特 n F 第一 O ut方式,因此在处理a.obj时,无法在其中找到任何新的公共符号,因为b.obj提供了a.obj拥有的所有公共符号,因此将抛出LNK4221。如果命令行2替换为

链接/库/out:test.lib b.obj a、 目标

现在警告消失了!

实际上,大多数LNK4221警告出现在stdafx.obj上,这是预编译头的名称。在本节中,我们将重点讨论两个典型的“真实世界”场景,并提供相应的解决方法。

使用对象文件构建静态库

通常,不应在stdafx.obj上抛出LNK4221。但在某些情况下,例如从其他IDE或项目系统迁移时,有多个源文件是用/Yc指定的,因此它们的.obj文件都将包含stdafx.obj中的内容,如果其中任何一个文件在stdafx.obj之前处理,将抛出LNK4221。如果发生这种情况,请尝试执行以下步骤来检查预编译头的配置。

1. 在项目的属性对话框中,选择“ 配置属性 ”->” C/C++ ”->” 预编译头 ”. 选择“ 使用预编译头(/Yu) “用于” 创建/使用预编译头 ,并接受其他两个选项的默认值。

图片[1]-链接器警告LNK4221,和一些提示,以避免它-yiteyi-C++库

2. 在解决方案资源管理器中右键单击“stdafx.cpp”。选择“属性”,然后选择 配置属性 ” -> ” C/C++ ” -> “ 预编译头 ”. 选择“ 创建预编译头(/Yc) “用于” 创建/使用预编译头 ,并接受其他两个选项的默认值。

图片[2]-链接器警告LNK4221,和一些提示,以避免它-yiteyi-C++库

3. 保存更改并重新生成项目。如果问题仍然存在,请检查构建日志以确认只有一个源文件(此处为“stdafx.cpp”)是用/Yc编译的,其他的是用/Yu编译的。

图片[3]-链接器警告LNK4221,和一些提示,以避免它-yiteyi-C++库

与其他静态库一起构建静态库

有时,为了方便起见,用户希望从现有库中构建一个静态库。这种方法可能会“导致”多个LNK4221警告,特别是当用户更改这些库的输出路径设置时。首先,创建一个简单的测试用例,如下所示

1. 在Visual Studio 2008中,创建“ 空白溶液 ”,  并命名为“ 解决方案1 ”.

2. 添加三个新的“ Win32项目 s“,lib1,lib2和wrapperlib,放入solution1,并在 应用程序设置 在向导的第页,选择 静态库 “用于” 应用程序类型 “,检查” 预编译头 “用于” 其他选项 ,然后检查 MFC公司 “用于” 为添加公共头文件 ”.

3. 使用以下代码将新的源文件lib1.cpp添加到项目lib1中

#包括

int func1()

{

返回1;

}

4. 使用以下代码将新的源文件lib2.cpp添加到项目lib2中

#包括

int func2()

{

返回1;

}

5. 在wrapperlib的属性对话框中,选择“ 配置属性 ” -> “ 图书管理员 ” -> “ 总则 ,输入 lib1.lib lib2.lib库 “在” 附加依赖项 ,然后输入 $(输出目录) “在” 其他库目录 ”.

创建完所有项目后,按照lib1、lib2和wrapperlib.lib的顺序构建所有库,除了显示如下信息外,其他一切都应该正常进行:

“替换.Debugstdafx.obj”

看到该消息的原因是链接器从一些对象文件和静态库构建库。它将尝试用命令行中同名的成员替换输入库的存档成员。在本例中,因为“.Debugstdafx.obj”被用作所有三个库的stdafx.obj的对应存档成员的名称。当链接器处理命令行中的“.Debugstdafx.obj”时(用于构建wrapperlib.lib的命令行看起来像“link/lib/out:wrapperlib.lib .Debugstdafx.obj lib1.lib lib2.lib”),它发现lib1和lib2都包含一个同名的成员,所以链接器将从链接中排除这两个成员。因此,没有其他文件将包含在此“stdafx.obj”中定义的符号。

要验证上述说明,请执行以下步骤:

1. 在lib1的属性对话框中,选择“ 配置属性 ” -> “ 总则 ,设置 中间目录 “与” $(SolutionDir)/中间/$(配置名称)/$(项目名称) ,这是某些用户项目层次结构的常见样式。

2. 重新生成lib1和wrapperlib,将显示以下警告。

stdafx.obj:警告LNK4221:未找到公共符号;存档成员将不可访问。

它(替换机制和LNK4221)是链接器的错误吗?答案是否定的,因为:

1. 链接器应该非常小心,不要仅仅因为库中的任何有用对象的名称与另一个对象的名称冲突就删除它

2. 如果发生了不寻常的事情(一个对象并没有提供新的符号来存档),应该通知用户。

由于此警告已被广泛报道,建议采用以下解决方法

执行以下步骤手动替换输入库中的“stdafx.obj”。

1. 在“VisualStudio2008命令提示符”中,为每个输入库输入以下命令。

库/remove:.Debugstdafx.obj lib1.lib

“/remove”后面的名称取决于您的实际设置,  您可以使用以下命令来确认

dumpbin/archivemembers lib1.lib文件

2. 如果某些“stdafx.obj”不相同 在内容中,您应该事先将所有“stdafx.obj”合并到wrapperlib.lib中的一个。

答。 从wrapperlib.lib中删除stdafx.h中的所有内容

b。 检查输入库(lib1.lib、lib2.lib等)中的所有stdafx.h,如果wrapperlib.lib中的内容(如“#include”子句)中没有包含任何内容,请添加它。如果定义有冲突,那就由你来决定使用哪一个。

c。 重复步骤b,直到检查输入库中的所有stdafx.h,这样wrapperlib.lib中的一个将包含所有内容。

3. 生成wrapperlib.lib

如果你不想解决这个链接器警告,只要忽略LNK4221。但是,您应该确保所有“stdafx.obj”的内容都是相同的。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享