You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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为例)

  1. 准备依赖:将Google Test源码放到thirdparty/gtest目录
  2. 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" }
  1. 编写测试代码(示例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);
}
  1. 编译运行:用Premake生成工程后,编译MyAppTests项目,运行即可查看测试结果。

内容的提问来源于stack exchange,提问作者IvonaK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:14:56