#!/bin/bash # -- # Copyright (C) CEA, EDF # Author : Nicolas Crouzet (CEA) # -- # # # salome2 environment file (.bash or .sh) - can also be specified with -e option ENVIRON_FILE= # if present, hxx2salome will try to compile new module, by sourcing ENVIRON_FILE file, and executing # build_configure, configure, make & make install # remark : hxx2salome has to be lanched with clean PATH, LD_LIBRARY_PATH & PYTHONPATH variables! # # options you want to pass to configure CONFIGURE_OPTION= # # usage() { echo -e "\n Usage :\n" echo -e " Set HXX2SALOME_ROOT_DIR variable" echo -e " ${HXX2SALOME_ROOT_DIR}/hxx2salome [options] " echo -e " cppComponent_root_dir cppComponent.hxx" echo -e " libcppComponent.so salomeComponentRoot\n" echo -e " - cppComponent_root_dir : install directory (absolute path)" echo -e " of the c++ component\n" echo -e " - cppComponent.hxx : header of the component" echo -e " - libcppComponent.so : library\n" echo -e " (cppComponent.hxx and libcppComponent.so have to be found" echo -e " in cppComponent_root_dir)\n" echo -e " - salomeComponentRoot : directory of the source/build/install" echo -e " of the Salome component\n" echo -e "\n Options :" echo -e " -h : help" echo -e " -e environment_script : to specify the name of a environment file that will be updated with new necessary commands" echo -e " (this file is also used for sourcing environment before compilation if it has sh or bash syntax," echo -e " if the syntax is csh, it is not sourced and for compiling (-c option) environment must be set up before)" echo -e " -s script_extension : to use if your environment file name doesn't have extension" echo -e " -g : to create a gui part in your component building tree" echo -e " -c : to compile after generation" echo -e " (use this option only if you don't have dependencies in your header or libraries" echo -e " if it is the case, you'll have to adapt your Makefile.am" echo -e " -l : to launch salome " exit } # welcome() { echo -e "\n\n" echo "----------------------------------------------------------------------------" echo echo " hxx2salome" echo echo " Automatic generation of a Salome2 component from a C++ component" echo echo "----------------------------------------------------------------------------" echo echo echo } check_arguments() { # check if $1 is a directory echo -e "-> check arguments\n" if [ ! -d $1 ] then echo -e "Error : directory $1 does not exist!\n" usage fi CPP_ROOT_DIR=${1%%/} # remove trailing slash if present echo " C++ Component directory : ${CPP_ROOT_DIR}" # look for include file $2 - check number of files found and extension nb=`find ${CPP_ROOT_DIR} -name $2 | wc -l` # number of files found, should be equal to 1 extension=${2##*\.} if [ $nb -eq 0 ] then echo -e "\n Error:\n Include file $2 not found in $1 directory!\n" usage elif [ $nb -ge 2 ] then echo -e "\n Error:\n More than one file named $2 was found in $1!\n Include file should be unique!" usage elif [ $extension != "hxx" -a $extension != "hh" -a $extension != "h" ] then echo -e "\n Error:\n Extension=$extension\n Include file $2 should have extension .hxx .hh or .h !\n" usage fi hxx_file=`find ${CPP_ROOT_DIR} -name $2` # name of c++ header we will parse to generate salome module hxx=$2 echo " C++ Component header : ${hxx_file}" hxx_dir=`dirname ${hxx_file}` # look for library $3 nb=`find ${CPP_ROOT_DIR} -name $3 | wc -l` # number of files found, should be equal to 1 if [ $nb -eq 0 ] then echo -e "\n Error:\n Library file $3 not found in $1 directory!\n" usage elif [ $nb -ge 2 ] then echo -e "\n Error:\n More than one file named $3 was found in $1!\n Library file should be unique!" usage fi so_file=`find ${CPP_ROOT_DIR} -name $3` # absolute path of library containing c++ module echo " C++ Component library : ${so_file}" lib_dir=`dirname ${so_file}` lib_file=${3%.so} # name without .so lib_file=${lib_file#lib} # name of library without lib and .so (needed by makefile) # installation directory if [[ ! -d $4 ]] then mkdir -p $4 fi salomeComponentRoot=${4%%/} # remove trailing slash echo " Salome Component directory : ${salomeComponentRoot}" } # retrieve python test file ending up with _test.py get_python_test_file() { cd ${CPP_ROOT_DIR} for file in `find . -name "*_test.py"` do cp $file ${tmp_dir}/${CLASS_NAME}_SRC/src/${CLASS_NAME} python_test_file=${python_test_file}" "`basename $file` done echo -e "\nList of exported python file test : $python_test_file \n" cd - } create_component_tree() { INSTALL_DIR=${salomeComponentRoot}/${CLASS_NAME} export NEW_COMPONENT_SRC_DIR=${INSTALL_DIR}/${CLASS_NAME}_SRC export NEW_COMPONENT_BUILD_DIR=${INSTALL_DIR}/${CLASS_NAME}_BUILD export NEW_COMPONENT_ROOT_DIR=${INSTALL_DIR}/${CLASS_NAME}_INSTALL \rm -rf ${NEW_COMPONENT_SRC_DIR} mkdir -p ${NEW_COMPONENT_SRC_DIR} } get_info_makefile() { makefile_lib="-L\${${CLASS_NAME}CPP_ROOT_DIR}${lib_dir#${CPP_ROOT_DIR}} -l${lib_file}" makefile_include="-I\${${CLASS_NAME}CPP_ROOT_DIR}${hxx_dir#${CPP_ROOT_DIR}}" echo -e "\nlinking option : $makefile_lib" echo -e "include option : $makefile_include" } generate_module_source() { # # go in temporary directory to work on code generation cd ${tmp_dir} # # # ------------------------- parse hxx file and generate code --------------------------------------- # echo -e "\n-> Extract public functions\n" # we get first rid of the c like comments (parse01), then of the excetion specification (sed filter), finnaly we extract public functions (parse1) cat ${hxx_file} | awk -f ${gene_dir}/parse01.awk | sed 's/virtual //g' | sed 's/MEDMEM_EXPORT//g' | sed 's/throw.*;/;/g' | awk -f ${gene_dir}/parse1.awk > ${CLASS_NAME}_public_functions cat ${CLASS_NAME}_public_functions if [ ! -s ${CLASS_NAME}_public_functions ] then echo -e "\nError:\n Sorry - No compatible function was found!\n Please check your header file\n" exit fi # echo -e "\n\n-> Parse public functions and generate Salome2 files\n\n compatibility function\n" cat ${CLASS_NAME}_public_functions | awk -f ${gene_dir}/parse2.awk |\ awk -v class_name=${CLASS_NAME} -f ${gene_dir}/parse3.awk # # outputs echo -e "\n IDL file:" cat parse_result > hxx2salome_journal echo -e "\n----------------- IDL file ------------------\n" >> hxx2salome_journal cat code_idl >> hxx2salome_journal cat code_idl echo -e "\n----------------- hxx file ------------------\n" >> hxx2salome_journal cat code_hxx >> hxx2salome_journal echo -e "\n----------------- cxx file ------------------\n" >> hxx2salome_journal cat code_cxx >> hxx2salome_journal echo # # select archive for MEDMEM or MEDCoupling grep MEDCoupling code_idl >& /dev/null if [ $? -eq 0 ] then template_component_archive=${gene_dir}/template_coupling_src.tgz else template_component_archive=${gene_dir}/template_src.tgz fi # # # ------------------- duplicates template module and insert generated code ------------------------------ # echo -e "\n-> Duplicate template module" | tee hxx2salome_journal tar xvfz ${template_component_archive} >> hxx2salome_journal mv HXX2SALOME_GENERIC_CLASS_NAME_SRC ${CLASS_NAME}_SRC ${gene_dir}/renameSalomeModule -i HXX2SALOME_GENERIC_CLASS_NAME ${CLASS_NAME} ${CLASS_NAME}_SRC ###>> hxx2salome_journal ${gene_dir}/renameSalomeModule -i hxx2salome_generic_class_name ${class_name} ${CLASS_NAME}_SRC ###>> hxx2salome_journal # if [ $make_gui -eq 0 ] then echo -e "\n-> Delete GUI part from the tree" >> hxx2salome_journal 'rm' -rf ${CLASS_NAME}_SRC/src/${CLASS_NAME}GUI sed "s/${CLASS_NAME}GUI//" < ${CLASS_NAME}_SRC/src/Makefile.am > /tmp/h2smkf.$$ mv /tmp/h2smkf.$$ ${CLASS_NAME}_SRC/src/Makefile.am cat ${CLASS_NAME}_SRC/configure.ac | awk ' $0 !~ "^.*GUI/Makefile" { print $0}' > /tmp/h2scac.$$ mv /tmp/h2scac.$$ ${CLASS_NAME}_SRC/configure.ac fi # echo -e "\n-> Substitute generated code in idl file" echo "// this idl file was generated by hxx2salome" > tmpfile cat ${CLASS_NAME}_SRC/idl/${CLASS_NAME}_Gen.idl |awk ' $0 ~ "HXX2SALOME_IDL_CODE" {system("cat code_idl >> tmpfile")} $0 != "HXX2SALOME_IDL_CODE" { print $0 >> "tmpfile" }' mv tmpfile ${CLASS_NAME}_SRC/idl/${CLASS_NAME}_Gen.idl # echo -e "\n-> Substitute generated code in hxx file" echo "// this hxx file was generated by hxx2salome" > tmpfile cat ${CLASS_NAME}_SRC/src/${CLASS_NAME}/${CLASS_NAME}_i.hxx |awk ' $0 ~ "HXX2SALOME_HXX_CODE" {system("cat code_hxx >> tmpfile")} $0 !~ "HXX2SALOME" { print $0 >> "tmpfile" }' mv tmpfile ${CLASS_NAME}_SRC/src/${CLASS_NAME}/${CLASS_NAME}_i.hxx # echo -e "\n-> Substitute generated code in cxx file" echo "// this cxx file was generated by hxx2salome" > tmpfile cat ${CLASS_NAME}_SRC/src/${CLASS_NAME}/${CLASS_NAME}_i.cxx |awk -v cpp_include=$hxx ' $0 ~ "HXX2SALOME_CXX_CODE" {system("cat code_cxx >> tmpfile")} $0 ~ "HXX2SALOME_CPP_INCLUDE" { printf "#include \"%s\"\n",cpp_include >> "tmpfile" } $0 !~ "HXX2SALOME" { print $0 >> "tmpfile" }' mv tmpfile ${CLASS_NAME}_SRC/src/${CLASS_NAME}/${CLASS_NAME}_i.cxx # # add flags in makefile get_python_test_file get_info_makefile echo -e "\n-> Substitute flags in Makefile.am" sed -i "s?HXX2SALOME_INCLUDE?${makefile_include}?g s?HXX2SALOME_PYTHON_FILE?${python_test_file}?g s?HXX2SALOME_LIB?${makefile_lib}?g " ${CLASS_NAME}_SRC/src/${CLASS_NAME}/Makefile.am # # generate component catalog echo -e "\n-> Generate component catalog" | tee hxx2salome_journal if [ -f ${KERNEL_ROOT_DIR}/bin/salome/runIDLparser ] then idlparser=${KERNEL_ROOT_DIR}/bin/salome/runIDLparser else idlparser=${gene_dir}/runIDLparser fi cd ${CLASS_NAME}_SRC/resources VER=`cat ${KERNEL_ROOT_DIR}/bin/salome/VERSION | awk ' { print $NF }'` # extract number of version export PYTHONPATH=${PYTHONPATH}:${KERNEL_ROOT_DIR}/bin/salome # to be sure IDLparser is in PYTHONPATH #${idlparser} -Wbcatalog=${CLASS_NAME}Catalog.xml,icon=${CLASS_NAME}.png,version=${VER} -I${KERNEL_ROOT_DIR}/idl/salome -I${MED_ROOT_DIR}/idl/salome ../idl/${CLASS_NAME}_Gen.idl >& /dev/null | tee hxx2salome_journal ${idlparser} -Wbcatalog=${CLASS_NAME}Catalog.xml,icon=${CLASS_NAME}.png,version=${VER} -I${KERNEL_ROOT_DIR}/idl/salome -I${MED_ROOT_DIR}/idl/salome ../idl/${CLASS_NAME}_Gen.idl if [ -f ${CLASS_NAME}Catalog.xml ] then sed -i "s?_Gen??g s?SALOME/vectorOfDouble?dblevec?g s?SALOME/vectorOfLong?intvec?g s?${CLASS_NAME}_ORB/StrSeq?stringvec?g" ${CLASS_NAME}Catalog.xml else echo Error with runIDLparser - the catalog was not generated exit fi } compile() { echo "----------------- Configure -------------------" echo "----------------- Compile ---------------------" make if [ $? -eq 0 ] then # compilation succeeded : we make install echo echo "----------------- Install ---------------------" make install else exit 1 fi } update_environment() { if [ -z ${ENVIRON_FILE} ] then ENVIRON_FILE="${NEW_COMPONENT_SRC_DIR}/env_${CLASS_NAME}.${SHELL_EXT}" fi echo -e "\nEnvironment file : ", $ENVIRON_FILE if [ -e ${ENVIRON_FILE} ] then cp ${ENVIRON_FILE} ${ENVIRON_FILE}.old fi touch ${ENVIRON_FILE} if [ "${SHELL_EXT}" == "csh" ] then grep -q " ${CLASS_NAME}_SRC_DIR" ${ENVIRON_FILE} res=$? if [ $res == 1 ] then echo -e "###\n#------ ${CLASS_NAME}-Src ------" >> ${ENVIRON_FILE} echo -e "setenv ${CLASS_NAME}_BASE ${INSTALL_DIR}" >> ${ENVIRON_FILE} echo -e "setenv ${CLASS_NAME}_SRC_DIR \${${CLASS_NAME}_BASE}/${CLASS_NAME}_SRC\n" >> ${ENVIRON_FILE} fi grep -q " ${CLASS_NAME}_ROOT_DIR" ${ENVIRON_FILE} res=$? if [ $res == 1 ] then echo -e "###\n#------ ${CLASS_NAME}-Bin ------" >> ${ENVIRON_FILE} echo -e "setenv ${CLASS_NAME}_ROOT_DIR \${${CLASS_NAME}_BASE}/${CLASS_NAME}_INSTALL" >> ${ENVIRON_FILE} echo -e "setenv ${CLASS_NAME}CPP_ROOT_DIR ${CPP_ROOT_DIR}" >> ${ENVIRON_FILE} echo -e "setenv LD_LIBRARY_PATH \${${CLASS_NAME}CPP_ROOT_DIR}${lib_dir#${CPP_ROOT_DIR}}:\${LD_LIBRARY_PATH}" >> ${ENVIRON_FILE} fi fi if [ "${SHELL_EXT}" == "sh" ] then grep -q " ${CLASS_NAME}_SRC_DIR=" ${ENVIRON_FILE} res=$? if [ $res == 1 ] then echo -e "###\n#------ ${CLASS_NAME}-Src ------" >> ${ENVIRON_FILE} echo -e "export ${CLASS_NAME}_BASE=${INSTALL_DIR}" >> ${ENVIRON_FILE} echo -e "export ${CLASS_NAME}_SRC_DIR=\${${CLASS_NAME}_BASE}/${CLASS_NAME}_SRC\n" >> ${ENVIRON_FILE} fi grep -q " ${CLASS_NAME}_ROOT_DIR=" ${ENVIRON_FILE} res=$? if [ $res == 1 ] then echo -e "###\n#------ ${CLASS_NAME}-Bin ------" >> ${ENVIRON_FILE} echo -e "export ${CLASS_NAME}_ROOT_DIR=\${${CLASS_NAME}_BASE}/${CLASS_NAME}_INSTALL" >> ${ENVIRON_FILE} echo -e "export ${CLASS_NAME}CPP_ROOT_DIR=${CPP_ROOT_DIR}" >> ${ENVIRON_FILE} echo -e "export LD_LIBRARY_PATH=\${${CLASS_NAME}CPP_ROOT_DIR}${lib_dir#${CPP_ROOT_DIR}}:\${LD_LIBRARY_PATH}" \ >> ${ENVIRON_FILE} fi fi } copy_component_source() { mv ${tmp_dir}/${CLASS_NAME}_SRC/* ${NEW_COMPONENT_SRC_DIR} mkdir -p ${NEW_COMPONENT_BUILD_DIR} mkdir -p ${NEW_COMPONENT_ROOT_DIR} } good_bye() { echo -e "\n\nModule was created in ${NEW_COMPONENT_SRC_DIR}" echo -e "\nTo compile it, do the following : \n" echo -e "\tsource ${ENVIRON_FILE}" echo -e "\tcd \${${CLASS_NAME}_SRC_DIR}" echo -e "\t./build_configure" echo -e "\tmkdir -p \${${CLASS_NAME}_BUILD_DIR}" echo -e "\tcd \${${CLASS_NAME}_BUILD_DIR}" echo -e "\t\${${CLASS_NAME}_SRC_DIR}/configure ${CONFIGURE_OPTION} --prefix=\${${CLASS_NAME}_ROOT_DIR}" echo -e "\tmake" echo -e "\tmake install" echo -e "\nTo use it :\n" echo -e "\tsource the Salome environment" echo -e "\tsource the component environment file (${ENVIRON_FILE})" echo -e "\trun Salome" echo -e "\tadd ${CLASS_NAME} to the Salome modules list" echo -e "\t\t(with the --modules option of the runSalome command or" echo -e "\t\tby editing your own per-user configuration file ~/.SalomeApprc.3.x.x)" echo -e "\nIf the header of your component includes other headers that are not in the same directories," echo -e "or if your library has dependencies you want to specify," echo -e "you'll have to modify the following files Makefile.am: " echo -e "\t\${${CLASS_NAME}_SRC_DIR}/src/${CLASS_NAME}/Makefile.am" echo -e "\t\${${CLASS_NAME}_SRC_DIR}/src/${CLASS_NAME}GUI/Makefile.am" } launch_salome() { ${KERNEL_ROOT_DIR}/bin/salome/runSalome --gui --modules=GEOM,SMESH,VISU,SUPERV,MED,`echo ${CLASS_NAME}` --containers=cpp,python --killall } compile_module() { if [ ! -d ${NEW_COMPONENT_BUILD_DIR} ] then mkdir -p ${NEW_COMPONENT_BUILD_DIR} fi if [ ! -d ${NEW_COMPONENT_ROOT_DIR} ] then mkdir -p ${NEW_COMPONENT_ROOT_DIR} fi \rm -rf ${NEW_COMPONENT_ROOT_DIR}/* ${NEW_COMPONENT_BUILD_DIR}/* # source ${ENVIRON_FILE} echo echo -e "\n-> Build Configure" cd ${NEW_COMPONENT_SRC_DIR} ./build_configure cd ${NEW_COMPONENT_BUILD_DIR} echo -e "\n-> Configure in ${NEW_COMPONENT_BUILD_DIR}" echo -e "\n-> Install in ${NEW_COMPONENT_ROOT_DIR}" ${NEW_COMPONENT_SRC_DIR}/configure ${CONFIGURE_OPTION} --prefix=${NEW_COMPONENT_ROOT_DIR} echo if [[ $do_compile -eq 1 ]] then compile fi if [[ $do_launch -eq 1 ]] then launch_salome fi } # # # ------------------------------------------------------------------------ # --------------------------- MAIN PROGRAM ------------------------------- # ------------------------------------------------------------------------ # CPP_ROOT_DIR= NEW_COMPONENT_ROOT_DIR= NEW_COMPONENT_SRC_DIR= NEW_COMPONENT_BUILD_DIR= SHELL_EXT=sh do_compile=0 do_launch=0 make_gui=0 # welcome # print some welcome info # gene_dir=`dirname $0` if [ ! -f ${gene_dir}/parse3.awk -o ! -f ${gene_dir}/template_src.tgz ] # final check then echo -e "\nError : scripts parse3.awk or template_src.tgz not present in hxx2salome directory : $gene_dir" usage fi # while getopts "cs:e:h:lg" Option do case $Option in h) usage exit;; e) ENVIRON_FILE=$OPTARG;; s) case $OPTARG in bash) SHELL_EXT=sh;; csh) SHELL_EXT=csh;; *) SHELL_EXT=sh;; esac;; g) make_gui=1;; c) do_compile=1;; l) do_launch=1;; *) echo "Unimplemented option chosen : $Option." usage exit;; # DEFAULT esac done shift $(($OPTIND - 1)) # check number of other arguments # if [ $# -ne 4 ] then echo -e "\nBad number of arguments\n\n" usage exit fi check_arguments $1 $2 $3 $4 # # if there is a sh compatible environment file, source it if [[ -n ${ENVIRON_FILE} && -f ${ENVIRON_FILE} ]] then # analyse extension of environment file case ${ENVIRON_FILE##*\.} in bash) SHELL_EXT=sh;; ksh) SHELL_EXT=sh;; csh) SHELL_EXT=csh;; sh) SHELL_EXT=sh;; esac fi # Environment policy : # - an existing sh file was specified : we source environment file # - else (no file or csh syntax) : we don't source environment file, and do compile # only if KERNEL_ROOT_DIR and MED_ROOT_DIR are defined if [ "${SHELL_EXT}" == "sh" ] && [ ${ENVIRON_FILE} ] && [ -f ${ENVIRON_FILE} ] then pwd echo -e "\n Environment file with sh syntax specified => we source ${ENVIRON_FILE}" cat ${ENVIRON_FILE} | sed "s/ENV_FOR_LAUNCH=1/ENV_FOR_LAUNCH=0/g" > ${ENVIRON_FILE}.tmp source ${ENVIRON_FILE}.tmp #rm ${ENVIRON_FILE}.tmp #source ${ENVIRON_FILE} else if [ ${KERNEL_ROOT_DIR} ] && [ -d ${KERNEL_ROOT_DIR} ] && [ ${MED_ROOT_DIR} ] && [ -d ${MED_ROOT_DIR} ] then # if KERNEL_ROOT_DIR and MED_ROOT_DIR are defined, we consider that environment is set echo -e "\n Environment already set (KERNEL_ROOT_DIR and MED_ROOT_DIR are defined)" else if [ $do_compile -eq 1 ] then echo -e "\n Warning - Cannot compile : Environment shoud be set up before, or specify a environment file with sh syntax!\n" do_compile=0 fi fi fi # # get class name # CLASS_NAME=`awk '$1 == "class" && $0 !~ /;/ {print $2}' ${hxx_file}|awk -F: '{print $1}'` echo " Name of class :" $CLASS_NAME class_name=`echo ${CLASS_NAME} | awk '{print tolower($0)}'` echo class_name = ${class_name} if [ ! $CLASS_NAME ] then echo -e "\nError:\n Sorry - No class definition was found!\n Please check your header file\n" exit fi # # create temporary working directory # tmp_dir="/tmp/${USER}/${CLASS_NAME}" if [ -d ${tmp_dir} ] then rm -rf ${tmp_dir}/* else mkdir -p ${tmp_dir} fi # # --------------------- Generation of module source from template ------------------------------------------ # get_info_makefile generate_module_source # # ---------------------- Installation of new module sources ------------------------------------------------ # create_component_tree # # ---------------------- Modification of Salome environment file ------------------------------------------- # update_environment export `echo ${CLASS_NAME}`_ROOT_DIR=${NEW_COMPONENT_ROOT_DIR} # to avoid resource env for compiling and launching salome export `echo ${CLASS_NAME}`CPP_ROOT_DIR=${CPP_ROOT_DIR} # idem # # ---------------------- Copy the generated source from temp dir ------------------------------------------- # copy_component_source # # ---------------------- If requested, compilation of the Salome component ---------------------------------- if [ ${do_compile} -eq 1 ] then compile_module else good_bye fi echo -e "\nGeneration done\n"