main.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * @package RobotAPI::application::AronArmemGenerator
17  * @author fabian.peller-konrad@kit.edu ( fabian dot peller-konrad at kit dot edu )
18  * @date 2020
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 // STD/STL
24 #include <ctime>
25 #include <filesystem>
26 #include <iostream>
27 
28 // CXXOPTS
29 #include "cxxopts.hpp"
30 
31 // ArmarX Executable
32 //#include <ArmarXCore/core/application/Application.h>
33 //#include <ArmarXCore/core/Component.h>
34 //#include <ArmarXCore/core/logging/Logging.h>
35 
36 // Aron
39 
40 #include <RobotAPI/interface/aron.h>
43 
44 using namespace armarx;
45 using namespace aron;
46 
47 /// Aron Code Generator Main Executable.
48 /// This executable calls generates a aron code file out of an aron xml file.
49 int
50 main(int argc, char* argv[])
51 {
52  try
53  {
54  cxxopts::Options options("AronArmemCodeGenerator",
55  "An application interface for the aron and armem code generation");
56 
57  std::string input_default = "/path/to/some/xml/file.xml";
58  std::string output_default = "/path/to/some/output/folder/";
59 
60  options.add_options("General")(
61  "v,verbose", "Enable verbose mode", cxxopts::value<bool>()->default_value("false"))(
62  "h,help", "Print usage");
63 
64  options.add_options("IO")("i,input",
65  "XML file name",
66  cxxopts::value<std::string>()->default_value(input_default))(
67  "o,output",
68  "The output path",
69  cxxopts::value<std::string>()->default_value(output_default))(
70  "I,include", "include path", cxxopts::value<std::vector<std::string>>());
71 
72  options.add_options("Generation")(
73  "f,force", "Enforce the generation", cxxopts::value<bool>()->default_value("false"));
74 
75  auto result = options.parse(argc, argv);
76 
77  if (result.count("help"))
78  {
79  std::cout << options.help() << std::endl;
80  exit(0);
81  }
82 
83  bool verbose = result["v"].as<bool>();
84  bool force = result["f"].as<bool>();
85 
86  std::string filename = result["i"].as<std::string>();
87  std::string output = result["o"].as<std::string>();
88 
89  if (filename == input_default || output == output_default)
90  {
91  std::cout << options.help() << std::endl;
92  exit(0);
93  }
94 
95  if (verbose)
96  {
97  std::cout << "Welcome to the AronCodeGenerator!" << std::endl;
98  std::cout << "Received the following parameters:" << std::endl;
99  std::cout << "- IO:" << std::endl;
100  std::cout << "-- Input: " << filename << std::endl;
101  std::cout << "-- Output: " << output << std::endl;
102  std::cout << "- Generation:" << std::endl;
103  std::cout << "-- Force: " << force << std::endl;
104  std::cout << std::endl;
105  }
106 
107  if (verbose)
108  {
109  std::cout << "Generating a new cpp file out of <" + filename + ">" << std::endl;
110  }
111 
112  std::filesystem::path input_file(filename);
113  std::filesystem::path output_folder(output);
114 
115  std::vector<std::filesystem::path> includePaths;
116 
117  if (result.count("I") > 0)
118  {
119  for (const auto& path : result["I"].as<std::vector<std::string>>())
120  {
121  includePaths.emplace_back(path);
122  }
123  }
124 
125 
126  if (!std::filesystem::exists(input_file) || !std::filesystem::is_regular_file(input_file))
127  {
128  std::cerr << "The input file does not exist or is not a regular file." << std::endl;
129  exit(1);
130  }
131 
132  if (!std::filesystem::exists(output_folder) ||
133  !std::filesystem::is_directory(output_folder))
134  {
135  std::cerr << "The output folder does not exist or is not an directory." << std::endl;
136  exit(1);
137  }
138 
139  if (input_file.extension().string() != ".xml")
140  {
141  std::cerr << "The file you passed has the wrong type." << std::endl;
142  exit(1);
143  }
144 
145  if (verbose)
146  {
147  std::cout << "Parsing the XML file..." << std::endl;
148  }
149 
151  reader.parseFile(input_file, includePaths);
152  if (verbose)
153  {
154  std::cout << "Parsing the XML file... done!" << std::endl;
155  std::cout << "--> Found " << reader.getGenerateObjects().size() << " types."
156  << std::endl;
157  std::cout << "--> They are: " << std::endl;
158  for (const auto& generateType : reader.getGenerateObjects())
159  {
160  std::cout << "----> " << generateType.typeName << std::endl;
161  }
162  }
163 
164  codegenerator::cpp::Writer writer("AronTestSegment", reader.getCodeIncludes());
165 
166  if (verbose)
167  {
168  std::cout << "Running the type class generator..." << std::endl;
169  }
170 
171  writer.generateTypeIntEnums(reader.getGenerateIntEnums());
172  writer.generateTypeObjects(reader.getGenerateObjects());
173 
174  if (verbose)
175  {
176  std::cout << "Running the type class generator... done!" << std::endl;
177  std::cout << "--> Found " << writer.getTypeClasses().size() << " type objects."
178  << std::endl;
179  std::cout << "--> They are: " << std::endl;
180  for (const auto& c : writer.getTypeClasses())
181  {
182  std::cout << "----> " << c->getName() << std::endl;
183  }
184  }
185 
186  std::time_t current_time = std::time(0);
187  std::tm* now = std::localtime(&current_time);
188  std::string current_year = std::to_string(now->tm_year + 1900);
189 
190  std::string fileDoc =
191  std::string("* This file is part of ArmarX. \n") + "* \n" + "* Copyright (C) 2012-" +
192  current_year + ", High Performance Humanoid Technologies (H2T), \n" +
193  "* Karlsruhe Institute of Technology (KIT), all rights reserved. \n" + "* \n" +
194  "* ArmarX is free software; you can redistribute it and/or modify \n" +
195  "* it under the terms of the GNU General Public License version 2 as \n" +
196  "* published by the Free Software Foundation. \n" + "* \n" +
197  "* ArmarX is distributed in the hope that it will be useful, but \n" +
198  "* WITHOUT ANY WARRANTY; without even the implied warranty of \n" +
199  "* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n" +
200  "* GNU General Public License for more details. \n" + "* \n" +
201  "* You should have received a copy of the GNU General Public License \n" +
202  "* along with this program. If not, see <http://www.gnu.org/licenses/>. \n" + "* \n" +
203  "* @copyright http://www.gnu.org/licenses/gpl-2.0.txt \n" +
204  "* GNU General Public License \n" +
205  "* *********************************************************************** \n" +
206  "* WARNING: This file is autogenerated. \n" + "* Original file: " + filename + " \n" +
207  "* Please do not edit since your changes may be overwritten on the next generation \n" +
208  "* If you have any questions please contact: Fabian Peller-Konrad (fabian dot "
209  "peller-konrad at kit dot edu) \n" +
210  "* ***********************************************************************";
211 
212  auto w = CppWriterPtr(new CppWriter(true, fileDoc));
213  w->header.line();
214  w->header.line();
215 
216  // Generate enums at top of generated header file
217  std::vector<MetaEnumPtr> enums = writer.getTypeEnums();
218  if (verbose)
219  {
220  std::cout << "Now exporting enums..." << std::endl;
221  }
222 
223  w->body.line("/*************************************************************************");
224  w->body.line(" * ALL GENERATED ENUMS ***************************************************");
225  w->body.line(" ************************************************************************/");
226  MetaEnum::Write(enums, w);
227  w->body.line();
228  w->body.line();
229 
230  std::string enum_file_generation_content = w->getString();
231 
232  if (verbose)
233  {
234  std::cout << "Now exporting enums... done!" << std::endl;
235  }
236 
237  if (enums.size() > 0 && enum_file_generation_content == "")
238  {
239  std::cerr << "\033[31m"
240  << "Error code 11 - Found error in code generation. Aborting!"
241  << "\033[0m" << std::endl;
242  exit(1);
243  }
244 
245  // Generate all classes
246  std::vector<MetaClassPtr> classes = writer.getTypeClasses();
247  if (verbose)
248  {
249  std::cout << "Now exporting classes..." << std::endl;
250  }
251 
252  w->body.line("/* ************************************************************************");
253  w->body.line(" * ALL GENERATED CLASSES *************************************************");
254  w->body.line(" * ***********************************************************************/");
255  CppClass::Write(classes, w);
256  w->body.line();
257  w->body.line();
258 
259  std::string class_file_generation_content =
260  simox::alg::remove_prefix(w->getString(), enum_file_generation_content);
261 
262  if (verbose)
263  {
264  std::cout << "Now exporting classes... done!" << std::endl;
265  }
266 
267  if (classes.size() > 0 && class_file_generation_content == "")
268  {
269  std::cerr << "\033[31m"
270  << "Error code 21 - Found error in code generation. Aborting!"
271  << "\033[0m" << std::endl;
272  exit(1);
273  }
274 
275  std::string new_file_full_content = w->getString();
276 
277  std::string new_name_with_extension = input_file.filename().replace_extension("").string();
278  new_name_with_extension += ".aron.generated.h";
279  std::string output_file_path = output + "/" + new_name_with_extension;
280  std::filesystem::path output_file(output_file_path);
281 
282  // check if file already exists
283  if (!force)
284  {
285  if (std::filesystem::exists(output_file))
286  {
287  std::ifstream ifs(output_file);
288  std::string file_content((std::istreambuf_iterator<char>(ifs)),
289  (std::istreambuf_iterator<char>()));
290 
291  if (file_content == new_file_full_content)
292  {
293  if (verbose)
294  {
295  std::cout << "\033[31m"
296  << "Error code 31 - File content not changed for <" +
297  output_file.string() + ">"
298  << "\033[0m" << std::endl;
299  }
300  exit(0);
301  }
302  }
303  }
304 
305  std::ofstream ofs;
306  ofs.open(output_file);
307  ofs << new_file_full_content;
308  ofs.close();
309 
310  if (verbose)
311  {
312  std::cout << "\033[32m"
313  << "Finished generating <" + output_file.string() +
314  ">. The new file ist called <"
315  << output_file.string() << ">"
316  << "\033[0m" << std::endl;
317  }
318  }
319  catch (const cxxopts::OptionException& e)
320  {
321  std::cerr << "\033[31m"
322  << "Error code 01 - Error in parsing cxxopts options: " << e.what() << "\033[0m"
323  << std::endl;
324  exit(1);
325  }
326  exit(0);
327 }
armarx::aron::typereader::xml::Reader::parseFile
void parseFile(const std::string &filename, const std::vector< std::filesystem::path > &includePaths={}) override
parse a filename
Definition: Reader.cpp:141
CppMethod.h
cxxopts::Options::parse
ParseResult parse(int &argc, char **&argv)
Definition: cxxopts.hpp:1532
armarx::aron::codegenerator::cpp::Writer::generateTypeObjects
virtual void generateTypeObjects(const std::vector< typereader::GenerateObjectInfo > &) override
Definition: Writer.cpp:274
armarx::MetaEnum::Write
static void Write(const std::vector< MetaEnumPtr > &classes, const MetaWriterPtr &writer)
Definition: MetaEnum.cpp:44
cxxopts::Options::add_options
OptionAdder add_options(std::string group="")
Definition: cxxopts.hpp:1359
Reader.h
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
armarx::aron::typereader::Reader::getGenerateIntEnums
std::vector< typereader::GenerateIntEnumInfo > getGenerateIntEnums() const
Definition: Reader.h:88
armarx::MetaClass::Write
static void Write(const std::vector< MetaClassPtr > &classes, const MetaWriterPtr &writer)
Definition: MetaClass.cpp:40
armarx::aron::codegenerator::CodeWriter::getTypeEnums
std::vector< MetaEnumPtr > getTypeEnums() const
Definition: CodeWriter.h:68
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:855
CppClass.h
armarx::aron::codegenerator::cpp::Writer
Definition: Writer.h:45
armarx::aron::typereader::Reader::getCodeIncludes
std::vector< std::string > getCodeIncludes() const
Definition: Reader.h:58
cxxopts.hpp
cxxopts::OptionException
Definition: cxxopts.hpp:284
main
int main(int argc, char *argv[])
Definition: main.cpp:32
filename
std::string filename
Definition: VisualizationRobot.cpp:86
Writer.h
cxxopts::Options
Definition: cxxopts.hpp:1110
armarx::aron::typereader::xml::Reader
The Reader class.
Definition: Reader.h:48
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::CppWriter
Definition: CppWriter.h:37
cxxopts::Options::help
std::string help(const std::vector< std::string > &groups={}) const
Definition: cxxopts.hpp:1854
armarx::aron::typereader::Reader::getGenerateObjects
std::vector< typereader::GenerateObjectInfo > getGenerateObjects() const
Definition: Reader.h:82
armarx::aron::codegenerator::CodeWriter::getTypeClasses
std::vector< MetaClassPtr > getTypeClasses() const
Definition: CodeWriter.h:62
armarx::CppWriterPtr
std::shared_ptr< CppWriter > CppWriterPtr
Definition: CppWriter.h:35
cxxopts::OptionException::what
virtual const char * what() const noexcept
Definition: cxxopts.hpp:292
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::aron::codegenerator::cpp::Writer::generateTypeIntEnums
virtual void generateTypeIntEnums(const std::vector< typereader::GenerateIntEnumInfo > &) override
Definition: Writer.cpp:388