Skip to content

Commit 1242546

Browse files
committed
Reuse generated bindings
1 parent bc0fea7 commit 1242546

33 files changed

+362
-150
lines changed

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+
"use-bindings", llvm::cl::cat(Category),
31+
llvm::cl::desc(
32+
"File that contains information about generated bindings."));
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
char *resolved = realpath(op.getSourcePathList()[0].c_str(), nullptr);
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

+19
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ static inline bool startsWith(const std::string &str,
6363
return str.substr(0, prefix.size()) == prefix;
6464
}
6565

66+
/**
67+
* @return true if str ends with given prefix
68+
*/
69+
static inline bool endsWith(const std::string &str, const std::string &suffix) {
70+
return str.substr(str.length() - suffix.size(), str.length()) == suffix;
71+
}
72+
6673
template <typename T, typename PT> static inline bool isInstanceOf(PT *type) {
6774
auto *p = dynamic_cast<const T *>(type);
6875
return p != nullptr;
@@ -119,4 +126,16 @@ static inline bool contains(const Type *type,
119126
return false;
120127
}
121128

129+
static inline std::string getRealPath(const char *path) {
130+
char *p = realpath(path, nullptr);
131+
std::string realPath;
132+
if (p) {
133+
realPath = p;
134+
delete[] p;
135+
} else {
136+
realPath = "";
137+
}
138+
return realPath;
139+
}
140+
122141
#endif // UTILS_H

bindgen/ir/Function.cpp

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Function.h"
22
#include "../Utils.h"
33
#include "Struct.h"
4+
#include <sstream>
45

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

14-
llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) {
15-
if (func.scalaName != func.name) {
16-
s << " @native.link(\"" << func.name << "\")\n";
15+
std::string
16+
Function::getDefinition(const LocationManager &locationManager) const {
17+
std::stringstream s;
18+
if (scalaName != name) {
19+
s << " @native.link(\"" << name << "\")\n";
1720
}
18-
s << " def " << handleReservedWords(func.scalaName) << "(";
21+
s << " def " << handleReservedWords(scalaName) << "(";
1922
std::string sep = "";
20-
for (const auto &param : func.parameters) {
23+
for (const auto &param : parameters) {
2124
s << sep << handleReservedWords(param->getName()) << ": "
22-
<< param->getType()->str();
25+
<< param->getType()->str(locationManager);
2326
sep = ", ";
2427
}
25-
if (func.isVariadic) {
28+
if (isVariadic) {
2629
/* the C Iso require at least one argument in a variadic function, so
2730
* the comma is fine */
28-
s << ", " << func.getVarargsParameterName() << ": native.CVararg*";
31+
s << ", " << getVarargsParameterName() << ": native.CVararg*";
2932
}
30-
s << "): " << func.retType->str() << " = native.extern\n";
31-
return s;
33+
s << "): " << retType->str(locationManager) << " = native.extern\n";
34+
return s.str();
3235
}
3336

3437
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
@@ -81,10 +81,9 @@ void IR::addVarDefine(std::string name, std::shared_ptr<Variable> variable) {
8181
}
8282

8383
bool IR::libObjEmpty() const {
84-
return functions.empty() && !hasOutputtedDeclaration(typeDefs) &&
85-
!hasOutputtedDeclaration(structs) &&
86-
!hasOutputtedDeclaration(unions) && varDefines.empty() &&
87-
variables.empty();
84+
return functions.empty() && !hasOutputtedType(typeDefs) &&
85+
!hasOutputtedType(structs) && !hasOutputtedType(unions) &&
86+
varDefines.empty() && variables.empty();
8887
}
8988

9089
llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
@@ -94,7 +93,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
9493
s << "package " << ir.packageName << "\n\n";
9594
}
9695

97-
if (!ir.libObjEmpty() || ir.hasOutputtedDeclaration(ir.enums) ||
96+
if (!ir.libObjEmpty() || ir.hasOutputtedType(ir.enums) ||
9897
!ir.literalDefines.empty()) {
9998
s << "import scala.scalanative._\n"
10099
<< "import scala.scalanative.native._\n\n";
@@ -117,8 +116,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
117116

118117
for (const auto &typeDef : ir.typeDefs) {
119118
visitedTypes.clear();
120-
if (ir.shouldOutput(typeDef, visitedTypes)) {
121-
s << *typeDef;
119+
if (ir.shouldOutputTypeDef(typeDef, visitedTypes)) {
120+
s << typeDef->getDefinition(ir.locationManager);
122121
} else if (typeDef->hasLocation() &&
123122
isAliasForOpaqueType(typeDef.get()) &&
124123
ir.locationManager.inMainFile(*typeDef->getLocation())) {
@@ -132,7 +131,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
132131

133132
for (const auto &variable : ir.variables) {
134133
if (!variable->hasIllegalUsageOfOpaqueType()) {
135-
s << *variable;
134+
s << variable->getDefinition(ir.locationManager);
136135
} else {
137136
llvm::errs() << "Error: Variable " << variable->getName()
138137
<< " is skipped because it has incomplete type.\n";
@@ -141,7 +140,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
141140

142141
for (const auto &varDefine : ir.varDefines) {
143142
if (!varDefine->hasIllegalUsageOfOpaqueType()) {
144-
s << *varDefine;
143+
s << varDefine->getDefinition(ir.locationManager);
145144
} else {
146145
llvm::errs() << "Error: Variable alias " << varDefine->getName()
147146
<< " is skipped because it has incomplete type.\n";
@@ -156,7 +155,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
156155
"passing structs and arrays by value.\n";
157156
llvm::errs().flush();
158157
} else {
159-
s << *func;
158+
s << func->getDefinition(ir.locationManager);
160159
}
161160
}
162161

@@ -167,16 +166,16 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
167166
if (!ir.literalDefines.empty()) {
168167
s << "object " << ir.libName << "Defines {\n";
169168
for (const auto &literalDefine : ir.literalDefines) {
170-
s << *literalDefine;
169+
s << literalDefine->getDefinition(ir.locationManager);
171170
}
172171
s << "}\n\n";
173172
}
174173

175-
if (ir.hasOutputtedDeclaration(ir.enums) || ir.hasHelperMethods()) {
174+
if (ir.hasOutputtedType(ir.enums) || ir.hasHelperMethods()) {
176175
s << "import " << objectName << "._\n\n";
177176
}
178177

179-
if (ir.hasOutputtedDeclaration(ir.enums)) {
178+
if (ir.hasOutputtedType(ir.enums)) {
180179
s << "object " << ir.libName << "Enums {\n";
181180

182181
std::string sep = "";
@@ -197,14 +196,14 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
197196
for (const auto &st : ir.structs) {
198197
visitedTypes.clear();
199198
if (ir.shouldOutput(st, visitedTypes) && st->hasHelperMethods()) {
200-
s << "\n" << st->generateHelperClass();
199+
s << "\n" << st->generateHelperClass(ir.locationManager);
201200
}
202201
}
203202

204203
for (const auto &u : ir.unions) {
205204
visitedTypes.clear();
206205
if (ir.shouldOutput(u, visitedTypes) && u->hasHelperMethods()) {
207-
s << "\n" << u->generateHelperClass();
206+
s << "\n" << u->generateHelperClass(ir.locationManager);
208207
}
209208
}
210209

@@ -321,7 +320,7 @@ bool IR::isTypeUsed(
321320
for (const auto &typeDef : typeDefs) {
322321
visitedTypesInner.clear();
323322
if (typeDef->usesType(type, false, visitedTypesInner)) {
324-
if (shouldOutput(typeDef, visitedTypes)) {
323+
if (shouldOutputTypeDef(typeDef, visitedTypes)) {
325324
return true;
326325
}
327326
}
@@ -461,13 +460,21 @@ IR::~IR() {
461460
}
462461

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

bindgen/ir/IR.h

+16-6
Original file line numberDiff line numberDiff line change
@@ -159,21 +159,31 @@ class IR {
159159
/**
160160
* @return true if the type will be printed.
161161
* Following types are not printed:
162+
* - Types that should be imported from other bindings
162163
* - Unused types from included headers
163-
* - Unused typedefs from main header if they reference an opaque
164-
* type (if such typedef is used then true is returned but error
165-
* message is printed when bindings are generated)
166164
*/
167165
bool
168166
shouldOutput(const std::shared_ptr<const LocatableType> &type,
169167
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
170168

171169
/**
172-
* @tparam T Struct or Union
170+
* @return true if typedef will be printed.
171+
* Following typedefs are not printed:
172+
* - TypeDefs that should be imported from other bindings
173+
* - Unused typedefs from included headers
174+
* - Unused typedefs from main header if they reference an opaque
175+
* type
176+
*/
177+
bool shouldOutputTypeDef(
178+
const std::shared_ptr<const TypeDef> &typeDef,
179+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
180+
181+
/**
182+
* @tparam T one of LocatableType
173183
*/
174184
template <typename T>
175-
bool hasOutputtedDeclaration(
176-
const std::vector<std::shared_ptr<T>> &declarations) const;
185+
bool
186+
hasOutputtedType(const std::vector<std::shared_ptr<T>> &declarations) const;
177187

178188
std::string libName; // name of the library
179189
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/LocationManager.cpp

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,45 @@
11
#include "LocationManager.h"
2+
#include "../Utils.h"
3+
#include "Enum.h"
4+
#include "Struct.h"
5+
#include <fstream>
26

37
LocationManager::LocationManager(std::string mainHeaderPath)
48
: mainHeaderPath(std::move(mainHeaderPath)) {}
59

610
void LocationManager::loadConfig(const std::string &path) {
7-
// TODO: implement
11+
std::string realPath = getRealPath(path.c_str());
12+
13+
std::ifstream input(realPath);
14+
for (std::string line; getline(input, line);) {
15+
size_t f = line.find('=');
16+
if (f != std::string::npos) {
17+
std::string header = line.substr(0, f);
18+
std::string import = line.substr(f + 1, std::string::npos);
19+
existingBindings[header] = import;
20+
}
21+
}
822
}
923

1024
bool LocationManager::inMainFile(const Location &location) const {
1125
return location.getPath() == mainHeaderPath;
1226
}
27+
28+
bool LocationManager::isImported(const Location &location) const {
29+
for (const auto &existingBinding : existingBindings) {
30+
if (endsWith(location.getPath(), existingBinding.first)) {
31+
return true;
32+
}
33+
}
34+
return false;
35+
}
36+
37+
std::string
38+
LocationManager::getContainingObject(const Location &location) const {
39+
for (const auto &existingBinding : existingBindings) {
40+
if (endsWith(location.getPath(), existingBinding.first)) {
41+
return existingBinding.second;
42+
}
43+
}
44+
assert(false && "Location is not in the list of imported bindings");
45+
}

bindgen/ir/LocationManager.h

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ class LocationManager {
1313

1414
bool inMainFile(const Location &location) const;
1515

16+
/**
17+
* @return true if given type is imported from another Scala object
18+
*/
19+
bool isImported(const Location &location) const;
20+
21+
std::string getContainingObject(const Location &location) const;
22+
1623
private:
1724
std::string mainHeaderPath;
1825
std::unordered_map<std::string, std::string> existingBindings;

0 commit comments

Comments
 (0)