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