PhoenixGenerator  2.0.0
Set of tools to generate code
wrapper_generator.cpp
Go to the documentation of this file.
1 /***************************************
2  Auteur : Pierre Aubert
3  Mail : pierre.aubert@lapp.in2p3.fr
4  Licence : CeCILL-C
5 ****************************************/
6 
7 #include "cmakelist_generator.h"
9 #include "wrapper_test.h"
10 #include "wrapper_generator.h"
11 
13 
17  ProjectConfig wrapper(projectConfig);
18  wrapper.name = "Py"+projectConfig.name;
19  wrapper.url = wrapper.url.replace(projectConfig.name, wrapper.name);
20 
21  return wrapper;
22 }
23 
25 
29 bool project_wrapper_generator_readme(const PPath & fileName, const ProjectConfig & projectConfig){
30  PString body;
31  body += "![PLIBS_9 logo](doc/logo.png)\n\n";
32 
33  body += "# Remarks\n\n";
34  body += "This project was generated automatically by [phoenix_filegenerator](https://gitlab.in2p3.fr/CTA-LAPP/PHOENIX_LIBS2/PhoenixFileGenerator)\n";
35  body += "using [phoenix_generator](https://gitlab.in2p3.fr/CTA-LAPP/PHOENIX_LIBS2/PhoenixGenerator) library\n\n";
36 
37  body += "# Code\n\n";
38  body += "Version : " + projectConfig.version + "\n\n";
39  body += projectConfig.url + "\n\n";
40  body += "# Description\n\n";
41  body += "Python wrapper version.\n";
42  body += projectConfig.description + "\n\n";
43 
44  return fileName.saveFileContent(body);
45 }
46 
48 
55 bool project_wrapper_generator_setuppy(const PPath & fileName, const ProjectConfig & projectConfig, const PString & baseImplInclude, const std::vector<PClassConfig> & vecClassConfig, const PVecPath & vecInclude){
56  PString body, moduleName = "py" + projectConfig.name.toLower();
57  body += "\n";
58  body += getCMakeListsHeader();
59  body += "from setuptools import setup\n";
60  body += "from setuptools import Extension\n";
61  body += "import sys\n";
62  body += "import numpy as np\n";
63  body += "import subprocess\n";
64  body += "\n";
65  body += "dataStreamIncludeDir = subprocess.run(['phoenixdatastream-config', '--include'], capture_output = True, text = True).stdout.strip(\"\\n\")\n";
66  body += "dataStreamLibDir = subprocess.run(['phoenixdatastream-config', '--lib'], capture_output = True, text = True).stdout.strip(\"\\n\")\n";
67  body += "\n";
68  body += "ext_modules = [\n";
69  body += "\tExtension(\""+moduleName+"\", sources=([\n";
70  body += "\t\t\""+moduleName+"/"+baseImplInclude+"_wrapper.cpp\",\n";
71  body += "\t\t\""+moduleName+"/"+projectConfig.name.toLower()+"_module.cpp\"\n";
72  body += "\t]),\n";
73  body += "\textra_compile_args = [\"-O3\", \"-Werror\", \"-g\"],\n";
74 
75  body += "\tinclude_dirs = [np.get_include(), dataStreamIncludeDir, \"./\", \""+moduleName+"/\"],\n";
76  body += "\tlibraries=[\"phoenix_data_stream\"],\n";
77  body += "\tlibrary_dirs=[dataStreamLibDir],\n";
78  body += "\t)\n";
79  body += "]\n\n";
80 
81  body += "try:\n";
82  body += "\tsetup(\n";
83  body += "\t\tname=\""+moduleName+"\",\n";
84  body += "\t\tversion=\""+projectConfig.version+"\",\n";
85  body += "\t\text_modules=ext_modules,\n";
86  body += "\t)\n";
87  body += "except Exception as e:\n";
88  body += "\tprint(str(e))\n";
89  body += "\tsys.exit(-1)\n";
90  body += "\n";
91  return fileName.saveFileContent(body);
92 }
93 
95 
102 bool project_wrapper_generator_pyprojectToml(const PPath & fileName, const ProjectConfig & projectConfig, const PString & baseImplInclude, const std::vector<PClassConfig> & vecClassConfig, const PVecPath & vecInclude){
103  PString body;
104  body += "\n";
105  body += getCMakeListsHeader();
106  body += "[project]\n";
107  body += "name = \"py"+projectConfig.name.toLower()+"\"\n";
108  body += "version = \""+projectConfig.version+"\"\n";
109  body += "description = \""+projectConfig.description.replace("\n", " ")+"\"\n";
110  body += "readme = \"README.md\"\n";
111  body += "license = \"CeCILL-C\"\n";
112  body += "dependencies = [\n";
113  body += "\t\"numpy\"\n";
114  body += "]\n";
115  body += "\n";
116  body += "[build-system]\n";
117  body += "requires = [\n";
118  body += "\t\"numpy\",\n";
119  body += "\t\"setuptools >= 74.1\",\n";
120  body += "\t\"cython\"\n";
121  body += "]\n";
122  body += "build-backend = \"setuptools.build_meta\"\n";
123  body += "\n";
124 // body += "[tool.setuptools]\n";
125 // body += "ext-modules = [\n";
126 // body += "\t{\n";
127 // body += "\t\tname = \""+projectConfig.name.toLower()+"\",\n";
128 // body += "\t\tsources = [\n";
129 // body += "\t\t\t\""+projectConfig.name.toLower()+"/"+baseImplInclude+"_wrapper.cpp\",\n";
130 // body += "\t\t\t\""+projectConfig.name.toLower()+"/"+projectConfig.name+"_module.cpp\"\n";
131 // body += "\t\t],\n";
132 // body += "\t\textra_compile_args = [\"-O3\", \"-Werror\", \"-g\"]\n";
133 // body += "\t}\n";
134 // body += "\n";
135 // body += "]\n";
136  body += "\n";
137  return fileName.saveFileContent(body);
138 }
139 
141 
143 void updateVecClassConfig(std::vector<PClassConfig> & vecClassConfig){
144  std::map<std::string, std::string> mapEnum;
145  for(std::vector<PClassConfig>::iterator it(vecClassConfig.begin()); it != vecClassConfig.end(); ++it){
146  if(it->getIsEnum()){
147  mapEnum[it->getName() + "::" + it->getName()] = it->getName();
148  size_t i(0lu);
149  std::vector<PClassAttribute> & vecAttr = it->getListAttribute();
150  for(std::vector<PClassAttribute>::iterator itAttr(vecAttr.begin()); itAttr != vecAttr.end(); ++itAttr){
151  if(itAttr->getDefaultValue() == ""){
152  itAttr->setDefaultValue(PString::toString(i));
153  }
154  ++i;
155  }
156  }
157  }
158  for(std::vector<PClassConfig>::iterator itClass(vecClassConfig.begin()); itClass != vecClassConfig.end(); ++itClass){
159  std::vector<PClassAttribute> & vecAttr = itClass->getListAttribute();
160  for(std::vector<PClassAttribute>::iterator itAttr(vecAttr.begin()); itAttr != vecAttr.end(); ++itAttr){
161  std::map<std::string, std::string>::iterator it(mapEnum.find(itAttr->getType()));
162  if(it != mapEnum.end()){
163  itAttr->setType(it->second);
164  itAttr->setIsEnum(true);
165  }
166  if(itAttr->getType() == "PPath" || itAttr->getType() == "PString"){
167  itAttr->setType("std::string");
168  }
169  }
170  }
171 }
172 
174 
178 bool project_wrapper_generator(const ProjectConfig & projectConfig, const PPath & configFile){
179  ProjectConfig wrapperConfig(project_createWrapperConfig(projectConfig));
180  PVecPath vecInclude;
181  std::vector<PClassConfig> vecClassConfig;
182  if(!parserClassConfig(vecClassConfig, vecInclude, configFile)){
183  std::cerr << "project_wrapper_generator : can't load file '" << configFile << "'" << std::endl;
184  return false;
185  }
186  //TODO : pass through vecClassConfig and replace PPath and PString by std::string to ensure PhoenixDataStream will work well on them for the wrapper
187  updateVecClassConfig(vecClassConfig);
188 
189  //Then, let's create the hierarchy
190  PPath mainProjectDir(wrapperConfig.name);
191  if(!mainProjectDir.createDirectory()){
192  std::cerr << "project_wrapper_generator : cannot create main directory of project '"<<mainProjectDir<<"'" << std::endl;
193  return false;
194  }
195  //And module dir
196  PPath mainProjectModule(mainProjectDir / PPath(wrapperConfig.name.toLower()));
197  if(!mainProjectModule.createDirectory()){
198  std::cerr << "project_generator : cannot create module directory of project '"<<mainProjectModule<<"'" << std::endl;
199  return false;
200  }
201  //The readme
202  PPath readmeFile(mainProjectDir / PPath("README.md"));
203  if(!project_wrapper_generator_readme(readmeFile, projectConfig)){return false;}
204 
205  PString baseImplInclude = configFile.getFileName().eraseExtension();
206  //The readme
207  PPath setupFile(mainProjectDir / PPath("setup.py"));
208  if(!project_wrapper_generator_setuppy(setupFile, projectConfig, baseImplInclude, vecClassConfig, vecInclude)){return false;}
209 
210  PPath pyprojectFile(mainProjectDir / PPath("pyproject.toml"));
211  if(!project_wrapper_generator_pyprojectToml(pyprojectFile, projectConfig, baseImplInclude, vecClassConfig, vecInclude)){return false;}
212  //The unit tests
213  if(!project_wrapper_moduleGeneratorTest(mainProjectDir, projectConfig, "py"+projectConfig.name.toLower(), vecClassConfig, vecInclude)){return false;}
214  //The full module
215  return project_wrapper_moduleGenerator(mainProjectModule, projectConfig, baseImplInclude, vecClassConfig, vecInclude);
216 }
217 
218 
219 
std::vector< PPath > PVecPath
Definition: PPath.h:75
Path of a directory or a file.
Definition: PPath.h:17
bool saveFileContent(const PString &content) const
Save a PString in a file.
Definition: PPath.cpp:395
PPath & eraseExtension()
Erase the extension of the PPath.
Definition: PPath.cpp:292
bool createDirectory(mode_t mode=0755) const
Create the current directory.
Definition: PPath.cpp:331
PPath getFileName() const
Get the name of the file, from last char to /.
Definition: PPath.cpp:172
Extends the std::string.
Definition: PString.h:16
static PString toString(const T &value)
Convert a value to a PString.
Definition: PString_impl.h:18
PString replace(const PString &pattern, const PString &replaceStr) const
Replace a PString into an other PString.
Definition: PString.cpp:204
PString toLower() const
Convert PString in lower case.
Definition: PString.cpp:598
PString getCMakeListsHeader()
Get the CMakeLists.txt header.
bool parserClassConfig(std::vector< PClassConfig > &listClassConfig, PVecPath &listInclude, const PPath &fileName)
Parser list class config.
Configuration of the project.
PString description
Description of the project.
PString name
Name of the project.
PString url
Project url.
PString version
Project version.
bool project_wrapper_generator_setuppy(const PPath &fileName, const ProjectConfig &projectConfig, const PString &baseImplInclude, const std::vector< PClassConfig > &vecClassConfig, const PVecPath &vecInclude)
Create the readme of the project directory.
bool project_wrapper_generator_readme(const PPath &fileName, const ProjectConfig &projectConfig)
Create the readme of the project directory.
bool project_wrapper_generator_pyprojectToml(const PPath &fileName, const ProjectConfig &projectConfig, const PString &baseImplInclude, const std::vector< PClassConfig > &vecClassConfig, const PVecPath &vecInclude)
Create the readme of the project directory.
ProjectConfig project_createWrapperConfig(const ProjectConfig &projectConfig)
Create the config of the wrapper.
void updateVecClassConfig(std::vector< PClassConfig > &vecClassConfig)
Update the vector of class configuration.
bool project_wrapper_generator(const ProjectConfig &projectConfig, const PPath &configFile)
Generate a full python wrapper project with PhoenixDataStream and PhoenixTypeStream.
bool project_wrapper_moduleGenerator(const PPath &modulePath, const ProjectConfig &projectConfig, const PString &baseImplInclude, const std::vector< PClassConfig > &vecClassConfig, const PVecPath &vecInclude)
Create the wrapper module.
bool project_wrapper_moduleGeneratorTest(const PPath &projectPath, const ProjectConfig &projectConfig, const PString &moduleName, const std::vector< PClassConfig > &vecClassConfig, const PVecPath &vecInclude)
Generate the unit tests of the project.