jcomp.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  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. // HACK - make it work with plugins. This should be handled at caller end!
  247. if (strncmp(tail.str(), "lib", 3) == 0)
  248. lname = tail.str() + 3;
  249. }
  250. quote = NULL; //quoting lib names with gcc causes link error (lib not found)
  251. }
  252. else
  253. {
  254. quote = "\"";
  255. }
  256. linkerOptions.append(" ").append(USE_LIB_FLAG[targetCompiler]).append(quote).append(lname).append(USE_LIB_TAIL[targetCompiler]).append(quote);
  257. }
  258. void CppCompiler::addLibraryPath(const char * libPath)
  259. {
  260. linkerOptions.append(" ").append(USE_LIBPATH_FLAG[targetCompiler]).append(libPath).append(USE_LIBPATH_TAIL[targetCompiler]);
  261. if (USE_LIBRPATH_FLAG[targetCompiler])
  262. linkerOptions.append(" ").append(USE_LIBRPATH_FLAG[targetCompiler]).append(libPath);
  263. }
  264. void CppCompiler::_addInclude(StringBuffer &s, const char * paths)
  265. {
  266. if (!paths)
  267. return;
  268. StringBuffer includePath;
  269. for (;;)
  270. {
  271. while (*paths && *paths != ENVSEPCHAR)
  272. includePath.append(*paths++);
  273. if (includePath.length())
  274. s.append(" ").append(USE_INCLUDE_FLAG[targetCompiler]).append(includePath).append(USE_INCLUDE_TAIL[targetCompiler]);
  275. if (!*paths)
  276. break;
  277. paths++;
  278. includePath.clear();
  279. }
  280. }
  281. void CppCompiler::addInclude(const char * paths)
  282. {
  283. _addInclude(compilerOptions, paths);
  284. }
  285. void CppCompiler::addLinkOption(const char * option)
  286. {
  287. linkerOptions.append(' ').append(option);
  288. }
  289. void CppCompiler::addSourceFile(const char * filename)
  290. {
  291. allSources.append(filename);
  292. }
  293. void CppCompiler::writeLogFile(const char* filepath, StringBuffer& log)
  294. {
  295. if(!filepath || !*filepath || !log.length())
  296. return;
  297. Owned <IFile> f = createIFile(filepath);
  298. if(f->exists())
  299. f->remove();
  300. Owned <IFileIO> fio = f->open(IFOcreaterw);
  301. if(fio.get())
  302. fio->write(0, log.length(), log.str());
  303. }
  304. bool CppCompiler::compile()
  305. {
  306. if (abortChecker && abortChecker->abortRequested())
  307. return false;
  308. TIME_SECTION(!verbose ? NULL : onlyCompile ? "compile" : "compile/link");
  309. Owned<IThreadPool> pool = createThreadPool("CCompilerWorker", this, NULL, maxCompileThreads?maxCompileThreads:1, INFINITE);
  310. addCompileOption(COMPILE_ONLY[targetCompiler]);
  311. bool ret = false;
  312. Semaphore finishedCompiling;
  313. int numSubmitted = 0;
  314. atomic_set(&numFailed, 0);
  315. ForEachItemIn(i0, allSources)
  316. {
  317. ret = compileFile(pool, allSources.item(i0), finishedCompiling);
  318. if (!ret)
  319. break;
  320. ++numSubmitted;
  321. }
  322. for (int idx = 0; idx < numSubmitted; idx++)
  323. {
  324. if (abortChecker)
  325. {
  326. while (!finishedCompiling.wait(5*1000))
  327. {
  328. if (abortChecker && abortChecker->abortRequested())
  329. {
  330. PrintLog("Aborting compilation");
  331. pool->stopAll(true);
  332. if (!pool->joinAll(true, 10*1000))
  333. WARNLOG("CCompilerWorker; timed out waiting for threads in pool");
  334. return false;
  335. }
  336. }
  337. }
  338. else
  339. finishedCompiling.wait();
  340. }
  341. if (atomic_read(&numFailed) > 0)
  342. ret = false;
  343. else if (!onlyCompile)
  344. ret = doLink();
  345. if (!saveTemps)
  346. {
  347. removeTemporaries();
  348. StringBuffer temp;
  349. ForEachItemIn(i2, allSources)
  350. remove(getObjectName(temp.clear(), allSources.item(i2)).str());
  351. }
  352. //Combine logfiles
  353. const char* cclog = ccLogPath.get();
  354. if(!cclog||!*cclog)
  355. cclog = queryCcLogName();
  356. Owned <IFile> dstfile = createIFile(cclog);
  357. dstfile->remove();
  358. Owned<IFileIO> dstIO = dstfile->open(IFOwrite);
  359. ForEachItemIn(i2, logFiles)
  360. {
  361. Owned <IFile> srcfile = createIFile(logFiles.item(i2));
  362. if (srcfile->exists())
  363. {
  364. dstIO->appendFile(srcfile);
  365. srcfile->remove();
  366. }
  367. }
  368. pool->joinAll(true, 1000);
  369. return ret;
  370. }
  371. bool CppCompiler::compileFile(IThreadPool * pool, const char * filename, Semaphore & finishedCompiling)
  372. {
  373. if (!filename || *filename == 0)
  374. return false;
  375. StringBuffer fullFileName;
  376. fullFileName.clear().append("\"").append(filename).append(".cpp").append("\"").append(" ");
  377. StringBuffer cmdline;
  378. cmdline.append(CC_NAME[targetCompiler]);
  379. cmdline.append(" ").append(sourceDir);
  380. cmdline.append(fullFileName);
  381. expandCompileOptions(cmdline);
  382. cmdline.append(" ").append(libraryOptions);
  383. _addInclude(cmdline, stdIncludes);
  384. if (targetCompiler == Vs6CppCompiler)
  385. {
  386. if (targetDir.get())
  387. cmdline.append(" /Fo").append("\"").append(targetDir).append("\"");
  388. cmdline.append(" /Fd").append("\"").append(targetDir).append(createDLL ? SharedObjectPrefix : NULL).append(filename).append(".pdb").append("\"");//MORE: prefer create a single pdb file using coreName
  389. }
  390. StringBuffer expanded;
  391. expandRootDirectory(expanded, cmdline);
  392. StringBuffer logFile;
  393. logFile.append(filename).append(".log");
  394. logFiles.append(logFile);
  395. Owned<CCompilerThreadParam> parm;
  396. if (verbose)
  397. PrintLog("%s", expanded.toCharArray());
  398. parm.setown(new CCompilerThreadParam(expanded, finishedCompiling, logFile));
  399. pool->start(parm.get());
  400. return true;
  401. }
  402. void CppCompiler::expandCompileOptions(StringBuffer & target)
  403. {
  404. target.append(" ").append(CC_OPTION_CORE[targetCompiler]).append(" ");
  405. if (targetDebug)
  406. target.append(CC_OPTION_DEBUG[targetCompiler]);
  407. else
  408. target.append(CC_OPTION_RELEASE[targetCompiler]);
  409. target.append(compilerOptions).append(CC_EXTRA_OPTIONS);
  410. }
  411. bool CppCompiler::doLink()
  412. {
  413. StringBuffer cmdline;
  414. cmdline.append(LINK_NAME[targetCompiler]).append(LINK_SEPARATOR[targetCompiler]).append(linkerOptions);
  415. ForEachItemIn(i0, allSources)
  416. cmdline.append(" ").append("\"").append(targetDir).append(allSources.item(i0)).append(".").append(OBJECT_FILE_EXT[targetCompiler]).append("\"");
  417. StringBuffer outName;
  418. outName.append(createDLL ? SharedObjectPrefix : NULL).append(CORE_NAME).append(createDLL ? SharedObjectExtension : ProcessExtension);
  419. cmdline.append(LINK_TARGET[targetCompiler]).append("\"").append(targetDir).append(outName).append("\"");
  420. StringBuffer temp;
  421. remove(temp.clear().append(targetDir).append(outName).str());
  422. StringBuffer expanded;
  423. expandRootDirectory(expanded, cmdline);
  424. DWORD runcode = 0;
  425. if (verbose)
  426. PrintLog("%s", expanded.toCharArray());
  427. StringBuffer logFile = StringBuffer(CORE_NAME).append("_link.log");
  428. logFiles.append(logFile);
  429. bool ret = invoke_program(expanded.toCharArray(), runcode, true, logFile) && (runcode == 0);
  430. return ret;
  431. }
  432. void CppCompiler::expandRootDirectory(StringBuffer & expanded, StringBuffer & in)
  433. {
  434. unsigned len = in.length();
  435. unsigned i;
  436. for (i = 0; i < len; i++)
  437. {
  438. char c = in.charAt(i);
  439. if (c == '#')
  440. {
  441. if (compilerRoot)
  442. expanded.append(compilerRoot);
  443. else
  444. expanded.append(DEFAULT_CC_LOCATION[targetCompiler]);
  445. }
  446. else
  447. expanded.append(c);
  448. }
  449. }
  450. StringBuffer & CppCompiler::getObjectName(StringBuffer & out, const char * filename)
  451. {
  452. #ifdef _WIN32
  453. out.append(targetDir);
  454. splitFilename(filename, NULL, NULL, &out, &out);
  455. #else
  456. //MORE: Not sure where gcc puts the object files... current directory? Same as cpp file?
  457. out.append(targetDir);
  458. splitFilename(filename, NULL, NULL, &out, &out);
  459. #endif
  460. return out.append(".").append(OBJECT_FILE_EXT[targetCompiler]);
  461. }
  462. void CppCompiler::removeTemporaries()
  463. {
  464. switch (targetCompiler)
  465. {
  466. case Vs6CppCompiler:
  467. case GccCppCompiler:
  468. {
  469. StringBuffer temp;
  470. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".exp").str());
  471. remove(getObjectName(temp.clear(), CORE_NAME).str());
  472. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".lib").str());
  473. #ifdef _WIN32
  474. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".res.lib").str());
  475. #else
  476. remove(temp.clear().append(targetDir).append(CORE_NAME).append(".res.o.lib").str());
  477. remove(temp.clear().append(targetDir).append("lib").append(CORE_NAME).append(".res.o.so").str());
  478. #endif
  479. break;
  480. }
  481. }
  482. }
  483. void CppCompiler::setDebug(bool _debug)
  484. {
  485. targetDebug = _debug;
  486. resetLinkOptions();
  487. }
  488. void CppCompiler::resetLinkOptions()
  489. {
  490. if (targetDebug)
  491. {
  492. setLinkOptions(createDLL ? DLL_LINK_OPTION_DEBUG[targetCompiler] : EXE_LINK_OPTION_DEBUG[targetCompiler]);
  493. }
  494. else
  495. {
  496. setLinkOptions(createDLL ? DLL_LINK_OPTION_RELEASE[targetCompiler] : EXE_LINK_OPTION_RELEASE[targetCompiler]);
  497. }
  498. }
  499. void CppCompiler::setDebugLibrary(bool debug)
  500. {
  501. if (debug)
  502. libraryOptions.set(LIBFLAG_DEBUG[targetCompiler]);
  503. else
  504. libraryOptions.set(LIBFLAG_RELEASE[targetCompiler]);
  505. }
  506. void CppCompiler::setLinkOptions(const char * option)
  507. {
  508. linkerOptions.clear().append(" ").append(option).append(" ");
  509. if (createDLL)
  510. linkerOptions.append(" ").append(LINK_OPTION_CORE[targetCompiler]);
  511. linkerOptions.append(stdLibs);
  512. }
  513. void CppCompiler::setCreateExe(bool _createExe)
  514. {
  515. createDLL = !_createExe;
  516. resetLinkOptions();
  517. }
  518. void CppCompiler::setOptimizeLevel(unsigned level)
  519. {
  520. const char * option = NULL;
  521. switch (targetCompiler)
  522. {
  523. case Vs6CppCompiler:
  524. switch (level)
  525. {
  526. case 0: option = "/Od"; break;
  527. case 1: option = "/O1"; break;
  528. case 2: option = "/O2"; break;
  529. default: // i.e. 3 or higher
  530. option = "/Ob1gty /G6"; break;
  531. }
  532. break;
  533. case GccCppCompiler:
  534. switch (level)
  535. {
  536. case 0: option = "-O0"; break; // do not optimize
  537. case 1: option = "-O1"; break;
  538. case 2: option = "-O2"; break;
  539. default: // i.e. 3 or higher
  540. option = "-O3"; break;
  541. }
  542. break;
  543. }
  544. if (option)
  545. addCompileOption(option);
  546. }
  547. void CppCompiler::setTargetBitLength(unsigned bitlength)
  548. {
  549. const char * option = NULL;
  550. switch (targetCompiler)
  551. {
  552. case Vs6CppCompiler:
  553. switch (bitlength)
  554. {
  555. case 32: break; // 64-bit windows TBD at present....
  556. default:
  557. throwUnexpected();
  558. }
  559. break;
  560. case GccCppCompiler:
  561. switch (bitlength)
  562. {
  563. case 32: option = "-m32"; break;
  564. case 64: option = "-m64"; break;
  565. default:
  566. throwUnexpected();
  567. }
  568. break;
  569. }
  570. if (option)
  571. addCompileOption(option);
  572. }
  573. void CppCompiler::setCCLogPath(const char* path)
  574. {
  575. if(path && *path)
  576. ccLogPath.set(path);
  577. }
  578. //===========================================================================
  579. bool fileIsOlder(const char *dest, const char *src)
  580. {
  581. int h1 = _open(dest, _O_RDONLY);
  582. if (h1 == -1)
  583. return true;
  584. int h2 = _open(src, _O_RDONLY);
  585. assertex(h2 != -1);
  586. struct _stat stat1;
  587. struct _stat stat2;
  588. _fstat(h1, &stat1);
  589. _fstat(h2, &stat2);
  590. _close(h1);
  591. _close(h2);
  592. return stat1.st_mtime < stat2.st_mtime;
  593. }
  594. //===========================================================================
  595. void setCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, bool verbose)
  596. {
  597. doSetCompilerPath(path, includes, libs, tmpdir, DEFAULT_COMPILER, verbose);
  598. }
  599. void setCompilerPath(const char * path, const char * includes, const char * libs, const char * tmpdir, CompilerType targetCompiler, bool verbose)
  600. {
  601. doSetCompilerPath(path, includes, libs, tmpdir, targetCompiler, verbose);
  602. }
  603. ICppCompiler * createCompiler(const char * coreName, const char * sourceDir, const char * targetDir, bool verbose)
  604. {
  605. return new CppCompiler(coreName, sourceDir, targetDir, DEFAULT_COMPILER, verbose);
  606. }
  607. ICppCompiler * createCompiler(const char * coreName, const char * sourceDir, const char * targetDir, CompilerType targetCompiler, bool verbose)
  608. {
  609. return new CppCompiler(coreName, sourceDir, targetDir, targetCompiler, verbose);
  610. }
  611. //===========================================================================
  612. class CCompilerWorker : public CInterface, implements IPooledThread
  613. {
  614. public:
  615. IMPLEMENT_IINTERFACE;
  616. CCompilerWorker(CppCompiler * _compiler) : compiler(_compiler) {}
  617. bool canReuse() { return true; }
  618. bool stop() { return true; }
  619. void init(void *_params) { params.set((CCompilerThreadParam *)_params); }
  620. void main()
  621. {
  622. DWORD runcode = 0;
  623. bool success;
  624. try
  625. {
  626. success = invoke_program(params->cmdline, runcode, true, params->logfile) && (runcode == 0);
  627. }
  628. catch(IException* e)
  629. {
  630. StringBuffer sb;
  631. e->errorMessage(sb);
  632. e->Release();
  633. if (sb.length())
  634. PrintLog("%s", sb.str());
  635. success = false;
  636. }
  637. if (!success)
  638. atomic_inc(&compiler->numFailed);
  639. params->finishedCompiling.signal();
  640. return;
  641. }
  642. private:
  643. CppCompiler * compiler;
  644. Owned<CCompilerThreadParam> params;
  645. };
  646. IPooledThread *CppCompiler::createNew()
  647. {
  648. return new CCompilerWorker(this);
  649. }