3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
7 # Thomas Nagy, 2005-2016 (ita)
10 Classes and methods shared by tools providing support for C-like language such
11 as C/C++/D/Assembly/Go (this support module is almost never used alone).
15 from waflib import Task, Utils, Node, Errors, Logs
16 from waflib.TaskGen import after_method, before_method, feature, taskgen_method, extension
17 from waflib.Tools import c_aliases, c_preproc, c_config, c_osx, c_tests
18 from waflib.Configure import conf
20 SYSTEM_LIB_PATHS = ['/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib']
22 USELIB_VARS = Utils.defaultdict(set)
24 Mapping for features to :py:class:`waflib.ConfigSet.ConfigSet` variables. See :py:func:`waflib.Tools.ccroot.propagate_uselib_vars`.
27 USELIB_VARS['c'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CCDEPS', 'CFLAGS', 'ARCH'])
28 USELIB_VARS['cxx'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CXXDEPS', 'CXXFLAGS', 'ARCH'])
29 USELIB_VARS['d'] = set(['INCLUDES', 'DFLAGS'])
30 USELIB_VARS['includes'] = set(['INCLUDES', 'FRAMEWORKPATH', 'ARCH'])
32 USELIB_VARS['cprogram'] = USELIB_VARS['cxxprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH', 'LDFLAGS'])
33 USELIB_VARS['cshlib'] = USELIB_VARS['cxxshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH', 'LDFLAGS'])
34 USELIB_VARS['cstlib'] = USELIB_VARS['cxxstlib'] = set(['ARFLAGS', 'LINKDEPS'])
36 USELIB_VARS['dprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
37 USELIB_VARS['dshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
38 USELIB_VARS['dstlib'] = set(['ARFLAGS', 'LINKDEPS'])
40 USELIB_VARS['asm'] = set(['ASFLAGS'])
42 # =================================================================================================
45 def create_compiled_task(self, name, node):
47 Create the compilation task: c, cxx, asm, etc. The output node is created automatically (object file with a typical **.o** extension).
48 The task is appended to the list *compiled_tasks* which is then used by :py:func:`waflib.Tools.ccroot.apply_link`
50 :param name: name of the task class
52 :param node: the file to compile
53 :type node: :py:class:`waflib.Node.Node`
54 :return: The task created
55 :rtype: :py:class:`waflib.Task.Task`
57 out = '%s.%d.o' % (node.name, self.idx)
58 task = self.create_task(name, node, node.parent.find_or_declare(out))
60 self.compiled_tasks.append(task)
61 except AttributeError:
62 self.compiled_tasks = [task]
66 def to_incnodes(self, inlst):
68 Task generator method provided to convert a list of string/nodes into a list of includes folders.
70 The paths are assumed to be relative to the task generator path, except if they begin by **#**
71 in which case they are searched from the top-level directory (``bld.srcnode``).
72 The folders are simply assumed to be existing.
74 The node objects in the list are returned in the output list. The strings are converted
75 into node objects if possible. The node is searched from the source directory, and if a match is found,
76 the equivalent build directory is created and added to the returned list too. When a folder cannot be found, it is ignored.
78 :param inlst: list of folders
79 :type inlst: space-delimited string or a list of string/nodes
80 :rtype: list of :py:class:`waflib.Node.Node`
81 :return: list of include folders as nodes
85 for x in self.to_list(inlst):
86 if x in seen or not x:
90 # with a real lot of targets, it is sometimes interesting to cache the results below
91 if isinstance(x, Node.Node):
95 lst.append(self.bld.root.make_node(x) or x)
98 p = self.bld.bldnode.make_node(x[1:])
99 v = self.bld.srcnode.make_node(x[1:])
101 p = self.path.get_bld().make_node(x)
102 v = self.path.make_node(x)
103 if p.is_child_of(self.bld.bldnode):
109 @feature('c', 'cxx', 'd', 'asm', 'fc', 'includes')
110 @after_method('propagate_uselib_vars', 'process_source')
111 def apply_incpaths(self):
113 Task generator method that processes the attribute *includes*::
115 tg = bld(features='includes', includes='.')
117 The folders only need to be relative to the current directory, the equivalent build directory is
118 added automatically (for headers created in the build directory). This enable using a build directory
119 or not (``top == out``).
121 This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``,
122 and the list of include paths in ``tg.env.INCLUDES``.
125 lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env.INCLUDES)
126 self.includes_nodes = lst
128 self.env.INCPATHS = [x.path_from(cwd) for x in lst]
130 class link_task(Task.Task):
132 Base class for all link tasks. A task generator is supposed to have at most one link task bound in the attribute *link_task*. See :py:func:`waflib.Tools.ccroot.apply_link`.
134 .. inheritance-diagram:: waflib.Tools.ccroot.stlink_task waflib.Tools.c.cprogram waflib.Tools.c.cshlib waflib.Tools.cxx.cxxstlib waflib.Tools.cxx.cxxprogram waflib.Tools.cxx.cxxshlib waflib.Tools.d.dprogram waflib.Tools.d.dshlib waflib.Tools.d.dstlib waflib.Tools.ccroot.fake_shlib waflib.Tools.ccroot.fake_stlib waflib.Tools.asm.asmprogram waflib.Tools.asm.asmshlib waflib.Tools.asm.asmstlib
139 """Default installation path for the link task outputs, or None to disable"""
142 """Default installation mode for the link task outputs"""
144 def add_target(self, target):
146 Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*.
147 The settings are retrieved from ``env.clsname_PATTERN``
149 if isinstance(target, str):
150 base = self.generator.path
151 if target.startswith('#'):
152 # for those who like flat structures
154 base = self.generator.bld.bldnode
156 pattern = self.env[self.__class__.__name__ + '_PATTERN']
159 folder, name = os.path.split(target)
161 if self.__class__.__name__.find('shlib') > 0 and getattr(self.generator, 'vnum', None):
162 nums = self.generator.vnum.split('.')
163 if self.env.DEST_BINFMT == 'pe':
164 # include the version in the dll file name,
165 # the import lib file name stays unversionned.
166 name = name + '-' + nums[0]
167 elif self.env.DEST_OS == 'openbsd':
168 pattern = '%s.%s' % (pattern, nums[0])
170 pattern += '.%s' % nums[1]
173 tmp = folder + os.sep + pattern % name
176 target = base.find_or_declare(tmp)
177 self.set_outputs(target)
179 def exec_command(self, *k, **kw):
180 ret = super(link_task, self).exec_command(*k, **kw)
181 if not ret and self.env.DO_MANIFEST:
187 Create manifest files for VS-like compilers (msvc, ifort, ...)
193 for out_node in self.outputs:
194 if out_node.name.endswith('.manifest'):
195 manifest = out_node.abspath()
198 # Should never get here. If we do, it means the manifest file was
199 # never added to the outputs list, thus we don't have a manifest file
200 # to embed, so we just return.
203 # embedding mode. Different for EXE's and DLL's.
204 # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx
206 for x in Utils.to_list(self.generator.features):
207 if x in ('cprogram', 'cxxprogram', 'fcprogram', 'fcprogram_test'):
209 elif x in ('cshlib', 'cxxshlib', 'fcshlib'):
212 Logs.debug('msvc: embedding manifest in mode %r', mode)
214 lst = [] + self.env.MT
215 lst.extend(Utils.to_list(self.env.MTFLAGS))
216 lst.extend(['-manifest', manifest])
217 lst.append('-outputresource:%s;%s' % (self.outputs[0].abspath(), mode))
219 return super(link_task, self).exec_command(lst)
221 class stlink_task(link_task):
223 Base for static link tasks, which use *ar* most of the time.
224 The target is always removed before being written.
226 run_str = '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'
229 """Default installation mode for the static libraries"""
234 try: os.remove(self.outputs[0].abspath())
237 setattr(cls, 'run', wrap)
240 @feature('c', 'cxx', 'd', 'fc', 'asm')
241 @after_method('process_source')
242 def apply_link(self):
244 Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and
245 use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task
246 matching a name from the attribute *features*, for example::
249 tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app')
251 will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram`
254 for x in self.features:
255 if x == 'cprogram' and 'cxx' in self.features: # limited compat
257 elif x == 'cshlib' and 'cxx' in self.features:
260 if x in Task.classes:
261 if issubclass(Task.classes[x], link_task):
267 objs = [t.outputs[0] for t in getattr(self, 'compiled_tasks', [])]
268 self.link_task = self.create_task(link, objs)
269 self.link_task.add_target(self.target)
271 # remember that the install paths are given by the task generators
273 inst_to = self.install_path
274 except AttributeError:
275 inst_to = self.link_task.__class__.inst_to
277 # install a copy of the node list we have at this moment (implib not added)
278 self.install_task = self.add_install_files(
279 install_to=inst_to, install_from=self.link_task.outputs[:],
280 chmod=self.link_task.chmod, task=self.link_task)
283 def use_rec(self, name, **kw):
285 Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use``
288 if name in self.tmp_use_not or name in self.tmp_use_seen:
292 y = self.bld.get_tgen_by_name(name)
293 except Errors.WafError:
294 self.uselib.append(name)
295 self.tmp_use_not.add(name)
298 self.tmp_use_seen.append(name)
301 # bind temporary attributes on the task generator
302 y.tmp_use_objects = objects = kw.get('objects', True)
303 y.tmp_use_stlib = stlib = kw.get('stlib', True)
305 link_task = y.link_task
306 except AttributeError:
310 if not isinstance(link_task, stlink_task):
312 y.tmp_use_var = 'LIB'
314 y.tmp_use_var = 'STLIB'
316 p = self.tmp_use_prec
317 for x in self.to_list(getattr(y, 'use', [])):
318 if self.env["STLIB_" + x]:
324 self.use_rec(x, objects=objects, stlib=stlib)
326 @feature('c', 'cxx', 'd', 'use', 'fc')
327 @before_method('apply_incpaths', 'propagate_uselib_vars')
328 @after_method('apply_link', 'process_source')
329 def process_use(self):
331 Process the ``use`` attribute which contains a list of task generator names::
334 bld.shlib(source='a.c', target='lib1')
335 bld.program(source='main.c', target='app', use='lib1')
337 See :py:func:`waflib.Tools.ccroot.use_rec`.
340 use_not = self.tmp_use_not = set()
341 self.tmp_use_seen = [] # we would like an ordered set
342 use_prec = self.tmp_use_prec = {}
343 self.uselib = self.to_list(getattr(self, 'uselib', []))
344 self.includes = self.to_list(getattr(self, 'includes', []))
345 names = self.to_list(getattr(self, 'use', []))
355 out = self.tmp_use_sorted = []
357 for x in self.tmp_use_seen:
358 for k in use_prec.values():
380 raise Errors.WafError('Cycle detected in the use processing %r' % use_prec)
383 link_task = getattr(self, 'link_task', None)
385 y = self.bld.get_tgen_by_name(x)
387 if var and link_task:
388 if var == 'LIB' or y.tmp_use_stlib or x in names:
389 self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]])
390 self.link_task.dep_nodes.extend(y.link_task.outputs)
391 tmp_path = y.link_task.outputs[0].parent.path_from(self.get_cwd())
392 self.env.append_unique(var + 'PATH', [tmp_path])
394 if y.tmp_use_objects:
395 self.add_objects_from_tgen(y)
397 if getattr(y, 'export_includes', None):
398 self.includes.extend(y.to_incnodes(y.export_includes))
400 if getattr(y, 'export_defines', None):
401 self.env.append_value('DEFINES', self.to_list(y.export_defines))
404 # and finally, add the use variables (no recursion needed)
407 y = self.bld.get_tgen_by_name(x)
408 except Errors.WafError:
409 if not self.env['STLIB_' + x] and not x in self.uselib:
410 self.uselib.append(x)
412 for k in self.to_list(getattr(y, 'use', [])):
413 if not self.env['STLIB_' + k] and not k in self.uselib:
414 self.uselib.append(k)
417 def accept_node_to_link(self, node):
419 PRIVATE INTERNAL USE ONLY
421 return not node.name.endswith('.pdb')
424 def add_objects_from_tgen(self, tg):
426 Add the objects from the depending compiled tasks as link task inputs.
428 Some objects are filtered: for instance, .pdb files are added
429 to the compiled tasks but not to the link tasks (to avoid errors)
430 PRIVATE INTERNAL USE ONLY
433 link_task = self.link_task
434 except AttributeError:
437 for tsk in getattr(tg, 'compiled_tasks', []):
438 for x in tsk.outputs:
439 if self.accept_node_to_link(x):
440 link_task.inputs.append(x)
443 def get_uselib_vars(self):
445 :return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`)
446 :rtype: list of string
449 for x in self.features:
451 _vars |= USELIB_VARS[x]
454 @feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib', 'asm')
455 @after_method('process_use')
456 def propagate_uselib_vars(self):
458 Process uselib variables for adding flags. For example, the following target::
461 bld.env.AFLAGS_aaa = ['bar']
462 from waflib.Tools.ccroot import USELIB_VARS
463 USELIB_VARS['aaa'] = ['AFLAGS']
465 tg = bld(features='aaa', aflags='test')
467 The *aflags* attribute will be processed and this method will set::
469 tg.env.AFLAGS = ['bar', 'test']
471 _vars = self.get_uselib_vars()
473 app = env.append_value
474 feature_uselib = self.features + self.to_list(getattr(self, 'uselib', []))
477 val = getattr(self, y, [])
479 app(var, self.to_list(val))
481 for x in feature_uselib:
482 val = env['%s_%s' % (var, x)]
486 # ============ the code above must not know anything about import libs ==========
488 @feature('cshlib', 'cxxshlib', 'fcshlib')
489 @after_method('apply_link')
490 def apply_implib(self):
492 Handle dlls and their import libs on Windows-like systems.
494 A ``.dll.a`` file called *import library* is generated.
495 It must be installed as it is required for linking the library.
497 if not self.env.DEST_BINFMT == 'pe':
500 dll = self.link_task.outputs[0]
501 if isinstance(self.target, Node.Node):
502 name = self.target.name
504 name = os.path.split(self.target)[1]
505 implib = self.env.implib_PATTERN % name
506 implib = dll.parent.find_or_declare(implib)
507 self.env.append_value('LINKFLAGS', self.env.IMPLIB_ST % implib.bldpath())
508 self.link_task.outputs.append(implib)
510 if getattr(self, 'defs', None) and self.env.DEST_BINFMT == 'pe':
511 node = self.path.find_resource(self.defs)
513 raise Errors.WafError('invalid def file %r' % self.defs)
514 if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
515 self.env.append_value('LINKFLAGS', '/def:%s' % node.path_from(self.get_cwd()))
516 self.link_task.dep_nodes.append(node)
518 #gcc for windows takes *.def file a an input without any special flag
519 self.link_task.inputs.append(node)
521 # where to put the import library
522 if getattr(self, 'install_task', None):
524 # user has given a specific installation path for the import library
525 inst_to = self.install_path_implib
526 except AttributeError:
528 # user has given an installation path for the main library, put the import library in it
529 inst_to = self.install_path
530 except AttributeError:
531 # else, put the library in BINDIR and the import library in LIBDIR
532 inst_to = '${IMPLIBDIR}'
533 self.install_task.install_to = '${BINDIR}'
534 if not self.env.IMPLIBDIR:
535 self.env.IMPLIBDIR = self.env.LIBDIR
536 self.implib_install_task = self.add_install_files(install_to=inst_to, install_from=implib,
537 chmod=self.link_task.chmod, task=self.link_task)
539 # ============ the code above must not know anything about vnum processing on unix platforms =========
541 re_vnum = re.compile('^([1-9]\\d*|0)([.]([1-9]\\d*|0)){0,2}?$')
542 @feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')
543 @after_method('apply_link', 'propagate_uselib_vars')
544 def apply_vnum(self):
546 Enforce version numbering on shared libraries. The valid version numbers must have either zero or two dots::
549 bld.shlib(source='a.c', target='foo', vnum='14.15.16')
551 In this example on Linux platform, ``libfoo.so`` is installed as ``libfoo.so.14.15.16``, and the following symbolic links are created:
553 * ``libfoo.so → libfoo.so.14.15.16``
554 * ``libfoo.so.14 → libfoo.so.14.15.16``
556 By default, the library will be assigned SONAME ``libfoo.so.14``, effectively declaring ABI compatibility between all minor and patch releases for the major version of the library. When necessary, the compatibility can be explicitly defined using `cnum` parameter:
559 bld.shlib(source='a.c', target='foo', vnum='14.15.16', cnum='14.15')
561 In this case, the assigned SONAME will be ``libfoo.so.14.15`` with ABI compatibility only between path releases for a specific major and minor version of the library.
563 On OS X platform, install-name parameter will follow the above logic for SONAME with exception that it also specifies an absolute path (based on install_path) of the library.
565 if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):
568 link = self.link_task
569 if not re_vnum.match(self.vnum):
570 raise Errors.WafError('Invalid vnum %r for target %r' % (self.vnum, getattr(self, 'name', self)))
571 nums = self.vnum.split('.')
572 node = link.outputs[0]
574 cnum = getattr(self, 'cnum', str(nums[0]))
575 cnums = cnum.split('.')
576 if len(cnums)>len(nums) or nums[0:len(cnums)] != cnums:
577 raise Errors.WafError('invalid compatibility version %s' % cnum)
580 if libname.endswith('.dylib'):
581 name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
582 name2 = libname.replace('.dylib', '.%s.dylib' % cnum)
584 name3 = libname + '.' + self.vnum
585 name2 = libname + '.' + cnum
587 # add the so name for the ld linker - to disable, just unset env.SONAME_ST
588 if self.env.SONAME_ST:
589 v = self.env.SONAME_ST % name2
590 self.env.append_value('LINKFLAGS', v.split())
592 # the following task is just to enable execution from the build dir :-/
593 if self.env.DEST_OS != 'openbsd':
594 outs = [node.parent.make_node(name3)]
596 outs.append(node.parent.make_node(name2))
597 self.create_task('vnum', node, outs)
599 if getattr(self, 'install_task', None):
600 self.install_task.hasrun = Task.SKIP_ME
601 path = self.install_task.install_to
602 if self.env.DEST_OS == 'openbsd':
603 libname = self.link_task.outputs[0].name
604 t1 = self.add_install_as(install_to='%s/%s' % (path, libname), install_from=node, chmod=self.link_task.chmod)
605 self.vnum_install_task = (t1,)
607 t1 = self.add_install_as(install_to=path + os.sep + name3, install_from=node, chmod=self.link_task.chmod)
608 t3 = self.add_symlink_as(install_to=path + os.sep + libname, install_from=name3)
610 t2 = self.add_symlink_as(install_to=path + os.sep + name2, install_from=name3)
611 self.vnum_install_task = (t1, t2, t3)
613 self.vnum_install_task = (t1, t3)
615 if '-dynamiclib' in self.env.LINKFLAGS:
616 # this requires after(propagate_uselib_vars)
618 inst_to = self.install_path
619 except AttributeError:
620 inst_to = self.link_task.__class__.inst_to
622 p = Utils.subst_vars(inst_to, self.env)
623 path = os.path.join(p, name2)
624 self.env.append_value('LINKFLAGS', ['-install_name', path])
625 self.env.append_value('LINKFLAGS', '-Wl,-compatibility_version,%s' % cnum)
626 self.env.append_value('LINKFLAGS', '-Wl,-current_version,%s' % self.vnum)
628 class vnum(Task.Task):
630 Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum`
637 for x in self.outputs:
645 os.symlink(self.inputs[0].name, path)
649 class fake_shlib(link_task):
651 Task used for reading a system library and adding the dependency on it
653 def runnable_status(self):
654 for t in self.run_after:
656 return Task.ASK_LATER
659 class fake_stlib(stlink_task):
661 Task used for reading a system library and adding the dependency on it
663 def runnable_status(self):
664 for t in self.run_after:
666 return Task.ASK_LATER
670 def read_shlib(self, name, paths=[], export_includes=[], export_defines=[]):
672 Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes::
676 bld.program(source='main.c', use='m')
678 return self(name=name, features='fake_lib', lib_paths=paths, lib_type='shlib', export_includes=export_includes, export_defines=export_defines)
681 def read_stlib(self, name, paths=[], export_includes=[], export_defines=[]):
683 Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes.
685 return self(name=name, features='fake_lib', lib_paths=paths, lib_type='stlib', export_includes=export_includes, export_defines=export_defines)
688 'shlib' : ['lib%s.so', '%s.so', 'lib%s.dylib', 'lib%s.dll', '%s.dll'],
689 'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'],
693 def process_lib(self):
695 Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`.
699 names = [x % self.name for x in lib_patterns[self.lib_type]]
700 for x in self.lib_paths + [self.path] + SYSTEM_LIB_PATHS:
701 if not isinstance(x, Node.Node):
702 x = self.bld.root.find_node(x) or self.path.find_node(x)
707 node = x.find_node(y)
710 Utils.h_file(node.abspath())
711 except EnvironmentError:
712 raise ValueError('Could not read %r' % y)
718 raise Errors.WafError('could not find library %r' % self.name)
719 self.link_task = self.create_task('fake_%s' % self.lib_type, [], [node])
720 self.target = self.name
723 class fake_o(Task.Task):
724 def runnable_status(self):
727 @extension('.o', '.obj')
728 def add_those_o_files(self, node):
729 tsk = self.create_task('fake_o', [], node)
731 self.compiled_tasks.append(tsk)
732 except AttributeError:
733 self.compiled_tasks = [tsk]
736 @before_method('process_source')
737 def process_objs(self):
739 Puts object files in the task generator outputs
741 for node in self.to_nodes(self.source):
742 self.add_those_o_files(node)
746 def read_object(self, obj):
748 Read an object file, enabling injection in libs/programs. Will trigger a rebuild if the file changes.
750 :param obj: object file path, as string or Node
752 if not isinstance(obj, self.path.__class__):
753 obj = self.path.find_resource(obj)
754 return self(features='fake_obj', source=obj, name=obj.name)
756 @feature('cxxprogram', 'cprogram')
757 @after_method('apply_link', 'process_use')
758 def set_full_paths_hpux(self):
760 On hp-ux, extend the libpaths and static library paths to absolute paths
762 if self.env.DEST_OS != 'hp-ux':
764 base = self.bld.bldnode.abspath()
765 for var in ['LIBPATH', 'STLIBPATH']:
767 for x in self.env[var]:
768 if x.startswith('/'):
771 lst.append(os.path.normpath(os.path.join(base, x)))