Allow property += value in ld.config.txt
ld.config.txt currently does not support split line. As the file gets
larger, this limitation makes the file very unreadable. Now, long lines
can be avoided by breaking one line into multiple lines using +=
operator.
ex)
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /system/${LIB}
Delimitor (':' for *.paths and *.shared_libs, and ',' for *.links) is
automatically added.
Bug: 69888716
Test: linker-unit-tests passes
Change-Id: I4b94fd4e7f8a76d59db8d1096c86aa2118e46625
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index f7d2c53..b203569 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -49,7 +49,8 @@
class ConfigParser {
public:
enum {
- kProperty,
+ kPropertyAssign,
+ kPropertyAppend,
kSection,
kEndOfFile,
kError,
@@ -60,7 +61,8 @@
/*
* Possible return values
- * kProperty: name is set to property name and value is set to property value
+ * kPropertyAssign: name is set to property name and value is set to property value
+ * kPropertyAppend: same as kPropertyAssign, but the value should be appended
* kSection: name is set to section name.
* kEndOfFile: reached end of file.
* kError: error_msg is set.
@@ -80,17 +82,24 @@
return kSection;
}
- found = line.find('=');
- if (found == std::string::npos) {
- *error_msg = std::string("invalid format: ") +
- line +
- ", expected \"name = property\" or \"[section]\"";
- return kError;
+ size_t found_assign = line.find('=');
+ size_t found_append = line.find("+=");
+ if (found_assign != std::string::npos && found_append == std::string::npos) {
+ *name = android::base::Trim(line.substr(0, found_assign));
+ *value = android::base::Trim(line.substr(found_assign + 1));
+ return kPropertyAssign;
}
- *name = android::base::Trim(line.substr(0, found));
- *value = android::base::Trim(line.substr(found + 1));
- return kProperty;
+ if (found_append != std::string::npos) {
+ *name = android::base::Trim(line.substr(0, found_append));
+ *value = android::base::Trim(line.substr(found_append + 2));
+ return kPropertyAppend;
+ }
+
+ *error_msg = std::string("invalid format: ") +
+ line +
+ ", expected \"name = property\", \"name += property\", or \"[section]\"";
+ return kError;
}
// to avoid infinite cycles when programmer makes a mistake
@@ -141,6 +150,14 @@
return value_;
}
+ void append_value(std::string&& value) {
+ value_ = value_ + value;
+ // lineno isn't updated as we might have cases like this:
+ // property.x = blah
+ // property.y = blah
+ // property.x += blah
+ }
+
size_t lineno() const {
return lineno_;
}
@@ -194,7 +211,7 @@
return false;
}
- if (result == ConfigParser::kProperty) {
+ if (result == ConfigParser::kPropertyAssign) {
if (!android::base::StartsWith(name, "dir.")) {
DL_WARN("error parsing %s:%zd: unexpected property name \"%s\", "
"expected format dir.<section_name> (ignoring this line)",
@@ -255,7 +272,7 @@
break;
}
- if (result == ConfigParser::kProperty) {
+ if (result == ConfigParser::kPropertyAssign) {
if (properties->find(name) != properties->end()) {
DL_WARN("%s:%zd: warning: property \"%s\" redefinition",
ld_config_file_path,
@@ -264,6 +281,29 @@
}
(*properties)[name] = PropertyValue(std::move(value), cp.lineno());
+ } else if (result == ConfigParser::kPropertyAppend) {
+ if (properties->find(name) == properties->end()) {
+ DL_WARN("%s:%zd: warning: appending to property \"%s\" which isn't defined",
+ ld_config_file_path,
+ cp.lineno(),
+ name.c_str());
+ (*properties)[name] = PropertyValue(std::move(value), cp.lineno());
+ } else {
+ if (android::base::EndsWith(name, ".links") ||
+ android::base::EndsWith(name, ".namespaces")) {
+ value = "," + value;
+ (*properties)[name].append_value(std::move(value));
+ } else if (android::base::EndsWith(name, ".paths") ||
+ android::base::EndsWith(name, ".shared_libs")) {
+ value = ":" + value;
+ (*properties)[name].append_value(std::move(value));
+ } else {
+ DL_WARN("%s:%zd: warning: += isn't allowed to property \"%s\". Ignoring.",
+ ld_config_file_path,
+ cp.lineno(),
+ name.c_str());
+ }
+ }
}
if (result == ConfigParser::kError) {