* 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.
This commit is contained in:
		
							parent
							
								
									2dc32f6ae4
								
							
						
					
					
						commit
						a90f2ca74f
					
				|  | @ -1,3 +1,11 @@ | |||
| 2013-07-25  Corinna Vinschen  <corinna@vinschen.de> | ||||
| 
 | ||||
| 	* 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  <corinna@vinschen.de> | ||||
| 
 | ||||
| 	* new-features.sgml (ov-new1.7.22): Add GetCommandLine and regcomp | ||||
|  |  | |||
|  | @ -4,11 +4,10 @@ | |||
| 
 | ||||
| <sect1 id="gcc"><title>Using GCC with Cygwin</title> | ||||
| 
 | ||||
| <sect2 id="gcc-cons"><title>Console Mode Applications</title> | ||||
| <sect2 id="gcc-default"><title>Standard Usage</title> | ||||
| 
 | ||||
| <para>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:</para> | ||||
| <para>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:</para> | ||||
| 
 | ||||
| <example id="gcc-hello-world"> | ||||
| <title>Building Hello World with GCC</title> | ||||
|  | @ -23,29 +22,104 @@ Hello, World | |||
| 
 | ||||
| </sect2> | ||||
| 
 | ||||
| <sect2 id="gcc-gui"><title>GUI Mode Applications</title> | ||||
| <sect2 id="gcc-64"><title>Building applications for 64 bit Cygwin</title> | ||||
| 
 | ||||
| <para>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.</para> | ||||
| <para>The 64 bit Cygwin toolchain uses the | ||||
| <ulink url="http://en.wikipedia.org/wiki/X86_calling_convention#Microsoft_x64_calling_convention">Microsoft x64 calling convention</ulink> | ||||
| by default, so you can create applications using the Win32 API just as with | ||||
| the 32 bit Cygwin toolchain.</para> | ||||
| 
 | ||||
| <para>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:</para> | ||||
| <para>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 | ||||
| <ulink url="http://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models">64-bit computing</ulink>.</para> | ||||
| 
 | ||||
| <para>While the Mingw and Microsoft compilers use the <literal>LLP64</literal> | ||||
| data model, Cygwin compilers use the <literal>LP64</literal> data model, just | ||||
| like Linux.  This affects the size of the type <literal>long</literal>.  In the | ||||
| <literal>LLP64</literal> model preferred by Microsoft, | ||||
| <function>sizeof(long)</function> is 4.  This applies for the related Win32 | ||||
| types like <literal>LONG</literal>, <literal>ULONG</literal>, | ||||
| <literal>DWORD</literal>, etc., too.</para> | ||||
| 
 | ||||
| <para>In the <literal>LP64</literal> model used by Cygwin, <function>sizeof(long)</function> is 8, | ||||
| just like the size of pointers or the types <literal>size_t/ssize_t</literal>. | ||||
| 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.</para> | ||||
| 
 | ||||
| <para>Here's an example.  The Win32 function <function>ReadFile</function> | ||||
| returns the number of read bytes via a pointer to a DWORD variable:</para> | ||||
| 
 | ||||
| <screen> | ||||
| int foo (int) __attribute__ ((__dllexport__)); | ||||
| 
 | ||||
| int | ||||
| foo (int i) | ||||
| BOOL WINAPI ReadFile (HANDLE, PVOID, DWORD, PDWORD, LPOVERLAPPED); | ||||
| </screen> | ||||
| 
 | ||||
| <para>The Makefile is similar to any other UNIX-like Makefile, | ||||
| and like any other Cygwin makefile.  The only difference is that you use | ||||
| <command>gcc -mwindows</command> to link your program into a GUI | ||||
| application instead of a command-line application.  Here's an example:</para> | ||||
| <para>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 <function>my_read</function> function using ReadFile:</para> | ||||
| 
 | ||||
| <example id="gcc-64-ex1"> | ||||
| <title>64bit-programming, Using ReadFile, 1st try</title> | ||||
| <screen> | ||||
| 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; | ||||
| } | ||||
| </screen> | ||||
| </example> | ||||
| 
 | ||||
| <para>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 | ||||
| <function>sizeof(ssize_t)</function> is 8, <function>ReadFile</function> | ||||
| will write the number of read bytes into the upper 4 bytes of the variable | ||||
| <literal>bytes_read</literal>.  <function>my_read</function> will | ||||
| return the wrong number of read bytes to the caller.</para> | ||||
| 
 | ||||
| <para>Here's the fixed version of <function>my_read</function>:</para> | ||||
| 
 | ||||
| <example id="gcc-64-ex2"> | ||||
| <title>64bit-programming, Using ReadFile, 2nd try</title> | ||||
| <screen> | ||||
| 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; | ||||
| } | ||||
| </screen> | ||||
| </example> | ||||
| 
 | ||||
| </sect2> | ||||
| 
 | ||||
| <sect2 id="gcc-gui"><title>GUI Mode Applications</title> | ||||
| 
 | ||||
| <para>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.</para> | ||||
| 
 | ||||
| <para>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.</para> | ||||
| 
 | ||||
| <para>The build process is similar to any other build process.  The only | ||||
| difference is that you use <command>gcc -mwindows</command> to link your | ||||
| program into a GUI application instead of a command-line application. | ||||
| Here's an example Makefile:</para> | ||||
| 
 | ||||
| <screen> | ||||
| <![CDATA[ | ||||
|  | @ -60,101 +134,8 @@ myapp.res : myapp.rc resource.h | |||
| <para>Note the use of <filename>windres</filename> to compile the | ||||
| Windows resources into a COFF-format <filename>.res</filename> 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 <filename>.res</filename> format file, | ||||
| but we can only link COFF objects.  So, we tell | ||||
| <filename>windres</filename> 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 | ||||
| <filename>.res</filename> naming convention.  For more information on | ||||
| need, into one handy object file.  For more information on | ||||
| <filename>windres</filename>, consult the Binutils manual.  </para> | ||||
| 
 | ||||
| <para> | ||||
| The following is a simple GUI-mode "Hello, World!" program to help | ||||
| get you started: | ||||
| <screen> | ||||
| /*-------------------------------------------------*/ | ||||
| /* 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; | ||||
| } | ||||
| </screen> | ||||
| </para> | ||||
| 
 | ||||
| </sect2> | ||||
| </sect1> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue