diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 567238aed1..8e0a0aa437 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -181,6 +181,68 @@ bool TryCreateParentDirectory(const string& prefix, const string& filename) { return true; } +// Get the absolute path of this protoc binary. +bool GetProtocAbsolutePath(string* path) { +#ifdef _WIN32 + char buffer[MAX_PATH]; + int len = GetModuleFileName(NULL, buffer, MAX_PATH); +#else + char buffer[PATH_MAX]; + int len = readlink("/proc/self/exe", buffer, PATH_MAX); +#endif + if (len > 0) { + path->assign(buffer, len); + return true; + } else { + return false; + } +} + +// Whether a path is where google/protobuf/descriptor.proto and other well-known +// type protos are installed. +bool IsInstalledProtoPath(const string& path) { + // Checking the descriptor.proto file should be good enough. + string file_path = path + "/google/protobuf/descriptor.proto"; + return access(file_path.c_str(), F_OK) != -1; +} + +// Add the paths where google/protobuf/descritor.proto and other well-known +// type protos are installed. +void AddDefaultProtoPaths(vector >* paths) { + // TODO(xiaofeng): The code currently only checks relative paths of where + // the protoc binary is installed. We probably should make it handle more + // cases than that. + string path; + if (!GetProtocAbsolutePath(&path)) { + return; + } + // Strip the binary name. + size_t pos = path.find_last_of("/\\"); + if (pos == string::npos || pos == 0) { + return; + } + path = path.substr(0, pos); + // Check the binary's directory. + if (IsInstalledProtoPath(path)) { + paths->push_back(pair("", path)); + return; + } + // Check if there is an include subdirectory. + if (IsInstalledProtoPath(path + "/include")) { + paths->push_back(pair("", path + "/include")); + return; + } + // Check if the upper level directory has an "include" subdirectory. + pos = path.find_last_of("/\\"); + if (pos == string::npos || pos == 0) { + return; + } + path = path.substr(0, pos); + if (IsInstalledProtoPath(path + "/include")) { + paths->push_back(pair("", path + "/include")); + return; + } +} } // namespace // A MultiFileErrorCollector that prints errors to stderr. @@ -644,6 +706,8 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { break; } + AddDefaultProtoPaths(&proto_path_); + // Set up the source tree. DiskSourceTree source_tree; for (int i = 0; i < proto_path_.size(); i++) {