1 # a waf tool to add autoconf-like macros to the configure section
2 # and for SAMBA_ macros for building libraries, binaries etc
4 import Build, os, Options, Task, Utils, cc, TaskGen, fnmatch, re, shutil, Logs, Constants
5 from Configure import conf
7 from samba_utils import SUBST_VARS_RECURSIVE
8 TaskGen.task_gen.apply_verif = Utils.nada
10 # bring in the other samba modules
11 from samba_optimisation import *
12 from samba_utils import *
13 from samba_version import *
14 from samba_autoconf import *
15 from samba_patterns import *
16 from samba_pidl import *
17 from samba_errtable import *
18 from samba_asn1 import *
19 from samba_autoproto import *
20 from samba_python import *
21 from samba_deps import *
22 from samba_bundled import *
24 import samba_conftests
34 # some systems have broken threading in python
35 if os.environ.get('WAF_NOTHREADS') == '1':
40 os.putenv('PYTHONUNBUFFERED', '1')
43 if Constants.HEXVERSION < 0x105016:
45 Please use the version of waf that comes with Samba, not
46 a system installed version. See http://wiki.samba.org/index.php/Waf
49 Alternatively, please use ./autogen-waf.sh, and then
50 run ./configure and make as usual. That will call the right version of waf.
56 def SAMBA_BUILD_ENV(conf):
57 '''create the samba build environment'''
58 conf.env.BUILD_DIRECTORY = conf.blddir
59 mkdir_p(os.path.join(conf.blddir, LIB_PATH))
60 mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
61 # this allows all of the bin/shared and bin/python targets
62 # to be expressed in terms of build directory paths
63 mkdir_p(os.path.join(conf.blddir, 'default'))
64 for p in ['python','shared']:
65 link_target = os.path.join(conf.blddir, 'default/' + p)
66 if not os.path.lexists(link_target):
67 os.symlink('../' + p, link_target)
69 # get perl to put the blib files in the build directory
70 blib_bld = os.path.join(conf.blddir, 'default/pidl/blib')
71 blib_src = os.path.join(conf.srcdir, 'pidl/blib')
72 mkdir_p(blib_bld + '/man1')
73 mkdir_p(blib_bld + '/man3')
74 if os.path.islink(blib_src):
76 elif os.path.exists(blib_src):
77 shutil.rmtree(blib_src)
80 def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
81 '''add an init_function to the list for a subsystem'''
82 if init_function is None:
84 bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
85 cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
86 if not subsystem in cache:
88 cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
89 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
93 #################################################################
94 def SAMBA_LIBRARY(bld, libname, source,
103 external_library=False,
113 target_type='LIBRARY',
114 bundled_extension=True,
122 '''define a Samba library'''
125 SET_TARGET_TYPE(bld, libname, 'DISABLED')
128 source = bld.EXPAND_VARIABLES(source, vars=vars)
130 # remember empty libraries, so we can strip the dependencies
131 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
132 SET_TARGET_TYPE(bld, libname, 'EMPTY')
135 if target_type != 'PYTHON' and BUILTIN_LIBRARY(bld, libname):
138 obj_target = libname + '.objlist'
140 # first create a target for building the object files for this library
141 # by separating in this way, we avoid recompiling the C files
142 # separately for the install library and the build library
143 bld.SAMBA_SUBSYSTEM(obj_target,
146 public_deps = public_deps,
148 public_headers = public_headers,
149 header_path = header_path,
152 autoproto = autoproto,
153 depends_on = depends_on,
154 needs_python = needs_python,
155 hide_symbols = hide_symbols,
156 local_include = local_include)
158 if libname == obj_target:
161 if not SET_TARGET_TYPE(bld, libname, target_type):
164 # the library itself will depend on that object target
165 deps += ' ' + public_deps
167 deps.append(obj_target)
169 if target_type == 'PYTHON' or realname or not is_bundled:
170 # Sanitize the library name
171 bundled_name = libname.lower().replace('_', '-')
172 while bundled_name.startswith("lib"):
173 bundled_name = bundled_name[3:]
175 bundled_name = BUNDLED_NAME(bld, libname, bundled_extension)
177 features = 'cc cshlib symlink_lib install_lib'
178 if target_type == 'PYTHON':
181 features += ' pyembed'
183 features += ' abi_check'
186 abi_file = os.path.join(bld.curdir, abi_file)
188 bld.SET_BUILD_GROUP(group)
192 target = bundled_name,
193 samba_cflags = CURRENT_CFLAGS(bld, libname, cflags),
194 depends_on = depends_on,
196 samba_includes = includes,
197 local_include = local_include,
200 samba_inst_path = install_path,
202 samba_realname = realname,
203 samba_install = install,
205 abi_match = abi_match,
206 is_bundled = is_bundled
209 if realname and not link_name:
210 link_name = 'shared/%s' % realname
213 t.link_name = link_name
215 if pc_files is not None:
216 bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
218 if manpages is not None and 'XSLTPROC' in bld.env and bld.env['XSLTPROC']:
219 bld.MANPAGES(manpages)
222 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
225 #################################################################
226 def SAMBA_BINARY(bld, binname, source,
236 use_global_deps=True,
247 '''define a Samba binary'''
250 SET_TARGET_TYPE(bld, binname, 'DISABLED')
253 if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
256 features = 'cc cprogram symlink_bin install_bin'
258 features += ' pyembed'
260 obj_target = binname + '.objlist'
262 source = bld.EXPAND_VARIABLES(source, vars=vars)
263 source = unique_list(TO_LIST(source))
265 # first create a target for building the object files for this binary
266 # by separating in this way, we avoid recompiling the C files
267 # separately for the install binary and the build binary
268 bld.SAMBA_SUBSYSTEM(obj_target,
274 autoproto = autoproto,
275 subsystem_name = subsystem_name,
276 needs_python = needs_python,
277 local_include = local_include,
278 use_hostcc = use_hostcc,
279 use_global_deps= use_global_deps)
281 bld.SET_BUILD_GROUP(group)
283 # the binary itself will depend on that object target
285 deps.append(obj_target)
291 samba_cflags = CURRENT_CFLAGS(bld, binname, cflags),
293 samba_includes = includes,
294 local_include = local_include,
295 samba_modules = modules,
297 samba_subsystem= subsystem_name,
299 samba_inst_path= install_path,
300 samba_install = install
303 # setup the subsystem_name as an alias for the real
304 # binary name, so it can be found when expanding
305 # subsystem dependencies
306 if subsystem_name is not None:
307 bld.TARGET_ALIAS(subsystem_name, binname)
309 if manpages is not None and 'XSLTPROC' in bld.env and bld.env['XSLTPROC']:
310 bld.MANPAGES(manpages)
312 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
315 #################################################################
316 def SAMBA_MODULE(bld, modname, source,
322 autoproto_extra_source='',
325 internal_module=True,
329 '''define a Samba module.'''
331 source = bld.EXPAND_VARIABLES(source, vars=vars)
333 if internal_module or BUILTIN_LIBRARY(bld, modname):
334 # treat internal modules as subsystems for now
335 if subsystem is not None:
336 deps += ' ' + subsystem
338 bld.SAMBA_SUBSYSTEM(modname, source,
342 autoproto_extra_source=autoproto_extra_source,
344 local_include=local_include,
347 bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
351 SET_TARGET_TYPE(bld, modname, 'DISABLED')
354 if not SET_TARGET_TYPE(bld, modname, 'MODULE'):
357 obj_target = modname + '.objlist'
359 bld.SAMBA_SUBSYSTEM(obj_target, source,
363 autoproto_extra_source=autoproto_extra_source,
365 local_include=local_include,
369 deps.append(obj_target)
371 if subsystem is not None:
372 deps.append(subsystem)
373 while realname.startswith("lib"+subsystem+"_"):
374 realname = realname[len("lib"+subsystem+"_"):]
375 while realname.startswith(subsystem+"_"):
376 realname = realname[len(subsystem+"_"):]
377 while realname.startswith("lib"):
378 realname = realname[len("lib"):]
380 bld.SET_BUILD_GROUP('main')
382 features = 'cc cshlib install_lib',
386 link_name = "modules/%s/%s.${SHLIBEXT}" % (subsystem, realname),
387 samba_cflags = CURRENT_CFLAGS(bld, modname, cflags),
388 samba_includes = includes,
389 local_include = local_include,
392 samba_inst_path= "${MODULESDIR}/%s" % subsystem,
393 samba_realname = realname+ ".${SHLIBEXT}",
395 samba_install = True,
399 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
402 #################################################################
403 def SAMBA_SUBSYSTEM(bld, modname, source,
412 init_function_sentinal=None,
413 heimdal_autoproto=None,
414 heimdal_autoproto_options=None,
415 heimdal_autoproto_private=None,
417 autoproto_extra_source='',
420 local_include_first=True,
424 use_global_deps=True,
428 '''define a Samba subsystem'''
431 SET_TARGET_TYPE(bld, modname, 'DISABLED')
434 # remember empty subsystems, so we can strip the dependencies
435 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
436 SET_TARGET_TYPE(bld, modname, 'EMPTY')
439 if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
442 source = bld.EXPAND_VARIABLES(source, vars=vars)
443 source = unique_list(TO_LIST(source))
445 deps += ' ' + public_deps
447 bld.SET_BUILD_GROUP(group)
457 samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
458 depends_on = depends_on,
459 samba_deps = TO_LIST(deps),
460 samba_includes = includes,
461 local_include = local_include,
462 local_include_first = local_include_first,
463 samba_subsystem= subsystem_name,
464 samba_use_hostcc = use_hostcc,
465 samba_use_global_deps = use_global_deps
468 if cflags_end is not None:
469 t.samba_cflags.extend(TO_LIST(cflags_end))
471 if heimdal_autoproto is not None:
472 bld.HEIMDAL_AUTOPROTO(heimdal_autoproto, source, options=heimdal_autoproto_options)
473 if heimdal_autoproto_private is not None:
474 bld.HEIMDAL_AUTOPROTO_PRIVATE(heimdal_autoproto_private, source)
475 if autoproto is not None:
476 bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
477 if public_headers is not None:
478 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
482 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
485 def SAMBA_GENERATOR(bld, name, rule, source='', target='',
486 group='generators', enabled=True,
490 '''A generic source generator target'''
492 if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
498 bld.SET_BUILD_GROUP(group)
501 source=bld.EXPAND_VARIABLES(source, vars=vars),
503 shell=isinstance(rule, str),
509 if public_headers is not None:
510 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
512 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
517 def SETUP_BUILD_GROUPS(bld):
518 '''setup build groups used to ensure that the different build
519 phases happen consecutively'''
520 bld.p_ln = bld.srcnode # we do want to see all targets!
521 bld.env['USING_BUILD_GROUPS'] = True
522 bld.add_group('setup')
523 bld.add_group('build_compiler_source')
524 bld.add_group('base_libraries')
525 bld.add_group('generators')
526 bld.add_group('compiler_prototypes')
527 bld.add_group('compiler_libraries')
528 bld.add_group('build_compilers')
529 bld.add_group('build_source')
530 bld.add_group('prototypes')
531 bld.add_group('main')
532 bld.add_group('binaries')
533 bld.add_group('final')
534 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
537 def SET_BUILD_GROUP(bld, group):
538 '''set the current build group'''
539 if not 'USING_BUILD_GROUPS' in bld.env:
542 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
547 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
548 """use timestamps instead of file contents for deps
549 this currently doesn't work"""
550 def h_file(filename):
552 st = os.stat(filename)
553 if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
555 m.update(str(st.st_mtime))
556 m.update(str(st.st_size))
559 Utils.h_file = h_file
563 t = Task.simple_task_type('copy_script', 'rm -f ${LINK_TARGET} && ln -s ${SRC[0].abspath(env)} ${LINK_TARGET}',
564 shell=True, color='PINK', ext_in='.bin')
567 @feature('copy_script')
568 @before('apply_link')
569 def copy_script(self):
570 tsk = self.create_task('copy_script', self.allnodes[0])
571 tsk.env.TARGET = self.target
573 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
574 '''used to copy scripts from the source tree into the build directory
575 for use by selftest'''
577 source = bld.path.ant_glob(pattern)
579 bld.SET_BUILD_GROUP('build_source')
580 for s in TO_LIST(source):
582 if installname != None:
584 target = os.path.join(installdir, iname)
585 tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
587 t = bld(features='copy_script',
592 t.env.LINK_TARGET = target
594 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
597 def install_file(bld, destdir, file, chmod=O644, flat=False,
598 python_fixup=False, destname=None, base_name=None):
600 destdir = bld.EXPAND_VARIABLES(destdir)
604 destname = os.path.basename(destname)
605 dest = os.path.join(destdir, destname)
607 # fixup the python path it will use to find Samba modules
608 inst_file = file + '.inst'
609 bld.SAMBA_GENERATOR('python_%s' % destname,
610 rule="sed 's|\(sys.path.insert.*\)bin/python\(.*\)$|\\1${PYTHONDIR}\\2|g' < ${SRC} > ${TGT}",
615 file = os.path.join(base_name, file)
616 bld.install_as(dest, file, chmod=chmod)
619 def INSTALL_FILES(bld, destdir, files, chmod=O644, flat=False,
620 python_fixup=False, destname=None, base_name=None):
621 '''install a set of files'''
622 for f in TO_LIST(files):
623 install_file(bld, destdir, f, chmod=chmod, flat=flat,
624 python_fixup=python_fixup, destname=destname,
626 Build.BuildContext.INSTALL_FILES = INSTALL_FILES
629 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=O644, flat=False,
630 python_fixup=False, exclude=None, trim_path=None):
631 '''install a set of files matching a wildcard pattern'''
632 files=TO_LIST(bld.path.ant_glob(pattern))
636 files2.append(os_path_relpath(f, trim_path))
641 if fnmatch.fnmatch(f, exclude):
643 INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
644 python_fixup=python_fixup, base_name=trim_path)
645 Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
648 def INSTALL_DIRS(bld, destdir, dirs):
649 '''install a set of directories'''
650 destdir = bld.EXPAND_VARIABLES(destdir)
651 dirs = bld.EXPAND_VARIABLES(dirs)
652 for d in TO_LIST(dirs):
653 bld.install_dir(os.path.join(destdir, d))
654 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
657 re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
658 class header_task(Task.Task):
660 The public headers (the one installed on the system) have both
661 different paths and contents, so the rename is not enough.
663 Intermediate .inst.h files are created because path manipulation
664 may be slow. The substitution is thus performed only once.
669 vars = ['INCLUDEDIR', 'HEADER_DEPS']
672 txt = self.inputs[0].read(self.env)
674 # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
675 txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
677 # use a regexp to substitute the #include lines in the files
678 map = self.generator.bld.hnodemap
679 dirnodes = self.generator.bld.hnodedirs
684 # pokemon headers: gotta catch'em all!
686 if s.startswith('bin/default'):
687 node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
689 Logs.warn('could not find the public header for %r' % s)
693 Logs.warn('could not find the public header replacement for build header %r' % s)
695 # this part is more difficult since the path may be relative to anything
696 for dirnode in dirnodes:
697 node = dirnode.find_resource(s)
703 Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
705 Logs.warn('-> could not find the public header for %r' % s)
707 return "#include <%s>" % fin
710 txt = re_header.sub(repl, txt)
712 # and write the output file
715 f = open(self.outputs[0].abspath(self.env), 'w')
721 @TaskGen.feature('pubh')
722 def make_public_headers(self):
724 collect the public headers to process and to install, then
725 create the substitutions (name and contents)
728 if not self.bld.is_install:
729 # install time only (lazy)
733 # hnodedirs: list of folders for searching the headers
734 # hnodemap: node ids and replacement string (node objects are unique)
736 self.bld.hnodedirs.append(self.path)
737 except AttributeError:
738 self.bld.hnodemap = {}
739 self.bld.hnodedirs = [self.bld.srcnode, self.path]
741 for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
742 node = self.bld.srcnode.find_dir(k)
744 self.bld.hnodedirs.append(node)
746 header_path = getattr(self, 'header_path', None) or ''
748 for x in self.to_list(self.headers):
750 # too complicated, but what was the original idea?
751 if isinstance(header_path, list):
753 for (p1, dir) in header_path:
754 lst = self.to_list(p1)
756 if fnmatch.fnmatch(x, p2):
764 inst_path = header_path
768 if x.find(':') != -1:
773 inn = self.path.find_resource(name)
776 raise ValueError("could not find the public header %r in %r" % (name, self.path))
777 out = inn.change_ext('.inst.h')
778 self.create_task('header', inn, out)
784 inst_path = inst_path + '/'
785 inst_path = inst_path + dest
787 self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
789 self.bld.hnodemap[inn.id] = inst_path
791 # create a hash (not md5) to make sure the headers are re-created if something changes
793 lst = list(self.bld.hnodemap.keys())
796 val = hash((val, k, self.bld.hnodemap[k]))
797 self.bld.env.HEADER_DEPS = val
799 def PUBLIC_HEADERS(bld, public_headers, header_path=None):
800 '''install some headers
802 header_path may either be a string that is added to the INCLUDEDIR,
803 or it can be a dictionary of wildcard patterns which map to destination
804 directories relative to INCLUDEDIR
806 bld.SET_BUILD_GROUP('final')
807 ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
809 Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
812 def subst_at_vars(task):
813 '''substiture @VAR@ style variables in a file'''
814 src = task.inputs[0].srcpath(task.env)
815 tgt = task.outputs[0].bldpath(task.env)
821 a = re.split('(@\w+@)', s)
824 back_sub = [ ('PREFIX', '${prefix}'), ('EXEC_PREFIX', '${exec_prefix}')]
826 if re.match('@\w+@', v):
828 if not vname in task.env and vname.upper() in task.env:
829 vname = vname.upper()
830 if not vname in task.env:
831 Logs.error("Unknown substitution %s in %s" % (v, task.name))
833 v = SUBST_VARS_RECURSIVE(task.env[vname], task.env)
834 # now we back substitute the allowed pc vars
835 for (b, m) in back_sub:
838 if not b in done_var:
839 # we don't want to substitute the first usage
845 contents = ''.join(out)
847 s = f.write(contents)
853 def PKG_CONFIG_FILES(bld, pc_files, vnum=None):
854 '''install some pkg_config pc files'''
855 dest = '${PKGCONFIGDIR}'
856 dest = bld.EXPAND_VARIABLES(dest)
857 for f in TO_LIST(pc_files):
858 base=os.path.basename(f)
859 t = bld.SAMBA_GENERATOR('PKGCONFIG_%s' % base,
864 t.env.PACKAGE_VERSION = vnum
865 INSTALL_FILES(bld, dest, f, flat=True, destname=base)
866 Build.BuildContext.PKG_CONFIG_FILES = PKG_CONFIG_FILES
869 def MANPAGES(bld, manpages):
870 '''build and install manual pages'''
871 # check if we are to skip man pages generation
872 if bld.SKIP_MANPAGES():
874 bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
875 for m in manpages.split():
877 bld.SAMBA_GENERATOR(m,
881 rule='${XSLTPROC} -o ${TGT} ${MAN_XSL} ${SRC}'
883 bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
884 Build.BuildContext.MANPAGES = MANPAGES
886 def SKIP_MANPAGES(bld):
887 '''Determine if we have to skip man pages generation'''
888 # return cached result if we know what to do
889 if 'SKIP_MANPAGES' in bld.env:
890 return bld.env['SKIP_MANPAGES']
891 # check if explicitly prohibit manpages from command line
892 if 'NO_MANPAGES' in bld.env and bld.env['NO_MANPAGES']:
893 Logs.warn('Skipping man pages generation')
894 bld.env['SKIP_MANPAGES'] = True
897 # TODO: check for other conditions
898 # TODO: (Metze suggested --nonet for example)
900 # manpages are allowed by default
901 bld.env['SKIP_MANPAGES'] = False
903 Build.BuildContext.SKIP_MANPAGES = SKIP_MANPAGES
905 #############################################################
906 # give a nicer display when building different types of files
907 def progress_display(self, msg, fname):
908 col1 = Logs.colors(self.color)
909 col2 = Logs.colors.NORMAL
910 total = self.position[1]
912 fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
913 return fs % (self.position[0], self.position[1], col1, fname, col2)
915 def link_display(self):
916 if Options.options.progress_bar != 0:
917 return Task.Task.old_display(self)
918 fname = self.outputs[0].bldpath(self.env)
919 return progress_display(self, 'Linking', fname)
920 Task.TaskBase.classes['cc_link'].display = link_display
922 def samba_display(self):
923 if Options.options.progress_bar != 0:
924 return Task.Task.old_display(self)
926 targets = LOCAL_CACHE(self, 'TARGET_TYPE')
927 if self.name in targets:
928 target_type = targets[self.name]
929 type_map = { 'GENERATOR' : 'Generating',
930 'PROTOTYPE' : 'Generating'
932 if target_type in type_map:
933 return progress_display(self, type_map[target_type], self.name)
935 fname = self.inputs[0].bldpath(self.env)
936 if fname[0:3] == '../':
938 ext_loc = fname.rfind('.')
940 return Task.Task.old_display(self)
941 ext = fname[ext_loc:]
943 ext_map = { '.idl' : 'Compiling IDL',
944 '.et' : 'Compiling ERRTABLE',
945 '.asn1': 'Compiling ASN1',
948 return progress_display(self, ext_map[ext], fname)
949 return Task.Task.old_display(self)
951 Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
952 Task.TaskBase.classes['Task'].display = samba_display