• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gn/eclipse_writer.h"
6 
7 #include <fstream>
8 #include <memory>
9 
10 #include "base/files/file_path.h"
11 #include "gn/builder.h"
12 #include "gn/config_values_extractors.h"
13 #include "gn/filesystem_utils.h"
14 #include "gn/loader.h"
15 #include "gn/xml_element_writer.h"
16 
17 namespace {
18 
19 // Escapes |unescaped| for use in XML element content.
EscapeForXML(const std::string & unescaped)20 std::string EscapeForXML(const std::string& unescaped) {
21   std::string result;
22   result.reserve(unescaped.length());
23   for (const char c : unescaped) {
24     if (c == '<')
25       result += "&lt;";
26     else if (c == '>')
27       result += "&gt;";
28     else if (c == '&')
29       result += "&amp;";
30     else
31       result.push_back(c);
32   }
33   return result;
34 }
35 
36 }  // namespace
37 
EclipseWriter(const BuildSettings * build_settings,const Builder & builder,std::ostream & out)38 EclipseWriter::EclipseWriter(const BuildSettings* build_settings,
39                              const Builder& builder,
40                              std::ostream& out)
41     : build_settings_(build_settings), builder_(builder), out_(out) {
42   languages_.push_back("C++ Source File");
43   languages_.push_back("C Source File");
44   languages_.push_back("Assembly Source File");
45   languages_.push_back("GNU C++");
46   languages_.push_back("GNU C");
47   languages_.push_back("Assembly");
48 }
49 
50 EclipseWriter::~EclipseWriter() = default;
51 
52 // static
RunAndWriteFile(const BuildSettings * build_settings,const Builder & builder,Err * err)53 bool EclipseWriter::RunAndWriteFile(const BuildSettings* build_settings,
54                                     const Builder& builder,
55                                     Err* err) {
56   base::FilePath file = build_settings->GetFullPath(build_settings->build_dir())
57                             .AppendASCII("eclipse-cdt-settings.xml");
58   std::ofstream file_out;
59   file_out.open(FilePathToUTF8(file).c_str(),
60                 std::ios_base::out | std::ios_base::binary);
61   if (file_out.fail()) {
62     *err =
63         Err(Location(), "Couldn't open eclipse-cdt-settings.xml for writing");
64     return false;
65   }
66 
67   EclipseWriter gen(build_settings, builder, file_out);
68   gen.Run();
69   return true;
70 }
71 
Run()72 void EclipseWriter::Run() {
73   GetAllIncludeDirs();
74   GetAllDefines();
75   WriteCDTSettings();
76 }
77 
GetAllIncludeDirs()78 void EclipseWriter::GetAllIncludeDirs() {
79   std::vector<const Target*> targets = builder_.GetAllResolvedTargets();
80   for (const Target* target : targets) {
81     if (!UsesDefaultToolchain(target))
82       continue;
83 
84     for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
85       for (const SourceDir& include_dir : it.cur().include_dirs()) {
86         include_dirs_.insert(
87             FilePathToUTF8(build_settings_->GetFullPath(include_dir)));
88       }
89     }
90   }
91 }
92 
GetAllDefines()93 void EclipseWriter::GetAllDefines() {
94   std::vector<const Target*> targets = builder_.GetAllResolvedTargets();
95   for (const Target* target : targets) {
96     if (!UsesDefaultToolchain(target))
97       continue;
98 
99     for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
100       for (const std::string& define : it.cur().defines()) {
101         size_t equal_pos = define.find('=');
102         std::string define_key;
103         std::string define_value;
104         if (equal_pos == std::string::npos) {
105           define_key = define;
106         } else {
107           define_key = define.substr(0, equal_pos);
108           define_value = define.substr(equal_pos + 1);
109         }
110         defines_[define_key] = define_value;
111       }
112     }
113   }
114 }
115 
UsesDefaultToolchain(const Target * target) const116 bool EclipseWriter::UsesDefaultToolchain(const Target* target) const {
117   return target->toolchain()->label() ==
118          builder_.loader()->GetDefaultToolchain();
119 }
120 
WriteCDTSettings()121 void EclipseWriter::WriteCDTSettings() {
122   out_ << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
123   XmlElementWriter cdt_properties_element(out_, "cdtprojectproperties",
124                                           XmlAttributes());
125 
126   {
127     const char* kIncludesSectionName =
128         "org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths";
129     std::unique_ptr<XmlElementWriter> section_element =
130         cdt_properties_element.SubElement(
131             "section", XmlAttributes("name", kIncludesSectionName));
132 
133     section_element->SubElement(
134         "language", XmlAttributes("name", "holder for library settings"));
135 
136     for (const std::string& language : languages_) {
137       std::unique_ptr<XmlElementWriter> language_element =
138           section_element->SubElement("language",
139                                       XmlAttributes("name", language));
140       for (const std::string& include_dir : include_dirs_) {
141         language_element
142             ->SubElement("includepath",
143                          XmlAttributes("workspace_path", "false"))
144             ->Text(EscapeForXML(include_dir));
145       }
146     }
147   }
148 
149   {
150     const char* kMacrosSectionName =
151         "org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros";
152     std::unique_ptr<XmlElementWriter> section_element =
153         cdt_properties_element.SubElement(
154             "section", XmlAttributes("name", kMacrosSectionName));
155 
156     section_element->SubElement(
157         "language", XmlAttributes("name", "holder for library settings"));
158 
159     for (const std::string& language : languages_) {
160       std::unique_ptr<XmlElementWriter> language_element =
161           section_element->SubElement("language",
162                                       XmlAttributes("name", language));
163       for (const auto& key_val : defines_) {
164         std::unique_ptr<XmlElementWriter> macro_element =
165             language_element->SubElement("macro");
166         macro_element->SubElement("name")->Text(EscapeForXML(key_val.first));
167         macro_element->SubElement("value")->Text(EscapeForXML(key_val.second));
168       }
169     }
170   }
171 }
172