FLTK logo

STR #2308

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 Home  |  Articles & FAQs  |  Bugs & Features  |  Documentation  |  Download  |  Screenshots  ]
 

Return to Bugs & Features | Roadmap 1.3 | SVN ⇄ GIT ]

STR #2308

Application:FLTK Library
Status:1 - Closed w/Resolution
Priority:3 - Moderate, e.g. unable to compile the software
Scope:2 - Specific to an operating system
Subsystem:Core Library
Summary:Compiling FLTK 1.3 with mingw-w64
Version:1.3.0
Created By:odinsbane
Assigned To:AlbrechtS
Fix Version:1.3.0 (SVN: v7982)
Update Notification:

Receive EMails Don't Receive EMails

Trouble Report Files:


Name/Time/Date Filename/Size  
 
#1 odinsbane
05:44 Jan 22, 2010
changes.txt
11k
 
 
#2 yuri
10:35 Oct 01, 2010
fltk-1.3.x-r7709-mingw64.patch
12k
 
 
#3 yuri
07:48 Oct 04, 2010
fltk-1.3.x-r7709-fl_long.patch
18k
 
 
#4 AlbrechtS
15:21 Nov 28, 2010
fl_intptr_t-r7907.diff
10k
 
     

Trouble Report Comments:


Name/Time/Date Text  
 
#1 odinsbane
05:44 Jan 22, 2010
I compiled FLTK with mingw-w64 and I found a couple errors that needed to be fixed.  There were 3 errors one of them was repeated.

i) casting (void*) to long -> fixed by usings <stdint.h> and intptr_t
ii) casting HINSTANCE to int -> fixed by using INT_PTR
iii) linking wsock32 fixed by using ws2_32

