# Example cbuild script file, which can be used to build itself with GCC. # Note: This is a comparitively simple example, and in no way showcases # CBuild's extensive capabilities. For more in-depth information, please see # the AWiki entry at # Everything past the first '#' character in a line is ignored. To put a '#' # character in a line, escape it like '\#', or put it in quotes. # Use ${var} to dereference the environment variable 'var', and $(cmd) to # replace text using sub-command 'cmd'. # &#xxxx; will give you the character the given number value represents, in # UTF-8 (ie. © or �xA9; will give you the copyright symbol on a UTF-8 # compatible console). In addition, the standard HTML entity names are also # valid (ie. © will also give you the copyright symbol). # All whitespace between a command and its option(s) are eaten by the parser. # You can use 'echo' to print a line to the console. Use 'put' to print a # line without a trailing newline echo "CBuild © 2006" echo "" # 'ifopt' checks the command line for the specified option. The rest of the # line will only be processed if it was passed. Whitespace between the option # name and next command is ignored. If the command line opt has a =, it will # be treated as an opt=val pair and only the portion before the = needs to # match. # 'verbose' causes cbuild to display the commands being run for a number of # commands, in place of the cleaner, more readable output. ifopt verbose verbose 1 # To keep the main directory clean, it's usually best to put the temporary # object and dependancy files into subdirectories. Changing the variables # OBJ_DIR and DEP_DIR will do just this. OBJ_DIR = obj DEP_DIR = dep # The 'do' command allows cbuild to execute a block if the following if-type # check passes. End the block with 'done' or use 'else' (which can also be # followed by an if-type command) to make another block to run if the initial # check failed. Indentation is unimportant. do ifopt help echo " CBuild - a platform-independant build system using (mostly) ANSI C. Available options: verbose - Enable more verbose command printing clean - Clean a previously compiled build --install path - Installs the optimized executable to the specified path --disable-gui - Disables using the GUI for installation on some platforms help - Display this help message For advanced scripting information, please see CBuild's AWiki entry at To report bugs, please email me at or . " # 'exit' returns from the script, and cbuild will return with the specified # number as the exit code exit 0 done # 'goto' jumps to the specified label (prepended with ':') which can be ahead # of or behind the current line. ifopt clean goto clean # Here we set some standard optimizing C flags. This only persists until # another line is encountered that sets them differently. You can use ?= # instead of = to set a variable only if its not already set. If you wish # to start with spaces, encapsulate the value in ''s or ""s, or escape # the first whitespace character with \ CFLAGS ?= "-O2 -W -Wall" # Create the object and dependancy file directories. 'ifnexist' will run the # following command if the specified file or directory doesn't exist. Testing # "name/." will make sure "name" is actually a directory. ifnexist "${OBJ_DIR}/." mkdir ${OBJ_DIR} ifnexist "${DEP_DIR}/." mkdir ${DEP_DIR} # There be a lot of funky magic in here. Only advanced users will want to worry # about this. define dialog 'noop' define dcop 'noop' do ifnopt --disable-gui # Locate dcop and make sure it's running. Also, look for kdialog. DCOP = $(*which dcop) do ifnot ${'DCOP'}='' setoutput /dev/null seterror /dev/null @!call ${'DCOP'} do ifret 0 DIALOG = $(*which kdialog) if ${'DIALOG'}='' DCOP = '' else DCOP = '' done setoutput seterror done # If KDE's not available, bail out and go console-only if ${'DCOP'}='' goto build_it # Set up a 4-part progress bar. The dcop reference will be stored in a temp # file seterror /dev/null @!readexec DCOP_REF ${'DIALOG'} --title "Building CBuild" --progressbar "Building CBuild, please wait..." 4 do ifnret 0 seterror goto build_it done seterror define dialog @!readexec '"${1}"' \'${'DIALOG'}\' '${@2}' define dcop @!call \'${'DCOP'}\' '${\'DCOP_REF\'} ${@}' # Setup an exit command, to make sure the progress bar is removed on exit define atexit_dcop dcop close else DCOP = '' done :build_it echo "- Building optimized version -" # This compiles a list of source files, one at a time. Files with the '.c' # extension are compiled using the program specified in 'CC' (default: 'gcc'). # The source files will have their extension changed to 'OBJ_EXT' (default # value: '.o') when compiled, and be placed in 'OBJ_DIR'. 'CFLAGS' and # 'CPPFLAGS' will be applied to the command line for C files. dcop setLabel "Compiling cbuild.c..." compile cbuild.c dcop setProgress 1 # linkexec will link the previously-compiled objects into the named file with # the command named in 'LD' (default: 'gcc'). LDFLAGS will be applied to the # end of the command line. The specified output file will have 'EXE_EXT' # (default: '.exe' in Win32/DOS, nothing elsewhere) appended. dcop setLabel "Linking cbuild"${'EXE_EXT'}"..." linkexec cbuild dcop setProgress 2 echo "" echo "- Building debug version -" # This sets some debug cflags and sets the object extension to '-dbg.o', causing # the source file to compile as 'cbuild-dbg.o' CFLAGS = "-MMD -g3 -W -Wall" OBJ_EXT = "-dbg.o" dcop setLabel "Compiling cbuild.c..." compile cbuild.c dcop setProgress 3 dcop setLabel "Linking cbuild-dbg"${'EXE_EXT'}"..." linkexec cbuild-dbg dcop setProgress 4 echo "" # The getoptval directive gives the value of an option passed to the command # line in the form of 'option=value' or 'option value'. Prefixing the command # name with * causes the returned string to be encapsulated in 'hard quotes' # (important for dealing with user input which may contain $ characters). INSTALL_PATH = $(*getoptval --install) dcop close define atexit_dcop ifnot ${'DCOP'}='' goto kde_install # 'ifnot' will run the following command(s) if the two values (in the form x=y) # are not equal. Putting the variable name in 'hard quotes' causes the expanded # string to be encapsulated similarly (important when dealing with unknown # input which may contain $ characters) do ifnot ${'INSTALL_PATH'}='' INPUT = ${'INSTALL_PATH'} goto check_dir done put "Do you wish to install CBuild? [y/N] " # 'read' will read user keyboard input until enter/return is pressed read INPUT # 'ifnret' will execute the follow command if the previous command's return # value is not the specified value. A return value of 0 typically indicates # success (and non-0 is failure). ifnret 0 exit 1 if ${'INPUT'}='' exit 0 if $(*tolower ${'INPUT'})='n' exit 0 if $(*tolower ${'INPUT'})='no' exit 0 if $(*tolower ${'INPUT'})='y' goto input_ok if $(*tolower ${'INPUT'})='yes' goto input_ok echo "Invalid response '"${'INPUT'}"'" echo "Aborting installation" exit 0 :input_ok do ifplat win32 INSTALL_PATH = ${'WINDIR'} else ifplat dos INSTALL_PATH = C:/DOS else INSTALL_PATH = /usr/local/bin done # 'fixpath' converts \ directory seperators to / in the specified var. This # is required for CBuild to behave properly with directories fixpath INSTALL_PATH echo "" echo "CBuild will install to '"${'INSTALL_PATH'}"'." echo "If you wish to use a different location, please specify it below (press enter" echo "for the default, type 'abort' to abort installation)" put "-> " :get_path read INPUT ifnret 0 exit 1 fixpath INPUT do ifnot ${'INPUT'}='' if $(*tolower ${'INPUT'})='abort' exit 0 :check_dir do ifnexist ${'INPUT'}/. echo "" echo "The directory '"${'INPUT'}"/' doesn't appear to be valid." echo "Please specify a valid path, or 'abort' to abort installation." put "-> " goto get_path done INSTALL_PATH = ${'INPUT'} done :copy_files copy cbuild${EXE_EXT} ${'INSTALL_PATH'}/ echo "" exit 0 :clean # Here's the cleanup area, accessible if you pass "clean" to cbuild. "rmexec" # deletes the specified executables (prepending 'EXE_EXT' to the filenames), # and "rmobj" deletes the object and dependancy files that would be generated # by compiling the specified file. Prepending a command with "-" will cause # cbuild to continue even if the command fails, while prepending with '!' will # cause cbuild to continue without any error messages. -rmexec cbuild cbuild-dbg -rmobj cbuild OBJ_EXT = "-dbg.o" -rmobj cbuild -rm "${OBJ_DIR}" "${DEP_DIR}" exit 0 :kde_install define atexit_stdout seterror seterror /dev/null # This portion is used to install using KDE's kdialog program for user # interaction. Much nicer than needing to use the keyboard. # Ask if the user wants to install, if they didn't previously specify to do if ${'INSTALL_PATH'}='' dialog '' --title "Install CBuild?" --yesno "Do you wish to install CBuild?" ifnret 0 exit 0 INSTALL_PATH = /usr/local/bin :kde_get_path # Get the install path from the user dialog INSTALL_PATH --title "Install CBuild in..." --getexistingdirectory ${'INSTALL_PATH'} do ifnexist ${'INSTALL_PATH'} dialog '' --title "CBuild install error" --error "Could not read install directory from kdialog! Install aborted!" exit 1 done done # If we don't have write permissions, we'll need to use kdesu to try and get # them. For larger projects, where you need to do much more than a simple copy, # you can put the commands you need potential root access for into a seperate # script, then call cbuild (with ${0}) using that script. do ifwrite ${'INSTALL_PATH'}/. @!call cp cbuild${'EXE_EXT'} ${'INSTALL_PATH'}/ else @!call kdesu -t -c "cp cbuild"${'EXE_EXT'}" "${'INSTALL_PATH'}"/" done # Make sure the copy succeeded do ifnret 0 dialog '' --title "Error installing CBuild" --warningyesno "Could not copy cbuild to "${'INSTALL_PATH'}"! This may be due to invalid permissions. Please check with your system administrator. Select a different location?" ifret 0 goto kde_get_path exit 1 done dialog '' --title "Install succeeded" --msgbox "Installation was successful! CBuild has been installed in "${'INSTALL_PATH'} exit 0