Skip to content

Commit 81de677

Browse files
committed
Reuse generated bindings
Use json format for config file Update documentation
1 parent 01a8ffb commit 81de677

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+567
-154
lines changed

Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ RUN set -x \
1313
g++ openjdk-8-jdk-headless sbt cmake make curl git \
1414
zlib1g-dev \
1515
libgc-dev libunwind8-dev libre2-dev \
16+
nlohmann-json-dev \
1617
&& rm -rf /var/lib/apt/lists/*
1718

1819
ARG LLVM_VERSION=6.0

bindgen/Main.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ int main(int argc, const char *argv[]) {
2626
llvm::cl::opt<std::string> LinkName(
2727
"link", llvm::cl::cat(Category),
2828
llvm::cl::desc("Library to link with, e.g. -luv for libuv"));
29+
llvm::cl::opt<std::string> ReuseBindingsConfig(
30+
"integrate-bindings", llvm::cl::cat(Category),
31+
llvm::cl::desc("Path to a config file that contains the information "
32+
"about bindings that should be reused"));
2933
clang::tooling::CommonOptionsParser op(argc, argv, Category);
3034
clang::tooling::ClangTool Tool(op.getCompilations(),
3135
op.getSourcePathList());
@@ -62,6 +66,11 @@ int main(int argc, const char *argv[]) {
6266
std::string resolved = getRealPath(op.getSourcePathList()[0].c_str());
6367
LocationManager locationManager(resolved);
6468

69+
auto reuseBindingsConfig = ReuseBindingsConfig.getValue();
70+
if (!reuseBindingsConfig.empty()) {
71+
locationManager.loadConfig(reuseBindingsConfig);
72+
}
73+
6574
IR ir(libName, linkName, objectName, Package.getValue(), locationManager);
6675

6776
DefineFinderActionFactory defineFinderActionFactory(ir);

bindgen/Utils.h

+7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ static inline bool startsWith(const std::string &str,
4949
return str.substr(0, prefix.size()) == prefix;
5050
}
5151

52+
/**
53+
* @return true if str ends with given prefix
54+
*/
55+
static inline bool endsWith(const std::string &str, const std::string &suffix) {
56+
return str.substr(str.length() - suffix.size(), str.length()) == suffix;
57+
}
58+
5259
template <typename T, typename PT> static inline bool isInstanceOf(PT *type) {
5360
auto *p = dynamic_cast<const T *>(type);
5461
return p != nullptr;

bindgen/ir/Function.cpp

+13-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "../Utils.h"
33
#include "Struct.h"
44
#include "Union.h"
5+
#include <sstream>
56

67
Parameter::Parameter(std::string name, std::shared_ptr<const Type> type)
78
: TypeAndName(std::move(name), type) {}
@@ -12,24 +13,26 @@ Function::Function(const std::string &name,
1213
: name(name), scalaName(name), parameters(std::move(parameters)),
1314
retType(std::move(retType)), isVariadic(isVariadic) {}
1415

15-
llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) {
16-
if (func.scalaName != func.name) {
17-
s << " @native.link(\"" << func.name << "\")\n";
16+
std::string
17+
Function::getDefinition(const LocationManager &locationManager) const {
18+
std::stringstream s;
19+
if (scalaName != name) {
20+
s << " @native.link(\"" << name << "\")\n";
1821
}
19-
s << " def " << handleReservedWords(func.scalaName) << "(";
22+
s << " def " << handleReservedWords(scalaName) << "(";
2023
std::string sep = "";
21-
for (const auto &param : func.parameters) {
24+
for (const auto &param : parameters) {
2225
s << sep << handleReservedWords(param->getName()) << ": "
23-
<< param->getType()->str();
26+
<< param->getType()->str(locationManager);
2427
sep = ", ";
2528
}
26-
if (func.isVariadic) {
29+
if (isVariadic) {
2730
/* the C Iso require at least one argument in a variadic function, so
2831
* the comma is fine */
29-
s << ", " << func.getVarargsParameterName() << ": native.CVararg*";
32+
s << ", " << getVarargsParameterName() << ": native.CVararg*";
3033
}
31-
s << "): " << func.retType->str() << " = native.extern\n";
32-
return s;
34+
s << "): " << retType->str(locationManager) << " = native.extern\n";
35+
return s.str();
3336
}
3437

3538
bool Function::usesType(

bindgen/ir/Function.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ class Function {
1818
std::vector<std::shared_ptr<Parameter>> parameters,
1919
std::shared_ptr<const Type> retType, bool isVariadic);
2020

21-
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
22-
const Function &func);
21+
std::string getDefinition(const LocationManager &locationManager) const;
2322

2423
bool usesType(std::shared_ptr<const Type> type, bool stopOnTypeDefs,
2524
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;

bindgen/ir/IR.cpp

+47-21
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,9 @@ void IR::addVarDefine(std::string name, std::shared_ptr<Variable> variable) {
8787
}
8888

8989
bool IR::libObjEmpty() const {
90-
return functions.empty() && !hasOutputtedDeclaration(typeDefs) &&
91-
!hasOutputtedDeclaration(structs) &&
92-
!hasOutputtedDeclaration(unions) && varDefines.empty() &&
93-
variables.empty();
90+
return functions.empty() && !hasOutputtedType(typeDefs) &&
91+
!hasOutputtedType(structs) && !hasOutputtedType(unions) &&
92+
varDefines.empty() && variables.empty();
9493
}
9594

9695
llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
@@ -100,7 +99,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
10099
s << "package " << ir.packageName << "\n\n";
101100
}
102101

103-
if (!ir.libObjEmpty() || ir.hasOutputtedDeclaration(ir.enums) ||
102+
if (!ir.libObjEmpty() || ir.hasOutputtedType(ir.enums) ||
104103
!ir.literalDefines.empty()) {
105104
s << "import scala.scalanative._\n"
106105
<< "import scala.scalanative.native._\n\n";
@@ -123,8 +122,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
123122

124123
for (const auto &typeDef : ir.typeDefs) {
125124
visitedTypes.clear();
126-
if (ir.shouldOutput(typeDef, visitedTypes)) {
127-
s << *typeDef;
125+
if (ir.shouldOutputTypeDef(typeDef, visitedTypes)) {
126+
s << typeDef->getDefinition(ir.locationManager);
128127
} else if (typeDef->hasLocation() &&
129128
isAliasForOpaqueType(typeDef.get()) &&
130129
ir.locationManager.inMainFile(*typeDef->getLocation())) {
@@ -138,7 +137,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
138137

139138
for (const auto &variable : ir.variables) {
140139
if (!variable->hasIllegalUsageOfOpaqueType()) {
141-
s << *variable;
140+
s << variable->getDefinition(ir.locationManager);
142141
} else {
143142
llvm::errs() << "Error: Variable " << variable->getName()
144143
<< " is skipped because it has incomplete type.\n";
@@ -147,7 +146,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
147146

148147
for (const auto &varDefine : ir.varDefines) {
149148
if (!varDefine->hasIllegalUsageOfOpaqueType()) {
150-
s << *varDefine;
149+
s << varDefine->getDefinition(ir.locationManager);
151150
} else {
152151
llvm::errs() << "Error: Variable alias " << varDefine->getName()
153152
<< " is skipped because it has incomplete type.\n";
@@ -162,7 +161,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
162161
"passing structs and arrays by value.\n";
163162
llvm::errs().flush();
164163
} else {
165-
s << *func;
164+
s << func->getDefinition(ir.locationManager);
166165
}
167166
}
168167

@@ -173,16 +172,16 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
173172
if (!ir.literalDefines.empty()) {
174173
s << "object " << ir.libName << "Defines {\n";
175174
for (const auto &literalDefine : ir.literalDefines) {
176-
s << *literalDefine;
175+
s << literalDefine->getDefinition(ir.locationManager);
177176
}
178177
s << "}\n\n";
179178
}
180179

181-
if (ir.hasOutputtedDeclaration(ir.enums) || ir.hasHelperMethods()) {
180+
if (ir.hasOutputtedType(ir.enums) || ir.hasHelperMethods()) {
182181
s << "import " << objectName << "._\n\n";
183182
}
184183

185-
if (ir.hasOutputtedDeclaration(ir.enums)) {
184+
if (ir.hasOutputtedType(ir.enums)) {
186185
s << "object " << ir.libName << "Enums {\n";
187186

188187
std::string sep = "";
@@ -203,14 +202,14 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
203202
for (const auto &st : ir.structs) {
204203
visitedTypes.clear();
205204
if (ir.shouldOutput(st, visitedTypes) && st->hasHelperMethods()) {
206-
s << "\n" << st->generateHelperClass();
205+
s << "\n" << st->generateHelperClass(ir.locationManager);
207206
}
208207
}
209208

210209
for (const auto &u : ir.unions) {
211210
visitedTypes.clear();
212211
if (ir.shouldOutput(u, visitedTypes) && u->hasHelperMethods()) {
213-
s << "\n" << u->generateHelperClass();
212+
s << "\n" << u->generateHelperClass(ir.locationManager);
214213
}
215214
}
216215

@@ -327,7 +326,7 @@ bool IR::isTypeUsed(
327326
for (const auto &typeDef : typeDefs) {
328327
visitedTypesInner.clear();
329328
if (typeDef->usesType(type, false, visitedTypesInner)) {
330-
if (shouldOutput(typeDef, visitedTypes)) {
329+
if (shouldOutputTypeDef(typeDef, visitedTypes)) {
331330
return true;
332331
}
333332
}
@@ -462,13 +461,21 @@ IR::~IR() {
462461
}
463462

464463
template <typename T>
465-
bool IR::hasOutputtedDeclaration(
464+
bool IR::hasOutputtedType(
466465
const std::vector<std::shared_ptr<T>> &declarations) const {
467466
std::vector<std::shared_ptr<const Type>> visitedTypes;
468467
for (const auto &declaration : declarations) {
469468
visitedTypes.clear();
470-
if (shouldOutput(declaration, visitedTypes)) {
471-
return true;
469+
auto typeDefPointer =
470+
std::dynamic_pointer_cast<const TypeDef>(declaration);
471+
if (typeDefPointer) {
472+
if (shouldOutputTypeDef(typeDefPointer, visitedTypes)) {
473+
return true;
474+
}
475+
} else {
476+
if (shouldOutput(declaration, visitedTypes)) {
477+
return true;
478+
}
472479
}
473480
}
474481
return false;
@@ -477,12 +484,31 @@ bool IR::hasOutputtedDeclaration(
477484
bool IR::shouldOutput(
478485
const std::shared_ptr<const LocatableType> &type,
479486
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
487+
if (locationManager.isImported(*type->getLocation())) {
488+
return false;
489+
}
480490
if (isTypeUsed(type, visitedTypes)) {
481491
return true;
482492
}
483-
if (isAliasForOpaqueType(type.get())) {
493+
/* remove unused types from included files */
494+
return locationManager.inMainFile(*type->getLocation());
495+
}
496+
497+
bool IR::shouldOutputTypeDef(
498+
const std::shared_ptr<const TypeDef> &typeDef,
499+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
500+
if (isTypeUsed(typeDef, visitedTypes)) {
501+
if (typeDef->wrapperForOpaqueType()) {
502+
/* it is not possible to get location of this typedef
503+
* so the typedef cannot be imported from other bindings */
504+
return true;
505+
}
506+
return !locationManager.isImported(*typeDef->getLocation());
507+
}
508+
if (isAliasForOpaqueType(typeDef.get())) {
509+
/* it does not matter where unused alias for opaque type is located */
484510
return false;
485511
}
486512
/* remove unused types from included files */
487-
return locationManager.inMainFile(*type->getLocation());
513+
return locationManager.inMainFile(*typeDef->getLocation());
488514
}

bindgen/ir/IR.h

+16-6
Original file line numberDiff line numberDiff line change
@@ -153,21 +153,31 @@ class IR {
153153
/**
154154
* @return true if the type will be printed.
155155
* Following types are not printed:
156+
* - Types that should be imported from other bindings
156157
* - Unused types from included headers
157-
* - Unused typedefs from main header if they reference an opaque
158-
* type (if such typedef is used then true is returned but error
159-
* message is printed when bindings are generated)
160158
*/
161159
bool
162160
shouldOutput(const std::shared_ptr<const LocatableType> &type,
163161
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
164162

165163
/**
166-
* @tparam T Struct or Union
164+
* @return true if typedef will be printed.
165+
* Following typedefs are not printed:
166+
* - TypeDefs that should be imported from other bindings
167+
* - Unused typedefs from included headers
168+
* - Unused typedefs from main header if they reference an opaque
169+
* type
170+
*/
171+
bool shouldOutputTypeDef(
172+
const std::shared_ptr<const TypeDef> &typeDef,
173+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
174+
175+
/**
176+
* @tparam T one of LocatableType
167177
*/
168178
template <typename T>
169-
bool hasOutputtedDeclaration(
170-
const std::vector<std::shared_ptr<T>> &declarations) const;
179+
bool
180+
hasOutputtedType(const std::vector<std::shared_ptr<T>> &declarations) const;
171181

172182
std::string libName; // name of the library
173183
std::string linkName; // name of the library to link with

bindgen/ir/LiteralDefine.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ LiteralDefine::LiteralDefine(std::string name, std::string literal,
44
std::shared_ptr<const Type> type)
55
: Define(std::move(name)), literal(std::move(literal)), type(type) {}
66

7-
llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
8-
const LiteralDefine &literalDefine) {
9-
s << " val " << literalDefine.name << ": " << literalDefine.type->str()
10-
<< " = " << literalDefine.literal << "\n";
11-
return s;
7+
std::string
8+
LiteralDefine::getDefinition(const LocationManager &locationManager) const {
9+
return " val " + name + ": " + type->str(locationManager) + " = " +
10+
literal + "\n";
1211
}
1312

1413
bool LiteralDefine::usesType(

bindgen/ir/LiteralDefine.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class LiteralDefine : public Define {
1010
LiteralDefine(std::string name, std::string literal,
1111
std::shared_ptr<const Type> type);
1212

13-
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
14-
const LiteralDefine &literalDefine);
13+
std::string getDefinition(const LocationManager &locationManager) const;
1514

1615
bool usesType(const std::shared_ptr<const Type> &type, bool stopOnTypeDefs,
1716
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;

bindgen/ir/Location.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Location {
1212
int getLineNumber() const;
1313

1414
private:
15-
std::string path;
15+
std::string path; // may be empty
1616
int lineNumber;
1717
};
1818

0 commit comments

Comments
 (0)