diff --git a/features.jam b/features.jam index b383b272c..66ee5c77e 100644 --- a/features.jam +++ b/features.jam @@ -71,9 +71,22 @@ variant debug : common : off ; -variant debug-python : debug : - BOOST_DEBUG_PYTHON - ; +if $(NT) +{ + variant debug-python : debug : + BOOST_DEBUG_PYTHON + _DEBUG + Py_DEBUG + ; +} +else +{ + variant debug-python : debug : + BOOST_DEBUG_PYTHON + Py_DEBUG + ; + +} variant release : common : off diff --git a/gcc-tools.jam b/gcc-tools.jam index fcb23e857..89848b8e0 100644 --- a/gcc-tools.jam +++ b/gcc-tools.jam @@ -74,7 +74,7 @@ rule Link-action # This will appear before the import library name when building a DLL, but # will be "multiplied away" otherwise. The --exclude-symbols directive # proved to be neccessary with some versions of Cygwin. - IMPLIB_COMMAND on $(<) = "-Wl,--exclude-symbols,_bss_end__:_bss_start__:_data_end__:_data_start__ -Wl,--out-implib," ; + IMPLIB_COMMAND on $(<) = "-Wl,--export-all-symbols -Wl,--exclude-symbols,_bss_end__:_bss_start__:_data_end__:_data_start__ -Wl,--out-implib," ; DEPENDS $(<) : $(NEEDLIBS) ; if $(<[2]) && $(NT) && ( -mno-cygwin in $(gBUILD_PROPERTIES:G=) ) { diff --git a/historic/jam/src/Jamfile b/historic/jam/src/Jamfile index fc4d385a4..c94a6020d 100644 --- a/historic/jam/src/Jamfile +++ b/historic/jam/src/Jamfile @@ -163,7 +163,7 @@ rule Package } } -VERSION = ftjam-2.3.5 ; +VERSION = boost-jam-3.0 ; actions Tar-Gz diff --git a/historic/jam/src/expand.c b/historic/jam/src/expand.c index 7524eda15..366afd508 100644 --- a/historic/jam/src/expand.c +++ b/historic/jam/src/expand.c @@ -243,6 +243,8 @@ var_expand( if( bracket[1] && ( dash = strchr( bracket + 2, '-' ) ) ) { + if( dash == bracket + 2 && *( bracket + 1 ) == '-') + --dash; string_truncate( &variable, dash - varname ); sub1 = atoi( bracket + 1 ); sub2 = atoi( dash + 1 ); @@ -564,8 +566,12 @@ static int adjust_index( int index, int length ) { if ( index < 0 ) index = length + 1 + index; - if ( index < 0 ) - index = 0; + /** For first range index negative values are ok. + For second return value of 0 means don't use second bound. + We need to make it -1 so that all elements are skipped. + */ + if ( index == 0 ) + index = -1; return index; } diff --git a/historic/jam/src/jam.c b/historic/jam/src/jam.c index ea545f4e3..ceb124b21 100644 --- a/historic/jam/src/jam.c +++ b/historic/jam/src/jam.c @@ -223,9 +223,8 @@ int main( int argc, char **argv, char **arg_environ ) if( ( s = getoptval( optv, 'v', 0 ) ) ) { - printf( "Jam/MR " ); + printf( "Boost.Jam " ); printf( "Version %s. ", VERSION ); - printf( "Copyright 1993, 2000 Christopher Seiwald. " ); printf( "%s.\n", OSMINOR ); return EXITOK; diff --git a/historic/jam/src/patchlevel.h b/historic/jam/src/patchlevel.h index 0d0af9597..813beea38 100644 --- a/historic/jam/src/patchlevel.h +++ b/historic/jam/src/patchlevel.h @@ -1,5 +1,5 @@ /* Keep JAMVERSYM in sync with VERSION. */ /* It can be accessed as $(JAMVERSION) in the Jamfile. */ -#define VERSION "2.3.2" -#define JAMVERSYM "JAMVERSION=2.3" +#define VERSION "3.0.0" +#define JAMVERSYM "JAMVERSION=3.0" diff --git a/jam_src/Jamfile b/jam_src/Jamfile index fc4d385a4..c94a6020d 100644 --- a/jam_src/Jamfile +++ b/jam_src/Jamfile @@ -163,7 +163,7 @@ rule Package } } -VERSION = ftjam-2.3.5 ; +VERSION = boost-jam-3.0 ; actions Tar-Gz diff --git a/jam_src/expand.c b/jam_src/expand.c index 7524eda15..366afd508 100644 --- a/jam_src/expand.c +++ b/jam_src/expand.c @@ -243,6 +243,8 @@ var_expand( if( bracket[1] && ( dash = strchr( bracket + 2, '-' ) ) ) { + if( dash == bracket + 2 && *( bracket + 1 ) == '-') + --dash; string_truncate( &variable, dash - varname ); sub1 = atoi( bracket + 1 ); sub2 = atoi( dash + 1 ); @@ -564,8 +566,12 @@ static int adjust_index( int index, int length ) { if ( index < 0 ) index = length + 1 + index; - if ( index < 0 ) - index = 0; + /** For first range index negative values are ok. + For second return value of 0 means don't use second bound. + We need to make it -1 so that all elements are skipped. + */ + if ( index == 0 ) + index = -1; return index; } diff --git a/jam_src/jam.c b/jam_src/jam.c index ea545f4e3..ceb124b21 100644 --- a/jam_src/jam.c +++ b/jam_src/jam.c @@ -223,9 +223,8 @@ int main( int argc, char **argv, char **arg_environ ) if( ( s = getoptval( optv, 'v', 0 ) ) ) { - printf( "Jam/MR " ); + printf( "Boost.Jam " ); printf( "Version %s. ", VERSION ); - printf( "Copyright 1993, 2000 Christopher Seiwald. " ); printf( "%s.\n", OSMINOR ); return EXITOK; diff --git a/jam_src/patchlevel.h b/jam_src/patchlevel.h index 0d0af9597..813beea38 100644 --- a/jam_src/patchlevel.h +++ b/jam_src/patchlevel.h @@ -1,5 +1,5 @@ /* Keep JAMVERSYM in sync with VERSION. */ /* It can be accessed as $(JAMVERSION) in the Jamfile. */ -#define VERSION "2.3.2" -#define JAMVERSYM "JAMVERSION=2.3" +#define VERSION "3.0.0" +#define JAMVERSYM "JAMVERSION=3.0" diff --git a/new/class.jam b/new/class.jam new file mode 100644 index 000000000..3db39fb00 --- /dev/null +++ b/new/class.jam @@ -0,0 +1,280 @@ +import numbers ; +import errors : * ; +import set ; + +module local classes ; + +# Declare a class with the given name. The caller should have defined +# a (local) rule called 'name' which acts as the new class' +# constructor. Module-local variables declared in the constructor will +# act like instance variables, and rules defined in the constructor +# will act like methods. +rule class ( name : bases * ) +{ + if $(name) in $(classes) + { + error class "$(name)" has already been declared ; + } + + classes += $(name) ; + + # Each class is assigned a new module which acts as a namespace + # for its rules and normal instance variables. + module class@$(name) + { + # This is a record of the class' base classes + module local __bases__ = $(bases) ; + + # always bring in the rules defined from this module, so that + # users can easily call "inherit", for example. + import class : * ; + + # The constructor will be known as "__init__" in the class' + # namespace. + IMPORT [ CALLER_MODULE ] : $(name) : class@$(name) : __init__ ; + + # Cause the __init__ function and all of the class modules + # rules to be visible to the builtin RULENAMES rule. We'll + # need them in order to implement subclasses and instances of + # the class. + EXPORT class@$(name) : __init__ [ RULENAMES class ] ; + + # Bring the __init__ functions in from the base classes, using + # the optional localize parameter so that it will execute in + # the instance's module + for local base in $(bases) + { + # ECHO import __init__ from module class@$(base) into class@$(name) as $(base).__init__ ; + IMPORT class@$(base) : __init__ : class@$(name) : $(base).__init__ ; + EXPORT class@$(name) : $(base).__init__ ; + } + } +} + +# Create a new instance of the given class with the given (global) +# name. The class' __init__ function is called with args. +rule instance ( name : class args * : * ) +{ + # Enter the namespace of the new object + module $(name) + { + # import all of the rules from the class into the instance, + # using the optional localize parameter so that they execute + # in the instance's namespace. + local rules = [ RULENAMES class@$(class) ] ; + # ECHO instance $(name) inherits rules: $(rules) from class $(class) ; + IMPORT class@$(class) : $(rules) : $(name) : $(rules) : localize ; + + # Also import the instance's rules into the global module as + # . + IMPORT $(name) : $(rules) : : $(name).$(rules) ; + + # Now initialize the instance + __init__ $(args) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + + # Make a record of the instance's class. We need to do this + # last because it will be set to each of the class' base + # classes as it is initialized. + module local __class__ = $(class) ; + } +} + +# Keeps track of the next unique object name to generate +module local next-instance = 1 ; + +# create a new uniquely-named instance of the given class, returning +# its name. +rule new ( class args * : * ) +{ + local name = object@$(next-instance) ; + instance $(name) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + + # bump the next unique object name + next-instance = [ numbers.increment $(next-instance) ] ; + + # Return the name of the new instance. + return $(name) ; +} + +rule bases ( class ) +{ + if ! ( $(class) in $(classes) ) + { + error class $(class) not defined ; + } + + module class@$(class) + { + return $(__bases__) ; + } +} + +rule is-derived ( class : bases + ) +{ + local all = $(class) $(bases) ; + if ! ( $(all) in $(classes) ) + { + error class(es) [ set.difference $(class) $(bases) : $(classes) ] not defined ; + } + + local stack = $(class) ; + local visited found ; + while ( ! $(found) ) && $(stack) + { + local top = $(stack[1]) ; + stack = $(stack[2-]) ; + if ! ( $(top) in $(visited) ) + { + visited += $(top) ; + stack += [ bases $(top) ] ; + + if $(bases) in $(visited) + { + found = true ; + } + } + } + return $(found) ; +} + +rule __test__ ( ) +{ + module class.__test__ + { + import class : * ; + import assert ; + + # This will be the construction function for a class called + # 'myclass' + local rule myclass ( x_ * : y_ * ) + { + # set some instance variables + module local x = $(x_) ; + module local y = $(y_) ; + + rule set-x ( newx * ) + { + x = $(newx) ; + } + + rule get-x ( ) + { + return $(x) ; + } + + rule set-y ( newy * ) + { + y = $(newy) ; + } + + rule get-y ( ) + { + return $(y) ; + } + + rule f ( ) + { + return [ g $(x) ] ; + } + + rule g ( args * ) + { + if $(x) in $(y) + { + return $(x) ; + } + else if $(y) in $(x) + { + return $(y) ; + } + else + { + return ; + } + } + } + + class myclass ; + + local rule derived1 ( z_ ) + { + myclass.__init__ $(z_) : X ; + module local z = $(z_) ; + + # override g + rule g ( args * ) + { + return derived1.g ; + } + + rule h ( ) + { + return derived1.h ; + } + + rule get-z ( ) + { + return $(z) ; + } + } + + class derived1 : myclass ; + + local rule derived2 ( ) + { + myclass.__init__ 1 : 2 ; + + # override g + rule g ( args * ) + { + return derived2.g ; + } + } + + class derived2 : myclass ; + + local a = [ new myclass 3 4 5 : 4 5 ] ; + local b = [ new derived1 4 ] ; + local c = [ new derived2 ] ; + local d = [ new derived2 ] ; + + assert.result 3 4 5 : $(a).get-x ; + assert.result 4 5 : $(a).get-y ; + assert.result 4 : $(b).get-x ; + assert.result X : $(b).get-y ; + assert.result 4 : $(b).get-z ; + assert.result 1 : $(c).get-x ; + assert.result 2 : $(c).get-y ; + assert.result 4 5 : $(a).f ; + assert.result derived1.g : $(b).f ; + assert.result derived2.g : $(c).f ; + assert.result derived2.g : $(d).f ; + $(a).set-x a.x ; + $(b).set-x b.x ; + $(c).set-x c.x ; + $(d).set-x d.x ; + assert.result a.x : $(a).get-x ; + assert.result b.x : $(b).get-x ; + assert.result c.x : $(c).get-x ; + assert.result d.x : $(d).get-x ; + + rule derived3 ( ) + { + } + class derived3 : derived1 derived2 ; + + assert.result : bases myclass ; + assert.result myclass : bases derived1 ; + assert.result myclass : bases derived2 ; + assert.result derived1 derived2 : bases derived3 ; + + assert.true is-derived derived1 : myclass ; + assert.true is-derived derived2 : myclass ; + assert.true is-derived derived3 : derived1 ; + assert.true is-derived derived3 : derived2 ; + assert.true is-derived derived3 : derived1 derived2 myclass ; + assert.true is-derived derived3 : myclass ; + + assert.false is-derived myclass : derived1 ; + } +} \ No newline at end of file diff --git a/new/modules.jam b/new/modules.jam index 41e72b54f..b0135fcd6 100644 --- a/new/modules.jam +++ b/new/modules.jam @@ -39,11 +39,16 @@ rule load ( module-name ) IMPORT modules : no_test_defined : $(module-name) : __test__ ; # Add some grist so that the module will have a unique target name - local module-target = $(module-name:G=module@:S=.jam) ; + local module-target ; + if $(module-name:S) != .jam { + module-target = $(module-name:G=module@).jam ; + } else { + module-target = $(module-name:G=module@) ; + } SEARCH on $(module-target) = $(BOOST_BUILD_PATH) ; BINDRULE on $(module-target) = modules.record-binding ; - include $(module-name:G=module@:S=.jam) ; + include $(module-target) ; } loading-modules = $(loading-modules[1--2]) ; diff --git a/python.jam b/python.jam index 242c13826..dd1362a72 100644 --- a/python.jam +++ b/python.jam @@ -38,11 +38,9 @@ if $(NT) # common properties required for compiling any Python module. PYTHON_PROPERTIES ?= - $(PYTHON_ROOT)/include - $(PYTHON_ROOT)/PC # in case the user is using a source installation + select-python-includes dynamic $(BOOST_ROOT) - _DEBUG <*>SIZEOF_LONG=4 <*>USE_DL_IMPORT <*>python$(PYTHON_VERSION).dll @@ -50,6 +48,9 @@ if $(NT) GCC_PYTHON_ROOT ?= $(CYGWIN_ROOT)/usr/local ; GCC_PYTHON_ROOT ?= /usr/local ; + + GCC_PYTHON_DEBUG_ROOT ?= $(CYGWIN_ROOT)/usr/local/pydebug ; + GCC_PYTHON_DEBUG_ROOT ?= /usr/local/pydebug ; } else if $(UNIX) { @@ -92,7 +93,16 @@ rule select-python-library ( toolset variant : properties * ) } properties += $(lib) ; } - else if ! ( $(toolset) in msvc intel-win32 gcc ) + else if $(toolset) = gcc + { + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(properties) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + properties += $(python-root)/lib/python$(PYTHON_VERSION)/config ; + } + else if ! ( $(toolset) = msvc ) { local lib = $(PYTHON_LIB) ; if BOOST_DEBUG_PYTHON in $(properties) @@ -105,6 +115,28 @@ rule select-python-library ( toolset variant : properties * ) return $(properties) ; } +rule select-python-includes ( toolset variant : properties * ) +{ + if $(toolset) = gcc + { + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(properties) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + properties += $(python-root)/include/python$(PYTHON_VERSION) ; + } + else + { + properties += + $(PYTHON_ROOT)/include + $(PYTHON_ROOT)/PC # in case the user is using a source installation + _DEBUG + ; + } + return $(properties) ; +} + PYTHON_PROPERTIES += <*>util @@ -124,7 +156,12 @@ rule add-cygwin-python-run-path ( module ) local d = $(GCC_ROOT_DIRECTORY) ; while $(d:D) != $(d) { - gRUN_PATH($(module)) += $(GCC_PYTHON_ROOT)/lib/python$(PYTHON_VERSION)/config ; + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(gBUILD_PROPERTIES) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + gRUN_PATH($(module)) += $(python-root)/lib/python$(PYTHON_VERSION)/config ; d = $(d:D) ; } @@ -136,9 +173,7 @@ rule add-cygwin-python-run-path ( module ) # dll-files. rule python-files ( module implib ? : sources * ) { - local actual-module = $(module) ; - - dll-files $(actual-module) $(implib) : $(sources) : PYD ; + dll-files $(module) $(implib) : $(sources) : PYD ; if ( $(gCURRENT_TOOLSET) = gcc ) { @@ -161,7 +196,13 @@ if $(NT) rule name-adjust-PYD ( pyd implib ? : properties * : toolset variant ) { - if BOOST_DEBUG_PYTHON in $(properties) + # Cygwin python is only happy if compiled modules have a .dll + # extension + if $(toolset) = gcc + { + pyd = $(pyd:S=.dll) ; + } + else if BOOST_DEBUG_PYTHON in $(properties) { pyd = $(pyd:S=)_d$(pyd:S) ; } @@ -239,9 +280,7 @@ rule python-test-target ( test-target : sources + ) { python-runtest-aux $(test-target) : $(sources) ; Clean clean : $(test-target) ; # remove the test-target as part of any clean operation - local debug = [ SUBST $(test-target:B) (_d)$ $1 ] ; - debug ?= "" ; - type-DEPENDS test$(debug) : $(test-target) ; + type-DEPENDS test : $(test-target) ; MakeLocate $(test-target) : $(LOCATE_TARGET) ; } actions python-test-target bind PYTHON @@ -257,6 +296,7 @@ SUFPYTHON_RUNTEST = .run ; gGENERATOR_FUNCTION(PYTHON_RUNTEST) = python-runtest-target ; rule python-runtest-target ( test-target : sources + ) { + type-DEPENDS runtest : $(test-target) ; python-runtest-aux $(test-target) : $(sources) ; NOTFILE $(test-target) ; ALWAYS $(test-target) ; @@ -304,8 +344,12 @@ rule python-runtest-aux ( target : sources + ) if $(NT) && ( $(gCURRENT_TOOLSET) = gcc ) { python = python$(PYTHON_VERSION)$(SUFEXE) ; - SEARCH on $(python) = [ join-path [ split-path $(GCC_PYTHON_ROOT)/bin ] ] $(RUN_PATH) ; - # Fix up path splitter for cygwin. + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(gBUILD_PROPERTIES) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + SEARCH on $(python) = [ join-path [ split-path $(python-root)/bin ] ] $(RUN_PATH) ; splitpath = ":" ; local pp ; @@ -334,7 +378,7 @@ rule python-runtest-aux ( target : sources + ) $(gRUN_PATH($(target))) # location of module dependencies $(>:D) # directory of python driver file(s) $(PATH) # base PATH from environment - : $(splitpath) ] ; # platform path separator + : $(SPLITPATH) ] ; # platform path separator PYTHON on $(target) = $(python) ; DEPENDS $(target) : $(python) ; diff --git a/test/check-jam-patches.jam b/test/check-jam-patches.jam index 4d8c86a73..d9db89435 100644 --- a/test/check-jam-patches.jam +++ b/test/check-jam-patches.jam @@ -120,6 +120,12 @@ assert-equal x y x-y assert-index -2 : d ; assert-index 2--2 : b c d ; assert-index -3--2 : c d ; + assert-index 1--2 : a b c d ; + assert-index --2 : a b c d ; + assert-index 1--10 : ; + x = a ; + assert-index 1--2 : ; + assert-index --2 : ; } # diff --git a/test/recursive.jam b/test/recursive.jam index faf359be3..0deedb30e 100644 --- a/test/recursive.jam +++ b/test/recursive.jam @@ -69,7 +69,6 @@ rule Jam-fail ( command : expected-output ? ) return $(target) ; } - # The temporary jamfile we write is called "temp.jam". If the user has set # BOOST_BUILD_ROOT, it will be built there. gBOOST_TEST_JAMFILE = temp.jam ; @@ -89,10 +88,11 @@ rule invoke-Jam ( command ) } actions invoke-Jam { - echo $(PREFIX) $(<:G=) > $(gBOOST_TEST_JAMFILE) - jam -f../Jambase -sJAMFILE=$(gBOOST_TEST_JAMFILE) $(JAMARGS) >$(redirect) - $(REMOVE) $(gBOOST_TEST_JAMFILE) + echo "$(PREFIX) $(<:G=)" > $(gBOOST_TEST_JAMFILE) + jam -sBOOST_BUILD_PATH=.. -sJAMFILE=$(gBOOST_TEST_JAMFILE) $(JAMARGS) >$(redirect) } +# $(REMOVE) $(gBOOST_TEST_JAMFILE) + # These actions expect to find the ungristed part of $(<) in scratch-output.txt # and return a nonzero exit code otherwise @@ -111,7 +111,7 @@ else # a regular expression. Is there a simpler find? actions quietly Expect-in-output { - $(VERBOSE)scratch-output.txt ; + $(VERBOSE)scratch-output.txt; grep "$(<:G=)" scratch-output.txt } } diff --git a/v1/features.jam b/v1/features.jam index b383b272c..66ee5c77e 100644 --- a/v1/features.jam +++ b/v1/features.jam @@ -71,9 +71,22 @@ variant debug : common : off ; -variant debug-python : debug : - BOOST_DEBUG_PYTHON - ; +if $(NT) +{ + variant debug-python : debug : + BOOST_DEBUG_PYTHON + _DEBUG + Py_DEBUG + ; +} +else +{ + variant debug-python : debug : + BOOST_DEBUG_PYTHON + Py_DEBUG + ; + +} variant release : common : off diff --git a/v1/gcc-tools.jam b/v1/gcc-tools.jam index fcb23e857..89848b8e0 100644 --- a/v1/gcc-tools.jam +++ b/v1/gcc-tools.jam @@ -74,7 +74,7 @@ rule Link-action # This will appear before the import library name when building a DLL, but # will be "multiplied away" otherwise. The --exclude-symbols directive # proved to be neccessary with some versions of Cygwin. - IMPLIB_COMMAND on $(<) = "-Wl,--exclude-symbols,_bss_end__:_bss_start__:_data_end__:_data_start__ -Wl,--out-implib," ; + IMPLIB_COMMAND on $(<) = "-Wl,--export-all-symbols -Wl,--exclude-symbols,_bss_end__:_bss_start__:_data_end__:_data_start__ -Wl,--out-implib," ; DEPENDS $(<) : $(NEEDLIBS) ; if $(<[2]) && $(NT) && ( -mno-cygwin in $(gBUILD_PROPERTIES:G=) ) { diff --git a/v1/python.jam b/v1/python.jam index 242c13826..dd1362a72 100644 --- a/v1/python.jam +++ b/v1/python.jam @@ -38,11 +38,9 @@ if $(NT) # common properties required for compiling any Python module. PYTHON_PROPERTIES ?= - $(PYTHON_ROOT)/include - $(PYTHON_ROOT)/PC # in case the user is using a source installation + select-python-includes dynamic $(BOOST_ROOT) - _DEBUG <*>SIZEOF_LONG=4 <*>USE_DL_IMPORT <*>python$(PYTHON_VERSION).dll @@ -50,6 +48,9 @@ if $(NT) GCC_PYTHON_ROOT ?= $(CYGWIN_ROOT)/usr/local ; GCC_PYTHON_ROOT ?= /usr/local ; + + GCC_PYTHON_DEBUG_ROOT ?= $(CYGWIN_ROOT)/usr/local/pydebug ; + GCC_PYTHON_DEBUG_ROOT ?= /usr/local/pydebug ; } else if $(UNIX) { @@ -92,7 +93,16 @@ rule select-python-library ( toolset variant : properties * ) } properties += $(lib) ; } - else if ! ( $(toolset) in msvc intel-win32 gcc ) + else if $(toolset) = gcc + { + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(properties) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + properties += $(python-root)/lib/python$(PYTHON_VERSION)/config ; + } + else if ! ( $(toolset) = msvc ) { local lib = $(PYTHON_LIB) ; if BOOST_DEBUG_PYTHON in $(properties) @@ -105,6 +115,28 @@ rule select-python-library ( toolset variant : properties * ) return $(properties) ; } +rule select-python-includes ( toolset variant : properties * ) +{ + if $(toolset) = gcc + { + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(properties) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + properties += $(python-root)/include/python$(PYTHON_VERSION) ; + } + else + { + properties += + $(PYTHON_ROOT)/include + $(PYTHON_ROOT)/PC # in case the user is using a source installation + _DEBUG + ; + } + return $(properties) ; +} + PYTHON_PROPERTIES += <*>util @@ -124,7 +156,12 @@ rule add-cygwin-python-run-path ( module ) local d = $(GCC_ROOT_DIRECTORY) ; while $(d:D) != $(d) { - gRUN_PATH($(module)) += $(GCC_PYTHON_ROOT)/lib/python$(PYTHON_VERSION)/config ; + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(gBUILD_PROPERTIES) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + gRUN_PATH($(module)) += $(python-root)/lib/python$(PYTHON_VERSION)/config ; d = $(d:D) ; } @@ -136,9 +173,7 @@ rule add-cygwin-python-run-path ( module ) # dll-files. rule python-files ( module implib ? : sources * ) { - local actual-module = $(module) ; - - dll-files $(actual-module) $(implib) : $(sources) : PYD ; + dll-files $(module) $(implib) : $(sources) : PYD ; if ( $(gCURRENT_TOOLSET) = gcc ) { @@ -161,7 +196,13 @@ if $(NT) rule name-adjust-PYD ( pyd implib ? : properties * : toolset variant ) { - if BOOST_DEBUG_PYTHON in $(properties) + # Cygwin python is only happy if compiled modules have a .dll + # extension + if $(toolset) = gcc + { + pyd = $(pyd:S=.dll) ; + } + else if BOOST_DEBUG_PYTHON in $(properties) { pyd = $(pyd:S=)_d$(pyd:S) ; } @@ -239,9 +280,7 @@ rule python-test-target ( test-target : sources + ) { python-runtest-aux $(test-target) : $(sources) ; Clean clean : $(test-target) ; # remove the test-target as part of any clean operation - local debug = [ SUBST $(test-target:B) (_d)$ $1 ] ; - debug ?= "" ; - type-DEPENDS test$(debug) : $(test-target) ; + type-DEPENDS test : $(test-target) ; MakeLocate $(test-target) : $(LOCATE_TARGET) ; } actions python-test-target bind PYTHON @@ -257,6 +296,7 @@ SUFPYTHON_RUNTEST = .run ; gGENERATOR_FUNCTION(PYTHON_RUNTEST) = python-runtest-target ; rule python-runtest-target ( test-target : sources + ) { + type-DEPENDS runtest : $(test-target) ; python-runtest-aux $(test-target) : $(sources) ; NOTFILE $(test-target) ; ALWAYS $(test-target) ; @@ -304,8 +344,12 @@ rule python-runtest-aux ( target : sources + ) if $(NT) && ( $(gCURRENT_TOOLSET) = gcc ) { python = python$(PYTHON_VERSION)$(SUFEXE) ; - SEARCH on $(python) = [ join-path [ split-path $(GCC_PYTHON_ROOT)/bin ] ] $(RUN_PATH) ; - # Fix up path splitter for cygwin. + local python-root = $(GCC_PYTHON_ROOT) ; + if BOOST_DEBUG_PYTHON in $(gBUILD_PROPERTIES) + { + python-root = $(GCC_PYTHON_DEBUG_ROOT) ; + } + SEARCH on $(python) = [ join-path [ split-path $(python-root)/bin ] ] $(RUN_PATH) ; splitpath = ":" ; local pp ; @@ -334,7 +378,7 @@ rule python-runtest-aux ( target : sources + ) $(gRUN_PATH($(target))) # location of module dependencies $(>:D) # directory of python driver file(s) $(PATH) # base PATH from environment - : $(splitpath) ] ; # platform path separator + : $(SPLITPATH) ] ; # platform path separator PYTHON on $(target) = $(python) ; DEPENDS $(target) : $(python) ; diff --git a/v2/kernel/class.jam b/v2/kernel/class.jam new file mode 100644 index 000000000..3db39fb00 --- /dev/null +++ b/v2/kernel/class.jam @@ -0,0 +1,280 @@ +import numbers ; +import errors : * ; +import set ; + +module local classes ; + +# Declare a class with the given name. The caller should have defined +# a (local) rule called 'name' which acts as the new class' +# constructor. Module-local variables declared in the constructor will +# act like instance variables, and rules defined in the constructor +# will act like methods. +rule class ( name : bases * ) +{ + if $(name) in $(classes) + { + error class "$(name)" has already been declared ; + } + + classes += $(name) ; + + # Each class is assigned a new module which acts as a namespace + # for its rules and normal instance variables. + module class@$(name) + { + # This is a record of the class' base classes + module local __bases__ = $(bases) ; + + # always bring in the rules defined from this module, so that + # users can easily call "inherit", for example. + import class : * ; + + # The constructor will be known as "__init__" in the class' + # namespace. + IMPORT [ CALLER_MODULE ] : $(name) : class@$(name) : __init__ ; + + # Cause the __init__ function and all of the class modules + # rules to be visible to the builtin RULENAMES rule. We'll + # need them in order to implement subclasses and instances of + # the class. + EXPORT class@$(name) : __init__ [ RULENAMES class ] ; + + # Bring the __init__ functions in from the base classes, using + # the optional localize parameter so that it will execute in + # the instance's module + for local base in $(bases) + { + # ECHO import __init__ from module class@$(base) into class@$(name) as $(base).__init__ ; + IMPORT class@$(base) : __init__ : class@$(name) : $(base).__init__ ; + EXPORT class@$(name) : $(base).__init__ ; + } + } +} + +# Create a new instance of the given class with the given (global) +# name. The class' __init__ function is called with args. +rule instance ( name : class args * : * ) +{ + # Enter the namespace of the new object + module $(name) + { + # import all of the rules from the class into the instance, + # using the optional localize parameter so that they execute + # in the instance's namespace. + local rules = [ RULENAMES class@$(class) ] ; + # ECHO instance $(name) inherits rules: $(rules) from class $(class) ; + IMPORT class@$(class) : $(rules) : $(name) : $(rules) : localize ; + + # Also import the instance's rules into the global module as + # . + IMPORT $(name) : $(rules) : : $(name).$(rules) ; + + # Now initialize the instance + __init__ $(args) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + + # Make a record of the instance's class. We need to do this + # last because it will be set to each of the class' base + # classes as it is initialized. + module local __class__ = $(class) ; + } +} + +# Keeps track of the next unique object name to generate +module local next-instance = 1 ; + +# create a new uniquely-named instance of the given class, returning +# its name. +rule new ( class args * : * ) +{ + local name = object@$(next-instance) ; + instance $(name) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + + # bump the next unique object name + next-instance = [ numbers.increment $(next-instance) ] ; + + # Return the name of the new instance. + return $(name) ; +} + +rule bases ( class ) +{ + if ! ( $(class) in $(classes) ) + { + error class $(class) not defined ; + } + + module class@$(class) + { + return $(__bases__) ; + } +} + +rule is-derived ( class : bases + ) +{ + local all = $(class) $(bases) ; + if ! ( $(all) in $(classes) ) + { + error class(es) [ set.difference $(class) $(bases) : $(classes) ] not defined ; + } + + local stack = $(class) ; + local visited found ; + while ( ! $(found) ) && $(stack) + { + local top = $(stack[1]) ; + stack = $(stack[2-]) ; + if ! ( $(top) in $(visited) ) + { + visited += $(top) ; + stack += [ bases $(top) ] ; + + if $(bases) in $(visited) + { + found = true ; + } + } + } + return $(found) ; +} + +rule __test__ ( ) +{ + module class.__test__ + { + import class : * ; + import assert ; + + # This will be the construction function for a class called + # 'myclass' + local rule myclass ( x_ * : y_ * ) + { + # set some instance variables + module local x = $(x_) ; + module local y = $(y_) ; + + rule set-x ( newx * ) + { + x = $(newx) ; + } + + rule get-x ( ) + { + return $(x) ; + } + + rule set-y ( newy * ) + { + y = $(newy) ; + } + + rule get-y ( ) + { + return $(y) ; + } + + rule f ( ) + { + return [ g $(x) ] ; + } + + rule g ( args * ) + { + if $(x) in $(y) + { + return $(x) ; + } + else if $(y) in $(x) + { + return $(y) ; + } + else + { + return ; + } + } + } + + class myclass ; + + local rule derived1 ( z_ ) + { + myclass.__init__ $(z_) : X ; + module local z = $(z_) ; + + # override g + rule g ( args * ) + { + return derived1.g ; + } + + rule h ( ) + { + return derived1.h ; + } + + rule get-z ( ) + { + return $(z) ; + } + } + + class derived1 : myclass ; + + local rule derived2 ( ) + { + myclass.__init__ 1 : 2 ; + + # override g + rule g ( args * ) + { + return derived2.g ; + } + } + + class derived2 : myclass ; + + local a = [ new myclass 3 4 5 : 4 5 ] ; + local b = [ new derived1 4 ] ; + local c = [ new derived2 ] ; + local d = [ new derived2 ] ; + + assert.result 3 4 5 : $(a).get-x ; + assert.result 4 5 : $(a).get-y ; + assert.result 4 : $(b).get-x ; + assert.result X : $(b).get-y ; + assert.result 4 : $(b).get-z ; + assert.result 1 : $(c).get-x ; + assert.result 2 : $(c).get-y ; + assert.result 4 5 : $(a).f ; + assert.result derived1.g : $(b).f ; + assert.result derived2.g : $(c).f ; + assert.result derived2.g : $(d).f ; + $(a).set-x a.x ; + $(b).set-x b.x ; + $(c).set-x c.x ; + $(d).set-x d.x ; + assert.result a.x : $(a).get-x ; + assert.result b.x : $(b).get-x ; + assert.result c.x : $(c).get-x ; + assert.result d.x : $(d).get-x ; + + rule derived3 ( ) + { + } + class derived3 : derived1 derived2 ; + + assert.result : bases myclass ; + assert.result myclass : bases derived1 ; + assert.result myclass : bases derived2 ; + assert.result derived1 derived2 : bases derived3 ; + + assert.true is-derived derived1 : myclass ; + assert.true is-derived derived2 : myclass ; + assert.true is-derived derived3 : derived1 ; + assert.true is-derived derived3 : derived2 ; + assert.true is-derived derived3 : derived1 derived2 myclass ; + assert.true is-derived derived3 : myclass ; + + assert.false is-derived myclass : derived1 ; + } +} \ No newline at end of file diff --git a/v2/modules.jam b/v2/modules.jam index 41e72b54f..b0135fcd6 100644 --- a/v2/modules.jam +++ b/v2/modules.jam @@ -39,11 +39,16 @@ rule load ( module-name ) IMPORT modules : no_test_defined : $(module-name) : __test__ ; # Add some grist so that the module will have a unique target name - local module-target = $(module-name:G=module@:S=.jam) ; + local module-target ; + if $(module-name:S) != .jam { + module-target = $(module-name:G=module@).jam ; + } else { + module-target = $(module-name:G=module@) ; + } SEARCH on $(module-target) = $(BOOST_BUILD_PATH) ; BINDRULE on $(module-target) = modules.record-binding ; - include $(module-name:G=module@:S=.jam) ; + include $(module-target) ; } loading-modules = $(loading-modules[1--2]) ; diff --git a/v2/test/check-jam-patches.jam b/v2/test/check-jam-patches.jam index 4d8c86a73..d9db89435 100644 --- a/v2/test/check-jam-patches.jam +++ b/v2/test/check-jam-patches.jam @@ -120,6 +120,12 @@ assert-equal x y x-y assert-index -2 : d ; assert-index 2--2 : b c d ; assert-index -3--2 : c d ; + assert-index 1--2 : a b c d ; + assert-index --2 : a b c d ; + assert-index 1--10 : ; + x = a ; + assert-index 1--2 : ; + assert-index --2 : ; } # diff --git a/v2/test/recursive.jam b/v2/test/recursive.jam index faf359be3..0deedb30e 100644 --- a/v2/test/recursive.jam +++ b/v2/test/recursive.jam @@ -69,7 +69,6 @@ rule Jam-fail ( command : expected-output ? ) return $(target) ; } - # The temporary jamfile we write is called "temp.jam". If the user has set # BOOST_BUILD_ROOT, it will be built there. gBOOST_TEST_JAMFILE = temp.jam ; @@ -89,10 +88,11 @@ rule invoke-Jam ( command ) } actions invoke-Jam { - echo $(PREFIX) $(<:G=) > $(gBOOST_TEST_JAMFILE) - jam -f../Jambase -sJAMFILE=$(gBOOST_TEST_JAMFILE) $(JAMARGS) >$(redirect) - $(REMOVE) $(gBOOST_TEST_JAMFILE) + echo "$(PREFIX) $(<:G=)" > $(gBOOST_TEST_JAMFILE) + jam -sBOOST_BUILD_PATH=.. -sJAMFILE=$(gBOOST_TEST_JAMFILE) $(JAMARGS) >$(redirect) } +# $(REMOVE) $(gBOOST_TEST_JAMFILE) + # These actions expect to find the ungristed part of $(<) in scratch-output.txt # and return a nonzero exit code otherwise @@ -111,7 +111,7 @@ else # a regular expression. Is there a simpler find? actions quietly Expect-in-output { - $(VERBOSE)scratch-output.txt ; + $(VERBOSE)scratch-output.txt; grep "$(<:G=)" scratch-output.txt } }