diff --git a/v2/build/feature.jam b/v2/build/feature.jam index b2cfd7cd0..e6ad37f35 100644 --- a/v2/build/feature.jam +++ b/v2/build/feature.jam @@ -658,7 +658,7 @@ rule expand-composites ( properties * ) error explicitly-specified values of non-free feature $(f) conflict : "existing values:" [ get-values $(f) : $(properties) ] : - "value from expanding " $(p) ":" (x:G=) ; + "value from expanding " $(p) ":" $(x:G=) ; } else { diff --git a/v2/build/project.jam b/v2/build/project.jam index 74f901b64..e848cc99f 100644 --- a/v2/build/project.jam +++ b/v2/build/project.jam @@ -674,6 +674,22 @@ rule current ( ) return $(.current-project) ; } +# Temporary changes the current project to 'project'. Should +# be followed by 'pop-current'. +rule push-current ( project ) +{ + .saved-current-project += $(.current-project) ; + .current-project = $(project) ; +} + +rule pop-current ( ) +{ + .current-project = $(.saved-current-project[-1]) ; + .saved-current-project = $(.saved-current-project[1--2]) ; +} + + + # Returns the project-attribute instance for the specified jamfile module. rule attributes ( project ) { diff --git a/v2/tools/builtin.jam b/v2/tools/builtin.jam index aed2e997c..4e1bba72e 100644 --- a/v2/tools/builtin.jam +++ b/v2/tools/builtin.jam @@ -50,6 +50,7 @@ feature asynch-exceptions : off on : propagated ; feature extern-c-nothrow : off on : propagated ; feature debug-symbols : on off : propagated ; feature define : : free ; +feature undef : : free ; feature "include" : : free path ; #order-sensitive ; feature cflags : : free ; feature cxxflags : : free ; diff --git a/v2/tools/common.jam b/v2/tools/common.jam index c5bbd4294..06d66366d 100644 --- a/v2/tools/common.jam +++ b/v2/tools/common.jam @@ -387,8 +387,9 @@ rule get-program-files-dir ( ) if [ os.name ] = NT { - RM = del /f ; + RM = del /f /q ; CP = copy ; + IGNORE = "2>nul >nul & setlocal" ; } else { @@ -546,6 +547,14 @@ actions copy $(CP) "$(>)" "$(<)" } +rule RmTemps +{ +} +actions quietly updated piecemeal together RmTemps +{ + $(RM) "$(>)" $(IGNORE) +} + rule __test__ ( ) { import assert ; diff --git a/v2/tools/cw.jam b/v2/tools/cw.jam index beb7737ea..3b0a4ba71 100644 --- a/v2/tools/cw.jam +++ b/v2/tools/cw.jam @@ -134,6 +134,9 @@ flags cw.compile CFLAGS off : -inline off ; flags cw.compile CFLAGS on : -inline on ; flags cw.compile CFLAGS full : -inline all ; flags cw.compile CFLAGS off : -Cpp_exceptions off ; + + +flags cw.compile CFLAGS on : -RTTI on ; flags cw.compile CFLAGS off : -RTTI off ; flags cw.compile CFLAGS on : -w on ; diff --git a/v2/tools/gcc.jam b/v2/tools/gcc.jam index 24c4111f5..6a05c9e6a 100644 --- a/v2/tools/gcc.jam +++ b/v2/tools/gcc.jam @@ -17,6 +17,12 @@ import set ; import common ; import errors ; +if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] +{ + .debug-configuration = true ; +} + + feature.extend toolset : gcc ; import unix ; @@ -28,7 +34,6 @@ generators.override gcc.prebuilt : builtin.prebuilt ; generators.override gcc.searched-lib-generator : searched-lib-generator ; - # Make the "o" suffix used for gcc toolset on all # platforms type.set-generated-target-suffix OBJ : gcc : o ; @@ -58,17 +63,38 @@ rule init ( version ? : command * : options * ) } init-link-flags gcc $(linker) $(condition) ; - # If gcc is installed in non-standard location, we'd need to - # add LD_LIBRARY_PATH when running programs created with it - # (for unit-test/run rules). + local root = [ feature.get-values : $(options) ] ; + local bin ; if $(command) { - local path = [ common.get-absolute-tool-path $(command[-1]) ] ; - local lib_path = $(path:D)/lib ; - flags gcc.link RUN_PATH : $(lib_path) ; + bin ?= [ common.get-absolute-tool-path $(command[-1]) ] ; + root ?= $(bin:D) ; + } + + # If gcc is installed in non-standard location, we'd need to + # add LD_LIBRARY_PATH when running programs created with it + # (for unit-test/run rules). + if $(command) + { + local lib_path = $(root)/lib ; + if $(.debug-configuration) + { + ECHO notice: using gcc libraries :: $(condition) :: $(lib_path) ; + } + flags gcc.link RUN_PATH $(condition) : $(lib_path) ; } - + #~ If it's not a system gcc install we should adjust the various + #~ programs as needed to prefer using the install specific versions. + #~ This is essential for correct use of MinGW and for cross-compiling. + local archiver = + [ common.get-invocation-command gcc + : ar : [ feature.get-values : $(options) ] : $(bin) : PATH ] ; + flags gcc.archive .AR $(condition) : $(archiver[1]) ; + if $(.debug-configuration) + { + ECHO notice: using gcc archiver :: $(condition) :: $(archiver[1]) ; + } } if [ os.name ] = NT @@ -323,21 +349,38 @@ actions link bind LIBRARIES } -# Always remove archive and start again. Here's rationale from -# Andre Hentz: -# I had a file, say a1.c, that was included into liba.a. -# I moved a1.c to a2.c, updated my Jamfiles and rebuilt. -# My program was crashing with absurd errors. -# After some debugging I traced it back to the fact that a1.o was *still* -# in liba.a -RM = [ common.rm-command ] ; +flags gcc.archive AROPTIONS ; -if [ os.name ] = NT +rule archive ( targets * : sources * : properties * ) { - RM = "if exist \"$(<[1])\" DEL \"$(<[1])\"" ; + # Always remove archive and start again. Here's rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. + # I moved a1.c to a2.c, updated my Jamfiles and rebuilt. + # My program was crashing with absurd errors. + # After some debugging I traced it back to the fact that a1.o was *still* + # in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM + # onto the archive action. That makes archives fail to build on NT + # when they have many files because it will no longer execute the + # action directly and blow the line length limit. Instead we + # remove the file in a different action, just before the building + # of the archive. + # + local clean.a = $(targets[1])(clean) ; + TEMPORARY $(clean.a) ; + NOCARE $(clean.a) ; + LOCATE on $(clean.a) = [ on $(targets[1]) return $(LOCATE) ] ; + DEPENDS $(clean.a) : $(sources) ; + DEPENDS $(targets) : $(clean.a) ; + common.RmTemps $(clean.a) : $(targets) ; } - # Declare action for creating static libraries # The 'r' letter means to add files to the archive with replacement # Since we remove archive, we don't care about replacement, but @@ -347,8 +390,7 @@ if [ os.name ] = NT # some platforms, for whatever reasons. actions piecemeal archive { - $(RM) "$(<)" - ar rc "$(<)" "$(>)" + "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)" } diff --git a/v2/tools/python.jam b/v2/tools/python.jam index e75a406ac..e28734979 100644 --- a/v2/tools/python.jam +++ b/v2/tools/python.jam @@ -39,6 +39,19 @@ import toolset : flags ; project.initialize $(__name__) ; project python ; +# Save the project so that if 'init' is called several +# times we define new targets in the python project, +# not in whatever project we were called by. +.project = [ project.current ] ; + +# Dynamic linker lib. Necessary to specify it explicitly +# on some platforms. +lib dl ; +# This contains 'openpty' function need by python. Again, on +# some system need to pass this to linker explicitly. +lib util ; + + # Initializes the Python toolset. # - version -- the version of Python to use. Should be in Major.Minor format, # for example 2.3 @@ -57,9 +70,12 @@ project python ; # using python 2.3 : /usr/local ; # Root specified, include and lib paths # # will be guessed # -rule init ( version ? : root ? : includes ? : libraries ? : cygwin-condition ? ) +rule init ( version ? : root ? : includes ? : libraries ? + : cygwin-condition * ) { .configured = true ; + + project.push-current $(.project) ; if [ os.name ] = NT { @@ -71,46 +87,64 @@ rule init ( version ? : root ? : includes ? : libraries ? : cygwin-condition ? ) } else if [ modules.peek : UNIX ] { - init-unix $(version) : $(root) : $(includes) : $(libraries) ; + init-unix $(version) : $(root) : $(includes) : $(libraries) : $(cygwin-condition) ; } + + project.pop-current ; } -rule init-unix ( version ? : root ? : includes ? : libraries ? ) +rule init-unix ( version ? : root ? : includes ? : libraries ? : condition * ) { root ?= /usr ; includes ?= $(root)/include/python$(version) ; libraries ?= $(root)/lib/python$(version)/config ; # Find the 'python' binary, which is used for testing. - # Look first in $(root)/bin, then in PATH. + # Look first in $(root)/bin, then in PATH. local interpreter = [ common.get-invocation-command python : python : : $(root)/bin : path-last ] ; + if $(interpreter:D) != $(root)/bin + { + ECHO "warning: was expecting Python interpreter in " $(root)/bin ; + ECHO "warning: found only in PATH:" $(interpreter) ; + } + if --debug-configuration in [ modules.peek : ARGV ] { ECHO "notice: Python include path is" $(includes) ; ECHO "notice: Python library path is" $(libraries) ; - ECHO "notice: Python interpreter is" $(interpreter) ; + ECHO "notice: Python interpreter is" $(interpreter) ; } - flags python.capture-output PYTHON : $(interpreter) ; + # If not specific condition is specified, set global value + # If condition is specified, set PYTHON on target. It will + # override the global value. + if ! $(condition) + { + PYTHON = $(interpreter) ; + } + else + { + flags python.capture-output PYTHON $(condition:J=/) : $(interpreter) ; + } # On Linux, we don't want to link either Boost.Python or # Python extensions to libpython, so that when extensions # loaded in the interpreter, the symbols in the interpreter # are used. If we linked to libpython, we'd get duplicate # symbols. So declare two targets -- one for headers and another - # for library. + # for library. alias python_for_extensions - : - : + : + : $(condition) : : $(includes) ; alias python - : - : + : dl util + : $(condition) : : $(includes) $(libraries) diff --git a/v2/tools/qt.jam b/v2/tools/qt.jam index a8d8839da..ab29f9357 100644 --- a/v2/tools/qt.jam +++ b/v2/tools/qt.jam @@ -1,208 +1,17 @@ -# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and -# distribute this software is granted provided this copyright notice appears in -# all copies. This software is provided "as is" without express or implied -# warranty, and with no claim as to its suitability for any purpose. +# Copyright (c) 2006 Vladimir Prus. +# +# Use, modification and distribution is subject to the Boost Software +# License Version 1.0. (See accompanying file LICENSE_1_0.txt or +# http://www.boost.org/LICENSE_1_0.txt) -import modules ; -import feature ; -import errors ; -import type ; -import "class" : new ; -import generators ; -import project ; -import toolset : flags ; +# Forwarning toolset file to Qt GUI library. Forwards to the toolset file +# for the current version of Qt. -# Convert this module into a project, so that we can declare -# targets here. +import qt4 ; -project.initialize $(__name__) ; -project qt ; - -# Initialized the QT support module. The 'prefix' parameter -# tells where QT is installed. When not given, environmental -# variable QTDIR should be set. rule init ( prefix ? ) { - if ! $(prefix) - { - prefix = [ modules.peek : QTDIR ] ; - if ! $(prefix) - { - errors.error - "QT installation prefix not given and QTDIR variable is empty" ; - } - } - - if $(.initialized) - { - if $(prefix) != $(.prefix) - { - errors.error - "Attempt the reinitialize QT with different installation prefix" ; - } - } - else - { - .initialized = true ; - .prefix = $(prefix) ; - - generators.register-standard qt.moc : H : CPP(moc_%) : qt ; - # Note: the OBJ target type here is fake, take a look - # at qt4.jam/uic-h-generator for explanations that - # apply in this case as well. - generators.register [ new moc-h-generator - qt.moc.cpp : MOCCABLE_CPP : OBJ : qt ] ; - - # The UI type is defined in types/qt.jam, - # and UIC_H is only used in qt.jam, but not in qt4.jam, so - # define it here. - type.register UIC_H : : H ; - - generators.register-standard qt.uic-h : UI : UIC_H : qt ; - - # The following generator is used to convert UI files to CPP - # It creates UIC_H from UI, and constructs CPP from UI/UIC_H - # In addition, it also returns UIC_H target, so that it can bee - # mocced. - class qt::uic-cpp-generator : generator - { - rule __init__ ( ) - { - generator.__init__ qt.uic-cpp : UI UIC_H : CPP : qt ; - } - - rule run ( project name ? : properties * : sources + ) - { - # Consider this: - # obj test : test_a.cpp : off ; - # - # This generator will somehow be called in this case, and, - # will fail -- which is okay. However, if there are - # properties they will be converted to sources, so the size of - # 'sources' will be more than 1. In this case, the base generator - # will just crash -- and that's not good. Just use a quick test - # here. - - local result ; - if ! $(sources[2]) - { - # Construct CPP as usual - result = [ generator.run $(project) $(name) - : $(properties) : $(sources) ] ; - - # If OK, process UIC_H with moc. It's pretty clear that - # the object generated with UIC will have Q_OBJECT macro. - if $(result) - { - local action = [ $(result[1]).action ] ; - local sources = [ $(action).sources ] ; - local mocced = [ generators.construct $(project) $(name) - : CPP : $(properties) : $(sources[2]) ] ; - result += $(mocced[2-]) ; - } - } - - return $(result) ; - } - } - - generators.register [ new qt::uic-cpp-generator ] ; - - # Finally, declare prebuilt target for QT library. - local usage-requirements = - $(.prefix)/include - $(.prefix)/lib - $(.prefix)/lib - qt - ; - lib qt : : qt-mt multi : : $(usage-requirements) ; - lib qt : : qt single : : $(usage-requirements) ; - } -} - -class moc-h-generator : generator -{ - rule __init__ ( * : * ) - { - generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; - } - - rule run ( project name ? : property-set : sources * ) - { - if ! $(sources[2]) && [ $(sources[1]).type ] = MOCCABLE_CPP - { - name = [ $(sources[1]).name ] ; - name = $(name:B) ; - - local a = [ new action $(sources[1]) : qt.moc.cpp : - $(property-set) ] ; - - local target = [ - new file-target $(name) : MOC : $(project) : $(a) ] ; - - local r = [ virtual-target.register $(target) ] ; - - # Since this generator will return H target, the linking generator - # won't use it at all, and won't set any dependency on it. - # However, we need to target to be seen by bjam, so that dependency - # from sources to this generated header is detected -- if jam does - # not know about this target, it won't do anything. - DEPENDS all : [ $(r).actualize ] ; - - return $(r) ; - } - } -} - - -# Query the installation directory -# This is needed in at least two scenarios -# First, when re-using sources from the Qt-Tree. -# Second, to "install" custom Qt plugins to the Qt-Tree. -rule directory -{ - return $(.prefix) ; -} - -# -f forces moc to include the processed source file. -# Without it, it would think that .qpp is not a header and would not -# include it from the generated file. -actions moc -{ - $(.prefix)/bin/moc -f $(>) -o $(<) -} - -# When moccing .cpp files, we don't need -f, otherwise generated -# code will include .cpp and we'll get duplicated symbols. -actions moc.cpp -{ - $(.prefix)/bin/moc $(>) -o $(<) -} - - -space = " " ; - -# Sometimes it's required to make 'plugins' available during -# uic invocation. To help with this we add paths to all dependency -# libraries to uic commane line. The intention is that it's possible -# to write -# -# exe a : ... a.ui ... : some_plugin ; -# -# and have everything work. We'd add quite a bunch of unrelated paths -# but it won't hurt. -flags qt.uic-h LIBRARY_PATH ; -actions uic-h -{ - $(.prefix)/bin/uic $(>) -o $(<) -L$(space)$(LIBRARY_PATH) -} - -flags qt.uic-cpp LIBRARY_PATH ; -# The second target is uic-generated header name. It's placed in -# build dir, but we want to include it using only basename. -actions uic-cpp -{ - $(.prefix)/bin/uic $(>[1]) -i $(>[2]:D=) -o $(<) -L$(space)$(LIBRARY_PATH) + qt4.init $(prefix) ; } diff --git a/v2/tools/qt3.jam b/v2/tools/qt3.jam new file mode 100644 index 000000000..8bae89e5e --- /dev/null +++ b/v2/tools/qt3.jam @@ -0,0 +1,213 @@ +# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and +# distribute this software is granted provided this copyright notice appears in +# all copies. This software is provided "as is" without express or implied +# warranty, and with no claim as to its suitability for any purpose. + +# Support for the Qt GUI library version 3 +# (http://www.trolltech.com/products/qt3/index.html). +# For new developments, it's recommented to use Qt4 via the qt4 +# Boost.Build module. + +import modules ; +import feature ; +import errors ; +import type ; +import "class" : new ; +import generators ; +import project ; +import toolset : flags ; + +# Convert this module into a project, so that we can declare +# targets here. + +project.initialize $(__name__) ; +project qt3 ; + +# Initialized the QT support module. The 'prefix' parameter +# tells where QT is installed. When not given, environmental +# variable QTDIR should be set. +rule init ( prefix ? ) +{ + if ! $(prefix) + { + prefix = [ modules.peek : QTDIR ] ; + if ! $(prefix) + { + errors.error + "QT installation prefix not given and QTDIR variable is empty" ; + } + } + + if $(.initialized) + { + if $(prefix) != $(.prefix) + { + errors.error + "Attempt the reinitialize QT with different installation prefix" ; + } + } + else + { + .initialized = true ; + .prefix = $(prefix) ; + + generators.register-standard qt.moc : H : CPP(moc_%) : qt ; + # Note: the OBJ target type here is fake, take a look + # at qt4.jam/uic-h-generator for explanations that + # apply in this case as well. + generators.register [ new moc-h-generator + qt.moc.cpp : MOCCABLE_CPP : OBJ : qt ] ; + + # The UI type is defined in types/qt.jam, + # and UIC_H is only used in qt.jam, but not in qt4.jam, so + # define it here. + type.register UIC_H : : H ; + + generators.register-standard qt.uic-h : UI : UIC_H : qt ; + + # The following generator is used to convert UI files to CPP + # It creates UIC_H from UI, and constructs CPP from UI/UIC_H + # In addition, it also returns UIC_H target, so that it can bee + # mocced. + class qt::uic-cpp-generator : generator + { + rule __init__ ( ) + { + generator.__init__ qt.uic-cpp : UI UIC_H : CPP : qt ; + } + + rule run ( project name ? : properties * : sources + ) + { + # Consider this: + # obj test : test_a.cpp : off ; + # + # This generator will somehow be called in this case, and, + # will fail -- which is okay. However, if there are + # properties they will be converted to sources, so the size of + # 'sources' will be more than 1. In this case, the base generator + # will just crash -- and that's not good. Just use a quick test + # here. + + local result ; + if ! $(sources[2]) + { + # Construct CPP as usual + result = [ generator.run $(project) $(name) + : $(properties) : $(sources) ] ; + + # If OK, process UIC_H with moc. It's pretty clear that + # the object generated with UIC will have Q_OBJECT macro. + if $(result) + { + local action = [ $(result[1]).action ] ; + local sources = [ $(action).sources ] ; + local mocced = [ generators.construct $(project) $(name) + : CPP : $(properties) : $(sources[2]) ] ; + result += $(mocced[2-]) ; + } + } + + return $(result) ; + } + } + + generators.register [ new qt::uic-cpp-generator ] ; + + # Finally, declare prebuilt target for QT library. + local usage-requirements = + $(.prefix)/include + $(.prefix)/lib + $(.prefix)/lib + qt + ; + lib qt : : qt-mt multi : : $(usage-requirements) ; + lib qt : : qt single : : $(usage-requirements) ; + } +} + +class moc-h-generator : generator +{ + rule __init__ ( * : * ) + { + generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + } + + rule run ( project name ? : property-set : sources * ) + { + if ! $(sources[2]) && [ $(sources[1]).type ] = MOCCABLE_CPP + { + name = [ $(sources[1]).name ] ; + name = $(name:B) ; + + local a = [ new action $(sources[1]) : qt.moc.cpp : + $(property-set) ] ; + + local target = [ + new file-target $(name) : MOC : $(project) : $(a) ] ; + + local r = [ virtual-target.register $(target) ] ; + + # Since this generator will return H target, the linking generator + # won't use it at all, and won't set any dependency on it. + # However, we need to target to be seen by bjam, so that dependency + # from sources to this generated header is detected -- if jam does + # not know about this target, it won't do anything. + DEPENDS all : [ $(r).actualize ] ; + + return $(r) ; + } + } +} + + +# Query the installation directory +# This is needed in at least two scenarios +# First, when re-using sources from the Qt-Tree. +# Second, to "install" custom Qt plugins to the Qt-Tree. +rule directory +{ + return $(.prefix) ; +} + +# -f forces moc to include the processed source file. +# Without it, it would think that .qpp is not a header and would not +# include it from the generated file. +actions moc +{ + $(.prefix)/bin/moc -f $(>) -o $(<) +} + +# When moccing .cpp files, we don't need -f, otherwise generated +# code will include .cpp and we'll get duplicated symbols. +actions moc.cpp +{ + $(.prefix)/bin/moc $(>) -o $(<) +} + + +space = " " ; + +# Sometimes it's required to make 'plugins' available during +# uic invocation. To help with this we add paths to all dependency +# libraries to uic commane line. The intention is that it's possible +# to write +# +# exe a : ... a.ui ... : some_plugin ; +# +# and have everything work. We'd add quite a bunch of unrelated paths +# but it won't hurt. +flags qt.uic-h LIBRARY_PATH ; +actions uic-h +{ + $(.prefix)/bin/uic $(>) -o $(<) -L$(space)$(LIBRARY_PATH) +} + +flags qt.uic-cpp LIBRARY_PATH ; +# The second target is uic-generated header name. It's placed in +# build dir, but we want to include it using only basename. +actions uic-cpp +{ + $(.prefix)/bin/uic $(>[1]) -i $(>[2]:D=) -o $(<) -L$(space)$(LIBRARY_PATH) +} + + diff --git a/v2/tools/qt4.jam b/v2/tools/qt4.jam index eb045c29c..4b5a2888d 100644 --- a/v2/tools/qt4.jam +++ b/v2/tools/qt4.jam @@ -46,23 +46,12 @@ import os ; import virtual-target ; project.initialize $(__name__) ; -project qt4 ; +project qt ; # Initialized the QT support module. The 'prefix' parameter -# tells where QT is installed. When not given, environmental -# variable QTDIR should be set. -rule init ( prefix ? ) +# tells where QT is installed. +rule init ( prefix ) { - if ! $(prefix) - { - prefix = [ modules.peek : QTDIR ] ; - if ! $(prefix) - { - errors.error - "QT installation prefix not given and QTDIR variable is empty" ; - } - } - if $(.initialized) { if $(prefix) != $(.prefix)