Skip to content

Commit

Permalink
feat: ecsact_binary and ecsact_library (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaucy authored Oct 5, 2023
1 parent 846c90c commit 227d9d0
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 13 deletions.
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module(
compatibility_level = 4,
)

bazel_dep(name = "rules_cc", version = "0.0.9")
bazel_dep(name = "bazel_skylib", version = "1.4.2")
bazel_dep(name = "platforms", version = "0.0.5")

Expand Down
6 changes: 6 additions & 0 deletions ecsact/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

load("//ecsact/private:ecsact_codegen.bzl", _ecsact_codegen = "ecsact_codegen")
load("//ecsact/private:ecsact_codegen_plugin.bzl", _ecsact_codegen_plugin = "ecsact_codegen_plugin")
load("//ecsact/private:ecsact_binary.bzl", _ecsact_binary = "ecsact_binary")
load("//ecsact/private:ecsact_build_recipe.bzl", _ecsact_build_recipe = "ecsact_build_recipe")
load("//ecsact/private:ecsact_library.bzl", _ecsact_library = "ecsact_library")

ecsact_codegen = _ecsact_codegen
ecsact_codegen_plugin = _ecsact_codegen_plugin
ecsact_binary = _ecsact_binary
ecsact_build_recipe = _ecsact_build_recipe
ecsact_library = _ecsact_library
113 changes: 113 additions & 0 deletions ecsact/private/ecsact_binary.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain")
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
load("//ecsact/private:ecsact_build_recipe.bzl", "EcsactBuildRecipeInfo")

def _ecsact_binary(ctx):
cc_toolchain = find_cc_toolchain(ctx)

temp_dir = ctx.actions.declare_directory(ctx.attr.name)

inputs = []

feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
)

variables = cc_common.create_link_variables(
cc_toolchain = cc_toolchain,
feature_configuration = feature_configuration,
)

env = cc_common.get_environment_variables(
feature_configuration = feature_configuration,
action_name = ACTION_NAMES.cpp_link_dynamic_library,
variables = variables,
)

ecsact_toolchain = ctx.toolchains["//ecsact:toolchain_type"].ecsact_info

# TODO(zaucy): derive runtime library extension based on ctx and cc_toolchain
runtime_output_file = ctx.actions.declare_file("{}.dll".format(ctx.attr.name))
outputs = [runtime_output_file]
tools = [] + ecsact_toolchain.tool_files

args = ctx.actions.args()
args.add("build")
args.add_all(ctx.files.srcs)
args.add_all(ctx.files.recipes, before_each = "-r")
args.add("-o", runtime_output_file)
args.add("--temp_dir", temp_dir.path)
args.add("-f", "text")

# TODO(zaucy): detect shared library extension
preferred_output_extension = ".dll"

compiler_config = {
"compiler_type": "auto",
"compiler_path": cc_toolchain.compiler_executable,
"compiler_version": "bazel c++ toolchain",
"install_path": "",
"std_inc_paths": cc_toolchain.built_in_include_directories,
"std_lib_paths": [],
"preferred_output_extension": preferred_output_extension,
"allowed_output_extensions": [preferred_output_extension],
}

compiler_config_file = ctx.actions.declare_file("{}.compiler_config.json".format(ctx.attr.name))

ctx.actions.write(compiler_config_file, json.encode(compiler_config))

args.add("--compiler_config", compiler_config_file)

if len(ctx.files.recipes) > 1:
fail("Only 1 recipe is allowed at this time")

inputs.extend(ctx.files.srcs)
inputs.extend(ctx.files.recipes)
inputs.append(compiler_config_file)

for recipe in ctx.attr.recipes:
recipe_info = recipe[EcsactBuildRecipeInfo]
inputs.extend(recipe_info.data)

executable = ecsact_toolchain.target_tool if ecsact_toolchain.target_tool != None else ecsact_toolchain.target_tool_path

ctx.actions.run(
mnemonic = "EcsactBuild",
progress_message = "Building Ecsact Runtime %{output}",
outputs = outputs + [temp_dir],
inputs = inputs,
executable = executable,
tools = tools,
arguments = [args],
env = env,
toolchain = Label("//ecsact:toolchain_type"),
)

return [
DefaultInfo(
files = depset(outputs),
),
]

ecsact_binary = rule(
implementation = _ecsact_binary,
attrs = {
"srcs": attr.label_list(
allow_files = [".ecsact"],
),
"recipes": attr.label_list(
allow_empty = False,
mandatory = True,
providers = [EcsactBuildRecipeInfo],
),
"_cc_toolchain": attr.label(
default = Label(
"@rules_cc//cc:current_cc_toolchain",
),
),
},
toolchains = ["//ecsact:toolchain_type"] + use_cc_toolchain(),
fragments = ["cpp"],
)
66 changes: 66 additions & 0 deletions ecsact/private/ecsact_build_recipe.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
load("//ecsact/private:ecsact_codegen_plugin.bzl", "EcsactCodegenPluginInfo")

