Search code examples
windowsbazelmidlstarlarkcppwinrt

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


When I use bazel to generate c++ header source code and winmd file from midl file, I found MyType.winmd file is in output folder, while MyType.h locates at same directory as source code MyType.idl. What I want is that my generated header file locates at the same folder as MyType.winmd file.

MyType.idl:

namespace NS
{
    [default_interface]
    runtimeclass MyType
    {
    }
}

BUILD:

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\10\bin\10.0.20206.0\x64\midl.exe" ^
/metadata_dir "%WindowsSdkDir%References\%WindowsSDKVersion%Windows.Foundation.FoundationContract\4.0.0.0" ^
/reference "%WindowsSdkDir%References\%WindowsSDKVersion%Windows.Foundation.FoundationContract\4.0.0.0\Windows.Foundation.FoundationContract.winmd" ^
/cpp_cmd "C:\PROGRA~2\MICROS~1\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\cl.exe" ^
/notlb ^
/winrt ^
/nomidl ^
/nologo ^
/enum_class ^
/ns_prefix ^
/client none ^
/server none ^
/winmd %1 %2

run command:

bazel build //cmd:all

Generated MyType.h here:

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

Generated MyType.winmd is here:

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

Anything I'm missing?


Solution

  • Thanks @rds Here is the my own answer.

    1. Add ctx.configuration.genfiles_dir.path as /out option value in midl.bat
    2. use ctx.declare_file for winmd and .h generated file name.
    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\4.0.0.0" ^
    /reference "%WINDOWS_SDK_REFERENCE_PATH%\Windows.Foundation.FoundationContract\4.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