3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
7 # Thomas Nagy, 2005-2018 (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 """Try to process link tasks as early as possible"""
142 """Default installation path for the link task outputs, or None to disable"""
145 """Default installation mode for the link task outputs"""
147 def add_target(self, target):
149 Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*.
150 The settings are retrieved from ``env.clsname_PATTERN``
152 if isinstance(target, str):
153 base = self.generator.path
154 if target.startswith('#'):
155 # for those who like flat structures
157 base = self.generator.bld.bldnode
159 pattern = self.env[self.__class__.__name__ + '_PATTERN']
162 folder, name = os.path.split(target)
164 if self.__class__.__name__.find('shlib') > 0 and getattr(self.generator, 'vnum', None):
165 nums = self.generator.vnum.split('.')
166 if self.env.DEST_BINFMT == 'pe':
167 # include the version in the dll file name,
168 # the import lib file name stays unversionned.
169 name = name + '-' + nums[0]
170 elif self.env.DEST_OS == 'openbsd':
171 pattern = '%s.%s' % (pattern, nums[0])
173 pattern += '.%s' % nums[1]
176 tmp = folder + os.sep + pattern % name
179 target = base.find_or_declare(tmp)
180 self.set_outputs(target)
182 def exec_command(self, *k, **kw):
183 ret = super(link_task, self).exec_command(*k, **kw)
184 if not ret and self.env.DO_MANIFEST:
190 Create manifest files for VS-like compilers (msvc, ifort, ...)
196 for out_node in self.outputs:
197 if out_node.name.endswith('.manifest'):
198 manifest = out_node.abspath()
201 # Should never get here. If we do, it means the manifest file was
202 # never added to the outputs list, thus we don't have a manifest file
203 # to embed, so we just return.
206 # embedding mode. Different for EXE's and DLL's.
207 # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx
209 for x in Utils.to_list(self.generator.features):
210 if x in ('cprogram', 'cxxprogram', 'fcprogram', 'fcprogram_test'):
212 elif x in ('cshlib', 'cxxshlib', 'fcshlib'):
215 Logs.debug('msvc: embedding manifest in mode %r', mode)
217 lst = [] + self.env.MT
218 lst.extend(Utils.to_list(self.env.MTFLAGS))
219 lst.extend(['-manifest', manifest])
220 lst.append('-outputresource:%s;%s' % (self.outputs[0].abspath(), mode))
222 return super(link_task, self).exec_command(lst)
224 class stlink_task(link_task):
226 Base for static link tasks, which use *ar* most of the time.
227 The target is always removed before being written.
229 run_str = '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'
232 """Default installation mode for the static libraries"""
238 os.remove(self.outputs[0].abspath())
242 setattr(cls, 'run', wrap)
245 @feature('c', 'cxx', 'd', 'fc', 'asm')
246 @after_method('process_source')
247 def apply_link(self):
249 Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and
250 use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task
251 matching a name from the attribute *features*, for example::
254 tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app')
256 will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram`
259 for x in self.features:
260 if x == 'cprogram' and 'cxx' in self.features: # limited compat
262 elif x == 'cshlib' and 'cxx' in self.features:
265 if x in Task.classes:
266 if issubclass(Task.classes[x], link_task):
272 objs = [t.outputs[0] for t in getattr(self, 'compiled_tasks', [])]
273 self.link_task = self.create_task(link, objs)
274 self.link_task.add_target(self.target)
276 # remember that the install paths are given by the task generators
278 inst_to = self.install_path
279 except AttributeError:
280 inst_to = self.link_task.inst_to
282 # install a copy of the node list we have at this moment (implib not added)
283 self.install_task = self.add_install_files(
284 install_to=inst_to, install_from=self.link_task.outputs[:],
285 chmod=self.link_task.chmod, task=self.link_task)
288 def use_rec(self, name, **kw):
290 Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use``
293 if name in self.tmp_use_not or name in self.tmp_use_seen:
297 y = self.bld.get_tgen_by_name(name)
298 except Errors.WafError:
299 self.uselib.append(name)
300 self.tmp_use_not.add(name)
303 self.tmp_use_seen.append(name)
306 # bind temporary attributes on the task generator
307 y.tmp_use_objects = objects = kw.get('objects', True)
308 y.tmp_use_stlib = stlib = kw.get('stlib', True)
310 link_task = y.link_task
311 except AttributeError:
315 if not isinstance(link_task, stlink_task):
317 y.tmp_use_var = 'LIB'
319 y.tmp_use_var = 'STLIB'
321 p = self.tmp_use_prec
322 for x in self.to_list(getattr(y, 'use', [])):
323 if self.env["STLIB_" + x]:
329 self.use_rec(x, objects=objects, stlib=stlib)
331 @feature('c', 'cxx', 'd', 'use', 'fc')
332 @before_method('apply_incpaths', 'propagate_uselib_vars')
333 @after_method('apply_link', 'process_source')
334 def process_use(self):
336 Process the ``use`` attribute which contains a list of task generator names::
339 bld.shlib(source='a.c', target='lib1')
340 bld.program(source='main.c', target='app', use='lib1')
342 See :py:func:`waflib.Tools.ccroot.use_rec`.
345 use_not = self.tmp_use_not = set()
346 self.tmp_use_seen = [] # we would like an ordered set
347 use_prec = self.tmp_use_prec = {}
348 self.uselib = self.to_list(getattr(self, 'uselib', []))
349 self.includes = self.to_list(getattr(self, 'includes', []))
350 names = self.to_list(getattr(self, 'use', []))
360 out = self.tmp_use_sorted = []
362 for x in self.tmp_use_seen:
363 for k in use_prec.values():
385 raise Errors.WafError('Cycle detected in the use processing %r' % use_prec)
388 link_task = getattr(self, 'link_task', None)
390 y = self.bld.get_tgen_by_name(x)
392 if var and link_task:
393 if var == 'LIB' or y.tmp_use_stlib or x in names:
394 self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]])
395 self.link_task.dep_nodes.extend(y.link_task.outputs)
396 tmp_path = y.link_task.outputs[0].parent.path_from(self.get_cwd())
397 self.env.append_unique(var + 'PATH', [tmp_path])
399 if y.tmp_use_objects:
400 self.add_objects_from_tgen(y)
402 if getattr(y, 'export_includes', None):
403 # self.includes may come from a global variable #2035
404 self.includes = self.includes + y.to_incnodes(y.export_includes)
406 if getattr(y, 'export_defines', None):
407 self.env.append_value('DEFINES', self.to_list(y.export_defines))
410 # and finally, add the use variables (no recursion needed)
413 y = self.bld.get_tgen_by_name(x)
414 except Errors.WafError:
415 if not self.env['STLIB_' + x] and not x in self.uselib:
416 self.uselib.append(x)
418 for k in self.to_list(getattr(y, 'use', [])):
419 if not self.env['STLIB_' + k] and not k in self.uselib:
420 self.uselib.append(k)
423 def accept_node_to_link(self, node):
425 PRIVATE INTERNAL USE ONLY
427 return not node.name.endswith('.pdb')
430 def add_objects_from_tgen(self, tg):
432 Add the objects from the depending compiled tasks as link task inputs.
434 Some objects are filtered: for instance, .pdb files are added
435 to the compiled tasks but not to the link tasks (to avoid errors)
436 PRIVATE INTERNAL USE ONLY
439 link_task = self.link_task
440 except AttributeError:
443 for tsk in getattr(tg, 'compiled_tasks', []):
444 for x in tsk.outputs:
445 if self.accept_node_to_link(x):
446 link_task.inputs.append(x)
449 def get_uselib_vars(self):
451 :return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`)
452 :rtype: list of string
455 for x in self.features:
457 _vars |= USELIB_VARS[x]
460 @feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib', 'asm')
461 @after_method('process_use')
462 def propagate_uselib_vars(self):
464 Process uselib variables for adding flags. For example, the following target::
467 bld.env.AFLAGS_aaa = ['bar']
468 from waflib.Tools.ccroot import USELIB_VARS
469 USELIB_VARS['aaa'] = ['AFLAGS']
471 tg = bld(features='aaa', aflags='test')
473 The *aflags* attribute will be processed and this method will set::
475 tg.env.AFLAGS = ['bar', 'test']
477 _vars = self.get_uselib_vars()
479 app = env.append_value
480 feature_uselib = self.features + self.to_list(getattr(self, 'uselib', []))
483 val = getattr(self, y, [])
485 app(var, self.to_list(val))
487 for x in feature_uselib:
488 val = env['%s_%s' % (var, x)]
492 # ============ the code above must not know anything about import libs ==========
494 @feature('cshlib', 'cxxshlib', 'fcshlib')
495 @after_method('apply_link')
496 def apply_implib(self):
498 Handle dlls and their import libs on Windows-like systems.
500 A ``.dll.a`` file called *import library* is generated.
501 It must be installed as it is required for linking the library.
503 if not self.env.DEST_BINFMT == 'pe':
506 dll = self.link_task.outputs[0]
507 if isinstance(self.target, Node.Node):
508 name = self.target.name
510 name = os.path.split(self.target)[1]
511 implib = self.env.implib_PATTERN % name
512 implib = dll.parent.find_or_declare(implib)
513 self.env.append_value('LINKFLAGS', self.env.IMPLIB_ST % implib.bldpath())
514 self.link_task.outputs.append(implib)
516 if getattr(self, 'defs', None) and self.env.DEST_BINFMT == 'pe':
517 node = self.path.find_resource(self.defs)
519 raise Errors.WafError('invalid def file %r' % self.defs)
520 if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
521 self.env.append_value('LINKFLAGS', '/def:%s' % node.path_from(self.get_cwd()))
522 self.link_task.dep_nodes.append(node)
524 #gcc for windows takes *.def file a an input without any special flag
525 self.link_task.inputs.append(node)
527 # where to put the import library
528 if getattr(self, 'install_task', None):
530 # user has given a specific installation path for the import library
531 inst_to = self.install_path_implib
532 except AttributeError:
534 # user has given an installation path for the main library, put the import library in it
535 inst_to = self.install_path
536 except AttributeError:
537 # else, put the library in BINDIR and the import library in LIBDIR
538 inst_to = '${IMPLIBDIR}'
539 self.install_task.install_to = '${BINDIR}'
540 if not self.env.IMPLIBDIR:
541 self.env.IMPLIBDIR = self.env.LIBDIR
542 self.implib_install_task = self.add_install_files(install_to=inst_to, install_from=implib,
543 chmod=self.link_task.chmod, task=self.link_task)
545 # ============ the code above must not know anything about vnum processing on unix platforms =========
547 re_vnum = re.compile('^([1-9]\\d*|0)([.]([1-9]\\d*|0)){0,2}?$')
548 @feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')
549 @after_method('apply_link', 'propagate_uselib_vars')
550 def apply_vnum(self):
552 Enforce version numbering on shared libraries. The valid version numbers must have either zero or two dots::
555 bld.shlib(source='a.c', target='foo', vnum='14.15.16')
557 In this example on Linux platform, ``libfoo.so`` is installed as ``libfoo.so.14.15.16``, and the following symbolic links are created:
559 * ``libfoo.so → libfoo.so.14.15.16``
560 * ``libfoo.so.14 → libfoo.so.14.15.16``
562 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:
565 bld.shlib(source='a.c', target='foo', vnum='14.15.16', cnum='14.15')
567 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.
569 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.
571 if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):
574 link = self.link_task
575 if not re_vnum.match(self.vnum):
576 raise Errors.WafError('Invalid vnum %r for target %r' % (self.vnum, getattr(self, 'name', self)))
577 nums = self.vnum.split('.')
578 node = link.outputs[0]
580 cnum = getattr(self, 'cnum', str(nums[0]))
581 cnums = cnum.split('.')
582 if len(cnums)>len(nums) or nums[0:len(cnums)] != cnums:
583 raise Errors.WafError('invalid compatibility version %s' % cnum)
586 if libname.endswith('.dylib'):
587 name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
588 name2 = libname.replace('.dylib', '.%s.dylib' % cnum)
590 name3 = libname + '.' + self.vnum
591 name2 = libname + '.' + cnum
593 # add the so name for the ld linker - to disable, just unset env.SONAME_ST
594 if self.env.SONAME_ST:
595 v = self.env.SONAME_ST % name2
596 self.env.append_value('LINKFLAGS', v.split())
598 # the following task is just to enable execution from the build dir :-/
599 if self.env.DEST_OS != 'openbsd':
600 outs = [node.parent.make_node(name3)]
602 outs.append(node.parent.make_node(name2))
603 self.create_task('vnum', node, outs)
605 if getattr(self, 'install_task', None):
606 self.install_task.hasrun = Task.SKIPPED
607 path = self.install_task.install_to
608 if self.env.DEST_OS == 'openbsd':
609 libname = self.link_task.outputs[0].name
610 t1 = self.add_install_as(install_to='%s/%s' % (path, libname), install_from=node, chmod=self.link_task.chmod)
611 self.vnum_install_task = (t1,)
613 t1 = self.add_install_as(install_to=path + os.sep + name3, install_from=node, chmod=self.link_task.chmod)
614 t3 = self.add_symlink_as(install_to=path + os.sep + libname, install_from=name3)
616 t2 = self.add_symlink_as(install_to=path + os.sep + name2, install_from=name3)
617 self.vnum_install_task = (t1, t2, t3)
619 self.vnum_install_task = (t1, t3)
621 if '-dynamiclib' in self.env.LINKFLAGS:
622 # this requires after(propagate_uselib_vars)
624 inst_to = self.install_path
625 except AttributeError:
626 inst_to = self.link_task.inst_to
628 p = Utils.subst_vars(inst_to, self.env)
629 path = os.path.join(p, name2)
630 self.env.append_value('LINKFLAGS', ['-install_name', path])
631 self.env.append_value('LINKFLAGS', '-Wl,-compatibility_version,%s' % cnum)
632 self.env.append_value('LINKFLAGS', '-Wl,-current_version,%s' % self.vnum)
634 class vnum(Task.Task):
636 Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum`
643 for x in self.outputs:
651 os.symlink(self.inputs[0].name, path)
655 class fake_shlib(link_task):
657 Task used for reading a system library and adding the dependency on it
659 def runnable_status(self):
660 for t in self.run_after:
662 return Task.ASK_LATER
665 class fake_stlib(stlink_task):
667 Task used for reading a system library and adding the dependency on it
669 def runnable_status(self):
670 for t in self.run_after:
672 return Task.ASK_LATER
676 def read_shlib(self, name, paths=[], export_includes=[], export_defines=[]):
678 Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes::
682 bld.program(source='main.c', use='m')
684 return self(name=name, features='fake_lib', lib_paths=paths, lib_type='shlib', export_includes=export_includes, export_defines=export_defines)
687 def read_stlib(self, name, paths=[], export_includes=[], export_defines=[]):
689 Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes.
691 return self(name=name, features='fake_lib', lib_paths=paths, lib_type='stlib', export_includes=export_includes, export_defines=export_defines)
694 'shlib' : ['lib%s.so', '%s.so', 'lib%s.dylib', 'lib%s.dll', '%s.dll'],
695 'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'],
699 def process_lib(self):
701 Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`.
705 names = [x % self.name for x in lib_patterns[self.lib_type]]
706 for x in self.lib_paths + [self.path] + SYSTEM_LIB_PATHS:
707 if not isinstance(x, Node.Node):
708 x = self.bld.root.find_node(x) or self.path.find_node(x)
713 node = x.find_node(y)
716 Utils.h_file(node.abspath())
717 except EnvironmentError:
718 raise ValueError('Could not read %r' % y)
724 raise Errors.WafError('could not find library %r' % self.name)
725 self.link_task = self.create_task('fake_%s' % self.lib_type, [], [node])
726 self.target = self.name
729 class fake_o(Task.Task):
730 def runnable_status(self):
733 @extension('.o', '.obj')
734 def add_those_o_files(self, node):
735 tsk = self.create_task('fake_o', [], node)
737 self.compiled_tasks.append(tsk)
738 except AttributeError:
739 self.compiled_tasks = [tsk]
742 @before_method('process_source')
743 def process_objs(self):
745 Puts object files in the task generator outputs
747 for node in self.to_nodes(self.source):
748 self.add_those_o_files(node)
752 def read_object(self, obj):
754 Read an object file, enabling injection in libs/programs. Will trigger a rebuild if the file changes.
756 :param obj: object file path, as string or Node
758 if not isinstance(obj, self.path.__class__):
759 obj = self.path.find_resource(obj)
760 return self(features='fake_obj', source=obj, name=obj.name)
762 @feature('cxxprogram', 'cprogram')
763 @after_method('apply_link', 'process_use')
764 def set_full_paths_hpux(self):
766 On hp-ux, extend the libpaths and static library paths to absolute paths
768 if self.env.DEST_OS != 'hp-ux':
770 base = self.bld.bldnode.abspath()
771 for var in ['LIBPATH', 'STLIBPATH']:
773 for x in self.env[var]:
774 if x.startswith('/'):
777 lst.append(os.path.normpath(os.path.join(base, x)))