Here is a diff file of two fltk-1.10 directories after an auto configure with cygwin. ( I manually removed the .o file references since the -x ".o" wouldn't ignore them for some reason.)

mbs
 
 
#2 d.zimmer
18:08 Jan 24, 2010
Your fix #1 will change the API, so it might be ok for 1.3 but not 1.1

For many compilers (eg. VC), this is just a warning, not an error.  It think can be silenced by:

-  long argument() const {return (long)user_data_;}
+  long argument() const {return (long)(intptr_t)user_data_;}

If you are using gcc, I think it can be downgraded to a warning using -fpermissive

Don.
 
 
#3 odinsbane
04:30 Jan 26, 2010
Yes the other way works fine, casting to intptr_t then to long. I'm working (very slowly) on compiling 1.3 but it has the some of the same casting issues.  (the guys at the #mingw-w64 say its one of the most common issues right now.)

thanks
mbs
 
 
#4 matt
10:58 Jan 31, 2010
FLTK 1.1 does not officially support 64 bit compilation. It works in pretty much all cases anyway, but we decided not to modify the code anymore. FLTK 1.3 should compile 64 bit, though.  
 
#5 matt
02:03 Apr 05, 2010
Is this still an issue? Is intptr_t a good solution?  
 
#6 odinsbane
13:29 Apr 05, 2010
I moved to 1.3 and I had to go through and make the changes, which seemed to work though it was a bit troublesome.  The suggestion by don worked, by casting to an intptr_t then to a long.  I suspect using the intptr_t seems to offer better 32bit/64bit support, but really I don't know, I just made a small interface. 

Thanks
 
 
#7 HenryN
16:56 Jun 11, 2010
Here is a patch that is generally a better choice as the current pointer cast:
===================================================================
--- src/fl_open_uri.cxx (revision 7637)
+++ src/fl_open_uri.cxx (working copy)
@@ -114,7 +114,7 @@
 #ifdef WIN32
   if (msg) snprintf(msg, msglen, "open %s", uri);
 
-  return (int)ShellExecute(HWND_DESKTOP, "open", uri, NULL, NULL, SW_SHOW) > 32;
+  return (int)(ShellExecute(HWND_DESKTOP, "open", uri, NULL, NULL, SW_SHOW) > (void*)32);
 
 #elif defined(__APPLE__)
   char *argv[3]; // Command-line arguments
 
 
#8 yuri
07:10 Oct 01, 2010
hm. intptr_t works, but :

void cb_smth(Fl_Widget*,long);

Fl_Menu_Item itm[]={
...
{"abra",0,(Fl_Callback*)cb_smth,1},
...

cause an error in conversion from void (*)(Fl_Widget*,long int) to void (*)(Fl_Widget*,void*)

it seems that we must use _int64 instead of long on WIN64 platforms
because sizeof(long)==4 but sizeof(void)==8.
 
 
#9 yuri
07:38 Oct 01, 2010
we must change long to intptr_t in all callbacks functions.  
 
#10 AlbrechtS
05:07 Oct 02, 2010
intptr_t seems to be defined in C99 [1] and in c++0x [2], but both definitions are *optional*. Citation from [1]:

7.18 Integer types <stdint.h>
 ...
7.18.1.4 Integer types capable of holding object pointers

The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

intptr_t

[... similar text for uintptr_t follows ...]

These types are optional.

-- end of citation --

I conclude that we would need a configure test and an own typedef that would fall back to something like "long" if intptr_t is not defined, *even* if we agree that we can use at least the C99 standard.

Can we assume that we will find intptr_t on all current 64-bit systems? If yes, then we could use the above mentioned configure test and typedef and use it wherever applicable, but if not... I don't know.

Note: In c++0x these type are defined in the header <cstdint> with namespace std::, but I believe that c++0x is not yet released (is it?).

---
Drafts of standards:
[1] http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
[2] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3126.pdf
 
 
#11 greg.ercolano
19:30 Oct 03, 2010
A few suggs:

In cases where sizeof(void*) >= sizeof(long), then I we can surely just use eg. memcpy() or whatever to save/retrieve longs from the void* 'data buffer' safely.

In cases where sizeof(void*) < sizeof(long), then I think the simple
solution is to have an #ifdef that simply adds a long variable called 'argument_' to Fl_Widget, and have argument() manipulate that.
 
 
#12 yuri
07:51 Oct 04, 2010
one of the possible way to solve the problem define fl_long type.

see patch.

from my point of view it's the simplest solution of this problem
 
 
#13 AlbrechtS
07:57 Oct 04, 2010
Whatever we do internally to store the value, please remember that the callback will always be called with only *one* calling convention: using

  callback_(Fl_Widget *,void *)

Storing anything in a union (as suggested elsewhere) doesn't help much either, because we can use only one of the union's members for calling the callback.
 
 
#14 greg.ercolano
12:51 Oct 04, 2010
Possibly the sugg of using a union was for conversion from
long <-> void* only in the argument() method, eg:

#include <stdio.h>
class Fl_Widget {
    void *userdata;
public:
    Fl_Widget() { userdata = 0; }
    void argument(long val) {
        union { void *v; long l; } vl;
        vl.l = val; // convert long..
        userdata = vl.v; // ..to void*
    }
    long argument() const {
        union { void *v; long l; } vl;
        vl.v = userdata; // convert void*..
        return(vl.l); // ..to long.
    }
};
int main() {
    Fl_Widget w;
    w.argument(305419896L); // aka. 0x12345678
    printf("Arg=%ld (%lx)\n", w.argument(), w.argument());
    printf("sizeof(void*)=%lu\n", sizeof(void*));
    printf(" sizeof(long)=%lu\n", sizeof(long));
    return(0);
}

    Even if sizeof(long) < sizeof(void*) that should work.
    (I tried above technique with a char <-> void* instead of long
    to simulate that condition, and seemed to compile/run OK on linux
    and windows)
 
 
#15 AlbrechtS
01:15 Oct 05, 2010
@Greg: Yes, of course your code version works, because you are always accessing (reading) the union in the same way as you stored the value. But you're missing the point that I wrote above: the callback *always* uses the full user_data_ value and calls the callback function with this as the second argument. If sizeof(long) < sizeof(void*) in your code, then the extraneous part in the void* part of the union is undefined. Accessing it via the argument() method is okay, but if we would call the callback via callback_(Fl_Widget *, user_data_), then that undefined part would be used in calling the callback. This *might* be okay as long as the callback is defined as my_callback(Fl_Widget*, long), but what if it is defined as my_callback(Fl_Widget*,void *v), and the code casts the given argument like "long my_arg = (long)v" ? What if the same is done on a big-endian and on a little-endian machine?

Please understand me right: I don't want to say that it wouldn't work in some or all cases as expected, but we would enter the gray zone of undefined (maybe implementation-dependent) behaviour of the code. At least...
 
 
#16 AlbrechtS
01:26 Oct 05, 2010
@Yuri: the "fl_long" patch looks much better to me than the previous one. Of course, the windres change in test/Makefile can't be done this way, but most of the other code looks good to me.

However, this *does* change the API for Win64 targets, since then all callback-related functions that used and expected a long now would use an intptr_t type, which differs in size from a long on a Win64 system. This changes the documented interface.

This would only concern users who port to Win64, but OTOH these users might have portability issues if they also want to use the code on other platforms. Maybe...

If we would go this way, we'd at least have to document this change thoroughly, but then this _could_ be one way to go, IMHO. Maybe the cleanest.

Other opinions?
 
 
#17 yuri
02:32 Oct 05, 2010
> the windres change in test/Makefile can't be done this way

hm. it's only do for cross-compiling. i forgot remove it from this patch

> this *does* change the API for Win64 targets ...
this only need to rebuild projects.

but intptr_t have the same size as void* and porting to win64 from other platforms will require only replace long to fl_long (this need to be documented)

the similar way is used at others toolkits gtk/glib or qt introdusing its own types.
 
 
#18 AlbrechtS
01:48 Nov 19, 2010
I'm working on a patch now, based on Yuri's idea using an own typedef
(fl_long), but I'm also trying to avoid changing the API, so that
Fl_Widget::argument() still returns long. I have a working proof of
concept, but this still needs some cleanup. I'll provide a patch shortly.

I also changed the title (summary) to reflect FLTK 1.3 instead of FLTK 1.1.10, because this is not going to be implemented in FLTK 1.1.
 
 
#19 yuri
09:26 Nov 19, 2010
i think there is no reason leave return type of argument to be long.
it may cause value lost of value in some future codes.

if we decide use typedef fl_long we must use it everywhere to avoid future errors.

P.S. I think that on 'normal' systems this will only be a 'cosmetic' changes and we only must recomended use of fl_long in fltk manual (and use in in all examples of course).
 
 
#20 matt
13:35 Nov 27, 2010
Albrecht, you said: This *might* be okay as long as the callback is defined as my_callback(Fl_Widget*, long), but what if it is defined as my_callback(Fl_Widget*,void *v), and the code casts the given argument like "long my_arg = (long)v" ? What if the same is done on a big-endian and on a little-endian machine?

To answer your questions: nothing is going to happen. As long as I use "long" to read and write, and the "void*" is equal in size or bigger, the "junk" bits will be clipped by the casts, no matter if that will be the first bits or last bits (MSB, LSB). The "union" approach would also always work.

I feel like this is an overly protective default compiler option. The user should set this to a warning, if at all.

Oh, and there is a perfect solution, too: we can have two member variables, a pointer AND a long. But that needs more space and would be incompatible to existing code.
 
 
#21 AlbrechtS
09:12 Nov 28, 2010
Matt, you wrote:

> To answer your questions: nothing is going to happen. As long as I
> use "long" to read and write, and the "void*" is equal in size or
> bigger, the "junk" bits will be clipped by the casts, no matter if
> that will be the first bits or last bits (MSB, LSB). The "union"
> approach would also always work.

I'm afraid that I disagree here. First, the point was that we were talking about the case that sizeof(void*) > sizeof(long). The case "=" is trivial. Second, I was writing about a case where you use the "long" union member to write and the "void *" union member to read the userdata field. The former is possible (and we can't prevent it) by the user calling widget->argument(int), and the latter is the way a callback is called by FLTK. Then, on a big endian system, writing the long union member would write the first 4 bytes only (the following 4 bytes are undefined). When FLTK calls the callback, it uses the "void *" member variable, and this means that the "LSB" will be the last byte (big endian), and thus the last 4 bytes will become the low order 4 bytes of the void * pointer. Casting this to a long in the callback will result in 4 undefined bytes.

Strictly spoken: a union's value is undefined, if you use another member variable to read than you used to write, and we wouldn't be able to control this because of the different calls (argument() and userdata()) that are available to set the value.

Fortunately, this would probably be moot, since the only systems with sizeof(long) < sizeof(void *) are Windows systems, and AFAIK Windows doesn't work on big endian machines. ;-)

But anyway, I recommend not to use a union for the given reasons.

---

Matt, you also wrote:

> Oh, and there is a perfect solution, too: we can have two member
> variables, a pointer AND a long. But that needs more space and would
> be incompatible to existing code.

We could do this from an ABI point of view now, but we would pose a new restriction on setting the userdata (aka. argument()) value and we would probably need to differentiate the callback signature we call depending on which way was used to set the userdata value. At least we would also need a flag that tells us which of the variables was set in the last call. If we do that, then we can also use a union, because we can then use the same member for reading that was used for writing. Or something similar. ...
 
 
#22 AlbrechtS
09:35 Nov 28, 2010
Yuri, you wrote:
> i think there is no reason leave return type of argument to be long.

I think that we should keep the API (literally) so that we keep the 'long' return type. This way most user's won't need to change any code or other data types.

> it may cause value lost of value in some future codes.

The only problem is with Windows 64bit systems, and users compiling code for these systems need to handle that "long/pointer incompatibility" anyway.

> if we decide use typedef fl_long we must use it everywhere to avoid
> future errors.

My intention is to have the least impact on application developers for the transition from FLTK 1.1 to 1.3. We decided that FLTK 1.3 should be API compatible as much as possible, so that FLTK 1.1 source code compiles well with FLTK 1.3. Again, this will not be given for users that also switch from 32-bit Windows to 64-bit Windows systems, but this is its own problem. Taking this as a reason to change the API for all users is not what I think is appropriate now.

> P.S. I think that on 'normal' systems this will only be a 'cosmetic'
> changes and we only must recomended use of fl_long in fltk manual (and
> use in in all examples of course).

It might be true that most of the code will compile anyway (maybe with warnings), but why would we want to change the API w/o need, if there's a way that we can fix the issue w/o doing so?

Having said that: yes, I agree that we should think about changing the callback related API and semantics in a future version of FLTK. But IMO this should not be FLTK 1.3. And if we do, then we should do it "The Right Way".

P.S. I hope that I can post my version of a patch during the next few hours...
 
 
#23 AlbrechtS
15:21 Nov 28, 2010
Please see attached file fl_intptr_t-r7907.diff for my modified patch. This does not change the API and uses a similar typedef as Yuri's patch. I decided to call it 'fl_intptr_t' instead of 'fl_long', because it's similar to intptr_t, but that's maybe a matter of taste. I used argument() instead of a cast, where applicable. Since this doesn't change the API, the effective patch is also much smaller.

I tested it on Windows (native and Cygwin/mingw-w64) and Ubuntu (32 and 64 bit version) successfully. There are two "FIXME's" included, because this may be changed, if we can find a better place for the typedef than in Fl_Widget.H.

Comments and test results welcome.
 
 
#24 yuri
12:30 Dec 03, 2010
fl_intptr_t is the better name then fl_long.

but i think that we can safely change all long to fl_intptr_t in callback related function. Old fltk-1.1 code will be compiled without problen on all suppoted platforms exept mingw64.
 
 
#25 matt
10:47 Dec 06, 2010
The patch looks ok to me.  
 
#26 AlbrechtS
10:58 Dec 06, 2010
I just posted a request for comments in fltk.development regarding whether we should change the API (use Yuri's patch) or not (use my patch) to solve this issue. Please read this post and give your votes. I'd like to finalize this STR and apply one of the patches ASAP. Thanks.

My RFC in fltk.development: <http://www.fltk.org/newsgroups.php?gfltk.development+v:11075>

Full thread (search): <http://www.fltk.org/newsgroups.php?gfltk.development+Q%22RFC+-+STR+%232308+-+To+change+or+not+to+change+the+callback+API%22>
 
 
#27 AlbrechtS
03:39 Dec 07, 2010
We have 4 votes against changing the API - thanks to all that took the time to read and vote. I'll go ahead and finalize my patch and commit it when time permits.  
 
#28 AlbrechtS
04:46 Dec 08, 2010
Thanks to HenryN for the suggested fix for src/fl_open_uri.cxx - this is really a better solution.

I committed this one separately in svn r7976, since it is an independent improvement. More to follow...
 
 
#29 AlbrechtS
06:19 Dec 08, 2010
Fixed in Subversion repository.

I committed the changes in svn r 7978 and hope that this fixes all warnings and errors. I tested on Windows and Linux, both 32-bit and 64-bit, and found no problems compiling and running (some) tests.

Please test and report any remaining problems. Thanks.

If there are no reports during the next few days, this STR will be closed.

There's a small remaining issue: the new typedef's fl_intptr_t and fl_uintptr_t should be document for Win64 users so that they know how they can do the necessary casts in their own software. I'll do this later, independent of the status of this STR.
 
 
#30 yuri
12:12 Dec 08, 2010
in branches/branch-1.3/test/line_style.cxx

(long)(choice[0]->mvalue()->argument())
... etc

casting seams unnecessary.
 
 
#31 AlbrechtS
15:52 Dec 08, 2010
Yes, that (unnecessary casting) is correct, thanks for pointing this out. I'll fix this...  
 
#32 AlbrechtS
16:12 Dec 08, 2010
Done: svn r7982.  
     

Return to Bugs & Features ]

 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.