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

如何在Makefile中实现单规则多目标?内核驱动编译报错

问题

我正在编译Windows内核驱动,现有Makefile通过all目标依次完成编译、链接、签名操作。希望改用单规则多目标的方式实现,而非仅依赖all目标。

现有Makefile内容如下:

PLATFORM := x64
CONFIGURATION := debug
PROJECT_NAME := Necrobyte

BIN_PATH := "bin\$(PLATFORM)\$(CONFIGURATION)\"
OUT_PATH := "build\$(PLATFORM)\$(CONFIGURATION)\"

# ++ COMPILE ++

SRC_FILES := $(wildcard *.c)

CC := "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\bin\HostX86\x64\CL.exe"
CFLAGS := /c /Ibin\$(PLATFORM)\$(CONFIGURATION)\ /Zi /nologo /W4 /WX /diagnostics:column /Od /Oi /Oy- /D _WIN64 /D _AMD64_ /D AMD64 \
            /D DEPRECATE_DDK_FUNCTIONS=1 /D MSC_NOOPT /D _WIN32_WINNT=0x0A00 /D WINVER=0x0A00 /D WINNT=1 \
            /D NTDDI_VERSION=0xA00000C /D DBG=1 /D KMDF_VERSION_MAJOR=1 /D KMDF_VERSION_MINOR=15 /GF /Gm- /Zp8 \
            /GS /guard:cf /Gy /fp:precise /Qspectre /Zc:wchar_t- /Zc:forScope /Zc:inline /GR- /Fo"bin\$(PLATFORM)\$(CONFIGURATION)\\" \
            /external:W4 /Gz /wd4748 /wd4603 /wd4627 /wd4986 /wd4987 \
            /FC /errorReport:queue /kernel -cbstring -d2epilogunwind /d1import_no_registry /d2AllowCompatibleILVersions \
            /d2Zi+
            
CINCLUDE := /FI"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared\warning.h" \
            /I"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include" \
            /I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\km" \
            /I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt" \
            /I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared"

# -- LINK --

SRC_OBJ := $(patsubst %.c, $(BIN_PATH)%.obj, $(SRC_FILES))

LNK := "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\bin\HostX86\x64\link.exe"
LFLAGS := /ERRORREPORT:QUEUE /OUT:"C:\Users\ihxd\Desktop\Necrobyte\build\x64\debug\$(PROJECT_NAME).sys" \
            /VERSION:"10.0" /INCREMENTAL:NO /NOLOGO /WX /SECTION:"INIT,d" \
            /NODEFAULTLIB /MANIFEST:NO /DEBUG \
            /PDB:"$(BIN_PATH)$(PROJECT_NAME).pdb" \
            /SUBSYSTEM:NATIVE,"10.00" /Driver /OPT:REF /OPT:ICF /ENTRY:"FxDriverEntry" /RELEASE \
            /IMPLIB:"$(BIN_PATH)$(PROJECT_NAME).lib" \
            /MERGE:"_TEXT=.text;_PAGE=PAGE" /MACHINE:X64 /PROFILE /guard:cf /kernel \
            /IGNORE:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221,4108,4088,4218,4235 \
            /osversion:10.0 /pdbcompress /debugtype:pdata \
            

LINCLUDE := "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\netio.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\BufferOverflowFastFailK.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\ntoskrnl.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\hal.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\wmilib.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\wdf\kmdf\x64\1.15\WdfLdr.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\wdf\kmdf\x64\1.15\WdfDriverEntry.lib"

# ** TEST SIGN **

SGN := "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\signtool.exe" sign /ph /fd "sha256" /sha1 "9606C369B02FF06D537D40268DCCE5DB4D1E5FF7"

all:
    $(CC) $(CINCLUDE) $(CFLAGS) $(SRC_FILES)
    $(LNK) $(LFLAGS) $(LINCLUDE) $(SRC_OBJ)
    $(SGN) $(OUT_PATH)$(PROJECT_NAME).sys

尝试修改为如下规则后,出现错误提示Multiple targets. STOP:

$(OUT_PATH): $(SRC_FILES)
    $(CC) $(CINCLUDE) $(CFLAGS) $(SRC_FILES)

错误原因

直接用$(OUT_PATH)(目录路径)作为目标,同时依赖多个源文件时,Make会将其误解为"多目标映射"——即试图把多个源文件对应到同一个目录目标,触发匹配冲突,从而抛出Multiple targets错误。


解决方案

要实现单规则多目标的链式流程,需明确**最终产物(签名后的sys文件)**为核心目标,让编译、链接、签名步骤自动依赖前置产物,替代all目标。以下是修改后的完整Makefile:

PLATFORM := x64
CONFIGURATION := debug
PROJECT_NAME := Necrobyte

# 简化路径定义,去掉不必要的引号
BIN_PATH := bin\$(PLATFORM)\$(CONFIGURATION)
OUT_PATH := build\$(PLATFORM)\$(CONFIGURATION)
FINAL_SYS := $(OUT_PATH)\$(PROJECT_NAME).sys
SIGNED_SYS := $(FINAL_SYS).signed  # 区分签名前后的文件,也可直接覆盖原sys

