blob: 3c8f9048335a07356c9d442b8a84859552997531 [file] [log] [blame]
//===-- Core-C-API.cpp ----------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// Include the public API.
#include <llbuild/llbuild.h>
#include "llbuild/Core/BuildDB.h"
#include "llbuild/Core/BuildEngine.h"
#include <cassert>
#include <cstring>
using namespace llbuild;
using namespace llbuild::core;
/* Build Engine API */
namespace {
class CAPIBuildEngineDelegate : public BuildEngineDelegate {
llb_buildengine_delegate_t cAPIDelegate;
friend class CAPITask;
virtual ~CAPIBuildEngineDelegate() {
if (cAPIDelegate.destroy_context) {
cAPIDelegate.destroy_context(cAPIDelegate.context);
}
}
virtual Rule lookupRule(const KeyType& key) override {
void* engineContext = cAPIDelegate.context;
llb_rule_t rule{};
llb_data_t key_data{ key.length(), (const uint8_t*)key.data() };
cAPIDelegate.lookup_rule(cAPIDelegate.context, &key_data, &rule);
// FIXME: Check that the client created the rule appropriately. We should
// change the API to be type safe here, by forcing the client to return a
// handle created by the C API.
assert(rule.create_task && "client failed to initialize rule");
std::function<bool(BuildEngine&, const Rule&,
const ValueType&)> isResultValid;
if (rule.is_result_valid) {
isResultValid = [rule, engineContext] (BuildEngine&,
const Rule& nativeRule,
const ValueType& value) {
// FIXME: Why do we pass the rule here, it is redundant. NativeRule
// should be == rule here.
llb_data_t value_data{ value.size(), value.data() };
return rule.is_result_valid(rule.context, engineContext, &rule,
&value_data);
};
}
std::function<void(BuildEngine&, Rule::StatusKind)> updateStatus;
if (rule.update_status) {
updateStatus = [rule, engineContext] (BuildEngine&,
Rule::StatusKind kind) {
return rule.update_status(rule.context, engineContext,
(llb_rule_status_kind_t)kind);
};
}
return Rule{
// FIXME: This is a wasteful copy.
key,
[rule, engineContext] (BuildEngine& engine) {
return (Task*) rule.create_task(rule.context, engineContext);
},
isResultValid,
updateStatus };
}
virtual void cycleDetected(const std::vector<core::Rule*>& items) override {
// FIXME.
assert(0 && "unexpected cycle!");
}
virtual void error(const Twine& message) override {
cAPIDelegate.error(cAPIDelegate.context, message.str().c_str());
}
public:
CAPIBuildEngineDelegate(llb_buildengine_delegate_t delegate)
: cAPIDelegate(delegate)
{
}
};
class CAPITask : public Task {
llb_task_delegate_t cAPIDelegate;
public:
CAPITask(llb_task_delegate_t delegate) : cAPIDelegate(delegate) {
assert(cAPIDelegate.start && "missing task start function");
assert(cAPIDelegate.provide_value &&
"missing task provide_value function");
assert(cAPIDelegate.inputs_available &&
"missing task inputs_available function");
}
virtual void start(BuildEngine& engine) override {
CAPIBuildEngineDelegate* delegate =
static_cast<CAPIBuildEngineDelegate*>(engine.getDelegate());
cAPIDelegate.start(cAPIDelegate.context,
delegate->cAPIDelegate.context,
(llb_task_t*)this);
}
virtual void provideValue(BuildEngine& engine, uintptr_t inputID,
const ValueType& value) override {
CAPIBuildEngineDelegate* delegate =
static_cast<CAPIBuildEngineDelegate*>(engine.getDelegate());
llb_data_t valueData{ value.size(), value.data() };
cAPIDelegate.provide_value(cAPIDelegate.context,
delegate->cAPIDelegate.context,
(llb_task_t*)this,
inputID, &valueData);
}
virtual void inputsAvailable(BuildEngine& engine) override {
CAPIBuildEngineDelegate* delegate =
static_cast<CAPIBuildEngineDelegate*>(engine.getDelegate());
cAPIDelegate.inputs_available(cAPIDelegate.context,
delegate->cAPIDelegate.context,
(llb_task_t*)this);
}
};
};
llb_buildengine_t* llb_buildengine_create(llb_buildengine_delegate_t delegate) {
// FIXME: Delegate is leaked, need to provide a provision for owning the
// delegate.
BuildEngineDelegate* engine_delegate = new CAPIBuildEngineDelegate(delegate);
return (llb_buildengine_t*) new BuildEngine(*engine_delegate);
}
void llb_buildengine_destroy(llb_buildengine_t* engine) {
// FIXME: Delegate is lost.
delete (BuildEngine*)engine;
}
bool llb_buildengine_attach_db(llb_buildengine_t* engine_p,
const llb_data_t* path,
uint32_t schema_version,
char** error_out) {
BuildEngine* engine = (BuildEngine*) engine_p;
std::string error;
std::unique_ptr<BuildDB> db(createSQLiteBuildDB(
std::string((char*)path->data,
path->length),
schema_version,
&error));
if (!db) {
*error_out = strdup(error.c_str());
return false;
}
bool result = engine->attachDB(std::move(db), &error);
*error_out = strdup(error.c_str());
return result;
}
void llb_buildengine_build(llb_buildengine_t* engine_p, const llb_data_t* key,
llb_data_t* result_out) {
BuildEngine* engine = (BuildEngine*) engine_p;
auto& result = engine->build(KeyType((const char*)key->data, key->length));
*result_out = llb_data_t{ result.size(), result.data() };
}
llb_task_t* llb_buildengine_register_task(llb_buildengine_t* engine_p,
llb_task_t* task) {
BuildEngine* engine = (BuildEngine*) engine_p;
engine->registerTask((Task*)task);
return task;
}
void llb_buildengine_task_needs_input(llb_buildengine_t* engine_p,
llb_task_t* task,
const llb_data_t* key,
uintptr_t input_id) {
BuildEngine* engine = (BuildEngine*) engine_p;
engine->taskNeedsInput((Task*)task,
KeyType((const char*)key->data, key->length),
input_id);
}
void llb_buildengine_task_must_follow(llb_buildengine_t* engine_p,
llb_task_t* task,
const llb_data_t* key) {
BuildEngine* engine = (BuildEngine*) engine_p;
engine->taskMustFollow((Task*)task,
KeyType((const char*)key->data, key->length));
}
void llb_buildengine_task_discovered_dependency(llb_buildengine_t* engine_p,
llb_task_t* task,
const llb_data_t* key) {
BuildEngine* engine = (BuildEngine*) engine_p;
engine->taskDiscoveredDependency((Task*)task,
KeyType((const char*)key->data,
key->length));
}
void llb_buildengine_task_is_complete(llb_buildengine_t* engine_p,
llb_task_t* task,
const llb_data_t* value,
bool force_change) {
BuildEngine* engine = (BuildEngine*) engine_p;
std::vector<uint8_t> result(value->length);
memcpy(result.data(), value->data, value->length);
engine->taskIsComplete((Task*)task, std::move(result));
}
llb_task_t* llb_task_create(llb_task_delegate_t delegate) {
return (llb_task_t*) new CAPITask(delegate);
}