+1 from me!
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/d19b575d-0b4e-4f63-82dd-dc1e8af0f328n%40googlegroups.com.
-- Gonzalo Garramuño ggar...@gmail.com
On 2/26/25 09:28, 'Albrecht Schlosser' via fltk.coredev wrote:
I discussed this already with Matthias and Manolo and we agreed that we want to begin 1.5 development as soon as possible.
- FLTK 1.5 shall be fully backwards compatible to 1.4's API as always (ABI will be changed). The goal is to make the switch from 1.4 to 1.5 as simple as possible for users (application developers): ideally a no-op, just recompile.
+1 Right sounds good.
- Exceptions: Methods, functions, exported variables etc. that were already deprecated in FLTK 1.3.x shall be removed in 1.5.0 (stuff deprecated in 1.4 will be kept in 1.5).
- autoconf/configure/Makefiles will be removed. The only build option is CMake.
- Minimum required C++ standard (compiler) shall be C++17. This allows us to use C++17 features. We must not use C++ features of later standards.
- Minimum supported compiler versions? Must be capable of C++17, for instance VS 2019 or later.
- Minimum supported Windows and macOS versions? To be discussed separately.
As soon as this is decided I will create a new `branch-1.4` which will be the maintenance branch for FLTK 1.4.x (same as now `branch-1.3` for 1.3.x). I will also update the version number in branch `master` to 1.5.0. Developers can keep pushing to `master`.
Fl_String and Fl_Int_Vector classes will be removed and replaced with appropriate C++ classes.
- We may extend the public API with newer C++ features, for instance Fl_Widget::label(std::string) and/or Fl_Widget::label(std::string_view) but this needs thorough consideration to provide a good and useful API, not just "everything you can think of". The latter (std::string_view) requires C++17, for instance.
- We shall define a whitelist of features we allow to use in FLTK development. We should be conservative in our internal usage to keep the code readable and maintainable, i.e. don't use all shiny new C++17 features just because they exist.
- We can remove maintenance burdens like memory allocation and dealing with reallocations etc. by using modern C++ where appropriate. There's no need to change all instances of alloc/realloc/free though. This can be done step by step (or not at all).
- We should add new features as appropriate, for instance multi-touch features on touchscreens and touchpads.
- Dynamic loading of libraries (Windows DLL's) that didn't exist in earlier than the minimal Windows version (to be defined) can be removed and replaced with direct access. This can simplify the code and reduce potential bugs. We can use newer Windows API's which we didn't use because we wanted to support very old Windows versions.
- Similar thoughts apply to macOS: we can remove conditional code for "ancient" macOS versions once we decide which macOS versions we want to support. Maybe those released during the last 5 years?
That's it for today, please vote as written above. Thanks in advance and have a nice day.
Ya, later discussion on all that I think; I have no immediate
response to that other than sounds good, but maybe longer than 5
years? 2017 maybe?
Generally +1 with everything, but can't weigh in on C++17 adoption because
I'm just not sure what it provides (I haven't been keeping up) that fltk internals
absolutely need.
My concern is that C++17 syntax is so different from what we've been supporting
that it might make it very hard to back-port changes to 1.4. Potentially much harder
than our to-date backports, where compiler syntax was never an issue.
TBH, I don't think I really mind about most of this... Except maybe exposing template stuff in the public API (fine to use it internally, just not in the API.)
Why?Because it isn't implemented uniformly across compiler versions, and so there's always a risk of weird compatibility issues.MS used to caution against using it in APIs at all (and AFAIK they still do) because msvc doesn't even implement it in a compatible way between versions.
Dear FLTK developers,
after the release of FLTK 1.4.2 I believe it's a good time to begin FLTK 1.5 development. This means to switch FLTK 1.4 to "maintenance mode" and not to change it anymore except for severe bug fixes. As with branch-1.3 we can release further versions, particularly if necessary for Debian.
We did already decide that FLTK 1.4.x is the last release series for users that want/need to use autoconf/configure/make with all its issues, for instance lack of proper build dependency management. This double maintenance burden (configure + CMake) will be gone.
I discussed this already with Matthias and Manolo and we agreed that we want to begin 1.5 development as soon as possible.
I'd appreciate your comments to my/our proposals. Please let me know if I forgot any short-term items.
Notes:
- This vote is about the first steps only, further development will be discussed later.
...
- We can start FLTK 1.5.0 development in branch `master`.
[etc. ]
To be discussed and decided later:
IMHO our goal to release 1.5.0 should be in this year (2025).
Ian, does this "template stuff" include std::string? Does this mean that we should NOT use std::string in our future API?
On Sun, 2 Mar 2025, 14:43 'Albrecht Schlosser' via fltk.coredevIan, does this "template stuff" include std::string? Does this mean that we should NOT use std::string in our future API?
TBH, I don't know. I only know I was burned by this "in the past", and I think I remember Greg complaining about it here too (long ago...)
Sometime within the last few weeks I was looking something up on msdn and stumbled across a section exhorting users *not* to put STL stuff in API because of issues with msvc versions & compatibility (probably across dll boundaries, based on what I think I was researching at the time!)
Seriously hoping that is old info, where
microsoft is trying to document problems with old libs.
I could say more on those subjects, but won't. Could also be dated info, as compilers now embrace std, and have gotten much better at error reporting and checking. They might report less confusing errors about typos with std stuff.
This sounds like something we need to research...
Someone replied to me privately with this link:
https://stackoverflow.com/questions/5661738/how-can-i-use-standard-library-stl-classes-in-my-dll-interface-or-abi
While the question was asked 13 yrs ago, there's followups
with recent dates, so apparently still an issue.
And if I squint my brain, it's not hard to see how templates,
basically complex macros, expanded at compile time might be
incompatible with precompiled templated code, because templates
are expanded at build time.
So if a pre-compiled FLTK lib is present on a machine that was
compiled with compiler verison X, and the user compiles against it
with compiler version Y, the std templates of X might not use
compatible code with version Y, and therefore hopelessly
incompatible.
And AFAIK, when you #include <string> there's no
versioning going on there, unless perhaps we somehow can encode
the STL (oops I mean std) version# into our #include files, so it
could at least /detect/ an incompatibility. Perhaps there's a way
to do that so the user gets an error or warning, but probably no
way to /solve/ that one.
So it sure sounds like a big NO for exposing /any/ std stuff
in the API, public or protected. Perhaps not even private! (Since
just delcaring a std::string might be a compile time template
expansion).
So that all sucks. I never really liked the STL library, and
now I have a new reason to dislike it.
Perhaps a workaround is to stick with our own Fl_String and
Fl_Array (or whatever), and implement it around a private instance
of the std equivalent, though I'm not sure we can even do that if
we can't even declare the std::string in our .H file.. how else
could we instance it?
IIRC, libraries like Qt have their own string and array
classes (QString, etc) and only uses that in their API calls. I
assumed that was because STL wasn't well supported, but now that
it is, I imagine they're still sticking with their implementations
for this reason.
So, like, wow.
On 3/2/25 10:22, Greg Ercolano wrote:
Perhaps a workaround is to stick with our own Fl_String and Fl_Array (or whatever), and implement it around a private instance of the std equivalent, though I'm not sure we can even do that if we can't even declare the std::string in our .H file.. how else could we instance it?
Or, we just continue as we have, keeping the C interface in
the API, dump our private Fl_String (etc) in favor of using std
internally, and never #include any std stuff in our public .H
files.
As long as the std stuff is expanded at the time the library
is built, we should be OK.
We'd have to be careful about returning C style strings, e.g.
with c_str(), and that might be tricky if we can't
instance the string via the .H files to prevent the variable going
out of scope during the return. Ick.
Also I'm not sure if there's any way to provide C style arrays
from a std::vector though, without making a copy or some such.
Jeez, this just sounds messy all the way around.
The only clean way out I see (other than to leave everything
as is), is to make our own Fl_String and Fl_Array classes so we
can use them publicly, and implement it with our own template
code. Or merge a third party string + array class into our code
like we do with e.g. the svg code.
Curious what others think.
Also I'm not sure if there's any way to provide C style arrays from a std::vector though, without making a copy or some such.
Jeez, this just sounds messy all the way around.
The only clean way out I see (other than to leave everything as is), is to make our own Fl_String and Fl_Array classes so we can use them publicly, and implement it with our own template code. Or [...]
Curious what others think.
// C4251.cpp // Compile with /std:c++20 /EHsc /W2 /c C4251.cpp #include <vector> class __declspec(dllexport) X { public: X(); ~X(); void do_something(); private: void do_something_else(); std::vector<int> data; // warning c4251 };```
FL/Fl_Table.H:170:class FL_EXPORT Fl_Table : public Fl_Group { FL/Fl_Table.H-171-public: ... FL/Fl_Table.H:257: std::vector<int> _colwidths; // column widths in pixels [1] FL/Fl_Table.H:258: std::vector<int> _rowheights; // row heights in pixels [1] ...```
__declspec(dllexport)
or __declspec(dllimport)
.
Instead, only mark the methods that are used directly by a
client."// C4251_fixed.cpp // Compile with /std:c++20 /EHsc /W2 /c C4251-fixed.cpp #include <vector> class X { public: __declspec(dllexport) X(); __declspec(dllexport) ~X(); __declspec(dllexport) void do_something(); private: void do_something_else(); std::vector<int> data; };```
FL/Fl_Table.H:223: class FL_EXPORT IntVector { ... FL/Fl_Table.H:257: IntVector _colwidths; // column widths in pixels FL/Fl_Table.H:258: IntVector _rowheights; // row heights in pixels```
C++ libraries compiled with GNU gcc < 5.0 are incompatible to gcc > 5.0,
VisualC <= 2019 is binary incompatible to VC > 2019.
std::string may be binary incompatible between clang, gcc,
and vc, and between versions of the same compiler.
For example, std::string_view is sometimes implemented a pointer/size, and sometimes as start_pointer/end_pointer. Even the way C++ function signatures are converted into assembler labels is not standardized (name mangling, decorated names).So unless we want to limit ourselves to pure "C", or rewrite everything in Rust, the best we can do is help the user discover if the FLTK library is compiled with the exact same compiler and version that is used to compile the user's app. Everything else is UB.Extending this, if we insist on the "same compiler", we can use anything that this compiler provides in our public headers.
tl;dr: Sorry, C++ has no standardized ABI. You simply can't link a library compiled with one compiler with an executable compiler with a different compiler (or compiler version).
C++ libraries compiled with GNU gcc < 5.0 are incompatible to gcc > 5.0, VisualC <= 2019 is binary incompatible to VC > 2019. std::string may be binary incompatible between clang, gcc, and vc, and between versions of the same compiler. For example, std::string_view is sometimes implemented a pointer/size, and sometimes as start_pointer/end_pointer. Even the way C++ function signatures are converted into assembler labels is not standardized (name mangling, decorated names).So unless we want to limit ourselves to pure "C", or rewrite everything in Rust, the best we can do is help the user discover if the FLTK library is compiled with the exact same compiler and version that is used to compile the user's app. Everything else is UB.
Extending this, if we insist on the "same compiler", we can use anything that this compiler provides in our public headers.
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/b410f593-28e9-40ee-a6e8-cfc642c9a4c5n%40googlegroups.com.
tl;dr: Sorry, C++ has no standardized ABI. You simply can't link a library compiled with one compiler with an executable compiler with a different compiler (or compiler version).
C++ libraries compiled with GNU gcc < 5.0 are incompatible to gcc > 5.0,
VisualC <= 2019 is binary incompatible to VC > 2019.
std::string may be binary incompatible between clang, gcc, and vc, and between versions of the same compiler. For example, std::string_view is sometimes implemented a pointer/size, and sometimes as start_pointer/end_pointer.
Even the way C++ function signatures are converted into assembler labels is not standardized (name mangling, decorated names).
So unless we want to limit ourselves to pure "C", or rewrite everything in Rust, the best we can do is help the user discover if the FLTK library is compiled with the exact same compiler and version that is used to compile the user's app. Everything else is UB.
Extending this, if we insist on the "same compiler", we can use anything that this compiler provides in our public headers.
I believe we need a decision to a "simple" question: Do we allow template stuff like std::string and std::vector in public FLTK headers?
Thank you. To me this was a very helpful answer (not only about C++, but also nice to see that we have lurking long timers ;-).
This reinforces the original idea to require at least C++11, introduce std::string and std::vector into the API, and see how it goes.
I see 1.5 as an introduction of slightly more modern C++ without too many new features, so users can fall back to 1.4 for the time being. As Albrecht said, we want 1.5 out before the end of the year and get quick feedback. If users have no issues with the extend API, on to 1.6 ;-) .
But what would happen if we changed Fl_Group as shown above (in my fork)? Would we force our users to use the same compiler for their FLTK libraries and their executables?
Would nobody be able to build their apps with clang and link against the shared system FLTK library on Debian (for instance) which is presumably built with gcc (or vice versa)?
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/89c51e2e-b98c-4c84-a156-f49d77de9292%40seriss.com.
On 3/3/25 12:36 'melcher....@googlemail.com' via fltk.coredev wrote:
std::string may be binary incompatible between clang, gcc, and vc, and between versions of the same compiler. For example, std::string_view is sometimes implemented a pointer/size, and sometimes as start_pointer/end_pointer.
Really bad.
Even the way C++ function signatures are converted into assembler labels is not standardized (name mangling, decorated names).
If this was (still) the case I wonder how any Linux distro could provide a shared FLTK library. Every distro must decide to use one particular compiler (maybe the current - or oldest supported - GCC compiler of that distribution). Let's assume the Debian distro uses GCC (any version) to build the shared FLTK library which can be installed in binary form. If name mangling didn't work the same when a user program is compiled with clang, then no user could compile their programs with clang and link to the system supplied shared FLTK library (compiled with GCC). Do you really believe that this is still the case? I could try this, but not right now (and if I did, this wouldn't proof that *all* combinations of compilers can cooperate).
So unless we want to limit ourselves to pure "C", or rewrite everything in Rust, the best we can do is help the user discover if the FLTK library is compiled with the exact same compiler and version that is used to compile the user's app. Everything else is UB.
Extending this, if we insist on the "same compiler", we can use anything that this compiler provides in our public headers.
Insisting on the "same compiler" would be hard to do for users deploying their applications as binaries. Static linking could be an option, but are we sure that all template code is compiled together with the program/library and nothing is used from a shared library (C++ runtime) on the target system?
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/bf32fde1-3b5d-47f6-9d08-fe0f4438eb75%40aljus.de.
On Mon, Mar 3, 2025 at 9:52 AM Greg Ercolano wrote:
Can we record the compiler version#/name in our public headers as part of the lib build process, and add warnings if they don't match when someone builds against the pre-built library?
I imagine this can all be done with macro logic.. would have to be very compiler specific though, and be a bit of a maintenance issue, but it might then let us use std freely.
This is absolutely what we did, even though we only shipped static libraries. We would rather have our C++ toolkit customers get a compile time failure (that we could document) vs. undefined runtime weirdness where the link worked but the code didn't really run correctly.
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/cd283fb7-538e-43ea-9e2b-1a026e6bd05e%40aljus.de.
On Mon, Mar 3, 2025 at 8:47 AM 'Albrecht Schlosser' via fltk.coredev <fltkc...@googlegroups.com> wrote:
On 3/3/25 12:36 'melcher....@googlemail.com' via fltk.coredev wrote:
std::string may be binary incompatible between clang, gcc, and vc, and between versions of the same compiler. For example, std::string_view is sometimes implemented a pointer/size, and sometimes as start_pointer/end_pointer.
Really bad.
I don't think this is bad.
This is different compilers taking different approaches to optimization. 'std::string_view' is an area for optimization to avoid unnecessary copies. As long as the API is standardized and people use the API, I'm not sure I see the downside of different implementations internally.
Even the way C++ function signatures are converted into assembler labels is not standardized (name mangling, decorated names).
If this was (still) the case I wonder how any Linux distro could provide a shared FLTK library. Every distro must decide to use one particular compiler (maybe the current - or oldest supported - GCC compiler of that distribution). Let's assume the Debian distro uses GCC (any version) to build the shared FLTK library which can be installed in binary form. If name mangling didn't work the same when a user program is compiled with clang, then no user could compile their programs with clang and link to the system supplied shared FLTK library (compiled with GCC). Do you really believe that this is still the case? I could try this, but not right now (and if I did, this wouldn't proof that *all* combinations of compilers can cooperate).
I wonder whether a "system" library written in C++ is almost an oxymoron. I'm sure there are examples, but it feels like most Linux system libs are C not C++. Certainly, there are Qt libs on machines, but frankly if you want to use the system Qt you probably have to use the system C++ as well - or handle the cross-compatibility yourself.
Certainly if I want to deploy on Linux, I'd be very careful about deps. DLL-hell has certainly become a problem on modern Linux. And a lot of the drive for folks to use Go or Rust is dependency management and the ability to avoid all these shared lib dep problems when deploying. Even on macOS we avoided the homebrew shared FLTK in favor of building our own with a known compiler and then statically linking it in.
If wide ABI compatibility is the ultimate goal vs. long-term API stability (so re-compiles work) then I think C++ in any form is inappropriate.
FLTK seems so much closer to "C with classes" than modern C++, that trying to be both will be hard.A strawman idea would be to move the core to C only then provide an FLTK++ library that uses modern C++ and wraps the C API. This way you could ship a much more stable C API/ABI core lib and the C++ as a wrapper. (Sadly this would break API on both the C and C++ side but would provide a path to a stable ABI).
This would be a ton of work but would also enable more languages via their C FFI. But, wow, that would be a ton of work.
On Mon, Mar 3, 2025 at 10:24 AM 'Albrecht Schlosser' ... wrote:
Is there code you can (i.e. are allowed to) post that gets the compiler name and version for us as a starter so we don't need to reinvent the wheel? Even if you are using closed source, this is maybe not an issue for such "simple macro stuff". Contributions are always appreciated (and thanks again for your previous post). Thanks in advance.
I'm happy to make a branch that can do this, at least a first pass, just so we can see what it might look like. Certainly we did allow ranges of versions when we knew (had tested) that they were compatible.
and CMake makes it easier (for me) to do this.
On 3/3/25 17:23 Bob Tolbert wrote:
Well, as it stands, FLTK is C++ and we can't change this. ABI compatibility is a high goal within minor versions, for instance 1.3.x, but not between 1.4.x and 1.5.x.
FLTK seems so much closer to "C with classes" than modern C++, that trying to be both will be hard.A strawman idea would be to move the core to C only then provide an FLTK++ library that uses modern C++ and wraps the C API. This way you could ship a much more stable C API/ABI core lib and the C++ as a wrapper. (Sadly this would break API on both the C and C++ side but would provide a path to a stable ABI).
The entire idea of FLTK was in the first place to "convert" an existing C library to C++ (and extend it) to allow for inheritance (AFAICT, Matthias and Bill, please correct me if I'm wrong). Moving the core library back to C doesn't sound sensible - in our special case.
This would be a ton of work but would also enable more languages via their C FFI. But, wow, that would be a ton of work.
We know of a Rust port (fltk-rs on github) which is - AFAICT - based on a C API that *wraps* the FLTK C++ library (Mohamed, is this true?). I think there are maybe other language bindings that are based on pure C wrappers. But that's the opposite way and not applicable to the core FLTK library.
Anyway, thanks for all your comments, this is very much appreciated.
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/ec4c00b3-e094-4133-ae7c-ca3dcd8d6137%40aljus.de.
I believe this is true, but (since I'm supporting code with huge variety of ancestry....) what I find *in practice* is that I can pretty much link gcc C++ code from different generations and have it work.As a particular example, one of our old projects is tied to an ancient toolchain that uses gcc-4.3 (which is *old*) but it shares functionality with another project that is "less old" and uses gcc-6.3 and, at least for static linking of .o files and .a archives, the linking works and the code runs.Also, AFAIK, the name-mangling used by gcc and clang _appears_ to be compatible. (I've mixed code from gcc and clang (llvm-12) and it seemed to be OK.)I think the last time I saw gcc API break badly was in the 3.2 to 3.3 transition, and in the 2.95 to 3.0 transition before that. Since then it does seem to have "worked", for the most part!That said, I'm only using "simple stuff" in the API. I'm not using any std:: stuff in the API, so I do not know how consistent that has been.AFAICT, using the std:: stuff "inside" the code seems to be OK - but...
A strawman idea would be to move the core to C only then provide an FLTK++ library that uses modern C++ and wraps the C API. This way you could ship a much more stable C API/ABI core lib and the C++ as a wrapper. This would be a ton of work but would also enable more languages via their C FFI. But, wow, that would be a ton of work.
On Mon, Mar 3, 2025 at 11:20 AM 'Albrecht Schlosser' ... wrote:
On 3/3/25 17:23 Bob Tolbert wrote:
Well, as it stands, FLTK is C++ and we can't change this. ABI compatibility is a high goal within minor versions, for instance 1.3.x, but not between 1.4.x and 1.5.x.
That is a very reasonable goal.
... If moving to pure C is not possible, and staying put is not reasonable, then a path toward modern C++ is the only conclusion [...] then the only decision is the slope of that change. The one good thing about C++ is even if FLTK 1.5 is only up to C++11, a user can use C++17 or later in their app with no problems.
I struggled whether to weigh in but figured you could ignore me.
This is a very important discussion and I'm glad to see it continuing.
On 3/3/25 08:24, 'Albrecht Schlosser' via fltk.coredev wrote:
Is there code you can (i.e. are allowed to) post that gets the compiler name and version for us as a starter so we don't need to reinvent the wheel? Even if you are using closed source, this is maybe not an issue for such "simple macro stuff". Contributions are always appreciated (and thanks again for your previous post). Thanks in advance.
But if not, never mind, this shouldn't be too difficult.
Perhaps an easy thing to do would be to make a separate test
program project makes a few dummy classes that exercises the std
stuff we want to do, and then add macros for the different
compilers, and do some tests across different compilers to verify
what we think we know.
This way if anything comes up it's easy to identify, exercise,
and retool, without getting into all of FLTK's innards.
I recently went down the path of trying to get a MacOS program to link with some parts built with gcc and other parts built with clang / xcode. If both compilation units use std::, it really isn't possible. Fundamentally, this is a libc++ vs libstdc++ problem.
Although there are hacks to gcc to point at the system SDK (libc++), it doesn't work in real life. The upstream gcc project does not support libc++, so they have no problem breaking things without warning. When Homebrew (or some other project) comes along with a fix, they have to fight an uphill battle to get the changes (for an unsupported platform) upstreamed.
In practice, using std:: will limit us to using one compiler per platform. If this is not OK, then some sort of MWE test project should be constructed before major changes to FLTK are undertaken. This test project should then be used to exercise all the toolchain combinatorics that are targeted to see if it is even possible.
I am not an FLTK dev -- just a user. So I don't really think I deserve a vote here.
However, I do have a few thoughts I'd like to share....
I absolutely abhor 'auto'. Some claim it makes code more readable -- in fact it does the opposite. Declaring types is fundamentally documentation. You're documenting (for future developers) exactly what type a variable has -- what information does it contain? what methods and fields are available? it it const or not? etc.
When you use 'auto', you're either saying either:1) I'm too lazy to document the type here. or2) I'm not clever enough to figure out the type here.
Both are bad. Unlike other documentation, declaring types has the advantage that it can not go out of date (as correctness is enforced at compile time).
Fl_SVG_File_Surface *surface = new Fl_SVG_File_Surface(ww, wh, svg);
int main(int argc, char **argv) { // Fl_Window *window = new Fl_Window(340, 180); auto window = new Fl_Window(340, 180); auto box = new Fl_Box(20, 40, 300, 100, "Hello, World!"); box->box(FL_UP_BOX); window->end(); window->show(argc, argv); return Fl::run(); }OK, some prefer to write 'auto *' in this case, but that's IMHO a matter of taste. However it's "easy" to change 'new Fl_Window' to 'new Fl_Double_Window' and to forget to change the variable type. In this case it doesn't matter (bad example), but there are cases where it matters (compilation errors would be the best that can happen).
I am sympathetic to Greg and other developers who must support users on antiquated platforms. Some of my users finally were forced to update from RHEL7 and it was a big step forward. However, choosing to maintain support for deprecated operating systems is potentially a large burden on FLTK's team. In my experience 'many tools' choose to limit support to the OS versions that are still supported (receiving security updates) from the vendor. This trickles down (compilers, Homebrew, Github Actions, etc) such that supporting deprecated platforms may limit our ability or willingness to use continuous integration tools.
I'm not saying that FLTK should not run on old iron. Old programs on old platforms can continue to use FLTK 1.4, 1.3 or 1.1. I simply think we should think hard about the Venn diagram of Win7 / OSX10.4 users who need to run the latest version of FLTK 1.5 apps. It even seems possible that Apple will stop supporting Intel processors before FLTK 1.5 is finished and released.
In my experience, libraries that expose their template system to the user are almost always 'header only'. This effectively eliminates any potential incompatibility with pre-compiled components of any sort. This also effectively forces static linking for said library.
A header-only FLTK would result in smaller binaries vs. static linking -- because only the components used by an app would get built and incorporated.
FLTK might actually be faster and lighter that way.
However, it would ditch any / all benefits of dynamic linking on platforms that use it.
In my experience, dynamic linking of FLTK "at scale" is a myth anyway.1) if you ship your own *.dll or *.so dynamic libraries with your app, you might as well be statically linking.2) platforms that provide system shared libraries (i.e. Linux) are hopelessly out of date in what they package3) platforms that provide system shared libraries (Linux distributions) are hopelessly incompatible with one another
Thanks for all your work,
[rewritten after having a cup of coffee, for better comprehension]:
Perhaps the easy thing to do would be to make a separate test project that makes a few dummy classes to exercise the std stuff we want to use, and then add macros for the different compilers, and do some tests across different compilers to verify what we think we know.
This way if anything comes up it's easy to identify, exercise, and retool, without getting into all of the overhead of FLTKs own code just to exercise a few simple std use cases.
On 3/3/25 10:35, Greg Ercolano wrote:
[rewritten after having a cup of coffee, for better comprehension]:
Perhaps the easy thing to do would be to make a separate test project that makes a few dummy classes to exercise the std stuff we want to use, and then add macros for the different compilers, and do some tests across different compilers to verify what we think we know.
This way if anything comes up it's easy to identify, exercise, and retool, without getting into all of the overhead of FLTKs own code just to exercise a few simple std use cases.
And of course adding the compiler version# macro tests to handle the compiler testing.
We could focus on one to start with, e.g. gcc/clang on linux, do some tests with that for results.
Also, the test program would of course let one build the test suite as a library, then
separately a test program to use the lib that could be compiled with other compiler versions.
I could perhaps start such a project in git and open it up to the devs, if that'd help.
In my mind a first step could be to use CMake to get the compiler ID and maybe version (I don't know how specific CMake can be with that).
-- C_COMPILER_ID GNU -- C_COMPILER_AR /usr/bin/gcc-ar-12 -- C_COMPILER_RANLIB /usr/bin/gcc-ranlib-12 -- CXX_COMPILER_ID GNU -- CXX_COMPILER_AR /usr/bin/gcc-ar-12 -- CXX_COMPILER_RANLIB /usr/bin/gcc-ranlib-12 -- C_COMPILER_ID Clang -- C_COMPILER_AR /usr/bin/llvm-ar-14 -- C_COMPILER_FRONTEND_VARIANT GNU -- C_COMPILER_RANLIB /usr/bin/llvm-ranlib-14 -- CXX_COMPILER_ID Clang -- CXX_COMPILER_AR /usr/bin/llvm-ar-14 -- CXX_COMPILER_FRONTEND_VARIANT GNU -- CXX_COMPILER_RANLIB /usr/bin/llvm-ranlib-14 -- C_COMPILER_ID GNU -- C_COMPILER_AR /usr/bin/x86_64-w64-mingw32-gcc-ar -- C_COMPILER_RANLIB /usr/bin/x86_64-w64-mingw32-gcc-ranlib -- CXX_COMPILER_ID GNU -- CXX_COMPILER_AR /usr/bin/x86_64-w64-mingw32-gcc-ar -- CXX_COMPILER_RANLIB /usr/bin/x86_64-w64-mingw32-gcc-ranlib
On 3/3/25 20:41 Greg Ercolano wrote:
On 3/3/25 10:35, Greg Ercolano wrote:
[rewritten after having a cup of coffee, for better comprehension]:
Perhaps the easy thing to do would be to make a separate test project that makes a few dummy classes to exercise the std stuff we want to use, and then add macros for the different compilers, and do some tests across different compilers to verify what we think we know.
I confess that I don't fully get what you suggest (above). What macros?
__GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__
..and "bake" those into our public .H files with some
"standard" FLTK name, like FL_CPP_VERSION_XXX, where XXX is MAJOR,
MINOR, PATCH or some such, whatever we come up with.
..and then test for these FL_CPP_VERSION_XXX macro names when
user applications build against our library, and compare them to
the gnu compiler's own.
Anything that doesn't match should toss a #warning message,
alerting the user they're using a different compiler than the one
the FLTK library was built with.
Particularly "do some tests across different compilers to verify what we think we know" would likely be a time consuming practice that would involve several (if not all) FLTK devs to test on "different compilers".
How many different compilers can you test with on a particular platform?
This way if anything comes up it's easy to identify, exercise, and retool, without getting into all of the overhead of FLTKs own code just to exercise a few simple std use cases.
??
In my mind a first step could be to use CMake to get the compiler ID and maybe version (I don't know how specific CMake can be with that). Other info can be retrieved by predefined constants such as __cplusplus in a real (compiled) program and the library itself.
This info would be displayed (again, this is only a first step) in our demo 'test/fltk-versions'. As a bonus we'd have two different values for whatever info we display:
(a) the version compiled into the test program
(b) the version queried from the library by a function call.
These versions can be different if the test program is linked against a shared FLTK library.
I'm more or less regularly building FLTK with gcc and clang, and I could build and use shared libraries and executable programs with both compilers to test interaction with each other, just as you suggested (below).
Also, the test program would of course let one build the test suite as a library, then
separately a test program to use the lib that could be compiled with other compiler versions.
Interesting.
Ya, that's the point - to make it easy to test:
o See if we can detect library vs. application compiler
versions and throw reasonable warning errors
o If std in the library can work properly within
major/minor/patch compiler versions across all compilers we
support
o Easy to quickly build/retest without all the noise from
FLTK building across different compilers
For that last item, I could see if we test lots of compilers,
esp on old machines where FLTK build times might be slow, we might
have to weed through lots of compiler warnings unrelated to what
we're testing for, and knowing FLTK devs, we'd get side tracked
trying to solve those, instead of focusing on the std/compiler
version issues.
Just seems to make sense to peel this off as a simple test
suite first, so we can exercise possible std weirdness in the API,
as obviously "there be dragons".
I could perhaps start such a project in git and open it up to the devs, if that'd help.
+1
Assuming the above sounds OK, I can try to put something
together.
Not with cmake though, lol, just simple Makefiles. Might have
to cheat on windows.
I'll start small with just a std::string and std::vector of
ints and strings.
I'm not sure exactly how to craft code that trips up the
compilers, but once I have a skeleton
in place, the devs can play with it.
I take it you mean in a separate repository?
On 3/3/25 12:53, Greg Ercolano wrote:
I take it you mean in a separate repository?
Ya, small test suite separate from FLTK, just to test std stuff used
in a library context, and compiler version macro testing.
I absolutely abhor 'auto'. Some claim it makes code more readable -- in fact it does the opposite. Declaring types is fundamentally documentation. You're documenting (for future developers) exactly what type a variable has -- what information does it contain? what methods and fields are available? it it const or not? etc.
When you use 'auto', you're either saying either:1) I'm too lazy to document the type here. or2) I'm not clever enough to figure out the type here.
Both are bad. Unlike other documentation, declaring types has the advantage that it can not go out of date (as correctness is enforced at compile time).I agree in most points. However, I think that sensible use of 'auto' can be helpful in *some* cases:
(1) Generally I suggest to use 'auto' only in limited cases (short code blocks) where it is (a) obvious what the type is and/or (b) avoids redundancy. Why would you want to write (from a real code example in FLTK):
Fl_SVG_File_Surface *surface = new Fl_SVG_File_Surface(ww, wh, svg);
Using Fl_SVG_File_Surface twice is redundant, makes the line longer and harder to read, and finally it's also error prone. Why the latter, you may think? Well, copy-and-paste bugs etc. happen.
(2) Iterator syntax is complicated and not intuitive. When an object is used only in a 'for' loop that's controlled by an iterator, why bother to write the exact type of the iterator/object?
With Apple everything seems to be possible. For us as library developers there must be a distinction:
(1) Platforms that are officially supported. On these platforms we can run CI tools and FLTK developers can develop and test on these platforms.
(2) On other platforms FLTK *may* (still) work but this is not guaranteed - i.e. these platforms are not "officially supported".
In my experience, libraries that expose their template system to the user are almost always 'header only'. This effectively eliminates any potential incompatibility with pre-compiled components of any sort. This also effectively forces static linking for said library.Good point.
But (sorry for nitpicking) technically you can compile and link a header-only library in a static or shared library (e.g. nanosvg) and use that in your program.
I doubt that this is correct. The memory footprint could be smaller if your previous assumption was true, and that could reduce the loading time. On memory constrained systems paging could be less, but effectively I don't think that a header-only library could have advantages as opposed to static linking (as in FLTK).
However, it would ditch any / all benefits of dynamic linking on platforms that use it.
In my experience, dynamic linking of FLTK "at scale" is a myth anyway.1) if you ship your own *.dll or *.so dynamic libraries with your app, you might as well be statically linking.2) platforms that provide system shared libraries (i.e. Linux) are hopelessly out of date in what they package3) platforms that provide system shared libraries (Linux distributions) are hopelessly incompatible with one anotherThe advantage of dynamic linking is IMHO visible on systems where lots (hundreds) of identical (or just FLTK) applications are running at the same time. Then read-only parts of the shared library may be loaded only once into memory, and read-write parts are only copied (copy-on-write) if/when they are modified. This can save lots of memory.
On 3/3/25 13:45, Rob McDonald wrote:
That is an interesting use case I had not considered. It is a little bit more of a stretch to imagine that application running hundreds of copies on a single machine is an interactive GUI application, but I guess it is possible.
We've had a few users who were eyeballing the FLTK lib size
very carefully.
One balked when the library binary doubled in size (IIRC) due
to some simple change we didn't realize, and we were able to
retool to get that back down.
In one case I think there was an embedded project that was
trying to keep the OS and FLTK apps as small as possible, due to
disk image limitations.
I think tiny core
linux is another such project, in that case to also keep the
disk image small, and where many FLTK apps are the default OS
interactive tools, e.g. system preferences, cpu monitor, clock,
simple text editor, etc, leveraging FLTK's small footprint via
dynamic libs.
I think FLTK should really cater to such uses as much as
possible, as these are aligned with one of our core tenets ("light
weight").
What I've been pitching in my last few posts is to have the FLTK library build access the compiler's version#s, e.g. in the case of gcc/g++:
__GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
..and "bake" those into our public .H files with some "standard" FLTK name, like FL_CPP_VERSION_XXX, where XXX is MAJOR, MINOR, PATCH or some such, whatever we come up with.
..and then test for these FL_CPP_VERSION_XXX macro names when user applications build against our library, and compare them to the gnu compiler's own.
Anything that doesn't match should toss a #warning message, alerting the user they're using a different compiler than the one the FLTK library was built with.
Particularly "do some tests across different compilers to verify what we think we know" would likely be a time consuming practice that would involve several (if not all) FLTK devs to test on "different compilers".
Right, though we're trying to determine if we can use std or not, so we'd want to test this against a few compilers, maybe, just to see what the behavior/error messages are?
How many different compilers can you test with on a particular platform?
I think you brought up gcc vs clang.
And of course on windows, VS verses mingw and whatever else we support.
On Mac, different versions of Xcode across different versions of OSX. I think we may have already encountered some of that with, what was it, "Mac Ports" builds of FLTK vs whatever local compiler the person installing ports used.
In my mind a first step could be to use CMake to get the compiler ID and maybe version (I don't know how specific CMake can be with that). Other info can be retrieved by predefined constants such as __cplusplus in a real (compiled) program and the library itself.
Right, by whatever means we can record the compiler version info, even if it means a shell script that parses the output of e.g. 'clang --version'.
For the test suite we wouldn't even need to dive into cmake, so we can easily test changes, and then when the tests are all good, go for tweaking FLTK's current git.
Just seems to make sense to peel this off as a simple test suite first, so we can exercise possible std weirdness in the API, as obviously "there be dragons".
...
Assuming the above sounds OK, I can try to put something together.
Not with cmake though, lol, just simple Makefiles. Might have to cheat on windows.
Ya, small test suite separate from FLTK, just to test std stuff used in a library context, and compiler version macro testing.
Will hold until the above makes sense, and if there's any requests for specific stuff for the test suite.
On Monday, March 3, 2025 at 11:40:45 AM UTC-8 Albrecht-S wrote:
I agree in most points. However, I think that sensible use of 'auto' can be helpful in *some* cases:
(1) Generally I suggest to use 'auto' only in limited cases (short code blocks) where it is (a) obvious what the type is and/or (b) avoids redundancy. Why would you want to write (from a real code example in FLTK):
Fl_SVG_File_Surface *surface = new Fl_SVG_File_Surface(ww, wh, svg);
Using Fl_SVG_File_Surface twice is redundant, makes the line longer and harder to read, and finally it's also error prone. Why the latter, you may think? Well, copy-and-paste bugs etc. happen.
What is obvious to you might not be obvious to the next person.
The copy/past errors will generally be caught at compile time.
If I want to use my IDE's ability to search for all declarations of a certain type, 'auto' defeats that.
For us as library developers there must be a distinction:
(1) Platforms that are officially supported. On these platforms we can run CI tools and FLTK developers can develop and test on these platforms.
(2) On other platforms FLTK *may* (still) work but this is not guaranteed - i.e. these platforms are not "officially supported".
I'm OK with this distinction, but I think it leaves out the question of whether un-official platforms still get a vote or veto in terms of toolchain, language support, or other processes.
For example, MacOS 10.4 appears to only support up to XCode 2.5 (according to https://xcodereleases.com/ and https://en.wikipedia.org/wiki/Xcode ). That is old enough that XCode was still based on gcc and not clang. It appears that XCode 2.5 was based on gcc 3.3 or 4.0, with 4.0 as the default. GCC 4.0 does not even support C++11 (https://gcc.gnu.org/projects/cxx-status.html).
So, drawing the line of supported platforms isn't just about 'maybe it will work' because of some subtle issue or general bit rot. It is also about drawing some distinct lines in what will and won't work.
In my experience, libraries that expose their template system to the user are almost always 'header only'. This effectively eliminates any potential incompatibility with pre-compiled components of any sort. This also effectively forces static linking for said library.
Good point.
But (sorry for nitpicking) technically you can compile and link a header-only library in a static or shared library (e.g. nanosvg) and use that in your program.
Sure -- as long as the templates aren't exposed through the API.
... I was under the impression that everything in the binary static library file (*.a or *.lib or whatever) ended up in the final binary executable file.
Whereas, in a header-only build, the compiler could do a more fine-grained selection of what to compile and incorporate.
The advantage of dynamic linking is IMHO visible on systems where lots (hundreds) of identical (or just FLTK) applications are running at the same time. Then read-only parts of the shared library may be loaded only once into memory, and read-write parts are only copied (copy-on-write) if/when they are modified. This can save lots of memory.
That is an interesting use case I had not considered. It is a little bit more of a stretch to imagine that application running hundreds of copies on a single machine is an interactive GUI application, but I guess it is possible.
In many situations with multiple copies of the same interactive GUI application running, you're going to want each one to be in a separate sandbox / container as well.
How does FLTK separate the read-only parts from the read-write parts? Even if the actual separation is handled by the compiler/linker/OS,
this seems to be something like data structure memory alignment -- where design decisions in the code implicitly determine what is possible much later on. Are there enough read-only parts that this savings is still realized in practice?
On 3/3/25 15:05, 'Albrecht Schlosser' via fltk.coredev wrote:
One thing you could start with is a class like FL_EXPORT Fl_Group that contains a vector of (widget) pointers. But this is already implemented in my fork as mentioned previously. Did it issue warnings or fail building? I don't think so but I need to check.
I'd appreciate if you proposed something we can use for testing. TIA.
Work in progress here; test lib + test application:
https://github.com/erco77/fltk-std-check
On 3/3/25 17:31, Greg Ercolano wrote:
On 3/3/25 15:05, 'Albrecht Schlosser' via fltk.coredev wrote:
I'd appreciate if you proposed something we can use for testing. TIA.
I nabbed the Fl_Export.H stuff, and will add compiler version checking as I go.
Work in progress here; test lib + test application:
https://github.com/erco77/fltk-std-check
OK, commited something that tests the compiler versions and
throws a #warning.
Currently tested on linux only with g++ (9.x) and clang (10.x)
on my ubuntu 20.04 machine.
Albrecht, give it a try; see the README for how to use.
Might be brittle; this is a first test, it's late, just got it
working. Will revisit tomorrow.
Currently static builds only, but that's still good enough to
test the compiler
check stuff.
I suggest we follow up in the project's git issues, as we did
with Fl_Terminal
to keep the development details noise out of the group.
__GNUC__
__GNUC_MINOR__ __GNUC_PATCHLEVEL__
This is what I have in mrv2:
<< _("With gcc ") << __GNUC__ << endl
#elif defined(__clang__)#endif
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/1e5a6577-3d2c-40ff-8bbe-5c2f708ca6ebn%40googlegroups.com.
-- Gonzalo Garramuño ggar...@gmail.com
On Monday, 3 March 2025 at 20:53:50 UTC, Greg wrote:
__GNUC__
__GNUC_MINOR__ __GNUC_PATCHLEVEL__
So, this (checking the preproc defines) was how I imagined doing this - rather than having CMAKE or etc. figure it out at build time.
That being so, I thought I'd check a few things, to see what this actually finds: clang didn't do quite what I'd expected, TBH; not sure if this is "normal" or an artefact of my weird clang setup...
So, running:
"g++ -dM -E -x c++ test_macro_structs.c | grep -i gnuc "
for one of the older gcc's I have, I get:#define __GNUC__ 6
#define __GNUC_MINOR__ 3#define __GNUC_PATCHLEVEL__ 0
$ touch test_macro_structs.c # create empty file $ g++ -dM -E -x c++ test_macro_structs.c | grep GNUC | sort #define __GNUC__ 12 #define __GNUC_MINOR__ 2 #define __GNUC_PATCHLEVEL__ 0 $ clang++ -dM -E -x c++ test_macro_structs.c | egrep 'clang|GNUC' | sort #define __clang__ 1 #define __clang_major__ 14 #define __clang_minor__ 0 #define __clang_patchlevel__ 6 #define __clang_version__ "14.0.6 " #define __GNUC__ 4 #define __GNUC_MINOR__ 2 #define __GNUC_PATCHLEVEL__ 1
My results are similar, clang also claims to be (compatible with?) gcc 4.2.1:
In practice we can check the __clang_* variables before the __GNUC_* variables (#if ... #elif ... #else ... #endif) and that should do it.