arcsbuilder.cpp
1 /*
2  name: tools/builder/arcsbuilder.cpp
3 
4  This file is part of ARCS - Augmented Reality Component System
5  (version 2-current), written by Jean-Yves Didier
6  for IBISC Laboratory (http: *www.ibisc.univ-evry.fr)
7 
8  Copyright (C) 2013 Université d'Evry-Val d'Essonne
9 
10  This program is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 2 of the License, or
13  (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program. If not, see <http: *www.gnu.org/licenses/>.
22 
23 
24  Please send bugreports with examples or suggestions to
25  jean-yves.didier__at__ibisc.univ-evry.fr
26 */
27 
28 
29 
47 #include <arcs/arcsxmlhandler.h>
48 #include <arcs/arcsapplicationcomponent.h>
49 #include <arcs/arcsfactory.h>
50 #include <QCoreApplication>
51 #include <QString>
52 #include <iostream>
53 #include <iomanip>
54 #include <cstdlib>
55 
56 #include <QMap>
57 #include <QStringList>
58 #include <QDir>
59 #include <QFile>
60 #include <QFileInfo>
61 #include <QRegExp>
62 #include <QTextStream>
63 #include <QProcess>
64 #include <QXmlQuery>
65 
66 #ifdef WIN32
67 #include <windows.h>
68 #else
69 #include <unistd.h>
70 #endif
71 
72 
73 
74 typedef struct {
75  QString path;
76  bool libmaker;
77 } LibraryPath ;
78 
79 LibraryPath libraryPath(QString p, bool b)
80 {
81  LibraryPath res ;
82  res.path = p ;
83  res.libmaker = b;
84  return res;
85 }
86 
87 
88 QMap<QString,LibraryPath> libraryDirBounds;
89 
93 QString getLibraryName(QString libpath)
94 {
95  QString lname = libpath.right(libpath.length() - libpath.lastIndexOf(QDir::separator())-1 );
96  lname = lname.left(lname.lastIndexOf('.'));
97  if (lname.startsWith("lib"))
98  {
99  lname = lname.right(lname.length()-3);
100  }
101 
102  return lname;
103 }
104 
105 
106 void exploreProjectFile(QString profile)
107 {
108  /* First : strip the name of the pro file*/
109  QFileInfo fi(profile) ;
110  QString name = fi.baseName();
111  QString path = fi.absolutePath();
112 
113  /* Second open the file and detect lines
114  * TARGET = something */
115  QString target;
116 
117  QFile filepro(profile);
118  filepro.open(QIODevice::ReadOnly);
119  QTextStream ts(&filepro);
120  QRegExp linematcher("^\\s*TARGET\\s*=\\s*(\\w+)\\W*$");
121 
122 
123  QString line;
124  do
125  {
126  line = ts.readLine();
127  if (linematcher.exactMatch(line))
128  {
129  target = linematcher.cap(1);
130  }
131  }
132  while ( !line.isNull());
133 
134  /* select what to put inside mapper */
135  if (target.isEmpty())
136  {
137  std::cout << std::setw(15) << qPrintable(name) << " => " << qPrintable(path) << std::endl;
138  libraryDirBounds[name] = libraryPath(path, false);
139  }
140  else
141  {
142  std::cout << std::setw(15) << qPrintable(target) << " => " << qPrintable(path) << std::endl;
143  libraryDirBounds[target] = libraryPath(path,false);
144  }
145 }
146 
147 
148 bool launchProcess(QString processName, QString path)
149 {
150  QProcess pr;
151  pr.setWorkingDirectory(path);
152  std::cout << " " << qPrintable(processName);
153  pr.start(processName);
154  while (pr.state() == QProcess::Running)
155  {
156  std::cout << "." ;
157  std::cout.flush();
158 
159 #ifdef WIN32
160  Sleep(1000);
161 #else
162  sleep(1);
163 #endif
164  }
165  std::cout << std::endl;
166  pr.waitForFinished();
167  return (pr.exitStatus() == QProcess::NormalExit && pr.exitCode() == 0);
168 }
169 
170 
171 void buildBounds(QString path)
172 {
173  unsigned int i;
174  QDir d(path);
175 
176  /* Make sure path is '/' terminated*/
177  if (path.at(path.length()-1) != QDir::separator())
178  path += QDir::separator();
179 
180  /* First pass : scan all .pro files*/
181  QStringList profiles = d.entryList(QStringList("*.pro"));
182  for (i=0; i < profiles.count() ; i++)
183  exploreProjectFile(path + profiles[i]);
184 
185  if( profiles.count() == 0)
186  {
187  std::cout << "Storing alxfiles" << std::endl;
188  QStringList alxfiles = d.entryList(QStringList("*.alx"));
189  for (i=0; i < alxfiles.count() ; i++)
190  {
191  std::cout << qPrintable(d.dirName()) << std::endl;
192  libraryDirBounds[d.dirName()] = libraryPath( path, true );
193  }
194  }
195 
196  /* Second pass : scan all directories */
197  QStringList dirs = d.entryList(QDir::Dirs);
198  for (i=0; i < dirs.count() ; i++)
199  {
200  /* filter out directories with leading '.'*/
201  if (dirs[i].at(0) != '.' )
202  buildBounds(path + dirs[i]);
203  }
204 }
205 
206 
207 bool buildLibrary(QString path,bool libmaker=false)
208 {
209  if (libmaker)
210  if (!launchProcess("arcslibmaker",path))
211  return false;
212  if (!launchProcess("qmake",path))
213  return false;
214  if (!launchProcess("make",path))
215  return false;
216  return true;
217 }
218 
219 
220 int buildApplication(QStringList libs, QString path)
221 {
222  int success = 0;
223 
224  std::cout << "Looking for bindings between libs and directories" << std::endl;
225  buildBounds(path);
226 
227  for (int i=0; i < libs.count() ; i++)
228  {
229  QString libname = getLibraryName(libs[i]);
230  std::cout << "Trying to build library " << qPrintable(libname) << std::endl;
231  QString dir = libraryDirBounds[libname].path;
232  if (!dir.isEmpty())
233  {
234  if (buildLibrary(dir,libraryDirBounds[libname].libmaker))
235  {
236  std::cout << std::setw(10) << " " << " Success !" << std::endl;
237  success++;
238  }
239  else
240  std::cout << std::setw(10) << " " << "Failed !" << std::endl;
241 
242 
243  }
244  else
245  std::cout << std::setw(10) << " " << "Failed !" << std::endl;
246  }
247  return success;
248 }
249 
250 
251 
252 
253 void usage(char* name)
254 {
255  std::cerr << "Usage: " << name << " application_file.xml [component/sources/path/]" << std::endl;
256  std::cerr << "Where: \"application_file.xml\" is an application file ;" << std::endl;
257  std::cerr << " \"component/sources/path/\" is an optional source path. " << std::endl;
258 }
259 
260 
261 int main(int argc,char* argv[])
262 {
263  QString path;
264  QCoreApplication app(argc,argv);
265  if ((argc == 1) || (argc > 3))
266  {
267  usage(argv[0]);
268  return 1;
269  }
270 
271  char* buildpath = getenv("ARCSBUILDPATH");
272 
273  if (buildpath == NULL)
274  std::cerr << "ARCSBUILDPATH environment variable not found." << std::endl;
275  else
276  path = QString(buildpath);
277 
278  if (buildpath == NULL && argc < 3)
279  {
280  usage(argv[0]);
281  return 1;
282  }
283 
284  if (argc == 3 )
285  path = QString(argv[2]);
286 
287 
288  QXmlQuery query;
289 
290  query.bindVariable("file",QVariant(QDir::currentPath() + QDir::separator() + QString(argv[1])));
291  query.setQuery("doc($file)/application/context/libraries/library/string(data(@path))");
292  QStringList libList;
293  if (query.evaluateTo(&libList))
294  {
295  int res = buildApplication(libList,path);
296  if (res != libList.count())
297  std::cerr << "Failed to build some libraries required by your application." << std::endl;
298  else
299  std::cout << "All libraries successfully built." << std::endl;
300  }
301  else
302  {
303  std::cerr << "Failed to load file " << argv[1] << std::endl;
304  return 1;
305  }
306 
307  return 0;
308 }