EcsactBuildRecipeInfo = provider(
doc = "",
fields = {
"recipe_path": "path to recipe yaml file",
"data": "files needed to build recipe",
},
)

def _ecsact_build_recipe(ctx):
recipe_yaml = ctx.actions.declare_file("{}.yml".format(ctx.attr.name))

sources = []
recipe_data = []

for src in ctx.files.srcs:
sources.append({
"path": src.path,
"outdir": "src",
"relative_to_cwd": True,
})
recipe_data.append(src)

for codegen_plugin in ctx.attr.codegen_plugins:
info = codegen_plugin[EcsactCodegenPluginInfo]
sources.append({
"codegen": [info.plugin],
"outdir": ctx.attr.codegen_plugins[codegen_plugin],
})

recipe = {
"name": ctx.attr.name,
"sources": sources,
"imports": ctx.attr.imports,
"exports": ctx.attr.exports,
}

ctx.actions.write(recipe_yaml, json.encode(recipe))

return [
DefaultInfo(
files = depset([recipe_yaml]),
),
EcsactBuildRecipeInfo(
recipe_path = recipe_yaml,
data = recipe_data,
),
]

ecsact_build_recipe = rule(
implementation = _ecsact_build_recipe,
attrs = {
"srcs": attr.label_list(
allow_files = True,
),
"codegen_plugins": attr.label_keyed_string_dict(
providers = [EcsactCodegenPluginInfo],
),
"imports": attr.string_list(
),
"exports": attr.string_list(
mandatory = True,
),
},
)
3 changes: 0 additions & 3 deletions ecsact/private/ecsact_codegen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ def _ecsact_codegen(ctx):
out_basename = ctx.attr.name + "/" + src.basename
outputs.append(ctx.actions.declare_file(out_basename + "." + plugin_info.output_extension))

for p in info.target_tool_path_runfiles:
tools.extend(p.files.to_list())

ctx.actions.run(
mnemonic = "EcsactCodegen",
outputs = [outdir] + outputs,
Expand Down
17 changes: 17 additions & 0 deletions ecsact/private/ecsact_library.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
EcsactLibraryInfo = provider()

def _ecsact_library(ctx):
return [EcsactLibraryInfo()]

ecsact_library = rule(
implementation = _ecsact_library,
attrs = {
"srcs": attr.label_list(
allow_files = [".ecsact"],
),
# "deps": attr.label_list(
# allow_rules = [EcsactLibraryInfo],
# ),
},
toolchains = ["//ecsact:toolchain_type"],
)
17 changes: 7 additions & 10 deletions ecsact/toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
EcsactInfo = provider(
doc = "Information about how to invoke the tool executable.",
fields = {
"target_tool": "",
"target_tool_path": "Path to the tool executable for the target platform.",
"target_tool_path_runfiles": "",
"tool_files": """Files required in runfiles to make the tool executable available.
May be empty if the target_tool_path points to a locally installed tool binary.""",
Expand All @@ -17,14 +17,13 @@ def _ecsact_toolchain_impl(ctx):
fail("Can only set one of target_tool or target_tool_path but both were set.")
if not ctx.attr.target_tool and not ctx.attr.target_tool_path:
fail("Must set one of target_tool or target_tool_path.")
if ctx.attr.target_tool and ctx.attr.target_tool_path_runfiles:
fail("Cannot use target_tool_path_runfiles with target_tool.")

tool_files = []
target_tool_path = ctx.attr.target_tool_path

if ctx.attr.target_tool:
tool_files = ctx.attr.target_tool.files.to_list()
tool_files = ctx.attr.target_tool[DefaultInfo].files.to_list()
tool_files.extend(ctx.attr.target_tool[DefaultInfo].default_runfiles.files.to_list())
target_tool_path = tool_files[0].path

# Make the $(ECSACT_BIN) variable available in places like genrules.
Expand All @@ -36,9 +35,12 @@ def _ecsact_toolchain_impl(ctx):
files = depset(tool_files),
runfiles = ctx.runfiles(files = tool_files),
)

target_tool = ctx.attr.target_tool[DefaultInfo].files_to_run if ctx.attr.target_tool else None

ecsact_info = EcsactInfo(
target_tool = target_tool,
target_tool_path = target_tool_path,
target_tool_path_runfiles = ctx.attr.target_tool_path_runfiles,
tool_files = tool_files,
)

Expand All @@ -65,11 +67,6 @@ ecsact_toolchain = rule(
doc = "Path to an existing executable for the target platform.",
mandatory = False,
),
"target_tool_path_runfiles": attr.label_list(
doc = "List of files needed at runtime for `target_tool_path`. Not valid with `target_tool`.",
mandatory = False,
allow_files = True,
),
},
doc = """Defines a ecsact compiler/runtime toolchain.
Expand Down

0 comments on commit 227d9d0

Please sign in to comment.