Repository: conan-io/conan-center-index

Issue:
[request] <flatcc>/<0.6.0>
### Package Details
  * Package Name/Version: **flatcc/0.6.0**
  * Website: **https://github.com/dvidelabs/flatcc**
  * Source code: **https://github.com/dvidelabs/flatcc**


### Description Of The Library / Tool
Existing recipes flatbuffers and flatc provide a flatbuffers-to-C++ compiler. The official flatbuffers-to-C compiler is flatcc.

Quote from http://google.github.io/flatbuffers/flatbuffers_guide_use_c.html :

> The C language binding exists in a separate project named FlatCC.
> The flatcc C schema compiler can generate code offline as well as online via a C library. It can also generate buffer verifiers and fast JSON parsers, printers.
> Great care has been taken to ensure compatibily with the main flatc project.


Discussion:

Resolving patch:
diff --git a/recipes/flatcc/all/conanfile.py b/recipes/flatcc/all/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/flatcc/all/conanfile.py
@@ -0,0 +1,110 @@
+import os
+from conans import CMake, ConanFile, tools
+from conans.errors import ConanInvalidConfiguration
+
+class FlatccConan(ConanFile):
+    name = "flatcc"
+    description = "C language binding for Flatbuffers, an efficient cross platform serialization library"
+    topics = "conan", "flatbuffers", "serialization"
+    url = "https://github.com/conan-io/conan-center-index"
+    homepage = "https://github.com/dvidelabs/flatcc"
+    license = "Apache-2.0"
+    options = { "shared": [True, False],
+                "fPIC": [True, False],
+                "portable": [True, False],
+                "gnu_posix_memalign": [True, False],
+                "runtime_lib_only": [True, False],
+                "verify_assert": [True, False],
+                "verify_trace": [True, False],
+                "reflection": [True, False],
+                "native_optim": [True, False],
+                "fast_double": [True, False],
+                "ignore_const_condition": [True, False],
+    }
+    default_options = { "shared": False,
+                        "fPIC": True,
+                        "portable": False,
+                        "gnu_posix_memalign": True,
+                        "runtime_lib_only": False,
+                        "verify_assert": False,
+                        "verify_trace": False,
+                        "reflection": True,
+                        "native_optim": False,
+                        "fast_double": False,
+                        "ignore_const_condition": False
+    }
+    settings = "os", "arch", "compiler", "build_type"
+    generators = "cmake"
+    exports_sources = ["CMakeLists.txt"]
+
+    _cmake = None
+
+
+    @property
+    def _source_subfolder(self):
+        return "source_subfolder"
+
+    @property
+    def _build_subfolder(self):
+        return "build_subfolder"
+
+    def config_options(self):
+        if self.settings.os == "Windows":
+            del self.options.fPIC
+
+    def configure(self):
+        if self.settings.os == "Windows":
+            if self.settings.compiler == "Visual Studio" and self.options.shared:
+                #Building flatcc shared libs with Visual Studio is broken
+                raise ConanInvalidConfiguration("Building flatcc libraries shared is not supported")
+            if self.settings.compiler == "gcc":
+                raise ConanInvalidConfiguration("Building flatcc with MinGW is not supported")
+        if self.options.shared:
+            del self.options.fPIC
+
+    def source(self):
+        tools.get(**self.conan_data["sources"][self.version])
+        extracted_dir = self.name + "-" + self.version
+        os.rename(extracted_dir, self._source_subfolder)
+
+    def _configure_cmake(self):
+        if not self._cmake:
+            self._cmake = CMake(self)
+            self._cmake.definitions["FLATCC_PORTABLE"] = self.options.portable
+            self._cmake.definitions["FLATCC_GNU_POSIX_MEMALIGN"] = self.options.gnu_posix_memalign
+            self._cmake.definitions["FLATCC_RTONLY"] = self.options.runtime_lib_only
+            self._cmake.definitions["FLATCC_INSTALL"] = True
+            self._cmake.definitions["FLATCC_COVERAGE"] = False
+            self._cmake.definitions["FLATCC_DEBUG_VERIFY"] = self.options.verify_assert
+            self._cmake.definitions["FLATCC_TRACE_VERIFY"] = self.options.verify_trace
+            self._cmake.definitions["FLATCC_REFLECTION"] = self.options.reflection
+            self._cmake.definitions["FLATCC_NATIVE_OPTIM"] = self.options.native_optim
+            self._cmake.definitions["FLATCC_FAST_DOUBLE"] = self.options.fast_double
+            self._cmake.definitions["FLATCC_IGNORE_CONST_COND"] = self.options.ignore_const_condition
+            self._cmake.definitions["FLATCC_TEST"] = False
+            self._cmake.configure(build_folder=self._build_subfolder)
+        return self._cmake
+
+    def build(self):
+        cmake = self._configure_cmake()
+        cmake.build()
+
+
+    def package(self):
+        cmake = self._configure_cmake()
+        cmake.install()
+        if self.settings.build_type == "Debug" and not tools.os_info.is_windows:
+            debug_suffix = "_d" if self.settings.build_type == "Debug" else ""
+            os.rename(os.path.join(self.package_folder, "bin", "flatcc%s" % debug_suffix),
+                      os.path.join(self.package_folder, "bin", "flatcc"))
+        # Copy license file
+        self.copy("LICENSE", dst="licenses", src=self._source_subfolder)
+
+    def package_info(self):
+        bin_path = os.path.join(self.package_folder, "bin")
+        self.output.info('Appending PATH environment variable: %s' % bin_path)
+        self.env_info.PATH.append(bin_path)
+        debug_suffix = "_d" if self.settings.build_type == "Debug" else ""
+        if not self.options.runtime_lib_only:
+            self.cpp_info.libs.append("flatcc%s" % debug_suffix)
+        self.cpp_info.libs.append("flatccrt%s" % debug_suffix)


