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,
376 allow_undefined_symbols=False
378 '''define a Samba module.'''
380 source = bld.EXPAND_VARIABLES(source, vars=vars)
382 if internal_module or BUILTIN_LIBRARY(bld, modname):
383 bld.SAMBA_SUBSYSTEM(modname, source,
387 autoproto_extra_source=autoproto_extra_source,
389 local_include=local_include,
392 bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
396 SET_TARGET_TYPE(bld, modname, 'DISABLED')
399 obj_target = modname + '.objlist'
402 if subsystem is not None:
403 deps += ' ' + subsystem
404 while realname.startswith("lib"+subsystem+"_"):
405 realname = realname[len("lib"+subsystem+"_"):]
406 while realname.startswith(subsystem+"_"):
407 realname = realname[len(subsystem+"_"):]
409 realname = bld.make_libname(realname)
410 while realname.startswith("lib"):
411 realname = realname[len("lib"):]
413 build_link_name = "modules/%s/%s" % (subsystem, realname)
416 cflags += " -D%s=%s" % (init_function, module_init_name)
418 bld.SAMBA_LIBRARY(modname,
423 autoproto = autoproto,
424 local_include=local_include,
426 link_name=build_link_name,
427 install_path="${MODULESDIR}/%s" % subsystem,
429 allow_undefined_symbols=allow_undefined_symbols
433 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
436 #################################################################
437 def SAMBA_SUBSYSTEM(bld, modname, source,
446 init_function_sentinal=None,
448 autoproto_extra_source='',
451 local_include_first=True,
455 use_global_deps=True,
460 '''define a Samba subsystem'''
463 SET_TARGET_TYPE(bld, modname, 'DISABLED')
466 # remember empty subsystems, so we can strip the dependencies
467 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
468 SET_TARGET_TYPE(bld, modname, 'EMPTY')
471 if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
474 source = bld.EXPAND_VARIABLES(source, vars=vars)
476 source = bld.SUBDIR(subdir, source)
477 source = unique_list(TO_LIST(source))
479 deps += ' ' + public_deps
481 bld.SET_BUILD_GROUP(group)
491 samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
492 depends_on = depends_on,
493 samba_deps = TO_LIST(deps),
494 samba_includes = includes,
495 local_include = local_include,
496 local_include_first = local_include_first,
497 samba_subsystem= subsystem_name,
498 samba_use_hostcc = use_hostcc,
499 samba_use_global_deps = use_global_deps
502 if cflags_end is not None:
503 t.samba_cflags.extend(TO_LIST(cflags_end))
505 if autoproto is not None:
506 bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
507 if public_headers is not None:
508 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
512 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
515 def SAMBA_GENERATOR(bld, name, rule, source='', target='',
516 group='generators', enabled=True,
521 '''A generic source generator target'''
523 if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
529 bld.SET_BUILD_GROUP(group)
532 source=bld.EXPAND_VARIABLES(source, vars=vars),
534 shell=isinstance(rule, str),
538 samba_type='GENERATOR',
539 dep_vars = [rule] + (vars or []),
545 if public_headers is not None:
546 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
548 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
553 def SETUP_BUILD_GROUPS(bld):
554 '''setup build groups used to ensure that the different build
555 phases happen consecutively'''
556 bld.p_ln = bld.srcnode # we do want to see all targets!
557 bld.env['USING_BUILD_GROUPS'] = True
558 bld.add_group('setup')
559 bld.add_group('build_compiler_source')
560 bld.add_group('vscripts')
561 bld.add_group('base_libraries')
562 bld.add_group('generators')
563 bld.add_group('compiler_prototypes')
564 bld.add_group('compiler_libraries')
565 bld.add_group('build_compilers')
566 bld.add_group('build_source')
567 bld.add_group('prototypes')
568 bld.add_group('main')
569 bld.add_group('symbolcheck')
570 bld.add_group('libraries')
571 bld.add_group('binaries')
572 bld.add_group('syslibcheck')
573 bld.add_group('final')
574 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
577 def SET_BUILD_GROUP(bld, group):
578 '''set the current build group'''
579 if not 'USING_BUILD_GROUPS' in bld.env:
582 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
587 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
588 """use timestamps instead of file contents for deps
589 this currently doesn't work"""
590 def h_file(filename):
592 st = os.stat(filename)
593 if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
595 m.update(str(st.st_mtime))
596 m.update(str(st.st_size))
599 Utils.h_file = h_file
603 t = Task.simple_task_type('copy_script', 'rm -f "${LINK_TARGET}" && ln -s "${SRC[0].abspath(env)}" ${LINK_TARGET}',
604 shell=True, color='PINK', ext_in='.bin')
607 @feature('copy_script')
608 @before('apply_link')
609 def copy_script(self):
610 tsk = self.create_task('copy_script', self.allnodes[0])
611 tsk.env.TARGET = self.target
613 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
614 '''used to copy scripts from the source tree into the build directory
615 for use by selftest'''
617 source = bld.path.ant_glob(pattern)
619 bld.SET_BUILD_GROUP('build_source')
620 for s in TO_LIST(source):
622 if installname != None:
624 target = os.path.join(installdir, iname)
625 tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
627 t = bld(features='copy_script',
632 t.env.LINK_TARGET = target
634 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
636 def copy_and_fix_python_path(task):
637 pattern='sys.path.insert(0, "bin/python")'
638 if task.env["PYTHONARCHDIR"] in sys.path and task.env["PYTHONDIR"] in sys.path:
640 elif task.env["PYTHONARCHDIR"] == task.env["PYTHONDIR"]:
641 replacement="""sys.path.insert(0, "%s")""" % task.env["PYTHONDIR"]
643 replacement="""sys.path.insert(0, "%s")
644 sys.path.insert(1, "%s")""" % (task.env["PYTHONARCHDIR"], task.env["PYTHONDIR"])
646 installed_location=task.outputs[0].bldpath(task.env)
647 source_file = open(task.inputs[0].srcpath(task.env))
648 installed_file = open(installed_location, 'w')
649 for line in source_file:
652 newline = line.replace(pattern, replacement)
653 installed_file.write(newline)
654 installed_file.close()
655 os.chmod(installed_location, 0755)
659 def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
660 python_fixup=False, destname=None, base_name=None):
662 destdir = bld.EXPAND_VARIABLES(destdir)
666 destname = os.path.basename(destname)
667 dest = os.path.join(destdir, destname)
669 # fixup the python path it will use to find Samba modules
670 inst_file = file + '.inst'
671 bld.SAMBA_GENERATOR('python_%s' % destname,
672 rule=copy_and_fix_python_path,
677 file = os.path.join(base_name, file)
678 bld.install_as(dest, file, chmod=chmod)
681 def INSTALL_FILES(bld, destdir, files, chmod=MODE_644, flat=False,
682 python_fixup=False, destname=None, base_name=None):
683 '''install a set of files'''
684 for f in TO_LIST(files):
685 install_file(bld, destdir, f, chmod=chmod, flat=flat,
686 python_fixup=python_fixup, destname=destname,
688 Build.BuildContext.INSTALL_FILES = INSTALL_FILES
691 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
692 python_fixup=False, exclude=None, trim_path=None):
693 '''install a set of files matching a wildcard pattern'''
694 files=TO_LIST(bld.path.ant_glob(pattern))
698 files2.append(os_path_relpath(f, trim_path))
703 if fnmatch.fnmatch(f, exclude):
705 INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
706 python_fixup=python_fixup, base_name=trim_path)
707 Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
710 def INSTALL_DIRS(bld, destdir, dirs):
711 '''install a set of directories'''
712 destdir = bld.EXPAND_VARIABLES(destdir)
713 dirs = bld.EXPAND_VARIABLES(dirs)
714 for d in TO_LIST(dirs):
715 bld.install_dir(os.path.join(destdir, d))
716 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
719 re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
720 class header_task(Task.Task):
722 The public headers (the one installed on the system) have both
723 different paths and contents, so the rename is not enough.
725 Intermediate .inst.h files are created because path manipulation
726 may be slow. The substitution is thus performed only once.
731 vars = ['INCLUDEDIR', 'HEADER_DEPS']
734 txt = self.inputs[0].read(self.env)
736 # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
737 txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
739 # use a regexp to substitute the #include lines in the files
740 map = self.generator.bld.hnodemap
741 dirnodes = self.generator.bld.hnodedirs
746 # pokemon headers: gotta catch'em all!
748 if s.startswith('bin/default'):
749 node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
751 Logs.warn('could not find the public header for %r' % s)
755 Logs.warn('could not find the public header replacement for build header %r' % s)
757 # this part is more difficult since the path may be relative to anything
758 for dirnode in dirnodes:
759 node = dirnode.find_resource(s)
765 Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
767 Logs.warn('-> could not find the public header for %r' % s)
769 return "#include <%s>" % fin
772 txt = re_header.sub(repl, txt)
774 # and write the output file
777 f = open(self.outputs[0].abspath(self.env), 'w')
783 @TaskGen.feature('pubh')
784 def make_public_headers(self):
786 collect the public headers to process and to install, then
787 create the substitutions (name and contents)
790 if not self.bld.is_install:
791 # install time only (lazy)
795 # hnodedirs: list of folders for searching the headers
796 # hnodemap: node ids and replacement string (node objects are unique)
798 self.bld.hnodedirs.append(self.path)
799 except AttributeError:
800 self.bld.hnodemap = {}
801 self.bld.hnodedirs = [self.bld.srcnode, self.path]
803 for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
804 node = self.bld.srcnode.find_dir(k)
806 self.bld.hnodedirs.append(node)
808 header_path = getattr(self, 'header_path', None) or ''
810 for x in self.to_list(self.headers):
812 # too complicated, but what was the original idea?
813 if isinstance(header_path, list):
815 for (p1, dir) in header_path:
816 lst = self.to_list(p1)
818 if fnmatch.fnmatch(x, p2):
826 inst_path = header_path
830 if x.find(':') != -1:
835 inn = self.path.find_resource(name)
838 raise ValueError("could not find the public header %r in %r" % (name, self.path))
839 out = inn.change_ext('.inst.h')
840 self.create_task('header', inn, out)
846 inst_path = inst_path + '/'
847 inst_path = inst_path + dest
849 self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
851 self.bld.hnodemap[inn.id] = inst_path
853 # create a hash (not md5) to make sure the headers are re-created if something changes
855 lst = list(self.bld.hnodemap.keys())
858 val = hash((val, k, self.bld.hnodemap[k]))
859 self.bld.env.HEADER_DEPS = val
861 def PUBLIC_HEADERS(bld, public_headers, header_path=None):
862 '''install some headers
864 header_path may either be a string that is added to the INCLUDEDIR,
865 or it can be a dictionary of wildcard patterns which map to destination
866 directories relative to INCLUDEDIR
868 bld.SET_BUILD_GROUP('final')
869 ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
871 Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
874 def MANPAGES(bld, manpages):
875 '''build and install manual pages'''
876 bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
877 for m in manpages.split():
879 bld.SAMBA_GENERATOR(m,
883 rule='${XSLTPROC} -o ${TGT} --nonet ${MAN_XSL} ${SRC}'
885 bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
886 Build.BuildContext.MANPAGES = MANPAGES
889 #############################################################
890 # give a nicer display when building different types of files
891 def progress_display(self, msg, fname):
892 col1 = Logs.colors(self.color)
893 col2 = Logs.colors.NORMAL
894 total = self.position[1]
896 fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
897 return fs % (self.position[0], self.position[1], col1, fname, col2)
899 def link_display(self):
900 if Options.options.progress_bar != 0:
901 return Task.Task.old_display(self)
902 fname = self.outputs[0].bldpath(self.env)
903 return progress_display(self, 'Linking', fname)
904 Task.TaskBase.classes['cc_link'].display = link_display
906 def samba_display(self):
907 if Options.options.progress_bar != 0:
908 return Task.Task.old_display(self)
910 targets = LOCAL_CACHE(self, 'TARGET_TYPE')
911 if self.name in targets:
912 target_type = targets[self.name]
913 type_map = { 'GENERATOR' : 'Generating',
914 'PROTOTYPE' : 'Generating'
916 if target_type in type_map:
917 return progress_display(self, type_map[target_type], self.name)
919 if len(self.inputs) == 0:
920 return Task.Task.old_display(self)
922 fname = self.inputs[0].bldpath(self.env)
923 if fname[0:3] == '../':
925 ext_loc = fname.rfind('.')
927 return Task.Task.old_display(self)
928 ext = fname[ext_loc:]
930 ext_map = { '.idl' : 'Compiling IDL',
931 '.et' : 'Compiling ERRTABLE',
932 '.asn1': 'Compiling ASN1',
935 return progress_display(self, ext_map[ext], fname)
936 return Task.Task.old_display(self)
938 Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
939 Task.TaskBase.classes['Task'].display = samba_display
944 def apply_bundle_remove_dynamiclib_patch(self):
945 if self.env['MACBUNDLE'] or getattr(self,'mac_bundle',False):
946 if not getattr(self,'vnum',None):
948 self.env['LINKFLAGS'].remove('-dynamiclib')
949 self.env['LINKFLAGS'].remove('-single_module')