diff --git a/build/monolithify-header.sh b/build/monolithify-header.sh index c6be11c1b..ed88bab56 100755 --- a/build/monolithify-header.sh +++ b/build/monolithify-header.sh @@ -50,7 +50,7 @@ print_usage() echo " " echo " Usage:" echo " " - echo " ${script_name} header header_out root_dir" + echo " ${script_name} header header_out dir_list" echo " " echo " Arguments:" echo " " @@ -61,18 +61,30 @@ print_usage() echo " header_out The filepath of the file into which the script will output" echo " the monolithic header." echo " " - echo " root_dir The path to the root of the directory tree containing the" - echo " headers that will be #included by 'header'. 'root_dir' is" - echo " searched recursively for any directory that contains .h" - echo " files, and the resulting list of directories is then" - echo " searched whenever a #include directive is encountered in" - echo " 'header' (or any file subsequently #included). If a" - echo " referenced header file is not found within 'root_dir'," - echo " the #include directive is left untouched and translated" - echo " directly into 'header_out'." + echo " dir_list The list of directory paths in which to search for the" + echo " headers that are #included by 'header'. By default, these" + echo " directories are scanned for .h files, but sub-directories" + echo " within the various directories are not inspected. If the" + echo " -r option is given, these directories are recursively" + echo " scanned. In either case, the subset of directories scanned" + echo " that actually contains .h files is then searched whenever" + echo " a #include directive is encountered in 'header' (or any" + echo " file subsequently #included). If a referenced header file" + echo " is not found, the #include directive is left untouched and" + echo " translated directly into 'header_out'." echo " " echo " The following options are accepted:" echo " " + echo " -r recursive" + echo " Scan the directories listed in 'dir_list' recursively when" + echo " searching for .h header files. By default, the directories" + echo " are not searched recursively." + echo " " + echo " -c strip C-style comments" + echo " Strip comments enclosed in /* */ delimiters from the" + echo " output, including multi-line comments. By default, these" + echo " comments are not stripped." + echo " " echo " -o SCRIPT output script name" echo " Use SCRIPT as a prefix when outputting messages instead" echo " the script's actual name. Useful when the current script" @@ -80,11 +92,6 @@ print_usage() echo " driver script and seeing the current script's name might" echo " unnecessarily confuse the user." echo " " - echo " -r remove C-style comments" - echo " Strip comments enclosed in /* */ delimiters from the" - echo " output, including multi-line comments. By default, these" - echo " comments are not stripped." - echo " " echo " -q quiet" echo " Suppress informational output. By default, the script is" echo " verbose." @@ -111,6 +118,23 @@ canonicalize_ws() echo "${str}" } +is_word_in_list() +{ + word="$1" + list="$2" + rval="" + + for item in ${list}; do + + if [ "${item}" == "${word}" ]; then + rval="${word}" + break + fi + done + + echo "${rval}" +} + echoinfo() { if [ -z "${quiet_flag}" ]; then @@ -167,6 +191,14 @@ find_header_dirs() # Iterate over the list of directory contents. for item in ${sub_items}; do + # Check whether the current item is in the ignore_list. If so, we + # ignore it. + result=$(is_word_in_list "${item}" "${ignore_list}") + if [ -n "${result}" ]; then + echoinfo "ignoring directory '${item}'." + continue + fi + # If the current item is a directory, recursively accumulate header # directories for that sub-directory. if [ -d "${cur_dirpath}/${item}" ]; then @@ -225,6 +257,7 @@ replace_pass() # thus will be ignored when the monolithic header is eventually read C # preprocessor and/or compiler. skipstr="\/\/skipped" + #skipstr="\/\*skipped\*\/" # The way we (optionally) remove C-style comments results in a single # blank line in its place (regardless of how many lines the comment @@ -237,14 +270,15 @@ replace_pass() while read -r curline do - # Check whether the line begins with a #include directive. - result=$(echo ${curline} | grep '^[[:space:]]*#include ' ) + # Check whether the line begins with a #include directive, but ignore + # the line if it contains the skip string. + result=$(echo ${curline} | grep '^[[:space:]]*#include ' | grep -v "${skipstr}") # If the #include directive was found... if [ -n "${result}" ]; then # Isolate the header filename. - header=$(echo ${curline} | sed -e "s/#include [\"<]\([a-zA-Z0-9.]*\)[\">]/\1/g") + header=$(echo ${curline} | sed -e "s/#include [\"<]\([a-zA-Z0-9\._\-]*\)[\">]/\1/g") # Add the header file to a list. headerlist=$(canonicalize_ws "${headerlist} ${header}") @@ -264,9 +298,9 @@ replace_pass() header_filepath=$(get_header_path ${header} "${dirpaths}") # If the header file was not found, get_header_path() returns an - # empty string. In this case, we assume the file is a system header - # and thus we skip it since we don't want to inline the contents of - # system headers anyway. + # empty string. This probably means that the header file is a + # system header and thus we skip it since we don't want to inline + # the contents of system headers anyway. if [ -z "${header_filepath}" ]; then echoinfo " could not locate file '${header}'; marking to skip." @@ -274,8 +308,12 @@ replace_pass() # Insert a comment after the #include so we know to ignore it # later. Notice that we mimic the quotes or angle brackets # around the header name, whichever pair was used in the input. + # We also reduce pairs of skip strings to singletons, as repeated + # passes can sometimes result in the same #include directive + # being skipped over and over. cat ${filename} \ | sed -e "s/^[[:space:]]*#include \([\"<]\)\(${header}\)\([\">]\)/#include \1\2\3 ${skipstr}/" \ + | sed -e "s/${skipstr} ${skipstr}/${skipstr}/g" \ > "${filename}.tmp" # Overwrite the original file with the updated copy. @@ -355,20 +393,28 @@ main() # The script name to use in informational output. Defaults to ${script_name}. output_name=${script_name} - # Whether or not we should suppress informational output. (Default is to - # output messages.) - quiet_flag="" - # Whether or not we should strip C-style comments from the outout. (Default # is to not strip C-style comments.) strip_comments="" + # Whether or not we search the directories in dir_list recursively. (Default + # is to not search recursively.) + recursive_flag="" + + # Whether or not we should suppress informational output. (Default is to + # output messages.) + quiet_flag="" + + # The list of directories to ignore + ignore_list="old other temp test testsuite windows" + # Process our command line options. - while getopts ":ho:qr" opt; do + while getopts ":o:rcqh" opt; do case $opt in o ) output_name=$OPTARG ;; + r ) recursive_flag="1" ;; + c ) strip_comments="1" ;; q ) quiet_flag="1" ;; - r ) strip_comments="1" ;; h ) print_usage ;; \? ) print_usage esac @@ -384,16 +430,74 @@ main() # Acquire the two required arguments: # - the input header file, # - the output header file, - # - the root directory to search when attempting to locate header files - # referenced in #include directives. + # - the list of directories in which to search for the headers inputfile="$1" outputfile="$2" - rootdir="$3" + dir_list="$3" - # Starting with the root search directory, recursively search for all - # directory paths that contains a header file. - dirpaths=$(find_header_dirs ${rootdir}) - dirpaths=$(canonicalize_ws "${dirpaths}") + # First, confirm that the directories in dir_list are valid. + dir_list2="" + for item in ${dir_list}; do + + echoninfo "checking ${item} " + + if [ -d ${item} ]; then + echon2info " ...directory exists." + dir_list2="${dir_list2} ${item}" + else + echon2info " ...invalid directory; omitting." + fi + done + dir_list2=$(canonicalize_ws "${dir_list2}") + + # Overwrite the original dir_list with the updated copy that omits + # invalid directories. + dir_list="${dir_list2}" + + echoinfo "check summary:" + echoinfo " accessible directories:" + echoinfo " ${dir_list}" + + if [ -n "${recursive_flag}" ]; then + + # If the recursive flag was given, we need to recursively scan each + # directory in dir_list for directories with headers via the + # function find_header_dirs(). + + dirpaths="" + for item in ${dir_list}; do + + item_dirpaths=$(find_header_dirs ${item}) + dirpaths="${dirpaths} ${item_dirpaths}" + done + dirpaths=$(canonicalize_ws "${dirpaths}") + + else + + # If the recursive flag was not given, we can just use dir_list + # as-is, though we opt to filter out the directories that don't + # contain .h files. + + dirpaths="" + for item in ${dir_list}; do + + echoninfo "scanning ${item}" + + # Acquire a list of the directory's contents. + sub_items=$(ls ${item}) + + # If there is at least one header present, add the current directory to + # the list header of directories. + result=$(echo ${sub_items} | grep "\.h") + if [ -n "${result}" ]; then + dirpaths="${dirpaths} ${item}" + echon2info " ...found headers." + else + echon2info " ...no headers found." + fi + done + dirpaths=$(canonicalize_ws "${dirpaths}") + fi echoinfo "scan summary:" echoinfo " headers found in:" @@ -421,7 +525,7 @@ main() else echoinfo "pass finished; result: no further passes needed." fi - +#exit 1 # If the return value was null, then we're done. if [ -z "${result}" ]; then done_flag="1"