* 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:
Corinna Vinschen 2013-07-25 09:04:21 +00:00
parent 2dc32f6ae4
commit a90f2ca74f
2 changed files with 104 additions and 115 deletions

View File

@ -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

View File

@ -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) &amp;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, &amp;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 &lt;windows.h&gt;
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(&amp;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(&amp;msg, NULL, 0, 0))
{
TranslateMessage(&amp;msg);
DispatchMessage(&amp;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, &amp;ps);
RECT rt;
GetClientRect(hWnd, &amp;rt);
DrawText(hdc, glpszText, strlen(glpszText), &amp;rt, DT_TOP | DT_LEFT);
EndPaint(hWnd, &amp;ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
</screen>
</para>
</sect2>
</sect1>