diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2010-02-05 18:01:45 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2010-02-05 18:01:45 +0200 |
commit | d7b7e218bfe92516f525568a6c1c9e1a9eb241fe (patch) | |
tree | 6cbc3155d7188f65e4b806c6edeecdd53393da69 /documentation |
Start tracking build with git
Diffstat (limited to 'documentation')
-rw-r--r-- | documentation/BUGS | 18 | ||||
-rw-r--r-- | documentation/CLEANUP | 2 | ||||
-rw-r--r-- | documentation/CONFIGURATION | 64 | ||||
-rw-r--r-- | documentation/DOC | 16 | ||||
-rw-r--r-- | documentation/FACILITIES | 16 | ||||
-rw-r--r-- | documentation/FEATURES | 5 | ||||
-rw-r--r-- | documentation/IDEAS | 156 | ||||
-rw-r--r-- | documentation/INSTALLATION | 5 | ||||
-rw-r--r-- | documentation/ISSUES | 72 | ||||
-rw-r--r-- | documentation/MAKE | 31 | ||||
-rw-r--r-- | documentation/NOTES | 34 | ||||
-rw-r--r-- | documentation/OPTIMIZATION | 21 | ||||
-rw-r--r-- | documentation/PROBLEMS | 70 | ||||
-rw-r--r-- | documentation/RELEASE | 7 | ||||
-rw-r--r-- | documentation/SHOWCASE | 85 | ||||
-rw-r--r-- | documentation/STYLE | 23 | ||||
-rw-r--r-- | documentation/TARGETS | 30 | ||||
-rw-r--r-- | documentation/TODO | 9 | ||||
-rw-r--r-- | documentation/default.css | 160 | ||||
-rw-r--r-- | documentation/index.xhtml | 970 |
20 files changed, 1794 insertions, 0 deletions
diff --git a/documentation/BUGS b/documentation/BUGS new file mode 100644 index 0000000..ec499ae --- /dev/null +++ b/documentation/BUGS @@ -0,0 +1,18 @@ +@@ Messages during configuration should be about 80 chars long. + Right now they are much shorter which makes it look really ugly. + +@@ some keywords (l:) are being framed + +%% Relative paths result in rebuilds. + +@% When configuring with -j N some strange warnings appear. Temporary + fix. Depends on GNU make bug #12229. + +%% Use src_root path as default value for out_root. + +@@ Intel C++ does not generate phony rule for non-existent headers. + +@@ It seems to me that in generated header prefix logic the dependency + patched by sed script and one produced by a subsequent run of the + compiler are different which triggers makefile reload. I wonder + why?
\ No newline at end of file diff --git a/documentation/CLEANUP b/documentation/CLEANUP new file mode 100644 index 0000000..fc3e263 --- /dev/null +++ b/documentation/CLEANUP @@ -0,0 +1,2 @@ +%@ add project_name, add corresponding message to all configuration scripts +
\ No newline at end of file diff --git a/documentation/CONFIGURATION b/documentation/CONFIGURATION new file mode 100644 index 0000000..feed13c --- /dev/null +++ b/documentation/CONFIGURATION @@ -0,0 +1,64 @@ + +@@ It would be nice if configuration happens only when it is + required. For example if I need to build something that + uses CORBA then only in this case happens configuration of + CORBA facilities. + + +@@ 'configure' should depend on 'clean' + + +@@ What if I change something in config file (let's say archive to shared) + and then say make - things will break. + + +@@ It would be nice if I could keep build/ outside of the project. This + is going to be very useful when multiple projects share the same + build system. + +@@ it would be nice to have a project_base which will be + $(root)/example/project. However, in normal most cases project will be + the same as root, right? Look at CCF. Some comments: + + Saying -I$(root) would be exactly what I need if its value would be + .../example/project. This, according to the concept of clusters, could + be achived if I make .../example/project a cluster (which is quite + natural thing to do). It would also be a good example of a cluster. + + +@@ Right now I have one global implicit rule for the project. In most + cases this is probably enough. But what if I want to use different + rules for different sub-projects (config clusters). For example two + parts of the same project could use different compilers or ORB or... + Probably the generic approach would be to provide sub-dir specific + rules. + +@@ concept of configuration clusters (no more src_root). + + +@@ Can I get rid of src_root and out_root (i.e. can they be /)? + + +@@ It would be nice if I could configure the same sub-system + (like CORBA) for dirrefent parts of the project differenty. + + +@@ Do I really need those configuration clusters? Is the structure + of CCF right? Or am I just trying to hide problems of wrong + structuring? Isn't it overcomplication? Even if not shouldn't + I postpone this until I gain more experience? + +--------------------- + +@@ Each project includes (in its root directory) copy of the build system. + +@@ The build system is configuration cluster. + +@@ Configuration cluster sets src/out_root. + +@@ Configuration cluster can inherit configuration from its parent. + +@@ Configuration cluster can override inherited values. + +@@ sub-projects in configuration cluster should not refer to anything + outside of this cluster. diff --git a/documentation/DOC b/documentation/DOC new file mode 100644 index 0000000..0ace1cf --- /dev/null +++ b/documentation/DOC @@ -0,0 +1,16 @@ +@@ Update to describe new option importing mechanism. Maybe even + include some general model of project building? + + +@@ Create style section and put STYLE file there. + + +@@ Describe canonical targets (from targets). + +@@ Currently I have no description of targtes (e.g., nobody knows about + disfigure). + +@@ Update documentation with the new output from examples. + +@@ Add News section to the index.xhtml + diff --git a/documentation/FACILITIES b/documentation/FACILITIES new file mode 100644 index 0000000..26492f4 --- /dev/null +++ b/documentation/FACILITIES @@ -0,0 +1,16 @@ + +@@ can I have different strategies for src/out? Would I be able + to come up with generic implicit rules that work for all cases? + +@@ optional facilities could go into pre-load. + +@@ from building point of view distinction on source and generated + files is not essential. + +@@ Common places for generated files (from multi-arch): + + - home (out == src) + + - parallel structure outside (out is set based on curdir?) + + - subdirs in source (potentially many) (out := src + something) diff --git a/documentation/FEATURES b/documentation/FEATURES new file mode 100644 index 0000000..1068025 --- /dev/null +++ b/documentation/FEATURES @@ -0,0 +1,5 @@ +@@ Allow multiple files in $(call load ). + +@! Extract compiler-specific include paths to create do-nothing rules + for headers. + diff --git a/documentation/IDEAS b/documentation/IDEAS new file mode 100644 index 0000000..649f375 --- /dev/null +++ b/documentation/IDEAS @@ -0,0 +1,156 @@ +@@ Need to create some show-case with some intermidiate compiler like + idl/lex/yacc. M4 comes to mind. + +%% Stages of building + + 1. configure/configuration + + 2. build/build + + 3a. test/testing + + 3b. install/installation + +@@ Maybe I should have a special function for inclusion from special + directories (like Build). + +@@ it would nice to have suffixes configurable + +@@ There could be a set of files to configure building environment (like + suffixes of files, names of utilities, etc). If I decide to ship + environment as standalon product I will have to somehow separate + those files (like putting in different directories). + +@@ It would make sense to split build system on subsystems like 'base' + 'c' 'cxx', 'corba/cxx' etc. + +%% Maybe I should pre-load some commonly used patterns. + +@@ Maybe makefiles that are not ment to be used interactively should + inherit their interactivity status from their includer. + +@@ Allow changing of options based on the category (plus all). This + can be done like this: + + %.o : %.cpp : cxx_options = $(cxx_cpp_flags) $(cxx_debug_flags) $(cxx_diagnostic_flags) + %.o : %.cpp : cxx_cpp_options := + %.o : %.cpp : cxx_debug_options := -g + %.o : %.cpp : cxx_diagnostic_options := -Wall + + This will allow the user to change only what he want without much + hassle. + +@! Can I make a dependecy of lib.l on lib.so? Should I? Or should I list + .so/.a in the pattern rule so it gets deleted? + +@@ It would be nice to have a custom message for phony targets that merely + depend on normal targets. For example if I could get a list of targets + that were updated I would have been able to print such a message. This + would probably require modifications to make. + + For default target of a dispatch makefile (better name?) I use directory + name which makes perfect sense. BTW, maybe I should call them directory + makefiles, or meta-makefiles, or stubs? + +@@ Since the build of multiple goals in the same target can be tricky I + may want to detect this and give a warning/error (this could be + configurable). + +@@ 'cxx' should depend on 'c'. 'cxx' can reuse ar facility from 'c'. + +@@ Make function extension framework. The idea is to use $(shell) to call + arbitrary executable/shell-script. The only problem is that I need a + way to build something before continuing to read makefile. Something + like .REQUIRE: target? When make sees this it stops reading makefile + and tries to build the target. If build succeeded make resumes to + read the makefile. If build failed make stops with an error. + + The other, more advanced, idea is to use dynamic loading of functions. + This way it will be alot faster. + + If included makefiles could be rebuilt on the spot (i.e. without + first reading the rest) then it would be a way. + +@@ Can I use linker script instead of my .l library descriptor (or together + with?). + +@@ There is a support for 'version script' in ld. I wonder what is that. + +@@ study linux kernel build system + +@! Maybe clean/disfigure target should include deletion of a directory + if (a) the build could potentially create it and (b) it is empty. + This way things will be cleaner and, after saying make clean in the + build directory, one gets just configuration. + +@@ I can ask user if he wants to override default .a/.so search paths + (for example to match the compiler). + + +@@ Multidir example probably belongs to c subsystem. + +@@ If I have build-as-you-need-them makefile inclusion scheme then if I + include makefiles in a proper order I can get rid of those + 'configuring blah-blah' messages. + +@@ I can be cool and make 'ls' in cxx to find present c++ compilers. This + way I will be able to distribute compiler-specific files separately. + +@@ It would be nice to have include function that includes a file + relatevely to the current's Makefile directory. + +@@ Maybe factor out cpp as a common facility in 'c'? Right now I duplicate + some support code in cxx/gnu and cxx/intel. + +@@ All this '.l' abstraction support belongs to 'c'. + +@@ In import/export stubs check for version compatibilities. Oohooo! + +@@ What if I save src_root somewhere in out_root? + +%% Need to try to use build with distcc. Works well. + +@@ I may want to store src_root someweher in out_root so that I don't + need to ask for it (will not work in all cases). + +@! It is probably a good idea to make each file responsible for + making sure its guts are included right number of times. + +@! With introduction of .NOT_DEFAULT I can factor out aliasing into + (per-project) bootstrap.make. Did in some projects - works well. + Need to do them in example. + +@@ foreach is a way to define local variable. + +@! use $(< file) instead of cat + +@! use last dir + relative path in messages + +@! what about using few-letters vars instead of cxx_obj (o) cxx_od (d)? + +@! How about uniform importing facility without any subsystems? For example + CORBA is a translator and a library at the same time - how to handle it? + + - can use whatever names in imported files. + + - will need importing from project build dir and from bld_root + +@! Need to think about hacker mode - passing config info via command line + with standard names like CXX CPPFLAGS LDFLAGS, etc. + +@! teach import stubs to not try include anything when cleaning/disfiguring? + +@@ local target that will rebuild only local object files? Or maybe set an + order of rebuilding local files first? + +@! Now since I have .DEFAULT_TARGET I can do save/restore thing for export + import. So there won't be a need to secure default target. Way too cool! + +%% Usually src_root and out_root are the same. I should suggest one + by default when asking user for it. + +@@ There are two situations where I can guess src_root from out_root: + first is when out_root == src_root (I can check for build/bootstrap.make + though bootstrap.make can be named differently). The other case is when + out_root already contains build project (I will need to kind of marker + that contains value of src_root; maybe build/configuratio-dynamic.make). diff --git a/documentation/INSTALLATION b/documentation/INSTALLATION new file mode 100644 index 0000000..24eebcf --- /dev/null +++ b/documentation/INSTALLATION @@ -0,0 +1,5 @@ +%% used install -d to create directories during installation. + +%@ splitting, completion, and cleanup + +%% terse messages for installation commands. diff --git a/documentation/ISSUES b/documentation/ISSUES new file mode 100644 index 0000000..e7b4263 --- /dev/null +++ b/documentation/ISSUES @@ -0,0 +1,72 @@ +@@ use shell && instead of multi-line rules since they don't consider + atomic (e.g. if something failed other files won't be deleted). Or + maybe not, think about it (and read the doc). + +@@ Some implicit rule should actually be two rules: one that looks + for the source under srd_root tree and the other under out_root. + Theoretically, any source could be just an intermidiate file generated + from something else (discovered while playing with idl). + +@@ Compensating rules: 'clean all' example. + +@@ Issues from "Multi-Architecture Builds Using GNU make": + + - big (bloated) makefiles + + - cannot say "make foo.o" + +@@ How can I integrate building of realpath utility in configuration + process? + +@@ Executing make from non-source directory is painful. Can I make it + easier? + +%% When shared library is linked with absolute path the loader is looking + for the library with the same path. See also -soname= and -rpath ls + options. + +@@ With multidir makefiles I loos the ability to say make where I am. + This is especially nasty when I edit a file and then say make. This + happens for example in CCF. The easy workaround is to say something + "make -C dir/to/test/driver". Once this is done life get very nice. + Actually I think this could be the best approach. + +@@ Variable inheritance doesn't play well with 'make foo.o'. + +@@ Configurations include absolute paths to imported libraries which + makes it hard to reuse them. In this light configurations on installed + libraries should not include any absolute paths. + +@@ Better name for project_name? build_name? + +@@ Repetition of paths in $(call message) is quite ugly. Anything I can do? + +@@ -MP conflicts with --no-implicit-phony. The new approach uses a special + terminal pattern rule to handle this. However headers without suffix + cannot be handled by this method. + +@! Delete-on-error does not cover .o.d files. I could specify it as a target + together with .o but then it will try to rebuild it. + +@! When you hide things from make (like .o.d or .l/.so) all sorts of bad things + happen. + +@@ What is a better term for development (not installed?) build? + +@@ /usr/bin/g++ is a link but extracted include paths have precise version in + them (e.g. 3.3.4). But then dependencies will trigger update, right? + +@! I am using some of the features of GNU find which are not available in SUS. + +@@ Since .l.cpp-options pattern does not have any prereqs then the file can + always be created (example: I misspelled file name). + +@@ Use abspath to prevent call-inclusion from -I dirs. + +@@ lib.cpp-options should be lib.cpp_options? + +@@ Use $@ in $$(dir $(out)/%). + +@! Need to make content of .l compiler-independant (rpath stuff). + +@@ export is now position-sensitive. diff --git a/documentation/MAKE b/documentation/MAKE new file mode 100644 index 0000000..50e073b --- /dev/null +++ b/documentation/MAKE @@ -0,0 +1,31 @@ + +@@ I was thinking about the way make handles inclusion of missing + makefile. The following strategy seems like a better choice: + if makefile is missing try to rebuild & read it immediately, + without parsing the rest of makefile and without reexecuting + make later. This approach has at least two benefits: + + + more efficient (no make re-execution) (this is not very + important in most cases, thoug) + + + more deterministic: if some of the code after (missing) + included makefile depends on some code from it (for + example a function) then things can break (example: + configuration of ORB). + + - sequential (cannot build makefile in parallel) + + +@! target/pattern-specific vpath + +@@ no `target is up to date' message when commnds are executed + but target is not changed. + +@@ %.o %.d and include + +%% implicit double expansion: now supports target/pattern variables + and $- + +%% create `examples' directory where I can put md5 and maybe hello. + +@! shortest stem diff --git a/documentation/NOTES b/documentation/NOTES new file mode 100644 index 0000000..7bed2c8 --- /dev/null +++ b/documentation/NOTES @@ -0,0 +1,34 @@ +@@ ?= is deferred + +@@ automatically-generated dependecies should include absolute paths + just like gcc does. Note that it only happens when you pass gcc + absolute paths in -I so I should watch out! + +@@ order-only dependencies allow for elegant creation of a directory + before build. + +@@ need to try generation of headers in out_dir. + +@@ maybe think about shared library versioning. This could be done + transparently at installation time. + +%% I should use some form of include function for -include for + consistency. + +@@ linker accepts -O options and can opimize. + +@@ use suffix (.make, .cxx) to specify file type - not as a mere + separator. Can I use '-' as separator? Should I use '_' as separator? + +@@ read lisp ASDF manual. + +@@ Use $(eval foo:=bar) in rule's command to set variable only if (and after) + the rule is in use. + +%% Files in import directory are called configuration. They are not quite + that. Maybe a better name would be stub? + +@@ For some (all? SUS?) platforms inclusion of .so in .l is redundant + because .so is already linked against them. + +@@ Need to continue cleaning if some files do not exist (rm -f ?). diff --git a/documentation/OPTIMIZATION b/documentation/OPTIMIZATION new file mode 100644 index 0000000..dfdb06d --- /dev/null +++ b/documentation/OPTIMIZATION @@ -0,0 +1,21 @@ +%% I should keep a separate list of files that are included-once which + should also cache the realpaths. + +@@ It would make sense to use $(call include-once,out_dir) in cxx/cxx-o.make + etc. + +@@ Need to check what is being framed. + +@@ I wonder how much it costs to have the second expansion in implicit rule? + +@@ Make executes each line in a separate shell. I wonder if using && is + more efficient? + +%% check make's default hash table size. + +@@ would using `makefile: ' tecknique to prevent make from trying to + match against pattern-rules help? + +@@ Look for redundant $(eval ) calls (like I had in include-*). + +@@ use head -n 1 instead of sed -e 1q diff --git a/documentation/PROBLEMS b/documentation/PROBLEMS new file mode 100644 index 0000000..a07fbda --- /dev/null +++ b/documentation/PROBLEMS @@ -0,0 +1,70 @@ +STRUCTURE + + +VARIABLES + +%% It would be nice to be able to include makefile in a way that + variables are restored. + +@% I definitely need some naming convention for "global" variables. + Since I include potentially unknown makefiles (like library + dependecies) I cannot predict what they do. This is another + argument for variable framing. + + Some ideas: + + - Variables that start and end with '%' are considered global + and system. Subsystems may define such vars if there is + a real need. (Currently defined names should be documented + here. Each subsystem should document names that it defines.) + Subsystem should prefix each such var with its name (e.g. cxx_). + + - Variables that contain '-' are considered 'functions' and not + framed. Generally subsystems should define those. The names + should be chosen carefully in order not to cause name clashes. + (Each subsystem should document names that it defines). + Subsystem should prefix each such function with its name + (e.g. cxx-). + + - Variables that appear in %frame_exclude% are not framed. General + rule is to add only special one-word functions (usually defined + by base subsystem) that are used often and thus having one-word + terse name is very important; for example 'include' or 'import' + + +%% After the inclusion of dependency makefiles I cannot use src_base + becasue it was reset by the included file. So I am forced to use + src_root now which will hurt especially sore when I include from + sub-directories. + + + +DEPENDENCIES : STRUCTURE + +@@ It would be nice to be able to chose dependency type project-wise + and on a by-makefile basis. This could be tricky, however. + +@@ Missing headers assumed generated with some inflexible logic (cur dir). + This can also vary among compilers (which is not something I would worry + too much as long as g++ works). Can I make it more reliable? Maybe capture + this (or essential) dependecies in a Makefile? + +@@ Can I specify dependencies in CORBA projects manually. Do I want to do + that? + +@@ Don't include dependecies when cleaning (configuring?). + + + +MISC + +@@ If I have generated idl files in src directory then build in some other + directory will fail or will use wrong headers. + +%% .NOT_DEFAULT: target in make? + +%@ configuration targets should not be parallel. try make -j 4 Maybe I can + detect that those files do not exist and disable parallelism for this + run. See .MUTEX bug (#3656). + +@@ relative paths and pattern matching does not work very well together diff --git a/documentation/RELEASE b/documentation/RELEASE new file mode 100644 index 0000000..fc216ed --- /dev/null +++ b/documentation/RELEASE @@ -0,0 +1,7 @@ +@@ add header to every file. + +@@ make sure all files conform to the STYLE. + +@@ remove empty directoris (left after disfigure) in examples/ + +@@ update copyright diff --git a/documentation/SHOWCASE b/documentation/SHOWCASE new file mode 100644 index 0000000..1a032f2 --- /dev/null +++ b/documentation/SHOWCASE @@ -0,0 +1,85 @@ +#@@ if a showcase complicated the initial example then it should +# be implemented as a separate example. + +%% build with nested directories from single Makefile + +%% generation of headers/sources from some other source with + automatically generated dependencies (IDL showcase) + +%% two executables in the same dir (though generally not recomended) + +%% selection of PIC by a target (target-specific variables + inheritance) (read the bug report about this feature). + +%% directory Makefiles (need a nice name for them) + +%@ configuration target + + - implemented disfigure only (for now). + + - not complete + + - need to implement configuration of installed dependencies. + +%@ installation target + + - prototype design + + - needs completion + +%@ test target + + - only in libhello + +%% generation of actual dependencies for C++/C + +@@ use of C & C++ compiler from the same Makefile + +@@ another C++/C compiler (Sun CC?) + +@@ cleaning after messy compilers (Sun CC?) + +@@ c subsystem + +@@ Quite mode. all answers defaulted. Error if something is wrong. + +@@ I need some way of programmatically supplying configuration + information (for example for debian package creation). Via + command line variables seems like a reasonable approach. Also + saving configuration seems like a good idea too (i.e. keeping + configuration around) but then I need to make sure there are + no absolute paths. + +%@ Installation process for the build system itself. + + - now installs only build system itself. + +%% What am I going to do with corba? Maybe package it as a separate + incomplete subsystem? + +@% All those "file not found" messages by make are quite nasty. I should + either fix make (preferable) or use -include. + + - using -include for now + +%% variable unsetting: do I still need it? Yes I do. + +@@ installation of examples + +@@ need to clean source code out of @@ + +@! target-specific vpath + +@! Can .INTERMIDIATE help me with .d problem? No! Also it seems + saying something like %.o %.d: %.cxx won't work either? Need + to check this. + +@! Need to run ranlib on certain platforms. Need to detect if I need to. + +@! .cpp-options: if add/remove .cpp-options prereqs the target file does not + get regenerated. Probably need to save list of prereqs and compare with it. + +@! shared library versioning + +@! Need to think on a general idea of state saving (like I do with + .cpp-options). Is there a cleaner way of doing this? diff --git a/documentation/STYLE b/documentation/STYLE new file mode 100644 index 0000000..32799f6 --- /dev/null +++ b/documentation/STYLE @@ -0,0 +1,23 @@ +@@ write "t: p" instead of "t : p" or "t :p" + +@@ write $(call f,a) instead of $(call f, a) or $(call f , a) + +@@ Use '-' to separate words in function names (e.g. foo-bar); + use 'define' to define functions. + +@@ Use '_' to separate words in variable names (e.g. foo_bar); + use := to assign value to a variable. Use '=' if you know + what you are doing. + +@@ Be careful with += in target-specific variables. + +@@ Action explicitly requested by the user (which should correspond + to verbs, e.g. install, clean, configure) should perform without + regards to up-to-dateness. + +@@ Use verbs for .PHONY targets. There is one notable exception:... + +@! maybe declare `__' variable prefix reserved? + +@@ Use directory name as a default phony target in directory makefiles. + (explain why).
\ No newline at end of file diff --git a/documentation/TARGETS b/documentation/TARGETS new file mode 100644 index 0000000..ff5476f --- /dev/null +++ b/documentation/TARGETS @@ -0,0 +1,30 @@ + +# Configuration +# + +configuration +configure : disfigure +disfigure : clean + +# build +# + +build : configuration +clean + + +# test +# +test : build + + +# install +# +install : build +uninstall + + +# help +# + +help diff --git a/documentation/TODO b/documentation/TODO new file mode 100644 index 0000000..4aec2c6 --- /dev/null +++ b/documentation/TODO @@ -0,0 +1,9 @@ +!! Need to change include path in hello example. + +!! And change to #include <> + +!! Need to get rid of those header patterns or implement shortest stem. + +!! finish cxx-d.make + +@@ Add include-dep to examples. diff --git a/documentation/default.css b/documentation/default.css new file mode 100644 index 0000000..7242a94 --- /dev/null +++ b/documentation/default.css @@ -0,0 +1,160 @@ +body { + font-family : sans-serif; + font-weight : normal; + + color : black; + background : white; + + max-width : 42em; + padding : 2em 2em 2em 3em; + margin : 0 auto; +} + +h1, h2, h3, h4, h5, h6 { + font-family : sans-serif; + font-weight : 500; +} + +h1 { font-size : 170%; } +h2 { font-size : 145%; } +h3 { font-size : 125%; } +h4 { font-size : 110%; } +h5 { font-size : 106%; } +h6 { font-size : 100%; } + + +p.indent { + margin-left : 1.5em; +} + + +/* table of content */ +ul.toc li { + padding : .4em 0em 0em 0em; +} + + + +/* list of links */ +ul.menu { + list-style-type : none; +} + +ul.menu li { + padding-top : 0.3em; + padding-bottom : 0.3em; +} + + + +/* @@ I should probably use child selector here */ +/* list with multiline list-elements */ +ul.multiline li { + padding-top : 0.4em; + padding-bottom : 0.4em; +} + +ol.multiline li { + padding-top : 0.4em; + padding-bottom : 0.4em; +} + +dl.multiline dd { + padding-top : 0.4em; + padding-bottom : 0.4em; +} + +/* code */ + +code { + font-size : 114%; + font-family : monospace; +} + + +/* C++ code snippet */ +pre.cxx { + + margin-top : 0em; + margin-bottom : 2em; + + margin-left : 1em; +} + + + +/* make code snippet */ +pre.make { + + margin-top : 0em; + margin-bottom : 2em; + + margin-left : 1em; +} + + + +/* terminal output */ +pre.term { + + margin-top : 0em; + margin-bottom : 2em; + + margin-left : 1em; +} + + +/* Images */ +div.center { + text-align: center; +} + +/* Navigation. */ +#navigation { + margin-top: 1em; + border-bottom: 1px dashed #000000; +} + +#content { + margin-top: 2.5em; +} + + +/* Document info. */ +#docinfo { + margin-top: 4em; + border-top: 1px dashed #000000; + font-size: 70%; +} + +/* distribution terms */ +div.terms { + font-size : 114%; + font-family : monospace; +} + + + +/* Footnote */ + +#footnote { + margin-top: 2em; +} + +#footnote hr { + margin-left: 0; + margin-bottom: 1.5em; + width: 8em; + border-top: 1px solid #000000; + border-right: none; + border-bottom: none; + border-left: none; + +} + +#footnote p { + font-size: .91em; + text-indent: -0.8em; + padding-left: 0.8em; +} + diff --git a/documentation/index.xhtml b/documentation/index.xhtml new file mode 100644 index 0000000..afc655c --- /dev/null +++ b/documentation/index.xhtml @@ -0,0 +1,970 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> + +<!-- + +file : documentation/index.xhtml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : Copyright (c) 2004-2010 Code Synthesis Tools CC +license : GNU FDL v1.2; http://www.codesynthesis.com/licenses/fdl-1.2.txt + +--> + +<!-- +@@ maybe background code? + +@@ describe all feature that appear in the example. +--> + +<head> + + <title>build/documentation</title> + + <meta name="author" content="Boris Kolpackov"/> + <meta name="copyright" content="© 2004-2010 Code Synthesis Tools CC"/> + <meta name="keywords" content="build,system,make"/> + <meta name="description" content="build/documentation"/> + + <link rel="stylesheet" type="text/css" href="default.css"/> + +</head> + +<body> +<div id="content"> +<ul class="toc"> +<li><a href="#introduction">Introduction</a></li> +<li><a href="#fundamentals">Fundamentals</a></li> +<li><a href="#first_example">First Example</a> + <ul> + <li><a href="#invocation">Invocation</a></li> + <li><a href="#makefiles">Makefiles</a></li> + </ul> +</li> +<li><a href="#inter_project_dependencies">Inter-Project Dependencies</a></li> +<li><a href="#administrivia">Administrivia</a> + <ul> + <li><a href="#license">License</a></li> + <li><a href="#bootstrapping">Bootstrapping</a></li> + <li><a href="#versioning">Versioning</a></li> + </ul> +</li> +</ul> + + +<h1><a name="introduction">Introduction</a></h1> + +<p>I hear you saying: "Yeah, yeah, another marvelous make +replacement with built-in support for various compilers, automatic +dependency scanning, parallel and distributed builds, and XML instead of +makefiles!" On the contrary, <em>build</em> is a software build system +that is implemented on top of GNU make. It defines extensible framework for +translators, delegates most of its tasks to existing tools, and uses GNU +make syntax for makefiles. <em>Build</em> was designed with the following +tasks in mind:</p> + +<ul class="multiline"> + <li>configuration</li> + <li>building</li> + <li>testing</li> + <li>installation</li> +</ul> + +<p>As distribution of software in source code is being replaced by +precompiled package distributions, greater emphasis was placed on +development-time conveniences. Some of the features of <em>build</em> +include:</p> + +<ul class="multiline"> + <li>position-independent makefiles</li> + + <li>non-recursive multi-makefile include-based structure</li> + + <li>leaf makefiles are full-fledged GNU makefiles, not just + variable definitions</li> + + <li>complete dependency graph</li> + + <li>inter-project dependency tracking</li> +</ul> + +<p>To understand leaf makefiles in this manual you will need basic +knowledge of how <code>make</code> works. However, inside, <em>build</em> +uses some of the more advanced features of GNU make including</p> + +<ul class="multiline"> +<li>order-only prerequisites</li> +<li>pattern and target-specific variables</li> +<li><code>$(call )</code> and <code>$(eval )</code></li> +<li>different flavors of <code>include</code> directive</li> +</ul> + +<p>If you find usage of some of the <code>make</code> techniques obscure +in this text you can always consult with the +<a href="http://www.gnu.org/software/make/manual/make.html">GNU make +manual</a>.</p> + + +<h1><a name="fundamentals">Fundamentals</a></h1> + +<p><em>Build</em> defines a framework in terms of which user makefiles +are written. Below is the list of fundamental concepts.</p> + +<dl class="multiline"> +<dt>Project</dt> +<dd>is a separately distributable collection of source files. A more +intuitive way of defining a project would be to say it's what you +normally assign a version number to (e.g., <code>libhello-0.0.1</code>) +and package as a tar ball (e.g., <code>libhello-0.0.1.tar.gz</code>). +A reasonably complex project usually has a hierarchy of sub-directories +under its root directory.</dd> + +<dt>Component</dt> +<dd>is part of a project for which you would normally write a +makefile. For example our <code>libhello</code> could consist of +two components: the library itself and a test driver.</dd> + +<dt>Source root</dt> +<dd>is a root directory of a project. For example, if we unpack our +<code>libhello-0.0.1.tar.gz</code> to <code>/tmp</code> and end up with +a directory <code>/tmp/libhello-0.0.1</code> then that would be this +project's <em>source root</em>.</dd> + +<dt>Source base</dt> +<dd>is a directory of a component in a project. Continuing our example, +if our <code>libhello</code> project had a subdirectory <code>test</code> +then the <em>source base</em> of the <code>test</code> component would be +<code>/tmp/libhello-0.0.1/test</code>. By definition, any <em>source base</em> +is a sub-directory of a <em>source root</em> for any particular project.</dd> + +<dt>Out root</dt> +<dd>is a root directory of a project's build (or output) hierarchy. This +directory signifies where generated files for the project will be placed. +For example, if we decide to build <code>libhello</code> in +<code>/tmp/libhello-i686-pc-linux-gnu</code> then that would be one of the +possible <em>out roots</em>.</dd> + +<dt>Out base</dt> +<dd>is a build (or output) directory of a component in a project. +If we continue our example, the <em>out base</em> for the <code>test</code> +component would be <code>/tmp/libhello-i686-pc-linux-gnu/test</code>.</dd> +</dl> + +<p>The <em>build</em> runtime defines four <code>make</code> variables that +correspond to the last four definitions:</p> + +<pre class="make"> +src_root +src_base +out_root +out_base +</pre> + +<p>Below is an example of how you could use some of them.</p> + +<pre class="make"> +driver := $(out_base)/driver + +$(driver): $(out_base)/driver.o $(out_root)/libhello/libhello.so +</pre> + +<p>Additionally, the <em>build</em> framework defines three more +variables:</p> + +<pre class="make"> +bld_root +scf_root := $(src_root)/build +dcf_root := $(out_root)/build +</pre> + +<p><code>bld_root</code> is a root directory of the <em>build</em> runtime. +Normally you would use it to include one of the <em>build</em>'s files.</p> + +<p><code>scf_root</code> stands for static configuration root and +points to a directory where project's static configuration is kept. +<code>dcf_root</code> stands for dynamic configuration root and +points to a directory where project's dynamic configuration is kept. +We will talk more about those two variables later.</p> + +<p>Also note that having <code>src_root</code> the same as +<code>out_root</code> is perfectly valid and indicates that we +are building in a source directory.</p> + +<h1><a name="first_example">First Example</a></h1> + +<p>Now we are ready to examine our first simple example. We +will skip one-file C-based "hello world", however, because it +is not very practical and there is not much room for improvement. +Rather we will start from a <code>libhello</code> library, a test +driver for it and a <code>hello</code> program that uses the library. +To make our example even more realistic the <code>libhello</code> +library and the <code>hello</code> program are two separate projects. +And, did I mention, they are written in C++. See +<code>examples/cxx/hello</code>.</p> + +<h2><a name="invocation">Invocation</a></h2> + +<p>Let's first get some user experience without looking into makefiles. +Suppose we unpacked <em>build</em> source into <code>/tmp/build-0.1.12</code>. +First let's try to build <code>libhello</code>:</p> + +<pre class="term"> +$ cd /tmp/build-0.1.12/examples/cxx/hello/libhello +$ make + + +configuring 'libhello' + + + +Please select the C++ compiler you would like to use: + +(1) GNU C++ (g++) +(2) Intel C++ (icc) + +[1]: 1 + +Would you like the C++ compiler to optimize generated code? + +[y]: y + +Would you like the C++ compiler to generate debug information? + +[y]: y + + +configuring 'libhello' + + + +Please select the default library type: + +(1) archive +(2) shared object + +[2]: 2 + + +configuring 'libhello' + + + +Please enter the g++ binary you would like to use, for example 'g++-3.4', +'/usr/local/bin/g++' or 'distcc g++'. You can use path auto-completion. + +[g++]: g++ + +Please select the optimization level you would like to use: + +(1) -O1 [Tries to reduce code size and execution time, without + performing any optimizations that take a great deal of + compilation time.] +(2) -O2 [Performs nearly all supported optimizations that do not + involve a space-speed tradeoff.] +(3) -O3 [Optimize even more.] +(4) -Os [Optimize for size.] + +[2]: 2 +c++ /tmp/build-0.1.12/examples/cxx/hello/libhello/libhello/hello.cxx +ld /tmp/build-0.1.12/examples/cxx/hello/libhello/libhello/hello.l +c++ /tmp/build-0.1.12/examples/cxx/hello/libhello/test/driver.cxx +ld /tmp/build-0.1.12/examples/cxx/hello/libhello/test/driver +</pre> + +<p>Here we were presented with a bunch of configuration questions. +If you have <code>g++</code> in your default path you can just keep +hitting enter to select defaults. If you would like to see real commands +that are being executed (useful when something goes wrong) you can +say <code>make verbose=1</code>.</p> + +<p>From the messages above we can deduce that we have built the +<code>libhello</code> library (<code>hello.l</code>) and the test driver +for it (<code>test/driver</code>). So far so good. Now let's try to build +the <code>hello</code> program:</p> + +<pre class="term"> +$ cd /tmp/build-0.1.12/examples/cxx/hello/hello +$ make +</pre> + +<p>Again you will be asked a bunch of questions you have already seen, +except these two:</p> + +<pre class="term"> +Configuring external dependency on 'libhello' for 'hello driver'. + + +Would you like to configure dependency on the installed +version as opposed to the development build? + +[y]: n + +Please enter the out_root for 'libhello'. + +[]: ../libhello + +Please enter the src_root for 'libhello'. + +[]: ../libhello +</pre> + +<p>The <code>hello</code> program depends on <code>libhello</code>. Since +they are distributed as separate projects <code>hello</code> needs to +know where to look for <code>libhello</code>. That's why user intervention +is required. The first question is whether we would like to use an installed +version of <code>libhello</code> as opposed to the not installed build. +Since we haven't installed <code>libhello</code> the answer is +<code>no</code>. The next two questions determine where the +<code>out_root</code> of the build and the <code>src_root</code> of the source +code are. Since we built <code>libhello</code> in its source directory both +become <code>/tmp/build-0.1.12/examples/cxx/hello/libhello</code> or +<code>../libhello</code> if we are in +<code>/tmp/build-0.1.12/examples/cxx/hello/hello</code>. After answering +those questions you will see something like this:</p> + +<pre class="term"> +c++ /tmp/build-0.1.12/examples/cxx/hello/hello/hello.cxx +ld /tmp/build-0.1.12/examples/cxx/hello/hello/hello +</pre> + +<p>And that's it.</p> + +<p>One of the nice features of <em>build</em> is that you can have several +builds in separate directories all from the same source base. Suppose we +would like to build an <code>-O3</code>-optimized statically-linked version +of <code>hello</code> without debug information:</p> + +<pre class="term"> +$ mkdir /tmp/hello-i686-pc-linux-gnu +$ cd /tmp/hello-i686-pc-linux-gnu +$ make -f ../build-0.1.12/examples/cxx/hello/hello/makefile + + +configuring 'hello driver' + + + +Please select the C++ compiler you would like to use: + +(1) GNU C++ (g++) +(2) Intel C++ (icc) + +[1]: 1 + +Would you like the C++ compiler to optimize generated code? + +[y]: y + +Would you like the C++ compiler to generate debug information? + +[y]: n + + +Configuring external dependency on 'libhello' for 'hello driver'. + + + +Would you like to configure dependency on the installed +version as opposed to the development build? + +[y]: n + +Please enter the out_root for 'libhello'. + +[]: /tmp/libhello-i686-pc-linux-gnu + +Please enter the src_root for 'libhello'. + +[]: ../build-0.1.12/examples/cxx/hello/libhello + + +configuring 'hello driver' + + + +Please enter the g++ binary you would like to use, for example 'g++-3.4', +'/usr/local/bin/g++' or 'distcc g++'. You can use path auto-completion. + +[g++]: g++ + +Please select the optimization level you would like to use: + +(1) -O1 [Tries to reduce code size and execution time, without + performing any optimizations that take a great deal of + compilation time.] +(2) -O2 [Performs nearly all supported optimizations that do not + involve a space-speed tradeoff.] +(3) -O3 [Optimize even more.] +(4) -Os [Optimize for size.] + +[2]: 3 + + +configuring 'libhello' + + + +Please select the C++ compiler you would like to use: + +(1) GNU C++ (g++) +(2) Intel C++ (icc) + +[1]: 1 + +Would you like the C++ compiler to optimize generated code? + +[y]: y + +Would you like the C++ compiler to generate debug information? + +[y]: n + + +configuring 'libhello' + + + +Please select the default library type: + +(1) archive +(2) shared object + +[2]: 1 + + +configuring 'libhello' + + + +Please enter the g++ binary you would like to use, for example 'g++-3.4', +'/usr/local/bin/g++' or 'distcc g++'. You can use path auto-completion. + +[g++]: g++ + +Please select the optimization level you would like to use: + +(1) -O1 [Tries to reduce code size and execution time, without + performing any optimizations that take a great deal of + compilation time.] +(2) -O2 [Performs nearly all supported optimizations that do not + involve a space-speed tradeoff.] +(3) -O3 [Optimize even more.] +(4) -Os [Optimize for size.] + +[2]: 3 +c++ /tmp/build-0.1.12/examples/cxx/hello/hello/hello.cxx +c++ /tmp/build-0.1.12/examples/cxx/hello/libhello/libhello/hello.cxx +ar /tmp/libhello-i686-pc-linux-gnu/libhello/hello.l +ld /tmp/hello-i686-pc-linux-gnu/hello +</pre> + +<h2><a name="makefiles">Makefiles</a></h2> + +<p>Now let's take a look at the makefiles. We will start from the +makefile for <code>libhello</code> (<code>hello/libhello/libhello/makefile</code>). +Note, that I removed support for <code>install</code> target for now.</p> + +<pre class="make"> +include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make + +cxx_tun := hello.cxx +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) +cxx_od := $(cxx_obj:.o=.o.d) + +hello.l := $(out_base)/hello.l +hello.l.cpp-options := $(out_base)/hello.l.cpp-options + +clean := $(out_base)/.clean + + +# Build. +# +$(hello.l): $(cxx_obj) + +$(cxx_obj): $(hello.l.cpp-options) + +$(hello.l.cpp-options): value := -I$(src_root) + +$(call -include,$(cxx_od)) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(hello.l).clean \ + $(addsuffix .clean,$(cxx_obj)) \ + $(hello.l.cpp-options).clean + + +# Aliases. +# +ifdef %interactive% + +.PHONY: clean + +clean: $(clean) + +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-l.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +</pre> + +<p>Let's examine this file line-by-line:</p> + +<pre class="make"> +include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make +</pre> + +<p>Every leaf makefile (i.e., one written to build a component) starts from a +line that looks like this. Its sole purpose is to bootstrap the build system. +In our case <code>$(dir $(lastword ...))</code> will expand to something +like</p> + +<pre class="make"> +include .../hello/libhello/libhello/../build/bootstrap.make +</pre> + +<p>Let's take a look at <code>libhello/build/bootstrap.make</code>:</p> + +<pre class="make"> +project_name := libhello +include $(dir $(lastword $(MAKEFILE_LIST))).../build/bootstrap.make +</pre> + +<p>The first line just initializes <code>project_name</code> with the name +of the project. The second line includes the real <code>bootstrap.make</code>. +See <a href="#bootstrap">Bootstrapping</a> section for more information on +various ways of bootstrapping the <em>build</em> runtime.</p> + +<p>What does <code>bootstrap.make</code> do? Besides other things (which are +explained as we encounter them) it sets all those <code>*_root</code> and +<code>*_base</code> variables.</p> + +<p>Let's go back to our <code>libhello/makefile</code>. The first line +should be clear by now so let's move on:</p> + +<pre class="make"> +cxx_tun := hello.cxx +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) +cxx_od := $(cxx_obj:.o=.o.d) +</pre> + +<p>This should be pretty straightforward: <code>cxx_tun</code> contains +a list of translation units, <code>cxx_obj</code> contains a list of +object files that will be produced from those translation units, and +<code>cxx_od</code> contains a list of automatically generated dependency +files for those translation units. After expansion these variables could +contain the following values (note, in this example <code>out_root</code> +is the same as <code>src_root</code>):</p> + +<pre class="make"> +cxx_tun := hello.cxx +cxx_obj := .../hello/libhello/libhello/hello.o +cxx_od := .../hello/libhello/libhello/hello.o.d +</pre> + +<p>Next chunk:</p> + +<pre class="make"> +hello.l := $(out_base)/hello.l +hello.l.cpp-options := $(out_base)/hello.l.cpp-options + +clean := $(out_base)/.clean +</pre> + +<p><code>hello.l</code> and <code>clean</code> are two variables that +store names of targets. You are probably wondering what the heck +is <code>hello.l</code>? This is a library abstraction the build system +provides to deal (besides other things) with archives/shared objects +uniformly. A user who builds your project can specify what type of +library they want without any additional effort from you. I encourage +you to take a look inside <code>hello.l</code>.</p> + +<p><code>hello.l.cpp-options</code> is a bit trickier. +<code>$(out_base)/hello.l.cpp-options</code> keeps C preprocessor options +that are required to compile library files as well as any piece of code +that uses it. Hopefully, it will become clear once you see the rest of +the makefile.</p> + +<p>Let's move on:</p> + +<pre class="make"> +# Build. +# +$(hello.l): $(cxx_obj) + +$(cxx_obj): $(hello.l.cpp-options) + +$(hello.l.cpp-options): value := -I$(src_root) + +$(call -include,$(cxx_od)) +</pre> + +<p>The first line tells us that <code>hello.l</code> is built from object +files listed in <code>cxx_obj</code>. The second line establishes dependency +of object files on C preprocessor options - in order to build an object file +we will need C++ source file and C preprocessor options - quite logical. The +third line sets target-specific variable <code>value</code> for +<code>hello.l.cpp-options</code>: that's how <code>hello.l.cpp-options</code> +gets its content. You may be wondering why do we need to add this +<code>-I$(src_root)</code>. The first line of <code>hello.cxx +</code> should clear things up:</p> + +<pre class="cxx"> +#include "libhello/hello.hxx" +</pre> + +<p>And finally the fourth line includes auto-generated dependency +information for each object file. You can think of +<code>$(call -include )</code> as being equivalent to <code>-include</code> +directive for now.</p> + + +<p>Next chunk:</p> + +<pre class="make"> +.PHONY: $(clean) + +$(clean): $(hello.l).clean \ + $(addsuffix .clean,$(cxx_obj)) \ + $(hello.l.cpp-options).clean +</pre> + +<p>Let's concentrate on the last line. There we are essentially saying that +cleaning <code>libhello</code> consists of cleaning the library, object +files and C preprocessor options. How does this work? It is done using +pattern rules. Part of the build system that defines how to build say +<code>%.l</code> also defines how to clean after it: <code>%.l.clean</code>. +You may want to look into <code>build/cxx/gnu/o-l.make</code> for details.</p> + +<p>Moving on:</p> + +<pre class="make"> +# Aliases. +# +ifdef %interactive% + +.PHONY: clean + +clean: $(clean) + +endif +</pre> + +<p>In this part we are creating a short alias (<code>clean</code>) +for its long equivalent (<code>$(out_base)/.clean</code>). <code> +%interactive%</code> is a <em>system variable</em> defined by +the framework. It is initialized only if current makefile is +used in interactive mode as opposed to being included.</p> + +<p>And finally:</p> + +<pre class="make"> +# How to. +# +$(call include,$(bld_root)/cxx/o-l.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +</pre> + +<p>In this makefile fragment we are including parts of the build +system that actually know <em>how to build</em>. As you might have +noticed, all the code that we have examined up until now was dealing +with <em>what to build</em>. <code>o-l.make</code> defines a pattern +rule to build libraries from object files. <code>cxx-o.make</code> +defines a pattern rule to build object files from C++ translation units.</p> + +<p>And this concludes our examination of the makefile for +<code>libhello</code>. Next is the test driver( +<code>hello/libhello/test/makefile</code>):</p> + +<pre class="make"> +include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make + +cxx_tun := driver.cxx +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) +cxx_od := $(cxx_obj:.o=.o.d) + +hello.l := $(out_root)/libhello/hello.l +hello.l.cpp-options := $(out_root)/libhello/hello.l.cpp-options + +driver := $(out_base)/driver.e +clean := $(out_base)/.clean +test := $(out_base)/.test + + +# Build. +# +$(driver): $(cxx_obj) $(hello.l) + +$(cxx_obj): $(hello.l.cpp-options) + +$(call -include,$(cxx_od)) + + +# Test. +# +.PHONY: $(test) + +$(test): $(driver) + $< + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).clean $(addsuffix .clean,$(cxx_obj)) + + +# Aliases. +# +ifdef %interactive% + +.PHONY: clean test + +test: $(test) +clean: $(clean) + +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) + + +# Load build information. +# +$(call load,$(src_root)/libhello/makefile) +</pre> + +<p>Do you see anything unknown or strange in this makefile? I hope you don't. +Just to re-iterate, I will remove everything we definitely saw and leave +only what's new:</p> + +<pre class="make"> +hello.l := $(out_root)/libhello/hello.l +hello.l.cpp-options := $(out_root)/libhello/hello.l.cpp-options + + +# Build. +# +$(driver): $(cxx_obj) $(hello.l) + +$(cxx_obj): $(hello.l.cpp-options) + + +# Load build information. +# +$(call load,$(src_root)/libhello/makefile) +</pre> + +<p>All of what's left deals in one way or the other with linking +to <code>libhello</code>. The first two lines define variables that +hold paths to the library and C preprocessor options (since we are in +the same project we know what those paths are relative to +<code>out_root</code>/<code>src_root</code>). The third line declares that +driver consists of object files and should be linked with +<code>libhello</code>. The next line says that we need C preprocessor options +to build object files, just like we did for <code>libhello</code>. And finally +the last line: what does the <code>load</code> function do? The +<code>load</code> function loads rules and dependency information from the +makefile specified. Note that it doesn't make variable definitions from that +makefile available (or, even worse, override ones we set) - only dependencies +and rules. The major benefit of doing this is in having complete dependency +information along with the rules in case something gets out of date. If, for +example, we change something in <code>libhello</code> and then execute +<code>make</code> in <code>test</code>, <code>make</code> will be able to +detect that <code>libhello</code> is out of date and will re-build it before +building the test driver.</p> + +<p>Now let's take a look at the makefile from the <code>hello</code> program +(<code>hello/hello/makefile</code>). Remember that it is a separate project +(I removed support for <code>install</code> target again):</p> + + +<pre class="make"> +include $(dir $(lastword $(MAKEFILE_LIST)))build/bootstrap.make + +cxx_tun := hello.cxx +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) +cxx_od := $(cxx_obj:.o=.o.d) + +hello.e := $(out_base)/hello.e +clean := $(out_base)/.clean + +# Secure default target. +# +$(hello.e): + + +# Import information about libhello. +# +$(call import,libhello,l: hello.l,cpp-options: hello.l.cpp-options) + + +# Build. +# +$(hello.e): $(cxx_obj) $(hello.l) + +$(cxx_obj): $(hello.l.cpp-options) + +$(call -include,$(cxx_od)) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(hello.e).clean $(addsuffix .clean,$(cxx_obj)) + + +# Aliases. +# +ifdef %interactive% + +.PHONY: clean + +clean: $(clean) + +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +</pre> + +<p>Again I will remove all the parts that we are familiar with leaving +only what's new:</p> + +<pre class="make"> +# Secure default target. +# +$(hello.e): + + +# Import information about libhello. +# +$(call import,libhello,l: hello.l,cpp-options: hello.l.cpp-options) +</pre> + +<p>Let's see what's going on here. I will start from the call to +the <code>import</code> function. It is similar to the <code>load</code> +function with a few exceptions. First of all, since we are importing +build information from a separate project we don't know where to look +for its parts; this will require dynamic configuration. Secondly, we +have no way to figure out where <code>hello.l</code> and +<code>hello.l.cpp-options</code> are. Thus we have +<code>`l: hello.l'</code> and <code>`cpp-options: hello.l.cpp-options'</code> +which essentially means "initialize variable <code>hello.l</code> with +the library path and variable <code>hello.l.cpp-options</code> with +the C preprocessor options file path".</p> + +<p>One side effect of the call to <code>import</code> function is the +potential loss of the default target. Thus, the first line.</p> + +<p>The inter-project dependency importing architecture is probably +the most complicated part of the build system. It will be described +in a separate section.</p> + +<p>This concludes our step-by-step examination. It was not trivial +but neither is building real software.</p> + +<h1><a name="inter_project_dependencies">Inter-Project Dependencies</a></h1> + +<p>To be completed.</p> + + +<h1><a name="administrivia">Administrivia</a></h1> + + +<h2><a name="license">License</a></h2> + +<p>The <em>build</em> runtime (makefiles, scripts, etc.) is distributed under +the terms of the <a href="http://www.codesynthesis.com/licenses/gpl-2.txt">GNU General +Public License, version 2</a>. <em>Build</em> documentation is distributed +under the terms of the <a href="http://www.codesynthesis.com/licenses/fdl-1.2.txt">GNU +Free Documentation License, version 1.2</a>.</p> + +<p>In particular, this means that any makefile, script, etc., that +includes, calls, or otherwise links to the <em>build</em> runtime must +be covered by a GPL-compatible license, should you decide to distribute +them.</p> + + +<h2><a name="bootstrapping">Bootstrapping</a></h2> + +<p>There are two ways to use the build system: your project can embed +all necessary files or you can require the <em>build</em> runtime to be +installed. The first approach allows you to make your project self-content, +modulo other external dependencies it might have. The disadvantage of this +approach manifests itself when your project participates in a build with +inter-project dependencies established: your project and the rest of the +build could use different (and potentially incompatible) versions of the +runtime. There is no such problem with the second approach.</p> + +<p>My advice is to go with the installed <em>build</em> unless you have +a compelling reason to do otherwise.</p> + +<p>When you go with the embedded runtime you can copy all necessary files +to your project's <code>build/</code> directory. When you use external +<em>build</em> your <code>build/bootstrap.make</code> might look something +like this:</p> + +<pre class="make"> +project_name := libhello +include build-0.1/bootstrap.make +</pre> + +<p>How will <code>make</code> find <code>build-0.1/bootstrap.make</code>? +There are two ways this can happen: you have the runtime installed (e.g., +into <code>/usr/local/include</code>) where <code>make</code> will look +for it by default or you can tell <code>make</code> where to look using +<code>-I</code> option in the command line or by setting +<code>MAKEFLAGS</code> environment variable.</p> + +<h2><a name="versioning">Versioning</a></h2> + +<p><em>Build</em> uses a three-digit versioning scheme: <code>X.Y.Z</code>. +<code>X</code> is a generation number; it is incremented when a completely +new design is implemented. <code>Y</code> is an interface version; two +<em>build</em> runtimes with different <code>Y</code> have incompatible +interfaces even though the ideology is the same (if ideology changes +<code>X</code> will most likely be incremented). Additionally, odd +<code>Y</code> indicates that it's a development release (similar to +the linux kernel). Finally, <code>Z</code> signifies a release number. +Releases with the same <code>X.Y</code> have the same interface.</p> + +<p>To allow co-existence of several versions of <em>build</em> on the +same system, the <code>X.Y</code> pair is made part of the path (e.g., +<code>/usr/include/build-0.1</code>) thus when you bootstrap the runtime +(in a project-specific <code>bootstrap.make</code>) you specify interface +version:</p> + +<pre class="make"> +include build-0.1/bootstrap.make +</pre> +</div> + + +<div id="docinfo"> +<p>Copyright © 2004-2010 <a href="http://www.codesynthesis.com">Code Synthesis Tools CC</a>.</p> + +<div class="terms"> +Permission is granted to copy, distribute and/or modify this document under +the terms of the <a href="http://www.codesynthesis.com/licenses/fdl-1.2.txt">GNU Free +Documentation License, version 1.2</a>; with no Invariant Sections, no +Front-Cover Texts and no Back-Cover Texts. +</div> +</div> + +</body> +</html> |