Skip to content

Commit 8b60db2

Browse files
mrziwangColecf
authored andcommitted
Add func KATI_visibility_prefix
syntax: $(KATI_visibility_prefix var, prefix) 1, Add a func KATI_visibility_prefix that takes a variable name and a list of strings, set this variable's visibility to these strings. Each string represents the relative path from the root, and is considered as prefix. e.g. $(KATI_visibility_prefix VAR, vendor/ device/b baz.mk) --> VAR is visible to "vendor/foo.mk", "device/bar.mk", "device/baz.mk", "baz.mk", but not visible to "bar.mk", "vendor.mk" or "vendor/baz.mk". If variable visibility is set more than once, and with a different list of strings, an error will occur. 2. When a variable is being referenced, if this variable has visibility prefix set, check if the current referencing file matches the visibility prefix. Throw an error if not. 3. In $(KATI_visibility_prefix FOO, prefix) If FOO is not defined, create a variable FOO with empty value. The prefix can also be reference to variable. If so, this function will expand the reference and set the visibility_prefix.
1 parent 2c503b6 commit 8b60db2

17 files changed

+224
-3
lines changed

src/expr.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class SymRef : public Value {
146146
Var* v = ev->LookupVarForEval(name_);
147147
v->Used(ev, name_);
148148
v->Eval(ev, s);
149+
v->CheckCurrentReferencingFile(ev->loc(), name_.c_str());
149150
ev->VarEvalComplete(name_);
150151
}
151152

@@ -176,6 +177,7 @@ class VarRef : public Value {
176177
Var* v = ev->LookupVarForEval(sym);
177178
v->Used(ev, sym);
178179
v->Eval(ev, s);
180+
v->CheckCurrentReferencingFile(ev->loc(), name.c_str());
179181
ev->VarEvalComplete(sym);
180182
}
181183

src/find.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#include <string_view>
2929
#include <vector>
3030

31-
//#undef NOLOG
31+
// #undef NOLOG
3232

3333
#include "fileutil.h"
3434
#include "log.h"

src/func.cc

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <algorithm>
2828
#include <iterator>
2929
#include <memory>
30+
#include <sstream>
3031
#include <unordered_map>
3132

3233
#include "eval.h"
@@ -510,7 +511,7 @@ void EvalFunc(const std::vector<Value*>& args, Evaluator* ev, std::string*) {
510511
}
511512
}
512513

513-
//#define TEST_FIND_EMULATOR
514+
// #define TEST_FIND_EMULATOR
514515

515516
// A hack for Android build. We need to evaluate things like $((3+4))
516517
// when we emit ninja file, because the result of such expressions
@@ -656,6 +657,59 @@ void ShellFuncNoRerun(const std::vector<Value*>& args,
656657
ShellStatusVar::SetValue(returnCode);
657658
}
658659

