From 540e4c573c3ffbff070b35607a049f910bcc657e Mon Sep 17 00:00:00 2001 From: Gavin Halliday Date: Fri, 3 Feb 2012 14:37:25 +0000 Subject: [PATCH] Fix gh-1426 Implement -Wl, and related changes * -Wl was passed to the compiler instead of the linker. * Any linker options set before setExe()/setDebug() were called were ignored. * #option action was ignored in a beginc++ (bugzilla bug #84603) * #option wasn't stripped from beginc++ that wasn't defined as a function (not very usual). * Added #option library 'mylib' within a beginc++ to add a library to the list passed to the linker. Signed-off-by: Gavin Halliday --- ecl/eclcc/eclcc.cpp | 14 ++++++-- ecl/hql/hqlexpr.cpp | 17 ++++++++- ecl/hql/hqlgram2.cpp | 5 +-- ecl/hql/hqllex.l | 4 ++- ecl/hql/hqlutil.cpp | 74 ++++++++++++++++++++++++++++++++++------ ecl/hqlcpp/hqlcpp.cpp | 27 ++++++++++++++- ecl/hqlcpp/hqlcpp.ipp | 1 + ecl/hqlcpp/hqlecl.cpp | 9 ++++- ecl/regress/cppbody6.ecl | 40 ++++++++++++++++++++++ ecl/regress/cppbody7.ecl | 40 ++++++++++++++++++++++ ecl/regress/cppbody8.ecl | 27 +++++++++++++++ system/jlib/jcomp.cpp | 49 +++++++++++--------------- system/jlib/jcomp.hpp | 1 - system/jlib/jcomp.ipp | 4 +-- 14 files changed, 260 insertions(+), 52 deletions(-) create mode 100644 ecl/regress/cppbody6.ecl create mode 100644 ecl/regress/cppbody7.ecl create mode 100644 ecl/regress/cppbody8.ecl diff --git a/ecl/eclcc/eclcc.cpp b/ecl/eclcc/eclcc.cpp index 13ac9503505..2574cbe9ed9 100644 --- a/ecl/eclcc/eclcc.cpp +++ b/ecl/eclcc/eclcc.cpp @@ -244,6 +244,7 @@ class EclCC IFileArray inputFiles; StringArray debugOptions; StringArray compileOptions; + StringArray linkOptions; StringArray libraryPaths; ClusterType optTargetClusterType; @@ -438,6 +439,9 @@ ICppCompiler * EclCC::createCompiler(const char * coreName) ForEachItemIn(iComp, compileOptions) compiler->addCompileOption(compileOptions.item(iComp)); + ForEachItemIn(iLink, linkOptions) + compiler->addLinkOption(linkOptions.item(iLink)); + ForEachItemIn(iLib, libraryPaths) compiler->addLibraryPath(libraryPaths.item(iLib)); @@ -1357,9 +1361,14 @@ bool EclCC::parseCommandLineOptions(int argc, const char* argv[]) { expandCommaList(compileOptions, arg+4); } - else if (startsWith(arg, "-Wl,") || startsWith(arg, "-Wp,") || startsWith(arg, "-Wa,")) + else if (startsWith(arg, "-Wl,")) + { + //Pass these straight through to the linker - with -Wl, prefix removed + linkOptions.append(arg+4); + } + else if (startsWith(arg, "-Wp,") || startsWith(arg, "-Wa,")) { - //Pass these straigh through to the gcc compiler + //Pass these straight through to the gcc compiler compileOptions.append(arg); } else if (iter.matchFlag(optWorkUnit, "-wu")) @@ -1417,6 +1426,7 @@ void EclCC::usage() " executable, or stdout)\n" " -P Specify the path of the output files\n" " -Wc,xx Supply option for the c++ compiler\n" + " -Wl,xx Supply option for the linker\n" " -save-cpps Do not delete generated c++ files (implied if -g)\n" " -save-temps Do not delete intermediate files\n" " -manifest Specify path to manifest file listing resources to add\n" diff --git a/ecl/hql/hqlexpr.cpp b/ecl/hql/hqlexpr.cpp index 83d1460817c..f7a196c5768 100644 --- a/ecl/hql/hqlexpr.cpp +++ b/ecl/hql/hqlexpr.cpp @@ -3416,8 +3416,17 @@ void CHqlExpression::updateFlagsAfterOperands() case no_call: { IHqlExpression * funcdef = queryBody()->queryFunctionDefinition(); - if (funcdef->getOperator() == no_funcdef && funcdef->queryChild(0)->getOperator() == no_outofline) + IHqlExpression * body = funcdef->queryChild(0); + if ((funcdef->getOperator() == no_funcdef) && (body->getOperator() == no_outofline)) + { infoFlags2 |= HEF2containsCall; + IHqlExpression * bodycode = body->queryChild(0); + if (bodycode->getOperator() == no_cppbody) + { + if (bodycode->queryProperty(actionAtom)) + infoFlags |= HEFvolatile; + } + } else infoFlags2 |= (HEF2containsCall|HEF2containsDelayedCall); break; @@ -3429,6 +3438,12 @@ void CHqlExpression::updateFlagsAfterOperands() infoFlags |= HEFvolatile; break; } + case no_cppbody: + { + if (queryProperty(actionAtom)) + infoFlags |= HEFvolatile; + break; + } } #ifdef VERIFY_EXPR_INTEGRITY diff --git a/ecl/hql/hqlgram2.cpp b/ecl/hql/hqlgram2.cpp index 6e29c5137c0..a7f73190895 100644 --- a/ecl/hql/hqlgram2.cpp +++ b/ecl/hql/hqlgram2.cpp @@ -838,7 +838,8 @@ IHqlExpression * HqlGram::convertToOutOfLineFunction(const ECLlocation & errpos, IHqlExpression * HqlGram::processCppBody(const attribute & errpos, IHqlExpression * cpp) { HqlExprArray args; - args.append(*LINK(cpp)); + cpp->unwindList(args, no_comma); + Linked type = current_type; if (!type) type.setown(makeVoidType()); @@ -847,7 +848,7 @@ IHqlExpression * HqlGram::processCppBody(const attribute & errpos, IHqlExpressio OwnedHqlExpr result; if (record) { - args.append(*LINK(record)); + args.add(*LINK(record),1); if (hasLinkCountedModifier(type)) args.append(*getLinkCountedAttr()); if (hasStreamedModifier(type)) diff --git a/ecl/hql/hqllex.l b/ecl/hql/hqllex.l index 4f7a15937cd..91417c152b4 100644 --- a/ecl/hql/hqllex.l +++ b/ecl/hql/hqllex.l @@ -1478,7 +1478,9 @@ FUNCTIONMACRO|MACRO { lexer->yyPosition -= delta; lexer->yyColumn -= delta; OwnedHqlExpr cppText = createConstant(createStringValue(lexer->yyBuffer+startpos, len)); - returnToken.setExpr(createLocationAnnotation(cppText.getClear(), returnToken.pos)); + OwnedHqlExpr annotated = createLocationAnnotation(cppText.getClear(), returnToken.pos); + OwnedHqlExpr options = extractCppBodyAttrs(len, lexer->yyBuffer+startpos); + returnToken.setExpr(createComma(annotated.getClear(), options.getClear())); return CPPBODY; } [^\n]+ { updatepos1; } diff --git a/ecl/hql/hqlutil.cpp b/ecl/hql/hqlutil.cpp index a8bcfc88002..e886e088216 100644 --- a/ecl/hql/hqlutil.cpp +++ b/ecl/hql/hqlutil.cpp @@ -4767,13 +4767,53 @@ bool isConstantDataset(IHqlExpression * expr) inline bool iseol(char c) { return c == '\r' || c == '\n'; } -#define MATCHOPTION(len, text) (((end - start) == len) && (memicmp(buffer+start, text, len) == 0)) +static unsigned skipSpace(unsigned start, unsigned len, const char * buffer) +{ + while (start < len && isspace((byte)buffer[start])) + start++; + return start; +} + +static unsigned trimSpace(unsigned len, const char * buffer) +{ + while (len && isspace((byte)buffer[len-1])) + len--; + return len; +} -IHqlExpression * extractCppBodyAttrs(unsigned len, const char * buffer) +static void stripQuotes(unsigned & start, unsigned & end, const char * buffer) +{ + if (end - start >= 2) + { + if (buffer[start] == '\'' && buffer[end-1] == '\'') + { + start++; + end--; + } + } +} + +static bool matchOption(unsigned & cur, unsigned max, const char * buffer, unsigned lenMatch, const char * match) +{ + if (cur + lenMatch > max) + return false; + if (memicmp(buffer+cur, match, lenMatch) != 0) + return false; + if (cur + lenMatch < max) + { + if (isalnum(buffer[cur+lenMatch])) + return false; + } + cur = skipSpace(cur+lenMatch, max, buffer); + return true; +} + + +IHqlExpression * extractCppBodyAttrs(unsigned lenBuffer, const char * buffer) { OwnedHqlExpr attrs; unsigned prev = '\n'; - for (unsigned i=0; i < len; i++) + for (unsigned i=0; i < lenBuffer; i++) { char next = buffer[i]; switch (next) @@ -4784,20 +4824,32 @@ IHqlExpression * extractCppBodyAttrs(unsigned len, const char * buffer) case '#': if (prev == '\n') { - if ((i + 1 + 6 < len) && memicmp(buffer+i+1, "option", 6) == 0) + if ((i + 1 + 6 < lenBuffer) && memicmp(buffer+i+1, "option", 6) == 0) { - unsigned start = i+1+6; - while (start < len && isspace((byte)buffer[start])) - start++; + unsigned start = skipSpace(i+1+6, lenBuffer, buffer); unsigned end = start; - while (end < len && !iseol((byte)buffer[end])) + while (end < lenBuffer && !iseol((byte)buffer[end])) end++; - if (MATCHOPTION(4, "pure")) + end = trimSpace(end, buffer); + if (matchOption(start, lenBuffer, buffer, 4, "pure")) attrs.setown(createComma(attrs.getClear(), createAttribute(pureAtom))); - else if (MATCHOPTION(4, "once")) + else if (matchOption(start, lenBuffer, buffer, 4, "once")) attrs.setown(createComma(attrs.getClear(), createAttribute(onceAtom))); - else if (MATCHOPTION(6, "action")) + else if (matchOption(start, lenBuffer, buffer, 6, "action")) attrs.setown(createComma(attrs.getClear(), createAttribute(actionAtom))); + else if (matchOption(start, lenBuffer, buffer, 7, "library")) + { + stripQuotes(start, end, buffer); + Owned restOfLine = createUtf8Value(end-start, buffer+start, makeUtf8Type(UNKNOWN_LENGTH, NULL)); + OwnedHqlExpr arg = createConstant(restOfLine.getClear()); + attrs.setown(createComma(attrs.getClear(), createAttribute(libraryAtom, arg.getClear()))); + } + else if (matchOption(start, lenBuffer, buffer, 4, "link")) + { + Owned restOfLine = createUtf8Value(end-start, buffer+start, makeUtf8Type(UNKNOWN_LENGTH, NULL)); + OwnedHqlExpr arg = createConstant(restOfLine.getClear()); + attrs.setown(createComma(attrs.getClear(), createAttribute(linkAtom, arg.getClear()))); + } } } //fallthrough diff --git a/ecl/hqlcpp/hqlcpp.cpp b/ecl/hqlcpp/hqlcpp.cpp index 8633fc1b92c..2998e48312e 100644 --- a/ecl/hqlcpp/hqlcpp.cpp +++ b/ecl/hqlcpp/hqlcpp.cpp @@ -7115,13 +7115,37 @@ void HqlCppTranslator::doBuildAssignToXml(BuildCtx & ctx, const CHqlBoundTarget //--------------------------------------------------------------------------- +void HqlCppTranslator::processCppBodyDirectives(IHqlExpression * expr) +{ + ForEachChild(i, expr) + { + IHqlExpression * cur = expr->queryChild(i); + if (cur->isAttribute()) + { + _ATOM name = cur->queryName(); + if (name == linkAtom) + { + } + else if (name == libraryAtom) + { + StringBuffer libraryName; + getStringValue(libraryName, cur->queryChild(0)); + if (libraryName.length()) + useLibrary(libraryName.str()); + } + } + } +} + void HqlCppTranslator::doBuildExprCppBody(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr * tgt) { if (!allowEmbeddedCpp()) throwError(HQLERR_EmbeddedCppNotAllowed); + processCppBodyDirectives(expr); StringBuffer text; expr->queryChild(0)->queryValue()->getStringValue(text); + text.setLength(cleanupEmbeddedCpp(text.length(), (char*)text.str())); OwnedHqlExpr quoted = createQuoted(text.str(), expr->getType()); if (tgt) @@ -11237,6 +11261,7 @@ void HqlCppTranslator::buildFunctionDefinition(IHqlExpression * funcdef) if (!allowEmbeddedCpp()) throwError(HQLERR_EmbeddedCppNotAllowed); + processCppBodyDirectives(bodyCode); IHqlExpression * location = queryLocation(bodyCode); const char * locationFilename = location ? location->querySourcePath()->str() : NULL; unsigned startLine = location ? location->getStartLine() : 0; @@ -11246,7 +11271,7 @@ void HqlCppTranslator::buildFunctionDefinition(IHqlExpression * funcdef) StringBuffer text; cppBody->queryValue()->getStringValue(text); - //remove /r so we don't end up with mixed format end of lines. + //remove #option and /r so we don't end up with mixed format end of lines. text.setLength(cleanupEmbeddedCpp(text.length(), (char*)text.str())); const char * start = text.str(); diff --git a/ecl/hqlcpp/hqlcpp.ipp b/ecl/hqlcpp/hqlcpp.ipp index 2d53b8808d7..b633d8dca7c 100644 --- a/ecl/hqlcpp/hqlcpp.ipp +++ b/ecl/hqlcpp/hqlcpp.ipp @@ -1748,6 +1748,7 @@ protected: IHqlExpression * spotGlobalCSE(IHqlExpression * _expr); void spotGlobalCSE(HqlExprArray & exprs); IHqlExpression * extractGlobalCSE(IHqlExpression * expr); + void processCppBodyDirectives(IHqlExpression * expr); void markThorBoundaries(WorkflowArray & array); diff --git a/ecl/hqlcpp/hqlecl.cpp b/ecl/hqlcpp/hqlecl.cpp index 6fed82482af..70263a209f3 100644 --- a/ecl/hqlcpp/hqlecl.cpp +++ b/ecl/hqlcpp/hqlecl.cpp @@ -37,6 +37,12 @@ #include "workunit.hpp" #include "thorplugin.hpp" +#ifdef _DEBUG +#define IS_DEBUG_BUILD true +#else +#define IS_DEBUG_BUILD false +#endif + #define MAIN_MODULE_TEMPLATE "thortpl.cpp" #define HEADER_TEMPLATE "thortpl.hpp" #define CHILD_MODULE_TEMPLATE "childtpl.cpp" @@ -366,8 +372,9 @@ bool HqlDllGenerator::doCompile(ICppCompiler * compiler) compiler->setMaxCompileThreads(maxThreads); bool debug = wu->getDebugValueBool("debugQuery", false); + bool debugLibrary = debug; // should be wu->getDebugValueBool("debugLibrary", IS_DEBUG_BUILD); change for 3.8 compiler->setDebug(debug); - compiler->setDebugLibrary(debug); + compiler->setDebugLibrary(debugLibrary); if (!debug) { int optimizeLevel = wu->getDebugValueInt("optimizeLevel", targetClusterType == RoxieCluster ? 3 : -1); diff --git a/ecl/regress/cppbody6.ecl b/ecl/regress/cppbody6.ecl new file mode 100644 index 00000000000..9bcccebd2c8 --- /dev/null +++ b/ecl/regress/cppbody6.ecl @@ -0,0 +1,40 @@ +/*############################################################################## + + Copyright (C) 2011 HPCC Systems. + + All rights reserved. This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +############################################################################## */ + + + +integer4 add1(integer4 x, integer4 y) := +BEGINC++ +return x + y; +ENDC++; + +integer4 add2(integer4 x, integer4 y) := +BEGINC++ +#option action +return x + y; +ENDC++; + +integer4 add3(integer4 x, integer4 y) := +BEGINC++ +#option pure +return x + y; +ENDC++; + +output(add1(10,20) * add1(10,20)); +output(add2(10,20) * add2(10,20)); +output(add3(10,20) * add3(10,20)); diff --git a/ecl/regress/cppbody7.ecl b/ecl/regress/cppbody7.ecl new file mode 100644 index 00000000000..092a8ac06b0 --- /dev/null +++ b/ecl/regress/cppbody7.ecl @@ -0,0 +1,40 @@ +/*############################################################################## + + Copyright (C) 2011 HPCC Systems. + + All rights reserved. This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +############################################################################## */ + + + +integer4 mkRandom1 := +BEGINC++ +rtlRandom() +ENDC++; + +integer4 mkRandom2 := +BEGINC++ +#option pure +rtlRandom() +ENDC++; + +integer4 mkRandom3 := +BEGINC++ +#option action +rtlRandom() +ENDC++; + +output(mkRandom1 * mkRandom1); +output(mkRandom2 * mkRandom2); +output(mkRandom3 * mkRandom3); diff --git a/ecl/regress/cppbody8.ecl b/ecl/regress/cppbody8.ecl new file mode 100644 index 00000000000..b38a01625da --- /dev/null +++ b/ecl/regress/cppbody8.ecl @@ -0,0 +1,27 @@ +/*############################################################################## + + Copyright (C) 2011 HPCC Systems. + + All rights reserved. This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +############################################################################## */ + + + +integer4 add1(integer4 x, integer4 y) := +BEGINC++ +#option library 'MySpecialLibrary' +return x + y; +ENDC++; + +output(add1(10,20) * add1(10,20)); diff --git a/system/jlib/jcomp.cpp b/system/jlib/jcomp.cpp index 383affa7eca..45efd905007 100644 --- a/system/jlib/jcomp.cpp +++ b/system/jlib/jcomp.cpp @@ -442,7 +442,12 @@ bool CppCompiler::compileFile(IThreadPool * pool, const char * filename, Semapho cmdline.append(" ").append(sourceDir); cmdline.append(fullFileName); expandCompileOptions(cmdline); - cmdline.append(" ").append(libraryOptions); + + if (useDebugLibrary) + cmdline.append(" ").append(LIBFLAG_DEBUG[targetCompiler]); + else + cmdline.append(" ").append(LIBFLAG_RELEASE[targetCompiler]); + _addInclude(cmdline, stdIncludes); if (targetCompiler == Vs6CppCompiler) @@ -484,7 +489,19 @@ void CppCompiler::expandCompileOptions(StringBuffer & target) bool CppCompiler::doLink() { StringBuffer cmdline; - cmdline.append(LINK_NAME[targetCompiler]).append(LINK_SEPARATOR[targetCompiler]).append(linkerOptions); + cmdline.append(LINK_NAME[targetCompiler]).append(LINK_SEPARATOR[targetCompiler]); + + cmdline.append(" "); + if (targetDebug) + cmdline.append(createDLL ? DLL_LINK_OPTION_DEBUG[targetCompiler] : EXE_LINK_OPTION_DEBUG[targetCompiler]); + else + cmdline.append(createDLL ? DLL_LINK_OPTION_RELEASE[targetCompiler] : EXE_LINK_OPTION_RELEASE[targetCompiler]); + cmdline.append(" "); + + if (createDLL) + cmdline.append(" ").append(LINK_OPTION_CORE[targetCompiler]); + cmdline.append(stdLibs); + cmdline.append(linkerOptions); ForEachItemIn(i0, allSources) cmdline.append(" ").append("\"").append(targetDir).append(allSources.item(i0)).append(".").append(OBJECT_FILE_EXT[targetCompiler]).append("\""); @@ -562,42 +579,16 @@ void CppCompiler::removeTemporaries() void CppCompiler::setDebug(bool _debug) { targetDebug = _debug; - resetLinkOptions(); } -void CppCompiler::resetLinkOptions() -{ - if (targetDebug) - { - setLinkOptions(createDLL ? DLL_LINK_OPTION_DEBUG[targetCompiler] : EXE_LINK_OPTION_DEBUG[targetCompiler]); - } - else - { - setLinkOptions(createDLL ? DLL_LINK_OPTION_RELEASE[targetCompiler] : EXE_LINK_OPTION_RELEASE[targetCompiler]); - } -} - - void CppCompiler::setDebugLibrary(bool debug) { - if (debug) - libraryOptions.set(LIBFLAG_DEBUG[targetCompiler]); - else - libraryOptions.set(LIBFLAG_RELEASE[targetCompiler]); -} - -void CppCompiler::setLinkOptions(const char * option) -{ - linkerOptions.clear().append(" ").append(option).append(" "); - if (createDLL) - linkerOptions.append(" ").append(LINK_OPTION_CORE[targetCompiler]); - linkerOptions.append(stdLibs); + useDebugLibrary = debug; } void CppCompiler::setCreateExe(bool _createExe) { createDLL = !_createExe; - resetLinkOptions(); } diff --git a/system/jlib/jcomp.hpp b/system/jlib/jcomp.hpp index 8691fa67f0e..75bf70905da 100644 --- a/system/jlib/jcomp.hpp +++ b/system/jlib/jcomp.hpp @@ -55,7 +55,6 @@ interface ICppCompiler : public IInterface virtual bool compile() = 0; virtual void setDebug(bool _debug) = 0; virtual void setDebugLibrary(bool _debug) = 0; - virtual void setLinkOptions(const char * option) = 0; virtual void setOnlyCompile(bool _onlyCompile) = 0; virtual void setCreateExe(bool _createExe) = 0; virtual void setOptimizeLevel(unsigned level) = 0; diff --git a/system/jlib/jcomp.ipp b/system/jlib/jcomp.ipp index 38cff3378ff..d44c4fae62b 100644 --- a/system/jlib/jcomp.ipp +++ b/system/jlib/jcomp.ipp @@ -39,7 +39,6 @@ public: virtual bool compile(); virtual void setDebug(bool _debug); virtual void setDebugLibrary(bool _debug); - virtual void setLinkOptions(const char * option); virtual void setOnlyCompile(bool _onlyCompile) { onlyCompile = _onlyCompile; } virtual void setCreateExe(bool _createExe); virtual void setOptimizeLevel(unsigned level); @@ -55,7 +54,6 @@ protected: void expandRootDirectory(StringBuffer & expanded, StringBuffer & in); StringBuffer & getObjectName(StringBuffer & out, const char * filename); void removeTemporaries(); - void resetLinkOptions(); bool compileFile(IThreadPool * pool, const char * filename, Semaphore & finishedCompiling); bool doLink(); void writeLogFile(const char* filepath, StringBuffer& log); @@ -65,7 +63,6 @@ public: protected: StringBuffer compilerOptions; - StringAttr libraryOptions; StringBuffer linkerOptions; StringBuffer linkerLibraries; StringAttr sourceDir; @@ -78,6 +75,7 @@ protected: bool onlyCompile; bool createDLL; bool targetDebug; + bool useDebugLibrary; bool verbose; void _addInclude(StringBuffer &s, const char *paths); bool saveTemps;