Lots of changes and improvements in today's commit to github. I did a lot of work on project management and incremental compiling for projects. Projects automatically save all generated object files ( *.o ) that are re-used on subsequent compiles. The datetime of the object file is checked against the source file. If the source file is time stamped later than the object file then the object file is regenerated. On a test of recompiling the FB compiler itself, the intial compile was about 12 seconds. Subsequent compiles reduced to about 1.5 seconds. The system is simple and easy and works very well so far.
As an aside, in FB there is usually more than one source file. Multiple *.bas files compose a project. Each .bas file is compiled into an object file and during the linking process they are combined with the main compiled source file. In our old PB ways, we normally created our applications by having one main source file and everything #Include'd into the main file. In FB all you need to do is include the child .bas object module's header files (*.bi) into the main file so that the main file can resolve references to variables, structures, subs, and functions located in the compiled object files.
Tried the 64-bit version. It GPFed when clicking the ListView of the Project Manager.
Looks like in NM_DBLCLK for listview I did not test for a Null pDoc pointer. Here is the corrected code:
Case NM_DBLCLK
' Load the selected file into the editor
If id = IDC_FRMPROJECTMANAGER_LISTVIEW Then
' Get the pDoc from the selected row
Dim pDoc As clsDocument Ptr = Cast( clsDocument Ptr, FF_ListView_GetlParam(nmi->hdr.hwndFrom, nmi->iItem) )
If pDoc Then
frmMain_OpenFileSafely(HWND_FRMMAIN, False, False, True, pDoc->DiskFilename, pDoc )
End If
End If
I am also reconsidering the folder layout for projects. I am going to simplify it more. I will do that in the morning, Too tired to start it now.
Also the window is larger than the height of the work area of my monitor. I suggest the following change in frmProjectManager_Show:
DIM rcWork AS RECT = pWindow->GetWorkArea
DIM nHeight AS LONG = (rcWork.Bottom - rcWork.Top) - (20 * pWindow->ryRatio)
HWND_FRMPROJECTMANAGER = _
pWindow->Create( hWndParent, L(188,"Project Manager"), @frmProjectManager_WndProc, 0, 0, 700, nHeight, _
WS_POPUP Or WS_CAPTION Or WS_SYSMENU Or WS_THICKFRAME Or WS_CLIPSIBLINGS Or WS_CLIPCHILDREN, _
WS_EX_CONTROLPARENT Or WS_EX_LEFT Or WS_EX_LTRREADING Or WS_EX_RIGHTSCROLLBAR)
' pWindow->SetClientSize(400, 500)
pWindow->Center(pWindow->hWindow, hWndParent)
Make sure that the dialogs aren't larger than the height of the work area. If they need to be, then it's time to use an scrollable window.
For the width choose the one that you prefer, but 400 looks too narrow tho show the paths of the files.
And thanks for removing the top most style.
The first thing that I did when it had this style was to change the language and didn't see the expected message because it was behind the top most dialog.
I have created a new project and added a file.
Each time that I open this project, it duplicates the same file(s).
The first time, it appears duplicated; the second time, quadruplicated, and so on.
Quote from: Jose Roca on July 03, 2016, 01:03:03 AM
I have created a new project and added a file.
Each time that I open this project, it duplicates the same file(s).
The first time, it appears duplicated; the second time, quadruplicated, and so on.
That's odd. I have not been able to duplicate that problem. A few days ago i saw something like that occur but I reworked the code a lot since then. Try the latest code in github to see if it is happening? I will keep trying to see if I can recreate the steps that lead to the duplicates being added.
Actually, hold off using any of the code in github until I finish changing the directory structure changes for the compiling. Should only be an hour at most. I will post again when everything is changed.
Okay, the changes are in github now. I also added a subclass for the Project Management listview in order to catch the ENTER key. This makes it easier to open a file (or multiple files) from the listview when using the keyboard.
> That's odd. I have not been able to duplicate that problem.
It's very easy to reproduce. Don't use F4 to activate the project manager, but choose "Open Project" from the menu. Each time you open it, the file names are duplicated.
I have created a project and added a file. After opening the project several times, I have ended with what you can see in the capture below.
Another thing: When I create a new project, it displays the dialog with the listview, but it doesn't leave you to do anything. You have to close it and select the menu option to add files to the project.
Thanks Jose, I see the problem with the duplicate files now. I will fix that as soon as I get home tonight. My attempt was to prevent the destruction of the Project Manager window and simply "hide" it whenever someone pressed F4 or clicked on the "X" button. Looks like Alt+F4 or close from the windows command menu destroys it. I need to trap and prevent that behaviour.
When the Project Manager displays, it is a non-modal window. You shouldn't have to close it in order to select options from the Project menu. Maybe I should have a menu or toolbar on the Project Manager window as well.
Jose, I have uploaded the changes for the duplicates. I don't think it had anything to do with the Project Manager window itself. I was not totally clearing the IsProjectFile attribute of the loaded pDoc's when a new project was opened.
I have also changed the folder structure for the generate object files ( *.o )for project files. Instead of having two separate folders (obj32, obj64) for the generated obj files, I am now using only one called wfbe_obj. All object files for both 32 and 64 bit are put in that folder (they are differentiated by appending either a 32 or 64 to their names).
I uploaded some new code tonight. F9 will now toggle viewing the Compile Results dialog. I am also experimenting with the font quality and anti-aliasing settings just to see if I like the way it looks. If you have any strong opinions of it then please let me know. I have also changed the setting that dictates how selections are visually displayed. Now the entire screen space is filled with the selection highlight rather than just to the end of the line. This is how my other editors looked when full lines were selected so it feels more natural for me. I also increased the pixel width of the caret from 1 pixel to 2 pixels.
I finally got to use the editor today in a real world situation. I am writing a utility that scans source code and generates the .bi header file. It is allowing me to work through how the editor works and how it looks and feels. Getting to use the project management features as well.
One thing that I am having a hard time getting used to is the behaviour of the Ctrl+left arrow key. I am used to using it to eventually stop at the beginning of the line (column 0) no matter if there is a word match or not. In Scintilla, it does not stop at the start of the line but will wrap itself to the previous line(s) until a beginning of word match is found. That is going to take some time for me to get used to. I often use Ctrl+left arrow rather than the HOME key to position to column 0.
Since I use the Consolas font (more readable than Courier New) I don't think that antialiasing will make a noticeable difference.
Scintilla passes the value down to the platform as lfQuality in the logical font struct for GDI:
SC_EFF_QUALITY_DEFAULT -> DEFAULT_QUALITY
SC_EFF_QUALITY_NON_ANTIALIASED -> NONANTIALIASED_QUALITY
SC_EFF_QUALITY_ANTIALIASED -> ANTIALIASED_QUALITY
SC_EFF_QUALITY_LCD_OPTIMIZED -> CLEARTYPE_QUALITY
Its a request. The platform may honour it or ignore it when configured to do so or when it can't because the device or context does not support that choice.
What it makes a big difference (using 192 DPI) is if the application is DPI aware or not. See capture.
Yes, that is a pretty big difference. :)
I have found that the CodeMax control that I used Jellyfish and my own custom built control for Firefly are a little more visually pleasing to the eye than Scintilla. I couldn't figure out just why until I noticed that it appears that Scintilla does not have as much spacing between it's lines than the other controls. I guess it makes the text a little more cramped together than I am used to. Maybe I am just getting old and set in my ways..... :)
I have run into a bit of a problem. I have been converting the project over to the FB way of doing things. I am trying to make a standalone object for each of the source files rather than include'ing them all off of the main file. I have been able to convert every file except for the CWindow class file. I am pretty sure that the problem is the NAMESPACE stuff. I guess I just don't understand it enough (yet) to be able to make the object file and corresponding header file. If this was going to be a standalone object (CWindow.o) that you would link to produce an EXE then how is it done? I will continue to plod away at this but my mind is a little mesmerized. It must be easy but right now I am not seeing it.
And what happens with conditional code (#if... #endif)?
I never have used PB SLLs because they don't allow conditional code.
Quote from: Jose Roca on July 04, 2016, 04:21:33 PM
And what happens with conditional code (#if... #endif)?
I never have used PB SLLs because they don't allow conditional code.
I assume that the library would access the target of the conditional operation either through whatever variables are defined within the module itself (eg. #DEFINE UNICODE, etc...). I assume the value if the target would have to known at compile time. I am thinking that in the case of CWindow where you have conditional defines for MDI support that you might have to implement dynamically rather than rely on a conditional at compile time. Maybe define an additional property for the class (BOOLEAN) that controls whether MDI is active. Remove the #IFDef and just do a tradition IF/THEN test on the property BOOLEAN and call the correct MDI or non-MDI routine. I guess that would also mean that you would need to compile code for both MDI and non-MDI cases into the library rather than excluding one or the other at compile time with a #Define. I'm just thinking out loud and typing so I may not be thinking of all the scenarios here.
I got basically no programming done last night because I had to reinstall my laptop.
Paul,
What advantages do you get with individual module .bas -> .c -> .obj link *.obj -> .exe in normal every day coding?
I can see the advantage if you have 100's of individual files but .... with the judicious use of #include Onece and Private I can include every source file I've every written :)
James
Hi James, yes of course you're right, for the everyday small project there is no real advantage. For larger projects the incremental compile time is greatly sped up if the object files already exist. Likewise, it promotes the use of header files with function/type definitions that aid in not having to always juggle around order to the files that you are Incude'ing into a main .bas file just to get it to compile. I guess what I'm saying is that I want to start to try to handle projects more like they do in the FB world just so I can be consistent with them. Either way, I am hoping that the new system is flexible enough to handle both styles of coding.
Paul,
Been there done that with FreeBasic many years ago prior to Private.
Sorry I don't believe Compile times on todays equipment are relevant.
Maintenance on a big library is just too much of a PIA for me.
To get the best granularity each function needs to be compiled to an obj file.
When I first started I thought the linker was smart enough to just link in the functions used from the obj file.
Not so. All code from each obj file is included used or not if it is linked in.
Even a minor change to one obj module means recreating your library. How to tell versions apart.
The need to maintain TWO libraries 32/64.
With source it can be just just one.
In my opinion I don't think many Fb coders are aware of the Power of Private. I was not.
The Fb way to do things as you say is the least common denominator for Win32/64, Linux, And DOS.
James
Thanks James, excellent commentary.
Here is a good explanation that confirms what you are saying:
Quote
If the library is a shared object or DLL, then everything in the library is loaded, but at run time. The cost in extra memory is (hopefully) offset by sharing the library (really, the code pages) between all the processes in memory that use that library. This is a big win for something like libc.so, less so for myreallyobscurelibrary.so. But you probably aren't asking about shared objects, really.
Static libraries are a simply a collection of individual object files, each the result of a separate compilation (or assembly), and possibly not even written in the same source language. Each object file has a number of exported symbols, and almost always a number of imported symbols.
The linker's job is to create a finished executable that has no remaining undefined imported symbols. (I'm lying, of course, if dynamic linking is allowed, but bear with me.) To do that, it starts with the modules named explicitly on the link command line (and possibly implicitly in its configuration) and assumes that any module named explicitly must be part of the finished executable. It then attempts to find definitions for all of the undefined symbols.
Usually, the named object modules expect to get symbols from some library such as libc.a.
In your example, you have a single module that calls the function a(), which will result in the linker looking for module that exports a().
You say that the library named A (on unix, probably libA.a) offers a() and b(), but you don't specify how. You implied that a() and b() do not call each other, which I will assume.
If libA.a was built from a.o and b.o where each defines the corresponding single function, then the linker will include a.o and ignore b.o.
However, if libA.a included ab.o that defined both a() and b() then it will include ab.o in the link, satisfying the need for a(), and including the unused function b().
As others have mentioned, there are linkers that are capable of splitting individual functions out of modules, and including only those that are actually used. In many cases, that is a safe thing to do. But it is usually safest to assume that your linker does not do that unless you have specific documentation.
Something else to be aware of is that most linkers make as few passes as they can through the files and libraries that are named on the command line, and build up their symbol table as they go. As a practical matter, this means that it is good practice to always specify libraries after all of the object modules on the link command line.
Quote from: James Fuller on July 05, 2016, 11:53:18 AM
The need to maintain TWO libraries 32/64.
With source it can be just just one.
Ah, yes, I can see this as being a huge pain the butt. Likewise, if the use of PRIVATE was better known then the source code route would be most advantageous to most people. Also, using source files alleviates having to deal with COMMON between modules. I have learned also that classes when shared between modules can NOT have constructors or destructor. This also implies that you can give your class default member values when you create your TYPE. You basically need to have another function in your class that you explicitly call in your code after the instance of your class is created in order to initialize the values in your TYPE.
Having said all that, the use of modules does seem to introduce an added level of complexity that may not be beneficial in the long run. I have attempted to create a version of the editor project that is 100% based on a main file and then compiled object files for all other code. It works but it is not as intuitive as an all source code approach. I have noticed though that there are areas where I can create independently compiled object files but the added compile speed advantage is not really worth the trade-offs.
I am going to leave the functionality in the editor in case people want to pursue that type of code development. Large projects will benefit from it but for the most part I am thinking it may be the exception rather than the rule unless you are a purist who always develops code one way. Having the ability in the editor will also help those people who want to write and share libraries of compiled code without also having to share the source code (granted, you don't see much of this in the FB community or open source community in general).
> In my opinion I don't think many Fb coders are aware of the Power of Private. I was not.
There is not a clear indication in the help file, that only says:
Quote
In procedure definitions, Private specifies that a procedure has internal linkage, meaning its name is not visible to external modules.
I discovered it because this post in the FB forum: http://www.freebasic.net/forum/viewtopic.php?t=23405
Quote
fbc already removes unused private procedures/variables, but that's pretty much it. There are no plans to improve this on the fbc side as far as I know, but of course with -gen gcc/llvm it will be done nevertheless (just not by fbc, but by gcc/llvm).
The "fbc already removes unused private procedures/variables" part is what pushed me to continue working with FB, that I had stopped because I didn't wanted having hello world type tests of more than 1 Mb. If you're going to use libraries, then Private no longer can be used.
Currently, CWindow has only conditional defines for MDI, but I have further plans, like an Ole Container control. There is one feature of the Ole Container that can only be activated at creation time, meaning that I would need to always include the code of this control, whether I may need it or not, or write a separate class for it.
I find the library system as outdated as using tabs in the source code to save some bytes of disk space (useful when we used floppy disks, but not today). I also prefer the use of "LIB" or "IMPORT" in the declares, instead of these annoying import libraries.
Thanks Jose, points well received. I'm happy that you, me and James had this conversation today.
:)
Here is a little gold nugget I discovered today while browsing the Scintilla documentation. You can get a direct pointer to the internal Scintilla text buffer. The call returns a byte pointer but because the call sets up the buffer with a null terminating character, we can cast that pointer to a ZString Ptr allowing us to save the whole buffer without first having to copy it to a string variable.
Dim psz As ZString Ptr
Dim As Long f = Freefile
Open "_test.txt" For Output As #f
psz = Cast( ZString Ptr, SendMessageW(hEdit, SCI_GETCHARACTERPOINTER, 0, 0) )
Print #f, *psz
Close #f
Or, we could just manipulate the buffer byte-by-byte...
Dim As Byte Ptr pByte = Cast( Byte Ptr, SendMessageW(hEdit, SCI_GETCHARACTERPOINTER, 0, 0) )
Dim As Long nLen = SendMessageW(hEdit, SCI_GETTEXTLENGTH, 0, 0)
Dim As Long f = Freefile
Open "_test.txt" For Output As #f
For i As Long = 0 To nLen - 1
Print #f, Chr(*pByte);
pByte += 1
Next
Close #f
Just a joke... or not?
Dear new FB user,
You come here looking for a BASIC compiler because you think that BASIC is the easiest language to learn and use. You're right, but we, the people that are making the compiler, are C programmers, and our life as programmers has been very rough, so we are going to make your programming experience with FB as nasty as we can.
We have implemented BYREF, but we aren't going to use it at all. No one of our translated API headers has a single BYREF parameter. Why to let you to just pass the variable name when we can force you to have to add a @ in front of it?
BASIC programmers are used to just write a declare with a LIB or IMPORT clause that let's them to call the function immediately, but that's too easy and, therefore, little professional. Instead, you have to make a .def file and an import library. But, of course, we aren't going to provide you all the tools you need. You will have to search the web to see if you find one that works. After reading about the subject, you find one of the recommended tools to make the .def file, but alas, poor Yorick!, it GPFs when you try it. You find the second recommended tool, but the linker doesn't like the library made with it, although it won't tell you why or what does not like. There is a third tool, but doesn't work with DLLs, so you have to download the Windows SDK to get the LIBs. Another little inconvenience is that the tool that works is only available in source code, so you have to learn C programming to compile it or beg a C programmer to do it for you. We never promised you a rose garden, did we?
If you're a foreigner that speak one of these strange foreign languages (we don't object to foreigners speaking a foreign language, but why don't speak the same foreign language all of them?), you're doomed. We have recently added unicode support, but only for null terminated strings. This way, you're going to feel the pain of ansi C programmers when have to deal with strings. BASIC, with its dynamic strings, makes it too easy. Real programmers have to allocate, deallocate and copy memory using pointers, and enjoy the joys of GPFs, buffer overruns and difficult programming.
The Unicode conversions will always use CP_ACP, without letting you to choose the code page, so if you really want to use unicode, forget automatic conversions and use the Windows API. These automatic conversions are only useful to those that don't need them and that think that unicode is simply a way to waste memory by adding a null in front of every character.
We are also going to force you to use CAST once or twice in almost every line of code. It is annoying, but that is the way that real programmers work. A guy even proposed more strict checking, but we thought that his proposals were a bit too sadistic.
"Abandon all hope, ye who enter here."
BEST. POST. EVER. :) :) :)
That just about sums it up!
I will upload more source code tomorrow. I am working on a Function List for the editor. I am going to make it somewhat like the ownerdrawn listbox in the JellyFish Editor that displays subs/functions in a multicolumn format. That is a simple an unobtrusive list. I have already written the code that generates a fast linked list of sub/function names and line numbers for each document as it loads in the editor. Using the code I posted earlier that accesses the Scintilla text buffer directly, I was able to create the list extremely fast. That's a good thing because whenever a document is modified and saved then the list for that document will be destroyed and a new one created. That process needs to be lightning fast.