📄 targets.jam
字号:
# Copyright Vladimir Prus 2002.# Copyright Rene Rivera 2006.## Distributed under the Boost Software License, Version 1.0.# (See accompanying file LICENSE_1_0.txt or copy at# http://www.boost.org/LICENSE_1_0.txt)# Supports 'abstract' targets, which are targets explicitly defined in a# Jamfile.## Abstract targets are represented by classes derived from 'abstract-target'# class. The first abstract target is 'project-target', which is created for# each Jamfile, and can be obtained by the 'target' rule in the Jamfile's module# (see project.jam).## Project targets keep a list of 'main-target' instances. A main target is what# the user explicitly defines in a Jamfile. It is possible to have several# definitions for a main target, for example to have different lists of sources# for different platforms. So, main targets keep a list of alternatives.## Each alternative is an instance of 'abstract-target'. When a main target# subvariant is defined by some rule, that rule will decide what class to use,# create an instance of that class and add it to the list of alternatives for# the main target.## Rules supplied by the build system will use only targets derived from# 'basic-target' class, which will provide some default behaviour. There will be# different classes derived from it such as 'make-target', created by the 'make'# rule, and 'typed-target', created by rules such as 'exe' and 'lib'.## +------------------------+# |abstract-target |# +========================+# |name |# |project |# | |# |generate(properties) = 0|# +-----------+------------+# |# ^# / \# +-+-+# |# |# +------------------------+------+------------------------------+# | | |# | | |# +----------+-----------+ +------+------+ +------+-------+# | project-target | | main-target | | basic-target |# +======================+ 1 * +=============+ alternatives +==============+# | generate(properties) |o-----------+ generate |<>------------->| generate |# | main-target | +-------------+ | construct = 0|# +----------------------+ +--------------+# |# ^# / \# +-+-+# |# |# ...--+----------------+------------------+----------------+---+# | | | |# | | | |# ... ---+-----+ +------+-------+ +------+------+ +--------+-----+# | | typed-target | | make-target | | stage-target |# . +==============+ +=============+ +==============+# . | construct | | construct | | construct |# +--------------+ +-------------+ +--------------+import assert ;import "class" : new ;import errors ;import feature ;import indirect ;import path ;import property ;import property-set ;import sequence ;import set ;import toolset ;# Base class for all abstract targets.#class abstract-target{ import project ; import assert ; import "class" ; import errors ; rule __init__ ( name # Name of the target in Jamfile. : project-target # The project target to which this one belongs. ) { # Note: it might seem that we don't need either name or project at all. # However, there are places where we really need it. One example is # error messages which should name problematic targets. Another is # setting correct paths for sources and generated files. self.name = $(name) ; self.project = $(project-target) ; self.location = [ errors.nearest-user-location ] ; } # Returns the name of this target. rule name ( ) { return $(self.name) ; } # Returns the project for this target. rule project ( ) { return $(self.project) ; } # Return the location where the target was declared. rule location ( ) { return $(self.location) ; } # Returns a user-readable name for this target. rule full-name ( ) { local location = [ $(self.project).get location ] ; return $(location)/$(self.name) ; } # Generates virtual targets for this abstract target using the specified # properties, unless a different value of some feature is required by the # target. # On success, returns: # - a property-set with the usage requirements to be applied to dependants # - a list of produced virtual targets, which may be empty. # If 'property-set' is empty, performs the default build of this target, in # a way specific to the derived class. # rule generate ( property-set ) { errors.error "method should be defined in derived classes" ; } rule rename ( new-name ) { self.name = $(new-name) ; }}if --debug-building in [ modules.peek : ARGV ]{ modules.poke : .debug-building : true ;}rule indent ( ){ return $(.indent:J="") ;}rule increase-indent ( ){ .indent += " " ;}rule decrease-indent ( ){ .indent = $(.indent[2-]) ;}# Project target class (derived from 'abstract-target').## This class has the following responsibilities:# - Maintaining a list of main targets in this project and building them.## Main targets are constructed in two stages:# - When Jamfile is read, a number of calls to 'add-alternative' is made. At# that time, alternatives can also be renamed to account for inline targets.# - The first time 'main-target' or 'has-main-target' rule is called, all# alternatives are enumerated and main targets are created.#class project-target : abstract-target{ import project ; import targets ; import path ; import print ; import property-set ; import set ; import sequence ; import "class" : new ; import errors ; rule __init__ ( name : project-module parent-project ? : requirements * : default-build * ) { abstract-target.__init__ $(name) : $(__name__) ; self.project-module = $(project-module) ; self.location = [ project.attribute $(project-module) location ] ; self.requirements = $(requirements) ; self.default-build = $(default-build) ; if $(parent-project) { inherit $(parent-project) ; } } # This is needed only by the 'make' rule. Need to find the way to make # 'make' work without this method. # rule project-module ( ) { return $(self.project-module) ; } rule get ( attribute ) { return [ project.attribute $(self.project-module) $(attribute) ] ; } rule build-dir ( ) { if ! $(self.build-dir) { self.build-dir = [ get build-dir ] ; if ! $(self.build-dir) { self.build-dir = [ path.join [ $(self.project).get location ] bin ] ; } } return $(self.build-dir) ; } # Generates all possible targets contained in this project. # rule generate ( property-set * ) { if [ modules.peek : .debug-building ] { ECHO [ targets.indent ] "building project" [ name ] " ('$(__name__)') with" [ $(property-set).raw ] ; targets.increase-indent ; } local usage-requirements = [ property-set.empty ] ; local targets ; for local t in [ targets-to-build ] { local g = [ $(t).generate $(property-set) ] ; usage-requirements = [ $(usage-requirements).add $(g[1]) ] ; targets += $(g[2-]) ; } targets.decrease-indent ; return $(usage-requirements) [ sequence.unique $(targets) ] ; } # Computes and returns a list of abstract-target instances which must be # built when this project is built. # rule targets-to-build ( ) { local result ; if ! $(self.built-main-targets) { build-main-targets ; } # Collect all main targets here, except for "explicit" ones. for local t in $(self.main-targets) { if ! [ $(t).name ] in $(self.explicit-targets) { result += $(t) ; } } # Collect all projects referenced via "projects-to-build" attribute. local self-location = [ get location ] ; for local pn in [ get projects-to-build ] { result += [ find $(pn) ] ; } return $(result) ; } # Add 'target' to the list of targets in this project that should be build # only by explicit request # rule mark-target-as-explicit ( target-name ) { # Record the name of the target, not instance, since this rule is called # before main target instances are created. self.explicit-targets += $(target-name) ; } # Add new target alternative # rule add-alternative ( target-instance ) { if $(self.built-main-targets) { errors.error add-alternative called when main targets are already created. : in project [ full-name ] ; } self.alternatives += $(target-instance) ; } # Returns a 'main-target' class instance corresponding to 'name'. # rule main-target ( name ) { if ! $(self.built-main-targets) { build-main-targets ; } return $(self.main-target.$(name)) ; } # Returns whether a main target with the specified name exists. # rule has-main-target ( name ) { if ! $(self.built-main-targets) { build-main-targets ; } if $(self.main-target.$(name)) { return true ; } } # Worker function for the find rule not implementing any caching and simply # returning nothing in case the target can not be found. # rule find-really ( id ) { local result ; local current-location = [ get location ] ; local split = [ MATCH (.*)//(.*) : $(id) ] ; local project-part = $(split[1]) ; local target-part = $(split[2]) ; local extra-error-message ; if $(project-part) { # There is an explicitly specified project part in id. Looks up the # project and passes the request to it. local pm = [ project.find $(project-part) : $(current-location) ] ; if $(pm) { project-target = [ project.target $(pm) ] ; result = [ $(project-target).find $(target-part) : no-error ] ; } else { # TODO: This extra error message will not get displayed most # likely due to some buggy refactoring. Refactor the code so the # message gets diplayed again. extra-error-message = error: could not find project '$(project-part)' ; } } else { # Interpret target-name as name of main target. Need to do this # before checking for file. Consider the following scenario with a # toolset not modifying its executable's names, e.g. gcc on # Unix-like platforms: # # exe test : test.cpp ; # install s : test : <location>. ; # # After the first build we would have a target named 'test' in the # Jamfile and a file named 'test' on the disk. We need the target to # override the file. result = [ main-target $(id) ] ; # Interpret id as an existing file reference. if ! $(result) { result = [ new file-reference [ path.make $(id) ] : $(self.project) ] ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -