Author Topic: Changes To Auto Install/Run QB64 on Raspberry PI ARM Processors  (Read 2772 times)

0 Members and 1 Guest are viewing this topic.

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Changes To Auto Install/Run QB64 on Raspberry PI ARM Processors
« on: February 03, 2022, 06:56:17 pm »
I've have updates ready to QB64 that will automatically install it on a Raspberry PI and works properly, including DATA statements.

With Apple's new computers running the M1 ARM processor, and Intel (announced in June of 2021), along with AMD and Microsoft working together (announced in October of 2021) to develop ARM processors, QB64 needs to be able to run on these chips as well.

I have tested my changes, but I would like some others to check it out as well before I push the change on Gitub.

In my tests, I have even run compiled QB64 programs that use MariaDB and Zenity on the PI without issues. Pipecom runs without issues as well as $DEBUG. However, my testing has only been done on the 32bit Raspian OS. I do plan to test it with other Linux systems that run on the PI.

There were a number of changes needed, which most are automated in the setup_lnx.sh script. The other change was made directly to common.h.

The two files that changed are below, but here is what I needed to change.

common.h
Two of the issues I ran into had to do with mis-aligned addresses (int32 and int16 for example). To correct this, I either needed to add "-fsanitize=address" to the gcc statement, or add code to the common.h file for ARM processors. I was given the code by a C++ programmer who explained that, while not an issue with x86_64 or i386 processors, it is an issue with ARM processors. The code (see below) corrects this issue. She also gave me the corresponding code for the x86_64/i386, just in case. I've regression tested this on my x86_64 system, but others should also run it as well.

setup_lnx.sh
The setup script has a number of issues on ARM processors. The first is it doesn't download the libraries needed, and the other it created invalid link modules. To correct the first issue, the setup script now checks whether or not the processor is an ARM. If so, it sets DISTRO to "raspbian". The issue about the link/binary executables has to do with how the ARM processes bits. ARM processors are little endian (See note below). So the script replaces both the makedat_lnx32.txt and makedat_lnx64.txt files with the correct parameters for the OBJCOPY. ("-Oelf32-littlearm -Barm" replaced the original "-Oelf32-i386 -Bi386" in the 32bit file and the "-Oelf64-littlearm -Barm" replaced the "-Oelf64-x86-64 -Bi386:x86-64" in the 64bit file)

NOTE: Yes, Intel, AMD and the PI ARM chips are all little endian. However, from what I've read, the Intel and AMD chips convert the little endian to big endian. It has something to do with floating point. However, this does not seem to be the case with ARM processors, at least for the PI. From what I read, the Apple M1 is designed the same as that the PI's ARM. This change to the OBJCOPY allows DATA statements, among other things, to work. the -Barm tells OBJCOPY how to format the binary executable file. This is my understanding, which is of course, subject to interpretation, but the changes makes QB64 run and compile, and compiled programs also run on the PI.

To implement these changes, after extracting the QB64 compiler, you need to replace the common.h file in the qb64/internal/c directory, and the setup_lnx.sh file in the main qb64 directory. Then all you have to do is run the setup_lnx.sh file to install library dependencies and compile qb64.bas.

These changes should also work on the Apple M1 ARM processor, but I do not have one to test this on. If someone has a M1 ARM processor, I can provide the changes to the setup_osx.command script. You'll have to do the testing as I will not have a M1 processor until July.

Also, besides the M1 processor, I haven't been able to test is a 64bit OS on the Raspberry PI. Raspberry no longer offers the 64bit version of their Raspbian OS. So while I am looking for non-raspbian OS's to test on, if someone here is running, say Kali on a PI or an earlier version of the 64bit Raspbian OS, please test this. I will do so as well, but the more who tests this, the better. (This was suggested by Fellippe).

Some Issues:
When testing this on my PI, I was unable to get InForm to run. It compiles, but I get a series of errors from "Bus signal errors" to misaligned addresses. I am still looking into this, but I may need to defer to Fellippe or Luke on this, as I am not a C++ programmer, and in my C coding, I've never encountered these errors. I have run tests in gdb and ddd utilites to try and isolate the issue, but I am at a loss. If someone wants to tackle this on their PI, I'd appreciate it.

