#!/bin/bash # Try compiling sources against various C compiler + standard combinations. set -euo pipefail cpu_count=$(cat /proc/cpuinfo | grep "^processor" | wc -l) # Use files listed on command line, if specified. file_pattern=*.c if [[ $#ARGV > 1 ]]; then file_pattern=$@ fi # Get list of files that require sys headers. These won't compile with MingW. declare -A require_sys for f in $(grep -l "#include.*sys/" $file_pattern /dev/null); do require_sys[$f]=1 done # Warning settings. silences="-Wno-implicit-fallthrough" warnings="-Wall -Wextra -Werror -pedantic $silences" # Initialize options for each compiler we want to test. # # Besides flags related to compiler warnings, we need the "-I." to add current # directory to the include path. This is so that "#include __FILE__" would # work even if the input source files are accessed with relative path. declare -A cflags cflags[gcc]="$warnings -I." cflags[clang]="$warnings -I." cflags[x86_64-w64-mingw32-gcc]="$warnings -I." # Need -Wno-deprecated for clang++ because it doesn't want to compile C files # as C++. declare -A cppflags cppflags[g++]="$warnings -I." cppflags[clang++]="$warnings -Wno-deprecated -I." cppflags[x86_64-w64-mingw32-g++]="$warnings -I." # Generate commands for each C compiler+standard combination. commands=$(mktemp) found_compilers=0 for cc in ${!cflags[@]}; do # Only include command of the compiler can report its own version. # # This is so that we skip compilers that are not installed. if ! ( $cc --version > /dev/null 2>&1 ); then continue fi found_compilers=1 for input in $file_pattern; do if [[ ! -s $input ]]; then continue fi # Add commands for each standard plus GNU extensions. for std in {c,gnu}{89,99,11,17}; do # Skip files that includes sys headers for mingw. if [[ "$cc" = *"mingw"* ]]; then if [[ ${require_sys[$input]+_} ]]; then continue fi fi echo "$cc ${cflags[$cc]} --std=$std -c $input -o /dev/null" \ >> $commands done done done # Generate commands for each C++ compiler+standard combination. for cc in ${!cppflags[@]}; do if ! ( $cc --version > /dev/null 2>&1 ); then continue fi found_compilers=1 for input in $file_pattern; do if [[ ! -s $input ]]; then continue fi # Add commands for each standard plus GNU extensions. for std in {c++,gnu++}{98,11,14,17,20}; do # Skip files that includes sys headers for mingw. if [[ "$cc" = *"mingw"* ]]; then if [[ ${require_sys[$input]+_} ]]; then continue fi fi echo "$cc ${cppflags[$cc]} --std=$std -c $input -o /dev/null" \ >> $commands done done done # Run commands. if [[ -s $commands ]]; then xargs -a $commands -d '\n' -P $cpu_count -n 1 bash -c else if [[ $found_compilers -eq 0 ]]; then echo "Did not find any usable compilers" else echo "No files matched" fi rm $commands exit 1 fi # Cleanup. rm $commands exit 0