Skip to content

Commit 92d9fd7

Browse files
committed
Add a C API and corresponding Swift interface for the Ninja component
The current Swift Ninja library runs the `llbuild` process to output a JSON file and then reads it in. Add a new C API to interface with the llbuild Ninja component. Use this to create a NinjaManifest interface in the Swift llbuild library and remove the separate Ninja library. Some known missing functionality: - Variables in the top-level/sub scopes - Cannot read all rules (the Swift interface exposes a map for rules that are referenced from statements, but will miss unreferenced rules) - Accessors to various special variables in a command (though they can be manually found through the `variables` field)
1 parent a23a768 commit 92d9fd7

File tree

15 files changed

+661
-454
lines changed

15 files changed

+661
-454
lines changed

Package.swift

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ let package = Package(
2828
.library(
2929
name: "llbuildAnalysis",
3030
targets: ["llbuildAnalysis"]),
31-
32-
// Swift library for accessing [Ninja](ninjabuild.org) files.
33-
.library(
34-
name: "Ninja",
35-
targets: ["Ninja"])
3631
],
3732
targets: [
3833
// MARK: Products
@@ -64,7 +59,7 @@ let package = Package(
6459
/// The public llbuild C API.
6560
.target(
6661
name: "libllbuild",
67-
dependencies: ["llbuildCore", "llbuildBuildSystem"],
62+
dependencies: ["llbuildCore", "llbuildBuildSystem", "llbuildNinja"],
6863
path: "products/libllbuild"
6964
),
7065

@@ -76,16 +71,6 @@ let package = Package(
7671
exclude: []
7772
),
7873

79-
/// The public Swift Ninja API.
80-
.target(
81-
name: "Ninja",
82-
dependencies: ["llbuild"],
83-
path: "products/swift-Ninja"),
84-
.testTarget(
85-
name: "SwiftNinjaTests",
86-
dependencies: ["llbuildTestSupport", "Ninja"],
87-
path: "unittests/swift-Ninja"),
88-
8974
// MARK: Components
9075

9176
.target(

include/llbuild/Ninja/ManifestLoader.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class ManifestLoaderActions {
4444

4545
/// Called by the loader to request the contents of a manifest file be loaded.
4646
///
47-
/// \param filename The name of the file to load.
47+
/// \param path Absolute path of the file to load.
4848
///
4949
/// \param forFilename If non-empty, the name of the file triggering the file
5050
/// load (for use in diagnostics).
@@ -54,8 +54,8 @@ class ManifestLoaderActions {
5454
///
5555
/// \returns The loaded file on success, or a nullptr. On failure, the action
5656
/// is assumed to have produced an appropriate error.
57-
virtual std::unique_ptr<llvm::MemoryBuffer> readFileContents(
58-
StringRef filename, StringRef forFilename, const Token* forToken) = 0;
57+
virtual std::unique_ptr<llvm::MemoryBuffer> readFile(
58+
StringRef path, StringRef forFilename, const Token* forToken) = 0;
5959
};
6060

6161
/// Interface for loading Ninja build manifests.

lib/Commands/NinjaBuildCommand.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -921,10 +921,10 @@ class BuildManifestActions : public ninja::ManifestLoaderActions {
921921
util::emitError(filename, message, at, loader->getCurrentParser());
922922
}
923923

924-
virtual std::unique_ptr<llvm::MemoryBuffer> readFileContents(
925-
StringRef filename, StringRef forFilename,
924+
virtual std::unique_ptr<llvm::MemoryBuffer> readFile(
925+
StringRef path, StringRef forFilename,
926926
const ninja::Token* forToken) override {
927-
auto bufferOrError = util::readFileContents(filename);
927+
auto bufferOrError = util::readFileContents(path);
928928
if (bufferOrError)
929929
return std::move(*bufferOrError);
930930

lib/Commands/NinjaCommand.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,10 @@ class LoadManifestActions : public ninja::ManifestLoaderActions {
363363
util::emitError(filename, message, at, Loader->getCurrentParser());
364364
}
365365

366-
virtual std::unique_ptr<llvm::MemoryBuffer> readFileContents(
367-
StringRef filename, StringRef forFilename,
366+
virtual std::unique_ptr<llvm::MemoryBuffer> readFile(
367+
StringRef path, StringRef forFilename,
368368
const ninja::Token* forToken) override {
369-
auto bufferOrError = util::readFileContents(filename);
369+
auto bufferOrError = util::readFileContents(path);
370370
if (bufferOrError)
371371
return std::move(*bufferOrError);
372372

lib/Ninja/ManifestLoader.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,14 @@ class ManifestLoader::ManifestLoaderImpl: public ParseActions {
8989

9090
bool enterFile(StringRef filename, Scope& scope,
9191
const Token* forToken = nullptr) {
92+
SmallString<256> path(filename);
93+
llvm::sys::fs::make_absolute(workingDirectory, path);
94+
9295
// Load the file data.
9396
StringRef forFilename = includeStack.empty() ? filename :
9497
getCurrentFilename();
95-
std::unique_ptr<llvm::MemoryBuffer> buffer = actions.readFileContents(
96-
filename, forFilename, forToken);
98+
std::unique_ptr<llvm::MemoryBuffer> buffer = actions.readFile(
99+
path, forFilename, forToken);
97100
if (!buffer)
98101
return false;
99102

@@ -456,7 +459,7 @@ class ManifestLoader::ManifestLoaderImpl: public ParseActions {
456459

457460
// FIXME: There is no need to store the parameters in the build decl anymore
458461
// once this is all complete.
459-
462+
460463
// Evaluate the build parameters.
461464
buildCommand.clear();
462465
decl->setCommandString(lookupNamedBuildParameter(

llbuild.xcodeproj/project.pbxproj

Lines changed: 46 additions & 215 deletions
Large diffs are not rendered by default.

products/libllbuild/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ set(SOURCES
44
Core-C-API.cpp
55
BuildDB-C-API.cpp
66
BuildKey-C-API.cpp
7-
BuildValue-C-API.cpp)
7+
BuildValue-C-API.cpp
8+
Ninja-C-API.cpp)
89

910
add_llbuild_library(libllbuild
1011
${SOURCES}
@@ -17,6 +18,7 @@ target_link_libraries(libllbuild PRIVATE
1718
llbuildBuildSystem
1819
llbuildCore
1920
llbuildBasic
21+
llbuildNinja
2022
llvmSupport
2123
SQLite::SQLite3)
2224

@@ -84,6 +86,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
8486
llbuildBuildSystem
8587
llbuildCore
8688
llbuildBasic
89+
llbuildNinja
8790
llvmSupport
8891
SQLite::SQLite3
8992
curses)
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//===-- Ninja-C-API.cpp ---------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include <llbuild/llbuild.h>
14+
#include <type_traits>
15+
16+
#include "llbuild/Basic/LLVM.h"
17+
#include "llbuild/Ninja/Lexer.h"
18+
#include "llbuild/Ninja/Manifest.h"
19+
#include "llbuild/Ninja/ManifestLoader.h"
20+
21+
#include "llvm/ADT/ArrayRef.h"
22+
#include "llvm/ADT/DenseMap.h"
23+
#include "llvm/ADT/SmallString.h"
24+
#include "llvm/ADT/STLExtras.h"
25+
#include "llvm/ADT/Twine.h"
26+
#include "llvm/Support/Allocator.h"
27+
#include "llvm/Support/MemoryBuffer.h"
28+
#include "llvm/Support/raw_ostream.h"
29+
30+
using namespace llbuild;
31+
using namespace llbuild::ninja;
32+
33+
static llb_string_ref_t toCRef(StringRef str) {
34+
return { str.size(), str.data() };
35+
}
36+
37+
namespace {
38+
class CAPIManifestActions : public ManifestLoaderActions {
39+
SmallVectorImpl<char> &Error;
40+
41+
public:
42+
CAPIManifestActions(SmallVectorImpl<char> &error) : Error(error) {}
43+
44+
virtual void initialize(ninja::ManifestLoader *Loader) override {}
45+
46+
virtual void error(StringRef path, StringRef message,
47+
const Token &at) override {
48+
addError(message, path, at.line, at.column);
49+
}
50+
51+
virtual std::unique_ptr<llvm::MemoryBuffer> readFile(
52+
StringRef path, StringRef forFilename,
53+
const Token *forToken) override {
54+
auto bufferOrError = llvm::MemoryBuffer::getFile(path);
55+
if (!bufferOrError) {
56+
auto ec = bufferOrError.getError();
57+
addError(ec.message(), forFilename);
58+
return nullptr;
59+
}
60+
return std::move(*bufferOrError);
61+
}
62+
63+
private:
64+
void addError(StringRef message, StringRef path) {
65+
llvm::raw_svector_ostream stream(Error);
66+
stream << path << ": " << message << "\n";
67+
}
68+
69+
void addError(StringRef message, StringRef path, unsigned line,
70+
unsigned column) {
71+
llvm::raw_svector_ostream stream(Error);
72+
stream << path << ":" << line << ":" << column << ": " << message << "\n";
73+
}
74+
};
75+
76+
class CAPIManifest {
77+
std::unique_ptr<Manifest> Underlying;
78+
SmallString<0> Error;
79+
llvm::BumpPtrAllocator Allocator;
80+
ArrayRef<llb_ninja_build_statement_t> Statements;
81+
ArrayRef<llb_string_ref_t> DefaultTargets;
82+
83+
using RuleCacheTy = llvm::DenseMap<const Rule *, const llb_ninja_rule_t *>;
84+
85+
template <typename Input, typename F>
86+
auto copyTransformed(const Input &orig, F &&transform) {
87+
using R = decltype(transform(*(orig.begin())));
88+
auto copied = llvm::makeMutableArrayRef(Allocator.Allocate<R>(orig.size()),
89+
orig.size());
90+
for (auto it : llvm::enumerate(orig)) {
91+
copied[it.index()] = transform(it.value());
92+
}
93+
return copied;
94+
}
95+
96+
CAPIManifest() {}
97+
98+
public:
99+
static llb_ninja_manifest_t build(StringRef filename,
100+
StringRef workingDirectory) {
101+
auto manifest = new CAPIManifest();
102+
103+
CAPIManifestActions actions(manifest->Error);
104+
ninja::ManifestLoader loader(workingDirectory, filename, actions);
105+
106+
if (auto underlying = loader.load()) {
107+
manifest->Underlying = std::move(underlying);
108+
manifest->allocateRefs();
109+
}
110+
111+
return {
112+
reinterpret_cast<llb_ninja_raw_manifest_t>(manifest),
113+
manifest->Statements.size(), manifest->Statements.data(),
114+
manifest->DefaultTargets.size(), manifest->DefaultTargets.data(),
115+
toCRef(manifest->Error)
116+
};
117+
}
118+
119+
private:
120+
void allocateRefs() {
121+
RuleCacheTy ruleCache;
122+
123+
Statements = copyTransformed(
124+
Underlying->getCommands(),
125+
[&](const Command *statement) -> llb_ninja_build_statement_t {
126+
auto explicitInputs = copyRefs(statement->explicitInputs_begin(),
127+
statement->explicitInputs_end());
128+
auto implicitInputs = copyRefs(statement->implicitInputs_begin(),
129+
statement->implicitInputs_end());
130+
auto orderOnlyInputs = copyRefs(statement->orderOnlyInputs_begin(),
131+
statement->orderOnlyInputs_end());
132+
auto outputs = copyRefs(statement->getOutputs());
133+
auto variables = copyRefs(statement->getParameters());
134+
135+
return {
136+
copyRefs(statement->getRule(), ruleCache),
137+
toCRef(statement->getCommandString()),
138+
toCRef(statement->getDescription()),
139+
explicitInputs.size(), explicitInputs.data(),
140+
implicitInputs.size(), implicitInputs.data(),
141+
orderOnlyInputs.size(), orderOnlyInputs.data(),
142+
outputs.size(), outputs.data(),
143+
variables.size(), variables.data(),
144+
statement->hasGeneratorFlag(),
145+
statement->hasRestatFlag()
146+
};
147+
});
148+
DefaultTargets = copyRefs(Underlying->getDefaultTargets());
149+
}
150+
151+
ArrayRef<llb_string_ref_t> copyRefs(ArrayRef<Node *> nodes) {
152+
return copyTransformed(nodes, [](auto &node) -> llb_string_ref_t {
153+
auto &path = node->getScreenPath();
154+
return { path.size(), path.data() };
155+
});
156+
}
157+
158+
ArrayRef<llb_string_ref_t> copyRefs(
159+
const std::vector<Node*>::const_iterator &begin,
160+
const std::vector<Node*>::const_iterator &end) {
161+
return copyRefs(llvm::makeArrayRef(&*begin, &*end));
162+
}
163+
164+
ArrayRef<llb_ninja_variable_t> copyRefs(
165+
const llvm::StringMap<std::string> &variables) {
166+
return copyTransformed(variables, [&](auto &var) -> llb_ninja_variable_t {
167+
return { toCRef(var.getKey()), toCRef(var.getValue()) };
168+
});
169+
}
170+
171+
const llb_ninja_rule_t *copyRefs(const Rule *rule, RuleCacheTy &ruleCache) {
172+
const llb_ninja_rule_t *&cRule = ruleCache[rule];
173+
if (cRule)
174+
return cRule;
175+
176+
auto cParams = copyRefs(rule->getParameters());
177+
return new (Allocator) llb_ninja_rule_t {
178+
toCRef(rule->getName()),
179+
cParams.size(), cParams.data()
180+
};
181+
}
182+
};
183+
}
184+
185+
llb_ninja_manifest_t llb_manifest_fs_load(
186+
const char *filename, const char *workingDirectory) {
187+
return CAPIManifest::build(filename, workingDirectory);
188+
}
189+
190+
void llb_manifest_destroy(llb_ninja_manifest_t *manifest) {
191+
delete reinterpret_cast<CAPIManifest *>(manifest->raw_manifest);
192+
}

products/libllbuild/include/llbuild/llbuild.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ LLBUILD_EXPORT int llb_get_api_version(void);
4242
#include "buildkey.h"
4343
#include "buildvalue.h"
4444

45+
#include "ninja.h"
46+
4547
#endif

0 commit comments

Comments
 (0)