qb64-phoenix-edition / qb64pe Goto Github PK
View Code? Open in Web Editor NEWThe QB64 Phoenix Edition Repository
Home Page: https://qb64phoenix.com
License: Other
The QB64 Phoenix Edition Repository
Home Page: https://qb64phoenix.com
License: Other
We now produce a symbol file (./internal/source/qb64.exe.sym
) for QB64 which we can use to debug crash dumps from QB64 (which has it's symbols removed). We should document the process for taking various dumps of QB64 on Linux and Windows, and also how you can actually use the dump and symbol file together to interrogate the dump.
In particular the Windows side will get interesting because the core dump will be in minidump format, but the symbols are in ELF format (I think), I'm pretty sure neither gdb
or windbg
can open both. I think the most straight-forward solution (based on the internet) is converting the minidump into a core file, and then loading the core file and symbols into gdb
. For Linux it would be the same steps with gdb
but the minidump conversion would be unnecessary.
We should also document how users can create these dumps for us if we ask for them.
setup_win.bat leaves a stray mingw compiler sitting in the root folder after setup. Do we want to clean this up, or just leave it for the end user to decide what to do with it?
I think it should allow supply 5 different settings:
-O2
for now, -Og
when debugging) (default: false)-Dvariable=20
, -fwhatever
) (default: blank)-l
, -L
, and others) (default: blank)-j X
parameter to make
to parallelize the build). (default: 3)This is not necessarily a fix to #55, but does give an easy work around at least. It also kinda resolves #40, but not completely as it does not make compilation faster by splitting up qbx.cpp
. Also note that some of these values, like the flags, are theoretically temporary until qbx.cpp
can be considered for splitting up.
This should either be tied into, or include the existing Advanced (C++)
dialog about debug information.
In #19 Steve was having troubles getting KILL to work with files that had spaces in the name. Based on the description of KILL here it seems like it should work if file names have spaces, but the C++ implementation sub_kill()
looks fairly questionable and should be reviewed.
At the very least there is a clear difference between the Linux and Windows implementations because Windows uses FindFirstFile()
which supposedly handles the *
and ?
wildcards, but Linux just uses remove()
which does not. Additionally, there is a lot of weird/suspicious path handling in Windows that might have been what was giving Steve some trouble. Certainly DeleteFile()
itself can handle spaces in paths.
IMO it would probably be worth just implementing the *
and ?
handling ourselves and use the same implementation for all platforms. That should hopefully also allow us to toss some of the weirder handling and get consistent behavior. We should also presumably verify the behavior of QuickBasic 4.5 a bit
qbx.cpp
is located outside of ./internal/temp
but is modified during the build. It also directly includes most of the files located inside of ./internal/temp
, which locks down the location of temp. Overall it greatly complicates any attempt to move the temp folder somewhere else. I think we have two options for what to do with it:
./internal/temp
during the build. Change the paths, and give the compiler a -I
flag back to ./internal/c/
so that qbx.cpp
can see the common.h
header without actually being in there.qbx.cpp
does not directly include anything from ./internal/temp
. This is more work but theoretically possible by restructuring how the .txt
files work and compile them separately on their own, and then link the whole thing together afterward.Allow simple variables to be initialized using Dim/ReDim.
For example:
Dim i As Integer = 20
Dim As Long b = 100
Dim fname As String = "screen.png"
Dim As Single x = 34.2, y = 45.5, z = 56.3
Dim s As String = "Hello", x As Long = -45, c As Byte = 32
Probably, later we can expand this to support array initialization :)
UDT's by their nature do not include any padding, because QB45 never included any padding and keeping it that way is important for compatibility reasons. However this becomes quite problematic because it means fields in the UDT are likely not aligned on their required alignment, Ex. 2 bytes for 16-bit integer, 4 bytes for 32-bit integer, etc.
The most straight-forward solution here is to probably just copy the values out of the UDT buffer using memcpy()
- they can be copied into a properly aligned temp variable where it can then be used. It would certainly be annoying, but it's probably easier than trying to introducing padding into the UDT structure itself due to compatibility concerns with things like PUT and GET. I haven't looked deeply into this though.
This was introduce with #33, and it's just too confusing to have two files people need to get the output from instead of just one. It also seems some references to compilelog.txt
were not updated. On all platforms we should be able to redirect stderr
to stdout
easily enough and just keep the single compilelog.txt
file as it was before.
I noticed that we have a _NEWIMAGE that lets us do the same for images, but nothing for sound. I am aware of _SNDRAW & _SNDOPENRAW, but that does not serve my purpose. What I really want is a sound buffer that can be created programmatically and filled with custom sample data to be reused later multiple times. Something like:
soundHandle& = _NEWSND(sampleRate&, sampleBits&, sampleChannels&, sampleLength&)
We can then get access to the buffer by using _MEMSOUND[(soundHandle&, channel%)]
.
If there is a way to do this currently in QB64 (without using external libs or hacks), then please let me know.
I am quite certain that help for _ErrorMessage$() is missing on wiki. Or probably this page was lost? Not sure.
Improvements to visual layout and various quirks.
Currently function names require type characters. For example:
Function test1% (x As Integer, y As Integer)
test1% = x + y
End Function
This is ok. However, also allow the following:
Function test1 (x As Integer, y As Integer) As Integer
test1 = x + y
End Function
And in the future, also allow functions to return UDT values.
Original request comes from QB64Team/qb64#225
qb64.1 file has a stray link to the old qb64.org site that needs to be purged and updated.
Currently we keep a copy of the help files in ./internal/help
so that they can be used when QB64 is downloaded without needing to download a copy. Keeping the copy in ./internal/help
in this repository is a bit messy though, so we should look into trying to download a fresh copy of ./internal/help
during the CI build - so that the repo doesn't have to contain a copy, but released versions of QB64 will has a fresh copy of whatever was present when it was released.
_SndRawLen always returns 0 no matter how many seconds of data are left to be played.
For example, in the code below it always returns 0.
We know that there is enough sound data in the queue because even when the loop is exited, we can still hear the sound playing for a long time.
Dim h As Long
h = _SndOpenRaw
Do
_SndRaw Rnd - Rnd, Rnd - Rnd, h
Locate 1, 1: Print _SndRawLen;
Loop While Len(InKey$) = 0
_SndClose h
For _SndRawLen , the wiki says:
The _SNDRAWLEN function returns the length, in seconds, of a sound currently queued.
Use _SNDRAWLEN to determine the length of a sound queue during creation and when to stop playing the sound.
Ensure that _SNDRAWLEN is comfortably above 0 (until you've actually finished playing sound).
If you are getting occasional random clicks, this generally means that _SNDRAWLEN has dropped to 0.
Clearly, this is not the way this is working at the moment.
Note: Please turn down your volume when running the above snippet. It's not pretty. ๐
_SndRawLen works when _SndRaw is used without a handle, as shown below.
Do
_SndRaw Rnd - Rnd, Rnd - Rnd
Locate 1, 1: Print _SndRawLen;
Loop While Len(InKey$) = 0
Well, this was unexpected. A better way for _SndRawLen to work would be to return the time left for "handle-less" streams and streams with handles when specified.
length# = _SndRawLen [pipeHandle&]
I want to be able to do something like ./qb64 -x ./foobar.bas -D key=value
, and then be able to use key
within my program to have it filled in or replaced with value
. In C/C++ this basically corresponds to #define
preprocessor values, and could potentially be implemented as some kind of extension of the $LET
logic.
version.bas
includes a good example of a use case for this - there is no way for us to put the version information only known at compile time into the source, so we're left with reading that information from a text file in ./internal
. If we could provide that information via a compiler switch (-D version_tag=foobar
) then the code could simply check if version_tag
exists at compile time to determine what the qb64 version should be, without having to modify version.bas
before building or use an external file.
The current QB64 networking only extends to basic TCP streams and UDP. This is certainly useful, but it's not all that usable for a lot of basic tasks people actually want to do with networking, in particular HTTP and HTTPS. Writing your own HTTP handler in QB64 is fairly hard to actually accomplish, and frankly not something you should really have to do. HTTPS is also effectively impossible since it would require implementing TLS support yourself. The best option is simply pulling in external libraries via DECLARE LIBRARY
. The QB64 IDE itself just shells out to curl
to download Wiki pages, effectively giving up on the idea of doing it itself.
The basics of doing this is really not that hard, as libcurl
is MIT licensed and can do all of this with a fairly simple interface. The hard part would be the interface offered, and whether it can be added into the existing networking functions (_OPENCLIENT()
and friends) or requires some new ones.
Some Win32 API need function pointers for callbacks. I am quite certain that we have other OS API requiring the same.
Not sure how feasible this is... but can we get _Offset() to return function pointers to Subs and Functions?
We can then use it like the example below.
mmr = waveOutOpen(hwaveout, WAVE_MAPPER, wfe, _Offset(WaveProc), 0, CALLBACK_FUNCTION)
merr = midiStreamOpen(hMidiStream, MidiDevice, 1, _Offset(MidiProc), 0, CALLBACK_FUNCTION)
Sub WaveProc (hwo As _Unsigned Long, uMsg As _Unsigned Long, dwInstance As _Unsigned Long, dwParam1 As _Unsigned Long, dwParam2 As _Unsigned Long)
If uMsg = WOM_DONE Then buffersout = buffersout - 1
End Sub
Sub MidiProc (hMidi As _Unsigned Long, uMsg As _Unsigned Long, dwInstance As _Unsigned Long, dwParam1 As _Unsigned Long, dwParam2 As _Unsigned Long)
Select Case uMsg
Case MOM_DONE
...
Case Else
...
End Select
End Sub
Currently the artifacts are named qb64-lnx-x64
and qb64-osx-x64
, but this is wrong because those releases support both 64-bit and 32-bit depending on the machine you run the setup script on.
We should also probably rename them to qb64pe
, and I'd really like to get the version into that name as well, something could probably be worked out to pull it from version.bas
along with the version calculation script.
In the Makefile the TEMP_ID identifies what temp*
folder contains the source files, along with what qbx.cpp
file to use. To ensure recompilation works correctly, all the files in ./internal/temp*
need to be listed as a dependency of qbx.cpp
. Unfortunately that dependency addition is missing TEMP_ID
so it only contains the contents of ./internal/temp
even when multiple instances are involved. The bugged line in particular is this one:
$(QB_QBX_OBJ): $(wildcard $(PATH_INTERNAL)/temp/*.txt)
Change about screen to show Phoenix Edition.
Not sure if we already have this. But I checked the wiki and found nothing.
Having an identifier (like DEBUG for example) auto-set when the $DEBUG metacommand is used can be useful to include code that we only need when debugging.
For example:
$DEBUG
$If DEBUG Then
Print "We are debugging"
$End If
X ^ -NOT Y
is valid syntax in QB45, but gives a syntax error in QB64 due to it not understanding the NOT
operator can come after -
within exponentiation (It thinks there has to be a number). It does correctly understand X ^ NOT Y
and X ^ - Y
, so it's just the combination negating the NOT that confuses the parser. The opposite X ^ NOT -Y
is seemly parsed correctly.
Currently the way versioning works is that the version label is generated during the CI build and placed into a file. This means that all CI builds have proper version labels on them to easily identify what version is being used.
Unfortunately this means that if you just build the repository manually you do not get a version label, making it confusing what exactly you're using if you're looking to get help. We should change the setup a bit so that if QB64 does not detect it was a release build (probably based on the presence of some file in ./internal
) then it produces some kind of generic "-LocalBuild" version label to indicate this.
Strings passed as parameters to a DECLARE LIBRARY function are not NUL terminated. This can be worked around in your QB64 code, but I think it's unacceptable behavior simply because it's way to easy to walk into very nasty problems due to forgetting the NUL character, and there's is no disadvantage to having QB64 add them automatically. Programs that weren't relying on it being there will have no idea the NUL is there, and programs that are mistakenly expecting it to be there will now work correctly all the time rather than randomly.
In the example below defcheck() returns 1. It would be helpful if it could see the QB64 preprocessor variable and return 5 instead.
This will allow us to directly use many single file C header libraries on GitHub, like the famous STB header only libraries.
Without the QB64 preprocessor variables visible, we must write a "stub" .h
file with #define XYZ_IMPLEMENTATION
and then include the actual header file.
-----------------------------
prog.bas
-----------------------------
$Let PENTIUM = 100
Declare Library "./myclib"
Function defcheck&
End Declare
Print defcheck
End
-----------------------------
myclib.h
-----------------------------
int defcheck()
{
#ifdef PENTIUM
return 5;
#else
return 1;
#endif
}
This needs some analysis of the best way to do it, but the end idea is that we need a way to provide:
Note that there's definitely some potential messy stuff here. For one, all the DECLARE LIBRARY
logic needs to be investigated to understand better how it works. The naming it allows is very lose and it does a whole lot of work to check common locations for matching .h
, .dll
, .so
, .dylib
, etc. files. Perhaps it allows for some of this already, and also I suspect QB64 will need to be able to find these files to work correctly. That last detail is where my second and third point come in - QB64 may need to know about the new locations, rather than just have them in an opaque string that gets tacked onto the compiler lines, so that may necessitate a few separate parameters rather than just one.
Separately, the location of the parameters in the compile string is actually important, which may necessitate multiple parameters - libraries need to be provided to the linker later on after the object files so that the linker knows the symbols needed from the library files. I'm pretty sure Include paths can be listed either at the beginning or the end, but I'm not 100% sure.
Interactions with #40 also need to be considered. Splitting up the output of the C++ source into many separate files that get linked together needs to be a goal, the benefits are large, and simply tacking the flags onto the end of every compile of those files may not make sense.
Perhaps a bit more lofty, it would probably be nice if we could just include arbitrary compile lines to be run at the beginning of the source. I see a decent number of people including regular C/C++ source in header files, which isn't a great approach. It would be pretty nice if we had something like this that people could do instead:
' These introduce extra flags to the compile lines
$compile-add: library: foobar2
$compile-add: include-path: /usr/include/foobar
' These just call the C or C++ compiler with these parameters when you build your .bas source
' That way you could provide separate .c or .cpp files without needing to compile them as a separate step
$compile: CPP: ./foobar.cpp -o ./foobar.o
$compile: C: ./foobar.c -o ./foobar.o
A fair amount of languages I know about hide new features behind 'future' or 'unstable' flags, with the idea being that they can still be part of the regular release but it is made clear they are features that may change or be removed in the future. I think one of either $FUTURE:
or $UNSTABLE:
could work decently for us to do the same thing.
Ex. If we're not quite sure if Steve's NoPrefix color changes are what we want to go with, then we could require adding $UNSTABLE:NOPREFIX_COLOR
to be able to use it. If at some point in the future we feel it's good as-is, then we simply drop the requirement to use the flag and it becomes part of the regular language.
One of the big advantages with this system is that it allows us to only maintain a single version of QB64, while still allowing us to introduce potential new features and get feedback on them. We're free to make changes to it between releases while it's hidden behind the flag, and once we're satisfied with a feature, we simply remove the required flag.
Simple to reproduce (hopefully). Open program and press F3 to search. Freezes and requires xkill to force close it.
Fairly simple, the Makefile
gives an error if it is called without supplying the OS
parameter, and ./setup_lnx.sh
is doing that when it calls make clean
. We simply need to put a OS=lnx
on the call.
Some things to touch on:
This is due to the new Makefile changes introduced in #33. Make does not like spaces in path names, so when the target executable has a space in it, it barfs. There's two issues which are reasonably easy to fix:
\
but then it will work as intended. Theoretically this should work for the path as well, and we can easily add test cases for this.internal/temp/[email protected]
which is dumb, I'm a little surprised that didn't already cause problems. This should be tweaked to do $(basename $@)
or something alone those lines to take off the path.It's not safe to simply call glutIconifyWindow()
, glutHideWindow()
, glutShowWindow()
with no threading protection while we have another thread that handles the GLUT stuff. There was some half-hearted attempts by using busy waits on a global variable, but that's really not the way to handle threading problems like these.
In this case these functions are all quite simple because they do not give any values back, so likely the easiest solution is to simply have the existing QB64 functions (sub__screenicon
, etc.) set some kind of flag that the GLUT thread can see and perform the appropriate action. I believe the glutTimerFunc
would be the place to do this, since it gets called at regular intervals.
The QBPE wiki says:
If imageHandle& parameter is omitted or zero is designated, the current software destination screen or image is copied
However, this is not how this works in the IDE like shown in the line below. The IDE complains about Incorrect number of arguments
.
tmp& = _CopyImage
So, this should either be corrected in the wiki or in code.
ive discovered that the bash script is not installing some dependacies correctly on Debian based disros, as the grep command is detecting the word make in the descriptions of the packages and assuming that make is installed.
I have found a work around that just tells apt to install everything as apt ignores previously installed packages
This is my fix:
pkg_install() {
#Search
if [ "$DISTRO" == "linuxmint" ] || [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ] || [ "$DISTRO" == "zorin" ]; then
echo "testing debian builds"
$installer_command $pkg_list
elseif
packages_to_install=
for pkg in $pkg_list; do
if [ -z "$(echo "$installed_packages" | grep $pkg)" ]; then
packages_to_install="$packages_to_install $pkg"
fi
done
fi
if [ -n "$packages_to_install" ]; then
echo "Installing required packages. If prompted to, please enter your password."
$installer_command $packages_to_install
fi
}
The previous repository had one, potentially we can just reuse it. It has good information on what to provide us about the bug.
ARM apparently has serious problems due to threading issues. Looking at the source code, there's some clear problems like here which attempts to use a regular variable as a mutex/spinlock with no real protection. This doesn't really work on x86, but ARM has even more relaxed memory ordering so that likely makes this much worse.
We need to do a full look through the source to catalog all usages of threads, and then we can start looking at adding some proper protection with their use.
./internal/c/parts/core/gl_header_for_parsing/temp/gl_helper_code.h
is an odd header that is included into qbx.cpp
and is modified during the build. The location of his header is hardcoded into opengl_methods.bas
and the path is not changed for multiple instances, Meaning, every instance of qb64 uses the same copy of this header. This is a similar problem to #43, but a bit worse because at least qbx.cpp
gets new copies for multiple instances of qb64.
To fix this we should modify the code to move gl_helper_code.h
into the ./internal/temp
folder. That should be relatively easy based on what thel code does with this file, and we can change the include in qbx.cpp
to include it from ./internal/temp
.
Currently QB64 does not compile programs with any optimizations enabled. -O2
is reasonably safe to use and things appear to work (though more testing could be done), but the biggest issue appears to be speed and memory usage: Compiling qb64.bas
with -O2
results in a ~15 minute compile on my machine and at one point uses ~10GB of memory, which is completely out of the realm of reasonable.
It appears most things compile fairly snappy (as you would expect) and the big culprit is qbx.cpp
which imports main.txt
, which is 200 thousand lines long for qb64.bas. Being that this contains all the function definitions in addition to the actual main code, with a lot of work it seems likely that this can be split into several .cpp
files that can then get compiled own their own and linked together, significantly reducing the amount of code each gcc process has to deal with.
Currently QB64 simply strips all symbols from the compiled executables. It's understandable from a size perspective (in many cases the symbols can account for more than half the size of the executable), but without having the symbols from compilation we really can't debug QB64 if it breaks.
The typical solution to this problem is to produce a separate symbol file alongside the executable. This isn't particularly hard but requires a few extra steps at the end of compilation - the way I've done it before is use objcopy
with --keep-only-debug
to produce the symbol file and then again with --strip-unneeded
to strip the executable. You can then load the symbol file when debugging. #51 will make this easier to implement.
When developing for QB64 itself (or even when building QB64 applications) it's fairly common to want to clean out ./internal/temp
and any built copies of libqb
. This is easy enough using make clean
, but it has the unfortunate side effect of also clearing out any built 3rd party dependencies such as freeglut
and others, which do take a bit of time to rebuild. Making changes to any of the 3rd party dependencies is very uncommon, so it would be nice to be able to avoid that cost and only clean the things that are directly part of QB64.
It could probably be called clean-libqb
or something along those lines, and would clean out compiled libqb
copies along with ./internal/temp
, qbx.o
, and maybe a few others. QB64's purge
logic would call this instead of the regular clean
.
Windows version.
Help menu.
Update All Pages.
Looks for 'curl' and fails.
when using the menu bar, the program hangs, and behaves like it is stuck in a do..loop.
windows 11
AMDe3020 with vega graphics
4gb ram
It's not clear to me why exactly this is the case, but currently the various $VERSIONINFO values accept non-quoted string information. Ex:
$VERSIONINFO:ProductName=foo bar
I personally find this extremely strange, as far as I know this is the only command that accepts such a thing. To me it seems like it should accept a quoted string (single quotes I think, since that's what other metacommands do), Ex:
$VERSIONINFO:ProductName='foo bar'
This could be done in a largely backwards compatible way as long as we fallback to the current behavior if the line doesn't begin and end with a quote (though it would be annoying that such behavior doesn't just produces an error, rather than expected behavior). To avoid that issue perhaps the current syntax could produce a warning, but I don't know much about the warning system yet. Also, there is a slight backwards compatibility break as that line currently would place the literal "'foo bar'" into the version information, but I don't think that's a big enough deal to worry about - I think most who wrote it that way probably didn't expect the quotes to be in the output to begin with.
Currently, if you use $EXEICON''
, the path to the icon file is based on the location you run the compiler from. Functionally this makes it impossible to use in an easily portable sense, because the path will likely be unpredictable unless they put the .bas
source in the same location as the compiler.
To fix this, we should allow $EXEiCON
to also accept paths to a file that are relative to the .bas
file it is located in. That way as long as the source files and icon file are kept together in the same structure, it does not matter where the compiler is run from to build it.
_SndRaw does not play stereo streams correctly. It sounds like a mono stream no matter which channel is being fed. As far as I can tell, this is not an issue with my system.
Dim h As Long, i As Long
h = _SndOpenRaw
For i = 1 To 100000
_SndRaw Sin(i / 10), 0, h
Next
For i = 1 To 100000
_SndRaw 0, Sin(i / 10), h
Next
_SndClose h
Can someone run the above snippet and let me know if this works as expected for them?
I am using QB64pe v0.5.0
I think there's a few goals here (in no particular order):
Some challenges I see:
./internal/temp
is really acceptable, because the install directory isn't generally supposed to be read/write. Ideally we move ./internal/temp
into the actual temp folder, but that's a big change. We also compile and change files outside of ./internal/temp
, so that's not the only thing that would need addressing.
Program Files
, but somewhere else (maybe user specific in AppData or something) and then it can have the read/write access to its directory that it wants. This is probably a good first step considering how much of a challenge it would be to fix it otherwise.The new 'Run only' option introduced in #19 does not work on some (likely many) Linux distros because it tries to use del
for deleting files. The typical Linux command for this is rm
.
Note that #34 is relevant here, the only reason this comes into play is because KILL
is not being used to remove the file. Considering that on Linux sub_kill
just passes the argument to remove()
it probably works ok and can be used rather than rm
(It is still bugged since it's not implementing the ?
and *
behavior that KILL
is supposed to have, but we're not using that there). Until #34 is complete we may need to avoid its use on Windows, but we already have separate paths for all three platforms so that's not a big deal.
The C++ files have a very serious need for some proper formatting, clang-format can do it automatically for us at least for the initial change. Since we don't use clang itself normally I don't think we can build it into our normal workflow just yet, but it would also be nice if we used it to verify the formatting was correct as a build check (So PR's can't be merged if they screw up the formatting).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.