WARNING: GufBuild is very new, and is still changing. This information may change without warning. Worse, this document could easily be out-of-date. Watch out.
GufBuild is a tool for building software written in C++. It is similar to Make, but with certain advantages and disadvantages. The main disadvantage is flexibility -- GufBuild is only designed to build C++ programs which are organized in a certain way. However, while GufBuild can do far less than Make can, what it can do it does much better than Make ever could.
Packages and Modules
GufBuild requires programs to be organized into packages and modules. A module includes a C++ source file and a header file which define a single class. The class may have helper classes embedded within it, but only one class should exist at the global scope. Both the source file and the header for a module must be named exactly the same as the class, including case. (Note to Windows users: Most OS's have case-sensitive filesystems. If you want your stuff to be portable, make sure to use the correct cases in your filenames.)
Packages contain modules and other packages. Physically, all of the contents of a package must be inside one directory. That directory must be named exactly the same as the package. Again, this is case-sensitive. Logically, all of the contents of a package must be within the same C++ namespace. This namespace must have the exact same name as the package.
The "executable" Property
GUF programs have no main() function. Instead, you declare a class derived from guf::GProcess. Then, you declare that module as "executable" in your build file. GufBuild will then add some information to the module when you compile it which will allow external programs to find and execute the module like a program. Additionally, if the module is compiled directly into an executable program, GufBuild will add to your program a main() function which will initialize GUF, allocate an instance of your class, and run it.
Of course, in order for GufBuild to generate such functions, it needs to
know how to allocate an instance of your class. It assumes that the class has
a static function New() which returns a smart pointer to a new instance of it.
(This is the standard way to allocate objects in GUF.)
Packages can also be declared "executable". In this case, it must declare one of its modules as the "main" module. Then, that module will represent the package if the package is executed as a program.
Executables and Libraries
Any module or package can be compiled into either an executable or a libary. Of course, the module or package must be declared "executable" in order to be compiled into an executable, but no special properties are required to compile a library. Executables are regular programs -- you can run them directly. Libraries are mainly for use by other programs. GufBuild only supports building dynamic libraries. Static libraries, while useful, have too many little quirks and problems to use effectively in a cross-platform way.
public and private
Packages and modules can be declared "public" or "private" within their parent package. If a package is declared "private", then all of its contents are made private, no matter how they are declared, but if a package is "public", it can define whether its contents are public or private. After all properties are assigned, any module which ends up being "public" will have its header file placed in the "include" directory for the software. This is mainly useful for libraries, allowing external programs to include those headers and link against the library.
GufBuild parses package definition files to determine what to build. These files are written using a syntax very similar to C++. Packages and modules are declared like classes, with the keyword "package" or "module" in the place of the "class" keyword. For example:
Note that no semicolon is required after the closing brace.
Everything which is declared between the open and close braces of a package is contained within the package. You can declare both packages and modules there. The above example declares the package "hello", containing the module "HelloWorld". This could be the beginnings of a "Hello World" program, but a couple more things are necessary.
To declare a module as executable, place the keyword "executable" between the braces, followed by a semicolon.
To declare a package as executable, you must also specify the module to use as the main module. You do this by placing the "main" keyword infront of that module's definition.
The module given as the main module must be within the package, and cannot be nested within a sub-package.
Our Hello World example still won't compile, however, until we tell it to output an executable. We do this by declaring an executable, which is similar to declaring a package.
This is placed after the package declaration. The "main" statement within the executable declaration indicates which package (or module) to compile into this executable. In this case, we specified the "hello" package.
Now our example will compile the Hello World program into an executable called "hello_world".
You can also specify packages (or modules) that are nested within other packages. In order to do this, you must specify the complete path using "::" as a separater. This is just like C++.
Libraries can be specified the same way as executables. Just use "library" in the place of the "executable" keyword.
Everything in the main package (or module) will be compiled into the
library. Of course, the main package does not have to have the "executable"
flag in this case.
Often, one wishes to specify special flags to the compiler or linker when compiling a program. GufBuild allows you to do this on a per-executable and per-library basis. Simply use the "cflags" or "ldflags" keyword in your executable or library definition. Either keyword should be followed by a string which can contain any number of parameters, separated by spaces. The parameters specified with "cflags" will go to the compiler, and those specified with "ldflags" to the linker. You can use these keywords multiple times in the same executable or library. If you do, all the parameters from all of the declarations will be used. (Usually, that fact isn't very useful.)
GufBuild also lets you specify what files you want deleted when one of the clean commands is run. There are three clean commands: "clean", "distclean", and "cvsclean". "distclean" will delete everything "clean" deletes (along with its own stuff), and "cvsclean" will delete everything "distclean" deletes (along with even more stuff). All three commands will delete the "bin", "lib", "build", and "include" directories, but you must specify any additional files you want deleted. This is done by using the "clean" declaration.
level must be one of: "normal", "dist", or "cvs", which indicates which clean command you are specifying files for. files is a list of files which should be deleted at that level. Each filename should be enclosed in quotes, and names should be separated by semicolons. Here is an example:
This says that when either "distclean" or "cvsclean" is run, the files "config" and "gufbuild.log" are to be deleted.
Package definition files parsed by GufBuild are run through a preprocessor before they are parsed. This means that you can use preprocessor directives to perform conditional compilation or to include files in other files. It also means that you can use C- and C++-style comments in your package files.
The recommended way to organize your package definition files is as follows: Place the definition for each package in a file in that package's directory. Then, include that file into the parent package using a #include directive. See the source code for GUF for a good example of this.
Intermediate and Output files
GufBuild keeps files as organized as possible. All source code must be placed in the directory "src" within the build directory. All intermediate files generated during a build are placed in the directory "build". Output executable files are placed in "bin" and libraries are placed in "lib". Public headers are placed in "include".
On Windows, libraries are exported in two parts. There is the .dll file which contains the executable code, and a .a file which programs may link with in order to use the library. The .dll is placed in the "bin" directory, as Windows requires that .dll's be either in your PATH or in the same directory as the executables that use them. The .a file is placed in "lib" as one would expect.
To run GufBuild from the command line, use the following syntax:
If you do not specify one of the possible parameters, "build" will be assumed. The commands work as follows:
I don't have any imminent changes planned at this time.
These are ideas I have for future features of GufBuild: