2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-20 14:42:14 +00:00

First implementation of "stage" and "prebuilt" rule.

* new/common.jam (copy): New rule.

* new/targets.jam (main-target.generate): Use a different
   algorith for selecting subvariant. Favour one with
   the longest intersection of requirements with build
   properties.

* new/virtual-target.jam (virtual-target): Eliminate 'subvariant'
   attribute. Use properties of action to for the same
   purpose. New methods 'set-path' and 'extra-grist'.


[SVN r16129]
This commit is contained in:
Vladimir Prus
2002-11-06 10:26:11 +00:00
parent e147aa0b32
commit 24d1722d55
38 changed files with 606 additions and 94 deletions

View File

@@ -14,8 +14,10 @@ import generators ;
import regex ;
import virtual-target ;
import os ;
import stage ;
import prebuilt ;
feature toolset : gcc : implicit propagated ;
feature toolset : gcc : implicit propagated link-incompatible ;
feature shared : false true : propagated ;
feature optimization : off on : propagated ;
feature threading : single multi : link-incompatible propagated ;

View File

@@ -61,3 +61,14 @@ actions piecemeal together existing Clean
rm $(>)
}
rule copy
{
}
actions copy
{
cp $(>) $(<)
}

56
new/prebuilt.jam Normal file
View File

@@ -0,0 +1,56 @@
# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears in
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
# This module defines the 'prebuilt' rule, which allows to use targets
# created outside of Boost.Build, or for which no source is available..
import targets ;
import class : class new ;
import property ;
import errors : error ;
import type : type ;
import regex ;
rule prebuilt-target-class ( name : project : type file : requirements * : use-requirements * )
{
abstract-target.__init__ $(name) : $(project) ;
self.type = $(type) ;
self.file = $(file) ;
self.requirements = $(requirements) ;
self.use-requirements = $(use-requirements) ;
rule generate ( properties * )
{
local pl = [ project.attribute $(self.project) location ] ;
local path = [ path.root [ path.native $(self.file:D) ] $(pl) ] ;
# CONSIDER: refine properties?
local t = [ new virtual-target $(self.file:S=:D=) : $(self.type)
: $(self.project) ] ;
$(t).set-use-requirements $(self.use-requirements) ;
$(t).set-path $(path) ;
$(t).extra-grist [ property.as-path $(self.requirements) ] ;
$(t).suffix [ MATCH .(.*) : $(self.file:S) ] ;
return $(t) ;
}
rule requirements ( )
{
return $(self.requirements) ;
}
}
class prebuilt-target-class : abstract-target ;
rule prebuilt ( type target-name : file : requirements * : use-requirements * )
{
targets.main-target-alternative
$(target-name) [ CALLER_MODULE ] prebuilt-target-class : 2 : 3 :
: $(type) $(file) : $(requirements) : $(use-requirements) ;
}
IMPORT $(__name__) : prebuilt : : prebuilt ;

56
new/stage.jam Normal file
View File

@@ -0,0 +1,56 @@
# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears in
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
# This module defines the 'stage' rule, used to copy a set of targets to
# a single location
import targets ;
import class : class new ;
import property ;
import errors : error ;
import type : type ;
import regex ;
rule stage-target-class ( name-and-dir : project : sources * : requirements * : default-build * )
{
basic-target.__init__ $(name-and-dir) : $(project) : $(sources) : $(requirements)
: $(default-build) ;
rule construct ( source-targets * : properties * )
{
local result ;
for local i in $(source-targets)
{
local i2 = [ new virtual-target [ $(i).name ] : [ $(i).type ]
: $(self.project) ] ;
local a = [ new action $(i2) : $(i) : common.copy ] ;
$(i2).action $(a) ;
local pl = [ project.attribute $(self.project) location ] ;
local path = [ path.root [ path.native $(self.name) ] $(pl) ] ;
$(i2).set-path $(path) ;
$(i2).extra-grist stage-$(self.name) ;
result += $(i2) ;
}
return $(result) ;
}
}
class stage-target-class : basic-target ;
rule stage ( directory : sources * : requirements * : default-build * )
{
# FIXME: for now, just use directory as target name. We really
# need to implement unnamed main targets.
targets.main-target-alternative
$(directory) [ CALLER_MODULE ] stage-target-class : 2 : : 3
: $(sources) : $(requirements) : $(default-build) ;
}
IMPORT $(__name__) : stage : : stage ;

