jcomp.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jlib.hpp"
  15. #include "jmisc.hpp"
  16. #include "jcomp.hpp"
  17. #include "jsem.hpp"
  18. #include "jexcept.hpp"
  19. #include "jregexp.hpp"
  20. #ifdef _WIN32
  21. #include <windows.h>
  22. #include <winbase.h>
  23. #include <io.h>
  24. #else
  25. #include <sys/wait.h>
  26. #endif
  27. #include <fcntl.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <stdio.h>
  31. #include "jfile.hpp"
  32. #include "jdebug.hpp"
  33. #include "jcomp.ipp"
  34. #define CC_EXTRA_OPTIONS ""
  35. #ifdef GENERATE_LISTING
  36. #undef CC_EXTRA_OPTIONS
  37. #define CC_EXTRA_OPTIONS " /FAs"
  38. #endif
  39. #ifdef _WIN32
  40. #define DEFAULT_COMPILER Vs6CppCompiler
  41. #else
  42. #define DEFAULT_COMPILER GccCppCompiler
  43. #endif
  44. //---------------------------------------------------------------------------
  45. #define BASE_ADDRESS "0x00480000"
  46. //#define BASE_ADDRESS "0x10000000"
  47. static const char * CC_NAME[] = { "\"#" PATHSEPSTR "bin" PATHSEPSTR "cl.bat\"", "\"#" PATHSEPSTR "bin" PATHSEPSTR "g++\"" };
  48. static const char * LINK_NAME[] = { "\"#" PATHSEPSTR "bin" PATHSEPSTR "link.bat\"", "\"#" PATHSEPSTR "bin" PATHSEPSTR "g++\"" };
  49. static const char * LIB_DIR[] = { "\"#\\lib\"", "\"#/lib\"" };
  50. static const char * LIB_OPTION_PREFIX[] = { "", "-Wl," };
  51. static const char * USE_LIBPATH_FLAG[] = { "/libpath:\"", "-L" };
  52. static const char * USE_LIBPATH_TAIL[] = { "\"", "" };
  53. static const char * USE_LIBRPATH_FLAG[] = { NULL, "-Wl,-rpath," };
  54. static const char * USE_LIB_FLAG[] = { "", "-l" };
  55. static const char * USE_LIB_TAIL[] = { ".lib", "" };
  56. static const char * USE_INCLUDE_FLAG[] = { "/I\"", "\"-I" };
  57. static const char * USE_DEFINE_FLAG[] = { "/D", "-D" };
  58. static const char * USE_INCLUDE_TAIL[] = { "\"", "\"" };
  59. static const char * INCLUDEPATH[] = { "\"#\\include\"", "\"#/include\"" };
  60. static const char * LINK_SEPARATOR[] = { " /link ", " " };
  61. static const char * OBJECT_FILE_EXT[] = { "obj", "o" };
  62. static const char * PCH_FILE_EXT[] = { "", "gch" };
  63. static const char * LIBFLAG_DEBUG[] = { "/MDd", "" };
  64. static const char * LIBFLAG_RELEASE[] = { "/MD", "" };
  65. static const char * COMPILE_ONLY[] = { "/c", "-c" };
  66. static const char * CC_OPTION_CORE[] = { "", "-fvisibility=hidden -DUSE_VISIBILITY=1" };
  67. static const char * LINK_OPTION_CORE[] = { "/DLL /libpath:." , "" };
  68. static const char * CC_OPTION_DEBUG[] = { "/Zm500 /EHsc /GR /Zi /nologo /bigobj", "-g -fPIC -pipe -O0" };
  69. static const char * DLL_LINK_OPTION_DEBUG[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO /DEBUG /DEBUGTYPE:CV", "-g -shared -L. -fPIC -pipe -O0" };
  70. static const char * EXE_LINK_OPTION_DEBUG[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO /DEBUG /DEBUGTYPE:CV", "-g -L. -Wl,-E -fPIC -pipe -O0" };
  71. static const char * CC_OPTION_RELEASE[] = { "/Zm500 /EHsc /GR /Oi /Ob1 /GF /nologo /bigobj", "-fPIC -pipe -O0" };
  72. static const char * CC_OPTION_PRECOMPILEHEADER[] = { "", " -x c++-header" };
  73. static const char * DLL_LINK_OPTION_RELEASE[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO", "-shared -L. -fPIC -pipe -O0" };
  74. static const char * EXE_LINK_OPTION_RELEASE[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO", "-L. -Wl,-E -fPIC -pipe -O0" };
  75. static const char * LINK_TARGET[] = { " /out:", " -o " };
  76. static const char * DEFAULT_CC_LOCATION[] = { ".", "." };
  77. //===========================================================================
  78. static StringAttr compilerRoot;
  79. static StringAttr stdIncludes;
  80. static StringBuffer stdLibs;
  81. static StringBuffer &dequote(StringBuffer &in)
  82. {
  83. if (in.length() >= 2 && in.charAt(0)=='"' && in.charAt(in.length()-1)=='"')
  84. {
  85. in.remove(in.length()-1, 1);
  86. in.remove(0, 1);
  87. }
  88. return in;
  89. }
  90. static void doSetCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, unsigned targetCompiler, bool verbose)
  91. {
  92. if (!includes)
  93. includes = INCLUDEPATH[targetCompiler];
  94. if (!libs)
  95. libs = LIB_DIR[targetCompiler];
  96. if (verbose)
  97. {
  98. PrintLog("Include directory set to %s", includes);
  99. PrintLog("Library directory set to %s", libs);
  100. }
  101. compilerRoot.set(path ? path : targetCompiler==GccCppCompiler ? "/usr" : ".\\CL");
  102. stdIncludes.set(includes);
  103. stdLibs.clear();
  104. for (;;)
  105. {
  106. StringBuffer thislib;
  107. while (*libs && *libs != ENVSEPCHAR)
  108. thislib.append(*libs++);
  109. if (thislib.length())
  110. {
  111. stdLibs.append(" ").append(USE_LIBPATH_FLAG[targetCompiler]).append(thislib).append(USE_LIBPATH_TAIL[targetCompiler]);
  112. if (USE_LIBRPATH_FLAG[targetCompiler])
  113. stdLibs.append(" ").append(USE_LIBRPATH_FLAG[targetCompiler]).append(thislib);
  114. }
  115. if (!*libs)
  116. break;
  117. libs++;
  118. }
  119. StringBuffer fname;
  120. if (path)
  121. {
  122. const char *finger = CC_NAME[targetCompiler];
  123. while (*finger)
  124. {
  125. if (*finger == '#')
  126. fname.append(path);
  127. else
  128. fname.append(*finger);
  129. finger++;
  130. }
  131. #if defined(__linux__)
  132. StringBuffer clbin_dir;
  133. const char* dir_end = strrchr(fname, '/');
  134. if(dir_end == NULL)
  135. clbin_dir.append(".");
  136. else
  137. clbin_dir.append((dir_end - fname.str()) + 1, fname.str());
  138. StringBuffer pathenv(clbin_dir.str());
  139. const char* oldpath = getenv("PATH");
  140. if(oldpath != NULL && *oldpath != '\0')
  141. pathenv.append(":").append(oldpath);
  142. setenv("PATH", pathenv.str(), 1);
  143. #endif
  144. }
  145. else
  146. {
  147. fname.append(compilerRoot).append(CC_NAME[targetCompiler]);
  148. fname.replaceString("#",NULL);
  149. }
  150. if (verbose)
  151. PrintLog("Compiler path set to %s", fname.str());
  152. dequote(fname);
  153. #ifdef _WIN32
  154. if (_access(fname.str(), 4))
  155. {
  156. #else
  157. #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
  158. struct stat filestatus;
  159. int r = stat(fname.str(), &filestatus);
  160. if ( (r != 0)
  161. || (!S_ISREG(filestatus.st_mode))
  162. || ((filestatus.st_mode&(S_IXOTH|S_IXGRP|S_IXUSR))==0))
  163. {
  164. if (r == -1) errno = ENOENT;
  165. #endif
  166. #endif
  167. if (verbose)
  168. PrintLog("SetCompilerPath - no compiler found");
  169. throw makeOsExceptionV(GetLastError(), "setCompilerPath could not locate compiler %s", fname.str());
  170. }
  171. if(tmpdir && *tmpdir)
  172. {
  173. //MORE: this should be done for the child process instead of the parent but invoke does not let me do it
  174. #if defined(__linux__)
  175. setenv("TMPDIR", tmpdir, 1);
  176. #endif
  177. #ifdef _WIN32
  178. StringBuffer tmpbuf;
  179. tmpbuf.append("TMP=").append(tmpdir);
  180. _putenv(tmpbuf.str());
  181. #endif
  182. }
  183. }
  184. //===========================================================================
  185. class CCompilerThreadParam : CInterface
  186. {
  187. public:
  188. IMPLEMENT_IINTERFACE;
  189. CCompilerThreadParam(const StringBuffer & _cmdline, Semaphore & _finishedCompiling, const StringBuffer & _logfile) : cmdline(_cmdline), finishedCompiling(_finishedCompiling), logfile(_logfile) {};
  190. StringBuffer cmdline;
  191. StringBuffer logfile;
  192. Semaphore & finishedCompiling;
  193. };
  194. //===========================================================================
  195. static void setDirectoryPrefix(StringAttr & target, const char * source)
  196. {
  197. if (source && *source)
  198. {
  199. StringBuffer temp;
  200. target.set(addDirectoryPrefix(temp, source));
  201. }
  202. }
  203. CppCompiler::CppCompiler(const char * _coreName, const char * _sourceDir, const char * _targetDir, unsigned _targetCompiler, bool _verbose)
  204. {
  205. #define CORE_NAME allSources.item(0)
  206. if (_coreName)
  207. addSourceFile(_coreName);
  208. targetCompiler = _targetCompiler;
  209. createDLL = true;
  210. #ifdef _DEBUG
  211. setDebug(true);
  212. setDebugLibrary(true);
  213. #else
  214. setDebug(false);
  215. setDebugLibrary(false);
  216. #endif
  217. setDirectoryPrefix(sourceDir, _sourceDir);
  218. setDirectoryPrefix(targetDir, _targetDir);
  219. maxCompileThreads = 1;
  220. onlyCompile = false;
  221. verbose = _verbose;
  222. saveTemps = false;
  223. abortChecker = NULL;
  224. precompileHeader = false;
  225. linkFailed = false;
  226. }
  227. void CppCompiler::addCompileOption(const char * option)
  228. {
  229. compilerOptions.append(' ').append(option);
  230. }
  231. void CppCompiler::setPrecompileHeader(bool _pch)
  232. {
  233. if (targetCompiler!=GccCppCompiler)
  234. throw MakeStringException(0, "precompiled header generation only supported for g++ and compatible compilers");
  235. precompileHeader = _pch;
  236. }
  237. void CppCompiler::addDefine(const char * symbolName, const char * value)
  238. {
  239. compilerOptions.append(" ").append(USE_DEFINE_FLAG[targetCompiler]).append(symbolName);
  240. if (value)
  241. compilerOptions.append('=').append(value);
  242. }
  243. void CppCompiler::addLibrary(const char * libName)
  244. {
  245. if (verbose)
  246. PrintLog("addLibrary %s", libName);
  247. const char* lname = libName;
  248. const char * quote;
  249. StringBuffer path, tail; // NOTE - because of the (hacky) code below that sets lname to point within tail.str(), this must NOT be moved inside the if block
  250. if (targetCompiler == GccCppCompiler)
  251. {
  252. // It seems gcc compiler doesn't like things like -lmydir/libx.so
  253. splitFilename(libName, &path, &path, &tail, &tail);
  254. if(path.length())
  255. {
  256. addLibraryPath(path);
  257. lname = tail.str();
  258. // HACK - make it work with plugins. This should be handled at caller end!
  259. if (strncmp(lname, "lib", 3) == 0)
  260. lname += 3;
  261. }
  262. quote = NULL; //quoting lib names with gcc causes link error (lib not found)
  263. }
  264. else
  265. {
  266. quote = "\"";
  267. }
  268. linkerLibraries.append(" ").append(USE_LIB_FLAG[targetCompiler]).append(quote).append(lname).append(USE_LIB_TAIL[targetCompiler]).append(quote);
  269. }
  270. void CppCompiler::addLibraryPath(const char * libPath)
  271. {
  272. linkerOptions.append(" ").append(USE_LIBPATH_FLAG[targetCompiler]).append(libPath).append(USE_LIBPATH_TAIL[targetCompiler]);
  273. if (USE_LIBRPATH_FLAG[targetCompiler])
  274. linkerOptions.append(" ").append(USE_LIBRPATH_FLAG[targetCompiler]).append(libPath);
  275. }
  276. void CppCompiler::_addInclude(StringBuffer &s, const char * paths)
  277. {
  278. if (!paths)
  279. return;
  280. StringBuffer includePath;
  281. for (;;)
  282. {
  283. while (*paths && *paths != ENVSEPCHAR)
  284. includePath.append(*paths++);
  285. if (includePath.length())
  286. s.append(" ").append(USE_INCLUDE_FLAG[targetCompiler]).append(includePath).append(USE_INCLUDE_TAIL[targetCompiler]);
  287. if (!*paths)
  288. break;
  289. paths++;
  290. includePath.clear();
  291. }
  292. }
  293. void CppCompiler::addInclude(const char * paths)
  294. {
  295. _addInclude(compilerOptions, paths);
  296. }
  297. void CppCompiler::addLinkOption(const char * option)
  298. {
  299. if (option && *option)
  300. linkerOptions.append(' ').append(LIB_OPTION_PREFIX[targetCompiler]).append(option);
  301. }
  302. void CppCompiler::addSourceFile(const char * filename)
  303. {
  304. allSources.append(filename);
  305. }
  306. void CppCompiler::writeLogFile(const char* filepath, StringBuffer& log)
  307. {
  308. if(!filepath || !*filepath || !log.length())
  309. return;
  310. Owned <IFile> f = createIFile(filepath);
  311. if(f->exists())
  312. f->remove();
  313. Owned <IFileIO> fio = f->open(IFOcreaterw);
  314. if(fio.get())
  315. fio->write(0, log.length(), log.str());
  316. }
  317. bool CppCompiler::compile()
  318. {
  319. if (abortChecker && abortChecker->abortRequested())
  320. return false;
  321. TIME_SECTION(!verbose ? NULL : onlyCompile ? "compile" : "compile/link");
  322. Owned<IThreadPool> pool = createThreadPool("CCompilerWorker", this, NULL, maxCompileThreads?maxCompileThreads:1, INFINITE);
  323. addCompileOption(COMPILE_ONLY[targetCompiler]);
  324. bool ret = false;
  325. Semaphore finishedCompiling;
  326. int numSubmitted = 0;
  327. atomic_set(&numFailed, 0);
  328. ForEachItemIn(i0, allSources)
  329. {
  330. ret = compileFile(pool, allSources.item(i0), finishedCompiling);
  331. if (!ret)
  332. break;
  333. ++numSubmitted;
  334. }
  335. for (int idx = 0; idx < numSubmitted; idx++)
  336. {
  337. if (abortChecker)
  338. {
  339. while (!finishedCompiling.wait(5*1000))
  340. {
  341. if (abortChecker && abortChecker->abortRequested())
  342. {
  343. PrintLog("Aborting compilation");
  344. pool->stopAll(true);
  345. if (!pool->joinAll(true, 10*1000))
  346. WARNLOG("CCompilerWorker; timed out waiting for threads in pool");
  347. return false;
  348. }
  349. }
  350. }
  351. else
  352. finishedCompiling.wait();
  353. }
  354. if (atomic_read(&numFailed) > 0)
  355. ret = false;
  356. else if (!onlyCompile && !precompileHeader)
  357. ret = doLink();
  358. if (!saveTemps && !onlyCompile)
  359. {
  360. removeTemporaries();
  361. StringBuffer temp;
  362. ForEachItemIn(i2, allSources)
  363. remove(getObjectName(temp.clear(), allSources.item(i2)).str());
  364. }
  365. //Combine logfiles
  366. const char* cclog = ccLogPath.get();
  367. if(!cclog||!*cclog)
  368. cclog = queryCcLogName();
  369. Owned <IFile> dstfile = createIFile(cclog);
  370. dstfile->remove();
  371. Owned<IFileIO> dstIO = dstfile->open(IFOwrite);
  372. ForEachItemIn(i2, logFiles)
  373. {
  374. Owned <IFile> srcfile = createIFile(logFiles.item(i2));
  375. if (srcfile->exists())
  376. {
  377. dstIO->appendFile(srcfile);
  378. srcfile->remove();
  379. }
  380. }
  381. //Don't leave lots of blank log files around if the compile was successful
  382. bool logIsEmpty = (dstIO->size() == 0);
  383. dstIO.clear();
  384. if (ret && logIsEmpty)
  385. dstfile->remove();
  386. pool->joinAll(true, 1000);
  387. return ret;
  388. }
  389. bool CppCompiler::compileFile(IThreadPool * pool, const char * filename, Semaphore & finishedCompiling)
  390. {
  391. if (!filename || *filename == 0)
  392. return false;
  393. StringBuffer cmdline;
  394. cmdline.append(CC_NAME[targetCompiler]);
  395. if (precompileHeader)
  396. cmdline.append(CC_OPTION_PRECOMPILEHEADER[targetCompiler]);
  397. cmdline.append(" \"");
  398. if (sourceDir.length())
  399. {
  400. cmdline.append(sourceDir);
  401. addPathSepChar(cmdline);
  402. }
  403. cmdline.append(filename);
  404. if (!precompileHeader)
  405. cmdline.append(".cpp");
  406. cmdline.append("\" ");
  407. expandCompileOptions(cmdline);
  408. if (useDebugLibrary)
  409. cmdline.append(" ").append(LIBFLAG_DEBUG[targetCompiler]);
  410. else
  411. cmdline.append(" ").append(LIBFLAG_RELEASE[targetCompiler]);
  412. _addInclude(cmdline, stdIncludes);
  413. if (targetCompiler == Vs6CppCompiler)
  414. {
  415. if (targetDir.get())
  416. cmdline.append(" /Fo").append("\"").append(targetDir).append("\"");
  417. cmdline.append(" /Fd").append("\"").append(targetDir).append(createDLL ? SharedObjectPrefix : NULL).append(filename).append(".pdb").append("\"");//MORE: prefer create a single pdb file using coreName
  418. }
  419. else
  420. {
  421. cmdline.append(" -o ").append("\"").append(targetDir).append(filename).append('.');
  422. if (precompileHeader)
  423. cmdline.append(PCH_FILE_EXT[targetCompiler]);
  424. else
  425. cmdline.append(OBJECT_FILE_EXT[targetCompiler]);
  426. cmdline.append("\"");
  427. }
  428. StringBuffer expanded;
  429. expandRootDirectory(expanded, cmdline);
  430. StringBuffer logFile;
  431. logFile.append(filename).append(".log.tmp");
  432. logFiles.append(logFile);
  433. Owned<CCompilerThreadParam> parm;
  434. if (verbose)
  435. PrintLog("%s", expanded.toCharArray());
  436. parm.setown(new CCompilerThreadParam(expanded, finishedCompiling, logFile));
  437. pool->start(parm.get());
  438. return true;
  439. }
  440. void CppCompiler::extractErrors(IArrayOf<IError> & errors)
  441. {
  442. const char* cclog = ccLogPath.get();
  443. if(!cclog||!*cclog)
  444. cclog = queryCcLogName();
  445. Owned <IFile> logfile = createIFile(cclog);
  446. if (!logfile->exists())
  447. return;
  448. try
  449. {
  450. StringBuffer file;
  451. file.loadFile(logfile);
  452. RegExpr vsErrorPattern("^{.+}({[0-9]+}) : error {.*$}");
  453. RegExpr vsLinkErrorPattern("^{.+} : error {.*$}");
  454. //cpperr.ecl:7:10: error: ‘syntaxError’ was not declared in this scope
  455. RegExpr gccErrorPattern("^{.+}:{[0-9]+}:{[0-9]+}: {[a-z]+}: {.*$}");
  456. RegExpr gccErrorPattern2("^{.+}:{[0-9]+}: {[a-z]+}: {.*$}");
  457. RegExpr gccLinkErrorPattern("^{.+}:{[0-9]+}: {.*$}"); // undefined reference
  458. RegExpr gccLinkErrorPattern2("^.+ld: {.*$}"); // fail to find library etc.
  459. RegExpr gccExitStatusPattern("^.*exit status$"); // collect2: error: ld returned 1 exit status
  460. const char * cur = file.str();
  461. do
  462. {
  463. const char * newline = strchr(cur, '\n');
  464. StringAttr next;
  465. if (newline)
  466. {
  467. next.set(cur, newline-cur);
  468. cur = newline+1;
  469. if (*cur == '\r')
  470. cur++;
  471. }
  472. else
  473. {
  474. next.set(cur);
  475. cur = NULL;
  476. }
  477. if (gccExitStatusPattern.find(next))
  478. {
  479. //ignore
  480. }
  481. else if (gccErrorPattern.find(next))
  482. {
  483. StringBuffer filename, line, column, kind, msg;
  484. gccErrorPattern.findstr(filename, 1);
  485. gccErrorPattern.findstr(line, 2);
  486. gccErrorPattern.findstr(column, 3);
  487. gccErrorPattern.findstr(kind, 4);
  488. gccErrorPattern.findstr(msg, 5);
  489. if (strieq(kind, "error"))
  490. errors.append(*createError(CategoryError, SeverityError, 2999, msg.str(), filename.str(), atoi(line), atoi(column), 0));
  491. else
  492. errors.append(*createError(CategoryCpp, SeverityWarning, 2999, msg.str(), filename.str(), atoi(line), atoi(column), 0));
  493. }
  494. else if (gccErrorPattern2.find(next))
  495. {
  496. StringBuffer filename, line, kind, msg;
  497. gccErrorPattern2.findstr(filename, 1);
  498. gccErrorPattern2.findstr(line, 2);
  499. gccErrorPattern2.findstr(kind, 3);
  500. gccErrorPattern2.findstr(msg, 4);
  501. if (strieq(kind, "error"))
  502. errors.append(*createError(CategoryError, SeverityError, 2999, msg.str(), filename.str(), atoi(line), 0, 0));
  503. else
  504. errors.append(*createError(CategoryCpp, SeverityWarning, 2999, msg.str(), filename.str(), atoi(line), 0, 0));
  505. }
  506. else if (gccLinkErrorPattern.find(next))
  507. {
  508. StringBuffer filename, line, msg;
  509. gccLinkErrorPattern.findstr(filename, 1);
  510. gccLinkErrorPattern.findstr(line, 2);
  511. gccLinkErrorPattern.findstr(msg, 3);
  512. ErrorSeverity severity = linkFailed ? SeverityError : SeverityWarning;
  513. errors.append(*createError(CategoryError, severity, 2999, msg.str(), filename.str(), atoi(line), 0, 0));
  514. }
  515. else if (gccLinkErrorPattern2.find(next))
  516. {
  517. StringBuffer msg("C++ link error: ");
  518. gccLinkErrorPattern2.findstr(msg, 1);
  519. ErrorSeverity severity = linkFailed ? SeverityError : SeverityWarning;
  520. errors.append(*createError(CategoryError, severity, 2999, msg.str(), NULL, 0, 0, 0));
  521. }
  522. else if (vsErrorPattern.find(next))
  523. {
  524. StringBuffer filename, line, msg("C++ compiler error: ");
  525. vsErrorPattern.findstr(filename, 1);
  526. vsErrorPattern.findstr(line, 2);
  527. vsErrorPattern.findstr(msg, 3);
  528. errors.append(*createError(CategoryError, SeverityError, 2999, msg.str(), filename.str(), atoi(line), 0, 0));
  529. }
  530. else if (vsLinkErrorPattern.find(next))
  531. {
  532. StringBuffer filename, msg("C++ link error: ");
  533. vsLinkErrorPattern.findstr(filename, 1);
  534. vsLinkErrorPattern.findstr(msg, 2);
  535. errors.append(*createError(CategoryError, SeverityError, 2999, msg.str(), filename.str(), 0, 0, 0));
  536. }
  537. } while (cur);
  538. }
  539. catch (IException * e)
  540. {
  541. e->Release();
  542. }
  543. }
  544. void CppCompiler::expandCompileOptions(StringBuffer & target)
  545. {
  546. target.append(" ").append(CC_OPTION_CORE[targetCompiler]).append(" ");
  547. if (targetDebug)
  548. target.append(CC_OPTION_DEBUG[targetCompiler]);
  549. else
  550. target.append(CC_OPTION_RELEASE[targetCompiler]);
  551. target.append(compilerOptions).append(CC_EXTRA_OPTIONS);
  552. }
  553. bool CppCompiler::doLink()
  554. {
  555. StringBuffer cmdline;
  556. cmdline.append(LINK_NAME[targetCompiler]).append(LINK_SEPARATOR[targetCompiler]);
  557. cmdline.append(" ");
  558. if (targetDebug)
  559. cmdline.append(createDLL ? DLL_LINK_OPTION_DEBUG[targetCompiler] : EXE_LINK_OPTION_DEBUG[targetCompiler]);
  560. else
  561. cmdline.append(createDLL ? DLL_LINK_OPTION_RELEASE[targetCompiler] : EXE_LINK_OPTION_RELEASE[targetCompiler]);
  562. cmdline.append(" ");
  563. if (createDLL)
  564. cmdline.append(" ").append(LINK_OPTION_CORE[targetCompiler]);
  565. cmdline.append(stdLibs);
  566. ForEachItemIn(i0, allSources)
  567. cmdline.append(" ").append("\"").append(targetDir).append(allSources.item(i0)).append(".").append(OBJECT_FILE_EXT[targetCompiler]).append("\"");
  568. cmdline.append(linkerOptions);
  569. cmdline.append(linkerLibraries);
  570. StringBuffer outName;
  571. outName.append(createDLL ? SharedObjectPrefix : NULL).append(CORE_NAME).append(createDLL ? SharedObjectExtension : ProcessExtension);
  572. cmdline.append(LINK_TARGET[targetCompiler]).append("\"").append(targetDir).append(outName).append("\"");
  573. StringBuffer temp;
  574. remove(temp.clear().append(targetDir).append(outName).str());
  575. StringBuffer expanded;
  576. expandRootDirectory(expanded, cmdline);
  577. DWORD runcode = 0;
  578. if (verbose)
  579. PrintLog("%s", expanded.toCharArray());
  580. StringBuffer logFile = StringBuffer(CORE_NAME).append("_link.log.tmp");
  581. logFiles.append(logFile);
  582. bool ret = invoke_program(expanded.toCharArray(), runcode, true, logFile) && (runcode == 0);
  583. linkFailed = !ret;
  584. return ret;
  585. }
  586. void CppCompiler::expandRootDirectory(StringBuffer & expanded, StringBuffer & in)
  587. {
  588. unsigned len = in.length();
  589. unsigned i;
  590. for (i = 0; i < len; i++)
  591. {
  592. char c = in.charAt(i);
  593. if (c == '#')
  594. {
  595. if (compilerRoot)
  596. expanded.append(compilerRoot);
  597. else
  598. expanded.append(DEFAULT_CC_LOCATION[targetCompiler]);
  599. }
  600. else
  601. expanded.append(c);
  602. }
  603. }
  604. StringBuffer & CppCompiler::getObjectName(StringBuffer & out, const char * filename)
  605. {
  606. out.append(targetDir);
  607. splitFilename(filename, NULL, NULL, &out, &out);
  608. return out.append(".").append(OBJECT_FILE_EXT[targetCompiler]);
  609. }
  610. void CppCompiler::removeTemporaries()
  611. {
  612. switch (targetCompiler)
  613. {
  614. case Vs6CppCompiler:
  615. case GccCppCompiler:
  616. {
  617. StringBuffer temp;
  618. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".exp").str());
  619. remove(getObjectName(temp.clear(), CORE_NAME).str());
  620. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".lib").str());
  621. #ifdef _WIN32
  622. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".res.lib").str());
  623. #else
  624. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".res.o.lib").str());
  625. remove(temp.clear().append(targetDir).append("lib").append(CORE_NAME).append(".res.o.so").str());
  626. #endif
  627. break;
  628. }
  629. }
  630. }
  631. void CppCompiler::setDebug(bool _debug)
  632. {
  633. targetDebug = _debug;
  634. }
  635. void CppCompiler::setDebugLibrary(bool debug)
  636. {
  637. useDebugLibrary = debug;
  638. }
  639. void CppCompiler::setCreateExe(bool _createExe)
  640. {
  641. createDLL = !_createExe;
  642. }
  643. void CppCompiler::setOptimizeLevel(unsigned level)
  644. {
  645. const char * option = NULL;
  646. switch (targetCompiler)
  647. {
  648. case Vs6CppCompiler:
  649. switch (level)
  650. {
  651. case 0: option = "/Od"; break;
  652. case 1: option = "/O1"; break;
  653. case 2: option = "/O2"; break;
  654. default: // i.e. 3 or higher
  655. option = "/Ob1gty /G6"; break;
  656. }
  657. break;
  658. case GccCppCompiler:
  659. switch (level)
  660. {
  661. case 0: option = "-O0"; break; // do not optimize
  662. case 1: option = "-O1"; break;
  663. case 2: option = "-O2"; break;
  664. default: // i.e. 3 or higher
  665. option = "-O3"; break;
  666. }
  667. break;
  668. }
  669. if (option)
  670. addCompileOption(option);
  671. }
  672. void CppCompiler::setTargetBitLength(unsigned bitlength)
  673. {
  674. const char * option = NULL;
  675. switch (targetCompiler)
  676. {
  677. case Vs6CppCompiler:
  678. switch (bitlength)
  679. {
  680. case 32: break; // 64-bit windows TBD at present....
  681. default:
  682. throwUnexpected();
  683. }
  684. break;
  685. case GccCppCompiler:
  686. switch (bitlength)
  687. {
  688. case 32: option = "-m32"; break;
  689. case 64: option = "-m64"; break;
  690. default:
  691. throwUnexpected();
  692. }
  693. break;
  694. }
  695. if (option)
  696. addCompileOption(option);
  697. }
  698. void CppCompiler::setCCLogPath(const char* path)
  699. {
  700. if(path && *path)
  701. ccLogPath.set(path);
  702. }
  703. //===========================================================================
  704. bool fileIsOlder(const char *dest, const char *src)
  705. {
  706. int h1 = _open(dest, _O_RDONLY);
  707. if (h1 == -1)
  708. return true;
  709. int h2 = _open(src, _O_RDONLY);
  710. assertex(h2 != -1);
  711. struct _stat stat1;
  712. struct _stat stat2;
  713. _fstat(h1, &stat1);
  714. _fstat(h2, &stat2);
  715. _close(h1);
  716. _close(h2);
  717. return stat1.st_mtime < stat2.st_mtime;
  718. }
  719. //===========================================================================
  720. void setCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, bool verbose)
  721. {
  722. doSetCompilerPath(path, includes, libs, tmpdir, DEFAULT_COMPILER, verbose);
  723. }
  724. void setCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, CompilerType targetCompiler, bool verbose)
  725. {
  726. doSetCompilerPath(path, includes, libs, tmpdir, targetCompiler, verbose);
  727. }
  728. ICppCompiler * createCompiler(const char * coreName, const char * sourceDir, const char * targetDir, bool verbose)
  729. {
  730. return new CppCompiler(coreName, sourceDir, targetDir, DEFAULT_COMPILER, verbose);
  731. }
  732. ICppCompiler * createCompiler(const char * coreName, const char * sourceDir, const char * targetDir, CompilerType targetCompiler, bool verbose)
  733. {
  734. return new CppCompiler(coreName, sourceDir, targetDir, targetCompiler, verbose);
  735. }
  736. //===========================================================================
  737. class CCompilerWorker : public CInterface, implements IPooledThread
  738. {
  739. public:
  740. IMPLEMENT_IINTERFACE;
  741. CCompilerWorker(CppCompiler * _compiler, bool _okToAbort) : compiler(_compiler), okToAbort(_okToAbort)
  742. {
  743. handle = 0;
  744. aborted = false;
  745. }
  746. bool canReuse() { return true; }
  747. bool stop()
  748. {
  749. if (okToAbort)
  750. interrupt_program(handle, true);
  751. aborted = true;
  752. return true;
  753. }
  754. void init(void *_params) { params.set((CCompilerThreadParam *)_params); }
  755. void main()
  756. {
  757. DWORD runcode = 0;
  758. bool success;
  759. aborted = false;
  760. handle = 0;
  761. try
  762. {
  763. success = invoke_program(params->cmdline, runcode, false, params->logfile, &handle, false, okToAbort);
  764. if (success)
  765. wait_program(handle, runcode, true);
  766. }
  767. catch(IException* e)
  768. {
  769. StringBuffer sb;
  770. e->errorMessage(sb);
  771. e->Release();
  772. if (sb.length())
  773. PrintLog("%s", sb.str());
  774. success = false;
  775. }
  776. handle = 0;
  777. if (!success || aborted)
  778. atomic_inc(&compiler->numFailed);
  779. params->finishedCompiling.signal();
  780. return;
  781. }
  782. private:
  783. CppCompiler * compiler;
  784. Owned<CCompilerThreadParam> params;
  785. HANDLE handle;
  786. bool aborted;
  787. bool okToAbort;
  788. };
  789. IPooledThread *CppCompiler::createNew()
  790. {
  791. return new CCompilerWorker(this, (abortChecker != NULL));
  792. }