From edca9ede55814481f8bd42f5676bf667b663953a Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 02:36:13 +0000 Subject: [PATCH 1/11] Change sh2exe.sh to sh2exe_v1.sh --- diff --git a/sh2exe.sh b/sh2exe.sh deleted file mode 100644 index 9b7a6a9..0000000 --- a/sh2exe.sh +++ /dev/null @@ -1,351 +0,0 @@ -#!/bin/sh -# Copyright 2023 Charadon -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -if [ ! "$MSYSTEM" = "MSYS" ]; -then - echo "You must run MSYS2 with the MSYS runtime." - exit 1 -fi - -help_screen() { - echo "Usage: $0 [verb/file]" - echo "Turns a POSIX shell script into a Windows Executable." - printf "\n" - echo "Valid Verbs:" - printf "help Displays this screen.\n" - printf "clean Cleans the workspace.\n" - printf " Tells script which script to turn into executable.\n\n" - echo "Exit status:" - echo " 0 = Success." - echo " 1 = Script failed before build part started." - echo " 2 = Checksum mismatch of downloaded files." - echo " 5 = Failed to change directory at some point in the script." - printf "\n" - echo "For more information visit sh2exe's website at: https://sh2exe.iotib.net" - echo "or the git repo at: https://pagure.io/DaLazySlackers/sh2exe" - exit "$1" -} - -SEVEN_ZIP="7zr.exe" - -if [ -z "$1" ]; -then - help_screen 1 -elif [ "$1" = "help" ]; -then - help_screen 0 -fi - -set -eu - -WORKDIR="$PWD/work" -rm -rf "$WORKDIR" -mkdir -p "$WORKDIR" -rm output.log > /dev/null 2>&1 || true -STARTING_DIR="$PWD" - -COREUTILS_SHA512SUM="a6ee2c549140b189e8c1b35e119d4289ec27244ec0ed9da0ac55202f365a7e33778b1dc7c4e64d1669599ff81a8297fe4f5adbcc8a3a2f75c919a43cd4b9bdfa *coreutils-9.1.tar.xz" -COREUTILS_VERSION="9.1" -OKSH_SHA512SUM="1b412ebbae58bdb1ccf9b9e0b64bab233cd5e184a02bc67db9b4ba82fce0749b8166dd688c24fd890d22a111d7f6ba859c47e3175f28675fca9c6def8c416a08 *oksh-7.2.tar.gz" -OKSH_VERSION="7.2" -NANO_SHA512SUM="b1eb5c06460b1407e3fc959070d2eaaba29d236ef099654fcbf9ba7cf7b22f64ebc9e6f232d471601c35f0e1c78d8c7aad9269e2afed25c0899572b97d44a95c *nano-7.1.tar.gz" -NANO_VERSION="7.1" -LESS_SHA512SUM="7945b7f88921832ebb1b45fba8cbb449ee0133342796b654a52c146dfff3d84db18724ee84e53349eeea6017a0ebe2d8eb5366210275981dde7bb7190118fa66 *less-608.tar.gz" -LESS_VERSION="608" -GAWK_SHA512SUM="1d2aaf90bd074379e13dce65b53e80d449c383ff1f2862bb294644b2053383c19172d3b68bfd9caad82ccd11bea1baf627994280e845da9fdd0e773a000cfe40 *gawk-5.2.1.tar.gz" -GAWK_VERSION="5.2.1" -GREP_SHA512SUM="69cf162886770c4ff86f869f78d8a7e291480f576a92f2afa87c42290c7d34c4ca5cf52e47d10c8e310eadd605d209a2701dc714b651d122be9eca1e73130409 *grep-3.8.tar.gz" -GREP_VERSION="3.8" - -# Speed up compilation times. -# Doesn't work: https://github.com/msys2/MSYS2-packages/issues/2492 -#CC="ccache gcc" -#export CC -#CXX="ccache g++" -#export CXX - - - -if [ "$1" = "clean" ]; -then - echo "Cleaning... " - rm -rvf "$WORKDIR" || true - rm -rvf "coreutils-$COREUTILS_VERSION/" || true - rm -rvf "oksh-$OKSH_VERSION/" || true - rm -rvf "nano-$NANO_VERSION/" || true - rm -rvf "gawk-$GAWK_VERSION/" || true - rm -rvf "grep-$GREP_VERSION/" || true - rm -rvf "less-$LESS_VERSION/" || true - rm -f ./*.tar.?z || true - rm -f ./*.7z || true - rm -f 7zip.h || true - rm -f runtime.h || true - rm -f 7zr.exe || true - rm -f *.stackdump - cd bin2c - make clean - cd .. - exit 0 -else - SHEBANG="$(head -1 "$1")" - if [ ! "$SHEBANG" = "#!/bin/sh" ]; - then - echo "Shebang needs to be #!/bin/sh." - exit 1 - fi - SCRIPT_NAME="$1" -fi - -echo "If your terminal closes, that means MSYS had an update that required a runtime restart." -echo "If the script ends, but there's no checkmark after the task, check the output.log for errors." -printf "Updating system... " -yes | pacman -Syu >> output.log 2>&1 -printf "✓\n" -printf "Installing dependencies... " -yes | pacman -S ncurses-devel gcc texinfo ccache >> output.log 2>&1 -printf "✓\n" - -download_7zip() { - curl "https://7-zip.org/a/7zr.exe" -O -} - -build_coreutils() { - curl "https://ftp.gnu.org/pub/gnu/coreutils/coreutils-$COREUTILS_VERSION.tar.xz" -O - if [ ! "$(sha512sum coreutils-"$COREUTILS_VERSION".tar.xz)" = "$COREUTILS_SHA512SUM" ]; - then - echo "Checksum mismatch for coreutils." - exit 2 - fi - if [ -f "coreutils-$COREUTILS_VERSION/DONE" ]; - then - cd "coreutils-$COREUTILS_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install-exec - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "coreutils-$COREUTILS_VERSION".tar.xz - cd "coreutils-$COREUTILS_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make DESTDIR="$WORKDIR" -j "$(nproc)" install-exec - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_nano() { - curl "https://ftp.gnu.org/gnu/nano/nano-$NANO_VERSION.tar.gz" -O - if [ ! "$(sha512sum nano-$NANO_VERSION.tar.gz)" = "$NANO_SHA512SUM" ]; - then - echo "Checksum mismatch for nano." - exit 2 - fi - if [ -f "nano-$NANO_VERSION/DONE" ]; - then - cd "nano-$NANO_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install-exec - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "nano-$NANO_VERSION.tar.gz" - cd "nano-$NANO_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr --enable-tiny - make -j "$(nproc)" - make DESTDIR="$WORKDIR" -j "$(nproc)" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_oksh() { - curl "https://github.com/ibara/oksh/releases/download/oksh-$OKSH_VERSION/oksh-$OKSH_VERSION.tar.gz" -OL - if [ ! "$(sha512sum oksh-$OKSH_VERSION.tar.gz)" = "$OKSH_SHA512SUM" ]; - then - echo "Checksum mismatch for OKSH." - exit 2 - fi - if [ -f oksh-$OKSH_VERSION/DONE ]; - then - cd "oksh-$OKSH_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "oksh-$OKSH_VERSION.tar.gz" - cd "oksh-$OKSH_VERSION" || exit 5 - make clean || true - ./configure --enable-curses --enable-sh --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_less() { - curl "https://ftp.gnu.org/gnu/less/less-$LESS_VERSION.tar.gz" -O - if [ ! "$(sha512sum less-$LESS_VERSION.tar.gz)" = "$LESS_SHA512SUM" ]; - then - echo "Checksum mismatch for Less" - exit 2 - fi - if [ -f less-$LESS_VERSION/DONE ]; - then - cd "less-$LESS_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "less-$LESS_VERSION.tar.gz" - cd "less-$LESS_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_gawk() { - curl "https://ftp.gnu.org/gnu/gawk/gawk-$GAWK_VERSION.tar.gz" -O - if [ ! "$(sha512sum gawk-$GAWK_VERSION.tar.gz)" = "$GAWK_SHA512SUM" ]; - then - echo "Checksum mismatch for Gawk" - exit 2 - fi - if [ -f gawk-$GAWK_VERSION/DONE ]; - then - cd "gawk-$GAWK_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "gawk-$GAWK_VERSION.tar.gz" - cd "gawk-$GAWK_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_grep() { - curl "https://ftp.gnu.org/gnu/grep/grep-$GREP_VERSION.tar.gz" -O - if [ ! "$(sha512sum grep-$GREP_VERSION.tar.gz)" = "$GREP_SHA512SUM" ]; - then - echo "Checksum mismatch for Grep" - exit 2 - fi - if [ -f grep-$GREP_VERSION/DONE ]; - then - cd "grep-$GREP_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "grep-$GREP_VERSION.tar.gz" - cd "grep-$GREP_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_bin2c() { - cd bin2c || exit 5 - make - cd "$STARTING_DIR" || exit 5 -} - -cleanup_work() { - # Remove man pages and headers. - rm -rf "${WORKDIR:?}/usr/share/man" - rm -rf "${WORKDIR:?}/usr/share/info" - rm -rf "${WORKDIR:?}/usr/include" - # Strip binaries - for i in "$WORKDIR/usr/bin"/*.exe; - do - strip --strip-unneeded "$i" - done - # Add DLLs from MSYS so executables can run. - cp "/usr/bin/msys-ncursesw6.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-2.0.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-iconv-2.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-intl-8.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-pcre-1.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-gcc_s-seh-1.dll" "$WORKDIR/usr/bin" - # Strip DLLs to save space. - for i in "$WORKDIR/usr/bin"/*.dll; - do - strip --strip-unneeded "$i" - done - cp "$SCRIPT_NAME" "$WORKDIR/usr/bin" - mkdir -p "$WORKDIR/usr/share/terminfo/63/" - cp "/usr/share/terminfo/63/cygwin" "$WORKDIR/usr/share/terminfo/63/" - # Time to 7zip it up. - ./$SEVEN_ZIP a -mx1 runtime.7z "$WORKDIR/*" -} - -build_runner() { - cp runsh.c "$WORKDIR/$SCRIPT_NAME.c" - bin2c/bin2c.exe "$SEVEN_ZIP" "$WORKDIR/7zip.h" SevenZip - bin2c/bin2c.exe "runtime.7z" "$WORKDIR/runtime.h" RuntimeArchive - sed -i "s|INSERT_SCRIPT_NAME_HERE|$(basename "$SCRIPT_NAME")|g" "$WORKDIR/$SCRIPT_NAME.c" - MSYSTEM="MINGW64" bash -l -c "gcc -I$WORKDIR -Wall -O1 \"$WORKDIR/$(basename $SCRIPT_NAME).c\" -o \"$WORKDIR/$(basename $SCRIPT_NAME).exe\"" -} -printf "Downloading 7-zip... " -download_7zip >> output.log 2>&1 -printf "✓\n" -printf "Compiling and installing GNU Coreutils... " -build_coreutils >> output.log 2>&1 -printf "✓\n" -printf "Installing some of MSYS2's Coreutils to workaround bugs... " -install -Dm755 "/usr/bin/ls" "$WORKDIR/usr/bin/ls" -install -Dm755 "/usr/bin/du" "$WORKDIR/usr/bin/du" -printf "✓\n" -printf "Compiling and installing GNU Awk... " -build_gawk >> output.log 2>&1 -printf "✓\n" -# Compiling grep and installing it results in segfault. We'll use MSYS2's for now. -printf "Installing GNU Grep... " -install -Dm755 "/usr/bin/grep" "$WORKDIR/usr/bin/grep" -printf "✓\n" -printf "Compiling and installing GNU Nano Text Editor... " -build_nano >> output.log 2>&1 -printf "✓\n" -printf "Compiling and installing GNU Less... " -build_less >> output.log 2>&1 -printf "✓\n" -printf "Compiling and installing Portable OpenBSD ksh... " -build_oksh >> output.log 2>&1 -printf "✓\n" -printf "Compiling bin2c... " -build_bin2c >> output.log 2>&1 -printf "✓\n" -printf "Creating runtime archive... " -cleanup_work >> output.log 2>&1 -printf "✓\n" -printf "Compiling executable... " -build_runner >> output.log 2>&1 -printf "✓\n" -echo "If all went well, your new executable should be in $WORKDIR/$(basename $SCRIPT_NAME).exe" -exit 0 diff --git a/sh2exe_v1.sh b/sh2exe_v1.sh new file mode 100644 index 0000000..e7d713a --- /dev/null +++ b/sh2exe_v1.sh @@ -0,0 +1,353 @@ +#!/bin/sh +# Copyright 2023 Charadon +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is slower, but saves a lot more space compared to the v2. + +if [ ! "$MSYSTEM" = "MSYS" ]; +then + echo "You must run MSYS2 with the MSYS runtime." + exit 1 +fi + +help_screen() { + echo "Usage: $0 [verb/file]" + echo "Turns a POSIX shell script into a Windows Executable." + printf "\n" + echo "Valid Verbs:" + printf "help Displays this screen.\n" + printf "clean Cleans the workspace.\n" + printf " Tells script which script to turn into executable.\n\n" + echo "Exit status:" + echo " 0 = Success." + echo " 1 = Script failed before build part started." + echo " 2 = Checksum mismatch of downloaded files." + echo " 5 = Failed to change directory at some point in the script." + printf "\n" + echo "For more information visit sh2exe's website at: https://sh2exe.iotib.net" + echo "or the git repo at: https://pagure.io/DaLazySlackers/sh2exe" + exit "$1" +} + +SEVEN_ZIP="7zr.exe" + +if [ -z "$1" ]; +then + help_screen 1 +elif [ "$1" = "help" ]; +then + help_screen 0 +fi + +set -eu + +WORKDIR="$PWD/work" +rm -rf "$WORKDIR" +mkdir -p "$WORKDIR" +rm output.log > /dev/null 2>&1 || true +STARTING_DIR="$PWD" + +COREUTILS_SHA512SUM="a6ee2c549140b189e8c1b35e119d4289ec27244ec0ed9da0ac55202f365a7e33778b1dc7c4e64d1669599ff81a8297fe4f5adbcc8a3a2f75c919a43cd4b9bdfa *coreutils-9.1.tar.xz" +COREUTILS_VERSION="9.1" +OKSH_SHA512SUM="1b412ebbae58bdb1ccf9b9e0b64bab233cd5e184a02bc67db9b4ba82fce0749b8166dd688c24fd890d22a111d7f6ba859c47e3175f28675fca9c6def8c416a08 *oksh-7.2.tar.gz" +OKSH_VERSION="7.2" +NANO_SHA512SUM="b1eb5c06460b1407e3fc959070d2eaaba29d236ef099654fcbf9ba7cf7b22f64ebc9e6f232d471601c35f0e1c78d8c7aad9269e2afed25c0899572b97d44a95c *nano-7.1.tar.gz" +NANO_VERSION="7.1" +LESS_SHA512SUM="7945b7f88921832ebb1b45fba8cbb449ee0133342796b654a52c146dfff3d84db18724ee84e53349eeea6017a0ebe2d8eb5366210275981dde7bb7190118fa66 *less-608.tar.gz" +LESS_VERSION="608" +GAWK_SHA512SUM="1d2aaf90bd074379e13dce65b53e80d449c383ff1f2862bb294644b2053383c19172d3b68bfd9caad82ccd11bea1baf627994280e845da9fdd0e773a000cfe40 *gawk-5.2.1.tar.gz" +GAWK_VERSION="5.2.1" +GREP_SHA512SUM="69cf162886770c4ff86f869f78d8a7e291480f576a92f2afa87c42290c7d34c4ca5cf52e47d10c8e310eadd605d209a2701dc714b651d122be9eca1e73130409 *grep-3.8.tar.gz" +GREP_VERSION="3.8" + +# Speed up compilation times. +# Doesn't work: https://github.com/msys2/MSYS2-packages/issues/2492 +#CC="ccache gcc" +#export CC +#CXX="ccache g++" +#export CXX + + + +if [ "$1" = "clean" ]; +then + echo "Cleaning... " + rm -rvf "$WORKDIR" || true + rm -rvf "coreutils-$COREUTILS_VERSION/" || true + rm -rvf "oksh-$OKSH_VERSION/" || true + rm -rvf "nano-$NANO_VERSION/" || true + rm -rvf "gawk-$GAWK_VERSION/" || true + rm -rvf "grep-$GREP_VERSION/" || true + rm -rvf "less-$LESS_VERSION/" || true + rm -f ./*.tar.?z || true + rm -f ./*.7z || true + rm -f 7zip.h || true + rm -f runtime.h || true + rm -f 7zr.exe || true + rm -f *.stackdump + cd bin2c + make clean + cd .. + exit 0 +else + SHEBANG="$(head -1 "$1")" + if [ ! "$SHEBANG" = "#!/bin/sh" ]; + then + echo "Shebang needs to be #!/bin/sh." + exit 1 + fi + SCRIPT_NAME="$1" +fi + +echo "If your terminal closes, that means MSYS had an update that required a runtime restart." +echo "If the script ends, but there's no checkmark after the task, check the output.log for errors." +printf "Updating system... " +yes | pacman -Syu >> output.log 2>&1 +printf "✓\n" +printf "Installing dependencies... " +yes | pacman -S ncurses-devel gcc texinfo ccache >> output.log 2>&1 +printf "✓\n" + +download_7zip() { + curl "https://7-zip.org/a/7zr.exe" -O +} + +build_coreutils() { + curl "https://ftp.gnu.org/pub/gnu/coreutils/coreutils-$COREUTILS_VERSION.tar.xz" -O + if [ ! "$(sha512sum coreutils-"$COREUTILS_VERSION".tar.xz)" = "$COREUTILS_SHA512SUM" ]; + then + echo "Checksum mismatch for coreutils." + exit 2 + fi + if [ -f "coreutils-$COREUTILS_VERSION/DONE" ]; + then + cd "coreutils-$COREUTILS_VERSION" || exit 5 + make DESTDIR="$WORKDIR" install-exec + cd "$STARTING_DIR" || exit 5 + return 0 + fi + tar -xvf "coreutils-$COREUTILS_VERSION".tar.xz + cd "coreutils-$COREUTILS_VERSION" || exit 5 + make clean || true + ./configure --prefix=/usr + make DESTDIR="$WORKDIR" -j "$(nproc)" install-exec + touch DONE + cd "$STARTING_DIR" || exit 5 + return 0 +} + +build_nano() { + curl "https://ftp.gnu.org/gnu/nano/nano-$NANO_VERSION.tar.gz" -O + if [ ! "$(sha512sum nano-$NANO_VERSION.tar.gz)" = "$NANO_SHA512SUM" ]; + then + echo "Checksum mismatch for nano." + exit 2 + fi + if [ -f "nano-$NANO_VERSION/DONE" ]; + then + cd "nano-$NANO_VERSION" || exit 5 + make DESTDIR="$WORKDIR" install-exec + cd "$STARTING_DIR" || exit 5 + return 0 + fi + tar -xvf "nano-$NANO_VERSION.tar.gz" + cd "nano-$NANO_VERSION" || exit 5 + make clean || true + ./configure --prefix=/usr --enable-tiny + make -j "$(nproc)" + make DESTDIR="$WORKDIR" -j "$(nproc)" install + touch DONE + cd "$STARTING_DIR" || exit 5 + return 0 +} + +build_oksh() { + curl "https://github.com/ibara/oksh/releases/download/oksh-$OKSH_VERSION/oksh-$OKSH_VERSION.tar.gz" -OL + if [ ! "$(sha512sum oksh-$OKSH_VERSION.tar.gz)" = "$OKSH_SHA512SUM" ]; + then + echo "Checksum mismatch for OKSH." + exit 2 + fi + if [ -f oksh-$OKSH_VERSION/DONE ]; + then + cd "oksh-$OKSH_VERSION" || exit 5 + make DESTDIR="$WORKDIR" install + cd "$STARTING_DIR" || exit 5 + return 0 + fi + tar -xvf "oksh-$OKSH_VERSION.tar.gz" + cd "oksh-$OKSH_VERSION" || exit 5 + make clean || true + ./configure --enable-curses --enable-sh --prefix=/usr + make -j "$(nproc)" + make DESTDIR="$WORKDIR" install + touch DONE + cd "$STARTING_DIR" || exit 5 + return 0 +} + +build_less() { + curl "https://ftp.gnu.org/gnu/less/less-$LESS_VERSION.tar.gz" -O + if [ ! "$(sha512sum less-$LESS_VERSION.tar.gz)" = "$LESS_SHA512SUM" ]; + then + echo "Checksum mismatch for Less" + exit 2 + fi + if [ -f less-$LESS_VERSION/DONE ]; + then + cd "less-$LESS_VERSION" || exit 5 + make DESTDIR="$WORKDIR" install + cd "$STARTING_DIR" || exit 5 + return 0 + fi + tar -xvf "less-$LESS_VERSION.tar.gz" + cd "less-$LESS_VERSION" || exit 5 + make clean || true + ./configure --prefix=/usr + make -j "$(nproc)" + make DESTDIR="$WORKDIR" install + touch DONE + cd "$STARTING_DIR" || exit 5 + return 0 +} + +build_gawk() { + curl "https://ftp.gnu.org/gnu/gawk/gawk-$GAWK_VERSION.tar.gz" -O + if [ ! "$(sha512sum gawk-$GAWK_VERSION.tar.gz)" = "$GAWK_SHA512SUM" ]; + then + echo "Checksum mismatch for Gawk" + exit 2 + fi + if [ -f gawk-$GAWK_VERSION/DONE ]; + then + cd "gawk-$GAWK_VERSION" || exit 5 + make DESTDIR="$WORKDIR" install + cd "$STARTING_DIR" || exit 5 + return 0 + fi + tar -xvf "gawk-$GAWK_VERSION.tar.gz" + cd "gawk-$GAWK_VERSION" || exit 5 + make clean || true + ./configure --prefix=/usr + make -j "$(nproc)" + make DESTDIR="$WORKDIR" install + touch DONE + cd "$STARTING_DIR" || exit 5 + return 0 +} + +build_grep() { + curl "https://ftp.gnu.org/gnu/grep/grep-$GREP_VERSION.tar.gz" -O + if [ ! "$(sha512sum grep-$GREP_VERSION.tar.gz)" = "$GREP_SHA512SUM" ]; + then + echo "Checksum mismatch for Grep" + exit 2 + fi + if [ -f grep-$GREP_VERSION/DONE ]; + then + cd "grep-$GREP_VERSION" || exit 5 + make DESTDIR="$WORKDIR" install + cd "$STARTING_DIR" || exit 5 + return 0 + fi + tar -xvf "grep-$GREP_VERSION.tar.gz" + cd "grep-$GREP_VERSION" || exit 5 + make clean || true + ./configure --prefix=/usr + make -j "$(nproc)" + make DESTDIR="$WORKDIR" install + touch DONE + cd "$STARTING_DIR" || exit 5 + return 0 +} + +build_bin2c() { + cd bin2c || exit 5 + make + cd "$STARTING_DIR" || exit 5 +} + +cleanup_work() { + # Remove man pages and headers. + rm -rf "${WORKDIR:?}/usr/share/man" + rm -rf "${WORKDIR:?}/usr/share/info" + rm -rf "${WORKDIR:?}/usr/include" + # Strip binaries + for i in "$WORKDIR/usr/bin"/*.exe; + do + strip --strip-unneeded "$i" + done + # Add DLLs from MSYS so executables can run. + cp "/usr/bin/msys-ncursesw6.dll" "$WORKDIR/usr/bin" + cp "/usr/bin/msys-2.0.dll" "$WORKDIR/usr/bin" + cp "/usr/bin/msys-iconv-2.dll" "$WORKDIR/usr/bin" + cp "/usr/bin/msys-intl-8.dll" "$WORKDIR/usr/bin" + cp "/usr/bin/msys-pcre-1.dll" "$WORKDIR/usr/bin" + cp "/usr/bin/msys-gcc_s-seh-1.dll" "$WORKDIR/usr/bin" + # Strip DLLs to save space. + for i in "$WORKDIR/usr/bin"/*.dll; + do + strip --strip-unneeded "$i" + done + cp "$SCRIPT_NAME" "$WORKDIR/usr/bin" + mkdir -p "$WORKDIR/usr/share/terminfo/63/" + cp "/usr/share/terminfo/63/cygwin" "$WORKDIR/usr/share/terminfo/63/" + # Time to 7zip it up. + ./$SEVEN_ZIP a -mx1 runtime.7z "$WORKDIR/*" +} + +build_runner() { + cp runsh.c "$WORKDIR/$SCRIPT_NAME.c" + bin2c/bin2c.exe "$SEVEN_ZIP" "$WORKDIR/7zip.h" SevenZip + bin2c/bin2c.exe "runtime.7z" "$WORKDIR/runtime.h" RuntimeArchive + sed -i "s|INSERT_SCRIPT_NAME_HERE|$(basename "$SCRIPT_NAME")|g" "$WORKDIR/$SCRIPT_NAME.c" + MSYSTEM="MINGW64" bash -l -c "gcc -I$WORKDIR -Wall -O1 \"$WORKDIR/$(basename $SCRIPT_NAME).c\" -o \"$WORKDIR/$(basename $SCRIPT_NAME).exe\"" +} +printf "Downloading 7-zip... " +download_7zip >> output.log 2>&1 +printf "✓\n" +printf "Compiling and installing GNU Coreutils... " +build_coreutils >> output.log 2>&1 +printf "✓\n" +printf "Installing some of MSYS2's Coreutils to workaround bugs... " +install -Dm755 "/usr/bin/ls" "$WORKDIR/usr/bin/ls" +install -Dm755 "/usr/bin/du" "$WORKDIR/usr/bin/du" +printf "✓\n" +printf "Compiling and installing GNU Awk... " +build_gawk >> output.log 2>&1 +printf "✓\n" +# Compiling grep and installing it results in segfault. We'll use MSYS2's for now. +printf "Installing GNU Grep... " +install -Dm755 "/usr/bin/grep" "$WORKDIR/usr/bin/grep" +printf "✓\n" +printf "Compiling and installing GNU Nano Text Editor... " +build_nano >> output.log 2>&1 +printf "✓\n" +printf "Compiling and installing GNU Less... " +build_less >> output.log 2>&1 +printf "✓\n" +printf "Compiling and installing Portable OpenBSD ksh... " +build_oksh >> output.log 2>&1 +printf "✓\n" +printf "Compiling bin2c... " +build_bin2c >> output.log 2>&1 +printf "✓\n" +printf "Creating runtime archive... " +cleanup_work >> output.log 2>&1 +printf "✓\n" +printf "Compiling executable... " +build_runner >> output.log 2>&1 +printf "✓\n" +echo "If all went well, your new executable should be in $WORKDIR/$(basename $SCRIPT_NAME).exe" +exit 0 From 84b7494f136f721720bbee9c45b558f28773a2e4 Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 02:36:53 +0000 Subject: [PATCH 2/11] Added CFLAGS and CXXFLAGS to optimize for small binaries. --- diff --git a/sh2exe_v1.sh b/sh2exe_v1.sh index e7d713a..d1fdf62 100644 --- a/sh2exe_v1.sh +++ b/sh2exe_v1.sh @@ -77,6 +77,8 @@ GREP_VERSION="3.8" #export CC #CXX="ccache g++" #export CXX +export CFLAGS="-Os" +export CXXFLAGS="-Os" From 17d7ec4745553dd9a0af786f48367ac309db061d Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 02:44:09 +0000 Subject: [PATCH 3/11] Safer syntax --- diff --git a/sh2exe_v1.sh b/sh2exe_v1.sh index d1fdf62..3e6cdf0 100644 --- a/sh2exe_v1.sh +++ b/sh2exe_v1.sh @@ -14,6 +14,7 @@ # limitations under the License. # This script is slower, but saves a lot more space compared to the v2. +# And since it uses oksh instead of bash, it's immune to bashisms. if [ ! "$MSYSTEM" = "MSYS" ]; then @@ -77,8 +78,10 @@ GREP_VERSION="3.8" #export CC #CXX="ccache g++" #export CXX -export CFLAGS="-Os" -export CXXFLAGS="-Os" +CFLAGS="-Os" +export CFLAGS +CXXFLAGS="-Os" +export CXXFLAGS From cdae4aecf3ea17fce33371ad47c3ed8944ea6e4b Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 06:32:01 +0000 Subject: [PATCH 4/11] renamed old readme to v1 --- diff --git a/README.txt b/README.txt deleted file mode 100644 index df1a991..0000000 --- a/README.txt +++ /dev/null @@ -1,57 +0,0 @@ - _____ _ _ ___ ______ __ __ ______ -/ ____| | | | | |__ \ | ____| \ \ / / | ____| -| (___ | |__| | ) | | |__ \ V / | |__ -\___ \ | __ | / / | __| > < | __| -____) | | | | | / /_ | |____ / . \ | |____ -|_____/ |_| |_| |____| |______| /_/ \_\ |______| -================================================================================ -WHAT IS IT? -------------- -sh2exe is a script that turns POSIX Shell scripts into Windows executables, -therefore allowing you to distribute a Shell Script on Windows without needing -a full Git for Bash or Cygwin environment installed somewhere. - -It currently bundles: -- GNU Coreutils -- GNU Less -- GNU Awk -- GNU Grep -- GNU Nano -- Portable OpenBSD Kornshell -This should give you a roughly complete POSIX Shell experience. - -Currently, the executable comes out at around 6MB, which is pretty small on -modern storage devices! - -USE CASES -------------- -This script can help you, if you need to distribute a script (say, to launch -a game your making *cough*) without needing to make a script *solely* for -Windows. Just turn it into an executable, and presto! You got a script that -runs! - -REQUIREMENTS -------------- -You must run this script in an MSYS2 environment. I might add cygwin support -eventually, but for now, MSYS2 only. However, once the executable has been -generated, you will *not* need MSYS2 installed to run it. - -USAGE -------------- -Simply run sh2exe.sh with the path to the script you want to convert. -Example: ./sh2exe.sh /path/to/script.sh - -You can run it on the included helloworld.sh script to see it in action! - -For more info, run ./sh2exe.sh help - -COPYRIGHT -------------- -The sh2exe.sh script itself is licensed under Apache 2.0, however the source -code template (runsh.c) is licensed under the GNU All-Permissive License, -meaning you can do whatever you want with the generated executable. - -SUPPORT ME -------------- -If you like this program, consider giving some dollary doos at -https://liberapay.com/Charadon diff --git a/README_v1.txt b/README_v1.txt new file mode 100644 index 0000000..db89d75 --- /dev/null +++ b/README_v1.txt @@ -0,0 +1,57 @@ + _____ _ _ ___ ______ __ __ ______ +/ ____| | | | | |__ \ | ____| \ \ / / | ____| +| (___ | |__| | ) | | |__ \ V / | |__ +\___ \ | __ | / / | __| > < | __| +____) | | | | | / /_ | |____ / . \ | |____ +|_____/ |_| |_| |____| |______| /_/ \_\ |______| v1 +================================================================================ +WHAT IS IT? +------------- +sh2exe is a script that turns POSIX Shell scripts into Windows executables, +therefore allowing you to distribute a Shell Script on Windows without needing +a full Git for Bash or Cygwin environment installed somewhere. + +It currently bundles: +- GNU Coreutils +- GNU Less +- GNU Awk +- GNU Grep +- GNU Nano +- Portable OpenBSD Kornshell +This should give you a roughly complete POSIX Shell experience. + +Currently, the executable comes out at around 6MB, which is pretty small on +modern storage devices! + +USE CASES +------------- +This script can help you, if you need to distribute a script (say, to launch +a game your making *cough*) without needing to make a script *solely* for +Windows. Just turn it into an executable, and presto! You got a script that +runs! + +REQUIREMENTS +------------- +You must run this script in an MSYS2 environment. I might add cygwin support +eventually, but for now, MSYS2 only. However, once the executable has been +generated, you will *not* need MSYS2 installed to run it. + +USAGE +------------- +Simply run sh2exe.sh with the path to the script you want to convert. +Example: ./sh2exe.sh /path/to/script.sh + +You can run it on the included helloworld.sh script to see it in action! + +For more info, run ./sh2exe.sh help + +COPYRIGHT +------------- +The sh2exe.sh script itself is licensed under Apache 2.0, however the source +code template (runsh.c) is licensed under the GNU All-Permissive License, +meaning you can do whatever you want with the generated executable. + +SUPPORT ME +------------- +If you like this program, consider giving some dollary doos at +https://liberapay.com/Charadon diff --git a/sh2exe.sh b/sh2exe.sh new file mode 100644 index 0000000..5a2038d --- /dev/null +++ b/sh2exe.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +set -eu + +# Create work directory. +WORKDIR="$PWD/work" +mkdir -p "$WORKDIR/var/lib/pacman" From ee97aeda7a51df10246ba893b4273c863a8df4ef Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 12:50:01 +0000 Subject: [PATCH 5/11] More work on version 2 --- diff --git a/sh2exe.sh b/sh2exe.sh index 5a2038d..19043fa 100644 --- a/sh2exe.sh +++ b/sh2exe.sh @@ -1,7 +1,162 @@ #!/bin/sh +help_screen() { + echo "Usage: $0 [-s FILE] [-w DIR]" + echo "Turns a POSIX shell script into a Windows Executable." + printf "\n" + echo "Options:" + echo "-s=FILE Script to convert to executable." + echo "-w=DIR Directory to use as a work directory." + echo "-h Shows this screen." + echo "-c Cleans workspace." + echo "-l Shows license of this script." + printf "\n" + echo "Example:" + echo "# Converts helloworld.sh to an executable while using a different workspace by default." + echo "$0 -s helloworld.sh -w /tmp/sh2exe_work" + printf "\n" + echo "Exit status:" + echo "0 = Success." + echo "1 = Initialization failure. (Before runtime was being built.)" + echo "5 = Failed to change directory while runtime was building." + return 0 +} + +show_license() { + echo " + Copyright 2023 Charadon + + Licensed under the Apache License, Version 2.0 (the \"License\"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an \"AS IS\" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + " + return 0 +} + +clean() { + return 0 +} + +if [ -z "$1" ]; +then + help_screen + exit 1 +fi + +while getopts ":s:w:chl" opt; +do + case "${opt}" in + s) + SCRIPT="${OPTARG}" + ;; + w) + WORKDIR=${OPTARG} + ;; + h) + help_screen + exit 0 + ;; + c) + clean + exit 0 + ;; + l) + show_license + exit 0 + ;; + *) + help_screen + exit 1 + ;; + esac +done + +if [ -z "$SCRIPT" ]; +then + help_screen + exit 1 +fi + set -eu +if [ ! "$MSYSTEM" = "MSYS" ]; +then + echo "You must run MSYS2 with the MSYS runtime." + exit 1 +fi + # Create work directory. -WORKDIR="$PWD/work" +WORKDIR="${WORKDIR:-$PWD/work}" +rm -rf "$WORKDIR" mkdir -p "$WORKDIR/var/lib/pacman" + +OUTPUT_LOG="${OUTPUT_LOG:-output.log}" +rm -f "$OUTPUT_LOG" + +# Update system +printf "Updating system... ⧖" +yes | pacman -Syu >> "$OUTPUT_LOG" 2>&1 +printf "\rUpdating system... ✓\n" + +# Install dependencies +printf "Installing dependencies... ⧖" +yes | pacman -S curl make gcc >> "$OUTPUT_LOG" 2>&1 +printf "\rInstalling dependencies... ✓\n" + +# Download 7-zip +printf "Downloading 7-zip... ⧖" +curl "https://7-zip.org/a/7zr.exe" -O >> "$OUTPUT_LOG" 2>&1 +printf "\rDownloading 7-zip... ✓\n" + +# Compile bin2c to embed runtime and 7zip into source file. +printf "Building bin2c... ⧖" +cd bin2c || exit 5 +make clean >> "$OUTPUT_LOG" 2>&1 +make -j "$(nproc)" >> "$OUTPUT_LOG" 2>&1 +cd .. || exit 5 +printf "\rBuilding bin2c... ✓\n" + +# Create runtime environment. +printf "Creating runtime environment... ⧖" +yes | pacman --root "$WORKDIR" -Sy >> "$OUTPUT_LOG" 2>&1 +yes | pacman --root "$WORKDIR" -S \ + coreutils \ + msys2-runtime \ + grep \ + gawk \ + less \ + sed \ + nano >> "$OUTPUT_LOG" 2>&1 +printf "\rCreating runtime environment... ✓\n" + +# Remove useless files from runtime environment. +printf "Pruning useless stuff from runtime... ⧖" +rm -rf "${WORKDIR:?}/var" +rm -rf "${WORKDIR:?}/usr/share/info" +rm -rf "${WORKDIR:?}/usr/share/man" +rm -rf "${WORKDIR:?}/usr/share/doc" +rm -rf "${WORKDIR:?}/usr/share/licenses" +rm -rf "${WORKDIR:?}/usr/share/locale" +rm -rf "${WORKDIR:?}/usr/include" +for i in $WORKDIR/usr/bin/*.exe; +do + strip --strip-unneeded "$i" +done +for i in $WORKDIR/usr/bin/*.dll; +do + strip --strip-unneeded "$i" +done +printf "\rPruning useless stuff from runtime... ✓\n" + +# Compress the runtime down with 7zip +printf "Create runtime archive... ⧖" +./7zr.exe a "$WORKDIR"/runtime.7z "$WORKDIR/*" >> "$OUTPUT_LOG" 2>&1 +printf "\rCreate runtime archive... ✓\n" From 26c506148187c5cfa2c7c9063db675a73e2fef94 Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 22:32:15 +0000 Subject: [PATCH 6/11] Finished v2 --- diff --git a/runsh.c b/runsh.c index 51f656a..e1f889f 100644 --- a/runsh.c +++ b/runsh.c @@ -129,6 +129,18 @@ int main(int argc, char *argv[]) { error_at_line(__LINE__, __FILE__, strerror(errno)); } + // Fix issue where bash will complain about missing /tmp + char RuntimeTmpDir[PATH_MAX]; + if(strncpy(RuntimeTmpDir, TempDir, PATH_MAX-1) == NULL) { + error_at_line(__LINE__, __FILE__, "strncpy"); + } + if(strncat(RuntimeTmpDir, "\\tmp", PATH_MAX-1) == NULL) { + error_at_line(__LINE__, __FILE__, "strncat"); + } + if(mkdir(RuntimeTmpDir) != 0) { + error_at_line(__LINE__, __FILE__, strerror(errno)); + } + // Set environment variables. // PATH char *PathEnv = getenv("PATH"); diff --git a/sh2exe.sh b/sh2exe.sh index 19043fa..df25997 100644 --- a/sh2exe.sh +++ b/sh2exe.sh @@ -56,9 +56,20 @@ do case "${opt}" in s) SCRIPT="${OPTARG}" + if [ ! -f "$SCRIPT" ]; + then + echo "File doesn't exist." + exit 1 + fi + SHEBANG="$(head -1 "$SCRIPT")" + if [ ! "$SHEBANG" = "#!/bin/sh" ]; + then + echo "File has invalid shebang. Aborting." + exit 1 + fi ;; w) - WORKDIR=${OPTARG} + WORKDIR="${OPTARG}" ;; h) help_screen @@ -93,6 +104,24 @@ then exit 1 fi +wait_for_finish() { + printf "|" + while kill -0 "$1" > /dev/null 2>&1; + do + printf "\b|" + sleep 0.1 + printf "\b/" + sleep 0.1 + printf "\b-" + sleep 0.1 + printf "\b\\" + sleep 0.1 + done + printf "\b" + wait "$1" + return "$?" +} + # Create work directory. WORKDIR="${WORKDIR:-$PWD/work}" rm -rf "$WORKDIR" @@ -102,22 +131,25 @@ OUTPUT_LOG="${OUTPUT_LOG:-output.log}" rm -f "$OUTPUT_LOG" # Update system -printf "Updating system... ⧖" -yes | pacman -Syu >> "$OUTPUT_LOG" 2>&1 +printf "Updating system... " +yes | pacman -Syu >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" printf "\rUpdating system... ✓\n" # Install dependencies -printf "Installing dependencies... ⧖" -yes | pacman -S curl make gcc >> "$OUTPUT_LOG" 2>&1 +printf "Installing dependencies... " +yes | pacman -S curl make gcc mingw-w64-x86_64-gcc >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" printf "\rInstalling dependencies... ✓\n" # Download 7-zip -printf "Downloading 7-zip... ⧖" -curl "https://7-zip.org/a/7zr.exe" -O >> "$OUTPUT_LOG" 2>&1 +printf "Downloading 7-zip... " +curl "https://7-zip.org/a/7zr.exe" -O >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" printf "\rDownloading 7-zip... ✓\n" # Compile bin2c to embed runtime and 7zip into source file. -printf "Building bin2c... ⧖" +printf "Building bin2c... " cd bin2c || exit 5 make clean >> "$OUTPUT_LOG" 2>&1 make -j "$(nproc)" >> "$OUTPUT_LOG" 2>&1 @@ -125,8 +157,9 @@ cd .. || exit 5 printf "\rBuilding bin2c... ✓\n" # Create runtime environment. -printf "Creating runtime environment... ⧖" -yes | pacman --root "$WORKDIR" -Sy >> "$OUTPUT_LOG" 2>&1 +printf "Creating runtime environment... " +yes | pacman --root "$WORKDIR" -Sy >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" yes | pacman --root "$WORKDIR" -S \ coreutils \ msys2-runtime \ @@ -134,11 +167,13 @@ yes | pacman --root "$WORKDIR" -S \ gawk \ less \ sed \ - nano >> "$OUTPUT_LOG" 2>&1 + nano >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" +cp "$SCRIPT" "$WORKDIR/usr/bin/" printf "\rCreating runtime environment... ✓\n" # Remove useless files from runtime environment. -printf "Pruning useless stuff from runtime... ⧖" +printf "Pruning useless stuff from runtime... " rm -rf "${WORKDIR:?}/var" rm -rf "${WORKDIR:?}/usr/share/info" rm -rf "${WORKDIR:?}/usr/share/man" @@ -157,6 +192,20 @@ done printf "\rPruning useless stuff from runtime... ✓\n" # Compress the runtime down with 7zip -printf "Create runtime archive... ⧖" -./7zr.exe a "$WORKDIR"/runtime.7z "$WORKDIR/*" >> "$OUTPUT_LOG" 2>&1 +printf "Create runtime archive... " +./7zr.exe a "$WORKDIR"/runtime.7z "$WORKDIR/*" >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" printf "\rCreate runtime archive... ✓\n" + +printf "Compiling executable... " +cp runsh.c "$WORKDIR/$(basename $SCRIPT).c" +sed -i "s/INSERT_SCRIPT_NAME_HERE/$(basename $SCRIPT)/g" "$WORKDIR/$(basename $SCRIPT).c" +bin2c/bin2c.exe "7zr.exe" "$WORKDIR/7zip.h" SevenZip >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" +bin2c/bin2c.exe "$WORKDIR/runtime.7z" "$WORKDIR/runtime.h" RuntimeArchive >> "$OUTPUT_LOG" 2>&1 & +wait_for_finish "$!" +MSYSTEM="MINGW64" bash -l -c "gcc -I$WORKDIR -Wall -O1 \"$WORKDIR/$(basename $SCRIPT).c\" -o \"$WORKDIR/$(basename $SCRIPT).exe\"" & +wait_for_finish "$!" +printf "\rCompiling executable... ✓\n" +echo "If everything went well, this script should've made an executable at:" +echo "$WORKDIR/$(basename $SCRIPT).exe" From 26938879df24210498f4b84e54c0ac8b9b18bb50 Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 22:56:17 +0000 Subject: [PATCH 7/11] Add POSIX vs Bash shell detection, and fixed error in runsh.c if /tmp already existed. --- diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..9be1925 --- /dev/null +++ b/README.txt @@ -0,0 +1,58 @@ + _____ _ _ ___ ______ __ __ ______ +/ ____| | | | | |__ \ | ____| \ \ / / | ____| +| (___ | |__| | ) | | |__ \ V / | |__ +\___ \ | __ | / / | __| > < | __| +____) | | | | | / /_ | |____ / . \ | |____ +|_____/ |_| |_| |____| |______| /_/ \_\ |______| v2 +================================================================================ +WHAT IS IT? +------------- +sh2exe is a script that turns POSIX Shell scripts into Windows executables, +therefore allowing you to distribute a Shell Script on Windows without needing +a full Git for Bash or Cygwin environment installed somewhere. + +It currently bundles: +- GNU Coreutils +- GNU Less +- GNU Awk +- GNU Grep +- GNU Nano +- GNU Bash +- MirBSD Shell +This should give you a roughly complete POSIX Shell experience. + +Currently, the executable comes out at around 6MB, which is pretty small on +modern storage devices! + +USE CASES +------------- +This script can help you, if you need to distribute a script (say, to launch +a game your making *cough*) without needing to make a script *solely* for +Windows. Just turn it into an executable, and presto! You got a script that +runs! + +REQUIREMENTS +------------- +You must run this script in an MSYS2 environment. I might add cygwin support +eventually, but for now, MSYS2 only. However, once the executable has been +generated, you will *not* need MSYS2 installed to run it. + +USAGE +------------- +Simply run sh2exe.sh with the path to the script you want to convert. +Example: ./sh2exe.sh /path/to/script.sh + +You can run it on the included helloworld.sh script to see it in action! + +For more info, run ./sh2exe.sh help + +COPYRIGHT +------------- +The sh2exe.sh script itself is licensed under Apache 2.0, however the source +code template (runsh.c) is licensed under the GNU All-Permissive License, +meaning you can do whatever you want with the generated executable. + +SUPPORT ME +------------- +If you like this program, consider giving some dollary doos at +https://liberapay.com/Charadon diff --git a/helloworld.sh b/helloworld.sh index f2517ba..38a3519 100644 --- a/helloworld.sh +++ b/helloworld.sh @@ -20,13 +20,13 @@ echo " Value: $HOME" echo "\$USER - Not on windows by default, but again, we provide it for you!" echo " Value: $USER" echo "\$EDITOR - If this isn't set in the user's environment, we make it Nano by default!" -echo " Value: $EDITOR" +echo " Value: $EDITOR" read CHOICE echo "Now i'm going to put a message on your desktop!" read CHOICE echo "How are you $USER? I hope you are having a wonderful day!" > "$HOME/Desktop/greetings.txt" -echo "Now let's open it..." +echo "Now let's open it with \$EDITOR..." read CHOICE $EDITOR "$HOME/Desktop/greetings.txt" echo "Here's all the commands you have available to you:" diff --git a/runsh.c b/runsh.c index e1f889f..baa98e5 100644 --- a/runsh.c +++ b/runsh.c @@ -138,7 +138,9 @@ int main(int argc, char *argv[]) { error_at_line(__LINE__, __FILE__, "strncat"); } if(mkdir(RuntimeTmpDir) != 0) { - error_at_line(__LINE__, __FILE__, strerror(errno)); + if(errno != EEXIST) { + error_at_line(__LINE__, __FILE__, strerror(errno)); + } } // Set environment variables. diff --git a/sh2exe.sh b/sh2exe.sh index df25997..d52a9e8 100644 --- a/sh2exe.sh +++ b/sh2exe.sh @@ -62,7 +62,7 @@ do exit 1 fi SHEBANG="$(head -1 "$SCRIPT")" - if [ ! "$SHEBANG" = "#!/bin/sh" ]; + if [ ! "$SHEBANG" = "#!/bin/sh" ] && [ ! "$SHEBANG" = "#!/bin/bash" ]; then echo "File has invalid shebang. Aborting." exit 1 @@ -167,6 +167,7 @@ yes | pacman --root "$WORKDIR" -S \ gawk \ less \ sed \ + mksh \ nano >> "$OUTPUT_LOG" 2>&1 & wait_for_finish "$!" cp "$SCRIPT" "$WORKDIR/usr/bin/" @@ -193,6 +194,12 @@ printf "\rPruning useless stuff from runtime... ✓\n" # Compress the runtime down with 7zip printf "Create runtime archive... " +# If shebang is the POSIX Shell (/bin/sh), use MirBSD Kornshell instead. +if [ "$SHEBANG" = "#!/bin/sh" ]; +then + rm "$WORKDIR/usr/bin/sh" # Remove bash + cp "$WORKDIR/usr/bin/mksh" "$WORKDIR/usr/bin/sh" # Put mksh in it's place. +fi ./7zr.exe a "$WORKDIR"/runtime.7z "$WORKDIR/*" >> "$OUTPUT_LOG" 2>&1 & wait_for_finish "$!" printf "\rCreate runtime archive... ✓\n" From 7541d2cf759c055cb33b09551d5758b0d4f56692 Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 23:26:14 +0000 Subject: [PATCH 8/11] Version 2 is so much better than Version 1, i'm removing v1, v2 is even smaller! --- diff --git a/README_v1.txt b/README_v1.txt deleted file mode 100644 index db89d75..0000000 --- a/README_v1.txt +++ /dev/null @@ -1,57 +0,0 @@ - _____ _ _ ___ ______ __ __ ______ -/ ____| | | | | |__ \ | ____| \ \ / / | ____| -| (___ | |__| | ) | | |__ \ V / | |__ -\___ \ | __ | / / | __| > < | __| -____) | | | | | / /_ | |____ / . \ | |____ -|_____/ |_| |_| |____| |______| /_/ \_\ |______| v1 -================================================================================ -WHAT IS IT? -------------- -sh2exe is a script that turns POSIX Shell scripts into Windows executables, -therefore allowing you to distribute a Shell Script on Windows without needing -a full Git for Bash or Cygwin environment installed somewhere. - -It currently bundles: -- GNU Coreutils -- GNU Less -- GNU Awk -- GNU Grep -- GNU Nano -- Portable OpenBSD Kornshell -This should give you a roughly complete POSIX Shell experience. - -Currently, the executable comes out at around 6MB, which is pretty small on -modern storage devices! - -USE CASES -------------- -This script can help you, if you need to distribute a script (say, to launch -a game your making *cough*) without needing to make a script *solely* for -Windows. Just turn it into an executable, and presto! You got a script that -runs! - -REQUIREMENTS -------------- -You must run this script in an MSYS2 environment. I might add cygwin support -eventually, but for now, MSYS2 only. However, once the executable has been -generated, you will *not* need MSYS2 installed to run it. - -USAGE -------------- -Simply run sh2exe.sh with the path to the script you want to convert. -Example: ./sh2exe.sh /path/to/script.sh - -You can run it on the included helloworld.sh script to see it in action! - -For more info, run ./sh2exe.sh help - -COPYRIGHT -------------- -The sh2exe.sh script itself is licensed under Apache 2.0, however the source -code template (runsh.c) is licensed under the GNU All-Permissive License, -meaning you can do whatever you want with the generated executable. - -SUPPORT ME -------------- -If you like this program, consider giving some dollary doos at -https://liberapay.com/Charadon diff --git a/sh2exe.sh b/sh2exe.sh index d52a9e8..626829e 100644 --- a/sh2exe.sh +++ b/sh2exe.sh @@ -42,6 +42,11 @@ show_license() { } clean() { + set -u + set +e + rm -rvf "$WORKDIR" + rm -fv "7zr.exe" + rm -fv output.log return 0 } @@ -50,7 +55,7 @@ then help_screen exit 1 fi - +CLEAN="false" while getopts ":s:w:chl" opt; do case "${opt}" in @@ -76,7 +81,7 @@ do exit 0 ;; c) - clean + CLEAN="true" exit 0 ;; l) @@ -90,6 +95,11 @@ do esac done +if [ "$CLEAN" = "true" ]; +then + clean +fi + if [ -z "$SCRIPT" ]; then help_screen diff --git a/sh2exe_v1.sh b/sh2exe_v1.sh deleted file mode 100644 index 3e6cdf0..0000000 --- a/sh2exe_v1.sh +++ /dev/null @@ -1,358 +0,0 @@ -#!/bin/sh -# Copyright 2023 Charadon -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This script is slower, but saves a lot more space compared to the v2. -# And since it uses oksh instead of bash, it's immune to bashisms. - -if [ ! "$MSYSTEM" = "MSYS" ]; -then - echo "You must run MSYS2 with the MSYS runtime." - exit 1 -fi - -help_screen() { - echo "Usage: $0 [verb/file]" - echo "Turns a POSIX shell script into a Windows Executable." - printf "\n" - echo "Valid Verbs:" - printf "help Displays this screen.\n" - printf "clean Cleans the workspace.\n" - printf " Tells script which script to turn into executable.\n\n" - echo "Exit status:" - echo " 0 = Success." - echo " 1 = Script failed before build part started." - echo " 2 = Checksum mismatch of downloaded files." - echo " 5 = Failed to change directory at some point in the script." - printf "\n" - echo "For more information visit sh2exe's website at: https://sh2exe.iotib.net" - echo "or the git repo at: https://pagure.io/DaLazySlackers/sh2exe" - exit "$1" -} - -SEVEN_ZIP="7zr.exe" - -if [ -z "$1" ]; -then - help_screen 1 -elif [ "$1" = "help" ]; -then - help_screen 0 -fi - -set -eu - -WORKDIR="$PWD/work" -rm -rf "$WORKDIR" -mkdir -p "$WORKDIR" -rm output.log > /dev/null 2>&1 || true -STARTING_DIR="$PWD" - -COREUTILS_SHA512SUM="a6ee2c549140b189e8c1b35e119d4289ec27244ec0ed9da0ac55202f365a7e33778b1dc7c4e64d1669599ff81a8297fe4f5adbcc8a3a2f75c919a43cd4b9bdfa *coreutils-9.1.tar.xz" -COREUTILS_VERSION="9.1" -OKSH_SHA512SUM="1b412ebbae58bdb1ccf9b9e0b64bab233cd5e184a02bc67db9b4ba82fce0749b8166dd688c24fd890d22a111d7f6ba859c47e3175f28675fca9c6def8c416a08 *oksh-7.2.tar.gz" -OKSH_VERSION="7.2" -NANO_SHA512SUM="b1eb5c06460b1407e3fc959070d2eaaba29d236ef099654fcbf9ba7cf7b22f64ebc9e6f232d471601c35f0e1c78d8c7aad9269e2afed25c0899572b97d44a95c *nano-7.1.tar.gz" -NANO_VERSION="7.1" -LESS_SHA512SUM="7945b7f88921832ebb1b45fba8cbb449ee0133342796b654a52c146dfff3d84db18724ee84e53349eeea6017a0ebe2d8eb5366210275981dde7bb7190118fa66 *less-608.tar.gz" -LESS_VERSION="608" -GAWK_SHA512SUM="1d2aaf90bd074379e13dce65b53e80d449c383ff1f2862bb294644b2053383c19172d3b68bfd9caad82ccd11bea1baf627994280e845da9fdd0e773a000cfe40 *gawk-5.2.1.tar.gz" -GAWK_VERSION="5.2.1" -GREP_SHA512SUM="69cf162886770c4ff86f869f78d8a7e291480f576a92f2afa87c42290c7d34c4ca5cf52e47d10c8e310eadd605d209a2701dc714b651d122be9eca1e73130409 *grep-3.8.tar.gz" -GREP_VERSION="3.8" - -# Speed up compilation times. -# Doesn't work: https://github.com/msys2/MSYS2-packages/issues/2492 -#CC="ccache gcc" -#export CC -#CXX="ccache g++" -#export CXX -CFLAGS="-Os" -export CFLAGS -CXXFLAGS="-Os" -export CXXFLAGS - - - -if [ "$1" = "clean" ]; -then - echo "Cleaning... " - rm -rvf "$WORKDIR" || true - rm -rvf "coreutils-$COREUTILS_VERSION/" || true - rm -rvf "oksh-$OKSH_VERSION/" || true - rm -rvf "nano-$NANO_VERSION/" || true - rm -rvf "gawk-$GAWK_VERSION/" || true - rm -rvf "grep-$GREP_VERSION/" || true - rm -rvf "less-$LESS_VERSION/" || true - rm -f ./*.tar.?z || true - rm -f ./*.7z || true - rm -f 7zip.h || true - rm -f runtime.h || true - rm -f 7zr.exe || true - rm -f *.stackdump - cd bin2c - make clean - cd .. - exit 0 -else - SHEBANG="$(head -1 "$1")" - if [ ! "$SHEBANG" = "#!/bin/sh" ]; - then - echo "Shebang needs to be #!/bin/sh." - exit 1 - fi - SCRIPT_NAME="$1" -fi - -echo "If your terminal closes, that means MSYS had an update that required a runtime restart." -echo "If the script ends, but there's no checkmark after the task, check the output.log for errors." -printf "Updating system... " -yes | pacman -Syu >> output.log 2>&1 -printf "✓\n" -printf "Installing dependencies... " -yes | pacman -S ncurses-devel gcc texinfo ccache >> output.log 2>&1 -printf "✓\n" - -download_7zip() { - curl "https://7-zip.org/a/7zr.exe" -O -} - -build_coreutils() { - curl "https://ftp.gnu.org/pub/gnu/coreutils/coreutils-$COREUTILS_VERSION.tar.xz" -O - if [ ! "$(sha512sum coreutils-"$COREUTILS_VERSION".tar.xz)" = "$COREUTILS_SHA512SUM" ]; - then - echo "Checksum mismatch for coreutils." - exit 2 - fi - if [ -f "coreutils-$COREUTILS_VERSION/DONE" ]; - then - cd "coreutils-$COREUTILS_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install-exec - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "coreutils-$COREUTILS_VERSION".tar.xz - cd "coreutils-$COREUTILS_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make DESTDIR="$WORKDIR" -j "$(nproc)" install-exec - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_nano() { - curl "https://ftp.gnu.org/gnu/nano/nano-$NANO_VERSION.tar.gz" -O - if [ ! "$(sha512sum nano-$NANO_VERSION.tar.gz)" = "$NANO_SHA512SUM" ]; - then - echo "Checksum mismatch for nano." - exit 2 - fi - if [ -f "nano-$NANO_VERSION/DONE" ]; - then - cd "nano-$NANO_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install-exec - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "nano-$NANO_VERSION.tar.gz" - cd "nano-$NANO_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr --enable-tiny - make -j "$(nproc)" - make DESTDIR="$WORKDIR" -j "$(nproc)" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_oksh() { - curl "https://github.com/ibara/oksh/releases/download/oksh-$OKSH_VERSION/oksh-$OKSH_VERSION.tar.gz" -OL - if [ ! "$(sha512sum oksh-$OKSH_VERSION.tar.gz)" = "$OKSH_SHA512SUM" ]; - then - echo "Checksum mismatch for OKSH." - exit 2 - fi - if [ -f oksh-$OKSH_VERSION/DONE ]; - then - cd "oksh-$OKSH_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "oksh-$OKSH_VERSION.tar.gz" - cd "oksh-$OKSH_VERSION" || exit 5 - make clean || true - ./configure --enable-curses --enable-sh --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_less() { - curl "https://ftp.gnu.org/gnu/less/less-$LESS_VERSION.tar.gz" -O - if [ ! "$(sha512sum less-$LESS_VERSION.tar.gz)" = "$LESS_SHA512SUM" ]; - then - echo "Checksum mismatch for Less" - exit 2 - fi - if [ -f less-$LESS_VERSION/DONE ]; - then - cd "less-$LESS_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "less-$LESS_VERSION.tar.gz" - cd "less-$LESS_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_gawk() { - curl "https://ftp.gnu.org/gnu/gawk/gawk-$GAWK_VERSION.tar.gz" -O - if [ ! "$(sha512sum gawk-$GAWK_VERSION.tar.gz)" = "$GAWK_SHA512SUM" ]; - then - echo "Checksum mismatch for Gawk" - exit 2 - fi - if [ -f gawk-$GAWK_VERSION/DONE ]; - then - cd "gawk-$GAWK_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "gawk-$GAWK_VERSION.tar.gz" - cd "gawk-$GAWK_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_grep() { - curl "https://ftp.gnu.org/gnu/grep/grep-$GREP_VERSION.tar.gz" -O - if [ ! "$(sha512sum grep-$GREP_VERSION.tar.gz)" = "$GREP_SHA512SUM" ]; - then - echo "Checksum mismatch for Grep" - exit 2 - fi - if [ -f grep-$GREP_VERSION/DONE ]; - then - cd "grep-$GREP_VERSION" || exit 5 - make DESTDIR="$WORKDIR" install - cd "$STARTING_DIR" || exit 5 - return 0 - fi - tar -xvf "grep-$GREP_VERSION.tar.gz" - cd "grep-$GREP_VERSION" || exit 5 - make clean || true - ./configure --prefix=/usr - make -j "$(nproc)" - make DESTDIR="$WORKDIR" install - touch DONE - cd "$STARTING_DIR" || exit 5 - return 0 -} - -build_bin2c() { - cd bin2c || exit 5 - make - cd "$STARTING_DIR" || exit 5 -} - -cleanup_work() { - # Remove man pages and headers. - rm -rf "${WORKDIR:?}/usr/share/man" - rm -rf "${WORKDIR:?}/usr/share/info" - rm -rf "${WORKDIR:?}/usr/include" - # Strip binaries - for i in "$WORKDIR/usr/bin"/*.exe; - do - strip --strip-unneeded "$i" - done - # Add DLLs from MSYS so executables can run. - cp "/usr/bin/msys-ncursesw6.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-2.0.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-iconv-2.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-intl-8.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-pcre-1.dll" "$WORKDIR/usr/bin" - cp "/usr/bin/msys-gcc_s-seh-1.dll" "$WORKDIR/usr/bin" - # Strip DLLs to save space. - for i in "$WORKDIR/usr/bin"/*.dll; - do - strip --strip-unneeded "$i" - done - cp "$SCRIPT_NAME" "$WORKDIR/usr/bin" - mkdir -p "$WORKDIR/usr/share/terminfo/63/" - cp "/usr/share/terminfo/63/cygwin" "$WORKDIR/usr/share/terminfo/63/" - # Time to 7zip it up. - ./$SEVEN_ZIP a -mx1 runtime.7z "$WORKDIR/*" -} - -build_runner() { - cp runsh.c "$WORKDIR/$SCRIPT_NAME.c" - bin2c/bin2c.exe "$SEVEN_ZIP" "$WORKDIR/7zip.h" SevenZip - bin2c/bin2c.exe "runtime.7z" "$WORKDIR/runtime.h" RuntimeArchive - sed -i "s|INSERT_SCRIPT_NAME_HERE|$(basename "$SCRIPT_NAME")|g" "$WORKDIR/$SCRIPT_NAME.c" - MSYSTEM="MINGW64" bash -l -c "gcc -I$WORKDIR -Wall -O1 \"$WORKDIR/$(basename $SCRIPT_NAME).c\" -o \"$WORKDIR/$(basename $SCRIPT_NAME).exe\"" -} -printf "Downloading 7-zip... " -download_7zip >> output.log 2>&1 -printf "✓\n" -printf "Compiling and installing GNU Coreutils... " -build_coreutils >> output.log 2>&1 -printf "✓\n" -printf "Installing some of MSYS2's Coreutils to workaround bugs... " -install -Dm755 "/usr/bin/ls" "$WORKDIR/usr/bin/ls" -install -Dm755 "/usr/bin/du" "$WORKDIR/usr/bin/du" -printf "✓\n" -printf "Compiling and installing GNU Awk... " -build_gawk >> output.log 2>&1 -printf "✓\n" -# Compiling grep and installing it results in segfault. We'll use MSYS2's for now. -printf "Installing GNU Grep... " -install -Dm755 "/usr/bin/grep" "$WORKDIR/usr/bin/grep" -printf "✓\n" -printf "Compiling and installing GNU Nano Text Editor... " -build_nano >> output.log 2>&1 -printf "✓\n" -printf "Compiling and installing GNU Less... " -build_less >> output.log 2>&1 -printf "✓\n" -printf "Compiling and installing Portable OpenBSD ksh... " -build_oksh >> output.log 2>&1 -printf "✓\n" -printf "Compiling bin2c... " -build_bin2c >> output.log 2>&1 -printf "✓\n" -printf "Creating runtime archive... " -cleanup_work >> output.log 2>&1 -printf "✓\n" -printf "Compiling executable... " -build_runner >> output.log 2>&1 -printf "✓\n" -echo "If all went well, your new executable should be in $WORKDIR/$(basename $SCRIPT_NAME).exe" -exit 0 From 8b33400db7ae291c1238d5512bc7c54412b2d2ca Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 23:29:26 +0000 Subject: [PATCH 9/11] Updated README --- diff --git a/README.txt b/README.txt index 9be1925..cf6332e 100644 --- a/README.txt +++ b/README.txt @@ -33,18 +33,23 @@ runs! REQUIREMENTS ------------- -You must run this script in an MSYS2 environment. I might add cygwin support -eventually, but for now, MSYS2 only. However, once the executable has been -generated, you will *not* need MSYS2 installed to run it. +You must run this script in an MSYS2 environment. However, once the executable +has been generated, you will *not* need MSYS2 installed to run it. USAGE ------------- Simply run sh2exe.sh with the path to the script you want to convert. -Example: ./sh2exe.sh /path/to/script.sh +Example: ./sh2exe.sh -s /path/to/script.sh -w /path/to/workdir You can run it on the included helloworld.sh script to see it in action! -For more info, run ./sh2exe.sh help +Which shell is used in the runtime depends on the shebang of the script. Here's +a table: + +#!/bin/sh = MirBSD Korn Shell used. +#!/bin/bash = GNU Bash used. + +For more info, run ./sh2exe.sh -h COPYRIGHT ------------- From 79ce1de486e153da0e24a9f6e6cb7193aeb32cd4 Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 23:32:23 +0000 Subject: [PATCH 10/11] Added git and website info in script. --- diff --git a/sh2exe.sh b/sh2exe.sh index 626829e..0f86d2a 100644 --- a/sh2exe.sh +++ b/sh2exe.sh @@ -19,6 +19,9 @@ help_screen() { echo "0 = Success." echo "1 = Initialization failure. (Before runtime was being built.)" echo "5 = Failed to change directory while runtime was building." + printf "\n" + echo "Website : sh2exe.iotib.net" + echo "Git : https://pagure.io/dalazyslackers/sh2exe" return 0 } From 4c2eaf2922b00bc7ec4510f7500331f865b8913b Mon Sep 17 00:00:00 2001 From: Charadon Date: Jan 05 2023 23:33:20 +0000 Subject: [PATCH 11/11] Clean bin2c if clean switch is used. --- diff --git a/sh2exe.sh b/sh2exe.sh index 0f86d2a..0a25f04 100644 --- a/sh2exe.sh +++ b/sh2exe.sh @@ -50,6 +50,7 @@ clean() { rm -rvf "$WORKDIR" rm -fv "7zr.exe" rm -fv output.log + make -C bin2c clean return 0 }