diff --git a/winsup/doc/ChangeLog b/winsup/doc/ChangeLog index 5fbe1be4f..bd4eeefa9 100644 --- a/winsup/doc/ChangeLog +++ b/winsup/doc/ChangeLog @@ -1,3 +1,11 @@ +2013-07-25 Corinna Vinschen + + * gcc.xml (gcc-default: Rename from gcc-cons. Change title. + (gcc-64): New section explaininig differences in programming for + 64 bit Cygwin. + (gcc-gui): Simplify description and aim at UNIX/Linux developers only. + Note that X programming is preferred. Drop example. + 2013-07-21 Corinna Vinschen * new-features.sgml (ov-new1.7.22): Add GetCommandLine and regcomp diff --git a/winsup/doc/gcc.xml b/winsup/doc/gcc.xml index b9039db96..e15862638 100644 --- a/winsup/doc/gcc.xml +++ b/winsup/doc/gcc.xml @@ -4,11 +4,10 @@ Using GCC with Cygwin -Console Mode Applications +Standard Usage -Use gcc to compile, just like under UNIX. -Refer to the GCC User's Guide for information on standard usage and -options. Here's a simple example: +Use gcc to compile, just like under UNIX. Refer to the GCC User's Guide +for information on standard usage and options. Here's a simple example: Building Hello World with GCC @@ -23,29 +22,104 @@ Hello, World -GUI Mode Applications +Building applications for 64 bit Cygwin -Cygwin allows you to build programs with full access to the -standard Windows 32-bit API, including the GUI functions as defined in -any Microsoft or off-the-shelf publication. However, the process of -building those applications is slightly different, as you'll be using -the GNU tools instead of the Microsoft tools. +The 64 bit Cygwin toolchain uses the +Microsoft x64 calling convention +by default, so you can create applications using the Win32 API just as with +the 32 bit Cygwin toolchain. -For the most part, your sources won't need to change at all. -However, you should remove all __export attributes from functions -and replace them like this: +There's just one important difference. The 64 bit Cygwin compilers use +a different data model than the Mingw and Microsoft compilers. For reference, +see the Wikipedia entry on +64-bit computing. + +While the Mingw and Microsoft compilers use the LLP64 +data model, Cygwin compilers use the LP64 data model, just +like Linux. This affects the size of the type long. In the +LLP64 model preferred by Microsoft, +sizeof(long) is 4. This applies for the related Win32 +types like LONG, ULONG, +DWORD, etc., too. + +In the LP64 model used by Cygwin, sizeof(long) is 8, +just like the size of pointers or the types size_t/ssize_t. +This simplifies porting Linux applications to 64 bit Cygwin, but it requires +due diligence when calling Windows functions taking LONG, ULONG, DWORD, or any +other equivalent type. This is especially important in conjunction with +pointers. + +Here's an example. The Win32 function ReadFile +returns the number of read bytes via a pointer to a DWORD variable: -int foo (int) __attribute__ ((__dllexport__)); - -int -foo (int i) +BOOL WINAPI ReadFile (HANDLE, PVOID, DWORD, PDWORD, LPOVERLAPPED); -The Makefile is similar to any other UNIX-like Makefile, -and like any other Cygwin makefile. The only difference is that you use -gcc -mwindows to link your program into a GUI -application instead of a command-line application. Here's an example: +Note that the forth parameter is a pointer to a DWORD, thus it's a +pointer to a 4 byte type, on 32 as well as on 64 bit Windows. Now we write +our own my_read function using ReadFile: + + +64bit-programming, Using ReadFile, 1st try + +ssize_t +my_read (int fd, void *buffer, size_t bytes_to_read) +{ + HANDLE fh = _get_osfhandle (fd); + ssize_t bytes_read; + + if (ReadFile (fh, buffer, bytes_to_read, (PDWORD) &bytes_read, NULL)) + return bytes_read; + set_errno_from_get_last_error (); + return -1; +} + + + +While this example code works fine on 32 bit Windows, it has in fact +a bad bug. The assumption that the size of ssize_t is the same as the size +of DWORD is wrong for 64 bit. In fact, since +sizeof(ssize_t) is 8, ReadFile +will write the number of read bytes into the upper 4 bytes of the variable +bytes_read. my_read will +return the wrong number of read bytes to the caller. + +Here's the fixed version of my_read: + + +64bit-programming, Using ReadFile, 2nd try + +ssize_t +my_read (int fd, void *buffer, size_t bytes_to_read) +{ + HANDLE fh = _get_osfhandle (fd); + DWORD bytes_read; + + if (ReadFile (fh, buffer, bytes_to_read, &bytes_read, NULL)) + return bytes_read; + set_errno_from_get_last_error (); + return -1; +} + + + + + +GUI Mode Applications + +Cygwin comes with an X server, so usually you should compile your +GUI applications as X applications to allow better interoperability with +other Cygwin GUI applications. + +Other than that, Cygwin allows you to build programs with full access +to the standard Windows API, including the GUI functions as defined in +any Microsoft or off-the-shelf publication. + +The build process is similar to any other build process. The only +difference is that you use gcc -mwindows to link your +program into a GUI application instead of a command-line application. +Here's an example Makefile: Note the use of windres to compile the Windows resources into a COFF-format .res file. That will include all the bitmaps, icons, and other resources you -need, into one handy object file. Normally, if you omitted the "-O -coff" it would create a Windows .res format file, -but we can only link COFF objects. So, we tell -windres to produce a COFF object, but for -compatibility with the many examples that assume your linker can -handle Windows resource files directly, we maintain the -.res naming convention. For more information on +need, into one handy object file. For more information on windres, consult the Binutils manual. - -The following is a simple GUI-mode "Hello, World!" program to help -get you started: - -/*-------------------------------------------------*/ -/* hellogui.c - gui hello world */ -/* build: gcc -mwindows hellogui.c -o hellogui.exe */ -/*-------------------------------------------------*/ -#include <windows.h> - -char glpszText[1024]; - -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); - -int APIENTRY WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - sprintf(glpszText, - "Hello World\nGetCommandLine(): [%s]\n" - "WinMain lpCmdLine: [%s]\n", - lpCmdLine, GetCommandLine() ); - - WNDCLASSEX wcex; - - wcex.cbSize = sizeof(wcex); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - wcex.lpszMenuName = NULL; - wcex.lpszClassName = "HELLO"; - wcex.hIconSm = NULL; - - if (!RegisterClassEx(&wcex)) - return FALSE; - - HWND hWnd; - hWnd = CreateWindow("HELLO", "Hello", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); - - if (!hWnd) - return FALSE; - - ShowWindow(hWnd, nCmdShow); - UpdateWindow(hWnd); - - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return msg.wParam; -} - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - PAINTSTRUCT ps; - HDC hdc; - - switch (message) - { - case WM_PAINT: - hdc = BeginPaint(hWnd, &ps); - RECT rt; - GetClientRect(hWnd, &rt); - DrawText(hdc, glpszText, strlen(glpszText), &rt, DT_TOP | DT_LEFT); - EndPaint(hWnd, &ps); - break; - case WM_DESTROY: - PostQuitMessage(0); - break; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - return 0; -} - - -