diff --git a/v2/doc/src/reference.xml b/v2/doc/src/reference.xml index 15cf13f74..80775aace 100644 --- a/v2/doc/src/reference.xml +++ b/v2/doc/src/reference.xml @@ -118,6 +118,14 @@ boost-build build-system ; file must be compiled with special properties. + + preprocessed + preprocessed + + Creates an preprocessed source file. The arguments follow the + common syntax. + + glob diff --git a/v2/test/preprocessor.py b/v2/test/preprocessor.py new file mode 100755 index 000000000..9faa711b7 --- /dev/null +++ b/v2/test/preprocessor.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the C/C++ preprocessor. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("jamroot.jam", """ +project ; +preprocessed hello : hello.cpp ; +preprocessed a : a.c ; +exe hello.exe : hello a : FAIL ; +""") + +t.write("hello.cpp", """ +#ifndef __cplusplus +#error "This file must be compiled as C++" +#endif +#ifdef FAIL +#error "Not preprocessed?" +#endif +extern "C" int foo(); +int main() { return foo(); } +""") + +t.write("a.c", """ +/* This will not compile unless in C mode. */ +#ifdef __cplusplus +#error "This file must be compiled as C" +#endif +#ifdef FAIL +#error "Not preprocessed?" +#endif +int foo() +{ + int new = 0; + new = (new+1)*7; + return new; +} +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug/hello.ii") +t.expect_addition("bin/$toolset/debug/a.i") +t.expect_addition("bin/$toolset/debug/hello.exe") + +t.cleanup() diff --git a/v2/tools/builtin.jam b/v2/tools/builtin.jam index 5ad05b311..d1351a423 100644 --- a/v2/tools/builtin.jam +++ b/v2/tools/builtin.jam @@ -26,6 +26,7 @@ import stage ; import symlink ; import toolset ; import type ; +import targets ; import types/register ; import utility ; import virtual-target ; @@ -603,6 +604,48 @@ generators.register generators.override builtin.prebuilt : builtin.lib-generator ; +class preprocessed-target-class : basic-target +{ + import generators ; + rule construct ( name : sources * : property-set ) + { + local result = [ generators.construct [ project ] + $(name) : PREPROCESSED_CPP : $(property-set) : $(sources) ] ; + if ! $(result) + { + result = [ generators.construct [ project ] + $(name) : PREPROCESSED_C : $(property-set) : $(sources) ] ; + } + if ! $(result) + { + local s ; + for x in $(sources) + { + s += [ $(x).name ] ; + } + local p = [ project ] ; + errors.user-error + "In project" [ $(p).name ] : + "Could not construct preprocessed file \"$(name)\" from $(s:J=, )." ; + } + return $(result) ; + } +} + +rule preprocessed ( name : sources * : requirements * : default-build * : + usage-requirements * ) +{ + local project = [ project.current ] ; + return [ targets.main-target-alternative + [ new preprocessed-target-class $(name) : $(project) + : [ targets.main-target-sources $(sources) : $(name) ] + : [ targets.main-target-requirements $(r) : $(project) ] + : [ targets.main-target-default-build $(default-build) : $(project) ] + : [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ] + ] ] ; +} + +IMPORT $(__name__) : preprocessed : : preprocessed ; class compile-action : action { diff --git a/v2/tools/gcc.jam b/v2/tools/gcc.jam index ebd7a3c8e..3893c4e78 100644 --- a/v2/tools/gcc.jam +++ b/v2/tools/gcc.jam @@ -284,6 +284,8 @@ if [ os.name ] = NT JAMSHELL = % ; } +generators.register-c-compiler gcc.compile.c++.preprocess : CPP : PREPROCESSED_CPP : gcc ; +generators.register-c-compiler gcc.compile.c.preprocess : C : PREPROCESSED_C : gcc ; generators.register-c-compiler gcc.compile.c++ : CPP : OBJ : gcc ; generators.register-c-compiler gcc.compile.c : C : OBJ : gcc ; generators.register-c-compiler gcc.compile.asm : ASM : OBJ : gcc ; @@ -507,6 +509,37 @@ actions compile.c.pch "$(CONFIG_COMMAND)" -x c-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" } +rule compile.c++.preprocess ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + if ! $(>:S) in .cc .cp .cxx .cpp .c++ .C + { + LANG on $(<) = "-x c++" ; + } + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; +} + +rule compile.c.preprocess ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + LANG on $(<) = "-x c" ; + #} + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; +} + rule compile.c++ ( targets * : sources * : properties * ) { setup-threading $(targets) : $(sources) : $(properties) ; @@ -570,6 +603,16 @@ actions compile.c bind PCH_FILE "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" } +actions compile.c++.preprocess bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-$(TEMPLATE_DEPTH) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" "$(>:W)" -E >"$(<:W)" +} + +actions compile.c.preprocess bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" "$(>)" -E >$(<) +} + actions compile.fortran { "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" diff --git a/v2/tools/msvc.jam b/v2/tools/msvc.jam index a7731cb54..e33a66d22 100644 --- a/v2/tools/msvc.jam +++ b/v2/tools/msvc.jam @@ -325,6 +325,14 @@ rule compile.c ( targets + : sources * : properties * ) } +rule compile.c.preprocess ( targets + : sources * : properties * ) +{ + C++FLAGS on $(targets[1]) = ; + get-rspline $(targets) : -TC ; + preprocess-c-c++ $(<) : $(>) [ on $(<) return $(PCH_FILE) ] [ on $(<) return $(PCH_HEADER) ] ; +} + + rule compile.c.pch ( targets + : sources * : properties * ) { C++FLAGS on $(targets[1]) = ; @@ -363,6 +371,11 @@ actions compile-c-c++ bind PDB_NAME $(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER) } +actions preprocess-c-c++ bind PDB_NAME +{ + $(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" >"$(<[1]:W)" +} + rule compile-c-c++ ( targets + : sources * ) { DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_HEADER) ] ; @@ -370,6 +383,13 @@ rule compile-c-c++ ( targets + : sources * ) PDB_NAME on $(<) = $(<:S=.pdb) ; } +rule preprocess-c-c++ ( targets + : sources * ) +{ + DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_HEADER) ] ; + DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_FILE) ] ; + PDB_NAME on $(<) = $(<:S=.pdb) ; +} + # Action for running the C/C++ compiler using precompiled headers. In addition # to whatever else it needs to compile, this action also adds a temporary source # .cpp file used to compile the precompiled headers themselves. @@ -397,6 +417,12 @@ rule compile.c++ ( targets + : sources * : properties * ) compile-c-c++ $(<) : $(>) [ on $(<) return $(PCH_FILE) ] [ on $(<) return $(PCH_HEADER) ] ; } +rule compile.c++.preprocess ( targets + : sources * : properties * ) +{ + get-rspline $(targets) : -TP ; + preprocess-c-c++ $(<) : $(>) [ on $(<) return $(PCH_FILE) ] [ on $(<) return $(PCH_HEADER) ] ; +} + rule compile.c++.pch ( targets + : sources * : properties * ) { @@ -1110,6 +1136,8 @@ local rule register-toolset-really ( ) generators.register-archiver msvc.archive : OBJ : STATIC_LIB : msvc ; generators.register-c-compiler msvc.compile.c++ : CPP : OBJ : msvc ; generators.register-c-compiler msvc.compile.c : C : OBJ : msvc ; + generators.register-c-compiler msvc.compile.c++.preprocess : CPP : PREPROCESSED_CPP : msvc ; + generators.register-c-compiler msvc.compile.c.preprocess : C : PREPROCESSED_C : msvc ; # Using 'register-c-compiler' adds the build directory to INCLUDES. generators.register-c-compiler msvc.compile.rc : RC : OBJ(%_res) : msvc ; diff --git a/v2/tools/types/preprocessed.jam b/v2/tools/types/preprocessed.jam new file mode 100644 index 000000000..c9187ba67 --- /dev/null +++ b/v2/tools/types/preprocessed.jam @@ -0,0 +1,9 @@ +# Copyright Steven Watanabe 2011 +# Distributed under the Boost Software License Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import type ; + +type.register PREPROCESSED_C : i : C ; +type.register PREPROCESSED_CPP : ii : CPP ;