Skip to content

Instantly share code, notes, and snippets.

@mofosyne
Created April 16, 2024 04:32
Show Gist options
  • Save mofosyne/21fca0eb74fbc788983c1068af92bc83 to your computer and use it in GitHub Desktop.
Save mofosyne/21fca0eb74fbc788983c1068af92bc83 to your computer and use it in GitHub Desktop.
This is a helper script to generate a minimum gnu autotools C based repo
#!/bin/bash
# INITIALIZE MINIMAL AUTOTOOLS BASED C PROGRAM (Brian Khuu 2024)
# https://briankhuu.com/blog/2024/04/11/initialise-minimal-autotools-script/
set -euo pipefail
# Function to display usage
show_usage() {
echo "Usage: $0 [PACKAGE_NAME]"
exit 1
}
# Parse command-line arguments
if [ "$#" -eq 0 ]; then
read -p "Enter project name: " PACKAGE_NAME
elif [ "$#" -eq 1 ]; then
PACKAGE_NAME="$1"
else
show_usage
fi
# Create project directory if it doesn't exist
if [ ! -d "$PACKAGE_NAME" ]; then
mkdir "$PACKAGE_NAME"
fi
cd "$PACKAGE_NAME" || exit 1
echo "== GENERATING FILES =="
# Create README.md
cat <<EOF >README.md
# $PACKAGE_NAME
A minimal Autotools-based C project.
Quickstart Tip: Just run \`./bootstrap.sh && ./build.sh && ./test.sh\` to build and test.
Your executable will be located at \`./$PACKAGE_NAME\`.
Use \`./clean.sh\ && ./bootstrap.sh\` to reset to a clean slate.
EOF
# Create M4 folder
mkdir -p m4
cat <<EOF >m4/readme.md
# Autotools M4 Macro Directory
This directory contains custom or third-party macros used by Autotools.
## Purpose
These macros are included in the Autotools build process via the \`AC_CONFIG_MACRO_DIRS([m4])\` directive in the \`configure.ac\` file.
It is also accessible within \`configure.ac\` as well as m4 does a double pass as well.
## Usage
Ensure to include \`-I m4\` in the \`ACLOCAL_AMFLAGS\` variable within the \`Makefile.am\` file to instruct \`aclocal\` to search for macros in this directory.
EOF
# Create configure.ac
cat <<EOF >configure.ac
m4_define([program_version], [0.1])
AC_INIT([$PACKAGE_NAME], [program_version])
AC_PREREQ([2.65]) # Minimum version number for autoconf build system
AC_CONFIG_SRCDIR([src/main.c]) # Ensure the main source file exists
AC_CONFIG_HEADERS([src/config.h:config_h.in]) # Generate config header
AC_CONFIG_AUX_DIR([build-aux]) # Put autotools auxiliary files into a seperate dir to reduce clutter
AC_CONFIG_MACRO_DIRS([m4]) # Put autotools M4 macros files into a seperate dir to reduce clutter
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) # Initialize Automake with options
AC_CONFIG_FILES([Makefile]) # Specify Makefile generation for main directory and src directory
AC_PROG_CC # Find and set up C compiler
AC_OUTPUT # Generate output files
EOF
# Create Makefile.am
cat <<EOF >Makefile.am
bin_PROGRAMS = $PACKAGE_NAME
${PACKAGE_NAME}_SOURCES = src/main.c src/hello.h
check_PROGRAMS = unit_test
unit_test_SOURCES = tests/unit_test.c src/hello.h
# ACLOCAL_AMFLAGS specifies additional flags for aclocal.
# -I m4: Include the m4 directory for additional macros.
# --install: Automatically install missing macros into the system-wide directory.
ACLOCAL_AMFLAGS = -I m4 --install
EOF
# Create source files
mkdir -p src
cat <<'EOF' >src/main.c
#include <stdio.h>
#include "config.h"
#include "hello.h"
int main() {
printf("%s! (version: %s)\n", HELLO_MESSAGE, PACKAGE_VERSION);
return 0;
}
EOF
# Create header file src/hello.h
cat <<'EOF' >src/hello.h
#ifndef HELLO_H
#define HELLO_H
#define HELLO_MESSAGE "Hello, world"
#endif /* HELLO_H */
EOF
# Create test source files
mkdir -p tests
cat <<'EOF' >tests/unit_test.c
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "hello.h"
int main() {
if(strcmp(HELLO_MESSAGE, "Hello, world") != 0) {
printf("Unit test failed: Message does not match expected output.\n");
return 1;
}
printf("All Unit Test Passed\n");
return 0;
}
EOF
# Create bootstrap.sh
cat <<EOF >bootstrap.sh
#!/bin/bash
# Setup Autotools Enviroment
set -euo pipefail
echo "== BOOTSTRAPPING =="
# Run autoreconf to generate configure script and Makefile.in files
echo "Running autoreconf..."
[ -e configure ] || autoreconf -vim
# Configure and build the project
echo "Configuring and building the project..."
[ -e Makefile ] || ( ./configure && make )
EOF
chmod +x bootstrap.sh
# Create build.sh
cat <<EOF >build.sh
#!/bin/bash
# Run the main program
set -euo pipefail
echo "== BUILD AND RUN $PACKAGE_NAME =="
make
./$PACKAGE_NAME
if [ $? -eq 0 ]; then
echo "build completed."
else
echo "build failed."
exit 1
fi
EOF
chmod +x build.sh
# Create test.sh
cat <<EOF >test.sh
#!/bin/bash
# Run the unit test program
set -euo pipefail
echo "== BUILD AND RUN UNIT TEST =="
make check
./unit_test
if [ $? -eq 0 ]; then
echo "Unit tests passed successfully."
else
echo "Unit tests failed."
exit 1
fi
EOF
chmod +x test.sh
# Create clean.sh
cat <<EOF >clean.sh
#!/bin/bash
# Clean out everything as much as possible
set -euo pipefail
echo "== CLEANING =="
make clean
make maintainer-clean
# Extra cleaning is possible if inside a git repo
if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Using .gitignore in an active git repo to clean out autotool files and directories"
git clean -Xdf
fi
EOF
chmod +x clean.sh
# Create .gitignore
cat <<EOF >.gitignore
# http://www.gnu.org/software/automake
Makefile.in
/ar-lib
/mdate-sh
/py-compile
/test-driver
/ylwrap
.deps/
.dirstamp
# http://www.gnu.org/software/autoconf
autom4te.cache
/autoscan.log
/autoscan-*.log
/aclocal.m4
/compile
/config.cache
/config.guess
/config.h.in
/config.log
/config.status
/config.sub
/configure
/configure.scan
/depcomp
/install-sh
/missing
/stamp-h1
# https://www.gnu.org/software/libtool/
/ltmain.sh
# http://www.gnu.org/software/texinfo
/texinfo.tex
# http://www.gnu.org/software/m4/
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
# Generated Makefile
# (meta build system like autotools,
# can automatically generate from config.status script
# (which is called by configure script))
Makefile
# Generated from configure.ac by autoheader
config_h.in
src/config.h
src/stamp-h1
# Generated by autoreconf -i because of AC_CONFIG_AUX_DIR()
build-aux/
EOF
# Check overall compilation flow
./bootstrap.sh && ./build.sh && ./test.sh && ./clean.sh
echo "== COMPLETE =="
echo "Project '$PACKAGE_NAME' initialized. Run './bootstrap.sh' to set up the Autotools project."
@mofosyne
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment