Revision 1 (by kittycat, 2006/04/24 09:05:55) initial import
# 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