Test patch:
diff --git a/recipes/flatcc/all/test_package/CMakeLists.txt b/recipes/flatcc/all/test_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/flatcc/all/test_package/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 2.8)
+project(flatcc_example)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+
+set(INC_DIR "${PROJECT_SOURCE_DIR}/include")
+set(GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
+set(FBS_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+
+include_directories("${GEN_DIR}" "${INC_DIR}")
+
+add_executable(monster monster.c)
+
+#On MacOS System Integrity Protection (SIP) will clear the DYLD_LIBRARY_PATH variable.
+#As a result calling flatcc from cmake will currently not work if the flatcc executable
+# is linked shared. As a workaround we generate the flatbuffer C files in the Conan recipe
+# when on MacOS and flatcc option 'shared' is True.
+if (NOT MACOS_SIP_WORKAROUND)
+    add_custom_target(gen_monster_fbs ALL)
+    add_custom_command (
+        TARGET gen_monster_fbs
+        COMMAND cmake -E make_directory "${GEN_DIR}"
+        COMMAND flatcc -a -o "${GEN_DIR}" "${FBS_DIR}/monster.fbs"
+        DEPENDS flatcc "${FBS_DIR}/monster.fbs"
+    )
+
+    add_dependencies(monster gen_monster_fbs)
+endif()
+
+
+target_link_libraries(monster ${CONAN_LIBS})
diff --git a/recipes/flatcc/all/test_package/conanfile.py b/recipes/flatcc/all/test_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/flatcc/all/test_package/conanfile.py
@@ -0,0 +1,27 @@
+import os.path
+
+from conans import ConanFile, CMake, tools, RunEnvironment
+
+
+class FlatccTestConan(ConanFile):
+    settings = "os", "compiler", "build_type", "arch"
+    generators = "cmake"
+
+    def build(self):
+        env_build = RunEnvironment(self)
+        with tools.environment_append(env_build.vars):
+            cmake = CMake(self)
+            if tools.os_info.is_macos and self.options["flatcc"].shared:
+                # Because of MacOS System Integraty Protection it is currently not possible to run the flatcc
+                # executable from cmake if it is linked shared. As a temporary work-around run flatcc here in
+                # the build function.
+                tools.mkdir(os.path.join(self.build_folder, "generated"))
+                self.run("flatcc -a -o " + os.path.join(self.build_folder, "generated") + " " + os.path.join(self.source_folder, "monster.fbs"), run_environment=True)
+                cmake.definitions["MACOS_SIP_WORKAROUND"] = True
+            cmake.configure()
+            cmake.build()
+
+    def test(self):
+        if not tools.cross_building(self):
+            bin_path = os.path.join(self.build_folder, "bin", "monster")
+            self.run(bin_path, cwd=self.source_folder, run_environment=True)
diff --git a/recipes/flatcc/all/test_package/monster.c b/recipes/flatcc/all/test_package/monster.c
new file mode 100644
--- /dev/null
+++ b/recipes/flatcc/all/test_package/monster.c
@@ -0,0 +1,350 @@
+// Example on how to build a Monster FlatBuffer.
+
+
+// Note: while some older C89 compilers are supported when
+// -DFLATCC_PORTABLE is defined, this particular sample is known not to
+// not work with MSVC 2010 (MSVC 2013 is OK) due to inline variable
+// declarations. These are easily move to the start of code blocks, but
+// since we follow the step-wise tutorial, it isn't really practical
+// in this case. The comment style is technically also in violation of C89.
+
+
+#include "monster_builder.h" // Generated by `flatcc`.
+// <string.h> and <assert.h> already included.
+
+// Convenient namespace macro to manage long namespace prefix.
+// The ns macro makes it possible to write `ns(Monster_create(...))`
+// instead of `MyGame_Sample_Monster_create(...)`
+#undef ns
+#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
+
+// A helper to simplify creating vectors from C-arrays.
+#define c_vec_len(V) (sizeof(V)/sizeof((V)[0]))
+
+// This allows us to verify result in optimized builds.
+#define test_assert(x) do { if (!(x)) { assert(0); return -1; }} while(0)
+
+// Bottom-up approach where we create child objects and store these
+// in temporary references before a parent object is created with
+// these references.
+int create_monster_bottom_up(flatcc_builder_t *B, int flexible)
+{
+    flatbuffers_string_ref_t weapon_one_name = flatbuffers_string_create_str(B, "Sword");
+    uint16_t weapon_one_damage = 3;
+
+    flatbuffers_string_ref_t weapon_two_name = flatbuffers_string_create_str(B, "Axe");
+    uint16_t weapon_two_damage = 5;
+
+    // Use the `MyGame_Sample_Weapon_create` shortcut to create Weapons
+    // with all the fields set.
+    //
+    // In the C-API, verbs (here create) always follow the type name
+    // (here Weapon), prefixed by the namespace (here MyGame_Sample_):
+    // MyGame_Sample_Weapon_create(...), or ns(Weapone_create(...)).
+    ns(Weapon_ref_t) sword = ns(Weapon_create(B, weapon_one_name, weapon_one_damage));
+    ns(Weapon_ref_t) axe = ns(Weapon_create(B, weapon_two_name, weapon_two_damage));
+
+    // Serialize a name for our monster, called "Orc".
+    // The _str suffix indicates the source is an ascii-z string.
+    flatbuffers_string_ref_t name = flatbuffers_string_create_str(B, "Orc");
+
+    // Create a `vector` representing the inventory of the Orc. Each number
+    // could correspond to an item that can be claimed after he is slain.
+    uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    flatbuffers_uint8_vec_ref_t inventory;
+    // `c_vec_len` is the convenience macro we defined earlier.
+    inventory = flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure));
+
+    // Here we use a top-down approach locally to build a Weapons vector
+    // in-place instead of creating a temporary external vector to use
+    // as argument like we did with the `inventory` earlier on, but the
+    // overall approach is still bottom-up.
+    ns(Weapon_vec_start(B));
+    ns(Weapon_vec_push(B, sword));
+    ns(Weapon_vec_push(B, axe));
+    ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B));
+
+
+    // Create a `Vec3`, representing the Orc's position in 3-D space.
+    ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
+
+
+    // Set his hit points to 300 and his mana to 150.
+    uint16_t hp = 300;
+    // The default value is 150, so we will never store this field.
+    uint16_t mana = 150;
+
+    // Create the equipment union. In the C++ language API this is given
+    // as two arguments to the create call, or as two separate add
+    // operations for the type and the table reference. Here we create
+    // a single union value that carries both the type and reference.
+    ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
+
+    if (!flexible) {
+        // Finally, create the monster using the `Monster_create` helper function
+        // to set all fields.
+        //
+        // Note that the Equipment union only take up one argument in C, where
+        // C++ takes a type and an object argument.
+        ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
+                             weapons, equipped));
+
+        // Unlike C++ we do not use a Finish call. Instead we use the
+        // `create_as_root` action which has better type safety and
+        // simplicity.
+        //
+        // However, we can also express this as:
+        //
+        // ns(Monster_ref_t) orc = ns(Monster_create(B, ...));
+        // flatcc_builder_buffer_create(orc);
+        //
+        // In this approach the function should return the orc and
+        // let a calling function handle the flatcc_buffer_create call
+        // for a more composable setup that is also able to create child
+        // monsters. In general, `flatcc_builder` calls are best isolated
+        // in a containing driver function.
+
+    } else {
+
+        // A more flexible approach where we mix bottom-up and top-down
+        // style. We still create child objects first, but then create
+        // a top-down style monster object that we can manipulate in more
+        // detail.
+
+        // It is important to pair `start_as_root` with `end_as_root`.
+        ns(Monster_start_as_root(B));
+        ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
+        // or alternatively
+        //ns(Monster_pos_add(&pos);
+
+        ns(Monster_hp_add(B, hp));
+        // Notice that `Monser_name_add` adds a string reference unlike the
+        // add_str and add_strn variants.
+        ns(Monster_name_add(B, name));
+        ns(Monster_inventory_add(B, inventory));
+        ns(Monster_color_add(B, ns(Color_Red)));
+        ns(Monster_weapons_add(B, weapons));
+        ns(Monster_equipped_add(B, equipped));
+        // Complete the monster object and make it the buffer root object.
+        ns(Monster_end_as_root(B));
+
+        // We could also drop the `as_root` suffix from Monster_start/end(B)
+        // and add the table as buffer root later:
+        //
+        // ns(Monster_ref_t) orc = ns(Monster_start(B));
+        // ...
+        // ns(Monster_ref_t) orc = ns(Monster_end(B));
+        // flatcc_builder_buffer_create(orc);
+        //
+        // It is best to keep the `flatcc_builder` calls in a containing
+        // driver function for modularity.
+    }
+    return 0;
+}
+
+// Alternative top-down approach where parent objects are created before
+// their children. We only need to save one reference because the `axe`
+// object is used in two places effectively making the buffer object
+// graph a DAG.
+int create_monster_top_down(flatcc_builder_t *B)
+{
+    uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    size_t treasure_count = c_vec_len(treasure);
+    ns(Weapon_ref_t) axe;
+
+    // NOTE: if we use end_as_root, we MUST also start as root.
+    ns(Monster_start_as_root(B));
+    ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
+    ns(Monster_hp_add(B, 300));
+    //ns(Monster_mana_add(B, 150));
+    // We use create_str instead of add because we have no existing string reference.
+    ns(Monster_name_create_str(B, "Orc"));
+    // Again we use create because we no existing vector object, only a C-array.
+    ns(Monster_inventory_create(B, treasure, treasure_count));
+    ns(Monster_color_add(B, ns(Color_Red)));
+    if (1) {
+        ns(Monster_weapons_start(B));
+        ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Sword"), 3));
+        // We reuse the axe object later. Note that we dereference a pointer
+        // because push always returns a short-term pointer to the stored element.
+        // We could also have created the axe object first and simply pushed it.
+        axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Axe"), 5));
+        ns(Monster_weapons_end(B));
+    } else {
+        // We can have more control with the table elements added to a vector:
+        //
+        ns(Monster_weapons_start(B));
+        ns(Monster_weapons_push_start(B));
+        ns(Weapon_name_create_str(B, "Sword"));
+        ns(Weapon_damage_add(B, 3));
+        ns(Monster_weapons_push_end(B));
+        ns(Monster_weapons_push_start(B));
+        ns(Weapon_name_create_str(B, "Axe"));
+        ns(Weapon_damage_add(B, 5));
+        axe = *ns(Monster_weapons_push_end(B));
+        ns(Monster_weapons_end(B));
+    }
+    // Unions can get their type by using a type-specific add/create/start method.
+    ns(Monster_equipped_Weapon_add(B, axe));
+
+    ns(Monster_end_as_root(B));
+    return 0;
+}
+
+// This isn't strictly needed because the builder already included the reader,
+// but we would need it if our reader were in a separate file.
+#include "monster_reader.h"
+
+#undef ns
+#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
+
+int access_monster_buffer(const void *buffer)
+{
+    // Note that we use the `table_t` suffix when reading a table object
+    // as opposed to the `ref_t` suffix used during the construction of
+    // the buffer.
+    ns(Monster_table_t) monster = ns(Monster_as_root(buffer));
+
+    // Note: root object pointers are NOT the same as the `buffer` pointer.
+
+    // Make sure the buffer is accessible.
+    test_assert(monster != 0);
+
+    uint16_t hp = ns(Monster_hp(monster));
+    uint16_t mana = ns(Monster_mana(monster));
+    // This is just a const char *, but it also supports a fast length operation.
+    flatbuffers_string_t name = ns(Monster_name(monster));
+    size_t name_len = flatbuffers_string_len(name);
+
+    test_assert(hp == 300);
+    // Since 150 is the default, we are reading a value that wasn't stored.
+    test_assert(mana == 150);
+    test_assert(0 == strcmp(name, "Orc"));
+    test_assert(name_len == strlen("Orc"));
+
+    int hp_present = ns(Monster_hp_is_present(monster)); // 1
+    int mana_present = ns(Monster_mana_is_present(monster)); // 0
+    test_assert(hp_present);
+    test_assert(!mana_present);
+
+    ns(Vec3_struct_t) pos = ns(Monster_pos(monster));
+    // Make sure pos has been set.
+    test_assert(pos != 0);
+    float x = ns(Vec3_x(pos));
+    float y = ns(Vec3_y(pos));
+    float z = ns(Vec3_z(pos));
+
+    // The literal `f` suffix is important because double literals does
+    // not always map cleanly to 32-bit represention even with only a few digits:
+    // `1.0 == 1.0f`, but `3.2 != 3.2f`.
+    test_assert(x == 1.0f);
+    test_assert(y == 2.0f);
+    test_assert(z == 3.0f);
+
+    // We can also read the position into a C-struct. We have to copy
+    // because we generally do not know if the native endian format
+    // matches the one stored in the buffer (pe: protocol endian).
+    ns(Vec3_t) pos_vec;
+    // `pe` indicates endian conversion from protocol to native.
+    ns(Vec3_copy_from_pe(&pos_vec, pos));
+    test_assert(pos_vec.x == 1.0f);
+    test_assert(pos_vec.y == 2.0f);
+    test_assert(pos_vec.z == 3.0f);
+
+    // This is a const uint8_t *, but it shouldn't be accessed directly
+    // to ensure proper endian conversion. However, uint8 (ubyte) are
+    // not sensitive endianness, so we *could* have accessed it directly.
+    // The compiler likely optimizes this so that it doesn't matter.
+    flatbuffers_uint8_vec_t inv = ns(Monster_inventory(monster));
+    size_t inv_len = flatbuffers_uint8_vec_len(inv);
+    // Make sure the inventory has been set.
+    test_assert(inv != 0);
+    // If `inv` were absent, the length would 0, so the above test is redundant.
+    test_assert(inv_len == 10);
+    // Index 0 is the first, index 2 is the third.
+    // NOTE: C++ uses the `Get` terminology for vector elemetns, C use `at`.
+    uint8_t third_item = flatbuffers_uint8_vec_at(inv, 2);
+    test_assert(third_item == 2);
+
+    ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster));
+    size_t weapons_len = ns(Weapon_vec_len(weapons));
+    test_assert(weapons_len == 2);
+    // We can use `const char *` instead of `flatbuffers_string_t`.
+    const char *second_weapon_name = ns(Weapon_name(ns(Weapon_vec_at(weapons, 1))));
+    uint16_t second_weapon_damage =  ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1))));
+    test_assert(second_weapon_name != 0 && strcmp(second_weapon_name, "Axe") == 0);
+    test_assert(second_weapon_damage == 5);
+
+    // Access union type field.
+    if (ns(Monster_equipped_type(monster)) == ns(Equipment_Weapon)) {
+        // Cast to appropriate type:
+        // C does not require the cast to Weapon_table_t, but C++ does.
+        ns(Weapon_table_t) weapon = (ns(Weapon_table_t)) ns(Monster_equipped(monster));
+        const char *weapon_name = ns(Weapon_name(weapon));
+        uint16_t weapon_damage = ns(Weapon_damage(weapon));
+
+        test_assert(0 == strcmp(weapon_name, "Axe"));
+        test_assert(weapon_damage == 5);
+    }
+    return 0;
+}
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+    // Create a `FlatBufferBuilder`, which will be used to create our
+    // monsters' FlatBuffers.
+    flatcc_builder_t builder;
+    void  *buf;
+    size_t size;
+
+    // Silence warnings.
+    (void)argc;
+    (void)argv;
+
+    // Initialize the builder object.
+    flatcc_builder_init(&builder);
+    test_assert(0 == create_monster_bottom_up(&builder, 0));
+
+    // Allocate and extract a readable buffer from internal builder heap.
+    // The returned buffer must be deallocated using `free`.
+    // NOTE: Finalizing the buffer does NOT change the builder, it
+    // just creates a snapshot of the builder content.
+    // NOTE2: finalize_buffer uses malloc while finalize_aligned_buffer
+    // uses a portable aligned allocation method. Often the malloc
+    // version is sufficient, but won't work for all schema on all
+    // systems. If the buffer is written to disk or network, but not
+    // accessed in memory, `finalize_buffer` is also sufficient.
+    buf = flatcc_builder_finalize_aligned_buffer(&builder, &size);
+    //buf = flatcc_builder_finalize_buffer(&builder, &size);
+
+    // We now have a FlatBuffer we can store on disk or send over a network.
+    // ** file/network code goes here :) **
+    // Instead, we're going to access it right away (as if we just received it).
+    //access_monster_buffer(buf);
+
+    // prior to v0.5.0, use `aligned_free`
+    flatcc_builder_aligned_free(buf);
+    //free(buf);
+    //
+    // The builder object can optionally be reused after a reset which
+    // is faster than creating a new builder. Subsequent use might
+    // entirely avoid temporary allocations until finalizing the buffer.
+    flatcc_builder_reset(&builder);
+    test_assert(0 == create_monster_bottom_up(&builder, 1));
+    buf = flatcc_builder_finalize_aligned_buffer(&builder, &size);
+    access_monster_buffer(buf);
+    flatcc_builder_aligned_free(buf);
+    flatcc_builder_reset(&builder);
+    create_monster_top_down(&builder);
+    buf = flatcc_builder_finalize_buffer(&builder, &size);
+    test_assert(0 == access_monster_buffer(buf));
+    free(buf);
+    // Eventually the builder must be cleaned up:
+    flatcc_builder_clear(&builder);
+
+    printf("The FlatBuffer was successfully created and accessed!\n");
+
+    return 0;
+}
diff --git a/recipes/flatcc/all/test_package/monster.fbs b/recipes/flatcc/all/test_package/monster.fbs
new file mode 100644
--- /dev/null
+++ b/recipes/flatcc/all/test_package/monster.fbs
@@ -0,0 +1,32 @@
+// Example IDL file for our monster's schema.
+
+namespace MyGame.Sample;
+
+enum Color:byte { Red = 0, Green, Blue = 2 }
+
+union Equipment { Weapon } // Optionally add more tables.
+
+struct Vec3 {
+  x:float;
+  y:float;
+  z:float;
+}
+
+table Monster {
+  pos:Vec3; // Struct.
+  mana:short = 150;
+  hp:short = 100;
+  name:string;
+  friendly:bool = false (deprecated);
+  inventory:[ubyte];  // Vector of scalars.
+  color:Color = Blue; // Enum.
+  weapons:[Weapon];   // Vector of tables.
+  equipped:Equipment; // Union.
+}
+
+table Weapon {
+  name:string;
+  damage:short;
+}
+
+root_type Monster;