Here is the common.h file:
Code: C: [Select]
  1. //Setup for ARM Processor (Similar to -fsanitize=address GCC compiler flag)
  2. #ifdef __arm__
  3.         #define POST_PACKED_STRUCTURE
  4. #else
  5.         #define POST_PACKED_STRUCTURE __attribute__((__packed__))
  6. #endif /* ARM */
  7.  
  8. //Fill out dependency macros
  9. #ifndef DEPENDENCY_NO_SOCKETS
  10.     #define DEPENDENCY_SOCKETS
  11. #endif
  12.  
  13. #ifndef DEPENDENCY_NO_PRINTER
  14.     #define DEPENDENCY_PRINTER
  15. #endif
  16.  
  17. #ifndef DEPENDENCY_NO_ICON
  18.     #define DEPENDENCY_ICON
  19. #endif
  20.  
  21. #ifndef DEPENDENCY_NO_SCREENIMAGE
  22.     #define DEPENDENCY_SCREENIMAGE
  23. #endif
  24.  
  25. #ifndef INC_COMMON_CPP
  26.     #define INC_COMMON_CPP
  27.     #include "os.h"
  28.    
  29.     #define QB64_GL1
  30.     #define QB64_GLUT
  31.    
  32.     #ifdef DEPENDENCY_CONSOLE_ONLY
  33.         #undef QB64_GLUT
  34.         #else
  35.         #define QB64_GUI
  36.     #endif
  37.    
  38.     //core
  39.     #ifdef QB64_GUI
  40.         #ifdef QB64_GLUT
  41.             //This file only contains header stuff
  42.             #include "parts/core/src.c"
  43.         #endif
  44.     #endif
  45.    
  46.     #ifdef QB64_WINDOWS
  47.        
  48.         #ifndef QB64_GUI
  49.             #undef int64 //definition of int64 from os.h conflicts with a definition within windows.h, temporarily undefine then redefine
  50.             #include <windows.h>
  51.             #define int64 __int64
  52.         #endif
  53.        
  54.         #include <shfolder.h>
  55.        
  56.         #include <float.h>
  57.         #include <winbase.h>
  58.        
  59.     #endif
  60.    
  61.     //common includes
  62.     #include <stdio.h>
  63.     #ifdef QB64_MACOSX
  64.         #include <cmath>
  65.         #else
  66.         //#include <math.h> //<-causes overloading abs conflicts in Windows
  67.         #include <cmath>
  68.     #endif
  69.     #include <time.h>
  70.     #include <iostream>
  71.     #include <fstream>
  72.     #include <time.h>
  73.     #include <string.h>
  74.     #include <errno.h>
  75.     #include <fcntl.h>
  76.    
  77.     //OS/compiler specific includes
  78.     #ifdef QB64_WINDOWS
  79.         #include <direct.h>
  80.         #ifdef DEPENDENCY_PRINTER
  81.             #include <winspool.h>
  82.         #endif
  83.         #include <csignal>
  84.         #include <process.h> //required for multi-threading
  85.         #if defined DEPENDENCY_AUDIO_OUT || defined QB64_GUI
  86.             #include <mmsystem.h>
  87.         #endif
  88.        
  89.         #else
  90.        
  91.         #include <stdlib.h>
  92.         #include <sys/types.h>
  93.         #include <sys/stat.h>
  94.         #include <sys/wait.h>
  95.         #include <unistd.h>
  96.         #include <stdint.h>
  97.         #include <pthread.h>
  98.         #ifndef QB64_MACOSX
  99.             #include <dlfcn.h>
  100.         #endif
  101.        
  102.     #endif
  103.    
  104.     #ifdef QB64_GUI
  105.         #ifdef QB64_GLUT
  106.             #include "parts/core/gl_headers/opengl_org_registery/glext.h"
  107.         #endif
  108.     #endif
  109.    
  110.    
  111.     //QB64 string descriptor structure
  112.     struct qbs_field{
  113.         int32 fileno;
  114.         int64 fileid;
  115.         int64 size;
  116.         int64 offset;
  117.     };
  118.    
  119.     struct qbs{
  120.         uint8 *chr;//a 32 bit pointer to the string's data
  121.         int32 len;//must be signed for comparisons against signed int32s
  122.         uint8 in_cmem;//set to 1 if in the conventional memory DBLOCK
  123.         uint16 *cmem_descriptor;
  124.         uint16 cmem_descriptor_offset;
  125.         uint32 listi;//the index in the list of strings that references it
  126.         uint8 tmp;//set to 1 if the string can be deleted immediately after being processed
  127.         uint32 tmplisti;//the index in the list of strings that references it
  128.         uint8 fixed;//fixed length string
  129.         uint8 readonly;//set to 1 if string is read only
  130.         qbs_field *field;
  131.     };
  132.    
  133.     struct img_struct{
  134.         void *lock_offset;
  135.         int64 lock_id;
  136.         uint8 valid;//0,1 0=invalid
  137.         uint8 text;//if set, surface is a text surface
  138.         uint8 console;//dummy surface to absorb unimplemented console functionality
  139.         uint16 width,height;
  140.         uint8 bytes_per_pixel;//1,2,4
  141.         uint8 bits_per_pixel;//1,2,4,8,16(text),32
  142.         uint32 mask;//1,3,0xF,0xFF,0xFFFF,0xFFFFFFFF
  143.         uint16 compatible_mode;//0,1,2,7,8,9,10,11,12,13,32,256
  144.         uint32 color,background_color,draw_color;
  145.         uint32 font;//8,14,16,?
  146.         int16 top_row,bottom_row;//VIEW PRINT settings, unique (as in QB) to each "page"
  147.         int16 cursor_x,cursor_y;//unique (as in QB) to each "page"
  148.         uint8 cursor_show, cursor_firstvalue, cursor_lastvalue;
  149.         union{
  150.             uint8 *offset;
  151.             uint32 *offset32;
  152.         };
  153.         uint32 flags;
  154.         uint32 *pal;
  155.         int32 transparent_color;//-1 means no color is transparent
  156.         uint8 alpha_disabled;
  157.         uint8 holding_cursor;
  158.         uint8 print_mode;
  159.         //BEGIN apm ('active page migration')
  160.         //everything between apm points is migrated during active page changes
  161.         //note: apm data is only relevent to graphics modes
  162.         uint8 apm_p1;
  163.         int32 view_x1,view_y1,view_x2,view_y2;
  164.         int32 view_offset_x,view_offset_y;
  165.         float x,y;
  166.         uint8 clipping_or_scaling;
  167.         float scaling_x,scaling_y,scaling_offset_x,scaling_offset_y;
  168.         float window_x1,window_y1,window_x2,window_y2;
  169.         double draw_ta;
  170.         double draw_scale;
  171.         uint8 apm_p2;
  172.         //END apm
  173.     };
  174.     //img_struct flags
  175.     #define IMG_FREEPAL 1 //free palette data before freeing image
  176.     #define IMG_SCREEN 2 //img is linked to other screen pages
  177.     #define IMG_FREEMEM 4 //if set, it means memory must be freed
  178.    
  179.    
  180.     //QB64 internal variable type flags (internally referenced by some C functions)
  181.     #define ISSTRING 1073741824
  182.     #define ISFLOAT 536870912
  183.     #define ISUNSIGNED 268435456
  184.     #define ISPOINTER 134217728
  185.     #define ISFIXEDLENGTH 67108864 //only set for strings with pointer flag
  186.     #define ISINCONVENTIONALMEMORY 33554432
  187.     #define ISOFFSETINBITS 16777216
  188.    
  189.     struct ontimer_struct{
  190.         uint8 allocated;
  191.         uint32 id;//the event ID to trigger (0=no event)
  192.         int64 pass;//the value to pass to the triggered event (only applicable to ON ... CALL ...(x)
  193.         uint8 active;//0=OFF, 1=ON, 2=STOP
  194.         uint8 state;//0=untriggered,1=triggered
  195.         double seconds;//how many seconds between events
  196.         double last_time;//the last time this event was triggered
  197.     };
  198.    
  199.     struct onkey_struct{
  200.         uint32 id;//the event ID to trigger (0=no event)
  201.         int64 pass;//the value to pass to the triggered event (only applicable to ON ... CALL ...(x)
  202.         uint8 active;//0=OFF, 1=ON, 2=STOP
  203.         uint8 state;//0=untriggered,1=triggered,2=in progress(TIMER only),2+=multiple events queued(KEY only)
  204.         uint32 keycode;//32-bit code, same as what _KEYHIT returns
  205.         uint32 keycode_alternate;//an alternate keycode which may also trigger event
  206.         uint8 key_scancode;
  207.         uint8 key_flags;
  208.         //flags:
  209.         //0 No keyboard flag, 1-3 Either Shift key, 4 Ctrl key, 8 Alt key,32 NumLock key,64 Caps Lock key, 128 Extended keys on a 101-key keyboard
  210.         //To specify multiple shift states, add the values together. For example, a value of 12 specifies that the user-defined key is used in combination with the Ctrl and Alt keys.
  211.         qbs *text;
  212.     };
  213.    
  214.     struct onstrig_struct{
  215.         uint32 id;//the event ID to trigger (0=no event)
  216.         int64 pass;//the value to pass to the triggered event (only applicable to ON ... CALL ...(x)
  217.         uint8 active;//0=OFF, 1=ON, 2=STOP
  218.         uint8 state;//0=untriggered,1=triggered,2=in progress(TIMER only),2+=multiple events queued(KEY only)
  219.     };
  220.    
  221.     struct byte_element_struct
  222.     {
  223.         uint64 offset;
  224.         int32 length;
  225.     };
  226.    
  227.     struct device_struct{
  228.         int32 used;
  229.         int32 type;
  230.         //0=Unallocated
  231.         //1=Joystick/Gamepad
  232.         //2=Keybaord
  233.         //3=Mouse  
  234.         char *name;
  235.         int32 connected;
  236.         int32 lastbutton;
  237.         int32 lastaxis;
  238.         int32 lastwheel;
  239.         //--------------
  240.         int32 max_events;
  241.         int32 queued_events;
  242.         uint8 *events;//the structure and size of the events depends greatly on the device and its capabilities
  243.         int32 event_size;
  244.         //--------------
  245.         uint8 STRIG_button_pressed[256];//checked and cleared by the STRIG function
  246.         //--------------
  247.         void *handle_pointer;//handle as pointer
  248.         int64 handle_int;//handle as integer
  249.         char *description;//description provided by manufacturer
  250.         int64 product_id;
  251.         int64 vendor_id;
  252.         int32 buttons;
  253.         int32 axes;
  254.         int32 balls;
  255.         int32 hats;
  256.     };
  257.    
  258.     //device_struct constants
  259.     #define QUEUED_EVENTS_LIMIT 1024
  260.     #define DEVICETYPE_CONTROLLER 1
  261.     #define DEVICETYPE_KEYBOARD 2
  262.     #define DEVICETYPE_MOUSE 3
  263.    
  264.     struct mem_block{
  265.         ptrszint offset;
  266.         ptrszint size;
  267.         int64 lock_id;//64-bit key, must be present at lock's offset or memory region is invalid
  268.         ptrszint lock_offset;//pointer to lock
  269.         ptrszint type;
  270.         /*
  271.             memorytype (4 bytes, but only the first used, for flags):
  272.             1 integer values
  273.             2 unsigned (set in conjunction with integer)
  274.             4 floating point values
  275.             8 char string(s) 'element-size is the memory size of 1 string
  276.         */
  277.         ptrszint elementsize;
  278.         int32 image;
  279.         int32 sound;
  280.     };
  281.     struct mem_lock{
  282.         uint64 id;
  283.         int32 type;//required to know what action to take (if any) when a request is made to free the block
  284.         //0=no security (eg. user defined block from _OFFSET)
  285.         //1=C-malloc'ed block
  286.         //2=image
  287.         //3=sub/function scope block
  288.         //4=array
  289.         //5=sound
  290.         //---- type specific variables follow ----
  291.         void *offset;//used by malloc'ed blocks to free them
  292.     };
  293.    
  294. #endif //INC_COMMON_CPP
  295.  

