jcomp.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "platform.h"
  15. #include "jlib.hpp"
  16. #include "jmisc.hpp"
  17. #include "jcomp.hpp"
  18. #include "jsem.hpp"
  19. #include "jexcept.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 * USE_LIBPATH_FLAG[] = { "/libpath:\"", "-L" };
  51. static const char * USE_LIBPATH_TAIL[] = { "\"", "" };
  52. static const char * USE_LIBRPATH_FLAG[] = { NULL, "-Wl,-rpath -Wl," };
  53. static const char * USE_LIB_FLAG[] = { "", "-l" };
  54. static const char * USE_LIB_TAIL[] = { ".lib", "" };
  55. static const char * USE_INCLUDE_FLAG[] = { "/I\"", "\"-I" };
  56. static const char * USE_DEFINE_FLAG[] = { "/D", "-D" };
  57. static const char * USE_INCLUDE_TAIL[] = { "\"", "\"" };
  58. static const char * INCLUDEPATH[] = { "\"#\\include\"", "\"#/include\"" };
  59. static const char * LINK_SEPARATOR[] = { " /link ", " " };
  60. static const char * OBJECT_FILE_EXT[] = { "obj", "o" };
  61. static const char * LIBFLAG_DEBUG[] = { "/MDd", "" };
  62. static const char * LIBFLAG_RELEASE[] = { "/MD", "" };
  63. static const char * COMPILE_ONLY[] = { "/c", "-c" };
  64. static const char * CC_OPTION_CORE[] = { "", "-fvisibility=hidden -DUSE_VISIBILITY=1" };
  65. static const char * LINK_OPTION_CORE[] = { "/DLL /libpath:." , "" };
  66. static const char * CC_OPTION_DEBUG[] = { "/Zm500 /EHsc /GR /Zi /nologo /bigobj", "-g -fPIC -pipe -O0" };
  67. static const char * DLL_LINK_OPTION_DEBUG[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO /DEBUG /DEBUGTYPE:CV", "-g -shared -L. -fPIC -pipe -O0" };
  68. static const char * EXE_LINK_OPTION_DEBUG[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO /DEBUG /DEBUGTYPE:CV", "-g -L. -Wl,-E -fPIC -pipe -O0" };
  69. static const char * CC_OPTION_RELEASE[] = { "/Zm500 /EHsc /GR /Oi /Ob1 /GF /nologo /bigobj", "-fPIC -pipe -O0" };
  70. static const char * DLL_LINK_OPTION_RELEASE[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO", "-shared -L. -fPIC -pipe -O0" };
  71. static const char * EXE_LINK_OPTION_RELEASE[] = { "/BASE:" BASE_ADDRESS " /NOLOGO /LARGEADDRESSAWARE /INCREMENTAL:NO", "-L. -Wl,-E -fPIC -pipe -O0" };
  72. static const char * LINK_TARGET[] = { " /out:", " -o " };
  73. static const char * DEFAULT_CC_LOCATION[] = { ".", "." };
  74. //===========================================================================
  75. static StringAttr compilerRoot;
  76. static StringAttr stdIncludes;
  77. static StringBuffer stdLibs;
  78. static StringBuffer &dequote(StringBuffer &in)
  79. {
  80. if (in.length() >= 2 && in.charAt(0)=='"' && in.charAt(in.length()-1)=='"')
  81. {
  82. in.remove(in.length()-1, 1);
  83. in.remove(0, 1);
  84. }
  85. return in;
  86. }
  87. static void doSetCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, unsigned targetCompiler, bool verbose)
  88. {
  89. if (!includes)
  90. includes = INCLUDEPATH[targetCompiler];
  91. if (!libs)
  92. libs = LIB_DIR[targetCompiler];
  93. if (verbose)
  94. {
  95. PrintLog("Include directory set to %s", includes);
  96. PrintLog("Library directory set to %s", libs);
  97. }
  98. compilerRoot.set(path ? path : targetCompiler==GccCppCompiler ? "/usr" : ".\\CL");
  99. stdIncludes.set(includes);
  100. stdLibs.clear();
  101. for (;;)
  102. {
  103. StringBuffer thislib;
  104. while (*libs && *libs != ';')
  105. thislib.append(*libs++);
  106. if (thislib.length())
  107. {
  108. stdLibs.append(" ").append(USE_LIBPATH_FLAG[targetCompiler]).append(thislib).append(USE_LIBPATH_TAIL[targetCompiler]);
  109. if (USE_LIBRPATH_FLAG[targetCompiler])
  110. stdLibs.append(" ").append(USE_LIBRPATH_FLAG[targetCompiler]).append(thislib);
  111. }
  112. if (!*libs)
  113. break;
  114. libs++;
  115. }
  116. StringBuffer fname;
  117. if (path)
  118. {
  119. const char *finger = CC_NAME[targetCompiler];
  120. while (*finger)
  121. {
  122. if (*finger == '#')
  123. fname.append(path);
  124. else
  125. fname.append(*finger);
  126. finger++;
  127. }
  128. #if defined(__linux__)
  129. StringBuffer clbin_dir;
  130. const char* dir_end = strrchr(fname, '/');
  131. if(dir_end == NULL)
  132. clbin_dir.append(".");
  133. else
  134. clbin_dir.append((dir_end - fname.str()) + 1, fname.str());
  135. StringBuffer pathenv(clbin_dir.str());
  136. const char* oldpath = getenv("PATH");
  137. if(oldpath != NULL && *oldpath != '\0')
  138. pathenv.append(":").append(oldpath);
  139. setenv("PATH", pathenv.str(), 1);
  140. #endif
  141. }
  142. else
  143. {
  144. fname.append(compilerRoot).append(CC_NAME[targetCompiler]);
  145. fname.replaceString("#",NULL);
  146. }
  147. if (verbose)
  148. PrintLog("Compiler path set to %s", fname.str());
  149. dequote(fname);
  150. #ifdef _WIN32
  151. if (_access(fname.str(), 4))
  152. {
  153. #else
  154. #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
  155. struct stat filestatus;
  156. int r = stat(fname.str(), &filestatus);
  157. if ( (r != 0)
  158. || (!S_ISREG(filestatus.st_mode))
  159. || (filestatus.st_mode&(S_IXOTH|S_IXGRP|S_IXUSR)==0))
  160. {
  161. if (r == -1) errno = ENOENT;
  162. #endif
  163. #endif
  164. if (verbose)
  165. PrintLog("SetCompilerPath - no compiler found");
  166. throw MakeOsException(GetLastError(), "setCompilerPath could not locate compiler %s", fname.str());
  167. }
  168. if(tmpdir && *tmpdir)
  169. {
  170. //MORE: this should be done for the child process instead of the parent but invoke does not let me do it
  171. #if defined(__linux__)
  172. setenv("TMPDIR", tmpdir, 1);
  173. #endif
  174. #ifdef _WIN32
  175. StringBuffer tmpbuf;
  176. tmpbuf.append("TMP=").append(tmpdir);
  177. _putenv(tmpbuf.str());
  178. #endif
  179. }
  180. }
  181. //===========================================================================
  182. class CCompilerThreadParam : CInterface
  183. {
  184. public:
  185. IMPLEMENT_IINTERFACE;
  186. CCompilerThreadParam(const StringBuffer & _cmdline, Semaphore & _finishedCompiling, const StringBuffer & _logfile) : cmdline(_cmdline), finishedCompiling(_finishedCompiling), logfile(_logfile) {};
  187. StringBuffer cmdline;
  188. StringBuffer logfile;
  189. Semaphore & finishedCompiling;
  190. };
  191. //===========================================================================
  192. static void setDirectoryPrefix(StringAttr & target, const char * source)
  193. {
  194. if (source && *source)
  195. {
  196. StringBuffer temp;
  197. target.set(addDirectoryPrefix(temp, source));
  198. }
  199. }
  200. CppCompiler::CppCompiler(const char * _coreName, const char * _sourceDir, const char * _targetDir, unsigned _targetCompiler, bool _verbose)
  201. {
  202. #define CORE_NAME allSources.item(0)
  203. if (_coreName)
  204. addSourceFile(_coreName);
  205. targetCompiler = _targetCompiler;
  206. createDLL = true;
  207. #ifdef _DEBUG
  208. setDebug(true);
  209. setDebugLibrary(true);
  210. #else
  211. setDebug(false);
  212. setDebugLibrary(false);
  213. #endif
  214. setDirectoryPrefix(sourceDir, _sourceDir);
  215. setDirectoryPrefix(targetDir, _targetDir);
  216. maxCompileThreads = 1;
  217. onlyCompile = false;
  218. verbose = _verbose;
  219. saveTemps = false;
  220. abortChecker = NULL;
  221. }
  222. void CppCompiler::addCompileOption(const char * option)
  223. {
  224. compilerOptions.append(' ').append(option);
  225. }
  226. void CppCompiler::addDefine(const char * symbolName, const char * value)
  227. {
  228. compilerOptions.append(" ").append(USE_DEFINE_FLAG[targetCompiler]).append(symbolName);
  229. if (value)
  230. compilerOptions.append('=').append(value);
  231. }
  232. void CppCompiler::addLibrary(const char * libName)
  233. {
  234. if (verbose)
  235. PrintLog("addLibrary %s", libName);
  236. const char* lname = libName;
  237. const char * quote;
  238. 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
  239. if (targetCompiler == GccCppCompiler)
  240. {
  241. // It seems gcc compiler doesn't like things like -lmydir/libx.so
  242. splitFilename(libName, &path, &path, &tail, &tail);
  243. if(path.length())
  244. {
  245. addLibraryPath(path);
  246. lname = tail.str();
  247. // HACK - make it work with plugins. This should be handled at caller end!
  248. if (strncmp(lname, "lib", 3) == 0)
  249. lname += 3;
  250. }
  251. quote = NULL; //quoting lib names with gcc causes link error (lib not found)
  252. }
  253. else
  254. {
  255. quote = "\"";
  256. }
  257. linkerLibraries.append(" ").append(USE_LIB_FLAG[targetCompiler]).append(quote).append(lname).append(USE_LIB_TAIL[targetCompiler]).append(quote);
  258. }
  259. void CppCompiler::addLibraryPath(const char * libPath)
  260. {
  261. linkerOptions.append(" ").append(USE_LIBPATH_FLAG[targetCompiler]).append(libPath).append(USE_LIBPATH_TAIL[targetCompiler]);
  262. if (USE_LIBRPATH_FLAG[targetCompiler])
  263. linkerOptions.append(" ").append(USE_LIBRPATH_FLAG[targetCompiler]).append(libPath);
  264. }
  265. void CppCompiler::_addInclude(StringBuffer &s, const char * paths)
  266. {
  267. if (!paths)
  268. return;
  269. StringBuffer includePath;
  270. for (;;)
  271. {
  272. while (*paths && *paths != ENVSEPCHAR)
  273. includePath.append(*paths++);
  274. if (includePath.length())
  275. s.append(" ").append(USE_INCLUDE_FLAG[targetCompiler]).append(includePath).append(USE_INCLUDE_TAIL[targetCompiler]);
  276. if (!*paths)
  277. break;
  278. paths++;
  279. includePath.clear();
  280. }
  281. }
  282. void CppCompiler::addInclude(const char * paths)
  283. {
  284. _addInclude(compilerOptions, paths);
  285. }
  286. void CppCompiler::addLinkOption(const char * option)
  287. {
  288. linkerOptions.append(' ').append(option);
  289. }
  290. void CppCompiler::addSourceFile(const char * filename)
  291. {
  292. allSources.append(filename);
  293. }
  294. void CppCompiler::writeLogFile(const char* filepath, StringBuffer& log)
  295. {
  296. if(!filepath || !*filepath || !log.length())
  297. return;
  298. Owned <IFile> f = createIFile(filepath);
  299. if(f->exists())
  300. f->remove();
  301. Owned <IFileIO> fio = f->open(IFOcreaterw);
  302. if(fio.get())
  303. fio->write(0, log.length(), log.str());
  304. }
  305. bool CppCompiler::compile()
  306. {
  307. if (abortChecker && abortChecker->abortRequested())
  308. return false;
  309. TIME_SECTION(!verbose ? NULL : onlyCompile ? "compile" : "compile/link");
  310. Owned<IThreadPool> pool = createThreadPool("CCompilerWorker", this, NULL, maxCompileThreads?maxCompileThreads:1, INFINITE);
  311. addCompileOption(COMPILE_ONLY[targetCompiler]);
  312. bool ret = false;
  313. Semaphore finishedCompiling;
  314. int numSubmitted = 0;
  315. atomic_set(&numFailed, 0);
  316. ForEachItemIn(i0, allSources)
  317. {
  318. ret = compileFile(pool, allSources.item(i0), finishedCompiling);
  319. if (!ret)
  320. break;
  321. ++numSubmitted;
  322. }
  323. for (int idx = 0; idx < numSubmitted; idx++)
  324. {
  325. if (abortChecker)
  326. {
  327. while (!finishedCompiling.wait(5*1000))
  328. {
  329. if (abortChecker && abortChecker->abortRequested())
  330. {
  331. PrintLog("Aborting compilation");
  332. pool->stopAll(true);
  333. if (!pool->joinAll(true, 10*1000))
  334. WARNLOG("CCompilerWorker; timed out waiting for threads in pool");
  335. return false;
  336. }
  337. }
  338. }
  339. else
  340. finishedCompiling.wait();
  341. }
  342. if (atomic_read(&numFailed) > 0)
  343. ret = false;
  344. else if (!onlyCompile)
  345. ret = doLink();
  346. if (!saveTemps)
  347. {
  348. removeTemporaries();
  349. StringBuffer temp;
  350. ForEachItemIn(i2, allSources)
  351. remove(getObjectName(temp.clear(), allSources.item(i2)).str());
  352. }
  353. //Combine logfiles
  354. const char* cclog = ccLogPath.get();
  355. if(!cclog||!*cclog)
  356. cclog = queryCcLogName();
  357. Owned <IFile> dstfile = createIFile(cclog);
  358. dstfile->remove();
  359. Owned<IFileIO> dstIO = dstfile->open(IFOwrite);
  360. ForEachItemIn(i2, logFiles)
  361. {
  362. Owned <IFile> srcfile = createIFile(logFiles.item(i2));
  363. if (srcfile->exists())
  364. {
  365. dstIO->appendFile(srcfile);
  366. srcfile->remove();
  367. }
  368. }
  369. pool->joinAll(true, 1000);
  370. return ret;
  371. }
  372. bool CppCompiler::compileFile(IThreadPool * pool, const char * filename, Semaphore & finishedCompiling)
  373. {
  374. if (!filename || *filename == 0)
  375. return false;
  376. StringBuffer fullFileName;
  377. fullFileName.clear().append("\"").append(filename).append(".cpp").append("\"").append(" ");
  378. StringBuffer cmdline;
  379. cmdline.append(CC_NAME[targetCompiler]);
  380. cmdline.append(" ").append(sourceDir);
  381. cmdline.append(fullFileName);
  382. expandCompileOptions(cmdline);
  383. cmdline.append(" ").append(libraryOptions);
  384. _addInclude(cmdline, stdIncludes);
  385. if (targetCompiler == Vs6CppCompiler)
  386. {
  387. if (targetDir.get())
  388. cmdline.append(" /Fo").append("\"").append(targetDir).append("\"");
  389. cmdline.append(" /Fd").append("\"").append(targetDir).append(createDLL ? SharedObjectPrefix : NULL).append(filename).append(".pdb").append("\"");//MORE: prefer create a single pdb file using coreName
  390. }
  391. else
  392. {
  393. if (targetDir.get())
  394. cmdline.append(" -o ").append("\"").append(targetDir).append(filename).append('.').append(OBJECT_FILE_EXT[targetCompiler]).append("\"");
  395. }
  396. StringBuffer expanded;
  397. expandRootDirectory(expanded, cmdline);
  398. StringBuffer logFile;
  399. logFile.append(filename).append(".log.tmp");
  400. logFiles.append(logFile);
  401. Owned<CCompilerThreadParam> parm;
  402. if (verbose)
  403. PrintLog("%s", expanded.toCharArray());
  404. parm.setown(new CCompilerThreadParam(expanded, finishedCompiling, logFile));
  405. pool->start(parm.get());
  406. return true;
  407. }
  408. void CppCompiler::expandCompileOptions(StringBuffer & target)
  409. {
  410. target.append(" ").append(CC_OPTION_CORE[targetCompiler]).append(" ");
  411. if (targetDebug)
  412. target.append(CC_OPTION_DEBUG[targetCompiler]);
  413. else
  414. target.append(CC_OPTION_RELEASE[targetCompiler]);
  415. target.append(compilerOptions).append(CC_EXTRA_OPTIONS);
  416. }
  417. bool CppCompiler::doLink()
  418. {
  419. StringBuffer cmdline;
  420. cmdline.append(LINK_NAME[targetCompiler]).append(LINK_SEPARATOR[targetCompiler]).append(linkerOptions);
  421. ForEachItemIn(i0, allSources)
  422. cmdline.append(" ").append("\"").append(targetDir).append(allSources.item(i0)).append(".").append(OBJECT_FILE_EXT[targetCompiler]).append("\"");
  423. cmdline.append(linkerLibraries);
  424. StringBuffer outName;
  425. outName.append(createDLL ? SharedObjectPrefix : NULL).append(CORE_NAME).append(createDLL ? SharedObjectExtension : ProcessExtension);
  426. cmdline.append(LINK_TARGET[targetCompiler]).append("\"").append(targetDir).append(outName).append("\"");
  427. StringBuffer temp;
  428. remove(temp.clear().append(targetDir).append(outName).str());
  429. StringBuffer expanded;
  430. expandRootDirectory(expanded, cmdline);
  431. DWORD runcode = 0;
  432. if (verbose)
  433. PrintLog("%s", expanded.toCharArray());
  434. StringBuffer logFile = StringBuffer(CORE_NAME).append("_link.log.tmp");
  435. logFiles.append(logFile);
  436. bool ret = invoke_program(expanded.toCharArray(), runcode, true, logFile) && (runcode == 0);
  437. return ret;
  438. }
  439. void CppCompiler::expandRootDirectory(StringBuffer & expanded, StringBuffer & in)
  440. {
  441. unsigned len = in.length();
  442. unsigned i;
  443. for (i = 0; i < len; i++)
  444. {
  445. char c = in.charAt(i);
  446. if (c == '#')
  447. {
  448. if (compilerRoot)
  449. expanded.append(compilerRoot);
  450. else
  451. expanded.append(DEFAULT_CC_LOCATION[targetCompiler]);
  452. }
  453. else
  454. expanded.append(c);
  455. }
  456. }
  457. StringBuffer & CppCompiler::getObjectName(StringBuffer & out, const char * filename)
  458. {
  459. out.append(targetDir);
  460. splitFilename(filename, NULL, NULL, &out, &out);
  461. return out.append(".").append(OBJECT_FILE_EXT[targetCompiler]);
  462. }
  463. void CppCompiler::removeTemporaries()
  464. {
  465. switch (targetCompiler)
  466. {
  467. case Vs6CppCompiler:
  468. case GccCppCompiler:
  469. {
  470. StringBuffer temp;
  471. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".exp").str());
  472. remove(getObjectName(temp.clear(), CORE_NAME).str());
  473. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".lib").str());
  474. #ifdef _WIN32
  475. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".res.lib").str());
  476. #else
  477. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".res.o.lib").str());
  478. remove(temp.clear().append(targetDir).append("lib").append(CORE_NAME).append(".res.o.so").str());
  479. #endif
  480. break;
  481. }
  482. }
  483. }
  484. void CppCompiler::setDebug(bool _debug)
  485. {
  486. targetDebug = _debug;
  487. resetLinkOptions();
  488. }
  489. void CppCompiler::resetLinkOptions()
  490. {
  491. if (targetDebug)
  492. {
  493. setLinkOptions(createDLL ? DLL_LINK_OPTION_DEBUG[targetCompiler] : EXE_LINK_OPTION_DEBUG[targetCompiler]);
  494. }
  495. else
  496. {
  497. setLinkOptions(createDLL ? DLL_LINK_OPTION_RELEASE[targetCompiler] : EXE_LINK_OPTION_RELEASE[targetCompiler]);
  498. }
  499. }
  500. void CppCompiler::setDebugLibrary(bool debug)
  501. {
  502. if (debug)
  503. libraryOptions.set(LIBFLAG_DEBUG[targetCompiler]);
  504. else
  505. libraryOptions.set(LIBFLAG_RELEASE[targetCompiler]);
  506. }
  507. void CppCompiler::setLinkOptions(const char * option)
  508. {
  509. linkerOptions.clear().append(" ").append(option).append(" ");
  510. if (createDLL)
  511. linkerOptions.append(" ").append(LINK_OPTION_CORE[targetCompiler]);
  512. linkerOptions.append(stdLibs);
  513. }
  514. void CppCompiler::setCreateExe(bool _createExe)
  515. {
  516. createDLL = !_createExe;
  517. resetLinkOptions();
  518. }
  519. void CppCompiler::setOptimizeLevel(unsigned level)
  520. {
  521. const char * option = NULL;
  522. switch (targetCompiler)
  523. {
  524. case Vs6CppCompiler:
  525. switch (level)
  526. {
  527. case 0: option = "/Od"; break;
  528. case 1: option = "/O1"; break;
  529. case 2: option = "/O2"; break;
  530. default: // i.e. 3 or higher
  531. option = "/Ob1gty /G6"; break;
  532. }
  533. break;
  534. case GccCppCompiler:
  535. switch (level)
  536. {
  537. case 0: option = "-O0"; break; // do not optimize
  538. case 1: option = "-O1"; break;
  539. case 2: option = "-O2"; break;
  540. default: // i.e. 3 or higher
  541. option = "-O3"; break;
  542. }
  543. break;
  544. }
  545. if (option)
  546. addCompileOption(option);
  547. }
  548. void CppCompiler::setTargetBitLength(unsigned bitlength)
  549. {
  550. const char * option = NULL;
  551. switch (targetCompiler)
  552. {
  553. case Vs6CppCompiler:
  554. switch (bitlength)
  555. {
  556. case 32: break; // 64-bit windows TBD at present....
  557. default:
  558. throwUnexpected();
  559. }
  560. break;
  561. case GccCppCompiler:
  562. switch (bitlength)
  563. {
  564. case 32: option = "-m32"; break;
  565. case 64: option = "-m64"; break;
  566. default:
  567. throwUnexpected();
  568. }
  569. break;
  570. }
  571. if (option)
  572. addCompileOption(option);
  573. }
  574. void CppCompiler::setCCLogPath(const char* path)
  575. {
  576. if(path && *path)
  577. ccLogPath.set(path);
  578. }
  579. //===========================================================================
  580. bool fileIsOlder(const char *dest, const char *src)
  581. {
  582. int h1 = _open(dest, _O_RDONLY);
  583. if (h1 == -1)
  584. return true;
  585. int h2 = _open(src, _O_RDONLY);
  586. assertex(h2 != -1);
  587. struct _stat stat1;
  588. struct _stat stat2;
  589. _fstat(h1, &stat1);
  590. _fstat(h2, &stat2);
  591. _close(h1);
  592. _close(h2);
  593. return stat1.st_mtime < stat2.st_mtime;
  594. }
  595. //===========================================================================
  596. void setCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, bool verbose)
  597. {
  598. doSetCompilerPath(path, includes, libs, tmpdir, DEFAULT_COMPILER, verbose);
  599. }
  600. void setCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, CompilerType targetCompiler, bool verbose)
  601. {
  602. doSetCompilerPath(path, includes, libs, tmpdir, targetCompiler, verbose);
  603. }
  604. ICppCompiler * createCompiler(const char * coreName, const char * sourceDir, const char * targetDir, bool verbose)
  605. {
  606. return new CppCompiler(coreName, sourceDir, targetDir, DEFAULT_COMPILER, verbose);
  607. }
  608. ICppCompiler * createCompiler(const char * coreName, const char * sourceDir, const char * targetDir, CompilerType targetCompiler, bool verbose)
  609. {
  610. return new CppCompiler(coreName, sourceDir, targetDir, targetCompiler, verbose);
  611. }
  612. //===========================================================================
  613. class CCompilerWorker : public CInterface, implements IPooledThread
  614. {
  615. public:
  616. IMPLEMENT_IINTERFACE;
  617. CCompilerWorker(CppCompiler * _compiler) : compiler(_compiler) {}
  618. bool canReuse() { return true; }
  619. bool stop() { return true; }
  620. void init(void *_params) { params.set((CCompilerThreadParam *)_params); }
  621. void main()
  622. {
  623. DWORD runcode = 0;
  624. bool success;
  625. try
  626. {
  627. success = invoke_program(params->cmdline, runcode, true, params->logfile) && (runcode == 0);
  628. }
  629. catch(IException* e)
  630. {
  631. StringBuffer sb;
  632. e->errorMessage(sb);
  633. e->Release();
  634. if (sb.length())
  635. PrintLog("%s", sb.str());
  636. success = false;
  637. }
  638. if (!success)
  639. atomic_inc(&compiler->numFailed);
  640. params->finishedCompiling.signal();
  641. return;
  642. }
  643. private:
  644. CppCompiler * compiler;
  645. Owned<CCompilerThreadParam> params;
  646. };
  647. IPooledThread *CppCompiler::createNew()
  648. {
  649. return new CCompilerWorker(this);
  650. }