I have a macro that looks like this:
def ispc_cc_library(name, out, ispc_main_source_file, srcs, defines = [], **kwargs):
generated_header_filename = out
ispc_defines_list = ""
if "defines" in kwargs:
ispc_defines_list = "-D" + " -D".join(kwargs["defines"])
elif len(defines) > 0:
ispc_defines_list = "-D" + " -D".join(defines)
native.genrule(
name = "%s_ispc_gen" % name,
srcs = srcs,
outs = [name + ".o", generated_header_filename],
cmd = select({
"@platforms//os:linux": "$(location @ispc_linux_x86_64//:ispc) %s --target=avx2 --target-os=linux --arch=x86-64 --addressing=64 --pic $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generated_header_filename, name),
"@rules_ispc//:osx_arm64": "$(location @ispc_osx_arm64//:ispc) %s --target=neon --target-os=macos --arch=aarch64 --addressing=64 --pic $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generated_header_filename, name),
"@rules_ispc//:osx_x86_64": "$(location @ispc_osx_x86_64//:ispc) %s --target=sse2 --target-os=macos --arch=x86-64 --addressing=64 --pic $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generated_header_filename, name),
"@platforms//os:windows": "$(location @ispc_windows_x86_64//:ispc) %s --target=avx2 --target-os=windows --arch=x86-64 --addressing=64 $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generated_header_filename, name),
}),
tools = select({
"@platforms//os:linux": ["@ispc_linux_x86_64//:ispc"],
"@rules_ispc//:osx_arm64": ["@ispc_osx_arm64//:ispc"],
"@rules_ispc//:osx_x86_64": ["@ispc_osx_x86_64//:ispc"],
"@platforms//os:windows": ["@ispc_windows_x86_64//:ispc"],
}),
)
native.cc_library(
name = name,
srcs = [name + ".o"],
hdrs = [name + ".h"],
defines = defines,
**kwargs
)
I want to convert it to a rule. My attempt so far:
def _ispc_cc_library_impl(ctx):
info = ctx.toolchains["@rules_ispc//tools:toolchain_type"].ispc_info
default_target_os = info.default_target_os
generated_header_filename = ctx.attr.generated_header_filename
ispc_defines_list = ""
if len(ctx.attr.defines) > 0:
ispc_defines_list = "-D" + " -D".join(ctx.attr.defines)
srcs = ctx.files.srcs
inputs = depset(srcs) # see https://bazel.build/extending/rules
output_file1 = ctx.actions.declare_file(generated_header_filename)
output_file2 = ctx.actions.declare_file(ctx.attr.name + ".o")
args = ctx.actions.args()
args.add("-o", generated_header_filename)
args.add(ispc_defines_list)
args.add("--target=neon")
args.add("--target-os=%s" % default_target_os)
args.add("--arch=aarch64")
args.add("--addressing=64")
args.add("--pic")
args.add("square.ispc")#ctx.attr.ispc_main_source_file)
args.add("--header-outfile=%s" % generated_header_filename)
args.add("-o")
args.add(ctx.attr.name + ".o")
ctx.actions.run(
inputs = inputs,
outputs = [output_file1, output_file2],
arguments = [args],
executable = info.ispc_path,
)
return [
DefaultInfo(files = depset([output_file1, output_file2])),
]
ispc_library2 = rule(
implementation = _ispc_cc_library_impl,
doc = """Compiles a ISPC program and makes it available as a C++ library
This rule uses a precompiled version of ISPC v1.19.0 for compilation.""",
attrs = {
"generated_header_filename": attr.string(
doc = """
Name of the generated header file.
""",
),
"ispc_main_source_file": attr.label(
allow_single_file = [".ispc"],
doc = """
File to compile.
""",
),
"srcs": attr.label_list(
allow_files = [".ispc", ".isph"],
doc = """
The list of ISPC source files that are compiled to create the library.
Only `.ispc` and `.isph` files are permitted.
""",
),
"defines": attr.string_list(
doc = """
List of defines handed over to the ISPC compiler.
""",
),
#"out": attr.output_list(),
},
#outputs = {
# "out": "{generated_header_filename}.o"
#},
toolchains = ["@rules_ispc//tools:toolchain_type"],
)
def ispc_cc_library2(name, generated_header_filename, ispc_main_source_file, srcs, defines = [], **kwargs):
ispc_library2(
name = "%s_ispc_gen" % name,
generated_header_filename = generated_header_filename,
ispc_main_source_file = ispc_main_source_file,
srcs = srcs,
defines = defines,
**kwargs
)
native.cc_library(
name = name,
srcs = [name + ".o"],
hdrs = [name + ".h"],
defines = defines,
#deps = ["%s_ispc_gen" % name],
**kwargs
)
The repository with the source code is here (see ispc.bzl
). When I try to replace in my tests ispc_cc_library
with ispc_cc_library2
I get some errors:
ERROR: /Users/vertexwahn/rules_ispc/tests/defines/BUILD.bazel:12:17: Linking defines/libsquare.a failed: missing input file '//defines:square.o'
ERROR: /Users/vertexwahn/rules_ispc/tests/defines/BUILD.bazel:12:17: Middleman _middlemen/_S_Sdefines_Csquare-cc_library-compile failed: missing input file '//defines:square.h'
ERROR: /Users/vertexwahn/rules_ispc/tests/defines/BUILD.bazel:12:17: Linking defines/libsquare.a failed: 1 input file(s) do not exist
ERROR: /Users/vertexwahn/rules_ispc/tests/defines/BUILD.bazel:12:17: Middleman _middlemen/_S_Sdefines_Csquare-cc_library-compile failed: 1 input file(s) do not exist
ERROR: /Users/vertexwahn/rules_ispc/tests/defines/BUILD.bazel:12:17: //defines:square: missing input file '//defines:square.o'
ERROR: /Users/vertexwahn/rules_ispc/tests/defines/BUILD.bazel:12:17 Linking defines/libsquare.a failed: 1 input file(s) do not exist
The idea of ispc_library2
is to generate a header file and object file. Those two files should be added to a cc_library
. I still don't understand how I can handover those artefacts - any advices welcome!
Steps to reproduce:
git clone https://github.com/Vertexwahn/rules_ispc.git
cd rules_ispc/tests/defines
bazel build //defines:main # should fail
Properly declare the object and header output of ispc_library2
, so that the cc_library
in the macro can see and depend on them:
diff --git a/ispc.bzl b/ispc.bzl
index e548836..499c091 100644
--- a/ispc.bzl
+++ b/ispc.bzl
@@ -14,11 +14,10 @@ def _ispc_cc_library_impl(ctx):
srcs = ctx.files.srcs
inputs = depset(srcs) # see https://bazel.build/extending/rules
- output_file1 = ctx.actions.declare_file(generated_header_filename)
- output_file2 = ctx.actions.declare_file(ctx.attr.name + ".o")
+ object = ctx.actions.declare_file(ctx.attr.name + ".o")
args = ctx.actions.args()
- args.add("-o", generated_header_filename)
+ args.add("-o", object)
args.add(ispc_defines_list)
args.add("--target=neon")
args.add("--target-os=%s" % default_target_os)
@@ -26,21 +25,17 @@ def _ispc_cc_library_impl(ctx):
args.add("--addressing=64")
args.add("--pic")
args.add("square.ispc")#ctx.attr.ispc_main_source_file)
- args.add("--header-outfile=%s" % generated_header_filename)
- args.add("-o")
- args.add(ctx.attr.name + ".o")
+ args.add("--header-outfile", ctx.outputs.generated_header_filename)
ctx.actions.run(
inputs = inputs,
- outputs = [output_file1, output_file2],
+ outputs = [object, ctx.outputs.generated_header_filename],
arguments = [args],
executable = info.ispc_path,
)
return [
- #DefaultInfo()
- #DefaultInfo(files = depset([output_file1, output_file2])),
- OutputGroupInfo(out = depset([output_file1, output_file2]))
+ DefaultInfo(files = depset(direct=[object])),
]
ispc_library2 = rule(
@@ -49,7 +44,7 @@ ispc_library2 = rule(
This rule uses a precompiled version of ISPC v1.19.0 for compilation.""",
attrs = {
- "generated_header_filename": attr.string(
+ "generated_header_filename": attr.output(
doc = """
Name of the generated header file.
""",
@@ -72,11 +67,7 @@ This rule uses a precompiled version of ISPC v1.19.0 for compilation.""",
List of defines handed over to the ISPC compiler.
""",
),
- #"out": attr.output_list(),
},
- #outputs = {
- # "out": "{generated_header_filename}.o"
- #},
toolchains = ["@rules_ispc//tools:toolchain_type"],
)
@@ -91,10 +82,9 @@ def ispc_cc_library2(name, generated_header_filename, ispc_main_source_file, src
)
native.cc_library(
name = name,
- srcs = [name + ".o"],
+ srcs = [":%s_ispc_gen" % name],
hdrs = [name + ".h"],
defines = defines,
- #deps = ["%s_ispc_gen" % name],
**kwargs
)