3 # Thomas Nagy, 2005-2018 (ita)
6 Classes and methods shared by tools providing support for C-like language such
7 as C/C++/D/Assembly/Go (this support module is almost never used alone).
11 from waflib
import Task
, Utils
, Node
, Errors
, Logs
12 from waflib
.TaskGen
import after_method
, before_method
, feature
, taskgen_method
, extension
13 from waflib
.Tools
import c_aliases
, c_preproc
, c_config
, c_osx
, c_tests
14 from waflib
.Configure
import conf
16 SYSTEM_LIB_PATHS
= ['/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib']
18 USELIB_VARS
= Utils
.defaultdict(set)
20 Mapping for features to :py:class:`waflib.ConfigSet.ConfigSet` variables. See :py:func:`waflib.Tools.ccroot.propagate_uselib_vars`.
23 USELIB_VARS
['c'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CCDEPS', 'CFLAGS', 'ARCH'])
24 USELIB_VARS
['cxx'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CXXDEPS', 'CXXFLAGS', 'ARCH'])
25 USELIB_VARS
['d'] = set(['INCLUDES', 'DFLAGS'])
26 USELIB_VARS
['includes'] = set(['INCLUDES', 'FRAMEWORKPATH', 'ARCH'])
28 USELIB_VARS
['cprogram'] = USELIB_VARS
['cxxprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH', 'LDFLAGS'])
29 USELIB_VARS
['cshlib'] = USELIB_VARS
['cxxshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH', 'LDFLAGS'])
30 USELIB_VARS
['cstlib'] = USELIB_VARS
['cxxstlib'] = set(['ARFLAGS', 'LINKDEPS'])
32 USELIB_VARS
['dprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
33 USELIB_VARS
['dshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
34 USELIB_VARS
['dstlib'] = set(['ARFLAGS', 'LINKDEPS'])
36 USELIB_VARS
['asm'] = set(['ASFLAGS'])
38 # =================================================================================================
41 def create_compiled_task(self
, name
, node
):
43 Create the compilation task: c, cxx, asm, etc. The output node is created automatically (object file with a typical **.o** extension).
44 The task is appended to the list *compiled_tasks* which is then used by :py:func:`waflib.Tools.ccroot.apply_link`
46 :param name: name of the task class
48 :param node: the file to compile
49 :type node: :py:class:`waflib.Node.Node`
50 :return: The task created
51 :rtype: :py:class:`waflib.Task.Task`
53 out
= '%s.%d.o' % (node
.name
, self
.idx
)
54 task
= self
.create_task(name
, node
, node
.parent
.find_or_declare(out
))
56 self
.compiled_tasks
.append(task
)
57 except AttributeError:
58 self
.compiled_tasks
= [task
]
62 def to_incnodes(self
, inlst
):
64 Task generator method provided to convert a list of string/nodes into a list of includes folders.
66 The paths are assumed to be relative to the task generator path, except if they begin by **#**
67 in which case they are searched from the top-level directory (``bld.srcnode``).
68 The folders are simply assumed to be existing.
70 The node objects in the list are returned in the output list. The strings are converted
71 into node objects if possible. The node is searched from the source directory, and if a match is found,
72 the equivalent build directory is created and added to the returned list too. When a folder cannot be found, it is ignored.
74 :param inlst: list of folders
75 :type inlst: space-delimited string or a list of string/nodes
76 :rtype: list of :py:class:`waflib.Node.Node`
77 :return: list of include folders as nodes
81 for x
in self
.to_list(inlst
):
82 if x
in seen
or not x
:
86 # with a real lot of targets, it is sometimes interesting to cache the results below
87 if isinstance(x
, Node
.Node
):
91 lst
.append(self
.bld
.root
.make_node(x
) or x
)
94 p
= self
.bld
.bldnode
.make_node(x
[1:])
95 v
= self
.bld
.srcnode
.make_node(x
[1:])
97 p
= self
.path
.get_bld().make_node(x
)
98 v
= self
.path
.make_node(x
)
99 if p
.is_child_of(self
.bld
.bldnode
):
105 @feature('c', 'cxx', 'd', 'asm', 'fc', 'includes')
106 @after_method('propagate_uselib_vars', 'process_source')
107 def apply_incpaths(self
):
109 Task generator method that processes the attribute *includes*::
111 tg = bld(features='includes', includes='.')
113 The folders only need to be relative to the current directory, the equivalent build directory is
114 added automatically (for headers created in the build directory). This enable using a build directory
115 or not (``top == out``).
117 This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``,
118 and the list of include paths in ``tg.env.INCLUDES``.
121 lst
= self
.to_incnodes(self
.to_list(getattr(self
, 'includes', [])) + self
.env
.INCLUDES
)
122 self
.includes_nodes
= lst
124 self
.env
.INCPATHS
= [x
.path_from(cwd
) for x
in lst
]
126 class link_task(Task
.Task
):
128 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`.
130 .. 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
135 """Try to process link tasks as early as possible"""
138 """Default installation path for the link task outputs, or None to disable"""
141 """Default installation mode for the link task outputs"""
143 def add_target(self
, target
):
145 Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*.
146 The settings are retrieved from ``env.clsname_PATTERN``
148 if isinstance(target
, str):
149 base
= self
.generator
.path
150 if target
.startswith('#'):
151 # for those who like flat structures
153 base
= self
.generator
.bld
.bldnode
155 pattern
= self
.env
[self
.__class
__.__name
__ + '_PATTERN']
158 folder
, name
= os
.path
.split(target
)
160 if self
.__class
__.__name
__.find('shlib') > 0 and getattr(self
.generator
, 'vnum', None):
161 nums
= self
.generator
.vnum
.split('.')
162 if self
.env
.DEST_BINFMT
== 'pe':
163 # include the version in the dll file name,
164 # the import lib file name stays unversioned.
165 name
= name
+ '-' + nums
[0]
166 elif self
.env
.DEST_OS
== 'openbsd':
167 pattern
= '%s.%s' % (pattern
, nums
[0])
169 pattern
+= '.%s' % nums
[1]
172 tmp
= folder
+ os
.sep
+ pattern
% name
175 target
= base
.find_or_declare(tmp
)
176 self
.set_outputs(target
)
178 def exec_command(self
, *k
, **kw
):
179 ret
= super(link_task
, self
).exec_command(*k
, **kw
)
180 if not ret
and self
.env
.DO_MANIFEST
:
186 Create manifest files for VS-like compilers (msvc, ifort, ...)
192 for out_node
in self
.outputs
:
193 if out_node
.name
.endswith('.manifest'):
194 manifest
= out_node
.abspath()
197 # Should never get here. If we do, it means the manifest file was
198 # never added to the outputs list, thus we don't have a manifest file
199 # to embed, so we just return.
202 # embedding mode. Different for EXE's and DLL's.
203 # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx
205 for x
in Utils
.to_list(self
.generator
.features
):
206 if x
in ('cprogram', 'cxxprogram', 'fcprogram', 'fcprogram_test'):
208 elif x
in ('cshlib', 'cxxshlib', 'fcshlib'):
211 Logs
.debug('msvc: embedding manifest in mode %r', mode
)
213 lst
= [] + self
.env
.MT
214 lst
.extend(Utils
.to_list(self
.env
.MTFLAGS
))
215 lst
.extend(['-manifest', manifest
])
216 lst
.append('-outputresource:%s;%s' % (self
.outputs
[0].abspath(), mode
))
218 return super(link_task
, self
).exec_command(lst
)
220 class stlink_task(link_task
):
222 Base for static link tasks, which use *ar* most of the time.
223 The target is always removed before being written.
225 run_str
= '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'
228 """Default installation mode for the static libraries"""
234 os
.remove(self
.outputs
[0].abspath())
238 setattr(cls
, 'run', wrap
)
241 @feature('c', 'cxx', 'd', 'fc', 'asm')
242 @after_method('process_source')
243 def apply_link(self
):
245 Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and
246 use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task
247 matching a name from the attribute *features*, for example::
250 tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app')
252 will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram`
255 for x
in self
.features
:
256 if x
== 'cprogram' and 'cxx' in self
.features
: # limited compat
258 elif x
== 'cshlib' and 'cxx' in self
.features
:
261 if x
in Task
.classes
:
262 if issubclass(Task
.classes
[x
], link_task
):
268 objs
= [t
.outputs
[0] for t
in getattr(self
, 'compiled_tasks', [])]
269 self
.link_task
= self
.create_task(link
, objs
)
270 self
.link_task
.add_target(self
.target
)
272 # remember that the install paths are given by the task generators
274 inst_to
= self
.install_path
275 except AttributeError:
276 inst_to
= self
.link_task
.inst_to
278 # install a copy of the node list we have at this moment (implib not added)
279 self
.install_task
= self
.add_install_files(
280 install_to
=inst_to
, install_from
=self
.link_task
.outputs
[:],
281 chmod
=self
.link_task
.chmod
, task
=self
.link_task
)
284 def use_rec(self
, name
, **kw
):
286 Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use``
289 if name
in self
.tmp_use_not
or name
in self
.tmp_use_seen
:
293 y
= self
.bld
.get_tgen_by_name(name
)
294 except Errors
.WafError
:
295 self
.uselib
.append(name
)
296 self
.tmp_use_not
.add(name
)
299 self
.tmp_use_seen
.append(name
)
302 # bind temporary attributes on the task generator
303 y
.tmp_use_objects
= objects
= kw
.get('objects', True)
304 y
.tmp_use_stlib
= stlib
= kw
.get('stlib', True)
306 link_task
= y
.link_task
307 except AttributeError:
311 if not isinstance(link_task
, stlink_task
):
313 y
.tmp_use_var
= 'LIB'
315 y
.tmp_use_var
= 'STLIB'
317 p
= self
.tmp_use_prec
318 for x
in self
.to_list(getattr(y
, 'use', [])):
319 if self
.env
["STLIB_" + x
]:
325 self
.use_rec(x
, objects
=objects
, stlib
=stlib
)
327 @feature('c', 'cxx', 'd', 'use', 'fc')
328 @before_method('apply_incpaths', 'propagate_uselib_vars')
329 @after_method('apply_link', 'process_source')
330 def process_use(self
):
332 Process the ``use`` attribute which contains a list of task generator names::
335 bld.shlib(source='a.c', target='lib1')
336 bld.program(source='main.c', target='app', use='lib1')
338 See :py:func:`waflib.Tools.ccroot.use_rec`.
341 use_not
= self
.tmp_use_not
= set()
342 self
.tmp_use_seen
= [] # we would like an ordered set
343 use_prec
= self
.tmp_use_prec
= {}
344 self
.uselib
= self
.to_list(getattr(self
, 'uselib', []))
345 self
.includes
= self
.to_list(getattr(self
, 'includes', []))
346 names
= self
.to_list(getattr(self
, 'use', []))
356 out
= self
.tmp_use_sorted
= []
358 for x
in self
.tmp_use_seen
:
359 for k
in use_prec
.values():
381 raise Errors
.WafError('Cycle detected in the use processing %r' % use_prec
)
384 link_task
= getattr(self
, 'link_task', None)
386 y
= self
.bld
.get_tgen_by_name(x
)
388 if var
and link_task
:
389 if var
== 'LIB' or y
.tmp_use_stlib
or x
in names
:
390 self
.env
.append_value(var
, [y
.target
[y
.target
.rfind(os
.sep
) + 1:]])
391 self
.link_task
.dep_nodes
.extend(y
.link_task
.outputs
)
392 tmp_path
= y
.link_task
.outputs
[0].parent
.path_from(self
.get_cwd())
393 self
.env
.append_unique(var
+ 'PATH', [tmp_path
])
395 if y
.tmp_use_objects
:
396 self
.add_objects_from_tgen(y
)
398 if getattr(y
, 'export_includes', None):
399 # self.includes may come from a global variable #2035
400 self
.includes
= self
.includes
+ y
.to_incnodes(y
.export_includes
)
402 if getattr(y
, 'export_defines', None):
403 self
.env
.append_value('DEFINES', self
.to_list(y
.export_defines
))
406 # and finally, add the use variables (no recursion needed)
409 y
= self
.bld
.get_tgen_by_name(x
)
410 except Errors
.WafError
:
411 if not self
.env
['STLIB_' + x
] and not x
in self
.uselib
:
412 self
.uselib
.append(x
)
414 for k
in self
.to_list(getattr(y
, 'use', [])):
415 if not self
.env
['STLIB_' + k
] and not k
in self
.uselib
:
416 self
.uselib
.append(k
)
419 def accept_node_to_link(self
, node
):
421 PRIVATE INTERNAL USE ONLY
423 return not node
.name
.endswith('.pdb')
426 def add_objects_from_tgen(self
, tg
):
428 Add the objects from the depending compiled tasks as link task inputs.
430 Some objects are filtered: for instance, .pdb files are added
431 to the compiled tasks but not to the link tasks (to avoid errors)
432 PRIVATE INTERNAL USE ONLY
435 link_task
= self
.link_task
436 except AttributeError:
439 for tsk
in getattr(tg
, 'compiled_tasks', []):
440 for x
in tsk
.outputs
:
441 if self
.accept_node_to_link(x
):
442 link_task
.inputs
.append(x
)
445 def get_uselib_vars(self
):
447 :return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`)
448 :rtype: list of string
451 for x
in self
.features
:
453 _vars |
= USELIB_VARS
[x
]
456 @feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib', 'asm')
457 @after_method('process_use')
458 def propagate_uselib_vars(self
):
460 Process uselib variables for adding flags. For example, the following target::
463 bld.env.AFLAGS_aaa = ['bar']
464 from waflib.Tools.ccroot import USELIB_VARS
465 USELIB_VARS['aaa'] = ['AFLAGS']
467 tg = bld(features='aaa', aflags='test')
469 The *aflags* attribute will be processed and this method will set::
471 tg.env.AFLAGS = ['bar', 'test']
473 _vars
= self
.get_uselib_vars()
475 app
= env
.append_value
476 feature_uselib
= self
.features
+ self
.to_list(getattr(self
, 'uselib', []))
479 val
= getattr(self
, y
, [])
481 app(var
, self
.to_list(val
))
483 for x
in feature_uselib
:
484 val
= env
['%s_%s' % (var
, x
)]
488 # ============ the code above must not know anything about import libs ==========
490 @feature('cshlib', 'cxxshlib', 'fcshlib')
491 @after_method('apply_link')
492 def apply_implib(self
):
494 Handle dlls and their import libs on Windows-like systems.
496 A ``.dll.a`` file called *import library* is generated.
497 It must be installed as it is required for linking the library.
499 if not self
.env
.DEST_BINFMT
== 'pe':
502 dll
= self
.link_task
.outputs
[0]
503 if isinstance(self
.target
, Node
.Node
):
504 name
= self
.target
.name
506 name
= os
.path
.split(self
.target
)[1]
507 implib
= self
.env
.implib_PATTERN
% name
508 implib
= dll
.parent
.find_or_declare(implib
)
509 self
.env
.append_value('LINKFLAGS', self
.env
.IMPLIB_ST
% implib
.bldpath())
510 self
.link_task
.outputs
.append(implib
)
512 if getattr(self
, 'defs', None) and self
.env
.DEST_BINFMT
== 'pe':
513 node
= self
.path
.find_resource(self
.defs
)
515 raise Errors
.WafError('invalid def file %r' % self
.defs
)
516 if self
.env
.def_PATTERN
:
517 self
.env
.append_value('LINKFLAGS', self
.env
.def_PATTERN
% node
.path_from(self
.get_cwd()))
518 self
.link_task
.dep_nodes
.append(node
)
520 # gcc for windows takes *.def file as input without any special flag
521 self
.link_task
.inputs
.append(node
)
523 # where to put the import library
524 if getattr(self
, 'install_task', None):
526 # user has given a specific installation path for the import library
527 inst_to
= self
.install_path_implib
528 except AttributeError:
530 # user has given an installation path for the main library, put the import library in it
531 inst_to
= self
.install_path
532 except AttributeError:
533 # else, put the library in BINDIR and the import library in LIBDIR
534 inst_to
= '${IMPLIBDIR}'
535 self
.install_task
.install_to
= '${BINDIR}'
536 if not self
.env
.IMPLIBDIR
:
537 self
.env
.IMPLIBDIR
= self
.env
.LIBDIR
538 self
.implib_install_task
= self
.add_install_files(install_to
=inst_to
, install_from
=implib
,
539 chmod
=self
.link_task
.chmod
, task
=self
.link_task
)
541 # ============ the code above must not know anything about vnum processing on unix platforms =========
543 re_vnum
= re
.compile('^([1-9]\\d*|0)([.]([1-9]\\d*|0)){0,2}?$')
544 @feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')
545 @after_method('apply_link', 'propagate_uselib_vars')
546 def apply_vnum(self
):
548 Enforce version numbering on shared libraries. The valid version numbers must have either zero or two dots::
551 bld.shlib(source='a.c', target='foo', vnum='14.15.16')
553 In this example on Linux platform, ``libfoo.so`` is installed as ``libfoo.so.14.15.16``, and the following symbolic links are created:
555 * ``libfoo.so → libfoo.so.14.15.16``
556 * ``libfoo.so.14 → libfoo.so.14.15.16``
558 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:
561 bld.shlib(source='a.c', target='foo', vnum='14.15.16', cnum='14.15')
563 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.
565 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.
567 if not getattr(self
, 'vnum', '') or os
.name
!= 'posix' or self
.env
.DEST_BINFMT
not in ('elf', 'mac-o'):
570 link
= self
.link_task
571 if not re_vnum
.match(self
.vnum
):
572 raise Errors
.WafError('Invalid vnum %r for target %r' % (self
.vnum
, getattr(self
, 'name', self
)))
573 nums
= self
.vnum
.split('.')
574 node
= link
.outputs
[0]
576 cnum
= getattr(self
, 'cnum', str(nums
[0]))
577 cnums
= cnum
.split('.')
580 if libname
.endswith('.dylib'):
581 name3
= name2
= libname
.replace('.dylib', '.%s.dylib' % cnum
)
583 name3
= libname
+ '.' + self
.vnum
584 name2
= libname
+ '.' + cnum
586 # add the so name for the ld linker - to disable, just unset env.SONAME_ST
587 if self
.env
.SONAME_ST
:
588 v
= self
.env
.SONAME_ST
% name2
589 self
.env
.append_value('LINKFLAGS', v
.split())
591 # the following task is just to enable execution from the build dir :-/
592 if self
.env
.DEST_OS
!= 'openbsd':
593 outs
= [node
.parent
.make_node(name3
)]
595 outs
.append(node
.parent
.make_node(name2
))
596 self
.create_task('vnum', node
, outs
)
598 if getattr(self
, 'install_task', None):
599 self
.install_task
.hasrun
= Task
.SKIPPED
600 self
.install_task
.no_errcheck_out
= True
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
.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
)))