In the following, we will start by getting a minimal project working with Boost.Build and use it to compile a simple C++ file. Next, we will preprocess the C++ file and then postprocess the resulting binary. Finally we will see that tasks that are not related to C/C++ can be executed in two different ways: by creating a generator or by using the make rule.
We will start with an empty Jamfile and the following project-root.jam:
import toolset : using ; using gcc ;
With this set up, you should be able to run bjam, even though it will not do anything.
#include <iostream> using std::cout; using std::endl; int main() { cout << "Hello, world!" << endl; return 0; }
The following Jamfile will take that and create an executable called hello
exe hello : hello_world.cpp ;
If you run bjam now, you will find the newly create 'hello' executable in the bin/gcc/debug directory
Imagine that we could create our hello_world.cpp from a text file that contains the message to be printed, say hello_world.str
Hello, world!
To include that step into our project we will have to inform Boost.build that there exists a type of file that we call MESSAGE, with extension .str.
import type : register ; register MESSAGE : str ;
Next, we create a action that will convert MESSAGE into CPP. Here, we will do that using only UNIX shell commands:
actions convert { printf "" > "$(<)" printf "#include <iostream>\n" >> "$(<)" printf "\n" >> "$(<)" printf "using std::cout;\n" >> "$(<)" printf "using std::endl;\n" >> "$(<)" printf "\n" >> "$(<)" printf "int main() {\n" >> "$(<)" printf " cout << \"" >> "$(<)" awk '{printf $0}' "$(>)" >> "$(<)" printf "\" << endl;\n" >> "$(<)" printf " return 0;\n" >> "$(<)" printf "}\n" >> "$(<)" } IMPORT $(__name__) : convert : : convert ;
Everything inside the actions statement is going to be executed by the shell and is therefore platform dependent. The MESSAGE file for the conversion is $(>), while the CPP file is $(<). The IMPORT statement make the actions visible to other parts of the system.
We now have to tell Boost.Build that convert can be use to generate CPP files:
import generators : register-standard ; register-standard convert : MESSAGE : CPP ;
Having done all that, we can now create the hello executable from hello_word.str.
exe hello : hello_world.str ;
Here's the complete Jamfile
import type : register ; register MESSAGE : str ; actions convert { printf "" > "$(<)" printf "#include <iostream>\n" >> "$(<)" printf "\n" >> "$(<)" printf "using std::cout;\n" >> "$(<)" printf "using std::endl;\n" >> "$(<)" printf "\n" >> "$(<)" printf "int main() {\n" >> "$(<)" printf " cout << \"" >> "$(<)" awk '{printf $0}' "$(>)" >> "$(<)" printf "\" << endl;\n" >> "$(<)" printf " return 0;\n" >> "$(<)" printf "}\n" >> "$(<)" } IMPORT $(__name__) : convert : : convert ; import generators : register-standard ; register-standard convert : MESSAGE : CPP ; exe hello : hello_world.str ;
First, we need to tell Boost.Build about this new type of files:
import type : register ; register COMPRESSED : gz : : main ;The last argument (main) will automatically create a rule that we can use to create compressed files, just as we used the exe rule above.
And again, we can define a simple set of actions that do the actual work:
actions compress { gzip -c "$(>)" > "$(<)" } IMPORT $(__name__) : compress : : compress ;
Next step: register the conversion.
import generators : register-standard ; register-standard compress : EXE : COMPRESSED ;
We are now ready to use the newly-created compressed rule
compresssed hello : hello_world.str ;
The contents of our Jamfile so far are:
import type : register ; register MESSAGE : str ; actions convert { printf "" > "$(<)" printf "#include <iostream>\n" >> "$(<)" printf "\n" >> "$(<)" printf "using std::cout;\n" >> "$(<)" printf "using std::endl;\n" >> "$(<)" printf "\n" >> "$(<)" printf "int main() {\n" >> "$(<)" printf " cout << \"" >> "$(<)" awk '{printf $0}' "$(>)" >> "$(<)" printf "\" << endl;\n" >> "$(<)" printf " return 0;\n" >> "$(<)" printf "}\n" >> "$(<)" } IMPORT $(__name__) : convert : : convert ; import generators : register-standard ; register-standard convert : MESSAGE : CPP ; import type : register ; register COMPRESSED : gz : : main ; actions compress { gzip -c "$(>)" > "$(<)" } IMPORT $(__name__) : compress : : compress ; import generators : register-standard ; register-standard compress : EXE : COMPRESSED ; compressed hello : hello_world.str ;
.str -> .sh -> .sh.gz
While we implement those conversions, let's reorganize our code a little by introducing three more files.
In the sh.jam file we will register the new type with Boost.Build
import type : register ; register SHELL : sh ;
The conversion from MESSAGE to SHELL will be represented in the file str2sh.jam
import sh ; import type : register ; register MESSAGE : str ; actions convert { printf "" > "$(<)" printf "#!/bin/sh\n" >> "$(<)" printf "\n" >> "$(<)" printf "echo \"" >> "$(<)" awk '{printf $0}' "$(>)" >> "$(<)" printf "\"\n" >> "$(<)" } import generators : register-standard ; register-standard str2sh.convert : MESSAGE : SHELL ;
In the sh2zip.jam file we will describe the second conversion
import sh ; import type : register ; register COMPRESSED : sh.gz : : main ; actions compress { gzip -c "$(>)" > "$(<)" } import generators : register-standard ; register-standard sh2zip.compress : SHELL : COMPRESSED ;
Our Jamfile now can simply contain
import str2sh ; import sh2zip ; compressed hello : hello_world.str ;
To achieve that, we first need a replacement for the convert rule. We are a little limited by what the windows shell can do here but the following will do
actions convert.NT { echo #!/bin/sh > "$(<).tmp" echo cat ^<^<EOF >> "$(<).tmp" copy "$(<).tmp" + "$(>)" "$(<)" }
We will now introduce a convert rule that will dispatch either to convert.NT or to convert.UNIX depending on the operating system.
import os : name ; rule convert ( target : sources * : properties * ) { switch [ os.name ] { case "NT" : convert.NT $(target) : $(sources) ; case "*" : convert.UNIX $(target) : $(sources) ; } }
Our str2sh.jam file looks like this:
import sh ; import type : register ; register MESSAGE : str ; actions convert.UNIX { printf "" > "$(<)" printf "#!/bin/sh\n" >> "$(<)" printf "\n" >> "$(<)" printf "echo \"" >> "$(<)" awk '{printf $0}' "$(>)" >> "$(<)" printf "\"\n" >> "$(<)" } actions convert.NT { echo #!/bin/sh > "$(<).tmp" echo cat ^<^<EOF >> "$(<).tmp" copy "$(<).tmp" + "$(>)" "$(<)" } import os : name ; rule convert ( target : sources * : properties * ) { switch [ os.name ] { case "NT" : convert.NT $(target) : $(sources) ; case "*" : convert.UNIX $(target) : $(sources) ; } } import generators : register-standard ; register-standard str2sh.convert : MESSAGE : SHELL ;
We may also want to replace gzip with zip on Windows. Besides creating a dispatching compress, we will need:
import os : name ; switch [ os.name ] { case "NT" : register COMPRESSED : sh.zip : : main ; case "*" : register COMPRESSED : sh.gz : : main ; }
Here is sh2zip.jam file
import sh ; import type : register ; import os : name ; switch [ os.name ] { case "NT" : register COMPRESSED : sh.zip : : main ; case "*" : register COMPRESSED : sh.gz : : main ; } actions compress.UNIX { gzip -c "$(>)" > "$(<)" } actions compress.NT { zip "$(<)" "$(>)" } import os : name ; rule compress ( target : sources * : properties * ) { switch [ os.name ] { case "NT" : compress.NT $(target) : $(sources) ; case "*" : compress.UNIX $(target) : $(sources) ; } } import generators : register-standard ; register-standard sh2zip.compress : SHELL : COMPRESSED ;
compress hello : hello_world.str : <degree>maximum ;
The first thing we need is a new feature called degree that can take one of two values: minimum or maximum
import feature : feature ; feature degree : minimum maximum : free ;
Now we map those values into options to be passed to gzip and zip
import toolset : flags ; flags sh2zip.compress OPTIONS <degree>maximum : -9 ; flags sh2zip.compre
Finally, our compression tools can used the options:
actions compress.UNIX { gzip $(OPTIONS) -c "$(>)" > "$(<)" } actions compress.NT { zip $(OPTIONS) "$(<)" "$(>)" }
Here's the resulting sh2zip.jam
import sh ; import type : register ; import os : name ; switch [ os.name ] { case "NT" : register COMPRESSED : sh.zip : : main ; case "*" : register COMPRESSED : sh.gz : : main ; } import feature : feature ; feature compression : minimum maximum : free ; import toolset : flags ; flags sh2zip.compress OPTIONS <degree>maximum : -9 ; flags sh2zip.compress OPTIONS <degree>minimum : -1 ; actions compress.UNIX { gzip $(OPTIONS) -c "$(>)" > "$(<)" } actions compress.NT { zip $(OPTIONS) "$(<)" "$(>)" } import os : name ; rule compress ( target : sources * : properties * ) { switch [ os.name ] { case "NT" : compress.NT $(target) : $(sources) ; case "*" : compress.UNIX $(target) : $(sources) ; } } import generators : register-standard ; register-standard sh2zip.compress : SHELL : COMPRESSED ;
make hello.sh.gz : hello_world.str : create-and-compress ; actions create-and-compress { printf "" > "$(<:S=)" printf "#!/bin/sh\n" >> "$(<:S=)" printf "\n" >> "$(<:S=)" printf "echo \"" >> "$(<:S=)" awk '{printf $0}' "$(>)" >> "$(<:S=)" printf "\"\n" >> "$(<:S=)" gzip -c "$(<:S=)" > "$(<)" } IMPORT $(__name__) : create-and-compress : : create-and-compress ;
[buy lipitor online] [buy lipitor] [[buy lipitor online]]