Skip to content

Custom generator #212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 51 commits into from
May 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
b11d4d7
Added custom_generator.fbs
coder137 May 1, 2022
85aa660
Added custom_generator_serialization.h/.cpp
coder137 May 1, 2022
d0e60fc
Updated schema
coder137 May 1, 2022
27529de
Updated schema
coder137 May 1, 2022
6d7aab6
Updated CustomGenerator schema
coder137 May 2, 2022
357d3a7
Updated schema
coder137 May 2, 2022
6a8b4cf
Added schema test for custom_generator_serialization
coder137 May 2, 2022
c344210
Updated builder_interface and test
coder137 May 2, 2022
4bb1dd5
Added custom_generator
coder137 May 2, 2022
9ce04a6
Added initial test custom generator
coder137 May 2, 2022
fbeef3b
Updated custom generator API
coder137 May 2, 2022
01dbe58
Updated custom_generator and tests
coder137 May 2, 2022
ad9db48
Updated custom_generator and tests
coder137 May 2, 2022
edefce7
Minor update to test_custom_generator.cpp
coder137 May 2, 2022
6df772b
Updated custom_generator.cpp
coder137 May 2, 2022
9670090
Updated test_custom_generator.cpp
coder137 May 5, 2022
7a35ffd
Updated custom_generator
coder137 May 6, 2022
bad1658
Updated custom_generator basic unit tests
coder137 May 6, 2022
c865e14
Updated failure tests for custom_generator
coder137 May 6, 2022
1aa5f7e
Updated test_custom_generator
coder137 May 6, 2022
b9a6598
Update custom_generator fix for potential dependency bug condition
coder137 May 6, 2022
90f19c0
Updated custom_generator.cpp
coder137 May 7, 2022
22c3978
Update command.cpp with try catch for exception handling
coder137 May 7, 2022
c72d783
Added Map Removed condition
coder137 May 7, 2022
d744d8e
Shifted header from generator.h to custom_generator.h
coder137 May 7, 2022
e6b619d
Added recheck_states.cpp
coder137 May 7, 2022
e6c01f5
Added recheck_states mocks
coder137 May 7, 2022
31a0bbb
Adedd Id states
coder137 May 7, 2022
cb81241
Updated buildcc.h
coder137 May 7, 2022
4d2890b
Updated unit tests
coder137 May 7, 2022
7bf8d32
Updated test_custom_generator.cpp
coder137 May 7, 2022
1e836e7
Added comments
coder137 May 7, 2022
21d4ab0
Updated custom_generator to handle subflow dependencies
coder137 May 9, 2022
e364c9b
Updated custom_generator
coder137 May 9, 2022
f3c65ee
Added dependency basic check
coder137 May 9, 2022
2224dd5
Added dependency_file test
coder137 May 9, 2022
affa14e
Updated custom_generator.cpp TaskRunner
coder137 May 9, 2022
7f92800
Fix recheck_states
coder137 May 9, 2022
9a40fb4
Updated with map remove condition
coder137 May 9, 2022
fdc4a45
Updated Map Add condition
coder137 May 9, 2022
9c27129
Updated custom_generator
coder137 May 9, 2022
ba36b0f
Updated unit tests for update example
coder137 May 9, 2022
e3554f9
Updated test_custom_generator for output changed condition
coder137 May 9, 2022
e0abbdb
Updated custom_generator with try/catch for dependency callback
coder137 May 9, 2022
8cadce6
Removed parallel from custom_generator
coder137 May 9, 2022
31e00e4
Updated tests for default argument usage
coder137 May 11, 2022
1c4cfa1
Updated AddDefaultArgument usage
coder137 May 11, 2022
692e2e4
Minor update to CMakeLists.txt for toolchains
coder137 May 11, 2022
c669365
Updated bootstrap
coder137 May 11, 2022
225eabd
Removed plugin test
coder137 May 11, 2022
4031c39
Update test_custom_generator.cpp
coder137 May 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion bootstrap/src/build_buildcc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ namespace buildcc {

void schema_gen_cb(BaseGenerator &generator, const BaseTarget &flatc_exe) {
generator.AddInput("{gen_root_dir}/path.fbs", "path_fbs");
generator.AddInput("{gen_root_dir}/custom_generator.fbs",
"custom_generator_fbs");
generator.AddInput("{gen_root_dir}/generator.fbs", "generator_fbs");
generator.AddInput("{gen_root_dir}/target.fbs", "target_fbs");

generator.AddOutput("{gen_build_dir}/path_generated.h");
generator.AddOutput("{gen_build_dir}/custom_generator_generated.h");
generator.AddOutput("{gen_build_dir}/generator_generated.h");
generator.AddOutput("{gen_build_dir}/target_generated.h");

Expand All @@ -33,7 +36,7 @@ void schema_gen_cb(BaseGenerator &generator, const BaseTarget &flatc_exe) {
// generator.AddCommand("{flatc_compiler} --help");
generator.AddCommand(
"{flatc_compiler} -o {gen_build_dir} -I {gen_root_dir} --gen-object-api "
"--cpp {path_fbs} {generator_fbs} {target_fbs}");
"--cpp {path_fbs} {custom_generator_fbs} {generator_fbs} {target_fbs}");

generator.Build();
}
Expand Down Expand Up @@ -71,6 +74,7 @@ void buildcc_cb(BaseTarget &target, const BaseGenerator &schema_gen,

// TARGET
target.GlobSources("lib/target/src/common");
target.GlobSources("lib/target/src/custom_generator");
target.GlobSources("lib/target/src/generator");
target.GlobSources("lib/target/src/api");
target.GlobSources("lib/target/src/target_info");
Expand Down
1 change: 1 addition & 0 deletions buildcc/buildcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

// Base
#include "toolchain/toolchain.h"
#include "target/custom_generator.h"
#include "target/generator.h"
#include "target/target_info.h"
#include "target/target.h"
Expand Down
9 changes: 8 additions & 1 deletion buildcc/lib/env/src/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ std::string Command::Construct(
});

// Construct your command
return fmt::vformat(pattern, store);
std::string ret;
try {
ret = fmt::vformat(pattern, store);
} catch (const std::exception &e) {
env::assert_fatal<false>(
fmt::format("Construct command failed: {}", e.what()));
}
return ret;
}

} // namespace buildcc::env
2 changes: 2 additions & 0 deletions buildcc/lib/target/cmake/common_target_src.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ set(COMMON_TARGET_SRCS
include/target/api/target_getter.h

# Generator
src/custom_generator/custom_generator.cpp
include/target/custom_generator.h
src/generator/generator.cpp
include/target/generator.h

Expand Down
3 changes: 3 additions & 0 deletions buildcc/lib/target/cmake/mock_target.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
add_library(mock_target STATIC
${COMMON_TARGET_SRCS}
# Custom Generator mocks
mock/custom_generator/runner.cpp
mock/custom_generator/recheck_states.cpp

# Generator mocks
src/generator/task.cpp
Expand Down
2 changes: 2 additions & 0 deletions buildcc/lib/target/cmake/target.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
set(TARGET_SRCS
${COMMON_TARGET_SRCS}

src/custom_generator/recheck_states.cpp

src/generator/task.cpp
src/generator/recheck_states.cpp

Expand Down
174 changes: 174 additions & 0 deletions buildcc/lib/target/include/target/custom_generator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright 2021-2022 Niket Naidu. All rights reserved.
*
* 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
*
* http://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.
*/

#ifndef TARGET_CUSTOM_GENERATOR_H_
#define TARGET_CUSTOM_GENERATOR_H_

#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>

#include "taskflow/taskflow.hpp"

#include "env/command.h"
#include "env/task_state.h"

#include "target/interface/builder_interface.h"

#include "schema/custom_generator_serialization.h"
#include "schema/path.h"

#include "target/common/target_env.h"

namespace buildcc {

// TODO, Shift to a different file
// TODO, Check if we need the "id" here as well
class CustomGeneratorContext {
public:
CustomGeneratorContext(const env::Command &c, const fs_unordered_set &i,
const fs_unordered_set &o)
: command(c), inputs(i), outputs(o) {}

public:
const env::Command &command;
const fs_unordered_set &inputs;
const fs_unordered_set &outputs;
};

// clang-format off
typedef std::function<bool(CustomGeneratorContext &)> GenerateCb;

typedef std::function<void(std::unordered_map<std::string, tf::Task> &)> DependencyCb;
// clang-format on

struct UserRelInputOutputSchema : internal::RelInputOutputSchema {
fs_unordered_set inputs;
GenerateCb generate_cb;
};

struct UserCustomGeneratorSchema : public internal::CustomGeneratorSchema {
std::unordered_map<std::string, UserRelInputOutputSchema> rels_map;

void ConvertToInternal() {
for (auto &r_miter : rels_map) {
r_miter.second.internal_inputs = path_schema_convert(
r_miter.second.inputs, internal::Path::CreateExistingPath);
auto p = internal_rels_map.emplace(r_miter.first, r_miter.second);
env::assert_fatal(p.second,
fmt::format("Could not save {}", r_miter.first));
}
}
};

class CustomGenerator : public internal::BuilderInterface {
public:
CustomGenerator(const std::string &name, const TargetEnv &env)
: name_(name),
env_(env.GetTargetRootDir(), env.GetTargetBuildDir() / name),
serialization_(env_.GetTargetBuildDir() / fmt::format("{}.bin", name)) {
Initialize();
}
virtual ~CustomGenerator() = default;
CustomGenerator(const CustomGenerator &) = delete;

/**
* @brief Add default arguments for input, output and command requirements
*
* @param arguments Key-Value pair for arguments
*/
void AddDefaultArguments(
const std::unordered_map<std::string, std::string> &arguments);

/**
* @brief Single Generator task for inputs->generate_cb->outputs
*
* @param id Unique id associated with Generator task
* @param inputs File inputs
* @param outputs File outputs
* @param generate_cb User-defined generate callback to build outputs from the
* provided inputs
*/
void AddGenInfo(const std::string &id, const fs_unordered_set &inputs,
const fs_unordered_set &outputs,
const GenerateCb &generate_cb);

// Callbacks
/**
* @brief Setup dependencies between Tasks using their `id`
* For example: `task_map["id1"].precede(task_map["id2"])`
*
* IMPORTANT: Successor tasks will not automatically run if dependent task is
* run.
* The Dependency callback only sets precedence (order in which your tasks
* should run)
* Default behaviour when dependency callback is not supplied: All task `id`s
* run in parallel.
*
* @param dependency_cb Unordered map of `id` and `task`
* The map can be safely mutated.
*/
void AddDependencyCb(const DependencyCb &dependency_cb);

void Build() override;

// Getters
const fs::path &GetBinaryPath() const {
return serialization_.GetSerializedFile();
}
const fs::path &GetRootDir() const { return env_.GetTargetRootDir(); }
const fs::path &GetBuildDir() const { return env_.GetTargetBuildDir(); }
tf::Taskflow &GetTaskflow() { return tf_; }

private:
void Initialize();

template <bool run> void TaskRunner(const std::string &id);

void GenerateTask();
void BuildGenerate(std::unordered_map<std::string, UserRelInputOutputSchema>
&gen_selected_map,
std::unordered_map<std::string, UserRelInputOutputSchema>
&dummy_gen_selected_map);

// Recheck states
void IdRemoved();
void IdAdded();
void IdUpdated();

private:
std::string name_;
TargetEnv env_;
internal::CustomGeneratorSerialization serialization_;

// Serialization
UserCustomGeneratorSchema user_;

std::mutex success_schema_mutex_;
std::unordered_map<std::string, UserRelInputOutputSchema> success_schema_;

// Internal
env::Command command_;
tf::Taskflow tf_;

// Callbacks
DependencyCb dependency_cb_;
};

} // namespace buildcc

#endif
6 changes: 2 additions & 4 deletions buildcc/lib/target/include/target/generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@
#ifndef TARGET_GENERATOR_H_
#define TARGET_GENERATOR_H_

#include <functional>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>

#include "taskflow/taskflow.hpp"

#include "env/env.h"
#include "env/task_state.h"

#include "env/command.h"
Expand Down Expand Up @@ -54,8 +52,8 @@ class Generator : public internal::BuilderInterface {
parallel_(parallel) {
Initialize();
}
virtual ~Generator() {}
Generator(const Generator &generator) = delete;
virtual ~Generator() = default;
Generator(const Generator &) = delete;

/**
* @brief Add default arguments for input, output and command requirements
Expand Down
60 changes: 60 additions & 0 deletions buildcc/lib/target/include/target/interface/builder_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,66 @@

namespace buildcc::internal {

enum PathState {
kNoChange,
kRemoved,
kAdded,
kUpdated,
};

template <typename T>
inline bool CheckChanged(const T &previous, const T &current) {
bool changed = false;
if (previous != current) {
changed = true;
}
return changed;
}

/**
* @brief
*
* @return PathState Returns first state found if `Removed`, `Added` or
* `Updated`
* If none of the above states are true then it returns `NoChange`
*/
inline PathState CheckPaths(const internal::path_unordered_set &previous_path,
const internal::path_unordered_set &current_path) {
PathState state{PathState::kNoChange};

// * Old path is removed
const bool removed = std::any_of(
previous_path.begin(), previous_path.end(), [&](const internal::Path &p) {
return current_path.find(p) == current_path.end();
});
if (removed) {
state = PathState::kRemoved;
} else {
(void)std::any_of(current_path.cbegin(), current_path.cend(),
[&](const internal::Path &p) -> bool {
bool dirty = false;
const auto find = previous_path.find(p);
const bool added_cond = (find == previous_path.end());
if (added_cond) {
dirty = true;
state = kAdded;
} else {
const bool updated_cond =
(p.GetLastWriteTimestamp() >
find->GetLastWriteTimestamp());
if (updated_cond) {
dirty = true;
state = kUpdated;
} else {
dirty = false;
}
}
return dirty;
});
}
return state;
}

// TODO, 1. Consider updating Recheck* APIs - do not modify internal `dirty_`
// flag
// TODO, 2. Consider removing dependency on target/common/util.h
Expand Down
43 changes: 43 additions & 0 deletions buildcc/lib/target/mock/custom_generator/recheck_states.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "target/custom_generator.h"

#include "expect_custom_generator.h"

#include "CppUTestExt/MockSupport.h"

namespace buildcc {

static constexpr const char *const ID_REMOVED_FUNCTION =
"CustomGenerator::IdRemoved";
static constexpr const char *const ID_ADDED_FUNCTION =
"CustomGenerator::IdAdded";
static constexpr const char *const ID_UPDATED_FUNCTION =
"CustomGenerator::IdUpdated";

void CustomGenerator::IdRemoved() {
mock().actualCall(ID_REMOVED_FUNCTION).onObject(this);
}
void CustomGenerator::IdAdded() {
mock().actualCall(ID_ADDED_FUNCTION).onObject(this);
}
void CustomGenerator::IdUpdated() {
mock().actualCall(ID_UPDATED_FUNCTION).onObject(this);
}

namespace m {

void CustomGeneratorExpect_IdRemoved(unsigned int calls,
CustomGenerator *generator) {
mock().expectNCalls(calls, ID_REMOVED_FUNCTION).onObject(generator);
}
void CustomGeneratorExpect_IdAdded(unsigned int calls,
CustomGenerator *generator) {
mock().expectNCalls(calls, ID_ADDED_FUNCTION).onObject(generator);
}
void CustomGeneratorExpect_IdUpdated(unsigned int calls,
CustomGenerator *generator) {
mock().expectNCalls(calls, ID_UPDATED_FUNCTION).onObject(generator);
}

} // namespace m

} // namespace buildcc
Loading