# ++ COMPILE ++
SRC_FILES := $(wildcard *.c)
SRC_OBJ := $(patsubst %.c, $(BIN_PATH)/%.obj, $(SRC_FILES))

CC := "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\bin\HostX86\x64\CL.exe"
CFLAGS := /c /I$(BIN_PATH)/ /Zi /nologo /W4 /WX /diagnostics:column /Od /Oi /Oy- /D _WIN64 /D _AMD64_ /D AMD64 \
            /D DEPRECATE_DDK_FUNCTIONS=1 /D MSC_NOOPT /D _WIN32_WINNT=0x0A00 /D WINVER=0x0A00 /D WINNT=1 \
            /D NTDDI_VERSION=0xA00000C /D DBG=1 /D KMDF_VERSION_MAJOR=1 /D KMDF_VERSION_MINOR=15 /GF /Gm- /Zp8 \
            /GS /guard:cf /Gy /fp:precise /Qspectre /Zc:wchar_t- /Zc:forScope /Zc:inline /GR- /Fo$(BIN_PATH)/ \
            /external:W4 /Gz /wd4748 /wd4603 /wd4627 /wd4986 /wd4987 \
            /FC /errorReport:queue /kernel -cbstring -d2epilogunwind /d1import_no_registry /d2AllowCompatibleILVersions \
            /d2Zi+
            
CINCLUDE := /FI"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared\warning.h" \
            /I"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include" \
            /I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\km" \
            /I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt" \
            /I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared"

# -- LINK --
LNK := "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\bin\HostX86\x64\link.exe"
LFLAGS := /ERRORREPORT:QUEUE /OUT:$(FINAL_SYS) \
            /VERSION:"10.0" /INCREMENTAL:NO /NOLOGO /WX /SECTION:"INIT,d" \
            /NODEFAULTLIB /MANIFEST:NO /DEBUG \
            /PDB:$(BIN_PATH)/$(PROJECT_NAME).pdb \
            /SUBSYSTEM:NATIVE,"10.00" /Driver /OPT:REF /OPT:ICF /ENTRY:"FxDriverEntry" /RELEASE \
            /IMPLIB:$(BIN_PATH)/$(PROJECT_NAME).lib \
            /MERGE:"_TEXT=.text;_PAGE=PAGE" /MACHINE:X64 /PROFILE /guard:cf /kernel \
            /IGNORE:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221,4108,4088,4218,4235 \
            /osversion:10.0 /pdbcompress /debugtype:pdata \
            

LINCLUDE := "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\netio.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\BufferOverflowFastFailK.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\ntoskrnl.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\hal.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\km\x64\wmilib.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\wdf\kmdf\x64\1.15\WdfLdr.lib" \
            "C:\Program Files (x86)\Windows Kits\10\lib\wdf\kmdf\x64\1.15\WdfDriverEntry.lib"

# ** TEST SIGN **
SGN := "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\signtool.exe" sign /ph /fd "sha256" /sha1 "9606C369B02FF06D537D40268DCCE5DB4D1E5FF7"

# 创建必要目录(顺序依赖,确保编译前目录存在)
$(BIN_PATH) $(OUT_PATH):
    @if not exist "$@" mkdir "$@"

# 单源文件编译规则:每个.c对应生成.obj
$(BIN_PATH)/%.obj: %.c | $(BIN_PATH)
    $(CC) $(CINCLUDE) $(CFLAGS) $<

# 链接规则:依赖所有.obj生成sys文件
$(FINAL_SYS): $(SRC_OBJ) | $(OUT_PATH)
    $(LNK) $(LFLAGS) $(LINCLUDE) $^

# 签名规则:依赖未签名sys生成签名后产物(单规则多目标核心)
$(SIGNED_SYS): $(FINAL_SYS)
    $(SGN) $<
    copy $< $@  # 保留原文件,生成签名副本;若要直接覆盖,替换为$(SGN) $@

# 设置默认目标为签名后的文件,直接执行make即可完成全流程
.DEFAULT_GOAL := $(SIGNED_SYS)

关键修改说明

  1. 目标层级拆分:
    • 编译阶段:用$(BIN_PATH)/%.obj: %.c实现单个源文件到目标文件的映射,避免多目标冲突。
    • 链接阶段:依赖所有编译生成的.obj文件,生成未签名的.sys。
    • 签名阶段:依赖未签名.sys,生成最终签名产物,形成完整依赖链。
  2. 目录依赖处理:用| $(BIN_PATH)的顺序依赖语法,确保编译/链接前先创建必要目录。
  3. 默认目标替换:将签名后的文件设为默认目标,无需指定all,直接执行make即可触发全流程。
  4. 路径优化:去掉路径中的多余引号,避免Make解析路径时出现异常。

如果不需要区分签名前后的文件,可简化签名规则,直接覆盖原.sys:

$(FINAL_SYS): $(SRC_OBJ) | $(OUT_PATH)
    $(LNK) $(LFLAGS) $(LINCLUDE) $^
    $(SGN) $@
.DEFAULT_GOAL := $(FINAL_SYS)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:59:51