bazel midl 规则生成的 c++ 头文件和 winmd 文件位于不同的文件夹中

bazel midl rule generated c++ header file and winmd file locates in different folder

当我使用 bazel 从 midl 文件生成 c++ 头源代码和 winmd 文件时,我发现 MyType.winmd 文件在输出文件夹中,而 MyType.h 与源代码位于同一目录 MyType.idl。我想要的是我生成的头文件与 MyType.winmd 文件位于同一文件夹中。

MyType.idl:

namespace NS
{
    [default_interface]
    runtimeclass MyType
    {
    }
}

构建:

load(":cmd.bzl", "midl")
sh_binary(
    name = "midlCmd.bat",
    srcs = ["midl.bat"],
)
midl(
    name = "midlcc.bat",
    idl = "MyType.idl",
    winmd = "MyType.winmd",
)

cmd.bzl:

def _impl(ctx):
    winmd = ctx.outputs.winmd
    idl = ctx.file.idl
    ctx.actions.run(
        inputs = [idl],
        outputs = [winmd],
        arguments = [winmd.path, idl.path],
        progress_message = "Generate winmd from idl file: %s" % idl,
        executable = ctx.executable.code_gen_tool,
    )
midl = rule(
    implementation = _impl,
    output_to_genfiles = True,
    attrs = {
        "idl": attr.label(allow_single_file = True, mandatory = True),
        "winmd": attr.output(mandatory = True),
        "code_gen_tool": attr.label(
            executable = True,
            cfg = "exec",
            allow_files = True,
            default = Label("//cmd:midlCmd.bat"),
        ),
    },
)

midl.bat:

"C:\Program Files (x86)\Windows Kits\bin.0.20206.0\x64\midl.exe" ^
/metadata_dir "%WindowsSdkDir%References\%WindowsSDKVersion%Windows.Foundation.FoundationContract.0.0.0" ^
/reference "%WindowsSdkDir%References\%WindowsSDKVersion%Windows.Foundation.FoundationContract.0.0.0\Windows.Foundation.FoundationContract.winmd" ^
/cpp_cmd "C:\PROGRA~2\MICROS~119\Community\VC\Tools\MSVC.28.29333\bin\Hostx64\x64\cl.exe" ^
/notlb ^
/winrt ^
/nomidl ^
/nologo ^
/enum_class ^
/ns_prefix ^
/client none ^
/server none ^
/winmd %1 %2

运行 命令:

bazel build //cmd:all

在此处生成 MyType.h:

C:\Users\songy\source\repos\tuware\cmd>dir
Directory of C:\Users\songy\source\repos\tuware\cmd
2020-12-02  10:41 PM    <DIR>          .
2020-12-02  10:40 PM    <DIR>          ..
2020-12-02  10:41 PM               188 BUILD
2020-12-02  10:33 PM               746 cmd.bzl
2020-12-02  10:30 PM            10,975 midl.bat
2020-12-02  10:41 PM             6,987 MyType.h
2020-11-02  08:41 PM                82 MyType.idl

生成的 MyType.winmd 在这里:

C:\Users\songy\source\repos\tuware\bazel-bin\cmd>dir
2020-12-02  10:30 PM            10,975 midlCmd.bat
2020-12-02  10:40 PM    <DIR>          midlCmd.bat.runfiles
2020-12-02  10:40 PM               247 midlCmd.bat.runfiles_manifest
2020-12-02  10:41 PM             1,536 MyType.winmd
2020-12-02  10:40 PM    <DIR>          setupCppDesktopDevEnvironment.bat.runfiles
2020-12-02  10:40 PM               293 setupCppDesktopDevEnvironment.bat.runfiles_manifest

有什么我想念的吗?

我看不出如何使用 bazel 的沙箱将文件输出到源目录中。

我唯一能想到的是 midlCmd.bat 硬编码了绝对路径。

生成器应该基于相对路径。如果需要目录结构,规则可以向生成器的命令行提供ctx.configuration.genfiles_dir.path

谢谢@rds 这是我自己的答案。

  1. 在 midl.bat
  2. 中添加 ctx.configuration.genfiles_dir.path 作为 /out 选项值
  3. 对 winmd 和 .h 生成的文件名使用 ctx.declare_file。
def _impl(ctx):
    
    idl = ctx.file.idl

    midl_out_dir = ctx.configuration.genfiles_dir.path

    winmd = ctx.actions.declare_file(ctx.label.name + ".winmd")
    header = ctx.actions.declare_file(ctx.label.name + ".h")

    ctx.actions.run(
        executable = ctx.executable.code_gen_tool,
        arguments = [midl_out_dir, idl.path],
        inputs = [idl],
        outputs = [winmd, header],
        progress_message = "Generate winmd from idl file: %s" % idl.path,
    )

    return [DefaultInfo(files=depset([winmd, header]))]

midl = rule(
    implementation = _impl,
    output_to_genfiles = True,
    attrs = {
        "idl": attr.label(allow_single_file = True, mandatory = True),
        "code_gen_tool": attr.label(
            executable = True,
            cfg = "exec",
            allow_files = True,
            default = Label("//cmd:midlCmd.bat"),
        ),
    },
)

midl.bat:

"%WindowsSdkDir%\bin\%WindowsSDKVersion%\%Platform%\midl.exe" ^
/metadata_dir "%WINDOWS_SDK_REFERENCE_PATH%\Windows.Foundation.FoundationContract.0.0.0" ^
/reference "%WINDOWS_SDK_REFERENCE_PATH%\Windows.Foundation.FoundationContract.0.0.0\Windows.Foundation.FoundationContract.winmd" ^
/cpp_cmd "%VSINSTALLDIR%\VC\Tools\MSVC\%VCToolsVersion%\bin\Host%Platform%\%Platform%\cl.exe" ^
/notlb ^
/winrt ^
/nomidl ^
/nologo ^
/enum_class ^
/ns_prefix ^
/client none ^
/server none ^
/out %1 ^
%2