#!/bin/sh -e # Specify the Python interpreter to use. # This is the command executed for the Python interpreter that is going # to be included in KLayout. python="python3" # Specify the Ruby interpreter to use. # This is the command executed for the Ruby interpreter that is going # to be included in KLayout. ruby="ruby" # Specify the path to the NSIS compiler makensis=/c/Program\ Files\ \(x86\)/NSIS/makensis.exe # --------------------------------------------------- # General initialization if ! [ -e ./build.sh ]; then echo "ERROR: build script not found (not in the main directory?)" exit 1 fi pwd=$(pwd) enable32bit=1 enable64bit=1 ucrt=0 args="" suffix="" qt="qt5" while [ "$1" != "" ]; do if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then echo "Runs the Windows build include installer generation." echo "" echo "Run this script from the root directory." echo "" echo "Usage:" echo " scripts/deploy-win-mingw.sh " echo "" echo "Options:" echo " -32 Run 32 bit build only (default: both)" echo " -64 Run 64 bit build only (default: both)" echo " -ucrt Builds with UCRT runtime only (not enabled by default)" echo " -qt5 Builds on qt5 (default)" echo " -qt6 Builds on qt6" echo " -s Binary suffix" echo "" echo "By default, both 32 and 64 bit builds are performed" exit 0 elif [ "$1" = "-ucrt" ]; then enable64bit=0 enable32bit=0 ucrt=1 elif [ "$1" = "-32" ]; then enable64bit=0 enable32bit=1 ucrt=0 elif [ "$1" = "-64" ]; then enable64bit=1 enable32bit=0 ucrt=0 elif [ "$1" = "-qt5" ]; then qt="qt5" elif [ "$1" = "-qt6" ]; then qt="qt6" args="$args -qmake qmake-qt6" elif [ "$1" = "-s" ]; then shift suffix="-$1" else args="$args $1" fi shift done # --------------------------------------------------- # Bootstrap script # This branch will fork to the actual builds for win32 and win64 if [ "$KLAYOUT_BUILD_IN_PROGRESS" == "" ]; then self=$(which $0) export KLAYOUT_BUILD_IN_PROGRESS=1 export KLAYOUT_BUILD_ARGS="$args" export KLAYOUT_BUILD_SUFFIX="$suffix" export KLAYOUT_BUILD_QT="$qt" # Run ourself in MINGW32 system for the win32 build if [ "$enable32bit" != "0" ]; then MSYSTEM=MINGW32 bash --login -c "cd $pwd ; $self" fi # Run ourself in MINGW64 system for the win64 build if [ "$enable64bit" != "0" ]; then MSYSTEM=MINGW64 bash --login -c "cd $pwd ; $self" fi # Run ourself in UCRT64 system for the ucrt build if [ "$ucrt" != "0" ]; then MSYSTEM=UCRT64 bash --login -c "cd $pwd ; $self" fi exit 0 fi # --------------------------------------------------- # Actual build branch if [ "$MSYSTEM" == "UCRT64" ]; then arch=win64-ucrt mingw_inst=/ucrt64 shopt -s nullglob ucrt_vssdk=(/c/Program\ Files\ \(x86\)/Windows\ Kits/10/Redist/10.0.*) shopt -u nullglob ucrt_vssdk=${ucrt_vssdk[0]} if [ "$ucrt_vssdk" = "" ]; then echo "ERROR: ucrt64 DLLs not found" exit 1 fi ucrt_vssdk=$(cygpath -w "$ucrt_vssdk") elif [ "$MSYSTEM" == "MINGW32" ]; then arch=win32 mingw_inst=/mingw32 elif [ "$MSYSTEM" == "MINGW64" ]; then arch=win64 mingw_inst=/mingw64 else echo "ERROR: not in ucrt64, mingw32 or mingw64 system." fi target=$pwd/bin-release-$arch$KLAYOUT_BUILD_SUFFIX build=$pwd/build-release-$arch$KLAYOUT_BUILD_SUFFIX src=$pwd/src scripts=$pwd/scripts # Update in NSIS script too: plugins="audio generic iconengines imageformats multimedia networkinformation platforms printsupport sqldrivers styles tls" # read the current version . ./version.sh echo "------------------------------------------------------------------" echo "Running build for architecture $arch .." echo "" echo " target = $target" echo " build = $build" echo " version = $KLAYOUT_VERSION" echo " build args = $KLAYOUT_BUILD_ARGS" echo " suffix = $KLAYOUT_BUILD_SUFFIX" echo " qt = $KLAYOUT_BUILD_QT" echo "" echo " UCRT libs = $ucrt_vssdk" echo "" rm -rf $target ./build.sh -python $python -ruby $ruby -bin $target -build $build -j2$KLAYOUT_BUILD_ARGS if ! [ -e $target ]; then echo "ERROR: Target directory $target not found" exit 1 fi if ! [ -e $target/klayout.exe ]; then echo "ERROR: Target directory $target does not contain klayout.exe" exit 1 fi # ---------------------------------------------------------- # cert.pem echo "Installing cert.pem .." cp $mingw_inst/etc/ssl/cert.pem $target # ---------------------------------------------------------- # Plugins echo "Installing plugins .." for p in $plugins; do if [ -e $mingw_inst/share/$KLAYOUT_BUILD_QT/plugins/$p ]; then echo " $mingw_inst/share/$KLAYOUT_BUILD_QT/plugins/$p .." cp -R $mingw_inst/share/$KLAYOUT_BUILD_QT/plugins/$p $target # remove the debug versions - otherwise they pull in the debug Qt libs shopt -s nullglob rm -f $target/$p/*d.dll $target/$p/*.dll.debug shopt -u nullglob fi done # ---------------------------------------------------------- # Ruby dependencies rubys=$($ruby -e 'puts $:' | sort | awk '{print $1}') rm -rf $target/.ruby-paths.txt echo '# Builds the Ruby paths.' >$target/.ruby-paths.txt echo '# KLayout will load the paths listed in this file into $0' >>$target/.ruby-paths.txt echo '# Use KLayout EXPRESSIONS syntax to specify a list of file paths.' >>$target/.ruby-paths.txt echo '[' >>$target/.ruby-paths.txt first=1 for p in $rubys; do p=$(cygpath $p) if [[ $p == "$mingw_inst"* ]] && [ -e "$p" ]; then rp=${p/"$mingw_inst/"} # Apparently adding the paths to the interpreter isn't required - # Ruby can figure out it's own paths # if [ $first == "0" ]; then # echo "," >>$target/.ruby-paths.txt # fi # first=0 # echo -n " combine(inst_path, '$rp')" >>$target/.ruby-paths.txt echo "Copying Ruby installation partial $p -> $target/$rp .." rm -rf $target/$rp mkdir -p $target/$rp rmdir $target/$rp cp -vR $p $target/$rp | sed -u 's/.*/echo -n ./' | sh echo "" fi done echo '' >>$target/.ruby-paths.txt echo ']' >>$target/.ruby-paths.txt # don't forget the gem directory (specifications and gems) p=$(ruby -e 'puts Gem::dir') p=$(cygpath $p) if [[ $p == "$mingw_inst"* ]] && [ -e "$p" ]; then rp=${p/"$mingw_inst/"} echo "Copying Ruby gems $p -> $target/$rp .." rm -rf $target/$rp mkdir -p $target/$rp rmdir $target/$rp cp -vR $p $target/$rp | sed -u 's/.*/echo -n ./' | sh echo "" fi # ---------------------------------------------------------- # Python dependencies pythons=$($python -c "import sys; print('\n'.join(sys.path))" | sort) rm -rf $target/.python-paths.txt echo '# Builds the Python paths.' >$target/.python-paths.txt echo '# KLayout will load the paths listed in this file into sys.path' >>$target/.python-paths.txt echo '# unless $KLAYOUT_PYTHONHOME ist set.' >>$target/.python-paths.txt echo '# Use KLayout EXPRESSIONS syntax to specify a list of file paths.' >>$target/.python-paths.txt echo '[' >>$target/.python-paths.txt first=1 for p in $pythons; do p=$(cygpath $p) rp="" if [[ $p == "$mingw_inst"* ]] && [ -e "$p" ]; then rp=${p/"$mingw_inst/"} fi # NOTE: "bin" is in the path sometimes and will pollute our installation, so we skip it if [ "$rp" != "" ] && [ "$rp" != "bin" ]; then if [ $first == "0" ]; then echo "," >>$target/.python-paths.txt fi first=0 echo -n " combine(inst_path, '$rp')" >>$target/.python-paths.txt echo "Copying Python installation partial $p -> $target/$rp .." rm -rf $target/$rp mkdir -p $target/$rp rmdir $target/$rp cp -vR $p $target/$rp | sed -u 's/.*/echo -n ./' | sh echo "" fi done echo '' >>$target/.python-paths.txt echo ']' >>$target/.python-paths.txt # ---------------------------------------------------------- # Binary dependencies pushd $target new_libs=$(find . -name "*.dll" -or -name "*.pyd" -or -name "*.so") while [ "$new_libs" != "" ]; do echo "Analyzing dependencies of $new_libs .." # Analyze the dependencies of our components and add the corresponding libraries from $mingw_inst/bin tmp_libs=.tmp-libs.txt rm -f $tmp_libs echo "" >$tmp_libs for l in $new_libs; do echo -n "." objdump -p $l | grep "DLL Name:" | sed 's/.*DLL Name: *//' >>$tmp_libs done echo "" libs=$(cat $tmp_libs | sort -u) rm -f $tmp_libs new_libs="" for l in $libs; do if [ -e $mingw_inst/bin/$l ] && ! [ -e $l ]; then echo "Copying binary installation partial $mingw_inst/bin/$l -> $l .." cp $mingw_inst/bin/$l $l new_libs="$new_libs $l" elif [ -e "${ucrt_vssdk}/$l" ] && ! [ -e $l ]; then echo "Copying binary installation partial ${ucrt_vssdk}/${l} -> $l .." cp "${ucrt_vssdk}/${l}" "$l" new_libs="$new_libs $l" fi done done popd # ---------------------------------------------------------- # Run NSIS # TODO: NSIS now supports /nocd with which we would no # longer require the copy cp $scripts/klayout-inst.nsis $target cd $target NSIS_VERSION=$KLAYOUT_VERSION NSIS_ARCH=$arch$KLAYOUT_BUILD_SUFFIX "$makensis" klayout-inst.nsis # ---------------------------------------------------------- # Produce the .zip file zipname="klayout-$KLAYOUT_VERSION-$arch$KLAYOUT_BUILD_SUFFIX" echo "Making .zip file $zipname.zip .." rm -rf $zipname $zipname.zip mkdir $zipname cp -Rv strm*.exe *.dll cert.pem .*-paths.txt db_plugins lay_plugins pymod $plugins lib $zipname | sed -u 's/.*/echo -n ./' | sh cp klayout.exe $zipname/klayout_app.exe cp klayout.exe $zipname/klayout_vo_app.exe echo "" zip -r $zipname.zip $zipname rm -rf $zipname