diff --git a/CMakeLists.txt b/CMakeLists.txt index 8de788a1967b17262318fe9c19fdfb12af72463a..14548ca67e20b55d1594ce2b0400e8d565f3b09c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,8 +133,8 @@ get_property(__clingetcpch GLOBAL PROPERTY CLINGETCPCH) add_custom_command(OUTPUT etc/dictpch/allLinkDefs.h etc/dictpch/allHeaders.h etc/dictpch/allCppflags.txt - COMMAND ${CMAKE_SOURCE_DIR}/build/unix/makepchinput.sh ${CMAKE_SOURCE_DIR} "." ${__clingetcpch} - DEPENDS ${CMAKE_SOURCE_DIR}/build/unix/makepchinput.sh ${__allFiles}) + COMMAND ${CMAKE_SOURCE_DIR}/build/unix/makepchinput.py ${CMAKE_SOURCE_DIR} "." ${__clingetcpch} + DEPENDS ${CMAKE_SOURCE_DIR}/build/unix/makepchinput.py ${__allFiles}) add_custom_command(OUTPUT etc/allDict.cxx.pch COMMAND ${CMAKE_SOURCE_DIR}/etc/dictpch/makepch.sh etc/allDict.cxx.pch -I${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR} diff --git a/build/unix/makepchinput.py b/build/unix/makepchinput.py new file mode 100755 index 0000000000000000000000000000000000000000..2a6677d05c1e4529f557d9287b1726b451d77f85 --- /dev/null +++ b/build/unix/makepchinput.py @@ -0,0 +1,515 @@ +#! /usr/bin/env python +# +# Extract the input needed to build a PCH for the main (enabled) ROOT modules. +# Script takes as argument the source directory path, the set of enabled +# modules and extra headers (from cling) to be included in the PCH. +# +# Copyright (c) 2014 Rene Brun and Fons Rademakers +# Author: Axel Naumann <axel@cern.ch>, 2014-10-16 +# Translated to Python by Danilo Piparo, 2015-04-22 + +import sys +import os +import glob +import shutil +from sets import Set + +#------------------------------------------------------------------------------- +def removeFiles(filesList): + existingFilesList = filter(os.path.exists,filesList) + map(os.unlink, existingFilesList) + +#------------------------------------------------------------------------------- +def removeLeftOvers(): + """ + Remove leftover files from old versions of this script. + """ + filesToRemove = [os.path.join("include","allHeaders.h"), + os.path.join("include","allHeaders.h.pch"), + os.path.join("include","allLinkDef.h"), + "all.h", + "cppflags.txt", + os.path.join("include","allLinkDef.h"), + os.path.join("etc","allDict.cxx"), + os.path.join("etc","allDict.cxx.h")] + removeFiles(filesToRemove) + +#------------------------------------------------------------------------------- +def getParams(): + """ + Extract parameters from the commandline, which looks like + makePCHInput.py ZZZ XXX YYY + """ + argv = sys.argv + rootSrcDir, modules = argv[1:3] + clingetpchList = argv[3:] + return rootSrcDir, modules, clingetpchList + +#------------------------------------------------------------------------------- +def getGuardedStlInclude(headerName): + return '#if __has_include("%s")\n' %headerName +\ + '#include <%s>\n' %headerName +\ + '#endif\n' + +#------------------------------------------------------------------------------- +def getSTLIncludes(): + """ + Here we include the list of c++11 stl headers + From http://en.cppreference.com/w/cpp/header + regex is removed until ROOT-7004 is fixed + """ + stlHeadersList = ("cstdlib", + "csignal", + "csetjmp", + "cstdarg", + "typeinfo", + "typeindex", + "type_traits", + "bitset", + "functional", + "utility", + "ctime", + "chrono", + "cstddef", + "initializer_list", + "tuple", + "new", + "memory", + "scoped_allocator", + "climits", + "cfloat", + "cstdint", + "cinttypes", + "limits", + "exception", + "stdexcept", + "cassert", + "system_error", + "cerrno", + "cctype", + "cwctype", + "cstring", + "cwchar", + "cuchar", + "string", + "array", + "vector", + "deque", + "list", + "forward_list", + "set", + "map", + "unordered_set", + "unordered_map", + "stack", + "queue", + "algorithm", + "iterator", + "cmath", + "complex", + "valarray", + "random", + "numeric", + "ratio", + "cfenv", + "iosfwd", + "ios", + "istream", + "ostream", + "iostream", + "fstream", + "sstream", + "iomanip", + "streambuf", + "cstdio", + "locale", + "clocale", + "codecvt", + "atomic", + "thread", + "mutex", + "future", + "condition_variable", + "ciso646", + "ccomplex", + "ctgmath", + "cstdalign", + "cstdbool") + + allHeadersPartContent = "// STL headers\n" + + for header in stlHeadersList: + allHeadersPartContent += getGuardedStlInclude(header) + + # Special case for regex + allHeadersPartContent += '// treat regex separately\n' +\ + '#if __has_include("regex") && !defined __APPLE__\n' +\ + '#include <regex>\n' +\ + '#endif\n' + + # treat this deprecated headers in a special way + stlDeprecatedHeadersList=["strstream"] + allHeadersPartContent += '// STL Deprecated headers\n' +\ + '#define _BACKWARD_BACKWARD_WARNING_H\n' +\ + "#pragma clang diagnostic push\n" +\ + '#pragma GCC diagnostic ignored "-Wdeprecated"\n' + + for header in stlDeprecatedHeadersList: + allHeadersPartContent += getGuardedStlInclude(header) + + allHeadersPartContent += '#pragma clang diagnostic pop\n' +\ + '#undef _BACKWARD_BACKWARD_WARNING_H\n' + return allHeadersPartContent + +#------------------------------------------------------------------------------- +def getExtraIncludes(headers): + """ + Add include files according to list + """ + allHeadersPartContent="" + for header in headers: + allHeadersPartContent+='#include "%s"\n' %header + return allHeadersPartContent + +#------------------------------------------------------------------------------- +def getDictNames(theDirName): + """ + Get a list of all dictionaries in a directory + """ + #`find $modules -name 'G__*.cxx' 2> /dev/null | grep -v /G__Cling.cxx | grep -v core/metautils/src/G__std_`; do + wildcards = (os.path.join(theDirName , "*", "*", "G__*.cxx"), + os.path.join(theDirName , "*", "G__*.cxx")) + allDictNames = [] + for wildcard in wildcards: + allDictNames += glob.glob(wildcard) + stdDictpattern = os.path.join("core","metautils","src","G__std_") + dictNames = filter (lambda dictName: not ('G__Cling.cxx' in dictName or stdDictpattern in dictName),allDictNames ) + return dictNames + +#------------------------------------------------------------------------------- +def getDirName(dictName): + """ + foo/src/G__PIPPO.cxx --> foo/ + """ + # get rid of the drive on win + dirName = os.path.splitdrive(dictName) + + # foo/src/G__PIPPO.cxx --> foo/src/ + dirName = os.path.split(dictName)[0] + + # foo/src/ --> foo/src + dirName = dirName[:-1] + + # foo/src --> foo/ + return os.path.normpath(os.path.split(dictName)[0]) + +#------------------------------------------------------------------------------- +def isAnyPatternInString(patterns,theString): + """ + Check if any of the patterns is contained in the string + """ + for pattern in patterns: + if pattern in theString: return True + return False + +#------------------------------------------------------------------------------- +def isDirForPCH(dirName): + """ + Check if the directory corresponds to a module whose headers must belong to + the PCH + """ + PCHPatternsWhitelist = ("interpreter/", + "core/", + "io/io", + "net/net", + "math/", + "hist/", + "tree/", + "graf2d", + "graf3d/ftgl", + "graf3d/g3d", + "graf3d/gl", + "gui/gui", + "gui/fitpanel", + "rootx", + "bindings/pyroot", + "roofit/", + "tmva", + "main") + PCHPatternsBlacklist = ("graf2d/qt", + "gui/guihtml", + "gui/guibuilder", + "math/fftw", + "math/foam", + "math/fumili", + "math/mlp", + "math/quadp", + "math/splot", + "math/unuran", + "math/vc", + "math/vdt") + + accepted = isAnyPatternInString(PCHPatternsWhitelist,dirName) and \ + not isAnyPatternInString(PCHPatternsBlacklist,dirName) + + return accepted + +#------------------------------------------------------------------------------- +def getLinesFromDict(marker, dictFileName): + """ + Search for the line marker + in the dictionary and save all lines until the line '0' + Return them as List + """ + selectedLines = [] + ifile = open(dictFileName) + lines = ifile.readlines() + ifile.close() + recording = False + for line in lines: + if marker in line: + recording = True + continue + + if recording and "0" == line[0]: break + + if recording: + selectedLines.append(line[:-1]) + + return selectedLines + +#------------------------------------------------------------------------------- +def getIncludeLinesFromDict(dictFileName): + """ + Search for the headers after the line + 'static const char* headers[]' + Return the code to be added to the allHeaders as string + """ + allHeadersPartContent="" + selectedLines = getLinesFromDict('static const char* headers[]', dictFileName) + allHeadersPartContent += "// %s\n" % dictFileName + for selectedLine in selectedLines: + header = selectedLine[:-1] # remove the "," + allHeadersPartContent += "#include %s\n" %header + return allHeadersPartContent + +#------------------------------------------------------------------------------- +def getIncludePathsFromDict(dictFileName): + """ + Search for the headers after the line + 'static const char* headers[]' + Return them as list + """ + incPathsPart=[] + selectedLines = getLinesFromDict('static const char* includePaths[]', dictFileName) + for selectedLine in selectedLines: + incPath = selectedLine[1:-2] # remove the "," and the two '"' + incPathsPart.append(incPath) + return incPathsPart + +#------------------------------------------------------------------------------- +def getDefUndefLines(dirName): + """ + Add undefines and defines if the directory needs them + """ + allHeadersPartContent="" + if "%sqt" %os.sep in dirName: + allHeadersPartContent += '#ifdef emit\n' +\ + '# undef emit\n' +\ + '#endif\n' +\ + '#ifdef signals\n' +\ + '# undef signals\n' +\ + '#endif\n' + if "%snet%sldap" %(os.sep,os.sep) in dirName: + allHeadersPartContent += '#ifdef Debug\n' +\ + '# undef Debug\n' +\ + '#endif\n' +\ + '#ifdef GSL_SUCCESS\n' +\ + '# undef GSL_SUCCESS\n' +\ + '#endif\n' + return allHeadersPartContent + +#------------------------------------------------------------------------------- +def mkdirIfNotThere(dirName): + if not os.path.exists(dirName): + os.mkdir(dirName) + +#------------------------------------------------------------------------------- +def copyLinkDefs(rootSrcDir, outdir , dirName): + """ + Extract the linkdef files + """ + linkDefPartContent = "" + curDir = os.getcwd() + os.chdir(rootSrcDir) + wildcard = os.path.join(dirName, "inc", "*LinkDef*.h") + linkDefNames = glob.glob(wildcard) + os.chdir(curDir) + for linkDefName in linkDefNames: + linkDefDirName = os.path.basename(linkDefName) + mkdirIfNotThere(os.path.join(outdir,linkDefDirName)) + srcName = os.path.join(rootSrcDir,linkDefName) + destName = os.path.join(outdir,linkDefName) + shutil.copyfile(srcName, destName) + +#------------------------------------------------------------------------------- +def getLocalLinkDefs(rootSrcDir, outdir , dirName): + linkDefPartContent = "" + curDir = os.getcwd() + os.chdir(rootSrcDir) + wildcards = (os.path.join(dirName , "*", "*", "*LinkDef*.h"), + os.path.join(dirName , "*", "*LinkDef*.h")) + linkDefNames = [] + for wildcard in wildcards: + linkDefNames += glob.glob(wildcard) + + # now get the ones in the inc directory + linkDefNames = filter (lambda name: "%sinc%s" %(os.sep,os.sep) in name, linkDefNames) + + for linkDefName in linkDefNames: + fullLinkDefName = os.path.join(outdir,linkDefName) + linkDefPartContent += '#include "%s"\n' %fullLinkDefName + os.chdir(curDir) + return linkDefPartContent + +#------------------------------------------------------------------------------- +def resolveSoftLinks(thePaths): + return map(os.path.realpath,thePaths) + +#------------------------------------------------------------------------------- +def getCppFlags(rootSrcDir,allIncPaths): + """ + Sort, clean, no duplicates + cat $cppflags.tmp | sort | uniq | grep -v $srcdir | grep -v `pwd` > $cppflags + We must resolve softlinks. + returns a string + """ + allHeadersPartContent = "" + filteredIncPaths = sorted(list(set(resolveSoftLinks(allIncPaths)))) + for name in resolveSoftLinks((rootSrcDir,os.getcwd())): + filteredIncPaths = filter (lambda incPath: not name in incPath,filteredIncPaths) + for incPath in filteredIncPaths: + allHeadersPartContent += "-I%s\n" %incPath + return allHeadersPartContent + +#------------------------------------------------------------------------------- +def writeToFile(content, filename): + ofile = open(filename, "w") + ofile.write(content) + ofile.close() + +#------------------------------------------------------------------------------- +def writeFiles(contentFileNamePairs): + for content, filename in contentFileNamePairs: + writeToFile(content, filename) + +#------------------------------------------------------------------------------- +def printModulesMessageOnScreen(selModules): + modulesList = sorted(list(selModules)) + print "\nGenerating PCH for %s\n" %" ".join(modulesList) + +#------------------------------------------------------------------------------- +def makePCHInput(): + """ + Create the input for the pch file, i.e. 3 files: + * etc/dictpch/allLinkDefs.h + * etc/dictpch/allHeaders.h + * etc/dictpch/allCppflags.txt + """ + rootSrcDir, modules, clingetpchList = getParams() + + removeLeftOvers() + + outdir = os.path.join("etc","dictpch") + allHeadersFilename = os.path.join(outdir,"allHeaders.h") + allLinkdefsFilename = os.path.join(outdir,"allLinkDefs.h") + cppFlagsFilename = os.path.join(outdir, "allCppflags.txt") + + mkdirIfNotThere(outdir) + removeFiles((allHeadersFilename,allLinkdefsFilename)) + + allHeadersContent = getSTLIncludes() + allHeadersContent += getExtraIncludes(clingetpchList) + + allLinkdefsContent = "" + + # Loop over the dictionaries, ROOT modules + dictNames = getDictNames(modules) + selModules = Set([]) + allIncPathsList = [] + for dictName in dictNames: + dirName = getDirName(dictName) + if not isDirForPCH(dirName): continue + + selModules.add(dirName) + + allHeadersContent += getIncludeLinesFromDict(dictName) + allIncPathsList += getIncludePathsFromDict(dictName) + + allHeadersContent += getDefUndefLines(dictName) + + allLinkdefsContent += getLocalLinkDefs(rootSrcDir, outdir , dirName) + + copyLinkDefs(rootSrcDir, outdir , dirName) + + cppFlagsContent = getCppFlags(rootSrcDir,allIncPathsList) + + writeFiles(((allHeadersContent, allHeadersFilename), + (allLinkdefsContent, allLinkdefsFilename), + (cppFlagsContent, cppFlagsFilename))) + + + printModulesMessageOnScreen(selModules) + +if __name__ == "__main__": + makePCHInput() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/unix/makepchinput.sh b/build/unix/makepchinput.sh deleted file mode 100755 index 2a75f8f92221e634582b5e22a76a7730a73aaa72..0000000000000000000000000000000000000000 --- a/build/unix/makepchinput.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/sh -# -# Extract the input needed to build a PCH for the main (enabled) ROOT modules. -# Script takes as argument the source directory path, the set of enabled -# modules and extra headers (from cling) to be included in the PCH. -# -# Copyright (c) 2014 Rene Brun and Fons Rademakers -# Author: Axel Naumann <axel@cern.ch>, 2014-10-16 - -srcdir=$1 -shift -modules=$1 -shift - -# Remove leftover files from old versions of this script. -rm -f include/allHeaders.h include/allHeaders.h.pch include/allLinkDef.h all.h cppflags.txt include/allLinkDef.h etc/allDict.cxx etc/allDict.cxx.h - -outdir=etc/dictpch -allheaders=$outdir/allHeaders.h -alllinkdefs=$outdir/allLinkDefs.h -cppflags=$outdir/allCppflags.txt - -mkdir -p $outdir -rm -f $allheaders $alllinkdefs - -# Here we include the list of c++11 stl headers -# From http://en.cppreference.com/w/cpp/header -# regex is removed until ROOT-7004 is fixed -stlHeaders="cstdlib csignal csetjmp cstdarg typeinfo typeindex type_traits bitset functional utility ctime chrono cstddef initializer_list tuple new memory scoped_allocator climits cfloat cstdint cinttypes limits exception stdexcept cassert system_error cerrno cctype cwctype cstring cwchar cuchar string array vector deque list forward_list set map unordered_set unordered_map stack queue algorithm iterator cmath complex valarray random numeric ratio cfenv iosfwd ios istream ostream iostream fstream sstream iomanip streambuf cstdio locale clocale codecvt atomic thread mutex future condition_variable ciso646 ccomplex ctgmath cstdalign cstdbool" - -echo "// STL headers" >> $allheaders -for stlHeader in $stlHeaders; do - echo '#if __has_include("'$stlHeader'")' >> $allheaders - echo '#include <'$stlHeader'>' >> $allheaders - echo '#endif' >> $allheaders -done - -# Special case for regex -echo "// treat regex separately" >> $allheaders -echo '#if __has_include("regex") && !defined __APPLE__' >> $allheaders -echo '#include <regex>' >> $allheaders -echo '#endif' >> $allheaders - -# treat this deprecated headers in a special way -stlDeprecatedHeaders="strstream" -echo "// STL Deprecated headers" >> $allheaders -echo '#pragma clang diagnostic push' >> $allheaders -echo '#pragma GCC diagnostic ignored "-Wdeprecated"' >> $allheaders -for stlHeader in stlDeprecatedHeaders; do - echo '#if __has_include("'$stlHeader'")' >> $allheaders - echo '#include <'$stlHeader'>' >> $allheaders - echo '#endif' >> $allheaders -done -echo '#pragma clang diagnostic pop' >> $allheaders - -while ! [ "x$1" = "x" ]; do - echo '#include "'$1'"' >> $allheaders - shift -done - -for dict in `find $modules -name 'G__*.cxx' 2> /dev/null | grep -v /G__Cling.cxx | grep -v core/metautils/src/G__std_`; do - dirname=`dirname $dict` # to get foo/src - dirname=`echo $dirname | sed -e 's,/src$,,' -e 's,^[.]/,,' ` # to get foo/ - - case $dirname in - graf2d/qt | math/fftw | math/foam | math/fumili | math/mlp | math/quadp | math/splot | math/unuran | math/vc | math/vdt) continue;; - - interpreter/* | core/* | io/io | net/net | math/* | hist/* | tree/* | graf2d/* | graf3d/ftgl | graf3d/g3d | graf3d/gl | gui/gui | gui/fitpanel | rootx | bindings/pyroot | roofit/* | tmva | main) ;; - - *) continue;; - esac - - # Check if selmodules already contains the dirname. - # Happens for instance for math/smatrix with its two (32bit and 64 bit) - # dictionaries. - if ! ( echo $selmodules | grep "$dirname " > /dev/null ); then - selmodules="$selmodules$dirname " - fi - - awk 'BEGIN{START=-1} /includePaths\[\] = {/, /^0$/ { if (START==-1) START=NR; else if ($0 != "0") { sub(/",/,"",$0); sub(/^"/,"-I",$0); print $0 } }' $dict >> $cppflags.tmp - echo "// $dict" >> $allheaders -# awk 'BEGIN{START=-1} /payloadCode =/, /^;$/ { if (START==-1) START=NR; else if ($1 != ";") { code=substr($0,2); sub(/\\n"/,"",code); print code } }' $dict >> $allheaders - awk 'BEGIN{START=-1} /headers\[\] = {/, /^0$/ { if (START==-1) START=NR; else if ($0 != "0") { sub(/,/,"",$0); print "#include",$0 } }' $dict >> $allheaders - - if ! test "$dirname" = "`echo $dirname| sed 's,/qt,,'`"; then - # something qt; undef emit afterwards - cat <<EOF >> $allheaders -#ifdef emit -# undef emit -#endif -#ifdef signals -# undef signals -#endif -EOF - elif ! test "$dirname" = "`echo $dirname| sed 's,net/ldap,,'`"; then - # ldap; undef Debug afterwards - cat <<EOF >> $allheaders -#ifdef Debug -# undef Debug -#endif -#ifdef GSL_SUCCESS -# undef GSL_SUCCESS -#endif -EOF - fi - - for f in `cd $srcdir; find $dirname/inc/ -name '*LinkDef*.h'`; do - echo '#include "'$outdir/$f'"' >> $alllinkdefs - done -done - -# E.g. core's LinkDef includes clib/LinkDef, so just copy all LinkDefs. -for f in `cd $srcdir; find . -name '*LinkDef*.h'`; do - mkdir -p $outdir/`dirname $f` - cp $srcdir/$f $outdir/$f -done - -cat $cppflags.tmp | sort | uniq | grep -v $srcdir | grep -v `pwd` > $cppflags - -echo -echo Generating PCH for ${selmodules} -echo