######################################################################### ######################### LogiLogi.org Make ############################# ######################################################################### ######## Copyright (C) 2004 Wybo Wiersma ######## ######################################################################### # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ######################################################################### ### Why yet again another ake... ### What makes (LogiLogi.org Make, lake for short) special is that it uses the C++ compiler both for the interpretation of the makefile and for the compilation itself. The process could be called a form of bootstrapping. A header and a footer (an extendable one, possibly even an extensive one) are added to the plain C++ sourcefile-like makefile, the merged file is compiled. This compiled makefile is then the program issuing the compile commands to the console. So whereas make requires one to use a clumsy scripting language, LogiLogi.org Make allows one to specify the way things are to be compiled using all the freedom that C++ offers. Moreover Lake offers increased automatisation over Make. So you don't need to create your lake-routines from scratch. Often all that is needed is one function-call (lakeBuild(dirTree,toExename)). Lake was inspired by Icmake, a make replacement written by F. Brokken (my C++ teacher) and Kubat. The strange thing with Icmake however is that, though it's commands looks like C++, it is really implemented as a scripting language. The drawbacks of this are several: it's unneccesary work (because we already have extensive C++ compilers), it doesn't support all C++ functionality so one has to get used to its in and outs, and also it is harder to extend because there's the scripting language in between. So although lake is not yet as mature as Icmake, it is architecture is cleaner. ### Requirements ### Lake requires a proper C++ compiler. Version 3.3.3 of the GNU C++ compiler will do. Lake has been tested on Linux as well as on Windows XP using Cygwin. It has not been tested on other systems (yet). The development effort will focus on Linux + GNU C++ first, however tests on other systems are very welcome. #### HowToUse LogiLogi.org Make ### ## Using an existing lake.make.cc file If you just downloaded lake then the lake.make.cc file builds a "Hello World with LogiLogi.org Make"-program consisting of a plain source file and a static library containing the function issuing the print to stdout. The lake.make.cc file is the file in which the functions to be called for the compile process are specified by the developer (it's what the Makefile is for make). Compile lake itself (lake uses make for part of its own compilation). This step only has to be done once. make Run lake (In this step lake compiles it's own extension lib(s) as well as the source of the program that is to be built) ./lake You're done. Run the hello world test-program to see that everything went well. ./hello Besides calling just ./lake there's also the possibillity of specifying which lake.make.cc file to use. If you call ./lake clean the lake.clean.cc file is executed. In general calling ./lake will execute lake..cc, so adding different make files to a project is easy. ### HowTo Construct a LogiLogi.org Make make file. ### ## Intro on possibilities What can and what can't be done depends largely on the contents of the header and the footer that are added to the lake.makefile. Besides that, libraries can also be used (the lake.make.cc file is going to become part of a normal C++ program after all during the compilation process). The current version of lake uses lake's core functionality and the extension libraries lakeExtend (makes extending lake easy), lakeUsr and it's parts (an extension that automates compile tasks) and lakeAuxFun (extra functions). The functions that are usable in this basic lake setup allow for the compilation of source trees, static libraries, and the installation of libraries and header files. Besides that cleaning (the removal of .o and .a files) and the uninstallation of libraries is also supported. A full list of the included functions (of the type lakeBuild(dirTree,toExename) but offering more options) and a description of the LakeUsr library can be found in README.USR.txt. Below is a step by step example of a simple lake-Makefile using lakeUsr. If you want to do more advanced things than this (for example adding new functions and/or changing what a function does (without having to replace the function or any of the files included in LakeExtend LakeUsr)) see WhereIsWhat and Architecture (below for Lake's basic structure) and have a look at the README.EXTEND.txt (and possibly README.USR.txt) file for more info on where to find and modify/add to which sources. Changing what a function does is quite simple and often just a matter of overloading a function-object (found in lakeUsrRunFun). ## A basic example, using default options Basic source building is done calling lakeBuild("source/dir/from/which/to/build/","executableToBuild"); If you want to use an existing library you can do so by using the following two functions. useLibDir(string libDirToAdd); useLib(string libToAdd); The first one defines the dir in which the lib(s) is/are to be found (call it multiple times to specify multiple lib dirs). The second one specifies the name of the lib to use (call it multiple times to use multiple libs). The order in which the functions are called is only of secondary importance because in the current setup the following happens: the commands are added to a list first (each command-type has its own list). Then, after all commands have been collected, they are executed in the order that is normally correct (this order can be set in the lakefile, in a config-file or be specified as a command- line argument, for how to specify settings see the part on configuration below). So if the add-to-list-functions return, no compilation has yet been done. Compiling libraries and installing libraries and headerfiles can be done using the following functions lakeBuildSLib(string sourceDir); lakeInstallSLib(string sourceDir,string libTargetDir, string libsHdrTargetDir); The first: lakeSLib allows for building a lib with the name of its (sub) dir. While installSLib installs a lib from sourceDir into libTargetDir (the .a lib file) and into libsHdrTargetDir (the header file). Separate commands in which a builddir can be specified (instead of the default .o/), or in which the specification of the lib's names is possible, are available also. See README.USR.txt for all of them. ### Configuration and command-line arguments ### ## Overview In lake pretty much everything can be configured and set in three transparent ways: via config-files, via command-line arguments and using setConf(setting, value) in a lakefile (using the lakeUsr library). They overload eachother in that order. All three of them are described below but. First a general remark. For all settings, wheiter set from the command-line or in a config-file or from a lakefile settings with the same name are the same setting, and all settings can be specified in all three ways. So the midName setting in a configfile is the same as --midName from the command-line. Using the lakeExtend or lakeUsr library it is also possible to specify extra settings not available in the normal ConfigStore. Adding "e_" in front of their names will do the trick. ## Config-files It starts with configfiles (config.txt). These are looked for in three locations: from localmost to globalmost: ./lake/config (directory from which lake is called) ~/lake/config (directory in the users home-dir) /etc/lake (system-wide config) Lake starts looking for the localmost configfile. If one is found that one is loaded, and then it loads from globalmost to localmost all config-files. This construction is used because the location of the config-files is also something that can be set in the config-files themselves. So this allows for flexibillity in specifying wheiter, and which global config-files to load. Not all settings have to be set and they never should be set in all files because the ConfigStore (found in lakelibsrc/lakeConfig) provides sensible defaults (the system-wide configfile should contain stuff like the normal c++ compiler, but never the location of local configfiles). (it is also possible to save and load extra config-files from lakefiles) ## command line arguments Command-line arguments to lake directly set values in the ConfigStore. Three types of arguments can be specified as follows: - (to lake compiling it's own extension libraries) -- (to your compiled lakefile) --- (both to lake itself and to your lakefile) The most used one will be --, for example --cc. Commonly used settings are: cc your c++-compiler, default "g++" ar your library-archiver src extensions of source files, default "cc", resulting in file.cc hdr extensions of headerfiles, default "h", resulting in file.h midName the middlepart of the lakefile you want to run (an alternative to ./lake , should be ran as ./lake -midName ) There are more, they all can be found in: lakelibsrc/lakeConfig/ConfigStore.cc Common extra arguments (not found in the ConfigStore) are: e_extraCompilePreArgs extra arguments to give to your compiler (these are to be specified as --e_extraCompilePreArgs "'\-O2'") e_extraCompilePostArgs extra compiler-arguments that should be specified after the Pre-Arguments, source and targetfile These are also available for linking and package-packing (replace the word Compile by Link or SLibPack) ## changing settings from lakefiles With setConf(setting,value) settings in the ConfigStore can be changed from a lakefile. Also extra settings can be set by prepending "e_" before their name. Using setConf requires the lakeUsr library that comes with lake. A thing to notice is that all Tasks will take their own copy of the config- store at the time they are created. So it is possible to work with different settings for each command. So for example compiling a set of .cpp and .cc source-files from one lakefile is no problem. See README.EXTEND for more info on how this works and what else one can set from a lakefile (like the behavior of some functions) ### WhereIsWhat to be found ### There are four main directories and five root-files in the package. .lake/ - lake libraries, includes, a temp dir and a data dir config/ - the localmost configfile data/ - timestamp data files (for internal use) include/- lib headers that are used by lake lib/ - libraries that are used by lake are installed here libsrc/ - extension libraries are added here (lakeUsr's are here) lakeAuxFun/ - auxiliary functions usable from your lakefile lakeExtend/ - the library making the extension of lake easy lakeUsrFun/ - functions you will use from your lakefile lakeUsrInit/ - base-classes shared by functions and tasks lakeUsrTask/ - functions and classes for tasks (like building) lakeUsrTaskRunFun/ - replacable functions that do the actual jobs partsrc/- the header and footer parts that are added to the makefile temp/ - dir in which the makefile is merged and compiled lakelibsrc/ - the core lake libs (lakeConfig, lakeFileSys, lakeCheck, lakeCore) lakesrc/ - the source of the core lake program is in here test/ - the test "Hello World with LogiLogi.org Make"-demonstration-program lake.clean.cc - the clean file for the test program lake.cleanlake.cc - the clean file for lake and it's extensions lake.make.cc - the lake makefile for the "Hello World..." test program Makefile - the makefile for the core of lake (lakesrc/ and lakelibsrc/) README.txt - what you are reading ### Architecture ### The dir-tree presented above suggest that lake has an elaborated architecture. This is true, but it's not too complicated. I will explain it here for those wanting to make adjustments, or for those interested in knowing how lake does what it does. When building with lake 4 sets of sources come into play. * 1 There's the core of lake, which we call lake core. This part is compiled only once. It's compiled using make. It exists of two main parts. The lake core libraries and the normal source file. The lake core library's sources can be found in lakelibsrc/lake/ and the normal sourcefile lake.cc (and .h) resides in the lakesrc/ directory. This is built into the lake executable that can be found after the initial make making-process has completed. * 2 There's the source of the lake extension librarie(s). At this point lakeExtend and lakeUsr are the main ones as lakeAuxFun is still premature. These extensions are cheked for change and (re-)built if neccesary when ./lake is called. * 3 There's the lake.make.cc sourcefile (to be found in the main directory) and it's header and footer files (to be found in .lake/partsrc/). If any one of these files has changed (or one of the extension library's) then calling ./lake will (also) result in lake.make.cc being merged and compiled (again). This happens in the directory .lake/temp/. Every time ./lake is called the call ends in the execution of the executable inside .lake/temp/. The compilation of the extension libraries and the executable itself happens once, and thereafter it will only happen if they have changed. The executable inside .lake/temp/ is the program that actually issues the commands for the compilation of your own non-lake related source files. * 4 The sourcefiles that are the reason you ran lake. These files are compiled by calling ./lake also because lake (creates and calls the executable that issues the compile-commands inside .lake/temp/). The files inside .lake/partsrc/ are the header/footer files as mentioned already. These files are added to the lake.make.cc file when ./lake is called and something inside lake or these files changed. The files are as follows: lake.head.1.include.cc - C++ includes lake.head.3.declare.cc - Declaration of functions in the merged file lake.head.5.main.cc - Main function; calls init, the lakefile, run and close lake.head.7.init.cc - Initializes some vars (if any) lake.head.9.lakeFileOpen.cc - just before lake.make.cc contents lake.tail.1.lakeFileClose.cc - just after lake.make.cc contents lake.tail.3.run.cc - Calls the function that execute the listed actions lake.tail.5.close.cc - Releases memory for the inited vars (if any) lake.tail.7.wrapper.cc - Allows for userfriendly wraps around added functions lake.tail.9.func.cc - Allows quick and dirty addition of ones own functions The *head* files are added before the lake.make.cc file, the *tail* files are added after the lake.make.cc file. The number right after the head/tail part of the name specifies the order in which the part is added (smaller numbers first). The part of the name before .cc is a name of it's task/contents. The lake library in lakelibsrc contains all the basic lake functionality. This however in a rather non-userfriendly way. The extension lakeUsr library, built upon the lakeExtend library (both in ./lake/libsrc) contain all that makes Lake easy to use. For extension libraries to be added to lake they must be put inside the .lake/libsrc/ dir. They are then automatically built and installed inside .lake/lib/ (.a files) and inside .lake/include/ (.h files). After that an include-directive has to be added to lake.head.1.include.cc in .lake/partsrc/, and that's all it takes to create extensions for LogiLogi.org Make... Building upon the lakeExtend library makes it even easier (just overload a class or two and add a few functions and you're set). Look README.EXTEND.txt and README.USR.txt show the way, and of course you can also always look in the source or copy parts from that if you need easy examples. The code is documented so looking there should be ok. ### ToDo ### - Support for compiling and installing shared- and dynamically loaded libraries - Spreading the word about lake - Further extensions (doc-building, better automated compiling, more user setting features, auto-detection of stuff) - Documentation - If one changes a lib, and runs lake with a midPart (say test) then the lakefile for that midpart is recompiled and re-linked. But other midParts in later runs are not automatically re-linked for the changed libs. - Extra compiler-arguments specified as command-line args are a bit clumsy on the bash-shell with '"\-Option \-Option"' (outer quotation-marks are removed by the shell as you run lake, the inner ones as you run your lakefile, and the slashes at the call of system to run the compile)