hqlecl.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  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 "build-config.h"
  14. #include "jliball.hpp"
  15. #include "jmisc.hpp"
  16. #include "jstream.hpp"
  17. #include "hql.hpp"
  18. #include "hqlexpr.hpp"
  19. #include "hqlecl.hpp"
  20. #include "hqlthql.hpp"
  21. #include "hqlcerrors.hpp"
  22. #include "hqlcatom.hpp"
  23. #include "hqllib.ipp"
  24. #include "hqlutil.hpp"
  25. #include "hqlhtcpp.ipp"
  26. #include "hqlwcpp.hpp"
  27. #include "hqllib.ipp"
  28. #include "hqlttcpp.ipp"
  29. #include "workunit.hpp"
  30. #include "thorplugin.hpp"
  31. #ifdef _DEBUG
  32. #define IS_DEBUG_BUILD true
  33. #else
  34. #define IS_DEBUG_BUILD false
  35. #endif
  36. #define MAIN_MODULE_TEMPLATE "thortpl.cpp"
  37. #define HEADER_TEMPLATE "thortpl.hpp"
  38. #define CHILD_MODULE_TEMPLATE "childtpl.cpp"
  39. #define PROTO_TEMPLATE "prototpl.cpp"
  40. class NullContextCallback : implements ICodegenContextCallback, public CInterface
  41. {
  42. public:
  43. NullContextCallback(IWorkUnit * _wu) : workunit(_wu) {}
  44. IMPLEMENT_IINTERFACE
  45. virtual void noteCluster(const char *clusterName) override {}
  46. virtual void pushCluster(const char *clusterName) override {}
  47. virtual void popCluster() override {}
  48. virtual bool allowAccess(const char * category, bool isSigned) override { return true; }
  49. virtual IHqlExpression *lookupDFSlayout(const char *filename, IErrorReceiver &errs, const ECLlocation &location, bool isOpt) const override { return nullptr; }
  50. virtual unsigned lookupClusterSize() const override { return 0; }
  51. virtual void getTargetPlatform(StringBuffer & result) override
  52. {
  53. workunit->getDebugValue("targetClusterType", StringBufferAdaptor(result));
  54. }
  55. protected:
  56. Linked<IWorkUnit> workunit;
  57. };
  58. class HqlDllGenerator : implements IHqlExprDllGenerator, implements IAbortRequestCallback, public CInterface
  59. {
  60. public:
  61. HqlDllGenerator(IErrorReceiver * _errs, const char * _wuname, const char * _targetdir, IWorkUnit * _wu, const char * _template_dir, ClusterType _targetClusterType, ICodegenContextCallback * _ctxCallback, bool _checkForLocalFileUploads, bool _okToAbort) :
  62. errs(_errs), wuname(_wuname), targetDir(_targetdir), wu(_wu), template_dir(_template_dir), targetClusterType(_targetClusterType), ctxCallback(_ctxCallback), checkForLocalFileUploads(_checkForLocalFileUploads), okToAbort(_okToAbort)
  63. {
  64. if (!ctxCallback)
  65. ctxCallback.setown(new NullContextCallback(_wu));
  66. noOutput = true;
  67. defaultMaxCompileThreads = 1;
  68. generateTarget = EclGenerateNone;
  69. code.setown(createCppInstance(wu, wuname));
  70. deleteGenerated = false;
  71. totalGeneratedSize = 0;
  72. }
  73. IMPLEMENT_IINTERFACE
  74. virtual void addLibrary(const char * name);
  75. virtual bool processQuery(OwnedHqlExpr & parsedQuery, EclGenerateTarget _generateTarget);
  76. virtual bool generateDll(ICppCompiler * compiler);
  77. virtual bool generateExe(ICppCompiler * compiler);
  78. virtual bool generatePackage(const char * packageName);
  79. virtual void setMaxCompileThreads(unsigned value) { defaultMaxCompileThreads = value; }
  80. virtual void addManifest(const char *filename) { code->addManifest(filename); }
  81. virtual void addManifestFromArchive(IPropertyTree *archive) { code->addManifestFromArchive(archive); }
  82. virtual void addWebServiceInfo(IPropertyTree *wsinfo){ code->addWebServiceInfo(wsinfo); }
  83. virtual double getECLcomplexity(IHqlExpression * exprs);
  84. virtual void setSaveGeneratedFiles(bool value) { deleteGenerated = !value; }
  85. protected:
  86. void addCppName(const char * filename, unsigned minActivity, unsigned maxActivity);
  87. void addLibrariesToCompiler();
  88. void addWorkUnitAsResource();
  89. void calculateHash(IHqlExpression * expr);
  90. bool doCompile(ICppCompiler * compiler);
  91. void doExpand(HqlCppTranslator & translator);
  92. void expandCode(StringBuffer & filename, const char * templateName, bool isHeader, IHqlCppInstance * code, bool multiFile, unsigned pass, CompilerType compiler);
  93. void flushResources();
  94. bool generateCode(HqlQueryContext & query);
  95. bool generateFullFieldUsageStatistics(HqlCppTranslator & translator, IHqlExpression * query);
  96. IPropertyTree * generateSingleFieldUsageStatistics(IHqlExpression * expr, const char * variety, const IPropertyTree * exclude);
  97. offset_t getGeneratedSize() const;
  98. void insertStandAloneCode();
  99. void setWuState(bool ok);
  100. inline bool abortRequested();
  101. protected:
  102. Linked<IErrorReceiver> errs;
  103. const char * wuname;
  104. StringAttr targetDir;
  105. Linked<IWorkUnit> wu;
  106. Owned<IHqlCppInstance> code;
  107. const char * template_dir;
  108. ClusterType targetClusterType;
  109. Linked<ICodegenContextCallback> ctxCallback;
  110. unsigned defaultMaxCompileThreads;
  111. StringArray sourceFiles;
  112. StringArray libraries;
  113. StringArray objects;
  114. offset_t totalGeneratedSize;
  115. bool checkForLocalFileUploads;
  116. bool noOutput;
  117. EclGenerateTarget generateTarget;
  118. bool deleteGenerated;
  119. bool okToAbort;
  120. };
  121. //---------------------------------------------------------------------------
  122. static void processMetaCommands(HqlCppTranslator & translator, IWorkUnit * wu, HqlQueryContext & query, ICodegenContextCallback *ctxCallback);
  123. void HqlDllGenerator::addCppName(const char * filename, unsigned minActivity, unsigned maxActivity)
  124. {
  125. if (wu)
  126. {
  127. Owned<IWUQuery> query = wu->updateQuery();
  128. associateLocalFile(query, FileTypeCpp, filename, pathTail(filename), 0, minActivity, maxActivity);
  129. }
  130. }
  131. void HqlDllGenerator::addLibrary(const char * name)
  132. {
  133. libraries.append(name);
  134. }
  135. void HqlDllGenerator::addLibrariesToCompiler()
  136. {
  137. unsigned idx=0;
  138. for (;;)
  139. {
  140. const char * lib = code->queryLibrary(idx);
  141. if (!lib)
  142. break;
  143. PrintLog("Adding library: %s", lib);
  144. addLibrary(lib);
  145. idx++;
  146. }
  147. idx=0;
  148. for (;;)
  149. {
  150. const char * obj = code->queryObjectFile(idx);
  151. if (!obj)
  152. break;
  153. PrintLog("Adding object file: %s", obj);
  154. objects.append(obj);
  155. idx++;
  156. }
  157. idx=0;
  158. for (;;)
  159. {
  160. const char * src = code->querySourceFile(idx);
  161. if (!src)
  162. break;
  163. PrintLog("Adding source file: %s", src);
  164. sourceFiles.append(src);
  165. idx++;
  166. }
  167. }
  168. void HqlDllGenerator::expandCode(StringBuffer & filename, const char * templateName, bool isHeader, IHqlCppInstance * code, bool multiFile, unsigned pass, CompilerType compiler)
  169. {
  170. filename.clear().append(wuname);
  171. if (pass != 0)
  172. filename.append("_").append(pass);
  173. const char * ext = isHeader ? ".hpp" : ".cpp";
  174. filename.append(ext);
  175. StringBuffer fullname;
  176. addDirectoryPrefix(fullname, targetDir).append(filename);
  177. Owned<IFile> out = createIFile(fullname.str());
  178. Owned<ITemplateExpander> expander = createTemplateExpander(out, templateName, template_dir);
  179. if (!expander)
  180. throwError2(HQLERR_CouldNotOpenTemplateXatY, templateName, template_dir ? template_dir : ".");
  181. Owned<ISectionWriter> writer = createCppWriter(*code, compiler);
  182. Owned<IProperties> props = createProperties(true);
  183. if (multiFile)
  184. {
  185. props->setProp("multiFile", true);
  186. props->setProp("pass", pass);
  187. }
  188. StringBuffer headerName;
  189. headerName.append(wuname).append(".hpp");
  190. props->setProp("headerName", headerName.str());
  191. props->setProp("outputName", fullname.str());
  192. expander->generate(*writer, pass, props);
  193. totalGeneratedSize += out->size();
  194. if (!deleteGenerated)
  195. {
  196. unsigned minActivity, maxActivity;
  197. code->getActivityRange(pass, minActivity, maxActivity);
  198. addCppName(fullname, minActivity, maxActivity);
  199. }
  200. }
  201. //---------------------------------------------------------------------------
  202. bool HqlDllGenerator::processQuery(OwnedHqlExpr & parsedQuery, EclGenerateTarget _generateTarget)
  203. {
  204. generateTarget = _generateTarget;
  205. assertex(wu->getHash());
  206. unsigned prevCount = errs->errCount();
  207. HqlQueryContext query;
  208. query.expr.setown(parsedQuery.getClear());
  209. bool ok = generateCode(query);
  210. code->flushHints();
  211. wu->commit();
  212. if (!ok)
  213. return false;
  214. if (errs->errCount() != prevCount)
  215. return false;
  216. switch (generateTarget)
  217. {
  218. case EclGenerateNone:
  219. case EclGenerateCpp:
  220. return true;
  221. }
  222. flushResources();
  223. addLibrariesToCompiler();
  224. // Free up memory before the c++ compile occurs
  225. code.clear();
  226. return true;
  227. }
  228. bool HqlDllGenerator::generateDll(ICppCompiler * compiler)
  229. {
  230. if (noOutput || !compiler)
  231. return true;
  232. bool ok = doCompile(compiler);
  233. setWuState(ok);
  234. return ok;
  235. }
  236. bool HqlDllGenerator::generateExe(ICppCompiler * compiler)
  237. {
  238. if (noOutput || !compiler)
  239. return true;
  240. compiler->setCreateExe(true);
  241. bool ok = doCompile(compiler);
  242. setWuState(ok);
  243. return ok;
  244. }
  245. bool HqlDllGenerator::generatePackage(const char * packageName)
  246. {
  247. return false;
  248. }
  249. static bool isSetMeta(IHqlExpression * expr)
  250. {
  251. switch (expr->getOperator())
  252. {
  253. case no_compound:
  254. case no_comma:
  255. return isSetMeta(expr->queryChild(0)) && isSetMeta(expr->queryChild(1));
  256. case no_setmeta:
  257. return true;
  258. default:
  259. return false;
  260. }
  261. }
  262. IPropertyTree * HqlDllGenerator::generateSingleFieldUsageStatistics(IHqlExpression * expr, const char * variety, const IPropertyTree * exclude)
  263. {
  264. //Generate each into a new workunit
  265. // Owned<IWorkUnit> localWu = createLocalWorkUnit();
  266. IWorkUnit * localWu = wu;
  267. //Generate the code into a new instance each time so it doesn't hang around eating memory
  268. Owned<IHqlCppInstance> localCode = createCppInstance(localWu, wuname);
  269. HqlQueryContext query;
  270. query.expr.set(expr);
  271. resetUniqueId();
  272. wu->resetBeforeGeneration();
  273. HqlCppTranslator translator(errs, wuname, localCode, targetClusterType, ctxCallback);
  274. try
  275. {
  276. translator.buildCpp(*localCode, query);
  277. return translator.gatherFieldUsage(variety, exclude);
  278. }
  279. catch (IException * e)
  280. {
  281. if (e->errorCode() != HQLERR_ErrorAlreadyReported)
  282. {
  283. unsigned errcode = e->errorCode() ? e->errorCode() : 1;
  284. StringBuffer s;
  285. errs->reportError(errcode, e->errorMessage(s).str(), NULL, 0, 0, 1);
  286. }
  287. e->Release();
  288. return NULL;
  289. }
  290. catch (RELEASE_CATCH_ALL)
  291. {
  292. errs->reportError(99, "Unknown error", NULL, 0, 0, 1);
  293. return NULL;
  294. }
  295. }
  296. bool HqlDllGenerator::generateFullFieldUsageStatistics(HqlCppTranslator & translator, IHqlExpression* query)
  297. {
  298. LinkedHqlExpr savedQuery = query;
  299. //Strip any #options etc. and check that the query consists of a single OUTPUT() action
  300. while ((savedQuery->getOperator() == no_compound) && isSetMeta(savedQuery->queryChild(0)))
  301. savedQuery.set(savedQuery->queryChild(1));
  302. if (savedQuery->getOperator() != no_output)
  303. throw MakeStringException(0, "#option('GenerateFullFieldUsage') requires the query to be a single OUTPUT()");
  304. Owned<IPropertyTree> allFields = createPTree("usage");
  305. IHqlExpression * dataset = savedQuery->queryChild(0);
  306. //First calculate which files are used if no fields are extracted from the output i.e. shared by all output fields
  307. //Use COUNT(dataset) as the query to test that
  308. OwnedHqlExpr countDataset = createValue(no_count, makeIntType(8, false), LINK(dataset));
  309. Owned<IPropertyTree> countFilesUsed = generateSingleFieldUsageStatistics(countDataset, "__shared__", NULL);
  310. if (countFilesUsed)
  311. allFields->addPropTree(countFilesUsed->queryName(), LINK(countFilesUsed));
  312. //Now project the output dataset down to a single field, and generate the file/field dependencies for each of those
  313. OwnedHqlExpr selSeq = createUniqueSelectorSequence();
  314. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  315. RecordSelectIterator iter(dataset->queryRecord(), left);
  316. ForEach(iter)
  317. {
  318. IHqlExpression * cur = iter.query();
  319. IHqlExpression * field = cur->queryChild(1);
  320. OwnedHqlExpr record = createRecord(field);
  321. OwnedHqlExpr self = getSelf(record);
  322. OwnedHqlExpr assign = createAssign(createSelectExpr(LINK(self), LINK(field)), LINK(cur));
  323. OwnedHqlExpr transform = createValue(no_transform, makeTransformType(record->getType()), LINK(assign), NULL);
  324. HqlExprArray args;
  325. args.append(*LINK(dataset));
  326. args.append(*LINK(transform));
  327. args.append(*LINK(selSeq));
  328. OwnedHqlExpr project = createDataset(no_hqlproject,args);
  329. OwnedHqlExpr projectedOutput = replaceChildDataset(savedQuery, project, 0);
  330. StringBuffer variety;
  331. getExprIdentifier(variety, cur);
  332. //Generate each into a new property tree, and only include fields not shared by all other output fields.
  333. Owned<IPropertyTree> filesUsed = generateSingleFieldUsageStatistics(projectedOutput, variety.str(), countFilesUsed);
  334. if (filesUsed)
  335. allFields->addPropTree(filesUsed->queryName(), LINK(filesUsed));
  336. //Generate progress so far
  337. translator.writeFieldUsage(targetDir, allFields, NULL);
  338. }
  339. translator.writeFieldUsage(targetDir, allFields, NULL);
  340. return false;
  341. }
  342. bool HqlDllGenerator::generateCode(HqlQueryContext & query)
  343. {
  344. noOutput = true;
  345. {
  346. // ensure warnings/errors are available before we do the processing...
  347. addTimeStamp(wu, SSTcompilestage, "compile:generate", StWhenStarted);
  348. wu->commit();
  349. cycle_t startCycles = get_cycles_now();
  350. HqlCppTranslator translator(errs, wuname, code, targetClusterType, ctxCallback);
  351. processMetaCommands(translator, wu, query, ctxCallback);
  352. translator.exportWarningMappings();
  353. if (wu->getDebugValueBool("generateFullFieldUsage", false))
  354. {
  355. //Ensure file information is generated. It only partially works with field information at the moment.
  356. //(The merging/difference logic would need to improve, but would be relatively simple if it was useful.)
  357. wu->setDebugValueInt("reportFileUsage", 1, true);
  358. return generateFullFieldUsageStatistics(translator, query.expr);
  359. }
  360. bool ok = false;
  361. try
  362. {
  363. if (!translator.buildCpp(*code, query))
  364. {
  365. wu->setState(WUStateCompleted);
  366. return true;
  367. }
  368. translator.generateStatistics(targetDir, NULL);
  369. translator.finalizeResources();
  370. translator.expandFunctions(true);
  371. }
  372. catch (IError * e)
  373. {
  374. if (e->errorCode() != HQLERR_ErrorAlreadyReported)
  375. {
  376. StringBuffer s;
  377. errs->reportError(e->errorCode(), e->errorMessage(s).str(), e->getFilename(), e->getLine(), e->getColumn(), e->getPosition());
  378. }
  379. e->Release();
  380. return false;
  381. }
  382. catch (IException * e)
  383. {
  384. if (e->errorCode() != HQLERR_ErrorAlreadyReported)
  385. {
  386. unsigned errcode = e->errorCode() ? e->errorCode() : 1;
  387. StringBuffer s;
  388. errs->reportError(errcode, e->errorMessage(s).str(), NULL, 0, 0, 1);
  389. }
  390. e->Release();
  391. return false;
  392. }
  393. catch (RELEASE_CATCH_ALL)
  394. {
  395. errs->reportError(99, "Unknown error", NULL, 0, 0, 1);
  396. return false;
  397. }
  398. if (generateTarget == EclGenerateExe)
  399. insertStandAloneCode();
  400. wu->commit();
  401. //Commit work unit so can view graphs etc. while compiling the C++
  402. if ((generateTarget == EclGenerateNone) || wu->getDebugValueBool("OnlyCheckQuery", false))
  403. {
  404. wu->setState(WUStateCompleted);
  405. return false;
  406. }
  407. if (wu->getDebugValueBool("saveEclTempFiles", false) || wu->getDebugValueBool("saveCppTempFiles", false) || wu->getDebugValueBool("saveCpp", false))
  408. setSaveGeneratedFiles(true);
  409. doExpand(translator);
  410. unsigned __int64 elapsed = cycle_to_nanosec(get_cycles_now() - startCycles);
  411. updateWorkunitTimeStat(wu, SSTcompilestage, "compile:generate", StTimeElapsed, NULL, elapsed);
  412. if (wu->getDebugValueBool("addMemoryToWorkunit", true))
  413. {
  414. memsize_t peakVm, peakResident;
  415. getPeakMemUsage(peakVm, peakResident);
  416. if (peakResident)
  417. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), SSTcompilestage, "compile", StSizePeakMemory, NULL, peakResident, 1, 0, StatsMergeReplace);
  418. }
  419. wu->commit();
  420. addWorkUnitAsResource();
  421. }
  422. noOutput = false;
  423. return true;
  424. }
  425. void HqlDllGenerator::addWorkUnitAsResource()
  426. {
  427. StringBuffer wuXML;
  428. exportWorkUnitToXML(wu, wuXML, false, false, false);
  429. code->addCompressResource("WORKUNIT", wuXML.length(), wuXML.str(), NULL, 1000);
  430. }
  431. void HqlDllGenerator::insertStandAloneCode()
  432. {
  433. BuildCtx ctx(static_cast<HqlCppInstance &>(*code), goAtom);
  434. ctx.addQuotedFunction("int main(int argc, const char *argv[])");
  435. ctx.addQuotedLiteral("return start_query(argc, argv);\n");
  436. }
  437. void HqlDllGenerator::doExpand(HqlCppTranslator & translator)
  438. {
  439. CCycleTimer elapsedTimer;
  440. addTimeStamp(wu, SSTcompilestage, "compile:write c++", StWhenStarted);
  441. unsigned numExtraFiles = translator.getNumExtraCppFiles();
  442. bool isMultiFile = translator.spanMultipleCppFiles();
  443. CompilerType targetCompiler = translator.queryOptions().targetCompiler;
  444. StringBuffer fullname;
  445. expandCode(fullname, MAIN_MODULE_TEMPLATE, false, code, isMultiFile, 0, targetCompiler);
  446. sourceFiles.append(fullname);
  447. if (isMultiFile)
  448. {
  449. expandCode(fullname, HEADER_TEMPLATE, true, code, true, 0, targetCompiler);
  450. for (unsigned i= 0; i < translator.getNumExtraCppFiles(); i++)
  451. {
  452. expandCode(fullname, CHILD_MODULE_TEMPLATE, false, code, true, i+1, targetCompiler);
  453. sourceFiles.append(fullname);
  454. }
  455. }
  456. updateWorkunitTimeStat(wu, SSTcompilestage, "compile:write c++", StTimeElapsed, NULL, elapsedTimer.elapsedNs());
  457. }
  458. bool HqlDllGenerator::abortRequested()
  459. {
  460. return (wu && wu->aborting());
  461. }
  462. bool HqlDllGenerator::doCompile(ICppCompiler * compiler)
  463. {
  464. cycle_t startCycles = get_cycles_now();
  465. addTimeStamp(wu, SSTcompilestage, "compile:compile c++", StWhenStarted);
  466. ForEachItemIn(i, sourceFiles)
  467. compiler->addSourceFile(sourceFiles.item(i));
  468. unsigned maxThreads = wu->getDebugValueInt("maxCompileThreads", defaultMaxCompileThreads);
  469. compiler->setMaxCompileThreads(maxThreads);
  470. bool debug = wu->getDebugValueBool("debugQuery", false);
  471. bool debugLibrary = debug; // should be wu->getDebugValueBool("debugLibrary", IS_DEBUG_BUILD); change for 3.8
  472. compiler->setDebug(debug);
  473. compiler->setDebugLibrary(debugLibrary);
  474. if (!debug)
  475. {
  476. int optimizeLevel = wu->getDebugValueInt("optimizeLevel", targetClusterType == RoxieCluster ? 3 : -1);
  477. if (optimizeLevel != -1)
  478. compiler->setOptimizeLevel(optimizeLevel);
  479. }
  480. #ifdef __64BIT__
  481. // ARMFIX: Map all the uses of this property and make sure
  482. // they're not used to mean x86_64 (it shouldn't, though)
  483. bool target64bit = wu->getDebugValueBool("target64bit", true);
  484. #else
  485. bool target64bit = wu->getDebugValueBool("target64bit", false);
  486. #endif
  487. compiler->setTargetBitLength(target64bit ? 64 : 32);
  488. ForEachItemIn(idx, libraries)
  489. compiler->addLibrary(libraries.item(idx));
  490. ForEachItemIn(idx2, objects)
  491. compiler->addObjectFile(objects.item(idx2));
  492. StringBuffer options;
  493. StringBufferAdaptor linkOptionAdaptor(options);
  494. wu->getDebugValue("linkOptions", linkOptionAdaptor);
  495. compiler->addLinkOption(options.str());
  496. options.clear();
  497. StringBufferAdaptor optionAdaptor(options);
  498. wu->getDebugValue("compileOptions", optionAdaptor);
  499. compiler->addCompileOption(options.str());
  500. if (okToAbort)
  501. compiler->setAbortChecker(this);
  502. PrintLog("Compiling %s", wuname);
  503. bool ok = compiler->compile();
  504. if(ok)
  505. PrintLog("Compiled %s", wuname);
  506. else
  507. PrintLog("Failed to compile %s", wuname);
  508. bool reportCppWarnings = wu->getDebugValueBool("reportCppWarnings", false);
  509. IArrayOf<IError> errors;
  510. compiler->extractErrors(errors);
  511. ForEachItemIn(iErr, errors)
  512. {
  513. IError & cur = errors.item(iErr);
  514. if (isError(&cur) || reportCppWarnings)
  515. errs->report(&cur);
  516. }
  517. unsigned __int64 elapsed = cycle_to_nanosec(get_cycles_now() - startCycles);
  518. updateWorkunitTimeStat(wu, SSTcompilestage, "compile:compile c++", StTimeElapsed, NULL, elapsed);
  519. //Keep the files if there was a compile error.
  520. if (ok && deleteGenerated)
  521. {
  522. StringBuffer temp;
  523. removeFileTraceIfFail(temp.clear().append(wuname).append(".hpp").str());
  524. ForEachItemIn(i, sourceFiles)
  525. {
  526. removeFileTraceIfFail(sourceFiles.item(i));
  527. }
  528. }
  529. return ok;
  530. }
  531. void HqlDllGenerator::flushResources()
  532. {
  533. if (code)
  534. code->flushResources(wuname, ctxCallback);
  535. }
  536. void HqlDllGenerator::setWuState(bool ok)
  537. {
  538. if(ok)
  539. {
  540. if(checkForLocalFileUploads && wu->requiresLocalFileUpload())
  541. wu->setState(WUStateUploadingFiles);
  542. else
  543. wu->setState(WUStateCompiled);
  544. }
  545. else
  546. wu->setState(WUStateFailed);
  547. }
  548. double HqlDllGenerator::getECLcomplexity(IHqlExpression * exprs)
  549. {
  550. Owned<IHqlCppInstance> code = createCppInstance(wu, NULL);
  551. HqlCppTranslator translator(errs, "temp", code, targetClusterType, NULL);
  552. HqlQueryContext query;
  553. query.expr.set(exprs);
  554. processMetaCommands(translator, wu, query, ctxCallback);
  555. return translator.getComplexity(*code, query.expr);
  556. }
  557. offset_t HqlDllGenerator::getGeneratedSize() const
  558. {
  559. return totalGeneratedSize;
  560. }
  561. extern HQLCPP_API double getECLcomplexity(IHqlExpression * exprs, IErrorReceiver * errs, IWorkUnit *wu, ClusterType targetClusterType)
  562. {
  563. HqlDllGenerator generator(errs, "unknown", NULL, wu, NULL, targetClusterType, NULL, false, false);
  564. return generator.getECLcomplexity(exprs);
  565. }
  566. extern HQLCPP_API IHqlExprDllGenerator * createDllGenerator(IErrorReceiver * errs, const char *wuname, const char * targetdir, IWorkUnit *wu, const char * template_dir, ClusterType targetClusterType, ICodegenContextCallback *ctxCallback, bool checkForLocalFileUploads, bool okToAbort)
  567. {
  568. return new HqlDllGenerator(errs, wuname, targetdir, wu, template_dir, targetClusterType, ctxCallback, checkForLocalFileUploads, okToAbort);
  569. }
  570. /*
  571. extern HQLCPP_API void addLibraryReference(IWorkUnit * wu, IHqlLibraryInfo * library, const char * lid)
  572. {
  573. StringBuffer libraryName;
  574. library->getName(libraryName);
  575. Owned<IWULibrary> entry = wu->updateLibraryByName(libraryName.str());
  576. entry->setMajorVersion(library->queryMajorVersion());
  577. entry->setMinorVersion(library->queryMinorVersion());
  578. entry->setCrc(library->queryInterfaceCrc());
  579. if (lid && *lid)
  580. entry->setLID(lid);
  581. }
  582. */
  583. extern HQLCPP_API ClusterType queryClusterType(IConstWorkUnit * wu, ClusterType prevType)
  584. {
  585. ClusterType targetClusterType = prevType;
  586. if (wu->getDebugValueBool("forceRoxie", false))
  587. targetClusterType = RoxieCluster;
  588. else if (prevType == NoCluster)
  589. targetClusterType = ThorLCRCluster;
  590. SCMStringBuffer targetText;
  591. wu->getDebugValue("targetClusterType", targetText);
  592. targetClusterType = getClusterType(targetText.s.str(), targetClusterType);
  593. if ((targetClusterType != RoxieCluster) && wu->getDebugValueBool("forceFakeThor", false))
  594. targetClusterType = HThorCluster;
  595. return targetClusterType;
  596. }
  597. static void processMetaCommands(HqlCppTranslator & translator, IWorkUnit * wu, HqlQueryContext & query, ICodegenContextCallback *ctxCallback)
  598. {
  599. NewThorStoredReplacer transformer(translator, wu, ctxCallback);
  600. translator.traceExpression("before process meta commands", query.expr);
  601. transformer.analyse(query.expr);
  602. if (transformer.needToTransform())
  603. query.expr.setown(transformer.transform(query.expr));
  604. }
  605. extern HQLCPP_API unsigned getLibraryCRC(IHqlExpression * library)
  606. {
  607. assertex(library->getOperator() == no_funcdef);
  608. return getExpressionCRC(library->queryChild(0));
  609. }
  610. void setWorkunitHash(IWorkUnit * wu, IHqlExpression * expr)
  611. {
  612. //Assuming builds come from different branches this will change the crc for each one.
  613. unsigned cacheCRC = crc32(BUILD_TAG, strlen(BUILD_TAG), ACTIVITY_INTERFACE_VERSION);
  614. cacheCRC += getExpressionCRC(expr);
  615. #ifdef _WIN32
  616. cacheCRC++; // make sure CRC is different in windows/linux
  617. #endif
  618. // make sure CRC is different for different host platform
  619. // shouldn't really matter if cross-compiling working properly,
  620. // but fairly harmless.
  621. #ifdef _ARCH_X86_
  622. cacheCRC += 1;
  623. #endif
  624. #ifdef _ARCH_X86_64_
  625. cacheCRC += 2;
  626. #endif
  627. // In theory, ARM and x86 workunits should be totally different, but...
  628. #ifdef _ARCH_ARM32_
  629. cacheCRC += 3;
  630. #endif
  631. #ifdef _ARCH_ARM64_
  632. cacheCRC += 4;
  633. #endif
  634. IExtendedWUInterface *ewu = queryExtendedWU(wu);
  635. cacheCRC = ewu->calculateHash(cacheCRC);
  636. wu->setHash(cacheCRC);
  637. }