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('.')
578 if len(cnums
)>len(nums
) or nums
[0:len(cnums
)] != cnums
:
579 raise Errors
.WafError('invalid compatibility version %s' % cnum
)
582 if libname
.endswith('.dylib'):
583 name3
= libname
.replace('.dylib', '.%s.dylib' % self
.vnum
)
584 name2
= libname
.replace('.dylib', '.%s.dylib' % cnum
)
586 name3
= libname
+ '.' + self
.vnum
587 name2
= libname
+ '.' + cnum
589 # add the so name for the ld linker - to disable, just unset env.SONAME_ST
590 if self
.env
.SONAME_ST
:
591 v
= self
.env
.SONAME_ST
% name2
592 self
.env
.append_value('LINKFLAGS', v
.split())
594 # the following task is just to enable execution from the build dir :-/
595 if self
.env
.DEST_OS
!= 'openbsd':
596 outs
= [node
.parent
.make_node(name3
)]
598 outs
.append(node
.parent
.make_node(name2
))
599 self
.create_task('vnum', node
, outs
)
601 if getattr(self
, 'install_task', None):
602 self
.install_task
.hasrun
= Task
.SKIPPED
603 self
.install_task
.no_errcheck_out
= True
604 path
= self
.install_task
.install_to
605 if self
.env
.DEST_OS
== 'openbsd':
606 libname
= self
.link_task
.outputs
[0].name
607 t1
= self
.add_install_as(install_to
='%s/%s' % (path
, libname
), install_from
=node
, chmod
=self
.link_task
.chmod
)
608 self
.vnum_install_task
= (t1
,)
610 t1
= self
.add_install_as(install_to
=path
+ os
.sep
+ name3
, install_from
=node
, chmod
=self
.link_task
.chmod
)
611 t3
= self
.add_symlink_as(install_to
=path
+ os
.sep
+ libname
, install_from
=name3
)
613 t2
= self
.add_symlink_as(install_to
=path
+ os
.sep
+ name2
, install_from
=name3
)
614 self
.vnum_install_task
= (t1
, t2
, t3
)
616 self
.vnum_install_task
= (t1
, t3
)
618 if '-dynamiclib' in self
.env
.LINKFLAGS
:
619 # this requires after(propagate_uselib_vars)
621 inst_to
= self
.install_path
622 except AttributeError:
623 inst_to
= self
.link_task
.inst_to
625 p
= Utils
.subst_vars(inst_to
, self
.env
)
626 path
= os
.path
.join(p
, name2
)
627 self
.env
.append_value('LINKFLAGS', ['-install_name', path
])
628 self
.env
.append_value('LINKFLAGS', '-Wl,-compatibility_version,%s' % cnum
)
629 self
.env
.append_value('LINKFLAGS', '-Wl,-current_version,%s' % self
.vnum
)
631 class vnum(Task
.Task
):
633 Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum`
640 for x
in self
.outputs
:
648 os
.symlink(self
.inputs
[0].name
, path
)
652 class fake_shlib(link_task
):
654 Task used for reading a system library and adding the dependency on it
656 def runnable_status(self
):
657 for t
in self
.run_after
:
659 return Task
.ASK_LATER
662 class fake_stlib(stlink_task
):
664 Task used for reading a system library and adding the dependency on it
666 def runnable_status(self
):
667 for t
in self
.run_after
:
669 return Task
.ASK_LATER
673 def read_shlib(self
, name
, paths
=[], export_includes
=[], export_defines
=[]):
675 Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes::
679 bld.program(source='main.c', use='m')
681 return self(name
=name
, features
='fake_lib', lib_paths
=paths
, lib_type
='shlib', export_includes
=export_includes
, export_defines
=export_defines
)
684 def read_stlib(self
, name
, paths
=[], export_includes
=[], export_defines
=[]):
686 Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes.
688 return self(name
=name
, features
='fake_lib', lib_paths
=paths
, lib_type
='stlib', export_includes
=export_includes
, export_defines
=export_defines
)
691 'shlib' : ['lib%s.so', '%s.so', 'lib%s.dylib', 'lib%s.dll', '%s.dll'],
692 'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'],
696 def process_lib(self
):
698 Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`.
702 names
= [x
% self
.name
for x
in lib_patterns
[self
.lib_type
]]
703 for x
in self
.lib_paths
+ [self
.path
] + SYSTEM_LIB_PATHS
:
704 if not isinstance(x
, Node
.Node
):
705 x
= self
.bld
.root
.find_node(x
) or self
.path
.find_node(x
)
710 node
= x
.find_node(y
)
713 Utils
.h_file(node
.abspath())
714 except EnvironmentError:
715 raise ValueError('Could not read %r' % y
)
721 raise Errors
.WafError('could not find library %r' % self
.name
)
722 self
.link_task
= self
.create_task('fake_%s' % self
.lib_type
, [], [node
])
723 self
.target
= self
.name
726 class fake_o(Task
.Task
):
727 def runnable_status(self
):
730 @extension('.o', '.obj')
731 def add_those_o_files(self
, node
):
732 tsk
= self
.create_task('fake_o', [], node
)
734 self
.compiled_tasks
.append(tsk
)
735 except AttributeError:
736 self
.compiled_tasks
= [tsk
]
739 @before_method('process_source')
740 def process_objs(self
):
742 Puts object files in the task generator outputs
744 for node
in self
.to_nodes(self
.source
):
745 self
.add_those_o_files(node
)
749 def read_object(self
, obj
):
751 Read an object file, enabling injection in libs/programs. Will trigger a rebuild if the file changes.
753 :param obj: object file path, as string or Node
755 if not isinstance(obj
, self
.path
.__class
__):
756 obj
= self
.path
.find_resource(obj
)
757 return self(features
='fake_obj', source
=obj
, name
=obj
.name
)
759 @feature('cxxprogram', 'cprogram')
760 @after_method('apply_link', 'process_use')
761 def set_full_paths_hpux(self
):
763 On hp-ux, extend the libpaths and static library paths to absolute paths
765 if self
.env
.DEST_OS
!= 'hp-ux':
767 base
= self
.bld
.bldnode
.abspath()
768 for var
in ['LIBPATH', 'STLIBPATH']:
770 for x
in self
.env
[var
]:
771 if x
.startswith('/'):
774 lst
.append(os
.path
.normpath(os
.path
.join(base
, x
)))