#!/bin/bash -e # # A script to produce the Qt declaration files # # This script utilizes the extraction framework from mkqtdecl_common. The extraction # framework is based on a C++ parser and a configuration file that specifies details # about the translation. # # By default, the script will take the Qt headers from /opt/qt/4.6.3, /opt/qt/5.5.1 # and /opt/qt/6.2.1 for Qt4, Qt5 and Qt6 respectively. # # Call it from project level as # # ./scripts/mkqtdecl.sh -update # Qt4 # ./scripts/mkqtdecl.sh -update -qt5 # Qt5 # ./scripts/mkqtdecl.sh -update -qt6 # Qt6 # # For more options see # # ./scripts/mkqtdecl.sh -h # # # Copyright (C) 2006-2025 Matthias Koefferlein # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA dry=0 sync=0 update=0 diff=0 reuse=0 qt="/opt/qt/4.6.3/include" qt5="/opt/qt/5.12.12/include" qt6="/opt/qt/6.2.1/include" inst_dir_common=`pwd`/scripts/mkqtdecl_common inst_dir4=`pwd`/scripts/mkqtdecl4 inst_dir5=`pwd`/scripts/mkqtdecl5 inst_dir6=`pwd`/scripts/mkqtdecl6 src_dir=`pwd`/src src_name4=gsiqt/qt4 src_name5=gsiqt/qt5 src_name6=gsiqt/qt6 qt_mods4="QtCore QtGui QtDesigner QtNetwork QtSql QtXml QtUiTools" qt_mods5="QtCore QtGui QtWidgets QtDesigner QtNetwork QtPrintSupport QtSql QtSvg QtXml QtXmlPatterns QtMultimedia QtUiTools" qt_mods6="QtCore QtGui QtWidgets QtNetwork QtPrintSupport QtSql QtSvg QtXml QtMultimedia QtUiTools QtCore5Compat" src_name=$src_name4 inst_dir=$inst_dir4 qt_mods=$qt_mods4 work_dir="mkqtdecl.tmp" while [ "$1" != "" ]; do a="$1" shift case "$a" in -h) echo "Produce Qt declaration" echo "Usage:" echo " mkqtdecl.sh -update Produce and synchronize" echo " mkqtdecl.sh -dry Dry run - produce, but don't synchronize" echo " mkqtdecl.sh -sync Sync only - don't produce, but synchronize" echo " mkqtdecl.sh -diff Show differences - don't produce and don't synchronize" echo " mkqtdecl.sh -qt path_to_include Use the specified include path" echo " mkqtdecl.sh -qt5 Use setup for Qt 5.x (use before -qt)" echo " mkqtdecl.sh -qt6 Use setup for Qt 6.x (use before -qt)" echo " mkqtdecl.sh -reuse Don't parse C++ container again" exit 0 ;; -dry) dry=1 ;; -sync) sync=1 ;; -update) update=1 ;; -diff) diff=1 ;; -reuse) reuse=1 ;; -qt) qt="$1" shift ;; -qt5) qt="$qt5" work_dir="mkqtdecl5.tmp" inst_dir="$inst_dir5" qt_mods="$qt_mods5" src_name="$src_name5" ;; -qt6) qt="$qt6" work_dir="mkqtdecl6.tmp" inst_dir="$inst_dir6" qt_mods="$qt_mods6" src_name="$src_name6" ;; *) echo "*** ERROR: unknown command option $a" exit 1 ;; esac done if [ `expr $update + $sync + $dry + $diff` != 1 ]; then echo "*** ERROR: either -update, -diff, -dry or -sync must be given" exit 1 fi # Production flags # -diff -> update=0, dry=1 # -dry -> update=1, dry=1 # -sync -> update=0, dry=0 # -update -> update=1, dry=0 if [ $diff != 0 ]; then dry=1 elif [ $dry != 0 ]; then update=1 fi if [ ! -e $src_dir ]; then echo "*** ERROR: Source directory ($src_dir) not found - run script in repository root" exit 1 fi if [ ! -e $inst_dir ]; then echo "*** ERROR: Installation path ($inst_dir) not found - run script in repository root" exit 1 fi if [ ! -e $inst_dir_common ]; then echo "*** ERROR: Installation path ($inst_dir_common) not found - run script in repository root" exit 1 fi if ! ruby -v >/dev/null 2>&1; then echo "*** ERROR: ruby not installed" exit 1 fi if ! ruby -e "require 'oj'" 2>&1; then echo "*** ERROR: ruby gem 'oj' not installed" exit 1 fi if ! ruby -e "require 'treetop'" 2>&1; then echo "*** ERROR: ruby gem 'treetop' not installed" exit 1 fi if [ $update != 0 ]; then if [ -e $work_dir ] && [ $reuse == 0 ]; then rm -rf $work_dir fi mkdir -p $work_dir cd $work_dir cp -R $inst_dir/Qt* . for d in Qt*; do cd $d cp $inst_dir/{mkqtdecl.conf,mkqtdecl.properties,mkqtdecl.events} . cp $inst_dir_common/{cpp_parser_classes.rb,cpp_classes.rb,c++.treetop,parse.rb,reader_ext.rb,produce.rb,common.conf} . cd .. done if [ $reuse == 0 ]; then for d in $qt_mods; do echo "--------------------------------------------------------" echo "Parsing $d ..." echo "" cd $d echo "Running gcc preprocessor .." # By using -D_GCC_LIMITS_H_ we make the gcc not include constants such as ULONG_MAX which will # remain as such. This way the generated code is more generic. gcc -std=c++17 -I$qt -fPIC -D_GCC_LIMITS_H_ -E -o allofqt.x allofqt.cpp echo "Stripping hash lines .." egrep -v '^#' allofqt.e rm allofqt.x echo "Parsing and producing db .." ./parse.rb -i allofqt.e -o allofqt.db cd .. done fi rm -f produced.txt touch produced.txt # Note the order of the modules is important: first modules get the # classes first for d in $qt_mods; do echo "--------------------------------------------------------" echo "Production on $d ..." echo "" cd $d mkdir -p generated echo "Producing code .." ./produce.rb -x ../produced.txt -i allofqt.db -m $d # mark classes produced here as done cat class_list.txt >>../produced.txt cd .. done else cd $work_dir fi for d in $qt_mods; do echo "--------------------------------------------------------" echo "Processing $d ..." echo "" cd $d if [ ! -e generated ]; then echo "*** ERROR: production output ("`pwd`"/generated) does not exist - production failed?" exit 1 fi cd generated if [ $dry != 0 ]; then echo "Synchronizing dry run .." else echo "Synchronizing .." fi count=0 for f in {*.cc,*.h} $d.pri; do needs_update=0 if ! [ -e $src_dir/$src_name/$d/$f ]; then echo "# INFO: creating new file $src_dir/$src_name/$f" needs_update=1 elif ! cmp -s $f $src_dir/$src_name/$d/$f; then echo "# INFO: out of date: syncing file $src_dir/$src_name/$f" needs_update=1 fi if [ $needs_update != 0 ]; then count=`expr $count + 1` if [ $dry != 0 ]; then echo cp $f $src_dir/$src_name/$d/$f else echo === cp $f $src_dir/$src_name/$d/$f cp $f $src_dir/$src_name/$d/$f fi fi done if [ $dry != 0 ]; then echo "# INFO: $count files to synchronize" else echo "# INFO: $count files synchronized" fi cd .. cd .. done