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, sys, 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_autoproto import *
18 from samba_python import *
19 from samba_deps import *
20 from samba_bundled import *
22 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 < 0x105019:
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 run ./configure and make as usual. That will
50 call the right version of waf.''')
55 def SAMBA_BUILD_ENV(conf):
56 '''create the samba build environment'''
57 conf.env.BUILD_DIRECTORY = conf.blddir
58 mkdir_p(os.path.join(conf.blddir, LIB_PATH))
59 mkdir_p(os.path.join(conf.blddir, LIB_PATH, "private"))
60 mkdir_p(os.path.join(conf.blddir, "modules"))
61 mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
62 # this allows all of the bin/shared and bin/python targets
63 # to be expressed in terms of build directory paths
64 mkdir_p(os.path.join(conf.blddir, 'default'))
65 for p in ['python','shared', 'modules']:
66 link_target = os.path.join(conf.blddir, 'default/' + p)
67 if not os.path.lexists(link_target):
68 os.symlink('../' + p, link_target)
70 # get perl to put the blib files in the build directory
71 blib_bld = os.path.join(conf.blddir, 'default/pidl/blib')
72 blib_src = os.path.join(conf.srcdir, 'pidl/blib')
73 mkdir_p(blib_bld + '/man1')
74 mkdir_p(blib_bld + '/man3')
75 if os.path.islink(blib_src):
77 elif os.path.exists(blib_src):
78 shutil.rmtree(blib_src)
81 def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
82 '''add an init_function to the list for a subsystem'''
83 if init_function is None:
85 bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
86 cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
87 if not subsystem in cache:
89 cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
90 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
94 #################################################################
95 def SAMBA_LIBRARY(bld, libname, source,
106 external_library=False,
118 target_type='LIBRARY',
119 bundled_extension=True,
125 private_library=False,
126 grouping_library=False,
128 '''define a Samba library'''
131 SET_TARGET_TYPE(bld, libname, 'DISABLED')
134 source = bld.EXPAND_VARIABLES(source, vars=vars)
136 source = bld.SUBDIR(subdir, source)
138 # remember empty libraries, so we can strip the dependencies
139 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
140 SET_TARGET_TYPE(bld, libname, 'EMPTY')
143 if BUILTIN_LIBRARY(bld, libname):
146 obj_target = libname + '.objlist'
148 if group == 'libraries':
149 subsystem_group = 'main'
151 subsystem_group = group
153 # first create a target for building the object files for this library
154 # by separating in this way, we avoid recompiling the C files
155 # separately for the install library and the build library
156 bld.SAMBA_SUBSYSTEM(obj_target,
159 public_deps = public_deps,
161 public_headers = public_headers,
162 header_path = header_path,
164 group = subsystem_group,
165 autoproto = autoproto,
166 depends_on = depends_on,
167 hide_symbols = hide_symbols,
168 pyext = pyext or (target_type == "PYTHON"),
169 local_include = local_include)
171 if BUILTIN_LIBRARY(bld, libname):
174 if not SET_TARGET_TYPE(bld, libname, target_type):
177 # the library itself will depend on that object target
178 deps += ' ' + public_deps
180 deps.append(obj_target)
182 realname = bld.map_shlib_extension(realname, python=(target_type=='PYTHON'))
183 link_name = bld.map_shlib_extension(link_name, python=(target_type=='PYTHON'))
185 # we don't want any public libraries without version numbers
186 if not private_library and vnum is None and soname is None and target_type != 'PYTHON' and not realname:
187 raise Utils.WafError("public library '%s' must have a vnum" % libname)
189 if target_type == 'PYTHON' or realname or not private_library:
190 bundled_name = libname.replace('_', '-')
192 bundled_name = PRIVATE_NAME(bld, libname, bundled_extension, private_library)
194 ldflags = TO_LIST(ldflags)
196 features = 'cc cshlib symlink_lib install_lib'
197 if target_type == 'PYTHON':
200 # this is quite strange. we should add pyext feature for pyext
201 # but that breaks the build. This may be a bug in the waf python tool
202 features += ' pyembed'
205 features += ' abi_check'
208 if bld.env.HAVE_LD_VERSION_SCRIPT:
210 version = "%s_%s" % (Utils.g_module.APPNAME, Utils.g_module.VERSION)
212 version = "%s_%s" % (libname, vnum)
216 vscript = "%s.vscript" % libname
217 bld.ABI_VSCRIPT(libname, abi_directory, version, vscript,
219 fullname = bld.env.shlib_PATTERN % bundled_name
220 bld.add_manual_dependency(bld.path.find_or_declare(fullname), bld.path.find_or_declare(vscript))
221 if Options.is_install:
222 # also make the .inst file depend on the vscript
223 instname = bld.env.shlib_PATTERN % (bundled_name + '.inst')
224 bld.add_manual_dependency(bld.path.find_or_declare(instname), bld.path.find_or_declare(vscript))
225 vscript = os.path.join(bld.path.abspath(bld.env), vscript)
227 bld.SET_BUILD_GROUP(group)
231 target = bundled_name,
232 depends_on = depends_on,
233 samba_ldflags = ldflags,
235 samba_includes = includes,
236 version_script = vscript,
237 local_include = local_include,
241 samba_inst_path = install_path,
243 samba_realname = realname,
244 samba_install = install,
245 abi_directory = "%s/%s" % (bld.path.abspath(), abi_directory),
246 abi_match = abi_match,
247 private_library = private_library,
248 grouping_library=grouping_library
251 if realname and not link_name:
252 link_name = 'shared/%s' % realname
255 t.link_name = link_name
257 if pc_files is not None:
258 bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
260 if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
261 bld.MANPAGES(manpages)
264 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
267 #################################################################
268 def SAMBA_BINARY(bld, binname, source,
278 use_global_deps=True,
290 '''define a Samba binary'''
293 SET_TARGET_TYPE(bld, binname, 'DISABLED')
296 if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
299 features = 'cc cprogram symlink_bin install_bin'
301 features += ' pyembed'
303 obj_target = binname + '.objlist'
305 source = bld.EXPAND_VARIABLES(source, vars=vars)
307 source = bld.SUBDIR(subdir, source)
308 source = unique_list(TO_LIST(source))
310 if group == 'binaries':
311 subsystem_group = 'main'
313 subsystem_group = group
315 # first create a target for building the object files for this binary
316 # by separating in this way, we avoid recompiling the C files
317 # separately for the install binary and the build binary
318 bld.SAMBA_SUBSYSTEM(obj_target,
323 group = subsystem_group,
324 autoproto = autoproto,
325 subsystem_name = subsystem_name,
326 local_include = local_include,
327 use_hostcc = use_hostcc,
329 use_global_deps= use_global_deps)
331 bld.SET_BUILD_GROUP(group)
333 # the binary itself will depend on that object target
335 deps.append(obj_target)
342 samba_includes = includes,
343 local_include = local_include,
344 samba_modules = modules,
346 samba_subsystem= subsystem_name,
348 samba_inst_path= install_path,
349 samba_install = install,
350 samba_ldflags = TO_LIST(ldflags)
353 if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
354 bld.MANPAGES(manpages)
356 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
359 #################################################################
360 def SAMBA_MODULE(bld, modname, source,
365 module_init_name='samba_init_module',
367 autoproto_extra_source='',
369 internal_module=True,
375 '''define a Samba module.'''
377 source = bld.EXPAND_VARIABLES(source, vars=vars)
379 if internal_module or BUILTIN_LIBRARY(bld, modname):
380 bld.SAMBA_SUBSYSTEM(modname, source,
384 autoproto_extra_source=autoproto_extra_source,
386 local_include=local_include,
389 bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
393 SET_TARGET_TYPE(bld, modname, 'DISABLED')
396 obj_target = modname + '.objlist'
399 if subsystem is not None:
400 deps += ' ' + subsystem
401 while realname.startswith("lib"+subsystem+"_"):
402 realname = realname[len("lib"+subsystem+"_"):]
403 while realname.startswith(subsystem+"_"):
404 realname = realname[len(subsystem+"_"):]
406 realname = bld.make_libname(realname)
407 while realname.startswith("lib"):
408 realname = realname[len("lib"):]
410 build_link_name = "modules/%s/%s" % (subsystem, realname)
413 cflags += " -D%s=%s" % (init_function, module_init_name)
415 bld.SAMBA_LIBRARY(modname,
420 autoproto = autoproto,
421 local_include=local_include,
423 link_name=build_link_name,
424 install_path="${MODULESDIR}/%s" % subsystem,
429 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
432 #################################################################
433 def SAMBA_SUBSYSTEM(bld, modname, source,
442 init_function_sentinal=None,
444 autoproto_extra_source='',
447 local_include_first=True,
451 use_global_deps=True,
456 '''define a Samba subsystem'''
459 SET_TARGET_TYPE(bld, modname, 'DISABLED')
462 # remember empty subsystems, so we can strip the dependencies
463 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
464 SET_TARGET_TYPE(bld, modname, 'EMPTY')
467 if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
470 source = bld.EXPAND_VARIABLES(source, vars=vars)
472 source = bld.SUBDIR(subdir, source)
473 source = unique_list(TO_LIST(source))
475 deps += ' ' + public_deps
477 bld.SET_BUILD_GROUP(group)
487 samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
488 depends_on = depends_on,
489 samba_deps = TO_LIST(deps),
490 samba_includes = includes,
491 local_include = local_include,
492 local_include_first = local_include_first,
493 samba_subsystem= subsystem_name,
494 samba_use_hostcc = use_hostcc,
495 samba_use_global_deps = use_global_deps
498 if cflags_end is not None:
499 t.samba_cflags.extend(TO_LIST(cflags_end))
501 if autoproto is not None:
502 bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
503 if public_headers is not None:
504 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
508 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
511 def SAMBA_GENERATOR(bld, name, rule, source='', target='',
512 group='generators', enabled=True,
517 '''A generic source generator target'''
519 if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
525 bld.SET_BUILD_GROUP(group)
528 source=bld.EXPAND_VARIABLES(source, vars=vars),
530 shell=isinstance(rule, str),
534 samba_type='GENERATOR',
535 dep_vars = [rule] + (vars or []),
541 if public_headers is not None:
542 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
544 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
549 def SETUP_BUILD_GROUPS(bld):
550 '''setup build groups used to ensure that the different build
551 phases happen consecutively'''
552 bld.p_ln = bld.srcnode # we do want to see all targets!
553 bld.env['USING_BUILD_GROUPS'] = True
554 bld.add_group('setup')
555 bld.add_group('build_compiler_source')
556 bld.add_group('vscripts')
557 bld.add_group('base_libraries')
558 bld.add_group('generators')
559 bld.add_group('compiler_prototypes')
560 bld.add_group('compiler_libraries')
561 bld.add_group('build_compilers')
562 bld.add_group('build_source')
563 bld.add_group('prototypes')
564 bld.add_group('main')
565 bld.add_group('symbolcheck')
566 bld.add_group('libraries')
567 bld.add_group('binaries')
568 bld.add_group('syslibcheck')
569 bld.add_group('final')
570 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
573 def SET_BUILD_GROUP(bld, group):
574 '''set the current build group'''
575 if not 'USING_BUILD_GROUPS' in bld.env:
578 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
583 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
584 """use timestamps instead of file contents for deps
585 this currently doesn't work"""
586 def h_file(filename):
588 st = os.stat(filename)
589 if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
591 m.update(str(st.st_mtime))
592 m.update(str(st.st_size))
595 Utils.h_file = h_file
599 t = Task.simple_task_type('copy_script', 'rm -f "${LINK_TARGET}" && ln -s "${SRC[0].abspath(env)}" ${LINK_TARGET}',
600 shell=True, color='PINK', ext_in='.bin')
603 @feature('copy_script')
604 @before('apply_link')
605 def copy_script(self):
606 tsk = self.create_task('copy_script', self.allnodes[0])
607 tsk.env.TARGET = self.target
609 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
610 '''used to copy scripts from the source tree into the build directory
611 for use by selftest'''
613 source = bld.path.ant_glob(pattern)
615 bld.SET_BUILD_GROUP('build_source')
616 for s in TO_LIST(source):
618 if installname != None:
620 target = os.path.join(installdir, iname)
621 tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
623 t = bld(features='copy_script',
628 t.env.LINK_TARGET = target
630 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
632 def copy_and_fix_python_path(task):
633 pattern='sys.path.insert(0, "bin/python")'
634 if task.env["PYTHONARCHDIR"] in sys.path and task.env["PYTHONDIR"] in sys.path:
636 elif task.env["PYTHONARCHDIR"] == task.env["PYTHONDIR"]:
637 replacement="""sys.path.insert(0, "%s")""" % task.env["PYTHONDIR"]
639 replacement="""sys.path.insert(0, "%s")
640 sys.path.insert(1, "%s")""" % (task.env["PYTHONARCHDIR"], task.env["PYTHONDIR"])
642 installed_location=task.outputs[0].bldpath(task.env)
643 source_file = open(task.inputs[0].srcpath(task.env))
644 installed_file = open(installed_location, 'w')
645 for line in source_file:
648 newline = line.replace(pattern, replacement)
649 installed_file.write(newline)
650 installed_file.close()
651 os.chmod(installed_location, 0755)
655 def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
656 python_fixup=False, destname=None, base_name=None):
658 destdir = bld.EXPAND_VARIABLES(destdir)
662 destname = os.path.basename(destname)
663 dest = os.path.join(destdir, destname)
665 # fixup the python path it will use to find Samba modules
666 inst_file = file + '.inst'
667 bld.SAMBA_GENERATOR('python_%s' % destname,
668 rule=copy_and_fix_python_path,
673 file = os.path.join(base_name, file)
674 bld.install_as(dest, file, chmod=chmod)
677 def INSTALL_FILES(bld, destdir, files, chmod=MODE_644, flat=False,
678 python_fixup=False, destname=None, base_name=None):
679 '''install a set of files'''
680 for f in TO_LIST(files):
681 install_file(bld, destdir, f, chmod=chmod, flat=flat,
682 python_fixup=python_fixup, destname=destname,
684 Build.BuildContext.INSTALL_FILES = INSTALL_FILES
687 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
688 python_fixup=False, exclude=None, trim_path=None):
689 '''install a set of files matching a wildcard pattern'''
690 files=TO_LIST(bld.path.ant_glob(pattern))
694 files2.append(os_path_relpath(f, trim_path))
699 if fnmatch.fnmatch(f, exclude):
701 INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
702 python_fixup=python_fixup, base_name=trim_path)
703 Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
706 def INSTALL_DIRS(bld, destdir, dirs):
707 '''install a set of directories'''
708 destdir = bld.EXPAND_VARIABLES(destdir)
709 dirs = bld.EXPAND_VARIABLES(dirs)
710 for d in TO_LIST(dirs):
711 bld.install_dir(os.path.join(destdir, d))
712 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
715 re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
716 class header_task(Task.Task):
718 The public headers (the one installed on the system) have both
719 different paths and contents, so the rename is not enough.
721 Intermediate .inst.h files are created because path manipulation
722 may be slow. The substitution is thus performed only once.
727 vars = ['INCLUDEDIR', 'HEADER_DEPS']
730 txt = self.inputs[0].read(self.env)
732 # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
733 txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
735 # use a regexp to substitute the #include lines in the files
736 map = self.generator.bld.hnodemap
737 dirnodes = self.generator.bld.hnodedirs
742 # pokemon headers: gotta catch'em all!
744 if s.startswith('bin/default'):
745 node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
747 Logs.warn('could not find the public header for %r' % s)
751 Logs.warn('could not find the public header replacement for build header %r' % s)
753 # this part is more difficult since the path may be relative to anything
754 for dirnode in dirnodes:
755 node = dirnode.find_resource(s)
761 Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
763 Logs.warn('-> could not find the public header for %r' % s)
765 return "#include <%s>" % fin
768 txt = re_header.sub(repl, txt)
770 # and write the output file
773 f = open(self.outputs[0].abspath(self.env), 'w')
779 @TaskGen.feature('pubh')
780 def make_public_headers(self):
782 collect the public headers to process and to install, then
783 create the substitutions (name and contents)
786 if not self.bld.is_install:
787 # install time only (lazy)
791 # hnodedirs: list of folders for searching the headers
792 # hnodemap: node ids and replacement string (node objects are unique)
794 self.bld.hnodedirs.append(self.path)
795 except AttributeError:
796 self.bld.hnodemap = {}
797 self.bld.hnodedirs = [self.bld.srcnode, self.path]
799 for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
800 node = self.bld.srcnode.find_dir(k)
802 self.bld.hnodedirs.append(node)
804 header_path = getattr(self, 'header_path', None) or ''
806 for x in self.to_list(self.headers):
808 # too complicated, but what was the original idea?
809 if isinstance(header_path, list):
811 for (p1, dir) in header_path:
812 lst = self.to_list(p1)
814 if fnmatch.fnmatch(x, p2):
822 inst_path = header_path
826 if x.find(':') != -1:
831 inn = self.path.find_resource(name)
834 raise ValueError("could not find the public header %r in %r" % (name, self.path))
835 out = inn.change_ext('.inst.h')
836 self.create_task('header', inn, out)
842 inst_path = inst_path + '/'
843 inst_path = inst_path + dest
845 self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
847 self.bld.hnodemap[inn.id] = inst_path
849 # create a hash (not md5) to make sure the headers are re-created if something changes
851 lst = list(self.bld.hnodemap.keys())
854 val = hash((val, k, self.bld.hnodemap[k]))
855 self.bld.env.HEADER_DEPS = val
857 def PUBLIC_HEADERS(bld, public_headers, header_path=None):
858 '''install some headers
860 header_path may either be a string that is added to the INCLUDEDIR,
861 or it can be a dictionary of wildcard patterns which map to destination
862 directories relative to INCLUDEDIR
864 bld.SET_BUILD_GROUP('final')
865 ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
867 Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
870 def MANPAGES(bld, manpages):
871 '''build and install manual pages'''
872 bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
873 for m in manpages.split():
875 bld.SAMBA_GENERATOR(m,
879 rule='${XSLTPROC} -o ${TGT} --nonet ${MAN_XSL} ${SRC}'
881 bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
882 Build.BuildContext.MANPAGES = MANPAGES
885 #############################################################
886 # give a nicer display when building different types of files
887 def progress_display(self, msg, fname):
888 col1 = Logs.colors(self.color)
889 col2 = Logs.colors.NORMAL
890 total = self.position[1]
892 fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
893 return fs % (self.position[0], self.position[1], col1, fname, col2)
895 def link_display(self):
896 if Options.options.progress_bar != 0:
897 return Task.Task.old_display(self)
898 fname = self.outputs[0].bldpath(self.env)
899 return progress_display(self, 'Linking', fname)
900 Task.TaskBase.classes['cc_link'].display = link_display
902 def samba_display(self):
903 if Options.options.progress_bar != 0:
904 return Task.Task.old_display(self)
906 targets = LOCAL_CACHE(self, 'TARGET_TYPE')
907 if self.name in targets:
908 target_type = targets[self.name]
909 type_map = { 'GENERATOR' : 'Generating',
910 'PROTOTYPE' : 'Generating'
912 if target_type in type_map:
913 return progress_display(self, type_map[target_type], self.name)
915 if len(self.inputs) == 0:
916 return Task.Task.old_display(self)
918 fname = self.inputs[0].bldpath(self.env)
919 if fname[0:3] == '../':
921 ext_loc = fname.rfind('.')
923 return Task.Task.old_display(self)
924 ext = fname[ext_loc:]
926 ext_map = { '.idl' : 'Compiling IDL',
927 '.et' : 'Compiling ERRTABLE',
928 '.asn1': 'Compiling ASN1',
931 return progress_display(self, ext_map[ext], fname)
932 return Task.Task.old_display(self)
934 Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
935 Task.TaskBase.classes['Task'].display = samba_display
940 def apply_bundle_remove_dynamiclib_patch(self):
941 if self.env['MACBUNDLE'] or getattr(self,'mac_bundle',False):
942 if not getattr(self,'vnum',None):
944 self.env['LINKFLAGS'].remove('-dynamiclib')
945 self.env['LINKFLAGS'].remove('-single_module')