Skip to content

xmake project -k ninja emits no build edge for Windows .rc resource files (missing and no known rule to make it) #7682

Description

@bionicbeagle

Xmake Version

3.0.8 (also reproducible with current dev — the code in question is unchanged)

Operating System Version and Architecture

Windows 11, x64, MSVC (VS 2026, but any MSVC version reproduces)

Describe Bug

build.ninja files generated by xmake project -k ninja do not contain build edges for Windows resource (.rc) files. The rule mrc definition is emitted, and the link edge for the target lists the .rc.obj among its inputs (it comes from target:objectfiles()), but no build <obj>: mrc <src> statement is ever generated. A clean ninja build therefore fails immediately:

ninja: error: 'build/.objs/hello/windows/x64/release/src/hello.rc.obj', needed by 'build/windows/x64/release/hello.exe', missing and no known rule to make it

The error is easy to miss if you have previously built the same tree with xmake directly: the stale .rc.obj files left in build/.objs/ satisfy ninja, and the build appears to work until the tree is cleaned.

Root cause: in xmake/plugins/project/ninja/build_ninja.lua, _sourcebatch_is_built() whitelists the sourcebatches that get object build edges:

function _sourcebatch_is_built(sourcebatch)
    -- we can only use rulename to filter them because sourcekind may be bound to multiple rules
    local rulename = sourcebatch.rulename
    if rulename == "c.build" or rulename == "c++.build"
        or rulename == "asm.build" or rulename == "cuda.build"
        or rulename == "objc.build" or rulename == "objc++.build" then
        return true
    end
end

Resource files belong to the win.sdk.resource rule, so their batch is skipped, while the linker inputs still reference the resource object. (This looks like a regression relative to the behaviour discussed in #1118, where the mrc build edge was still being emitted.)

Suggested fix: add win.sdk.resource to the whitelist. The resource batch's sourcekind is mrc, which matches the emitted rule name, so the generic _add_build_for_objects() path then produces a correct edge:

    if rulename == "c.build" or rulename == "c++.build"
        or rulename == "asm.build" or rulename == "cuda.build"
        or rulename == "objc.build" or rulename == "objc++.build"
        or rulename == "win.sdk.resource" then

I verified locally that with this one-line change the generated build.ninja contains the mrc edge and a clean ninja build of a real project (two targets with .rc files) succeeds end to end.

Expected Behavior

ninja builds the generated project from a clean tree, compiling .rc files via the emitted mrc rule.

Project Configuration

Minimal repro:

add_rules("mode.release")
target("hello")
    set_kind("binary")
    add_files("src/main.cpp")
    add_files("src/hello.rc")

src/main.cpp:

int main() { return 0; }

src/hello.rc:

1 VERSIONINFO
FILEVERSION 1,0,0,0
BEGIN
END
$ xmake config -y -p windows -a x64 -m release
$ xmake project -k ninja
$ ninja    # from a VS x64 developer prompt
ninja: error: 'build/.objs/hello/windows/x64/release/src/hello.rc.obj', needed by 'build/windows/x64/release/hello.exe', missing and no known rule to make it

Additional Information and Error Logs

Generated build.ninja (excerpt) — rule mrc exists, hello.rc.obj is a link input, but no build edge references mrc:

rule mrc
 command = C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\rc.exe $ARGS -Fo$out $in
 deps = msvc
 description = compiling.release $in

build build/windows/x64/release/hello.exe: ld build/.objs/hello/windows/x64/release/src/main.cpp.obj build/.objs/hello/windows/x64/release/src/hello.rc.obj

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions