Generación automática de headers de módulo

English version of this post.
Últimamente he estado trabajando en una librería para simulaciones fdtd. Tenía en mente diseñar la librería de tal forma que el usuario solo incluyera un archivo de header el cual proveería toda la funcionalidad de la librería, pero también se debería de conservar la modularidad y las abstracciones.

En general, me gusta tener el control de la manera en que el código se compila mediante makefiles, por lo que proveer tal header global y tener que hacer mantenimiento manual sobre él simplemente no funciona para mí, por lo que hice algunas búsquedas en google y no encontré información tan relevante sobre el tema por lo que decidí hacer un pequeño script que se encargaría de hacer el mantenimiento del archivo de header para cada módulo.

Pensé que podría ser de ayuda para alguien con el mismo problema por lo que lo incluyo a continuación.

GenerateModuleHeaders.sh

#!/bin/bash
 
moduleName="${1}"
moduleNameUpper=${moduleName^^}  # Module name in uppercase
 
# Run as user, -e allows to interpret new line \n
echo -e "\n \
********************************************************** \n \
** Automatic header generation for module ${moduleName} \n \
**********************************************************"
 
incDir="${2}"
outFile="${3}"
 
# "ls -l $incDir"         = get a directory listing
# --time-style="long-iso" = makes sure that the same format for the date-time string is the same in all environments.
# "| egrep '^d'"          = pipe to egrep and select only the directories
# "awk '{print $8}'"      = pipe the result from egrep to awk and print only the 8th field
incDirs=`ls -l --time-style="long-iso" $incDir | egrep '^d' | awk '{print $8}'`
 
cat <<EOF >"${outFile}"
/*
 * ${moduleName}.hpp
 *
 * Auto-Generated module header file, do not modify directly
 * to prevent changes loss, to modify please change GenHeaders.sh
 * 
 *  Created on: 2014
 *      Author: nano
 */
 
#ifndef ${moduleNameUpper}_HPP_
#define ${moduleNameUpper}_HPP_
 
// Include all headers that are part of the ${moduleName} module
EOF
 
# Loop through the directories
for dir in ${incDirs}; do
    echo -e "\n${dir}";  
    currDir=${incDir}/${dir}
    fileCnt=$( find ${currDir} -name "*.h*" | wc -l )
    if [ ${fileCnt} -gt 0 ]; then  # check  if we have headers in dir
        for file in ${currDir}/*.h*; do # Loop through files and add includes
            echo "#include \"${file}\"" >> ${outFile};
            echo "${file}";
        done       
    fi
done
echo -e "\n";
 
# Add closing ifdef    
echo "" >> ${outFile}
echo "#endif /* ${moduleNameUpper}_HPP_ */" >> ${outFile}

Y aquí está un resultado como ejemplo

Nems_Data.hpp

/*
 * Nems_Data.hpp
 *
 * Auto-Generated module header file, do not modify directly
 * to prevent changes loss, to modify please change GenHeaders.sh
 * 
 *  Created on: 2014
 *      Author: nano
 */
 
#ifndef NEMS_DATA_HPP_
#define NEMS_DATA_HPP_
 
// Include all headers that are part of the Nems_Data module
#include "./include/common/Programs.hpp"
#include "./include/common/Visualizers.hpp"
#include "./include/config/EmConstants.hpp"
#include "./include/config/SimulationConfig.hpp"
#include "./include/gnuplot/GnuplotConfig.hpp"
#include "./include/gnuplot/GnuplotItem1D.hpp"
#include "./include/gnuplot/GnuplotItem2D.hpp"
#include "./include/gnuplot/GnuplotShapes.hpp"
 
#endif /* NEMS_DATA_HPP_ */

Finalmente, puedes agregar un target en el makefile de manera que el header del módulo se genere automáticamente en cada compilación de esta manera

target

# This target generates a global header file for this module, this header
# file includes all the headers of the module and is a convenient way to
# use the API from the client code using only one header file, the shell script
# will be maintaining the list of header files automatically on each build :). 
genheaders:
    @echo Generate headers file for module.
    sh ../GenerateModuleHeaders.sh Nems_Data ./include ./Nems_Data.hpp

¡Y eso es todo!

¡Saludos! 🙂
-Yohan

Leave a Reply

Your email address will not be published. Required fields are marked *