17from SCons.Builder 
import Builder
 
   18from SCons.Scanner.C 
import CScanner
 
   23    re.compile(
r'^#pragma\s+link\s+C\+\+\s+[\w]*\s+([\w]*).*[+-]?\!?;\s*//.*global.*$', re.M)
 
   27    re.compile(
r'^#pragma\s+link\s+C\+\+\s+[\w]*\s+Belle2::.*$', re.M)
 
   31    re.compile(
r'^#pragma\s+link\s+C\+\+\s+[\w]*\s+Belle2::([\w]*::)?([\w]*).*[+-]?\!?;.*$', re.M)
 
   35    re.compile(
r'^#pragma\s+link\s+C\+\+\s+[\w]*\s+Belle2::.*;\s*//.*implicit.*$', re.M)
 
   38def linkdef_emitter(target, source, env):
 
   39    linkdef = source.pop()
 
   41    source_dir = os.path.dirname(str(linkdef))
 
   42    include_dir = source_dir
 
   43    if include_dir.endswith(
'include'):
 
   44        include_dir = os.path.dirname(include_dir)
 
   45    include_dir = os.path.join(env[
'INCDIR'], include_dir)
 
   47    dict_basename = os.path.splitext(str(target[0]))[0]
 
   49    target.append(dict_basename + 
'.rootmap')
 
   51    target.append(dict_basename + 
'_rdict.pcm')
 
   54    contents = linkdef.get_text_contents()
 
   55    for line 
in contents.split(
'\n'):
 
   57        match = linkdef_global.match(line)
 
   59            classname = match.group(1)
 
   60            if classname 
is not None:
 
   61                include_base = classname + 
'.h' 
   62                header_file = os.path.join(source_dir, include_base)
 
   63                if os.path.isfile(header_file):
 
   64                    include_file = os.path.join(include_dir, include_base)
 
   65                    if include_file 
not in source:
 
   66                        source.append(include_file)
 
   68                    print(f
'Cannot find header file for the line "{line}".')
 
   71        if linkdef_everything.search(line) 
is None:
 
   74        match = linkdef_class_re.search(line)
 
   77                f
"{linkdef} contains '{line}' which we couldn't parse. The syntax may be incorrect," 
   78                " or the build system may lack support for the feature you're using.")
 
   80        namespace = match.group(1)  
 
   81        classname = match.group(2)
 
   83            raise RuntimeError(f
"{str(linkdef)} contains '{str(line)}' without class name?")
 
   85        is_implicit = 
not linkdef_implicit.search(line) 
is None 
   89        include_base = classname + 
'.h' 
   90        header_file = os.path.join(source_dir, include_base)
 
   92        if not os.path.isfile(header_file):
 
   95                print(f
"{str(linkdef)} contains '{str(line)}' where we couldn't find a header file. " 
   96                      "If dictionary compilation fails, this might be the reason. " 
   97                      "For classes residing in other directories and already " 
   98                      "included via other link requests, add '// implicit' at " 
   99                      "the end to suppress this message.")
 
  103            include_base = namespace.split(
':')[0] + 
'.h' 
  104        include_file = os.path.join(include_dir, include_base)
 
  105        if include_file 
not in source:
 
  106            source.append(include_file)
 
  109    source.append(linkdef)
 
  110    return (target, source)
 
  115    action=
'rootcling --failOnWarnings -f $TARGET $CLINGFLAGS -rmf "${TARGET.base}.rootmap" -rml lib${ROOTCLING_ROOTMAP_LIB}.so ' 
  116    '$_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES',
 
  117    emitter=linkdef_emitter,
 
  118    source_scanner=CScanner())
 
  119rootcling.action.cmdstr = 
'${ROOTCLINGCOMSTR}' 
  122classversion = Builder(action=
'b2code-classversion-check --error-style gcc $SOURCE && touch $TARGET')
 
  123classversion.action.cmdstr = 
'${CLASSVERSIONCOMSTR}' 
  127    env[
'BUILDERS'][
'RootDict'] = rootcling
 
  128    env[
'BUILDERS'][
'ClassVersionCheck'] = classversion