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,
127 allow_undefined_symbols=False,
129 '''define a Samba library'''
132 SET_TARGET_TYPE(bld, libname, 'DISABLED')
135 source = bld.EXPAND_VARIABLES(source, vars=vars)
137 source = bld.SUBDIR(subdir, source)
139 # remember empty libraries, so we can strip the dependencies
140 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
141 SET_TARGET_TYPE(bld, libname, 'EMPTY')
144 if BUILTIN_LIBRARY(bld, libname):
147 obj_target = libname + '.objlist'
149 if group == 'libraries':
150 subsystem_group = 'main'
152 subsystem_group = group
154 # first create a target for building the object files for this library
155 # by separating in this way, we avoid recompiling the C files
156 # separately for the install library and the build library
157 bld.SAMBA_SUBSYSTEM(obj_target,
160 public_deps = public_deps,
162 public_headers = public_headers,
163 header_path = header_path,
165 group = subsystem_group,
166 autoproto = autoproto,
167 depends_on = depends_on,
168 hide_symbols = hide_symbols,
169 pyext = pyext or (target_type == "PYTHON"),
170 local_include = local_include)
172 if BUILTIN_LIBRARY(bld, libname):
175 if not SET_TARGET_TYPE(bld, libname, target_type):
178 # the library itself will depend on that object target
179 deps += ' ' + public_deps
181 deps.append(obj_target)
183 realname = bld.map_shlib_extension(realname, python=(target_type=='PYTHON'))
184 link_name = bld.map_shlib_extension(link_name, python=(target_type=='PYTHON'))
186 # we don't want any public libraries without version numbers
187 if not private_library and vnum is None and soname is None and target_type != 'PYTHON' and not realname:
188 raise Utils.WafError("public library '%s' must have a vnum" % libname)
190 if target_type == 'PYTHON' or realname or not private_library:
191 bundled_name = libname.replace('_', '-')
193 bundled_name = PRIVATE_NAME(bld, libname, bundled_extension, private_library)
195 ldflags = TO_LIST(ldflags)
197 features = 'cc cshlib symlink_lib install_lib'
198 if target_type == 'PYTHON':
201 # this is quite strange. we should add pyext feature for pyext
202 # but that breaks the build. This may be a bug in the waf python tool
203 features += ' pyembed'
206 features += ' abi_check'
209 if bld.env.HAVE_LD_VERSION_SCRIPT:
211 version = "%s_%s" % (Utils.g_module.APPNAME, Utils.g_module.VERSION)
213 version = "%s_%s" % (libname, vnum)
217 vscript = "%s.vscript" % libname
218 bld.ABI_VSCRIPT(libname, abi_directory, version, vscript,
220 fullname = bld.env.shlib_PATTERN % bundled_name
221 bld.add_manual_dependency(bld.path.find_or_declare(fullname), bld.path.find_or_declare(vscript))
222 if Options.is_install:
223 # also make the .inst file depend on the vscript
224 instname = bld.env.shlib_PATTERN % (bundled_name + '.inst')
225 bld.add_manual_dependency(bld.path.find_or_declare(instname), bld.path.find_or_declare(vscript))
226 vscript = os.path.join(bld.path.abspath(bld.env), vscript)
228 bld.SET_BUILD_GROUP(group)
232 target = bundled_name,
233 depends_on = depends_on,
234 samba_ldflags = ldflags,
236 samba_includes = includes,
237 version_script = vscript,
238 local_include = local_include,
242 samba_inst_path = install_path,
244 samba_realname = realname,
245 samba_install = install,
246 abi_directory = "%s/%s" % (bld.path.abspath(), abi_directory),
247 abi_match = abi_match,
248 private_library = private_library,
249 grouping_library=grouping_library,
250 allow_undefined_symbols=allow_undefined_symbols
253 if realname and not link_name:
254 link_name = 'shared/%s' % realname
257 t.link_name = link_name
259 if pc_files is not None:
260 bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
262 if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
263 bld.MANPAGES(manpages)
266 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
269 #################################################################
270 def SAMBA_BINARY(bld, binname, source,
280 use_global_deps=True,
292 '''define a Samba binary'''
295 SET_TARGET_TYPE(bld, binname, 'DISABLED')
298 if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
301 features = 'cc cprogram symlink_bin install_bin'
303 features += ' pyembed'
305 obj_target = binname + '.objlist'
307 source = bld.EXPAND_VARIABLES(source, vars=vars)
309 source = bld.SUBDIR(subdir, source)
310 source = unique_list(TO_LIST(source))
312 if group == 'binaries':
313 subsystem_group = 'main'
315 subsystem_group = group
317 # first create a target for building the object files for this binary
318 # by separating in this way, we avoid recompiling the C files
319 # separately for the install binary and the build binary
320 bld.SAMBA_SUBSYSTEM(obj_target,
325 group = subsystem_group,
326 autoproto = autoproto,
327 subsystem_name = subsystem_name,
328 local_include = local_include,
329 use_hostcc = use_hostcc,
331 use_global_deps= use_global_deps)
333 bld.SET_BUILD_GROUP(group)
335 # the binary itself will depend on that object target
337 deps.append(obj_target)
344 samba_includes = includes,
345 local_include = local_include,
346 samba_modules = modules,
348 samba_subsystem= subsystem_name,
350 samba_inst_path= install_path,
351 samba_install = install,
352 samba_ldflags = TO_LIST(ldflags)
355 if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
356 bld.MANPAGES(manpages)
358 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
361 #################################################################
362 def SAMBA_MODULE(bld, modname, source,
367 module_init_name='samba_init_module',
369 autoproto_extra_source='',
371 internal_module=True,
377 allow_undefined_symbols=False
379 '''define a Samba module.'''
381 source = bld.EXPAND_VARIABLES(source, vars=vars)
383 source = bld.SUBDIR(subdir, source)
385 if internal_module or BUILTIN_LIBRARY(bld, modname):
386 bld.SAMBA_SUBSYSTEM(modname, source,
390 autoproto_extra_source=autoproto_extra_source,
392 local_include=local_include,
395 bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
399 SET_TARGET_TYPE(bld, modname, 'DISABLED')
402 obj_target = modname + '.objlist'
405 if subsystem is not None:
406 deps += ' ' + subsystem
407 while realname.startswith("lib"+subsystem+"_"):
408 realname = realname[len("lib"+subsystem+"_"):]
409 while realname.startswith(subsystem+"_"):
410 realname = realname[len(subsystem+"_"):]
412 realname = bld.make_libname(realname)
413 while realname.startswith("lib"):
414 realname = realname[len("lib"):]
416 build_link_name = "modules/%s/%s" % (subsystem, realname)
419 cflags += " -D%s=%s" % (init_function, module_init_name)
421 bld.SAMBA_LIBRARY(modname,
427 autoproto = autoproto,
428 local_include=local_include,
430 link_name=build_link_name,
431 install_path="${MODULESDIR}/%s" % subsystem,
433 allow_undefined_symbols=allow_undefined_symbols
437 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
440 #################################################################
441 def SAMBA_SUBSYSTEM(bld, modname, source,
450 init_function_sentinal=None,
452 autoproto_extra_source='',
455 local_include_first=True,
459 use_global_deps=True,
464 '''define a Samba subsystem'''
467 SET_TARGET_TYPE(bld, modname, 'DISABLED')
470 # remember empty subsystems, so we can strip the dependencies
471 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
472 SET_TARGET_TYPE(bld, modname, 'EMPTY')
475 if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
478 source = bld.EXPAND_VARIABLES(source, vars=vars)
480 source = bld.SUBDIR(subdir, source)
481 source = unique_list(TO_LIST(source))
483 deps += ' ' + public_deps
485 bld.SET_BUILD_GROUP(group)
495 samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
496 depends_on = depends_on,
497 samba_deps = TO_LIST(deps),
498 samba_includes = includes,
499 local_include = local_include,
500 local_include_first = local_include_first,
501 samba_subsystem= subsystem_name,
502 samba_use_hostcc = use_hostcc,
503 samba_use_global_deps = use_global_deps
506 if cflags_end is not None:
507 t.samba_cflags.extend(TO_LIST(cflags_end))
509 if autoproto is not None:
510 bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
511 if public_headers is not None:
512 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
516 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
519 def SAMBA_GENERATOR(bld, name, rule, source='', target='',
520 group='generators', enabled=True,
525 '''A generic source generator target'''
527 if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
533 bld.SET_BUILD_GROUP(group)
536 source=bld.EXPAND_VARIABLES(source, vars=vars),
538 shell=isinstance(rule, str),
542 samba_type='GENERATOR',
543 dep_vars = [rule] + (vars or []),
549 if public_headers is not None:
550 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
552 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
557 def SETUP_BUILD_GROUPS(bld):
558 '''setup build groups used to ensure that the different build
559 phases happen consecutively'''
560 bld.p_ln = bld.srcnode # we do want to see all targets!
561 bld.env['USING_BUILD_GROUPS'] = True
562 bld.add_group('setup')
563 bld.add_group('build_compiler_source')
564 bld.add_group('vscripts')
565 bld.add_group('base_libraries')
566 bld.add_group('generators')
567 bld.add_group('compiler_prototypes')
568 bld.add_group('compiler_libraries')
569 bld.add_group('build_compilers')
570 bld.add_group('build_source')
571 bld.add_group('prototypes')
572 bld.add_group('main')
573 bld.add_group('symbolcheck')
574 bld.add_group('libraries')
575 bld.add_group('binaries')
576 bld.add_group('syslibcheck')
577 bld.add_group('final')
578 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
581 def SET_BUILD_GROUP(bld, group):
582 '''set the current build group'''
583 if not 'USING_BUILD_GROUPS' in bld.env:
586 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
591 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
592 """use timestamps instead of file contents for deps
593 this currently doesn't work"""
594 def h_file(filename):
596 st = os.stat(filename)
597 if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
599 m.update(str(st.st_mtime))
600 m.update(str(st.st_size))
603 Utils.h_file = h_file
607 t = Task.simple_task_type('copy_script', 'rm -f "${LINK_TARGET}" && ln -s "${SRC[0].abspath(env)}" ${LINK_TARGET}',
608 shell=True, color='PINK', ext_in='.bin')
611 @feature('copy_script')
612 @before('apply_link')
613 def copy_script(self):
614 tsk = self.create_task('copy_script', self.allnodes[0])
615 tsk.env.TARGET = self.target
617 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
618 '''used to copy scripts from the source tree into the build directory
619 for use by selftest'''
621 source = bld.path.ant_glob(pattern)
623 bld.SET_BUILD_GROUP('build_source')
624 for s in TO_LIST(source):
626 if installname != None:
628 target = os.path.join(installdir, iname)
629 tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
631 t = bld(features='copy_script',
636 t.env.LINK_TARGET = target
638 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
640 def copy_and_fix_python_path(task):
641 pattern='sys.path.insert(0, "bin/python")'
642 if task.env["PYTHONARCHDIR"] in sys.path and task.env["PYTHONDIR"] in sys.path:
644 elif task.env["PYTHONARCHDIR"] == task.env["PYTHONDIR"]:
645 replacement="""sys.path.insert(0, "%s")""" % task.env["PYTHONDIR"]
647 replacement="""sys.path.insert(0, "%s")
648 sys.path.insert(1, "%s")""" % (task.env["PYTHONARCHDIR"], task.env["PYTHONDIR"])
650 installed_location=task.outputs[0].bldpath(task.env)
651 source_file = open(task.inputs[0].srcpath(task.env))
652 installed_file = open(installed_location, 'w')
653 for line in source_file:
656 newline = line.replace(pattern, replacement)
657 installed_file.write(newline)
658 installed_file.close()
659 os.chmod(installed_location, 0755)
663 def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
664 python_fixup=False, destname=None, base_name=None):
666 destdir = bld.EXPAND_VARIABLES(destdir)
670 destname = os.path.basename(destname)
671 dest = os.path.join(destdir, destname)
673 # fixup the python path it will use to find Samba modules
674 inst_file = file + '.inst'
675 bld.SAMBA_GENERATOR('python_%s' % destname,
676 rule=copy_and_fix_python_path,
681 file = os.path.join(base_name, file)
682 bld.install_as(dest, file, chmod=chmod)
685 def INSTALL_FILES(bld, destdir, files, chmod=MODE_644, flat=False,
686 python_fixup=False, destname=None, base_name=None):
687 '''install a set of files'''
688 for f in TO_LIST(files):
689 install_file(bld, destdir, f, chmod=chmod, flat=flat,
690 python_fixup=python_fixup, destname=destname,
692 Build.BuildContext.INSTALL_FILES = INSTALL_FILES
695 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
696 python_fixup=False, exclude=None, trim_path=None):
697 '''install a set of files matching a wildcard pattern'''
698 files=TO_LIST(bld.path.ant_glob(pattern))
702 files2.append(os_path_relpath(f, trim_path))
707 if fnmatch.fnmatch(f, exclude):
709 INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
710 python_fixup=python_fixup, base_name=trim_path)
711 Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
714 def INSTALL_DIRS(bld, destdir, dirs):
715 '''install a set of directories'''
716 destdir = bld.EXPAND_VARIABLES(destdir)
717 dirs = bld.EXPAND_VARIABLES(dirs)
718 for d in TO_LIST(dirs):
719 bld.install_dir(os.path.join(destdir, d))
720 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
723 re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
724 class header_task(Task.Task):
726 The public headers (the one installed on the system) have both
727 different paths and contents, so the rename is not enough.
729 Intermediate .inst.h files are created because path manipulation
730 may be slow. The substitution is thus performed only once.
735 vars = ['INCLUDEDIR', 'HEADER_DEPS']
738 txt = self.inputs[0].read(self.env)
740 # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
741 txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
743 # use a regexp to substitute the #include lines in the files
744 map = self.generator.bld.hnodemap
745 dirnodes = self.generator.bld.hnodedirs
750 # pokemon headers: gotta catch'em all!
752 if s.startswith('bin/default'):
753 node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
755 Logs.warn('could not find the public header for %r' % s)
759 Logs.warn('could not find the public header replacement for build header %r' % s)
761 # this part is more difficult since the path may be relative to anything
762 for dirnode in dirnodes:
763 node = dirnode.find_resource(s)
769 Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
771 Logs.warn('-> could not find the public header for %r' % s)
773 return "#include <%s>" % fin
776 txt = re_header.sub(repl, txt)
778 # and write the output file
781 f = open(self.outputs[0].abspath(self.env), 'w')
787 @TaskGen.feature('pubh')
788 def make_public_headers(self):
790 collect the public headers to process and to install, then
791 create the substitutions (name and contents)
794 if not self.bld.is_install:
795 # install time only (lazy)
799 # hnodedirs: list of folders for searching the headers
800 # hnodemap: node ids and replacement string (node objects are unique)
802 self.bld.hnodedirs.append(self.path)
803 except AttributeError:
804 self.bld.hnodemap = {}
805 self.bld.hnodedirs = [self.bld.srcnode, self.path]
807 for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
808 node = self.bld.srcnode.find_dir(k)
810 self.bld.hnodedirs.append(node)
812 header_path = getattr(self, 'header_path', None) or ''
814 for x in self.to_list(self.headers):
816 # too complicated, but what was the original idea?
817 if isinstance(header_path, list):
819 for (p1, dir) in header_path:
820 lst = self.to_list(p1)
822 if fnmatch.fnmatch(x, p2):
830 inst_path = header_path
834 if x.find(':') != -1:
839 inn = self.path.find_resource(name)
842 raise ValueError("could not find the public header %r in %r" % (name, self.path))
843 out = inn.change_ext('.inst.h')
844 self.create_task('header', inn, out)
850 inst_path = inst_path + '/'
851 inst_path = inst_path + dest
853 self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
855 self.bld.hnodemap[inn.id] = inst_path
857 # create a hash (not md5) to make sure the headers are re-created if something changes
859 lst = list(self.bld.hnodemap.keys())
862 val = hash((val, k, self.bld.hnodemap[k]))
863 self.bld.env.HEADER_DEPS = val
865 def PUBLIC_HEADERS(bld, public_headers, header_path=None):
866 '''install some headers
868 header_path may either be a string that is added to the INCLUDEDIR,
869 or it can be a dictionary of wildcard patterns which map to destination
870 directories relative to INCLUDEDIR
872 bld.SET_BUILD_GROUP('final')
873 ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
875 Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
878 def MANPAGES(bld, manpages):
879 '''build and install manual pages'''
880 bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
881 for m in manpages.split():
883 bld.SAMBA_GENERATOR(m,
887 rule='${XSLTPROC} -o ${TGT} --nonet ${MAN_XSL} ${SRC}'
889 bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
890 Build.BuildContext.MANPAGES = MANPAGES
893 #############################################################
894 # give a nicer display when building different types of files
895 def progress_display(self, msg, fname):
896 col1 = Logs.colors(self.color)
897 col2 = Logs.colors.NORMAL
898 total = self.position[1]
900 fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
901 return fs % (self.position[0], self.position[1], col1, fname, col2)
903 def link_display(self):
904 if Options.options.progress_bar != 0:
905 return Task.Task.old_display(self)
906 fname = self.outputs[0].bldpath(self.env)
907 return progress_display(self, 'Linking', fname)
908 Task.TaskBase.classes['cc_link'].display = link_display
910 def samba_display(self):
911 if Options.options.progress_bar != 0:
912 return Task.Task.old_display(self)
914 targets = LOCAL_CACHE(self, 'TARGET_TYPE')
915 if self.name in targets:
916 target_type = targets[self.name]
917 type_map = { 'GENERATOR' : 'Generating',
918 'PROTOTYPE' : 'Generating'
920 if target_type in type_map:
921 return progress_display(self, type_map[target_type], self.name)
923 if len(self.inputs) == 0:
924 return Task.Task.old_display(self)
926 fname = self.inputs[0].bldpath(self.env)
927 if fname[0:3] == '../':
929 ext_loc = fname.rfind('.')
931 return Task.Task.old_display(self)
932 ext = fname[ext_loc:]
934 ext_map = { '.idl' : 'Compiling IDL',
935 '.et' : 'Compiling ERRTABLE',
936 '.asn1': 'Compiling ASN1',
939 return progress_display(self, ext_map[ext], fname)
940 return Task.Task.old_display(self)
942 Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
943 Task.TaskBase.classes['Task'].display = samba_display
948 def apply_bundle_remove_dynamiclib_patch(self):
949 if self.env['MACBUNDLE'] or getattr(self,'mac_bundle',False):
950 if not getattr(self,'vnum',None):
952 self.env['LINKFLAGS'].remove('-dynamiclib')
953 self.env['LINKFLAGS'].remove('-single_module')