-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Win: define Win32 API functions #4832
Conversation
src/lib_windows.cr
Outdated
|
||
require "winerror.cr" | ||
|
||
data = uninitialized LibWindows::WSAData |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be a top-level variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove these lines because as I see nothing from Winsock dll is used.
src/lib_windows.cr
Outdated
@@ -0,0 +1,253 @@ | |||
@[CallConvention("X86_StdCall")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a quick question, have we tried without this? If we're using --target x86_64-pc-windows-msvc
the default calling convention for everything should be X86_StdCall
so it should work without.
src/lib_windows.cr
Outdated
end | ||
|
||
struct WIN32_FIND_DATA_A | ||
dwFileAttributes : DWord |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renaming these struct members to be more crystally such as file_attributes
here would be great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we should stick to same namings. Reasons:
- It's easier to lookup for documention;
- Avoids juggling with different names;
- Bindings should eventually be generated automatically; we shouldn't have to rewrite anything if/when that happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just my 2 cents. I partly agree. Struct names have to be the same due to Microsoft documentation. But struct member naming can be changed because:
- otherwise they look alien
- it's still easy to find them in documentation due to struct naming
- I don't think this binding will be regenerated eventually (because API aren't changed for decades and other reasons). But even so, it would be easy to keep previous changed names during regeneration (it's just simple engineering problem)
And more importantly, what to do with the current function naming, for example:
fun duplicate_handle = DuplicateHandle(...)
Shoud I rename duplicate_handle as DuplicateHandle?
Sorry for long reading.
src/winerror.cr
Outdated
@@ -0,0 +1,2104 @@ | |||
class WinError < Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deeply disagree with creating a WinError
class. Errno
is platform-specific, and it needs to go. Exception hierarchy should never depend on the platform you're running on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this. The problem is that errno also exists on Windows and it's used for C functions like _open link and Errno class is already working for Windows. So mostly Win32 API functions use GetLastError, "posix" subsystem (some functionality will be used in crystal) uses errno. So how to use one class for these different things simultaneously?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You somewhat abstract system errors or map one to the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll try to figure out then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now mapping to errno will work but we must remove errno before the first release. We should abstract the exception hierarchy to be platform specific. There's a good document on how python did this that we can take inspiration from. Doing that is beyond the scope of this pr though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few rules I would like this to have, following the the existing platform specific rules for POSIX systems:
- Bindings should live under
src/lib_c/arch-sys-abi
, for examplesrc/lib_c/x86_64-pc-win32/c
(I'm not sure of the exact target) andsrc/i686-pc-win32
. - File and directory structure should follow the C headers counterpart (allowing to eventually generate these automatically).
- Keep exact naming of structs and fields (just like you did); it simplifies looking for documention.
This is all so such bindings can be generated automatically, make sure each architecture has a specific set of bindings (they usually have tiny differences) and documentation for and definitions in the original C headers can be found quickly and easily.
The correct target is |
Vendor in target triples is decorative and can be skipped safely, which we're doing in Crystal. We only keep Looking into the rust code, the windows targets seem to be the following, with a translation to GNU targets (for GCC?):
Since the vendor should be omitted, it would seem the target should be |
@ysbaddaden The problem is we don't just keep |
FYI, in win branch this way is used to find windows target path. |
I'm no sure. Did I fulfill the requests or I need to do something else? |
You can't assume
In fact, you don't need to change anything in Now, you can't assume |
If I run |
@txe "x86_64-windows-msvc" is the correct triple, but you can't define all triples containing windows to be that. |
I installed MSYS2 and installed LLVM (mingw-w64-x86_64-llvm) there. This version reports |
src/winerror.cr
Outdated
|
||
def winerror_to_errno(winerror) | ||
case winerror | ||
when 2; return 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bunch of magical numbers. I have no idea what they mean. Where do the value come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an undocumented function _dosmaperr. Python uses this functions to generate a mapper. Because the mapper has not be changed for 6 years, I supposed it's quite correct and just copied those numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great if you could replace these numbers with their respective constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
@@ -27,6 +27,7 @@ class Crystal::Program | |||
set.add "freebsd" if set.any?(&.starts_with?("freebsd")) | |||
set.add "openbsd" if set.any?(&.starts_with?("openbsd")) | |||
set.add "unix" if set.any? { |flag| %w(cygnus darwin freebsd linux openbsd).includes?(flag) } | |||
set.add "win32" if set.any?(&.starts_with?("windows")) && set.any? { |flag| %w(gnu msvc).includes?(flag) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use the "windows" flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason is given in #4832 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I didn't see that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is starting to look very good.
I just personally wish functions, structs and fields naming would keep their original form: SYSTEMTIME
, TIME_ZONE_INFORMATION
, wDayOfWeek
, ...
The problem are functions, since Windows decided they should be CamelCase... maybe prefix them with an _
or keep them as underscored...
src/winerror.cr
Outdated
when 267; return 20 | ||
when 1816; return 12 | ||
else return Errno::EINVAL | ||
when ERROR_FILE_NOT_FOUND ; return Errno::ENOENT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need semicolons. In fact you don't even need return
:
when ERROR_FILE_NOT_FOUND then Errno::ENOENT
daylight_bias : Long | ||
end | ||
|
||
struct FileTime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplication: there is already FILETIME
above.
I didn't get it. Could you give an example of what to do? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks perfect to me!
I believe keeping the original case is important, but I understand that keeping the function names with a leading underscore may not be the best choice. If someone doesn't like that, maybe we can agree on something better. Otherwise, perfect!
Thanks! |
src/winerror.cr
Outdated
buffer = uninitialized UInt8[256] | ||
size = LibC._FormatMessageA(LibC::FORMAT_MESSAGE_FROM_SYSTEM, nil, code, 0, buffer, buffer.size, nil) | ||
details = String.new(buffer.to_unsafe, size).strip | ||
super "#{message}: [WinError #{code}, #{details}]", winerror_to_errno(code) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a tiny subjective nitpick, can we have brackets here (super("#{message}: [WinError #{code}, #{details}]", winerror_to_errno(code))
), it looks weird without (I actually missed the winerror_to_errno
call).
IO::FileDescriptor is implemented |
Where? It's not in this PR. |
It's in my branch, I'm going to make a number of small PRs, so that will help to keep things simple. |
Can't wait for other PRs 😍 |
So why did Windows stuff end up in |
Because everything in |
|
I thought a bit about flag |
Any progress on approving the PR? |
I maintain that we should find a less ugly way of naming these functions than starting with |
@txe Even though function names can start with uppercase, that will only happen in the next release. So until then you'll probably have to use the underscore... |
This reverts commit f416f6c. revert the previous commit
So, I suppose, it doesn't make sense to merge this PR until the next release? |
@txe I think it does make sense. Later we can rename the function names. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we merge?
🎉 |
I'd like to begin merging source from txe/crystal-win:win with master doing it bit by bit.
This PR adds some basic stuff which will be used by code related to Windows:
I suppose the file and function naming is controversial so I'm prepared to change the naming if you give appropriate one.