Add c_embed_data build tool (#5540)
Add the build tool to generate c embed data for testing. The code is
used to bypass fileIO and it can be used with the C API.
Change the build rule of iree_bytecode_module to include the c embed
codegen. The user needs to assign a non-empty value in the "c_output"
field.
build_tools/embed_data/generate_embed_data_main.cc now can produce
either c code or c++ code, controlled by --c_output flag.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9958c07..92f7dfe 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -218,6 +218,7 @@
include(iree_tablegen_library)
include(iree_tablegen_doc)
include(iree_cc_embed_data)
+include(iree_c_embed_data)
include(iree_bytecode_module)
include(iree_c_module)
include(iree_python)
diff --git a/build_tools/bazel_to_cmake/bazel_to_cmake_converter.py b/build_tools/bazel_to_cmake/bazel_to_cmake_converter.py
index 72ce425..5d86fae 100644
--- a/build_tools/bazel_to_cmake/bazel_to_cmake_converter.py
+++ b/build_tools/bazel_to_cmake/bazel_to_cmake_converter.py
@@ -447,6 +447,37 @@
f"{flatten_block}"
f" PUBLIC\n)\n\n")
+ def c_embed_data(self,
+ name,
+ srcs,
+ c_file_output,
+ h_file_output,
+ testonly=None,
+ strip_prefix=None,
+ flatten=None,
+ identifier=None,
+ **kwargs):
+ if identifier:
+ self._convert_unimplemented_function("c_embed_data",
+ name + " has identifier")
+ name_block = _convert_string_arg_block("NAME", name, quote=False)
+ srcs_block = _convert_srcs_block(srcs)
+ c_file_output_block = _convert_string_arg_block("C_FILE_OUTPUT",
+ c_file_output)
+ h_file_output_block = _convert_string_arg_block("H_FILE_OUTPUT",
+ h_file_output)
+ testonly_block = _convert_option_block("TESTONLY", testonly)
+ flatten_block = _convert_option_block("FLATTEN", flatten)
+
+ self.converter.body += (f"iree_c_embed_data(\n"
+ f"{name_block}"
+ f"{srcs_block}"
+ f"{c_file_output_block}"
+ f"{h_file_output_block}"
+ f"{testonly_block}"
+ f"{flatten_block}"
+ f" PUBLIC\n)\n\n")
+
def spirv_kernel_cc_library(self, name, srcs):
name_block = _convert_string_arg_block("NAME", name, quote=False)
srcs_block = _convert_srcs_block(srcs)
@@ -462,10 +493,12 @@
flags=None,
translate_tool=None,
cc_namespace=None,
+ c_output=None,
testonly=None):
name_block = _convert_string_arg_block("NAME", name, quote=False)
src_block = _convert_string_arg_block("SRC", src)
namespace_block = _convert_string_arg_block("CC_NAMESPACE", cc_namespace)
+ c_output_block = _convert_option_block("C_OUTPUT", c_output)
translate_tool_block = _convert_translate_tool_block(translate_tool)
flags_block = _convert_string_list_block("FLAGS", flags)
testonly_block = _convert_option_block("TESTONLY", testonly)
@@ -474,6 +507,7 @@
f"{name_block}"
f"{src_block}"
f"{namespace_block}"
+ f"{c_output_block}"
f"{translate_tool_block}"
f"{flags_block}"
f"{testonly_block}"
diff --git a/build_tools/cmake/iree_bytecode_module.cmake b/build_tools/cmake/iree_bytecode_module.cmake
index 0af567a..e297083 100644
--- a/build_tools/cmake/iree_bytecode_module.cmake
+++ b/build_tools/cmake/iree_bytecode_module.cmake
@@ -26,6 +26,7 @@
# TRANSLATE_TOOL: Translation tool to invoke (CMake target). The default
# tool is "iree-translate".
# CC_NAMESPACE: Wraps everything in a C++ namespace.
+# C_OUTPUT: Control flag to generate c embed code instead.
# PUBLIC: Add this so that this library will be exported under ${PACKAGE}::
# Also in IDE, target will appear in ${PACKAGE} folder while non PUBLIC
# will be in ${PACKAGE}/internal.
@@ -39,7 +40,7 @@
function(iree_bytecode_module)
cmake_parse_arguments(
_RULE
- "PUBLIC;TESTONLY"
+ "PUBLIC;TESTONLY;C_OUTPUT"
"NAME;SRC;TRANSLATE_TOOL;CC_NAMESPACE"
"FLAGS"
${ARGN}
@@ -104,4 +105,22 @@
"${_TESTONLY_ARG}"
)
endif()
+
+ if(_RULE_C_OUTPUT)
+ iree_c_embed_data(
+ NAME
+ "${_RULE_NAME}_c"
+ IDENTIFIER
+ "${_RULE_NAME}_c"
+ GENERATED_SRCS
+ "${_RULE_NAME}.vmfb"
+ C_FILE_OUTPUT
+ "${_RULE_NAME}_c.c"
+ H_FILE_OUTPUT
+ "${_RULE_NAME}_c.h"
+ FLATTEN
+ "${_PUBLIC_ARG}"
+ "${_TESTONLY_ARG}"
+ )
+ endif()
endfunction()
diff --git a/build_tools/cmake/iree_c_embed_data.cmake b/build_tools/cmake/iree_c_embed_data.cmake
new file mode 100644
index 0000000..0037daf
--- /dev/null
+++ b/build_tools/cmake/iree_c_embed_data.cmake
@@ -0,0 +1,97 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include(CMakeParseArguments)
+
+# iree_c_embed_data()
+#
+# CMake function to imitate Bazel's c_embed_data rule.
+#
+# Parameters:
+# NAME: Name of target (see Note).
+# SRCS: List of source files to embed.
+# GENERATED_SRCS: List of generated source files to embed.
+# C_FILE_OUTPUT: The C implementation file to output.
+# H_FILE_OUTPUT: The H header file to output.
+# STRIP_PREFIX: Strips this verbatim prefix from filenames (in the TOC).
+# FLATTEN: Removes all directory components from filenames (in the TOC).
+# IDENTIFIER: The identifier to use in generated names (defaults to name).
+# PUBLIC: Add this so that this library will be exported under ${PACKAGE}::
+# Also in IDE, target will appear in ${PACKAGE} folder while non PUBLIC will be
+# in ${PACKAGE}/internal.
+# TESTONLY: When added, this target will only be built if user passes
+# -DIREE_BUILD_TESTS=ON to CMake.
+# TODO(scotttodd): Support passing KWARGS down into iree_cc_library?
+#
+function(iree_c_embed_data)
+ cmake_parse_arguments(
+ _RULE
+ "PUBLIC;TESTONLY;FLATTEN"
+ "NAME;IDENTIFIER;STRIP_PREFIX;C_FILE_OUTPUT;H_FILE_OUTPUT"
+ "SRCS;GENERATED_SRCS"
+ ${ARGN}
+ )
+
+ if(_RULE_TESTONLY AND NOT IREE_BUILD_TESTS)
+ return()
+ endif()
+
+ if(DEFINED _RULE_IDENTIFIER)
+ set(_IDENTIFIER ${_RULE_IDENTIFIER})
+ else()
+ set(_IDENTIFIER ${_RULE_NAME})
+ endif()
+
+ set(_ARGS)
+ list(APPEND _ARGS "--output_header=${_RULE_H_FILE_OUTPUT}")
+ list(APPEND _ARGS "--output_impl=${_RULE_C_FILE_OUTPUT}")
+ list(APPEND _ARGS "--identifier=${_IDENTIFIER}")
+ list(APPEND _ARGS "--c_output=true")
+ if(DEFINED _RULE_STRIP_PREFIX})
+ list(APPEND _ARGS "--strip_prefix=${_RULE_STRIP_PREFIX}")
+ endif()
+ if(DEFINED _RULE_FLATTEN})
+ list(APPEND _ARGS "--flatten")
+ endif()
+
+ foreach(SRC ${_RULE_SRCS})
+ list(APPEND _ARGS "${CMAKE_CURRENT_SOURCE_DIR}/${SRC}")
+ endforeach(SRC)
+ foreach(SRC ${_RULE_GENERATED_SRCS})
+ list(APPEND _ARGS "${SRC}")
+ endforeach(SRC)
+
+ iree_get_executable_path(_EXE_PATH generate_embed_data)
+
+ add_custom_command(
+ OUTPUT "${_RULE_H_FILE_OUTPUT}" "${_RULE_C_FILE_OUTPUT}"
+ COMMAND ${_EXE_PATH} ${_ARGS}
+ DEPENDS ${_EXE_PATH} ${_RULE_SRCS} ${_RULE_GENERATED_SRCS}
+ )
+
+ if(_RULE_TESTONLY)
+ set(_TESTONLY_ARG "TESTONLY")
+ endif()
+ if(_RULE_PUBLIC)
+ set(_PUBLIC_ARG "PUBLIC")
+ endif()
+
+ iree_cc_library(
+ NAME ${_RULE_NAME}
+ HDRS "${_RULE_H_FILE_OUTPUT}"
+ SRCS "${_RULE_C_FILE_OUTPUT}"
+ "${_PUBLIC_ARG}"
+ "${_TESTONLY_ARG}"
+ )
+endfunction()
diff --git a/build_tools/cmake/iree_cc_embed_data.cmake b/build_tools/cmake/iree_cc_embed_data.cmake
index 7eeac23..893c2e9 100644
--- a/build_tools/cmake/iree_cc_embed_data.cmake
+++ b/build_tools/cmake/iree_cc_embed_data.cmake
@@ -62,6 +62,7 @@
list(APPEND _ARGS "--output_header=${_RULE_H_FILE_OUTPUT}")
list(APPEND _ARGS "--output_impl=${_RULE_CC_FILE_OUTPUT}")
list(APPEND _ARGS "--identifier=${_IDENTIFIER}")
+ list(APPEND _ARGS "--c_output=false")
if(DEFINED _RULE_CPP_NAMESPACE)
list(APPEND _ARGS "--cpp_namespace=${_RULE_CPP_NAMESPACE}")
endif()
@@ -79,7 +80,7 @@
list(APPEND _ARGS "${SRC}")
endforeach(SRC)
- iree_get_executable_path(_EXE_PATH generate_cc_embed_data)
+ iree_get_executable_path(_EXE_PATH generate_embed_data)
add_custom_command(
OUTPUT "${_RULE_H_FILE_OUTPUT}" "${_RULE_CC_FILE_OUTPUT}"
diff --git a/build_tools/embed_data/BUILD b/build_tools/embed_data/BUILD
index 37097f6..0ade681 100644
--- a/build_tools/embed_data/BUILD
+++ b/build_tools/embed_data/BUILD
@@ -14,7 +14,7 @@
# Generates source files with embedded file contents.
-load(":build_defs.bzl", "cc_embed_data")
+load(":build_defs.bzl", "c_embed_data", "cc_embed_data")
package(
default_visibility = ["//visibility:public"],
@@ -23,8 +23,8 @@
)
cc_binary(
- name = "generate_cc_embed_data",
- srcs = ["generate_cc_embed_data_main.cc"],
+ name = "generate_embed_data",
+ srcs = ["generate_embed_data_main.cc"],
deps = [
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/flags:parse",
@@ -66,3 +66,25 @@
"//iree/testing:gtest_main",
],
)
+
+c_embed_data(
+ name = "testembed1_c",
+ # do not sort
+ srcs = [
+ "file1.txt",
+ "data/file2.txt",
+ ],
+ c_file_output = "testembed1_c.c",
+ flatten = True,
+ h_file_output = "testembed1_c.h",
+)
+
+cc_test(
+ name = "c_embed_data_test",
+ srcs = ["c_embed_data_test.cc"],
+ deps = [
+ ":testembed1_c",
+ "//iree/testing:gtest",
+ "//iree/testing:gtest_main",
+ ],
+)
diff --git a/build_tools/embed_data/CMakeLists.txt b/build_tools/embed_data/CMakeLists.txt
index 7f28f75..92ac014 100644
--- a/build_tools/embed_data/CMakeLists.txt
+++ b/build_tools/embed_data/CMakeLists.txt
@@ -13,16 +13,17 @@
# limitations under the License.
if(NOT CMAKE_CROSSCOMPILING)
- add_executable(generate_cc_embed_data)
- target_sources(generate_cc_embed_data PRIVATE generate_cc_embed_data_main.cc)
- set_target_properties(generate_cc_embed_data PROPERTIES OUTPUT_NAME generate_cc_embed_data)
+ add_executable(generate_embed_data)
+ target_sources(generate_embed_data PRIVATE generate_embed_data_main.cc)
+ set_target_properties(generate_embed_data PROPERTIES OUTPUT_NAME generate_embed_data)
- target_link_libraries(generate_cc_embed_data
+ target_link_libraries(generate_embed_data
absl::flags
absl::flags_parse
absl::strings
)
- install(TARGETS generate_cc_embed_data
- COMPONENT generate_cc_embed_data
+
+ install(TARGETS generate_embed_data
+ COMPONENT generate_embed_data
RUNTIME DESTINATION bin)
endif()
diff --git a/build_tools/embed_data/build_defs.bzl b/build_tools/embed_data/build_defs.bzl
index 872542a..bb16601 100644
--- a/build_tools/embed_data/build_defs.bzl
+++ b/build_tools/embed_data/build_defs.bzl
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Embeds data files into a C++ module."""
+"""Embeds data files into a C or C++ module."""
def cc_embed_data(
name,
@@ -57,7 +57,7 @@
identifier: The identifier to use in generated names (defaults to name).
**kwargs: Args to pass to the cc_library.
"""
- generator = "//build_tools/embed_data:generate_cc_embed_data"
+ generator = "//build_tools/embed_data:generate_embed_data"
generator_location = "$(location %s)" % generator
if identifier == None:
identifier = name
@@ -66,6 +66,7 @@
cc_file_output,
)
flags += " --identifier='%s'" % (identifier,)
+ flags += " --c_output=false"
if cpp_namespace != None:
flags += " --cpp_namespace='%s'" % (cpp_namespace,)
if strip_prefix != None:
@@ -91,3 +92,87 @@
testonly = testonly,
**kwargs
)
+
+def c_embed_data(
+ name,
+ srcs,
+ c_file_output,
+ h_file_output,
+ testonly = False,
+ strip_prefix = None,
+ flatten = False,
+ identifier = None,
+ **kwargs):
+ """Embeds 'srcs' into a C module.
+
+ Generates a header like:
+ #if __cplusplus
+ extern "C" {
+ #endif // __cplusplus
+ struct FileToc {
+ const char* name; // the file's original name
+ const char* data; // beginning of the file
+ size_t size; // length of the file
+ };
+ #if __cplusplus
+ }
+ #endif // __cplusplus
+
+ #if __cplusplus
+ extern "C" {
+ #endif // __cplusplus
+ const struct FileToc* this_rule_name__create();
+ #if __cplusplus
+ }
+ #endif // __cplusplus
+
+ The 'this_rule_name()' function will return an array of FileToc
+ structs terminated by one that has NULL 'name' and 'data' fields.
+ The 'data' field always has an extra null terminator at the end (which
+ is not included in the size).
+
+ Args:
+ name: The rule name, which will also be the identifier of the generated
+ code symbol.
+ srcs: List of files to embed.
+ c_file_output: The C implementation file to output.
+ h_file_output: The H header file to output.
+ testonly: If True, only testonly targets can depend on this target.
+ strip_prefix: Strips this verbatim prefix from filenames (in the TOC).
+ flatten: Removes all directory components from filenames (in the TOC).
+ identifier: The identifier to use in generated names (defaults to name).
+ **kwargs: Args to pass to the cc_library.
+ """
+ generator = "//build_tools/embed_data:generate_embed_data"
+ generator_location = "$(location %s)" % generator
+ if identifier == None:
+ identifier = name
+ flags = "--output_header='$(location %s)' --output_impl='$(location %s)'" % (
+ h_file_output,
+ c_file_output,
+ )
+ flags += " --c_output=true"
+ flags += " --identifier='%s'" % (identifier,)
+ if strip_prefix != None:
+ flags += " --strip_prefix='%s'" % (strip_prefix,)
+ if flatten:
+ flags += " --flatten"
+
+ native.genrule(
+ name = name + "__generator",
+ srcs = srcs,
+ outs = [
+ c_file_output,
+ h_file_output,
+ ],
+ tools = [generator],
+ cmd = "%s $(SRCS) %s" % (generator_location, flags),
+ testonly = testonly,
+ )
+ native.cc_library(
+ name = name,
+ hdrs = [h_file_output],
+ srcs = [c_file_output],
+ testonly = testonly,
+ **kwargs
+ )
diff --git a/build_tools/embed_data/c_embed_data_test.cc b/build_tools/embed_data/c_embed_data_test.cc
new file mode 100644
index 0000000..a112907
--- /dev/null
+++ b/build_tools/embed_data/c_embed_data_test.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "build_tools/embed_data/testembed1_c.h"
+#include "iree/testing/gtest.h"
+
+namespace {
+
+TEST(Generator, TestContents) {
+ auto* toc1 = testembed1_c_create();
+ ASSERT_EQ("file1.txt", std::string(toc1->name));
+ ASSERT_EQ(R"(Are you '"Still"' here?)"
+ "\n",
+ std::string(toc1->data));
+ ASSERT_EQ(24, toc1->size);
+ ASSERT_EQ(0, *(toc1->data + toc1->size));
+
+ ++toc1;
+ ASSERT_EQ("file2.txt", std::string(toc1->name));
+ ASSERT_EQ(R"(¯\_(ツ)_/¯)"
+ "\n",
+ std::string(toc1->data));
+ ASSERT_EQ(14, toc1->size);
+ ASSERT_EQ(0, *(toc1->data + toc1->size));
+
+ ++toc1;
+ ASSERT_EQ(nullptr, toc1->name);
+ ASSERT_EQ(nullptr, toc1->data);
+}
+
+} // namespace
diff --git a/build_tools/embed_data/generate_cc_embed_data_main.cc b/build_tools/embed_data/generate_embed_data_main.cc
similarity index 68%
rename from build_tools/embed_data/generate_cc_embed_data_main.cc
rename to build_tools/embed_data/generate_embed_data_main.cc
index 0ded0e6..137479c 100644
--- a/build_tools/embed_data/generate_cc_embed_data_main.cc
+++ b/build_tools/embed_data/generate_embed_data_main.cc
@@ -25,12 +25,25 @@
ABSL_FLAG(std::string, identifier, "resources",
"name of the resources function");
ABSL_FLAG(std::string, output_header, "", "output header file");
-ABSL_FLAG(std::string, output_impl, "", "output cc impl file");
+ABSL_FLAG(std::string, output_impl, "", "output impl file");
ABSL_FLAG(std::string, cpp_namespace, "", "generate in a c++ namespace");
+ABSL_FLAG(bool, c_output, false, "generate a c output");
ABSL_FLAG(std::string, strip_prefix, "", "strip prefix from filenames");
ABSL_FLAG(bool, flatten, false,
"whether to flatten the directory structure (only include basename)");
+void GenerateExternCOpen(std::ofstream& f) {
+ f << "\n#if __cplusplus\n";
+ f << "extern \"C\" {\n";
+ f << "#endif // __cplusplus\n";
+}
+
+void GenerateExternCClose(std::ofstream& f) {
+ f << "#if __cplusplus\n";
+ f << "}\n";
+ f << "#endif // __cplusplus\n\n";
+}
+
void GenerateNamespaceOpen(std::ofstream& f) {
const auto& ns = absl::GetFlag(FLAGS_cpp_namespace);
if (ns.empty()) return;
@@ -54,32 +67,58 @@
}
void GenerateTocStruct(std::ofstream& f) {
+ const auto& c_output = absl::GetFlag(FLAGS_c_output);
f << "#ifndef IREE_FILE_TOC\n";
f << "#define IREE_FILE_TOC\n";
- f << "namespace iree {\n";
+ if (c_output) {
+ GenerateExternCOpen(f);
+ } else {
+ f << "namespace iree {\n";
+ }
f << "struct FileToc {\n";
f << " const char* name; // the file's original name\n";
f << " const char* data; // beginning of the file\n";
- f << " std::size_t size; // length of the file\n";
- f << "};\n";
- f << "} // namespace iree\n";
+ if (c_output) {
+ f << " size_t size; // length of the file\n";
+ f << "};\n";
+ GenerateExternCClose(f);
+ } else {
+ f << " std::size_t size; // length of the file\n";
+ f << "};\n";
+ f << "} // namespace iree\n";
+ }
f << "#endif // IREE_FILE_TOC\n";
}
bool GenerateHeader(const std::string& header_file,
const std::vector<std::string>& toc_files) {
std::ofstream f(header_file, std::ios::out | std::ios::trunc);
+ const auto& c_output = absl::GetFlag(FLAGS_c_output);
+
f << "#pragma once\n"; // Pragma once isn't great but is the best we can do.
- f << "#include <cstddef>\n";
- GenerateTocStruct(f);
- GenerateNamespaceOpen(f);
- f << "extern const struct ::iree::FileToc* "
- << absl::GetFlag(FLAGS_identifier) << "_create();\n";
- f << "static inline std::size_t " << absl::GetFlag(FLAGS_identifier)
- << "_size() { \n";
- f << " return " << toc_files.size() << ";\n";
- f << "}\n";
- GenerateNamespaceClose(f);
+ if (c_output) {
+ f << "#include <stddef.h>\n";
+ GenerateTocStruct(f);
+ GenerateExternCOpen(f);
+ f << "const struct FileToc* " << absl::GetFlag(FLAGS_identifier)
+ << "_create();\n";
+ f << "static inline size_t " << absl::GetFlag(FLAGS_identifier)
+ << "_size() {\n";
+ f << " return " << toc_files.size() << ";\n";
+ f << "}\n";
+ GenerateExternCClose(f);
+ } else {
+ f << "#include <cstddef>\n";
+ GenerateTocStruct(f);
+ GenerateNamespaceOpen(f);
+ f << "extern const struct ::iree::FileToc* "
+ << absl::GetFlag(FLAGS_identifier) << "_create();\n";
+ f << "static inline std::size_t " << absl::GetFlag(FLAGS_identifier)
+ << "_size() { \n";
+ f << " return " << toc_files.size() << ";\n";
+ f << "}\n";
+ GenerateNamespaceClose(f);
+ }
f.close();
return f.good();
}
@@ -109,9 +148,16 @@
const std::vector<std::string>& input_files,
const std::vector<std::string>& toc_files) {
std::ofstream f(impl_file, std::ios::out | std::ios::trunc);
- f << "#include <cstddef>\n";
- GenerateTocStruct(f);
- GenerateNamespaceOpen(f);
+ const auto& c_output = absl::GetFlag(FLAGS_c_output);
+ if (c_output) {
+ f << "#include <stddef.h>\n";
+ f << "#include <stdalign.h>\n";
+ GenerateTocStruct(f);
+ } else {
+ f << "#include <cstddef>\n";
+ GenerateTocStruct(f);
+ GenerateNamespaceOpen(f);
+ }
for (size_t i = 0, e = input_files.size(); i < e; ++i) {
f << "alignas(alignof(void*)) static char const file_" << i << "[] = {\n";
std::string contents;
@@ -128,7 +174,11 @@
}
f << "};\n";
}
- f << "static const struct ::iree::FileToc toc[] = {\n";
+ if (c_output) {
+ f << "static const struct FileToc toc[] = {\n";
+ } else {
+ f << "static const struct ::iree::FileToc toc[] = {\n";
+ }
assert(input_files.size() == toc_files.size());
for (size_t i = 0, e = input_files.size(); i < e; ++i) {
f << " {\n";
@@ -137,14 +187,22 @@
f << " sizeof(file_" << i << ") - 1\n";
f << " },\n";
}
- f << " {nullptr, nullptr, 0},\n";
- f << "};\n";
- f << "const struct ::iree::FileToc* " << absl::GetFlag(FLAGS_identifier)
- << "_create() {\n";
+ if (c_output) {
+ f << " {NULL, NULL, 0},\n";
+ f << "};\n";
+ f << "const struct FileToc* " << absl::GetFlag(FLAGS_identifier)
+ << "_create() {\n";
+ } else {
+ f << " {nullptr, nullptr, 0},\n";
+ f << "};\n";
+ f << "const struct ::iree::FileToc* " << absl::GetFlag(FLAGS_identifier)
+ << "_create() {\n";
+ }
f << " return &toc[0];\n";
f << "}\n";
-
- GenerateNamespaceClose(f);
+ if (!c_output) {
+ GenerateNamespaceClose(f);
+ }
f.close();
return f.good();
}
@@ -175,7 +233,12 @@
}
toc_files.push_back(toc_file);
}
-
+ // Can either generate the c or c++ output.
+ if (!absl::GetFlag(FLAGS_cpp_namespace).empty() &&
+ absl::GetFlag(FLAGS_c_output)) {
+ std::cerr << "Can only generate either c or c++ output.\n";
+ return 1;
+ }
if (!absl::GetFlag(FLAGS_output_header).empty()) {
if (!GenerateHeader(absl::GetFlag(FLAGS_output_header), toc_files)) {
std::cerr << "Error generating headers.\n";
diff --git a/iree/tools/compilation.bzl b/iree/tools/compilation.bzl
index b3a85be..159df41 100644
--- a/iree/tools/compilation.bzl
+++ b/iree/tools/compilation.bzl
@@ -14,7 +14,7 @@
"""Rules for compiling IREE executables, modules, and archives."""
-load("//build_tools/embed_data:build_defs.bzl", "cc_embed_data")
+load("//build_tools/embed_data:build_defs.bzl", "c_embed_data", "cc_embed_data")
# TODO(benvanik): port to a full starlark rule, document, etc.
def iree_bytecode_module(
@@ -23,6 +23,7 @@
flags = ["-iree-mlir-to-vm-bytecode-module"],
translate_tool = "//iree/tools:iree-translate",
cc_namespace = None,
+ c_output = False,
**kwargs):
native.genrule(
name = name,
@@ -57,3 +58,14 @@
flatten = True,
**kwargs
)
+ # Embed the module for use in C.
+ if c_output:
+ c_embed_data(
+ name = "%s_c" % (name),
+ identifier = "%s_c" % (name),
+ srcs = ["%s.vmfb" % (name)],
+ c_file_output = "%s_c.c" % (name),
+ h_file_output = "%s_c.h" % (name),
+ flatten = True,
+ **kwargs
+ )