Here is the setup_lnx.sh file:
Code: Bash: [Select]
  1. #!/bin/bash
  2. #QB64 Installer -- Shell Script -- Matt Kilgore 2013
  3. #Version 5 -- January 2020
  4.  
  5. #This version includes the updates to sucessfully install QB64 on the PI
  6. #or any ARM processor (Current version only tested on the Raspberry PI and
  7. #sets the DISTRO to "raspbian".) -- George McGinn (2/1/2022)
  8.  
  9. #This checks the currently installed packages for the one's QB64 needs
  10. #And runs the package manager to install them if that is the case
  11. pkg_install() {
  12.   #Search
  13.   packages_to_install=
  14.   for pkg in $pkg_list; do
  15.     if [ -z "$(echo "$installed_packages" | grep $pkg)" ]; then
  16.       packages_to_install="$packages_to_install $pkg"
  17.     fi
  18.   done
  19.   if [ -n "$packages_to_install" ]; then
  20.     echo "Installing required packages. If prompted to, please enter your password."
  21.     $installer_command $packages_to_install
  22.   fi
  23.  
  24. }
  25.  
  26. #Make sure we're not running as root
  27. if [ $EUID == "0" ]; then
  28.   echo "You are trying to run this script as root. This is highly unrecommended."
  29.   echo "This script will prompt you for your sudo password if needed to install packages."
  30.   exit 1
  31. fi
  32.  
  33. GET_WGET=
  34. #Path to Icon
  35. #Relative Path to icon -- Don't include beginning or trailing '/'
  36. QB64_ICON_PATH="internal/source"
  37.  
  38. #Name of the Icon picture
  39. QB64_ICON_NAME="qb64icon32.png"
  40.  
  41. DISTRO=
  42.  
  43. lsb_command=`which lsb_release 2> /dev/null`
  44. if [ -z "$lsb_command" ]; then
  45.   lsb_command=`which lsb_release 2> /dev/null`
  46. fi
  47.  
  48. #Outputs from lsb_command:
  49.  
  50. #Arch Linux  = arch
  51. #Debian      = debian
  52. #Fedora      = Fedora
  53. #KUbuntu     = ubuntu
  54. #LUbuntu     = ubuntu
  55. #Linux Mint  = linuxmint
  56. #Ubuntu      = ubuntu
  57. #Raspbian    = raspbian
  58. #Slackware   = slackware
  59. #VoidLinux   = voidlinux
  60. #XUbuntu     = ubuntu
  61. #Zorin       = Zorin
  62. if [ -n "$lsb_command" ]; then
  63.   DISTRO=`$lsb_command -si | tr '[:upper:]' '[:lower:]'`
  64. elif [ -e /etc/arch-release ]; then
  65.   DISTRO=arch
  66. elif [ -e /etc/debian_version ] || [ -e /etc/debian_release ]; then
  67.   DISTRO=debian
  68. elif [ -e /etc/fedora-release ]; then
  69.   DISTRO=fedora
  70. elif [ -e /etc/redhat-release ]; then
  71.   DISTRO=redhat
  72. elif [ -e /etc/centos-release ]; then
  73.   DISTRO=centos
  74. elif $(arch | grep arm > /dev/null); then
  75.   DISTRO=raspbian
  76. fi
  77.  
  78. echo "DISTRO detected = $DISTRO"
  79.  
  80. #Find and install packages
  81. if [ "$DISTRO" == "arch" ]; then
  82.   echo "ArchLinux detected."
  83.   pkg_list="gcc zlib xorg-xmessage $GET_WGET"
  84.   installed_packages=`pacman -Q`
  85.   installer_command="sudo pacman -S "
  86.   pkg_install
  87. elif [ "$DISTRO" == "linuxmint" ] || [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ] || [ "$DISTRO" == "zorin" ] || [ "$DISTRO" == "raspbian" ]; then
  88.   echo "Debian/Raspian based distro detected."
  89.   pkg_list="g++ x11-utils mesa-common-dev libglu1-mesa-dev libasound2-dev zlib1g-dev $GET_WGET"
  90.   installed_packages=`dpkg -l`
  91.   installer_command="sudo apt-get -y install "
  92.   pkg_install
  93. elif [ "$DISTRO" == "fedora" ] || [ "$DISTRO" == "redhat" ] || [ "$DISTRO" == "centos" ]; then
  94.   echo "Fedora/Redhat based distro detected."
  95.   pkg_list="gcc-c++ xmessage mesa-libGLU-devel alsa-lib-devel zlib-devel $GET_WGET"
  96.   installed_packages=`yum list installed`
  97.   installer_command="sudo yum install "
  98.   pkg_install
  99. elif [ "$DISTRO" == "voidlinux" ]; then
  100.    echo "VoidLinux detected."
  101.    pkg_list="gcc xmessage glu-devel zlib-devel alsa-lib-devel $GET_WGET"
  102.    installed_packages=`xbps-query -l |grep -v libgcc`
  103.    installer_command="sudo xbps-install -Sy "
  104.    pkg_install
  105. elif [ -z "$DISTRO" ]; then
  106.   echo "Unable to detect distro, skipping package installation"
  107.   echo "Please be aware that for QB64 to compile, you will need the following installed:"
  108.   echo "  OpenGL developement libraries"
  109.   echo "  ALSA development libraries"
  110.   echo "  GNU C++ Compiler (g++)"
  111.   echo "  xmessage (x11-utils)"
  112.   echo "  zlib"
  113. fi
  114.  
  115. echo "Compiling and installing QB64..."
  116.  
  117. ### Build process
  118. find . -name "*.sh" -exec chmod +x {} \;
  119. find internal/c/parts -type f -iname "*.a" -exec rm -f {} \;
  120. find internal/c/parts -type f -iname "*.o" -exec rm -f {} \;
  121. find internal/c/libqb -type f -iname "*.o" -exec rm -f {} \;
  122. rm ./internal/temp/*
  123.  
  124. #if [ "$DISTRO" == "raspbian" ]; then
  125. if $(arch | grep arm > /dev/null); then
  126.   echo "Updating files for the ARM processor..."
  127.   echo "updating makedat_lnx32.txt file..."
  128.   pushd internal/c >/dev/null
  129.   cat > makedat_lnx32.txt <<EOF
  130. objcopy -Ibinary -Oelf32-littlearm -Barm
  131. EOF
  132.   echo "updating makedat_lnx64.txt file..."
  133.   cat > makedat_lnx64.txt <<EOF
  134. objcopy -Ibinary -Oelf64-littlearm -Barm
  135. EOF
  136.   popd >/dev/null
  137. fi
  138.  
  139. echo "Building library 'LibQB'"
  140. pushd internal/c/libqb/os/lnx >/dev/null
  141. rm -f libqb_setup.o
  142. ./setup_build.sh
  143. popd >/dev/null
  144.  
  145. echo "Building library 'FreeType'"
  146. pushd internal/c/parts/video/font/ttf/os/lnx >/dev/null
  147. rm -f src.o
  148. ./setup_build.sh
  149. popd >/dev/null
  150.  
  151. echo "Building library 'Core:FreeGLUT'"
  152. pushd internal/c/parts/core/os/lnx >/dev/null
  153. rm -f src.a
  154. ./setup_build.sh
  155. popd >/dev/null
  156.  
  157. echo "Building 'QB64'"
  158. cp -r ./internal/source/* ./internal/temp/
  159. pushd internal/c >/dev/null
  160. g++ -no-pie -w qbx.cpp libqb/os/lnx/libqb_setup.o parts/video/font/ttf/os/lnx/src.o parts/core/os/lnx/src.a -lGL -lGLU -lX11 -lpthread -ldl -lrt -D FREEGLUT_STATIC -o ../../qb64
  161. popd
  162.  
  163. if [ -e "./qb64" ]; then
  164.   echo "Done compiling!!"
  165.  
  166.   echo "Creating ./run_qb64.sh script..."
  167.   _pwd=`pwd`
  168.   echo "#!/bin/sh" > ./run_qb64.sh
  169.   echo "cd $_pwd" >> ./run_qb64.sh
  170.   echo "./qb64 &" >> ./run_qb64.sh
  171.  
  172.   chmod +x ./run_qb64.sh
  173.   #chmod -R 777 ./
  174.   echo "Adding QB64 menu entry..."
  175.   cat > ~/.local/share/applications/qb64.desktop <<EOF
  176. [Desktop Entry]
  177. Name=QB64 Programming IDE
  178. GenericName=QB64 Programming IDE
  179. Exec=$_pwd/run_qb64.sh
  180. Icon=$_pwd/$QB64_ICON_PATH/$QB64_ICON_NAME
  181. Terminal=false
  182. Type=Application
  183. Categories=Development;IDE;
  184. Path=$_pwd
  185. StartupNotify=false
  186. EOF
  187.  
  188.   echo "Running QB64..."
  189.   ./qb64 &
  190.   echo "QB64 is located in this folder:"
  191.   echo "`pwd`"
  192.   echo "There is a ./run_qb64.sh script in this folder that should let you run qb64 if using the executable directly isn't working."
  193.   echo
  194.   echo "You should also find a QB64 option in the Programming/Development section of your menu you can use."
  195. else
  196.   ### QB64 didn't compile
  197.   echo "It appears that the qb64 executable file was not created, this is usually an indication of a compile failure (You probably saw lots of error messages pop up on the screen)"
  198.   echo "Usually these are due to missing packages needed for compilation. If you're not running a distro supported by this compiler, please note you will need to install the packages listed above."
  199.   echo "If you need help, please feel free to post on the QB64 Forums detailing what happened and what distro you are using."
  200.   echo "Also, please tell them the exact contents of this next line:"
  201.   echo "DISTRO: $DISTRO"
  202. fi
  203. echo
  204. echo "Thank you for using the QB64 installer."
  205.  



Thanks,
____________________________________________________________________
George McGinn
Theoretical/Applied Computer Scientist
Member: IEEE, IEEE Computer Society
Technical Council on Software Engineering
IEEE Standards Association
American Association for the Advancement of Science (AAAS)