How to make my script for building Analog Clock in AEC as portable as possible?
Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
How to make my script for building Analog Clock in AEC as portable as possible?
I've tried to write a as-portable-as-possible script for downloading the source code and building the Analog Clock in AEC.
For AEC-to-x86:
Code:
mkdir ArithmeticExpressionCompiler
cd ArithmeticExpressionCompiler
if [ $(command -v wget > /dev/null 2>&1 ; echo $?) -eq 0 ] # Check if "wget" exists, see those StackOverflow answers for more details:
# https://stackoverflow.com/a/75103891/8902065
# https://stackoverflow.com/a/75103209/8902065
then
wget https://flatassembler.github.io/Duktape.zip
else
curl -o Duktape.zip https://flatassembler.github.io/Duktape.zip
fi
unzip Duktape.zip
if [ $(command -v gcc > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
gcc -o aec aec.c duktape.c -lm # The linker that comes with recent versions of Debian Linux insists that "-lm" is put AFTER the source files, or else it outputs some confusing error message.
else
clang -o aec aec.c duktape.c -lm
fi
./aec analogClock.aec
if [ $(command -v gcc > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
gcc -o analogClock analogClock.s -m32
else
clang -o analogClock analogClock.s -m32
fi
./analogClock
For AEC-to-WebAssembly:
Code:
if [ $(command -v git > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
git clone https://github.com/FlatAssembler/AECforWebAssembly.git
cd AECforWebAssembly
elif [ $(command -v wget > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
mkdir AECforWebAssembly
cd AECforWebAssembly
wget https://github.com/FlatAssembler/AECforWebAssembly/archive/refs/heads/master.zip
unzip master.zip
cd AECforWebAssembly-master
else
mkdir AECforWebAssembly
cd AECforWebAssembly
curl -o AECforWebAssembly.zip -L https://github.com/FlatAssembler/AECforWebAssembly/archive/refs/heads/master.zip # Without the "-L", "curl" will store HTTP Response headers of redirects to the ZIP file instead of the actual ZIP file.
unzip AECforWebAssembly.zip
cd AECforWebAssembly-master
fi
if [ $(command -v g++ > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
g++ -std=c++11 -o aec AECforWebAssembly.cpp # "-std=c++11" should not be necessary for newer versions of "g++". Let me know if it is, as that probably means I disobeyed some new C++ standard (say, C++23).
else
clang++ -o aec AECforWebAssembly.cpp
fi
cd analogClock
../aec analogClock.aec
npx -p wabt wat2wasm analogClock.wat
node analogClock
Is there anybody knowledgeable about various operating systems here to know how to make the scripts better?
I barely managed to get the NodeJS version check to work on Git Bash on Windows. Before NodeJS outputted the error message "stdout is not a tty" instead of outputting the version number. Here is what the shell script to use the AEC-to-WebAssembly compiler looks like now:
Code:
if [ $(command -v git > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
git clone https://github.com/FlatAssembler/AECforWebAssembly.git
cd AECforWebAssembly
elif [ $(command -v wget > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
mkdir AECforWebAssembly
cd AECforWebAssembly
wget https://github.com/FlatAssembler/AECforWebAssembly/archive/refs/heads/master.zip
unzip master.zip
cd AECforWebAssembly-master
else
mkdir AECforWebAssembly
cd AECforWebAssembly
curl -o AECforWebAssembly.zip -L https://github.com/FlatAssembler/AECforWebAssembly/archive/refs/heads/master.zip # Without the "-L", "curl" will store HTTP Response headers of redirects to the ZIP file instead of the actual ZIP file.
unzip AECforWebAssembly.zip
cd AECforWebAssembly-master
fi
if [ $(command -v g++ > /dev/null 2>&1 ; echo $?) -eq 0 ]
then
g++ -std=c++11 -o aec AECforWebAssembly.cpp # "-std=c++11" should not be necessary for newer versions of "g++". Let me know if it is, as that probably means I disobeyed some new C++ standard (say, C++23).
else
clang++ -o aec AECforWebAssembly.cpp
fi
cd analogClock
../aec analogClock.aec
npx -p wabt wat2wasm analogClock.wat
if [ "$OS" = "Windows_NT" ] # https://stackoverflow.com/a/75125384/8902065
# https://www.reddit.com/r/bash/comments/10cip05/comment/j4h9f0x/?utm_source=share&utm_medium=web2x&context=3
then
node_version=$(node.exe -v)
else # We are presumably running on an UNIX-like system, where storing output of some program into a variable works as expected.
node_version=$(node -v)
fi
# "node -v" outputs version in the format "v18.12.1"
node_version=${node_version:1} # Remove 'v' at the beginning
node_version=${node_version%\.*} # Remove trailing ".*".
node_version=${node_version%\.*} # Remove trailing ".*".
node_version=$(($node_version)) # Convert the NodeJS version number from a string to an integer.
if [ $node_version -lt 11 ]
then
echo "NodeJS version is lower than 11 (it is $node_version), you will probably run into trouble!"
fi
node analogClock
I have modified the shell script to compile Analog Clock for x86, so that it might be able to run on Windows. Here is what it looks like now:
Code:
mkdir ArithmeticExpressionCompiler
cd ArithmeticExpressionCompiler
if [ $(command -v wget > /dev/null 2>&1 ; echo $?) -eq 0 ] # Check if "wget" exists, see those StackOverflow answers for more details:
# https://stackoverflow.com/a/75103891/8902065
# https://stackoverflow.com/a/75103209/8902065
then
wget https://flatassembler.github.io/Duktape.zip
else
curl -o Duktape.zip https://flatassembler.github.io/Duktape.zip
fi
unzip Duktape.zip
if [ $(command -v clang > /dev/null 2>&1 ; echo $?) -eq 0 ] # We prefer "clang" to "gcc" because... what if somebody tries to run this in CygWin terminal? GCC will not work then, CLANG might.
then
c_compiler="clang"
else
c_compiler="gcc"
fi
$c_compiler -o aec aec.c duktape.c -lm # The linker that comes with recent versions of Debian Linux insists that "-lm" is put AFTER the source files, or else it outputs some confusing error message.
if [ "$OS" = "Windows_NT" ]
then
./aec analogClockForWindows.aec
$c_compiler -o analogClockForWindows analogClockForWindows.s -m32
./analogClockForWindows
else
./aec analogClock.aec
$c_compiler -o analogClock analogClock.s -m32
./analogClock
fi
Well, I guess the shell scripts are good enough to be added to READMEs
Code:
# instead of
if [ $(command -v clang > /dev/null 2>&1 ; echo $?) -eq 0 ]
# use
if command -v clang >/dev/null 2>&1;
# or
if which clang >/dev/null 2>&1;
Writing shell scripts has left a very bad impression on me. I have written two short scripts, and I have had to ask no less than three StackOverflow questions (Fortunately, none of them reduced my reputation, and one of them received two upvotes.). One would think that checking whether a program with some name is available is one of the most common things one would like to do in a shell script. Nonetheless, doing that is very complicated. And two times in two short scripts, I had to rely on truly mysterious fixes. I've written a rant about it on my blog:
Quote:
Originally Posted by https://flatassembler.github.io/informatics
Oh, and understand that you will sometimes have to apply fixes which you have no idea how they work. You will get a lot further by being empirical than by being a rationalist and only relying on things you understand. This is especially true when writing shell scripts, although it's also somewhat true in other types of programming. When writing a shell script to download, compile and run Analog Clock in AEC for x86, I ran into a problem that, on recent versions of Debian Linux, the linker insists that "-lm", the option for linking in the math library, is put after the source files, and it outputs some confusing error message if it's put before the source files. A rationalist solution would be to try to implement the math functions that Duktape invokes yourself, like I've implemented them in my programming language when writing Analog Clock for WebAssembly. Instead, I did a bit of Googling, and found a way nicer solution: put "-lm" after the source files, and not before them. I do not understand how it works, but I can empirically say it does work. You can read the zero9178's explanation for that if you are interested, I do not fully understand it either, and I probably know more about compiler theory than most programmers. And when writing a shell script to download, compile and run Analog Clock in AEC for WebAssembly, I realized that the code my AEC-to-WebAssembly compiler outputs works only on NodeJS 11 and newer, because it relies on WebAssembly global variables. So, I decided to warn the user if they have installed NodeJS that's older than NodeJS 11. So, I wrote "node_version=$(node -v)" to store the NodeJS version string into a variable called "node_version", so that I can extract the first number from it and act accordingly. That worked on Linux, but on Windows NodeJS outputted the error message "stdout is not a tty" instead of outputting the version string. I can't think of a rationalist work-around. But I was empirical, so I posted a question on StackOverflow, and I got the answer: on Windows, do "node_version=$(node.exe -v)". I almost did not try it, as it seemed so ridiculous. However, I was empirical enough that I tried it, and it somehow magically worked. I still have no idea how it works. It has something to do with the difference between how terminals work on Linux and how they work on Windows, but I don't understand the details. And like I've said, the fact that you sometimes stumble upon problems with truly mysterious fixes is true not only in shell scripting, but also in other types of programming, such as CSS. Look up the Internet Explorer 6 double-margin bug. Or how, when programming my PicoBlaze Simulator, I ran into a problem that the tooltips I made worked in Firefox but not in Chrome. In both cases, the fix seems so ridiculous that it's not even worth trying. For the Internet Explorer 6 double-margin bug, it was a mysterious bug in Internet Explorer 6. For the Chrome issue I've run into, the people on StackOverflow insist that Chrome is actually obeying the standard, while Firefox isn't. If so, the standard goes wildly against common sense here. Programming is an empirical thing, but universities pretend it's a rationalist thing.
Writing shell scripts has left a very bad impression on me. I have written two short scripts, and I have had to ask no less than three StackOverflow questions (Fortunately, none of them reduced my reputation, and one of them received two upvotes.). One would think that checking whether a program with some name is available is one of the most common things one would like to do in a shell script. Nonetheless, doing that is very complicated. And two times in two short scripts, I had to rely on truly mysterious fixes. I've written a rant about it on my blog:
Shell is an interesting language, you may say it is a bit strange (or odd). And actually you cannot guess the correct syntax, that is almost impossible. So you need to learn all the features you want to use. As usual, without knowing it (or anything else) you will find it difficult and mysterious or complicated. But a lot of people use it, so actually it is definitely usable (and not that terrible).
Linux ( a work-a-like of Unix) and Windows were built by different organisations at different times and are different OSes, so there's no reason why they would have exactly the same setup/cmds, otherwise they'd be the same ..
Unix was create by Bell Labs research group within AT&T in 1970 (the Unix epoch).
Windows (in fact the DOS cli precursor) dates from 1980 and was created by Microsoft.
The Unix convention is that executable binary files (programs) do not have a file extension, hence ls, cp, mv, node (!) etc.
The MSWin (& ofc DOS) convention is that executable binary files (programs) do have a file extension; specifically '.exe' .
Linux ( a work-a-like of Unix) and Windows were built by different organisations at different times and are different OSes, so there's no reason why they would have exactly the same setup/cmds, otherwise they'd be the same ..
Unix was create by Bell Labs research group within AT&T in 1970 (the Unix epoch).
Windows (in fact the DOS cli precursor) dates from 1980 and was created by Microsoft.
The Unix convention is that executable binary files (programs) do not have a file extension, hence ls, cp, mv, node (!) etc.
The MSWin (& ofc DOS) convention is that executable binary files (programs) do have a file extension; specifically '.exe' .
HTH
As far as I understand it, on Windows, "node" and "node.exe" are supposed to do exactly the same thing. But in Git Bash, they don't do the same. "node_version=$(node -v)" outputs "stdout is not a tty", whereas "node_version=$(node.exe -v)" actually works.
As far as I understand it, on Windows, "node" and "node.exe" are supposed to do exactly the same thing. But in Git Bash, they don't do the same. "node_version=$(node -v)" outputs "stdout is not a tty", whereas "node_version=$(node.exe -v)" actually works.
you need to understand (a lot of things). At first, stdout is not a tty is an error message, the execution of the command (node -v) was not successful (therefore that is not the version).
Next, in linux (and mostly on windows too) we have two output channels, stdout and stderr, the error message you got was sent to stderr, not stdout, but the real version number (when the execution is successful) will be sent to stdout. Both stdout and stderr are displayed on the same terminal, so sometimes you cannot distinguish them.
Additionally the command node can check if it was executed in a terminal (=interactive mode) and in your case node reported that it could not find the terminal. So both node and node.exe supposed to do exactly the same thing, but actually the environment is definitely different and therefore that may cause strange effects.
The correct statement: node and node.exe will do exactly the same thing if they can work (but in your case the command node could not even be started).
you need to understand (a lot of things). At first, stdout is not a tty is an error message, the execution of the command (node -v) was not successful (therefore that is not the version).
Next, in linux (and mostly on windows too) we have two output channels, stdout and stderr, the error message you got was sent to stderr, not stdout, but the real version number (when the execution is successful) will be sent to stdout. Both stdout and stderr are displayed on the same terminal, so sometimes you cannot distinguish them.
Additionally the command node can check if it was executed in a terminal (=interactive mode) and in your case node reported that it could not find the terminal. So both node and node.exe supposed to do exactly the same thing, but actually the environment is definitely different and therefore that may cause strange effects.
The correct statement: node and node.exe will do exactly the same thing if they can work (but in your case the command node could not even be started).
As far as I understand it, executing "node.exe" instead of "node" should only change the argv[0] inside NodeJS, and nothing else. It's mysterious why it would output "stdout is not a tty" error message instead of version number depending on what's inside argv[0], right?
As far as I understand it, executing "node.exe" instead of "node" should only change the argv[0] inside NodeJS, and nothing else. It's mysterious why it would output "stdout is not a tty" error message instead of version number depending on what's inside argv[0], right?
no
node is executed on linux and node.exe is executed on windows. So all the OS and environment were changed.
As I tried to explain node could not even start, because it did not find a working terminal, therefore it just reported that. Obviously, if it had started properly, it should have responded with the same version number instead of an error message.
# instead of
if [ $(command -v clang > /dev/null 2>&1 ; echo $?) -eq 0 ]
# use
if command -v clang >/dev/null 2>&1;
# or
if which clang >/dev/null 2>&1;
no
node is executed on linux and node.exe is executed on windows. So all the OS and environment were changed.
As I tried to explain node could not even start, because it did not find a working terminal, therefore it just reported that. Obviously, if it had started properly, it should have responded with the same version number instead of an error message.
You do realize that, on Windows, you can type either "NOTEPAD" or "NOTEPAD.EXE", and, in both cases, Notepad will be started?
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.