Skip to content

Bash sample code: Check the basic rules of a makefile

Jean-Michel Gigault edited this page Aug 11, 2015 · 1 revision

42FileChecker features a test that checks the rules of a Makefile (Which rule is missing and which rule is failing), here are a sample code and its tips.


Sample code

# Declare a function that takes 2 arguments
function makefile_checker
{
	local MK_PATH=$1      # 1st argument: Working directory
	local MK_BINARY=$2    # 2nd argument: Name of the binary to be compiled

	# Does a file named 'Makefile' exist in the working directory?
	if [ ! -f "$MK_PATH/Makefile" ]
	then
		echo "Makefile not found"
		return
	fi

	# Read the 'Makefile' and save it into a temporary variable $MK_CAT
 	local MK_CAT=`cat "$MK_PATH/Makefile"`
	local TEST

	# Check if a rule named 'all:' does exist
	TEST=$(echo "$MK_CAT" | awk '$0 ~ /^all[\t ]*:/ {print}')
	if [ "$TEST" == "" ]
	then
		echo "Missing rule: 'all'"
		return
	fi

	# Check if a rule named 'clean:' does exist
	TEST=$(echo "$MK_CAT" | awk '$0 ~ /^clean[\t ]*:/ {print}')
	if [ "$TEST" == "" ]
        then
		echo "Missing rule: 'clean'"
		return
	fi

	# Check if a rule named 'fclean:' does exist
	TEST=$(echo "$MK_CAT" | awk '$0 ~ /^fclean[\t ]*:/ {print}')
	if [ "$TEST" == "" ]
	then
		echo "Missing rule: 'fclean'"
		return
	fi

	# Check if a rule named 're:' does exist	
	TEST=$(echo "$MK_CAT" | awk '$0 ~ /^re[\t ]*:/ {print}')
	if [ "$TEST" == "" ]
	then
		echo "Missing rule: 're'"
		return
	fi

	# Check if a rule named '$(NAME):' does exist	
	TEST=$(echo "$MK_CAT" | awk '$0 ~ /^\$\(NAME\)[\t ]*:/ {print}')
	if [ "$TEST" == "" ]
	then
		echo "Missing rule: '\$(NAME)'"
		return
	fi

	# Clean the working directory by running 'make fclean'
	make -C "$MK_PATH" fclean 1>/dev/null 2>&1

	# Check if the rule 'all' is compiling the proper binary
	make -C "$MK_PATH" all 1>/dev/null 2>&1
	if [ ! -f "$MK_PATH/$MK_BINARY" ]
	then
		echo "Failing rule: 'all' does not compile the binary"
		return
	fi

	# Check if the rule 'clean' is removing the objects
	make -C "$MK_PATH" clean 1>/dev/null 2>&1
	if [ ! -z "$(ls -1 "$MK_PATH" | awk '$0 ~ /\.o$/ {print}')" ]
	then
		echo "Failing rule: 'clean' does not remove the objects"
		return
	fi

	# Check if the rule 'fclean' is removing the binary
	make -C "$MK_PATH" fclean 1>/dev/null 2>&1
	if [ -f "$MK_PATH/$MK_BINARY" ]
	then
		echo "Failing rule: 'fclean' does not remove the binary"
		return
	fi

	# Check if the rule 're' is re-compiling the binary
	# 1. Get inode value of the binary after running 'make all'
	make -C "$MK_PATH" all 1>/dev/null 2>&1
	local TEST1=$(ls -i "$MK_PATH/$MK_BINARY")
	# 2. Get inode value of the binary after running 'make re'
	make -C "$MK_PATH" re 1>/dev/null 2>&1
	local TEST2=$(ls -i "$MK_PATH/$MK_BINARY" 2>/dev/null)
	# 3. When the two inode values are identical, the rule 're' has failed
	if [ "$TEST1" == "$TEST2" -o "$TEST2" == "" ]
	then
		echo "Failing rule: 're' is not re-compiling the binary"
		return
	fi

	# The test did not failed, everything is OK
	echo "Makefile seems to work perfectly"
}

# Call the function with two arguments:
# 1st: The path where the Makefile is working
# 2nd: The name of the binary to be compiled
makefile_checker "." "test.a"

Tips


Check if a file or a directory exists
declare FILENAME=./Makefile    # Declare a variable containing the filename
if [ -f "$FILENAME" ]          # Use the file test '-f'
then
    echo "$FILENAME exists"    # On succes, the file exists
fi

declare DIRECTORY=./includes   # Declare a variable containing the dirname
if [ -d "$DIRECTORY" ]         # Use the directory test '-d'
then
    echo "$DIRECTORY exists"   # On succes, the directory exists
fi

More primaries test here: Bash Beginners Guide


Read a whole file into a variable
declare MY_VAR=`cat "./path/to/the/file"`   # Using `...`
declare MY_VAR=$(cat "./path/to/the/file")  # Using $(...)

Find a string in a file using awk

Read Bash tools: Awk to learn more about Awk.

declare TEXT=$(cat "./path/to/the/file")

echo "$TEXT" | awk '$0 ~ /word/ {print "true"; exit} END {print "false"}'
# Find a line that contains the term 'word', 
# -> print "true" and stop searching (exit) if a line is found
# If any line is found after reading the whole file: 
# -> do the END block and print "false"

Get inode of a file
declare MY_FILE="./path/to/the/file"

ls -i "$MY_FILE"                     # Use 'ls' to get inode
ls -i "$MY_FILE" | awk '{print $1}'  # Use awk to keep the 1st column only

# Save the result in a variable
declare MY_VAR=$(ls -i "$MY_FILE" | awk '{print $1}')