View File

@@ -237,7 +237,7 @@ rule main-target ( name : project )
else
{
# Find the alternative with the longest set of non-free and
# non-indicental requirements
# non-indicental requirements and are in 'properties'
local r = [ $(alternatives).indices ] ;
# First compute the length of requirements sets
@@ -245,28 +245,22 @@ rule main-target ( name : project )
for local p in $(r)
{
local target = [ $(alternatives).at $(p) : 1 ] ;
assert.equal [ is-a $(target) : basic-target ] : true ;
local props = [ $(target).requirements ] ;
req-length += [ sequence.length [ property.remove free :
[ $(target).requirements ] ] ] ;
# FIXME: in general, 'abstract-target' derivatives might not
# have 'requirements' method.
# assert.equal [ is-a $(target) : basic-target ] : true ;
local req = [ $(target).requirements ] ;
req = [ property.remove free incidental : $(req) ] ;
req-length += [ sequence.length
[ set.intersection $(req) : $(properties) ] ] ;
}
# Then find if there's single requirements set with maximum length
local req-length2 = [ sequence.insertion-sort $(req-length) ] ;
if $(req-length2[-1]) != $(req-length2[-2])
{
# Have signle maximum value
local max-length = $(req-length2[-1]) ;
local best ;
while $(r) && ! $(best)
{
if $(req-length[$(r[1])]) = $(max-length)
{
best = [ $(alternatives).get-at $(r[1]) ] ;
}
r = $(r[2-]) ;
}
result = $(best[2-]) ;
local best = [ sequence.select-highest-ranked $(r) : $(req-length) ] ;
if ! $(best[2])
{
local index = $(best[1]) ;
result = [ $(alternatives).get-at $(index) ] ;
result = $(result[2-]) ;
}
else
{
@@ -382,7 +376,7 @@ rule basic-target ( name : project
[ property.refine $(properties) : $(self.requirements) ] ;
rproperties = [ property.evaluate-conditionals $(rproperties) ] ;
if $(rproperties[1]) != "@error"
{
# TODO: issue a warning when requirements change properties, but
@@ -472,7 +466,7 @@ rule basic-target ( name : project
return [ $(main-target).generate $(rproperties) ] ;
}
}
# Constructs the virtual targets for this abstract targets and
# the dependecy graph. Returns the list of virtual targets.
# Should be overrided in derived classes.

View File

@@ -40,6 +40,14 @@ rule virtual-target ( name : type ? : project )
}
return $(self.suffix) ;
}
# Sets the path. When generating target name, it will override any path
# computation from properties.
rule set-path ( path )
{
self.path = $(path) ;
}
# Property set that distinguishes different variants of a target.
# May be a subset of the property set that is used for building.
@@ -106,6 +114,13 @@ rule virtual-target ( name : type ? : project )
{
self.extra-path = $(p) ;
}
# Specifies an extra grist to be added to the target name.
rule extra-grist ( g )
{
self.extra-grist = $(g) ;
}
# Generates all the actual targets and build instructions needed to build
# this target. Returns the actual target name. Can be called several times.
@@ -181,7 +196,13 @@ rule virtual-target ( name : type ? : project )
DEPENDS $(name) : $(path) ;
common.MkDir $(path) ;
common.Clean clean : $(name) ;
} else {
}
else if $(self.path)
{
LOCATE on $(name) = $(self.path) ;
}
else
{
SEARCH on $(name) =
[ path.native [ project.attribute $(self.project) source-location ] ] ;
}
@@ -251,7 +272,11 @@ rule virtual-target ( name : type ? : project )
{
grist = $(location-grist) ;
}
if $(self.extra-grist)
{
grist = $(grist)/$(self.extra-grist) ;
}
if $(self.suffix)
{
self.actual-name = [ sequence.join <$(grist)>$(self.name)
@@ -273,13 +298,20 @@ rule virtual-target ( name : type ? : project )
# Returns the directory for this target
rule path ( )
{
local path = [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ;
if $(self.path)
{
return $(self.path) ;
}
else
{
local path = [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ;
return [ path.native $(path) ] ;
return [ path.native $(path) ] ;
}
}
}

26
test/prebuilt.py Normal file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/python
# Test that we can use already built sources
from BoostBuild import Tester
t = Tester()
t.set_tree('prebuilt')
# First, build the external project
t.run_build_system("debug release", subdir="ext")
# Then pretend that we don't have the sources for the external project,
# and can only use compiled binaries
t.copy("ext/Jamfile2", "ext/Jamfile")
# Now check that we can build the main project, and that
# correct prebuilt file is picked, depending of variant.
# This also checks that correct includes for prebuilt
# libraries are used.
t.run_build_system("debug release")
t.expect_addition("bin/gcc/debug/main-target-hello/hello")
t.expect_addition("bin/gcc/release/main-target-hello/hello")
t.cleanup()

9
test/prebuilt/Jamfile Normal file
View File

@@ -0,0 +1,9 @@
project test
: requirements <variant>release:<define>RELEASE
;
use-project /ext : ext ;
exe hello : hello.cpp @/ext/a ;

View File

@@ -0,0 +1,6 @@
project ext
: requirements <variant>release:<define>RELEASE
;
lib a : a.cpp ;

View File

@@ -0,0 +1,15 @@
project ext ;
prebuilt LIB a
: bin/gcc/debug/a.a
: <variant>debug
: <include>debug
;
prebuilt LIB a
: bin/gcc/release/a.a
: <variant>release
: <include>release
;

6
test/prebuilt/ext/a.cpp Normal file
View File

@@ -0,0 +1,6 @@
#ifdef RELEASE
void release() {}
#else
void debug() {}
#endif

View File

@@ -0,0 +1,2 @@
void debug();

View File

@@ -0,0 +1,2 @@
import gcc ;

View File

@@ -0,0 +1,2 @@
void release();

11
test/prebuilt/hello.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include <a.h>
int main()
{
#ifdef RELEASE
release();
#else
debug();
#endif
}

View File

@@ -0,0 +1,2 @@
import gcc ;

View File

@@ -71,22 +71,25 @@ expected="""warning: skipping build of project /mylib at lib2
t.run_build_system("rtti=on", stdout=expected, status=None)
# We don't yet make targets depend on Jamfile, so need to start from scratch
t.set_tree("project-test4")
t.copy("Jamfile2", "Jamfile")
# The following test is disabled, because of problems related to
# issue 634319
t.run_build_system()
#t.set_tree("project-test4")
#t.copy("Jamfile2", "Jamfile")
t.expect_addition("bin/gcc/debug/a_gcc.obj")
t.expect_content("bin/gcc/debug/a_gcc.obj",
"""gcc/debug
a_gcc.cpp
""")
#t.run_build_system()
t.expect_content("bin/gcc/debug/a.exe",
"gcc/debug\n" +
"bin/gcc/debug/a.obj " +
"lib/bin/gcc/debug/optimization-on/b.obj " +
"bin/gcc/debug/a_gcc.obj\n"
)
#t.expect_addition("bin/gcc/debug/a_gcc.obj")
#t.expect_content("bin/gcc/debug/a_gcc.obj",
#"""gcc/debug
#a_gcc.cpp
#""")
#t.expect_content("bin/gcc/debug/a.exe",
#"gcc/debug\n" +
#"bin/gcc/debug/a.obj " +
#"lib/bin/gcc/debug/optimization-on/b.obj " +
#"bin/gcc/debug/a_gcc.obj\n"
#)
t.cleanup()

19
test/stage.py Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/python
# Test staging
from BoostBuild import Tester
t = Tester()
t.write("project-root.jam", "import gcc ;")
t.write("Jamfile", """
lib a : a.cpp ;
stage dist : a a.h ;
""")
t.write("a.cpp", "")
t.write("a.h", "")
t.run_build_system()
t.expect_addition(["dist/a.a", "dist/a.h"])
t.cleanup()

View File

@@ -30,3 +30,5 @@ import default_build
import main_properties
import use_requirements
import conditionals
import stage
import prebuilt

View File

@@ -237,7 +237,7 @@ rule main-target ( name : project )
else
{
# Find the alternative with the longest set of non-free and
# non-indicental requirements
# non-indicental requirements and are in 'properties'
local r = [ $(alternatives).indices ] ;
# First compute the length of requirements sets
@@ -245,28 +245,22 @@ rule main-target ( name : project )
for local p in $(r)
{
local target = [ $(alternatives).at $(p) : 1 ] ;
assert.equal [ is-a $(target) : basic-target ] : true ;
local props = [ $(target).requirements ] ;
req-length += [ sequence.length [ property.remove free :
[ $(target).requirements ] ] ] ;
# FIXME: in general, 'abstract-target' derivatives might not
# have 'requirements' method.
# assert.equal [ is-a $(target) : basic-target ] : true ;
local req = [ $(target).requirements ] ;
req = [ property.remove free incidental : $(req) ] ;
req-length += [ sequence.length
[ set.intersection $(req) : $(properties) ] ] ;
}
# Then find if there's single requirements set with maximum length
local req-length2 = [ sequence.insertion-sort $(req-length) ] ;
if $(req-length2[-1]) != $(req-length2[-2])
{
# Have signle maximum value
local max-length = $(req-length2[-1]) ;
local best ;
while $(r) && ! $(best)
{
if $(req-length[$(r[1])]) = $(max-length)
{
best = [ $(alternatives).get-at $(r[1]) ] ;
}
r = $(r[2-]) ;
}
result = $(best[2-]) ;
local best = [ sequence.select-highest-ranked $(r) : $(req-length) ] ;
if ! $(best[2])
{
local index = $(best[1]) ;
result = [ $(alternatives).get-at $(index) ] ;
result = $(result[2-]) ;
}
else
{
@@ -382,7 +376,7 @@ rule basic-target ( name : project
[ property.refine $(properties) : $(self.requirements) ] ;
rproperties = [ property.evaluate-conditionals $(rproperties) ] ;
if $(rproperties[1]) != "@error"
{
# TODO: issue a warning when requirements change properties, but
@@ -472,7 +466,7 @@ rule basic-target ( name : project
return [ $(main-target).generate $(rproperties) ] ;
}
}
# Constructs the virtual targets for this abstract targets and
# the dependecy graph. Returns the list of virtual targets.
# Should be overrided in derived classes.

View File

@@ -40,6 +40,14 @@ rule virtual-target ( name : type ? : project )
}
return $(self.suffix) ;
}
# Sets the path. When generating target name, it will override any path
# computation from properties.
rule set-path ( path )
{
self.path = $(path) ;
}
# Property set that distinguishes different variants of a target.
# May be a subset of the property set that is used for building.
@@ -106,6 +114,13 @@ rule virtual-target ( name : type ? : project )
{
self.extra-path = $(p) ;
}
# Specifies an extra grist to be added to the target name.
rule extra-grist ( g )
{
self.extra-grist = $(g) ;
}
# Generates all the actual targets and build instructions needed to build
# this target. Returns the actual target name. Can be called several times.
@@ -181,7 +196,13 @@ rule virtual-target ( name : type ? : project )
DEPENDS $(name) : $(path) ;
common.MkDir $(path) ;
common.Clean clean : $(name) ;
} else {
}
else if $(self.path)
{
LOCATE on $(name) = $(self.path) ;
}
else
{
SEARCH on $(name) =
[ path.native [ project.attribute $(self.project) source-location ] ] ;
}
@@ -251,7 +272,11 @@ rule virtual-target ( name : type ? : project )
{
grist = $(location-grist) ;
}
if $(self.extra-grist)
{
grist = $(grist)/$(self.extra-grist) ;
}
if $(self.suffix)
{
self.actual-name = [ sequence.join <$(grist)>$(self.name)
@@ -273,13 +298,20 @@ rule virtual-target ( name : type ? : project )
# Returns the directory for this target
rule path ( )
{
local path = [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ;
if $(self.path)
{
return $(self.path) ;
}
else
{
local path = [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ;
return [ path.native $(path) ] ;
return [ path.native $(path) ] ;
}
}
}

26
v2/test/prebuilt.py Normal file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/python
# Test that we can use already built sources
from BoostBuild import Tester
t = Tester()
t.set_tree('prebuilt')
# First, build the external project
t.run_build_system("debug release", subdir="ext")
# Then pretend that we don't have the sources for the external project,
# and can only use compiled binaries
t.copy("ext/Jamfile2", "ext/Jamfile")
# Now check that we can build the main project, and that
# correct prebuilt file is picked, depending of variant.
# This also checks that correct includes for prebuilt
# libraries are used.
t.run_build_system("debug release")
t.expect_addition("bin/gcc/debug/main-target-hello/hello")
t.expect_addition("bin/gcc/release/main-target-hello/hello")
t.cleanup()

9
v2/test/prebuilt/Jamfile Normal file
View File

@@ -0,0 +1,9 @@
project test
: requirements <variant>release:<define>RELEASE
;
use-project /ext : ext ;
exe hello : hello.cpp @/ext/a ;

View File

@@ -0,0 +1,6 @@
project ext
: requirements <variant>release:<define>RELEASE
;
lib a : a.cpp ;

View File

@@ -0,0 +1,15 @@
project ext ;
prebuilt LIB a
: bin/gcc/debug/a.a
: <variant>debug
: <include>debug
;
prebuilt LIB a
: bin/gcc/release/a.a
: <variant>release
: <include>release
;

View File

@@ -0,0 +1,6 @@
#ifdef RELEASE
void release() {}
#else
void debug() {}
#endif

View File

@@ -0,0 +1,2 @@
void debug();

View File

@@ -0,0 +1,2 @@
import gcc ;

View File

@@ -0,0 +1,2 @@
void release();

View File

@@ -0,0 +1,11 @@
#include <a.h>
int main()
{
#ifdef RELEASE
release();
#else
debug();
#endif
}

View File

@@ -0,0 +1,2 @@
import gcc ;

View File

@@ -71,22 +71,25 @@ expected="""warning: skipping build of project /mylib at lib2
t.run_build_system("rtti=on", stdout=expected, status=None)
# We don't yet make targets depend on Jamfile, so need to start from scratch
t.set_tree("project-test4")
t.copy("Jamfile2", "Jamfile")
# The following test is disabled, because of problems related to
# issue 634319
t.run_build_system()
#t.set_tree("project-test4")
#t.copy("Jamfile2", "Jamfile")
t.expect_addition("bin/gcc/debug/a_gcc.obj")
t.expect_content("bin/gcc/debug/a_gcc.obj",
"""gcc/debug
a_gcc.cpp
""")
#t.run_build_system()
t.expect_content("bin/gcc/debug/a.exe",
"gcc/debug\n" +
"bin/gcc/debug/a.obj " +
"lib/bin/gcc/debug/optimization-on/b.obj " +
"bin/gcc/debug/a_gcc.obj\n"
)
#t.expect_addition("bin/gcc/debug/a_gcc.obj")
#t.expect_content("bin/gcc/debug/a_gcc.obj",
#"""gcc/debug
#a_gcc.cpp
#""")
#t.expect_content("bin/gcc/debug/a.exe",
#"gcc/debug\n" +
#"bin/gcc/debug/a.obj " +
#"lib/bin/gcc/debug/optimization-on/b.obj " +
#"bin/gcc/debug/a_gcc.obj\n"
#)
t.cleanup()

19
v2/test/stage.py Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/python
# Test staging
from BoostBuild import Tester
t = Tester()
t.write("project-root.jam", "import gcc ;")
t.write("Jamfile", """
lib a : a.cpp ;
stage dist : a a.h ;
""")
t.write("a.cpp", "")
t.write("a.h", "")
t.run_build_system()
t.expect_addition(["dist/a.a", "dist/a.h"])
t.cleanup()

View File

@@ -30,3 +30,5 @@ import default_build
import main_properties
import use_requirements
import conditionals
import stage
import prebuilt

View File

@@ -14,8 +14,10 @@ import generators ;
import regex ;
import virtual-target ;
import os ;
import stage ;
import prebuilt ;
feature toolset : gcc : implicit propagated ;
feature toolset : gcc : implicit propagated link-incompatible ;
feature shared : false true : propagated ;
feature optimization : off on : propagated ;
feature threading : single multi : link-incompatible propagated ;

View File

@@ -61,3 +61,14 @@ actions piecemeal together existing Clean
rm $(>)
}
rule copy
{
}
actions copy
{
cp $(>) $(<)
}

56
v2/tools/prebuilt.jam Normal file
View File

@@ -0,0 +1,56 @@
# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears in
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
# This module defines the 'prebuilt' rule, which allows to use targets
# created outside of Boost.Build, or for which no source is available..
import targets ;
import class : class new ;
import property ;
import errors : error ;
import type : type ;
import regex ;
rule prebuilt-target-class ( name : project : type file : requirements * : use-requirements * )
{
abstract-target.__init__ $(name) : $(project) ;
self.type = $(type) ;
self.file = $(file) ;
self.requirements = $(requirements) ;
self.use-requirements = $(use-requirements) ;
rule generate ( properties * )
{
local pl = [ project.attribute $(self.project) location ] ;
local path = [ path.root [ path.native $(self.file:D) ] $(pl) ] ;
# CONSIDER: refine properties?
local t = [ new virtual-target $(self.file:S=:D=) : $(self.type)
: $(self.project) ] ;
$(t).set-use-requirements $(self.use-requirements) ;
$(t).set-path $(path) ;
$(t).extra-grist [ property.as-path $(self.requirements) ] ;
$(t).suffix [ MATCH .(.*) : $(self.file:S) ] ;
return $(t) ;
}
rule requirements ( )
{
return $(self.requirements) ;
}
}
class prebuilt-target-class : abstract-target ;
rule prebuilt ( type target-name : file : requirements * : use-requirements * )
{
targets.main-target-alternative
$(target-name) [ CALLER_MODULE ] prebuilt-target-class : 2 : 3 :
: $(type) $(file) : $(requirements) : $(use-requirements) ;
}
IMPORT $(__name__) : prebuilt : : prebuilt ;

56
v2/tools/stage.jam Normal file
View File

@@ -0,0 +1,56 @@
# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears in
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
# This module defines the 'stage' rule, used to copy a set of targets to
# a single location
import targets ;
import class : class new ;
import property ;
import errors : error ;
import type : type ;
import regex ;
rule stage-target-class ( name-and-dir : project : sources * : requirements * : default-build * )
{
basic-target.__init__ $(name-and-dir) : $(project) : $(sources) : $(requirements)
: $(default-build) ;
rule construct ( source-targets * : properties * )
{
local result ;
for local i in $(source-targets)
{
local i2 = [ new virtual-target [ $(i).name ] : [ $(i).type ]
: $(self.project) ] ;
local a = [ new action $(i2) : $(i) : common.copy ] ;
$(i2).action $(a) ;
local pl = [ project.attribute $(self.project) location ] ;
local path = [ path.root [ path.native $(self.name) ] $(pl) ] ;
$(i2).set-path $(path) ;
$(i2).extra-grist stage-$(self.name) ;
result += $(i2) ;
}
return $(result) ;
}
}
class stage-target-class : basic-target ;
rule stage ( directory : sources * : requirements * : default-build * )
{
# FIXME: for now, just use directory as target name. We really
# need to implement unnamed main targets.
targets.main-target-alternative
$(directory) [ CALLER_MODULE ] stage-target-class : 2 : : 3
: $(sources) : $(requirements) : $(default-build) ;
}
IMPORT $(__name__) : stage : : stage ;