2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-16 01:12:13 +00:00

Improve shared/static linking interface and

introduce separate <link-runtime> feature.
Allow to use the 'lib' rule to declare
libraries that should be searched for.

* builtin.jam: Remove 'shared' features. Introduce
   'link' and 'link-runtime'.
   (searched-lib-target): New class
   (searched-lib-generator): New generator.
   (lib-action): New class, derived from 'action'.
   Handles instances of 'searched-lib-target' in sources.
   Also, moves all libraries from sources to property value,
   so that we can repeat them twice in command line.
   (lib-generator): Generator which uses 'lib-action'.

* generators.jam: Allow empty list of sources everywhere.

* virtual-target.jam (file-target): Split into
   'abstract-file-target' and 'file-target'.
   (abstra
  (action.actualize-sources): New rule. Allows to
  handle the fact that some sources are special,
  and should not become $(>) in action body.


[SVN r16573]
This commit is contained in:
Vladimir Prus
2002-12-09 10:02:37 +00:00
parent 4ba0a5b989
commit fdc3fa6c54
20 changed files with 668 additions and 248 deletions

View File

@@ -21,7 +21,10 @@ import errors : error ;
import symlink ;
feature toolset : : implicit propagated link-incompatible symmetric ;
feature shared : false true : propagated ;
feature link : shared static : propagated ;
feature link-runtime : shared static : propagated ;
feature optimization : off on : propagated ;
feature threading : single multi : link-incompatible propagated ;
feature rtti : on off : link-incompatible propagated ;
@@ -33,10 +36,14 @@ feature version : : free ;
feature dependency : : free dependency ;
feature library : : free dependency ;
feature find-library : : free ;
feature find-shared-library : : free ;
feature find-static-library : : free ;
feature library-path : : free path ;
feature library-file : : free path ;
feature name : : free ;
feature search : : free path ;
feature variant : : implicit composite propagated symmetric ;
# Declares a new variant.
@@ -121,6 +128,45 @@ IMPORT $(__name__) : variant : : variant ;
variant debug : <optimization>off <debug-symbols>on ;
variant release : <optimization>on <debug-symbols>off ;
rule searched-lib-target ( name
: project
: shared ?
: real-name ?
: search *
)
{
abstract-file-target.__init__ $(name) : SEARCHED_LIB : $(project) ;
self.shared = $(shared) ;
self.real-name = $(real-name) ;
self.real-name ?= $(name) ;
self.search = $(search) ;
rule shared ( )
{
return $(self.shared) ;
}
rule real-name ( )
{
return $(self.real-name) ;
}
rule search ( )
{
return $(self.search) ;
}
rule actualize-location ( target )
{
NOTFILE $(target) ;
}
}
class searched-lib-target : abstract-file-target ;
type.register LIB : : : main ;
# register the given type on the specified OSes, or on remaining OSes
@@ -146,6 +192,8 @@ declare-type : STATIC_LIB : a : LIB : main ;
declare-type NT : SHARED_LIB : dll : LIB : main ;
declare-type : SHARED_LIB : so : LIB : main ;
declare-type : SEARCHED_LIB : : LIB : main ;
declare-type NT CYGWIN : EXE : exe : : main ;
declare-type : EXE : : : main ;
@@ -238,11 +286,15 @@ rule lib-generator ( )
{
composing-generator.__init__ lib-generator : unknown-source-type : LIB : <main-target-type>LIB ;
rule run ( project name ? : properties * : sources + )
rule run ( project name ? : properties * : sources * )
{
# Determine the needed target type
local actual-type ;
if <shared>true in $(properties)
if <search> in $(properties:G) || <name> in $(properties:G)
{
actual-type = SEARCHED_LIB ;
}
else if <link>shared in $(properties)
{
actual-type = SHARED_LIB ;
}
@@ -261,6 +313,30 @@ class lib-generator : composing-generator ;
generators.register [ new lib-generator ] ;
rule searched-lib-generator ( )
{
generator.__init__ searched-lib-generator : : SEARCHED_LIB ;
rule run ( project name ? : properties * : sources * )
{
local shared ;
if <link>shared in $(properties)
{
shared = true ;
}
return [ new searched-lib-target $(name) : $(project) : $(shared)
: [ feature.get-values <name> : $(properties) ]
: [ feature.get-values <search> : $(properties) ]
] ;
}
}
class searched-lib-generator : generator ;
generators.register [ new searched-lib-generator ] ;
rule compile-action ( targets + : sources * : action-name : properties * )
{
action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ;
@@ -305,6 +381,92 @@ rule register-c-compiler ( id : source-types + : target-types + :
# register all generators as "generator.some-rule", not with "some-module.some-rule".)
IMPORT $(__name__) : register-c-compiler : : generators.register-c-compiler ;
rule link-action ( targets + : sources * : action-name : properties * )
{
action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ;
rule adjust-properties ( properties * )
{
local extra ;
for local s in $(self.sources)
{
if [ class.is-a $(s) : searched-lib-target ]
{
local name = [ $(s).real-name ] ;
if [ $(s).shared ]
{
extra += <find-shared-library>$(name) ;
}
else
{
extra += <find-static-library>$(name) ;
}
local search = [ $(s).search ] ;
extra += <library-path>$(search) ;
}
# We also move orginary libs form sources to
# "library" property. This allows us to
# easily repeat all the list of libs on
# command line, when it's needed.
else if [ type.is-derived [ $(s).type ] LIB ]
{
extra += <library>$(s) ;
}
}
ECHO "EXtra is " $(extra) ;
return $(properties) $(extra) ;
}
rule actualize-sources ( sources * )
{
local real-sources ;
for local s in $(sources)
{
if ! [ type.is-derived [ $(s).type ] LIB ]
{
real-sources += $(s) ;
}
else
{
self.dependency-only-sources += [ $(s).actualize ] ;
}
}
action.actualize-sources $(real-sources) ;
}
}
class link-action : action ;
rule linking-generator ( id : source-types + : target-types + :
requirements * )
{
composing-generator.__init__ $(id) : $(source-types) : $(target-types) :
$(requirements) ;
rule action-class ( )
{
return link-action ;
}
}
class linking-generator : composing-generator ;
rule register-linker ( id : source-types + : target-types + :
requirements * )
{
local g = [ new linking-generator $(id) : $(source-types)
: $(target-types) : $(requirements) ] ;
generators.register $(g) ;
}
IMPORT $(__name__) : register-linker : : generators.register-linker ;

View File

@@ -33,9 +33,9 @@ rule init ( a1 * : a2 * : a3 * )
}
# Declare generators
generators.register-composing gcc.link : LIB OBJ : EXE : <toolset>gcc ;
generators.register-linker gcc.link : LIB OBJ : EXE : <toolset>gcc ;
generators.register-composing gcc.archive : OBJ : STATIC_LIB : <toolset>gcc ;
generators.register-composing gcc.link-dll : OBJ : SHARED_LIB : <toolset>gcc ;
generators.register-linker gcc.link-dll : OBJ : SHARED_LIB : <toolset>gcc ;
generators.register-c-compiler gcc.compile : CPP : OBJ : <toolset>gcc ;
generators.register-c-compiler gcc.compile : C : OBJ : <toolset>gcc ;
@@ -55,13 +55,21 @@ actions compile
# Declare flags and action for linking
toolset.flags gcc.link OPTIONS <debug-symbols>on : -g ;
toolset.flags gcc.link LINKPATH <library-path> ;
toolset.flags gcc.link FINDLIBS <find-library> ;
toolset.flags gcc.link LIBRARIES <library-file> ;
toolset.flags gcc.link FINDLIBS-ST <find-static-library> ;
toolset.flags gcc.link FINDLIBS-SA <find-shared-library> ;
toolset.flags gcc.link LIBRARIES <library> ;
toolset.flags gcc.link LINK-RUNTIME <link-runtime>static : static ;
toolset.flags gcc.link LINK-RUNTIME <link-runtime>shared : dynamic ;
rule link ( targets * : sources * : properties * )
{
ECHO "PROPS = " $(properties) ;
}
actions link bind LIBRARIES
{
$(NAME:E=g++) $(OPTIONS) -L$(LINKPATH) -o $(<) $(>) $(LIBRARIES) -l$(FINDLIBS)
$(NAME:E=g++) $(OPTIONS) -L$(LINKPATH) -o $(<) $(>) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) -Wl,-B$(LINK-RUNTIME)
}
# Declare action for creating static libraries
@@ -73,11 +81,14 @@ actions archive
# Declare flags and action for linking shared libraries
toolset.flags gcc.link-dll OPTIONS <debug-symbols>on : -g ;
toolset.flags gcc.link-dll LINKPATH <library-path> ;
toolset.flags gcc.link-dll FINDLIBS <find-library> ;
toolset.flags gcc.link-dll LIBRARIES <library-file> ;
toolset.flags gcc.link-dll FINDLIBS-ST <find-static-library> ;
toolset.flags gcc.link-dll FINDLIBS-SA <find-shared-library> ;
toolset.flags gcc.link-dll LIBRARIES <library> ;
toolset.flags gcc.link-dll LINK-RUNTIME <link-runtime>static : static ;
toolset.flags gcc.link-dll LINK-RUNTIME <link-runtime>shared : dynamic ;
actions link-dll bind LIBS
actions link-dll bind LIBRARIES
{
$(NAME:E=g++) $(OPTIONS) -o $(<) -Wl,-soname,$(<[1]:D=) -shared $(>) $(LIBS) $(FINDLIBS)
$(NAME:E=g++) $(OPTIONS) -o $(<) -Wl,-soname,$(<[1]:D=) -shared $(>) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) -Wl,-B$(LINK-RUNTIME)
}

View File

@@ -92,7 +92,7 @@ rule generator (
id # identifies the generator - should be name of the rule which
# sets up build actions
: source-types + # types that this generator can handle
: source-types * # types that this generator can handle
: target-types-and-names +
# types the generator will create and, optionally, names for
@@ -457,6 +457,7 @@ rule register ( g )
{
.generators.$(t) += $(g) ;
}
}
@@ -486,7 +487,7 @@ rule register-composing ( id : source-types + : target-types + : requirements *
rule try-one-generator ( project name ? : generator multiple ? :
target-types + : properties * : sources + )
target-types + : properties * : sources * )
{
generators.dout [ indent ] " trying generator" [ $(generator).id ]
"for" $(target-types:J=" ") "(" $(multiple) ")" ;
@@ -752,7 +753,7 @@ local rule select-dependency-graph ( options )
# 'construct' in stack, returns only targets of requested 'target-type',
# otherwise, returns also unused sources and additionally generated
# targets.
rule construct ( project name ? : target-type multiple ? : properties * : sources +
rule construct ( project name ? : target-type multiple ? : properties * : sources *
: allow-composing ? # Allows to use composing generators for constructing this
# target. This will be typically set when creating main targets,
# and unset when called recursively from 'run' method of

View File

@@ -137,7 +137,9 @@ rule virtual-target ( name # Name of this target -- specifies the name of
class virtual-target ;
# Target which correspond to a file.
# Target which correspond to a file. The exact mapping for file
# is not yet specified in this class. (TODO: Actually, the class name
# could be better...)
#
# May be a source file (when no action is specified), or
# derived file (otherwise).
@@ -146,19 +148,7 @@ class virtual-target ;
# properties of action (for derived files), and the value
# passed to 'extra-grist'.
#
# The file path is determined as
# - value passed to the 'set-path' method, if any
# - for derived files, project's build dir, joined with components
# that describe action's properties. If the free properties
# are not equal to the project's reference properties
# an element with name of main target is added.
# - for source files, project's source dir
#
# The file suffix is
# - the value passed to the 'suffix' method, if any, or
# - the suffix which correspond to the target's type.
#
rule file-target ( name
rule abstract-file-target ( name
: type ? # Optional type for this target
: project
)
@@ -258,43 +248,7 @@ rule file-target ( name
common.Clean clean : $(name) ;
}
}
rule actualize-location ( target )
{
compute-extra-path ;
if $(self.path)
{
LOCATE on $(target) = $(self.path) ;
# Make sure the path exists. Do this only
# for derived files.
if $(self.action)
{
DEPENDS $(target) : $(self.path) ;
common.MkDir $(self.path) ;
}
}
else if $(self.action)
{
# This is a derived file.
local path = [ path.native [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ] ;
LOCATE on $(target) = $(path) ;
# Make sure the path exists.
DEPENDS $(target) : $(path) ;
common.MkDir $(path) ;
}
else
{
# This is a source file.
SEARCH on $(target) =
[ path.native [ project.attribute $(self.project) source-location ] ] ;
}
}
rule str ( )
{
local action = [ action ] ;
@@ -377,6 +331,92 @@ rule file-target ( name
return $(self.actual-name) ;
}
}
class abstract-file-target : virtual-target ;
# File target with explicitly known location.
#
# The file path is determined as
# - value passed to the 'set-path' method, if any
# - for derived files, project's build dir, joined with components
# that describe action's properties. If the free properties
# are not equal to the project's reference properties
# an element with name of main target is added.
# - for source files, project's source dir
#
# The file suffix is
# - the value passed to the 'suffix' method, if any, or
# - the suffix which correspond to the target's type.
#
rule file-target (
name
: type ? # Optional type for this target
: project
)
{
abstract-file-target.__init__ $(name) : $(type) : $(project) ;
rule actualize-location ( target )
{
compute-extra-path ;
if $(self.path)
{
LOCATE on $(target) = $(self.path) ;
# Make sure the path exists. Do this only
# for derived files.
if $(self.action)
{
DEPENDS $(target) : $(self.path) ;
common.MkDir $(self.path) ;
}
}
else if $(self.action)
{
# This is a derived file.
local path = [ path.native [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ] ;
LOCATE on $(target) = $(path) ;
# Make sure the path exists.
DEPENDS $(target) : $(path) ;
common.MkDir $(path) ;
}
else
{
# This is a source file.
SEARCH on $(target) =
[ path.native [ project.attribute $(self.project) source-location ] ] ;
}
}
rule compute-extra-path ( )
{
if $(self.action)
{
local properties = [ property.take free : [ property.remove incidental :
[ $(self.action).properties ] ] ] ;
local main-target = [ $(self.dg).main-target ] ;
local project = [ $(main-target).project ] ;
local plocation = [ project.attribute $(project) location ] ;
local ptarget = [ project.target $(plocation) ] ;
local ref = [ $(ptarget).reference-properties [ $(self.dg).properties ] ] ;
properties = [ sequence.insertion-sort
[ sequence.unique $(properties) ] ] ;
ref = [ sequence.insertion-sort
[ sequence.unique $(ref) ] ] ;
if $(properties) != $(ref)
{
self.extra-path = [ sequence.join main-target- [ $(main-target).name ] ] ;
}
}
}
# Returns the directory for this target
# ### This partly DUPLICATES functionality of actualize-location
# above. Seems like subvariant-dg.all-target-paths is the only method
@@ -398,30 +438,13 @@ rule file-target ( name
return [ path.native $(path) ] ;
}
}
rule compute-extra-path ( )
{
if $(self.action)
{
local properties = [ property.take free : [ property.remove incidental :
[ $(self.action).properties ] ] ] ;
local main-target = [ $(self.dg).main-target ] ;
local project = [ $(main-target).project ] ;
local plocation = [ project.attribute $(project) location ] ;
local ptarget = [ project.target $(plocation) ] ;
local ref = [ $(ptarget).reference-properties [ $(self.dg).properties ] ] ;
if $(properties) != $(ref)
{
self.extra-path = [ sequence.join main-target- [ $(main-target).name ] ] ;
}
}
}
}
}
class file-target : virtual-target ;
class file-target : abstract-file-target ;
# Returns the binding for the given actual target.
# CONSIDER: not sure this rule belongs here.
@@ -479,34 +502,47 @@ rule action ( targets + : sources * : action-name : properties * )
local properties = [ adjust-properties [ properties ] ] ;
local actual-targets ;
for local i in [ targets ]
{
actual-targets += [ $(i).actualize ] ;
}
actualize-sources [ sources ] ;
DEPENDS $(actual-targets) : $(self.actual-sources) $(self.dependency-only-sources) ;
local actual-sources ;
for local i in [ sources ]
{
local scanner ;
if [ $(i).type ]
{
scanner =
[ type.get-scanner [ $(i).type ] : $(properties) ] ;
}
actual-sources += [ $(i).actualize $(scanner) ] ;
}
DEPENDS $(actual-targets) : $(actual-sources) ;
toolset.set-target-variables $(self.action-name) $(actual-targets[0]) :
$(properties) ;
toolset.set-target-variables $(self.action-name) $(actual-targets[0]) :
$(properties) ;
$(self.action-name)
$(actual-targets) : $(actual-sources) : $(properties) ;
$(actual-targets) : $(self.actual-sources) : $(properties) ;
}
}
# Creates actual jam targets for sources. Initialized two member
# variables:.
# 'self.actual-sources' -- sources which are passed to updating action
# 'self.dependency-only-sources' -- sources which are made dependencies, but
# are not used otherwise.
#
# New values will be *appended* to the variables. They may be non-empty,
# if caller wants it.
rule actualize-sources ( sources * )
{
for local i in $(sources)
{
local scanner ;
if [ $(i).type ]
{
scanner =
[ type.get-scanner [ $(i).type ] : $(properties) ] ;
}
self.actual-sources += [ $(i).actualize $(scanner) ] ;
}
}
rule path ( )
{
local subvariant = [ property.remove free incidental : $(self.properties) ] ;

View File

@@ -10,19 +10,19 @@ t = Tester()
t.write("project-root.jam", "import gcc ;")
t.write("a.cpp", """
#ifdef SHARED
#ifdef STATIC
int main() {}
#endif
""")
t.write("Jamfile", "exe a : a.cpp : <shared>true:<define>SHARED ;")
t.run_build_system("shared=true")
t.expect_addition("bin/gcc/debug/shared-true/main-target-a/a")
t.write("Jamfile", "exe a : a.cpp : <link>static:<define>STATIC ;")
t.run_build_system("link=static")
t.expect_addition("bin/gcc/debug/link-static/main-target-a/a")
t.write("Jamfile", """
project : requirements <shared>true:<define>SHARED ;
project : requirements <link>static:<define>STATIC ;
exe a : a.cpp ;
""")
t.run_build_system("shared=true")
t.expect_addition("bin/gcc/debug/shared-true/a")
t.run_build_system("link=static")
t.expect_addition("bin/gcc/debug/link-static/a")
t.cleanup()

View File

@@ -10,6 +10,6 @@ t = Tester()
t.set_tree("direct-request-test")
t.run_build_system(extra_args="define=MACROS")
t.expect_addition("bin/gcc/debug/" * List("a.o b.o b.a a"))
t.expect_addition("bin/gcc/debug/" * List("a.o b.o b.so a"))
t.cleanup()

View File

@@ -19,10 +19,10 @@ t.expect_addition(["lib/bin/gcc/debug/c.o",
t.run_build_system(subdir='lib')
t.expect_addition(["lib/bin/gcc/debug/auxilliary2.a"])
t.expect_addition(["lib/bin/gcc/debug/auxilliary2.so"])
t.run_build_system(subdir='lib', extra_args="shared=true")
t.run_build_system(subdir='lib', extra_args="link=static")
t.expect_addition(["lib/bin/gcc/debug/shared-true/auxilliary2.so"])
t.expect_addition(["lib/bin/gcc/debug/link-static/auxilliary2.a"])
t.cleanup()

View File

@@ -2,13 +2,13 @@
project ext ;
prebuilt LIB a
: bin/gcc/debug/a.a
: bin/gcc/debug/a.so
: <variant>debug
: <include>debug
;
prebuilt LIB a
: bin/gcc/release/a.a
: bin/gcc/release/a.so
: <variant>release
: <include>release
;

View File

@@ -45,9 +45,9 @@ t.run_build_system("--no-error-backtrace", stdout=expected, status=None)
t.copy("lib/Jamfile3", "lib/Jamfile")
expected="""warning: skipped build of lib/b.obj with properties <toolset>gcc
<shared>false <optimization>on <threading>single <rtti>on <debug-symbols>on
<variant>debug
expected="""warning: skipped build of lib/b.obj with properties <toolset>gcc <link>shared
<link-runtime>shared <optimization>on <threading>single <rtti>on
<debug-symbols>on <variant>debug
don't know how to make <.>lib/b.obj/<optimization>on
...skipped <./gcc/debug>a.exe for lack of <.>lib/b.obj/<optimization>on...
"""

View File

@@ -14,6 +14,6 @@ t.write("a.cpp", "")
t.write("a.h", "")
t.run_build_system()
t.expect_addition(["dist/a.a", "dist/a.h"])
t.expect_addition(["dist/a.so", "dist/a.h"])
t.cleanup()

View File

@@ -92,7 +92,7 @@ rule generator (
id # identifies the generator - should be name of the rule which
# sets up build actions
: source-types + # types that this generator can handle
: source-types * # types that this generator can handle
: target-types-and-names +
# types the generator will create and, optionally, names for
@@ -457,6 +457,7 @@ rule register ( g )
{
.generators.$(t) += $(g) ;
}
}
@@ -486,7 +487,7 @@ rule register-composing ( id : source-types + : target-types + : requirements *
rule try-one-generator ( project name ? : generator multiple ? :
target-types + : properties * : sources + )
target-types + : properties * : sources * )
{
generators.dout [ indent ] " trying generator" [ $(generator).id ]
"for" $(target-types:J=" ") "(" $(multiple) ")" ;
@@ -752,7 +753,7 @@ local rule select-dependency-graph ( options )
# 'construct' in stack, returns only targets of requested 'target-type',
# otherwise, returns also unused sources and additionally generated
# targets.
rule construct ( project name ? : target-type multiple ? : properties * : sources +
rule construct ( project name ? : target-type multiple ? : properties * : sources *
: allow-composing ? # Allows to use composing generators for constructing this
# target. This will be typically set when creating main targets,
# and unset when called recursively from 'run' method of

View File

@@ -137,7 +137,9 @@ rule virtual-target ( name # Name of this target -- specifies the name of
class virtual-target ;
# Target which correspond to a file.
# Target which correspond to a file. The exact mapping for file
# is not yet specified in this class. (TODO: Actually, the class name
# could be better...)
#
# May be a source file (when no action is specified), or
# derived file (otherwise).
@@ -146,19 +148,7 @@ class virtual-target ;
# properties of action (for derived files), and the value
# passed to 'extra-grist'.
#
# The file path is determined as
# - value passed to the 'set-path' method, if any
# - for derived files, project's build dir, joined with components
# that describe action's properties. If the free properties
# are not equal to the project's reference properties
# an element with name of main target is added.
# - for source files, project's source dir
#
# The file suffix is
# - the value passed to the 'suffix' method, if any, or
# - the suffix which correspond to the target's type.
#
rule file-target ( name
rule abstract-file-target ( name
: type ? # Optional type for this target
: project
)
@@ -258,43 +248,7 @@ rule file-target ( name
common.Clean clean : $(name) ;
}
}
rule actualize-location ( target )
{
compute-extra-path ;
if $(self.path)
{
LOCATE on $(target) = $(self.path) ;
# Make sure the path exists. Do this only
# for derived files.
if $(self.action)
{
DEPENDS $(target) : $(self.path) ;
common.MkDir $(self.path) ;
}
}
else if $(self.action)
{
# This is a derived file.
local path = [ path.native [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ] ;
LOCATE on $(target) = $(path) ;
# Make sure the path exists.
DEPENDS $(target) : $(path) ;
common.MkDir $(path) ;
}
else
{
# This is a source file.
SEARCH on $(target) =
[ path.native [ project.attribute $(self.project) source-location ] ] ;
}
}
rule str ( )
{
local action = [ action ] ;
@@ -377,6 +331,92 @@ rule file-target ( name
return $(self.actual-name) ;
}
}
class abstract-file-target : virtual-target ;
# File target with explicitly known location.
#
# The file path is determined as
# - value passed to the 'set-path' method, if any
# - for derived files, project's build dir, joined with components
# that describe action's properties. If the free properties
# are not equal to the project's reference properties
# an element with name of main target is added.
# - for source files, project's source dir
#
# The file suffix is
# - the value passed to the 'suffix' method, if any, or
# - the suffix which correspond to the target's type.
#
rule file-target (
name
: type ? # Optional type for this target
: project
)
{
abstract-file-target.__init__ $(name) : $(type) : $(project) ;
rule actualize-location ( target )
{
compute-extra-path ;
if $(self.path)
{
LOCATE on $(target) = $(self.path) ;
# Make sure the path exists. Do this only
# for derived files.
if $(self.action)
{
DEPENDS $(target) : $(self.path) ;
common.MkDir $(self.path) ;
}
}
else if $(self.action)
{
# This is a derived file.
local path = [ path.native [ path.join
[ project.attribute $(self.project) location ]
[ $(self.action).path ]
$(self.extra-path)
] ] ;
LOCATE on $(target) = $(path) ;
# Make sure the path exists.
DEPENDS $(target) : $(path) ;
common.MkDir $(path) ;
}
else
{
# This is a source file.
SEARCH on $(target) =
[ path.native [ project.attribute $(self.project) source-location ] ] ;
}
}
rule compute-extra-path ( )
{
if $(self.action)
{
local properties = [ property.take free : [ property.remove incidental :
[ $(self.action).properties ] ] ] ;
local main-target = [ $(self.dg).main-target ] ;
local project = [ $(main-target).project ] ;
local plocation = [ project.attribute $(project) location ] ;
local ptarget = [ project.target $(plocation) ] ;
local ref = [ $(ptarget).reference-properties [ $(self.dg).properties ] ] ;
properties = [ sequence.insertion-sort
[ sequence.unique $(properties) ] ] ;
ref = [ sequence.insertion-sort
[ sequence.unique $(ref) ] ] ;
if $(properties) != $(ref)
{
self.extra-path = [ sequence.join main-target- [ $(main-target).name ] ] ;
}
}
}
# Returns the directory for this target
# ### This partly DUPLICATES functionality of actualize-location
# above. Seems like subvariant-dg.all-target-paths is the only method
@@ -398,30 +438,13 @@ rule file-target ( name
return [ path.native $(path) ] ;
}
}
rule compute-extra-path ( )
{
if $(self.action)
{
local properties = [ property.take free : [ property.remove incidental :
[ $(self.action).properties ] ] ] ;
local main-target = [ $(self.dg).main-target ] ;
local project = [ $(main-target).project ] ;
local plocation = [ project.attribute $(project) location ] ;
local ptarget = [ project.target $(plocation) ] ;
local ref = [ $(ptarget).reference-properties [ $(self.dg).properties ] ] ;
if $(properties) != $(ref)
{
self.extra-path = [ sequence.join main-target- [ $(main-target).name ] ] ;
}
}
}
}
}
class file-target : virtual-target ;
class file-target : abstract-file-target ;
# Returns the binding for the given actual target.
# CONSIDER: not sure this rule belongs here.
@@ -479,34 +502,47 @@ rule action ( targets + : sources * : action-name : properties * )
local properties = [ adjust-properties [ properties ] ] ;
local actual-targets ;
for local i in [ targets ]
{
actual-targets += [ $(i).actualize ] ;
}
actualize-sources [ sources ] ;
DEPENDS $(actual-targets) : $(self.actual-sources) $(self.dependency-only-sources) ;
local actual-sources ;
for local i in [ sources ]
{
local scanner ;
if [ $(i).type ]
{
scanner =
[ type.get-scanner [ $(i).type ] : $(properties) ] ;
}
actual-sources += [ $(i).actualize $(scanner) ] ;
}
DEPENDS $(actual-targets) : $(actual-sources) ;
toolset.set-target-variables $(self.action-name) $(actual-targets[0]) :
$(properties) ;
toolset.set-target-variables $(self.action-name) $(actual-targets[0]) :
$(properties) ;
$(self.action-name)
$(actual-targets) : $(actual-sources) : $(properties) ;
$(actual-targets) : $(self.actual-sources) : $(properties) ;
}
}
# Creates actual jam targets for sources. Initialized two member
# variables:.
# 'self.actual-sources' -- sources which are passed to updating action
# 'self.dependency-only-sources' -- sources which are made dependencies, but
# are not used otherwise.
#
# New values will be *appended* to the variables. They may be non-empty,
# if caller wants it.
rule actualize-sources ( sources * )
{
for local i in $(sources)
{
local scanner ;
if [ $(i).type ]
{
scanner =
[ type.get-scanner [ $(i).type ] : $(properties) ] ;
}
self.actual-sources += [ $(i).actualize $(scanner) ] ;
}
}
rule path ( )
{
local subvariant = [ property.remove free incidental : $(self.properties) ] ;

View File

@@ -33,9 +33,9 @@ rule init ( a1 * : a2 * : a3 * )
}
# Declare generators
generators.register-composing gcc.link : LIB OBJ : EXE : <toolset>gcc ;
generators.register-linker gcc.link : LIB OBJ : EXE : <toolset>gcc ;
generators.register-composing gcc.archive : OBJ : STATIC_LIB : <toolset>gcc ;
generators.register-composing gcc.link-dll : OBJ : SHARED_LIB : <toolset>gcc ;
generators.register-linker gcc.link-dll : OBJ : SHARED_LIB : <toolset>gcc ;
generators.register-c-compiler gcc.compile : CPP : OBJ : <toolset>gcc ;
generators.register-c-compiler gcc.compile : C : OBJ : <toolset>gcc ;
@@ -55,13 +55,21 @@ actions compile
# Declare flags and action for linking
toolset.flags gcc.link OPTIONS <debug-symbols>on : -g ;
toolset.flags gcc.link LINKPATH <library-path> ;
toolset.flags gcc.link FINDLIBS <find-library> ;
toolset.flags gcc.link LIBRARIES <library-file> ;
toolset.flags gcc.link FINDLIBS-ST <find-static-library> ;
toolset.flags gcc.link FINDLIBS-SA <find-shared-library> ;
toolset.flags gcc.link LIBRARIES <library> ;
toolset.flags gcc.link LINK-RUNTIME <link-runtime>static : static ;
toolset.flags gcc.link LINK-RUNTIME <link-runtime>shared : dynamic ;
rule link ( targets * : sources * : properties * )
{
ECHO "PROPS = " $(properties) ;
}
actions link bind LIBRARIES
{
$(NAME:E=g++) $(OPTIONS) -L$(LINKPATH) -o $(<) $(>) $(LIBRARIES) -l$(FINDLIBS)
$(NAME:E=g++) $(OPTIONS) -L$(LINKPATH) -o $(<) $(>) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) -Wl,-B$(LINK-RUNTIME)
}
# Declare action for creating static libraries
@@ -73,11 +81,14 @@ actions archive
# Declare flags and action for linking shared libraries
toolset.flags gcc.link-dll OPTIONS <debug-symbols>on : -g ;
toolset.flags gcc.link-dll LINKPATH <library-path> ;
toolset.flags gcc.link-dll FINDLIBS <find-library> ;
toolset.flags gcc.link-dll LIBRARIES <library-file> ;
toolset.flags gcc.link-dll FINDLIBS-ST <find-static-library> ;
toolset.flags gcc.link-dll FINDLIBS-SA <find-shared-library> ;
toolset.flags gcc.link-dll LIBRARIES <library> ;
toolset.flags gcc.link-dll LINK-RUNTIME <link-runtime>static : static ;
toolset.flags gcc.link-dll LINK-RUNTIME <link-runtime>shared : dynamic ;
actions link-dll bind LIBS
actions link-dll bind LIBRARIES
{
$(NAME:E=g++) $(OPTIONS) -o $(<) -Wl,-soname,$(<[1]:D=) -shared $(>) $(LIBS) $(FINDLIBS)
$(NAME:E=g++) $(OPTIONS) -o $(<) -Wl,-soname,$(<[1]:D=) -shared $(>) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) $(LIBRARIES) -Wl,-Bdynamic -l$(FINDLIBS-SA) -Wl,-Bstatic -l$(FINDLIBS-ST) -Wl,-B$(LINK-RUNTIME)
}

View File

@@ -10,19 +10,19 @@ t = Tester()
t.write("project-root.jam", "import gcc ;")
t.write("a.cpp", """
#ifdef SHARED
#ifdef STATIC
int main() {}
#endif
""")
t.write("Jamfile", "exe a : a.cpp : <shared>true:<define>SHARED ;")
t.run_build_system("shared=true")
t.expect_addition("bin/gcc/debug/shared-true/main-target-a/a")
t.write("Jamfile", "exe a : a.cpp : <link>static:<define>STATIC ;")
t.run_build_system("link=static")
t.expect_addition("bin/gcc/debug/link-static/main-target-a/a")
t.write("Jamfile", """
project : requirements <shared>true:<define>SHARED ;
project : requirements <link>static:<define>STATIC ;
exe a : a.cpp ;
""")
t.run_build_system("shared=true")
t.expect_addition("bin/gcc/debug/shared-true/a")
t.run_build_system("link=static")
t.expect_addition("bin/gcc/debug/link-static/a")
t.cleanup()

View File

@@ -10,6 +10,6 @@ t = Tester()
t.set_tree("direct-request-test")
t.run_build_system(extra_args="define=MACROS")
t.expect_addition("bin/gcc/debug/" * List("a.o b.o b.a a"))
t.expect_addition("bin/gcc/debug/" * List("a.o b.o b.so a"))
t.cleanup()

View File

@@ -19,10 +19,10 @@ t.expect_addition(["lib/bin/gcc/debug/c.o",
t.run_build_system(subdir='lib')
t.expect_addition(["lib/bin/gcc/debug/auxilliary2.a"])
t.expect_addition(["lib/bin/gcc/debug/auxilliary2.so"])
t.run_build_system(subdir='lib', extra_args="shared=true")
t.run_build_system(subdir='lib', extra_args="link=static")
t.expect_addition(["lib/bin/gcc/debug/shared-true/auxilliary2.so"])
t.expect_addition(["lib/bin/gcc/debug/link-static/auxilliary2.a"])
t.cleanup()

View File

@@ -2,13 +2,13 @@
project ext ;
prebuilt LIB a
: bin/gcc/debug/a.a
: bin/gcc/debug/a.so
: <variant>debug
: <include>debug
;
prebuilt LIB a
: bin/gcc/release/a.a
: bin/gcc/release/a.so
: <variant>release
: <include>release
;

View File

@@ -45,9 +45,9 @@ t.run_build_system("--no-error-backtrace", stdout=expected, status=None)
t.copy("lib/Jamfile3", "lib/Jamfile")
expected="""warning: skipped build of lib/b.obj with properties <toolset>gcc
<shared>false <optimization>on <threading>single <rtti>on <debug-symbols>on
<variant>debug
expected="""warning: skipped build of lib/b.obj with properties <toolset>gcc <link>shared
<link-runtime>shared <optimization>on <threading>single <rtti>on
<debug-symbols>on <variant>debug
don't know how to make <.>lib/b.obj/<optimization>on
...skipped <./gcc/debug>a.exe for lack of <.>lib/b.obj/<optimization>on...
"""

View File

@@ -14,6 +14,6 @@ t.write("a.cpp", "")
t.write("a.h", "")
t.run_build_system()
t.expect_addition(["dist/a.a", "dist/a.h"])
t.expect_addition(["dist/a.so", "dist/a.h"])
t.cleanup()

View File

@@ -21,7 +21,10 @@ import errors : error ;
import symlink ;
feature toolset : : implicit propagated link-incompatible symmetric ;
feature shared : false true : propagated ;
feature link : shared static : propagated ;
feature link-runtime : shared static : propagated ;
feature optimization : off on : propagated ;
feature threading : single multi : link-incompatible propagated ;
feature rtti : on off : link-incompatible propagated ;
@@ -33,10 +36,14 @@ feature version : : free ;
feature dependency : : free dependency ;
feature library : : free dependency ;
feature find-library : : free ;
feature find-shared-library : : free ;
feature find-static-library : : free ;
feature library-path : : free path ;
feature library-file : : free path ;
feature name : : free ;
feature search : : free path ;
feature variant : : implicit composite propagated symmetric ;
# Declares a new variant.
@@ -121,6 +128,45 @@ IMPORT $(__name__) : variant : : variant ;
variant debug : <optimization>off <debug-symbols>on ;
variant release : <optimization>on <debug-symbols>off ;
rule searched-lib-target ( name
: project
: shared ?
: real-name ?
: search *
)
{
abstract-file-target.__init__ $(name) : SEARCHED_LIB : $(project) ;
self.shared = $(shared) ;
self.real-name = $(real-name) ;
self.real-name ?= $(name) ;
self.search = $(search) ;
rule shared ( )
{
return $(self.shared) ;
}
rule real-name ( )
{
return $(self.real-name) ;
}
rule search ( )
{
return $(self.search) ;
}
rule actualize-location ( target )
{
NOTFILE $(target) ;
}
}
class searched-lib-target : abstract-file-target ;
type.register LIB : : : main ;
# register the given type on the specified OSes, or on remaining OSes
@@ -146,6 +192,8 @@ declare-type : STATIC_LIB : a : LIB : main ;
declare-type NT : SHARED_LIB : dll : LIB : main ;
declare-type : SHARED_LIB : so : LIB : main ;
declare-type : SEARCHED_LIB : : LIB : main ;
declare-type NT CYGWIN : EXE : exe : : main ;
declare-type : EXE : : : main ;
@@ -238,11 +286,15 @@ rule lib-generator ( )
{
composing-generator.__init__ lib-generator : unknown-source-type : LIB : <main-target-type>LIB ;
rule run ( project name ? : properties * : sources + )
rule run ( project name ? : properties * : sources * )
{
# Determine the needed target type
local actual-type ;
if <shared>true in $(properties)
if <search> in $(properties:G) || <name> in $(properties:G)
{
actual-type = SEARCHED_LIB ;
}
else if <link>shared in $(properties)
{
actual-type = SHARED_LIB ;
}
@@ -261,6 +313,30 @@ class lib-generator : composing-generator ;
generators.register [ new lib-generator ] ;
rule searched-lib-generator ( )
{
generator.__init__ searched-lib-generator : : SEARCHED_LIB ;
rule run ( project name ? : properties * : sources * )
{
local shared ;
if <link>shared in $(properties)
{
shared = true ;
}
return [ new searched-lib-target $(name) : $(project) : $(shared)
: [ feature.get-values <name> : $(properties) ]
: [ feature.get-values <search> : $(properties) ]
] ;
}
}
class searched-lib-generator : generator ;
generators.register [ new searched-lib-generator ] ;
rule compile-action ( targets + : sources * : action-name : properties * )
{
action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ;
@@ -305,6 +381,92 @@ rule register-c-compiler ( id : source-types + : target-types + :
# register all generators as "generator.some-rule", not with "some-module.some-rule".)
IMPORT $(__name__) : register-c-compiler : : generators.register-c-compiler ;
rule link-action ( targets + : sources * : action-name : properties * )
{
action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ;
rule adjust-properties ( properties * )
{
local extra ;
for local s in $(self.sources)
{
if [ class.is-a $(s) : searched-lib-target ]
{
local name = [ $(s).real-name ] ;
if [ $(s).shared ]
{
extra += <find-shared-library>$(name) ;
}
else
{
extra += <find-static-library>$(name) ;
}
local search = [ $(s).search ] ;
extra += <library-path>$(search) ;
}
# We also move orginary libs form sources to
# "library" property. This allows us to
# easily repeat all the list of libs on
# command line, when it's needed.
else if [ type.is-derived [ $(s).type ] LIB ]
{
extra += <library>$(s) ;
}
}
ECHO "EXtra is " $(extra) ;
return $(properties) $(extra) ;
}
rule actualize-sources ( sources * )
{
local real-sources ;
for local s in $(sources)
{
if ! [ type.is-derived [ $(s).type ] LIB ]
{
real-sources += $(s) ;
}
else
{
self.dependency-only-sources += [ $(s).actualize ] ;
}
}
action.actualize-sources $(real-sources) ;
}
}
class link-action : action ;
rule linking-generator ( id : source-types + : target-types + :
requirements * )
{
composing-generator.__init__ $(id) : $(source-types) : $(target-types) :
$(requirements) ;
rule action-class ( )
{
return link-action ;
}
}
class linking-generator : composing-generator ;
rule register-linker ( id : source-types + : target-types + :
requirements * )
{
local g = [ new linking-generator $(id) : $(source-types)
: $(target-types) : $(requirements) ] ;
generators.register $(g) ;
}
IMPORT $(__name__) : register-linker : : generators.register-linker ;