From fdc3fa6c54a266c678eb607e3c7d20fa4267da98 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 9 Dec 2002 10:02:37 +0000 Subject: [PATCH] Improve shared/static linking interface and introduce separate 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] --- new/builtin.jam | 170 ++++++++++++++++++++++++- new/gcc.jam | 29 +++-- new/generators.jam | 7 +- new/virtual-target.jam | 218 +++++++++++++++++++-------------- test/conditionals.py | 14 +-- test/direct_request_test.py | 2 +- test/generators_test.py | 6 +- test/prebuilt/ext/Jamfile2 | 4 +- test/project_test4.py | 6 +- test/stage.py | 2 +- v2/build/generators.jam | 7 +- v2/build/virtual-target.jam | 218 +++++++++++++++++++-------------- v2/gcc.jam | 29 +++-- v2/test/conditionals.py | 14 +-- v2/test/direct_request_test.py | 2 +- v2/test/generators_test.py | 6 +- v2/test/prebuilt/ext/Jamfile2 | 4 +- v2/test/project_test4.py | 6 +- v2/test/stage.py | 2 +- v2/tools/builtin.jam | 170 ++++++++++++++++++++++++- 20 files changed, 668 insertions(+), 248 deletions(-) diff --git a/new/builtin.jam b/new/builtin.jam index 983c111bf..bed598609 100644 --- a/new/builtin.jam +++ b/new/builtin.jam @@ -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 : off on ; variant release : on 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 : LIB ; - rule run ( project name ? : properties * : sources + ) + rule run ( project name ? : properties * : sources * ) { # Determine the needed target type local actual-type ; - if true in $(properties) + if in $(properties:G) || in $(properties:G) + { + actual-type = SEARCHED_LIB ; + } + else if 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 shared in $(properties) + { + shared = true ; + } + return [ new searched-lib-target $(name) : $(project) : $(shared) + : [ feature.get-values : $(properties) ] + : [ feature.get-values : $(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 += $(name) ; + } + else + { + extra += $(name) ; + } + local search = [ $(s).search ] ; + extra += $(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 += $(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 ; + + + diff --git a/new/gcc.jam b/new/gcc.jam index 0b4448734..a3e7543e5 100644 --- a/new/gcc.jam +++ b/new/gcc.jam @@ -33,9 +33,9 @@ rule init ( a1 * : a2 * : a3 * ) } # Declare generators -generators.register-composing gcc.link : LIB OBJ : EXE : gcc ; +generators.register-linker gcc.link : LIB OBJ : EXE : gcc ; generators.register-composing gcc.archive : OBJ : STATIC_LIB : gcc ; -generators.register-composing gcc.link-dll : OBJ : SHARED_LIB : gcc ; +generators.register-linker gcc.link-dll : OBJ : SHARED_LIB : gcc ; generators.register-c-compiler gcc.compile : CPP : OBJ : gcc ; generators.register-c-compiler gcc.compile : C : OBJ : gcc ; @@ -55,13 +55,21 @@ actions compile # Declare flags and action for linking toolset.flags gcc.link OPTIONS on : -g ; toolset.flags gcc.link LINKPATH ; -toolset.flags gcc.link FINDLIBS ; -toolset.flags gcc.link LIBRARIES ; +toolset.flags gcc.link FINDLIBS-ST ; +toolset.flags gcc.link FINDLIBS-SA ; toolset.flags gcc.link LIBRARIES ; +toolset.flags gcc.link LINK-RUNTIME static : static ; +toolset.flags gcc.link 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 on : -g ; toolset.flags gcc.link-dll LINKPATH ; -toolset.flags gcc.link-dll FINDLIBS ; -toolset.flags gcc.link-dll LIBRARIES ; +toolset.flags gcc.link-dll FINDLIBS-ST ; +toolset.flags gcc.link-dll FINDLIBS-SA ; toolset.flags gcc.link-dll LIBRARIES ; +toolset.flags gcc.link-dll LINK-RUNTIME static : static ; +toolset.flags gcc.link-dll 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) } diff --git a/new/generators.jam b/new/generators.jam index 5d983dcf8..a8ff4c591 100644 --- a/new/generators.jam +++ b/new/generators.jam @@ -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 diff --git a/new/virtual-target.jam b/new/virtual-target.jam index 9e3e00ffd..c425c9b3d 100644 --- a/new/virtual-target.jam +++ b/new/virtual-target.jam @@ -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) ] ; diff --git a/test/conditionals.py b/test/conditionals.py index 78a84d84b..3d85f1b3e 100644 --- a/test/conditionals.py +++ b/test/conditionals.py @@ -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 : true: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 : static:STATIC ;") +t.run_build_system("link=static") +t.expect_addition("bin/gcc/debug/link-static/main-target-a/a") t.write("Jamfile", """ -project : requirements true:SHARED ; +project : requirements static: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() diff --git a/test/direct_request_test.py b/test/direct_request_test.py index 52a7a31be..be061f632 100644 --- a/test/direct_request_test.py +++ b/test/direct_request_test.py @@ -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() diff --git a/test/generators_test.py b/test/generators_test.py index 7a44b266e..f3a0983a4 100644 --- a/test/generators_test.py +++ b/test/generators_test.py @@ -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() diff --git a/test/prebuilt/ext/Jamfile2 b/test/prebuilt/ext/Jamfile2 index 5d57442c0..68e5d7fb4 100644 --- a/test/prebuilt/ext/Jamfile2 +++ b/test/prebuilt/ext/Jamfile2 @@ -2,13 +2,13 @@ project ext ; prebuilt LIB a - : bin/gcc/debug/a.a + : bin/gcc/debug/a.so : debug : debug ; prebuilt LIB a - : bin/gcc/release/a.a + : bin/gcc/release/a.so : release : release ; diff --git a/test/project_test4.py b/test/project_test4.py index e9b7abc9f..66250549b 100644 --- a/test/project_test4.py +++ b/test/project_test4.py @@ -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 gcc -false on single on on -debug +expected="""warning: skipped build of lib/b.obj with properties gcc shared +shared on single on +on debug don't know how to make <.>lib/b.obj/on ...skipped <./gcc/debug>a.exe for lack of <.>lib/b.obj/on... """ diff --git a/test/stage.py b/test/stage.py index 9af8e4192..260383848 100644 --- a/test/stage.py +++ b/test/stage.py @@ -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() diff --git a/v2/build/generators.jam b/v2/build/generators.jam index 5d983dcf8..a8ff4c591 100644 --- a/v2/build/generators.jam +++ b/v2/build/generators.jam @@ -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 diff --git a/v2/build/virtual-target.jam b/v2/build/virtual-target.jam index 9e3e00ffd..c425c9b3d 100644 --- a/v2/build/virtual-target.jam +++ b/v2/build/virtual-target.jam @@ -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) ] ; diff --git a/v2/gcc.jam b/v2/gcc.jam index 0b4448734..a3e7543e5 100644 --- a/v2/gcc.jam +++ b/v2/gcc.jam @@ -33,9 +33,9 @@ rule init ( a1 * : a2 * : a3 * ) } # Declare generators -generators.register-composing gcc.link : LIB OBJ : EXE : gcc ; +generators.register-linker gcc.link : LIB OBJ : EXE : gcc ; generators.register-composing gcc.archive : OBJ : STATIC_LIB : gcc ; -generators.register-composing gcc.link-dll : OBJ : SHARED_LIB : gcc ; +generators.register-linker gcc.link-dll : OBJ : SHARED_LIB : gcc ; generators.register-c-compiler gcc.compile : CPP : OBJ : gcc ; generators.register-c-compiler gcc.compile : C : OBJ : gcc ; @@ -55,13 +55,21 @@ actions compile # Declare flags and action for linking toolset.flags gcc.link OPTIONS on : -g ; toolset.flags gcc.link LINKPATH ; -toolset.flags gcc.link FINDLIBS ; -toolset.flags gcc.link LIBRARIES ; +toolset.flags gcc.link FINDLIBS-ST ; +toolset.flags gcc.link FINDLIBS-SA ; toolset.flags gcc.link LIBRARIES ; +toolset.flags gcc.link LINK-RUNTIME static : static ; +toolset.flags gcc.link 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 on : -g ; toolset.flags gcc.link-dll LINKPATH ; -toolset.flags gcc.link-dll FINDLIBS ; -toolset.flags gcc.link-dll LIBRARIES ; +toolset.flags gcc.link-dll FINDLIBS-ST ; +toolset.flags gcc.link-dll FINDLIBS-SA ; toolset.flags gcc.link-dll LIBRARIES ; +toolset.flags gcc.link-dll LINK-RUNTIME static : static ; +toolset.flags gcc.link-dll 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) } diff --git a/v2/test/conditionals.py b/v2/test/conditionals.py index 78a84d84b..3d85f1b3e 100644 --- a/v2/test/conditionals.py +++ b/v2/test/conditionals.py @@ -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 : true: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 : static:STATIC ;") +t.run_build_system("link=static") +t.expect_addition("bin/gcc/debug/link-static/main-target-a/a") t.write("Jamfile", """ -project : requirements true:SHARED ; +project : requirements static: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() diff --git a/v2/test/direct_request_test.py b/v2/test/direct_request_test.py index 52a7a31be..be061f632 100644 --- a/v2/test/direct_request_test.py +++ b/v2/test/direct_request_test.py @@ -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() diff --git a/v2/test/generators_test.py b/v2/test/generators_test.py index 7a44b266e..f3a0983a4 100644 --- a/v2/test/generators_test.py +++ b/v2/test/generators_test.py @@ -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() diff --git a/v2/test/prebuilt/ext/Jamfile2 b/v2/test/prebuilt/ext/Jamfile2 index 5d57442c0..68e5d7fb4 100644 --- a/v2/test/prebuilt/ext/Jamfile2 +++ b/v2/test/prebuilt/ext/Jamfile2 @@ -2,13 +2,13 @@ project ext ; prebuilt LIB a - : bin/gcc/debug/a.a + : bin/gcc/debug/a.so : debug : debug ; prebuilt LIB a - : bin/gcc/release/a.a + : bin/gcc/release/a.so : release : release ; diff --git a/v2/test/project_test4.py b/v2/test/project_test4.py index e9b7abc9f..66250549b 100644 --- a/v2/test/project_test4.py +++ b/v2/test/project_test4.py @@ -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 gcc -false on single on on -debug +expected="""warning: skipped build of lib/b.obj with properties gcc shared +shared on single on +on debug don't know how to make <.>lib/b.obj/on ...skipped <./gcc/debug>a.exe for lack of <.>lib/b.obj/on... """ diff --git a/v2/test/stage.py b/v2/test/stage.py index 9af8e4192..260383848 100644 --- a/v2/test/stage.py +++ b/v2/test/stage.py @@ -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() diff --git a/v2/tools/builtin.jam b/v2/tools/builtin.jam index 983c111bf..bed598609 100644 --- a/v2/tools/builtin.jam +++ b/v2/tools/builtin.jam @@ -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 : off on ; variant release : on 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 : LIB ; - rule run ( project name ? : properties * : sources + ) + rule run ( project name ? : properties * : sources * ) { # Determine the needed target type local actual-type ; - if true in $(properties) + if in $(properties:G) || in $(properties:G) + { + actual-type = SEARCHED_LIB ; + } + else if 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 shared in $(properties) + { + shared = true ; + } + return [ new searched-lib-target $(name) : $(project) : $(shared) + : [ feature.get-values : $(properties) ] + : [ feature.get-values : $(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 += $(name) ; + } + else + { + extra += $(name) ; + } + local search = [ $(s).search ] ; + extra += $(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 += $(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 ; + + +