RE: Generating Function Prototypes
I just reread that section and can't see anything that contradicts the idea that the FFI implementation ignores any header files provided. For example, the phrase:
"implements calls to C functions ... as if a function prototype for the called functions is in scope"
can be interpreted as meaning:
1) Will generate code (by generating machine code directly, by generating C code which is then compiled, or by some other means) which assumes the existence of a prototype _even if the user does not supply one_.
[I see this as the most obvious interpretation of the phrase.]
2) Will generate C code which #includes any header files the user has provided.
[I see this as a less likely interpretation but it seems to be the one you intend?]
Neither, I think. You're taking an operational interpretation of that phrase, when it is really just talking about the semantics of the call. For example: a C function which takes a float as an argument has two possible calling conventions: the argument may be promoted to double (used by the C compiler when no prototype is in scope), or it may be passed as a float (used by the C compiler when there is a prototype). The FFI spec simply says that it is the latter calling convention that is used. Whether a header file is supplied or not should not affect the semantics of the call (I'm pretty sure you agree with this, but we seem to have lost track of this central concept somewhere along the way...). Similarly, whether there is a prototype in scope or not should not affect the semantics of the call. The FFI spec doesn't say this explicitly, but I don't think it needs to.
My reading of the whole section is that every mention of users providing header files and function prototypes refers to compiling the C code being called not the Haskell code doing the calling. The examples of using foreign import don't show the use of header files though the second example needs a header file to compile correctly with GHC.
Only when -fvia-C is on. This is a compiler-specific issue, the FFI doesn't need to say anything about it.
If the intent is that any user-provided header files must be obeyed, then I think the spec should explicitly say:
When a header file containing a function prototype is not provided, the function calling convention employed is undefined. It may vary between different operating systems, between different Haskell compilers, and between different functions.
This is exactly what we *don't* want - the semantics should be specified by the FFI declaration alone, independent of any header files. Again, I'm sure you agree with this - but why do you think that supplying a header file should make a difference to the semantics?
I attach my rewording of the section. Note that I am trying to make it quite clear that an ffi declaration is not portable unless you provide function prototypes except in the special case that your C compiler generates the same code with or without a prototype.
I really don't think the FFI spec needs to say anything about this at all. If a particular compiler requires prototypes in order to generate correct code (such as GHC when going via C) then this is a matter for that compiler's documentation. Indeed, the GHC User's Guide does mention this. [ Heh. Now I remember why I didn't like being able to specify header files in the FFI declaration :-) ]
ps I still think we're better off removing header files completely and having the Haskell type completely determine the calling convention employed. But since I'm not getting any takers on that, I'll settle for pinning down the spec as tightly as possible.
Aha! I must have lost track of the discussion because I can't remember at which point someone said that the Haskell type does not completely specify the calling convention. Cheers, Simon
Simon:
Whether a header file is supplied or not should not affect the semantics of the call (I'm pretty sure you agree with this, but we seem to have lost track of this central concept somewhere along the way...).
I absolutely agree that the ffi design _should_ not allow it to affect it. As I understand it, the current ffi specification/ design _does_ allow it to affect it.
Similarly, whether there is a prototype in scope or not should not affect the semantics of the call. The FFI spec doesn't say this explicitly, but I don't think it needs to.
Yes If that is the intention, then it should say so explicitly. And if that is not the intention then it should say that. What I believe I'm hearing from Manuel is that the presence of function prototypes is allowed to affect code generation. This is what ghc -fvia-C does but (by implication) not what GHC's native code generator does. Even within a single compiler we find both interpretations of the ffi spec... Alastair:
[...] the second example needs a header file to compile correctly with GHC.
Only when -fvia-C is on. This is a compiler-specific issue, the FFI doesn't need to say anything about it.
The ffi spec should be clear about whether GHC (and Hugs and NHC) is allowed to ignore the header file, required to obey the header file or free to do one thing or another.
When a header file containing a function prototype is not provided, the function calling convention employed is undefined. It may vary between different operating systems, between different Haskell compilers, and between different functions.
This is exactly what we *don't* want - the semantics should be specified by the FFI declaration alone, independent of any header files. Again, I'm sure you agree with this - but why do you think that supplying a header file should make a difference to the semantics?
I agree that it is undesirable but I think that it currently _does_ make a difference to the semantics. I'd much rather have a spec where its presence doesn't matter but failing that I'd like a spec which is clear about what you need to do to write portable code.
Note that I am trying to make it quite clear that an ffi declaration is not portable unless you provide function prototypes except in the special case that your C compiler generates the same code with or without a prototype.
I really don't think the FFI spec needs to say anything about this at all. If a particular compiler requires prototypes in order to generate correct code (such as GHC when going via C) then this is a matter for that compiler's documentation. Indeed, the GHC User's Guide does mention this.
As someone who wants to be able to write portable ffi code (actually, I want to be able to steal ffi code originally written for GHC :-), I need to know what ffi code is portable and what is not. I have attempted to describe what is currently portable between the different implementations. I believe it is the job of the ffi to be clear about what it can guarantee and what it cannot.
[ Heh. Now I remember why I didn't like being able to specify header files in the FFI declaration :-) ]
I don't especially like it either - much better to specify it on the compiler command line just as it's better to specify libraries on the command line. Some obvious problems: Suppose a single .hs file contains foreign imports which #include two different header files. Are those header files allowed to have conflicting definitions? What if a foreign import is inlined into another module and it then conflicts with a foreign import in that module. Is it enough for just one foreign import in the file to mention a header file? What about multiple includes of the same file? Is the header file required to use some form of multi-include protection? These all stem from the same problem as library specs - pretending that each header file/ library lives in its own personal namespace when there is a single global namespace.
ps I still think we're better off removing header files completely and having the Haskell type completely determine the calling convention employed. But since I'm not getting any takers on that, I'll settle for pinning down the spec as tightly as possible.
Aha!
I must have lost track of the discussion because I can't remember at which point someone said that the Haskell type does not completely specify the calling convention.
If specifying a header file with a function prototype is allowed to affect the generated code (i.e., the calling convention), then it is clear that the Haskell type does not completely determine the calling convention. And if it does not, let's remove header files from the spec. -- Alastair
participants (2)
-
Alastair Reid -
Simon Marlow