660+
void VarVisibilityFunc(const std::vector<Value*>& args,
661+
Evaluator* ev,
662+
std::string* s) {
663+
std::string arg = args[0]->Eval(ev);
664+
std::vector<std::string> prefixes;
665+
666+
std::stringstream ss(args[1]->Eval(ev));
667+
std::string prefix;
668+
while (ss >> prefix) {
669+
if (HasPrefix(prefix, "/")) {
670+
ERROR_LOC(ev->loc(), "Visibility prefix should not start with /");
671+
}
672+
if (HasPrefix(prefix, "../")) {
673+
ERROR_LOC(ev->loc(), "Visibility prefix should not start with ../");
674+
}
675+
676+
std::string normalizedPrefix = prefix;
677+
NormalizePath(&normalizedPrefix);
678+
if (prefix != normalizedPrefix) {
679+
ERROR_LOC(ev->loc(),
680+
"Visibility prefix %s is not normalized. Normalized prefix: %s",
681+
prefix.c_str(), normalizedPrefix.c_str());
682+
}
683+
684+
// one visibility prefix cannot be the prefix of another visibility prefix
685+
for (std::vector<std::string>::iterator it = prefixes.begin();
686+
it != prefixes.end(); ++it) {
687+
if (HasPathPrefix(*it, prefix)) {
688+
ERROR_LOC(ev->loc(),
689+
"Visibility prefix %s is the prefix of another visibility "
690+
"prefix %s",
691+
prefix.c_str(), it->c_str());
692+
} else if (HasPathPrefix(prefix, *it)) {
693+
ERROR_LOC(ev->loc(),
694+
"Visibility prefix %s is the prefix of another visibility "
695+
"prefix %s",
696+
it->c_str(), prefix.c_str());
697+
}
698+
}
699+
700+
prefixes.push_back(prefix);
701+
}
702+
703+
Symbol sym = Intern(arg);
704+
Var* v = ev->PeekVar(sym);
705+
// If variable is not defined, create an empty variable.
706+
if (!v->IsDefined()) {
707+
v = new SimpleVar(VarOrigin::FILE, ev->CurrentFrame(), ev->loc());
708+
sym.SetGlobalVar(v, false, nullptr);
709+
}
710+
v->SetVisibilityPrefix(prefixes, sym.c_str());
711+
}
712+
659713
void CallFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) {
660714
static const Symbol tmpvar_names[] = {
661715
Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
@@ -1149,6 +1203,7 @@ static const std::unordered_map<std::string_view, FuncInfo> g_func_info_map = {
11491203
ENTRY("KATI_shell_no_rerun", &ShellFuncNoRerun, 1, 1, false, false),
11501204
ENTRY("KATI_foreach_sep", &ForeachWithSepFunc, 4, 4, false, false),
11511205
ENTRY("KATI_file_no_rerun", &FileFuncNoRerun, 2, 1, false, false),
1206+
ENTRY("KATI_visibility_prefix", &VarVisibilityFunc, 2, 1, false, false),
11521207
};
11531208

11541209
} // namespace

src/strutil.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ bool HasPrefix(std::string_view str, std::string_view prefix) {
110110
return size_diff >= 0 && str.substr(0, prefix.size()) == prefix;
111111
}
112112

113+
bool HasPathPrefix(std::string_view str, std::string_view prefix) {
114+
return HasPrefix(str, prefix) &&
115+
(str.size() == prefix.size() || str.at(prefix.size()) == '/');
116+
}
117+
113118
bool HasSuffix(std::string_view str, std::string_view suffix) {
114119
ssize_t size_diff = str.size() - suffix.size();
115120
return size_diff >= 0 && str.substr(size_diff) == suffix;

src/strutil.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ inline std::string JoinStrings(std::vector<String> v, const char* sep) {
8080

8181
bool HasPrefix(std::string_view str, std::string_view prefix);
8282

83+
// Checks path-like prefixes. str and prefix and both considered as strings
84+
// that represent "path".
85+
// e.g. str "foo/bar" has path prefix "foo" but doesn't have path prefix "fo".
86+
bool HasPathPrefix(std::string_view str, std::string_view prefix);
87+
8388
bool HasSuffix(std::string_view str, std::string_view suffix);
8489

8590
bool HasWord(std::string_view str, std::string_view w);

src/symtab.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
// +build ignore
1616

17-
//#define ENABLE_TID_CHECK
17+
// #define ENABLE_TID_CHECK
1818

1919
#include "symtab.h"
2020

src/var.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,41 @@ void Var::Used(Evaluator* ev, const Symbol& sym) const {
8585
}
8686
}
8787

88+
void Var::SetVisibilityPrefix(const std::vector<std::string>& prefixes,
89+
const char* name) {
90+
const std::vector<std::string>& current_prefixes = VisibilityPrefix();
91+
if (current_prefixes.size() == 0) {
92+
visibility_prefix_ = prefixes;
93+
} else if (current_prefixes != prefixes) {
94+
ERROR("Visibility prefix conflict on variable: %s", name);
95+
}
96+
}
97+
98+
void Var::CheckCurrentReferencingFile(Loc loc, const char* name) {
99+
const std::vector<std::string>& prefixes = VisibilityPrefix();
100+
if (prefixes.size() == 0) {
101+
return;
102+
}
103+
bool valid = false;
104+
for (const std::string& prefix : prefixes) {
105+
if (HasPathPrefix(loc.filename, prefix)) {
106+
valid = true;
107+
break;
108+
}
109+
}
110+
if (!valid) {
111+
std::string prefixesString;
112+
for (const std::string& p : prefixes) {
113+
prefixesString += (p + "\n");
114+
}
115+
prefixesString.pop_back();
116+
ERROR(
117+
"%s is not a valid file to reference variable %s. Line #%d.\nValid "
118+
"file prefixes:\n%s",
119+
loc.filename, name, loc.lineno, prefixesString.c_str());
120+
}
121+
}
122+
88123
const char* Var::diagnostic_message_text() const {
89124
auto it = diagnostic_messages_.find(this);
90125
return it == diagnostic_messages_.end() ? "" : it->second.c_str();

src/var.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ class Var : public Evaluable {
7373
bool SelfReferential() const { return self_referential_; }
7474
void SetSelfReferential() { self_referential_ = true; }
7575

76+
const std::vector<std::string>& VisibilityPrefix() const {
77+
return visibility_prefix_;
78+
}
79+
void SetVisibilityPrefix(const std::vector<std::string>& prefixes,
80+
const char* name);
81+
void CheckCurrentReferencingFile(Loc loc, const char* name);
82+
7683
const std::string& DeprecatedMessage() const;
7784

7885
// This variable was used (either written or read from)
@@ -101,6 +108,8 @@ class Var : public Evaluable {
101108
const char* diagnostic_message_text() const;
102109

103110
static std::unordered_map<const Var*, std::string> diagnostic_messages_;
111+
112+
std::vector<std::string> visibility_prefix_;
104113
};
105114

106115
class SimpleVar : public Var {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FOO := foo
2+
BAR := bar
3+
PREFIX := pone/ptwo
4+
5+
$(KATI_visibility_prefix FOO, pone/ptwo baz)
6+
$(KATI_visibility_prefix FOO, $(PREFIX) baz)
7+
8+
$(KATI_visibility_prefix BAR, pone/ptwo baz)
9+
$(KATI_visibility_prefix BAR, baz $(PREFIX))
10+
11+
ifndef KATI
12+
$(info Visibility prefix conflict on variable: BAR)
13+
endif
14+
15+
test:
16+
@:
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
$(KATI_visibility_prefix FOO, Makefile)
2+
3+
BAR := $(FOO)
4+
5+
test:
6+
echo '$(BAR)'

0 commit comments

Comments
 (0)