Premake5.lua特定配置下项目运行出现链接错误的排查求助
Premake5 链接错误(LNK2019/LNK1120)原因分析、解决方案及新手指南
问题原因
当你用files { "src/**.cpp", "src/**.hpp" }时,Premake只会递归搜索src目录下的所有.cpp和.hpp文件进行编译。如果项目里还有其他目录(比如tests/、utils/)存在需要编译的.cpp文件,这些文件会被漏掉——链接器需要所有实现代码的目标文件才能生成可执行文件,缺少的话就会抛出LNK2019(未解析外部符号)和LNK1120(未解析符号数量)错误。
而files { "**.cpp", "**.hpp" }是递归搜索整个项目根目录下的所有cpp/hpp文件,所有需要的实现代码都被编译,自然链接通过。
解决方案
不要盲目用全局匹配,应该根据项目结构精准配置文件范围,避免编译不必要的文件(比如临时文件、第三方库源码):
场景1:主代码在src,测试代码在tests
如果项目有单独的测试目录,建议把主项目和测试项目分开配置,避免耦合:
-- 主项目(编译为静态库,供测试项目调用) project "MyAppCore" kind "StaticLib" language "C++" targetdir "bin/%{cfg.buildcfg}" objdir "obj/%{cfg.buildcfg}" files { "src/**.cpp", "src/**.hpp" } -- 测试项目(可执行文件,依赖主库) project "MyAppTests" kind "ConsoleApp" language "C++" targetdir "bin/%{cfg.buildcfg}" objdir "obj/%{cfg.buildcfg}" files { "tests/**.cpp", "tests/**.hpp" } -- 链接主静态库 links { "MyAppCore" }
场景2:所有代码都在src但有子目录
如果所有代码都在src下但有子目录,原配置src/**.cpp本身是有效的,这时要检查:
- 是否有cpp文件不在src目录下(比如根目录下的
main.cpp) - 是否拼写错误(比如把
src/**.cpp写成src/*.cpp,后者只会匹配src下一级文件,不会递归子目录)
完整示例:配置、结构、错误信息
1. 出错时的Premake配置
workspace "MyApp" configurations { "Debug", "Release" } platforms { "x64" } project "MyApp" kind "ConsoleApp" language "C++" targetdir "bin/%{cfg.buildcfg}" objdir "obj/%{cfg.buildcfg}" -- 仅包含src下文件,漏掉tests目录的实现代码 files { "src/**.cpp", "src/**.hpp" } filter "configurations:Debug" defines { "DEBUG" } symbols "On" filter "configurations:Release" defines { "RELEASE" } optimize "On"
2. 项目文件夹结构
MyApp/ ├── premake5.lua ├── src/ │ ├── core/ │ │ ├── Math.hpp │ │ └── Math.cpp │ └── main.cpp └── tests/ ├── MathTests.cpp # 未被编译,里面引用Math.hpp的函数导致链接错误 └── TestMain.cpp
3. 具体错误信息
LNK2019 未解析的外部符号 "public: static int __cdecl Math::Add(int,int)" (?Add@Math@@SAHHH@Z),该符号在函数 "void __cdecl TestMathAdd(void)" (?TestMathAdd@@YAXXZ) 中被引用
LNK1120 1 个未解析的外部符号
规范C++项目结构(新手友好)
推荐分层结构,便于维护和扩展:
MyApp/ ├── premake5.lua # Premake配置文件 ├── include/ # 公共头文件(对外暴露的接口) │ └── MyApp/ │ └── Math.hpp ├── src/ # 实现代码,与include头文件一一对应 │ ├── Math.cpp │ └── main.cpp ├── tests/ # 单元测试代码,与主代码分离 │ ├── MathTests.cpp │ └── TestMain.cpp ├── thirdparty/ # 第三方依赖库(如Google Test) │ └── gtest/ └── bin/ # 生成的可执行文件目录 ├── Debug/ └── Release/
单元测试创建方法(以Google Test为例)
- 准备依赖:将Google Test源码放到
thirdparty/gtest目录 - Premake配置测试项目:
workspace "MyApp" configurations { "Debug", "Release" } platforms { "x64" } -- 主静态库 project "MyAppCore" kind "StaticLib" language "C++" targetdir "bin/%{cfg.buildcfg}" objdir "obj/%{cfg.buildcfg}" files { "include/MyApp/**.hpp", "src/**.cpp" } includedirs { "include" } -- Google Test静态库 project "gtest" kind "StaticLib" language "C++" targetdir "bin/%{cfg.buildcfg}" objdir "obj/%{cfg.buildcfg}" files { "thirdparty/gtest/src/**.cc", "thirdparty/gtest/include/**.h" } includedirs { "thirdparty/gtest/include", "thirdparty/gtest" } -- 测试可执行项目 project "MyAppTests" kind "ConsoleApp" language "C++" targetdir "bin/%{cfg.buildcfg}" objdir "obj/%{cfg.buildcfg}" files { "tests/**.cpp" } includedirs { "include", "thirdparty/gtest/include" } links { "MyAppCore", "gtest" }
- 编写测试代码(示例
tests/MathTests.cpp):
#include <gtest/gtest.h> #include "MyApp/Math.hpp" TEST(MathTest, Add) { EXPECT_EQ(Math::Add(2, 3), 5); EXPECT_EQ(Math::Add(-1, 1), 0); }
- 编译运行:用Premake生成工程后,编译
MyAppTests项目,运行即可查看测试结果。
内容的提问来源于stack exchange,提问作者IvonaK
相关产品推荐
相关产品推荐

