WineHQ

Wine Developer's Guide/Coding Practice: Difference between revisions

(removed all references to sending patches by email)
(updated and copied in notes about style and portability from Submitting Patches#Code guidelines, Developer Hints#Using only C89-compliant code, and https://gitlab.winehq.org/wine/wine/-/merge_requests/3059)
Line 4: Line 4:
== Some notes about style ==
== Some notes about style ==


There are a few conventions about coding style that have been adopted over the years of development. The rationale for these “rules” is explained for each one.
In the time since the Wine project was started in 1993, its developers have settled on the following general style conventions. These conventions are merely matters of taste; although some of them were once required for compiler compatibility, the current standards for compiler compatibility are documented in the [[#Writing portable code|Writing portable code]] section below. Not all existing Wine code follows these rules, but '''please do the following when adding new code''':


<ul>
* Use 4-space indentation instead of tabs
<li><p>Tabs are not forbidden but discouraged. A tab is defined as 8 characters and the usual amount of indentation is 4 characters.</p></li>
* Avoid very long lines ([https://www.winehq.org/pipermail/wine-devel/2012-September/097024.html there is no hard limit], the preferred length is 100, but 120 or 80 chars are fine too)
<li><p>C++ style comments are forbidden since some compilers choke on them.</p></li>
* Use only slash-star comments, never slash-slash comments (e.g. write <code>/* */</code> instead of<code>//</code>)
<li><p>Commenting out a block of code is usually done by using <code>if (0)</code>. For example:</p>
* Use snake_case instead of camelCase or TitleCase, except if the Windows API requires it
<source lang="c">/* note about reason for commenting block */
* Prefer asterisks to declare pointers instead of the P and LP typedefs (e.g. write <code>DWORD *</code> instead of <code>LPDWORD</code>)
* Be consistent in your own changes (e.g. don't write <code>int* foo</code> in one place and <code>int *foo</code> in another)
* Limit type casts as much as possible (e.g. don't cast a <code>void *</code> to a <code>DWORD *</code> or vice-versa)
* Don't use Hungarian notation (e.g. write <code>char *important_buffer</code> instead of <code>char *pImportantBuffer</code>)
* Write hexadecimal constants and variable suffixes in all lowercase (e.g. <code>0xcafe1234u</code>)
* Put spaces around arithmetic and boolean operators (e.g. write <code>(1 + 2) * 3</code> instead of <code>(1+2)*3</code>)
* Use the <code>ARRAY_SIZE</code> macro where appropriate
* Remove trailing whitespace from your changes, but don't change whitespace in other lines
* Comment out code with <code>if (0)</code>, to ensure that the code compiles:
<source lang="c">
/* note about reason for commenting block */
if (0) {
if (0) {
code
    code
code /* comments */
    code /* comments */
code
    code
}</source>
}
<p>The reason for using this method is that it does not require that you edit comments that may be inside the block of code and it makes sure the code gets maintained.</p></li>
</source>
<li><p>Code is usually limited to 100 columns. It generally makes code easier to read.</p></li>
* Use <code>void</code> when declaring or defining parameter-less functions:
</ul>
<source lang="c">
int foo();                      /* Incorrect */
int foo() { }                  /* Also incorrect */
 
int foo(void);                  /* Much better */
int foo(void) { }              /* Also much better */
</source>
* Always put variable declarations at the beginning of a block, never in the middle and never in the initializer of a for loop:
<source lang="c">
int bar1(void)
{
    do_something();
 
    int number1 = 5;            /* Disliked */
 
    for (int i = 0; i < 8; i++) /* Also not preferred */
        do_something_else();
}
 
int bar2(void)
{
    int number2 = 17;          /* Much better */
    int i;                      /* Ditto */
 
    do_something();
 
    for (i = 0; i < 8; i++)
        do_something_else();
}
</source>


=== Preferred D3D coding style ===
=== Preferred D3D coding style ===
Direct3D and DirectShow enforce a more restrictive coding style than most of the rest of Wine. The following describes Direct3D coding style. Note that many of these principles are used elsewhere.
 
Direct3D and DirectShow enforce a more restrictive coding style than most of the rest of Wine. The following describes Direct3D coding style. Note that many of these principles are applicable elsewhere.


* Describe exactly what you're changing in the patch subject line instead of, e.g., a generic 'fix something'.
* Describe exactly what you're changing in the patch subject line instead of, e.g., a generic 'fix something'.
* Trace messages on function entry should include variable names. This makes debugging much easier, as you then don't have to look up the parameter order.
* Trace messages on function entry should include variable names. This makes debugging much easier, as you then don't have to look up the parameter order.
* Trace enumerations using %#x. Use %#x when tracing hexadecimal numbers (e.g. do not use "%x", "0x%x", "%08x"...)
* Trace enumerations using <code>%#x</code>. Use <code>%#x</code> when tracing hexadecimal numbers (e.g. do not use <code>%x</code>, <code>0x%x</code>, <code>%08x</code>, etc.)
* Trace floats using %.8e, and doubles using %.16e. This always gives enough precision to determine the unique number.
* Trace floats using <code>%.8e</code>, and doubles using <code>%.16e</code>. This always gives enough precision to determine the unique number.
* Always use 8 space indentation when continuing a previous line (instead of e.g. trying to align to the first function parameter). This avoids wasting space when a continuation must begin late in the line. For example:
* Always use 8 space indentation when continuing a previous line (instead of e.g. trying to align to the first function parameter). This avoids wasting space when a continuation must begin late in the line. For example:
<source lang="c">
<source lang="c">
Line 32: Line 72:
             output, debug_d3dformat(format_id), scanline_ordering);
             output, debug_d3dformat(format_id), scanline_ordering);
</source>
</source>
* When continuing a previous line, || and && should begin the line, rather than ending the previous line.
* When continuing a previous line, <code>||</code> and <code>&&</code> should begin the line, rather than ending the previous line.
* Always end trace messages with a period.
* Always end trace messages with a period.
* Prefer British spelling.
* Prefer British spelling.
* Prefer snake_case to camelCase or TitleCase. In particular do not use Hungarian notation (e.g. lpVar).
* Don't introduce typedefs. Always using e.g. <code>struct</code> and <code>*</code> makes it clearer what kind of object you're dealing with.
* Don't introduce typedefs. Always using e.g. "struct" and "*" makes it clearer what kind of object you're dealing with.
* Similarly, avoid Win32 pointer typedefs (e.g. use "void *" instead of "LPVOID").
* Put the body of an if statement on the next line, even if it's short. It can be easy to miss otherwise when reading.
* Put the body of an if statement on the next line, even if it's short. It can be easy to miss otherwise when reading.
* Braces need not be used when an "if" body is only a single line, but if an "if" body has braces, the "else" body should too, and vice versa.
* Braces need not be used when an "if" body is only a single line, but if an "if" body has braces, the "else" body should too, and vice versa.
* Use sizeof(*var) in allocations instead of sizeof(type).
* Use <code>sizeof(*var)</code> in allocations instead of <code>sizeof(type)</code>.
* Use the ARRAY_SIZE() macro where appropriate.
* Sort variable declarations to a reverse Christmas tree by length.
* Sort variable declarations to a reverse Christmas tree by length.
* Prefer unsigned types for things like loop counters.
* Prefer unsigned types for things like loop counters.
== Writing portable code ==
Write code that compiles on recent versions of both GCC and Clang, as well as MSVC if the code is in a PE module. That means:
* Avoid compiler extensions:
<source lang="c">
typeof(D3DCreateBlob) pD3DCreateBlob;                  /* GCC extension */
HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T, ID3DBlob **);  /* Works on both GCC and MSVC */
ch += offset ?: size            /* GCC extension */
ch += offset ? offset : size    /* Works on both GCC and MSVC */
</source>
* When declaring function pointers, put the calling convention inside the parentheses:
<source lang="c">
HRESULT WINAPI (*pD3DCreateBlob)(SIZE_T, ID3DBlob **);  /* Works on GCC but not MSVC */
HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T, ID3DBlob **);  /* Works on both GCC and MSVC */
</source>
* Use types with dependable definitions:
<source lang="c">
long wrong = 0xcafe1234l;      /* long is 4 bytes in Win64 but 8 bytes in Unix64 */
LONG right = 0xcafe1234;      /* LONG is 4 bytes, the same as int, on both platforms */
</source>
* Use WCHAR and array syntax for Unicode string literals in non-PE modules ([https://gitlab.com/mywinetools/mywinetools/raw/master/wstr.py helpful tool]):
<source lang="c">
const WCHAR str1[] = L"Hello";  /* Preferred on PE modules. But it won't compile on non-PE modules. */
const WCHAR str2[] = {          /* Tedious, but correct */
    'H','e','l','l','o',0
};
</source>
* Don't use designated initializers for nameless structs or unions ([https://bugs.winehq.org/show_bug.cgi?id=50378 it breaks GCC 4.3])
* Don't declare a typedef more than once ([https://gitlab.winehq.org/wine/wine/-/merge_requests/3059 it breaks GCC 4.3])


== Quality Assurance ==
== Quality Assurance ==

Revision as of 09:21, 8 July 2023

__NUMBEREDHEADINGS__ This chapter describes the relevant coding practices in Wine, that you should be aware of before doing any serious development in Wine.

Some notes about style

In the time since the Wine project was started in 1993, its developers have settled on the following general style conventions. These conventions are merely matters of taste; although some of them were once required for compiler compatibility, the current standards for compiler compatibility are documented in the Writing portable code section below. Not all existing Wine code follows these rules, but please do the following when adding new code:

  • Use 4-space indentation instead of tabs
  • Avoid very long lines (there is no hard limit, the preferred length is 100, but 120 or 80 chars are fine too)
  • Use only slash-star comments, never slash-slash comments (e.g. write /* */ instead of//)
  • Use snake_case instead of camelCase or TitleCase, except if the Windows API requires it
  • Prefer asterisks to declare pointers instead of the P and LP typedefs (e.g. write DWORD * instead of LPDWORD)
  • Be consistent in your own changes (e.g. don't write int* foo in one place and int *foo in another)
  • Limit type casts as much as possible (e.g. don't cast a void * to a DWORD * or vice-versa)
  • Don't use Hungarian notation (e.g. write char *important_buffer instead of char *pImportantBuffer)
  • Write hexadecimal constants and variable suffixes in all lowercase (e.g. 0xcafe1234u)
  • Put spaces around arithmetic and boolean operators (e.g. write (1 + 2) * 3 instead of (1+2)*3)
  • Use the ARRAY_SIZE macro where appropriate
  • Remove trailing whitespace from your changes, but don't change whitespace in other lines
  • Comment out code with if (0), to ensure that the code compiles:
/* note about reason for commenting block */
if (0) {
    code
    code /* comments */
    code
}
  • Use void when declaring or defining parameter-less functions:
int foo();                      /* Incorrect */
int foo() { }                   /* Also incorrect */

int foo(void);                  /* Much better */
int foo(void) { }               /* Also much better */
  • Always put variable declarations at the beginning of a block, never in the middle and never in the initializer of a for loop:
int bar1(void)
{
    do_something();

    int number1 = 5;            /* Disliked */

    for (int i = 0; i < 8; i++) /* Also not preferred */
        do_something_else();
}

int bar2(void)
{
    int number2 = 17;           /* Much better */
    int i;                      /* Ditto */

    do_something();

    for (i = 0; i < 8; i++) 
        do_something_else();
}

Preferred D3D coding style

Direct3D and DirectShow enforce a more restrictive coding style than most of the rest of Wine. The following describes Direct3D coding style. Note that many of these principles are applicable elsewhere.

  • Describe exactly what you're changing in the patch subject line instead of, e.g., a generic 'fix something'.
  • Trace messages on function entry should include variable names. This makes debugging much easier, as you then don't have to look up the parameter order.
  • Trace enumerations using %#x. Use %#x when tracing hexadecimal numbers (e.g. do not use %x, 0x%x, %08x, etc.)
  • Trace floats using %.8e, and doubles using %.16e. This always gives enough precision to determine the unique number.
  • Always use 8 space indentation when continuing a previous line (instead of e.g. trying to align to the first function parameter). This avoids wasting space when a continuation must begin late in the line. For example:
    TRACE("output %p, format %s, scanline_ordering %#x.\n",
            output, debug_d3dformat(format_id), scanline_ordering);
  • When continuing a previous line, || and && should begin the line, rather than ending the previous line.
  • Always end trace messages with a period.
  • Prefer British spelling.
  • Don't introduce typedefs. Always using e.g. struct and * makes it clearer what kind of object you're dealing with.
  • Put the body of an if statement on the next line, even if it's short. It can be easy to miss otherwise when reading.
  • Braces need not be used when an "if" body is only a single line, but if an "if" body has braces, the "else" body should too, and vice versa.
  • Use sizeof(*var) in allocations instead of sizeof(type).
  • Sort variable declarations to a reverse Christmas tree by length.
  • Prefer unsigned types for things like loop counters.

Writing portable code

Write code that compiles on recent versions of both GCC and Clang, as well as MSVC if the code is in a PE module. That means:

  • Avoid compiler extensions:
typeof(D3DCreateBlob) pD3DCreateBlob;                   /* GCC extension */
HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T, ID3DBlob **);  /* Works on both GCC and MSVC */

ch += offset ?: size            /* GCC extension */
ch += offset ? offset : size    /* Works on both GCC and MSVC */
  • When declaring function pointers, put the calling convention inside the parentheses:
HRESULT WINAPI (*pD3DCreateBlob)(SIZE_T, ID3DBlob **);  /* Works on GCC but not MSVC */
HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T, ID3DBlob **);  /* Works on both GCC and MSVC */
  • Use types with dependable definitions:
long wrong = 0xcafe1234l;      /* long is 4 bytes in Win64 but 8 bytes in Unix64 */
LONG right = 0xcafe1234;       /* LONG is 4 bytes, the same as int, on both platforms */
  • Use WCHAR and array syntax for Unicode string literals in non-PE modules (helpful tool):
const WCHAR str1[] = L"Hello";  /* Preferred on PE modules. But it won't compile on non-PE modules. */
const WCHAR str2[] = {          /* Tedious, but correct */
    'H','e','l','l','o',0
};

Quality Assurance

(Or, “How do I get Alexandre to apply my patch quickly so I can build on it and it will not go stale?”)

Make sure your patch applies to the current Git HEAD revisions. If a bunch of patches are committed that may affect whether your patch will apply cleanly then verify that your patch does apply! git fetch; git rebase origin is your friend!

Patches must not break building Wine or cause test failures. Adding dead code should also be avoided.

Save yourself some embarrassment and run your patched code against more than just your current test example. Experience will tell you how much effort to apply here. If there are any conformance tests for the code you're working on, run them and make sure they still pass after your patch is applied. Running tests can be done by running make test. You may need to run make testclean to undo the results of a previous test run. See the “testing” guide for more details on Wine conformance tests.

Porting Wine to new Platforms

This document provides a few tips on porting Wine to your favorite (UNIX-based) operating system.

Why ifdef MyOS is probably a mistake.

Operating systems change. Maybe yours doesn't have the foo.h header, but maybe a future version will have it. If you want to #include <foo.h>, it doesn't matter what operating system you are using; it only matters whether foo.h is there.

Furthermore, operating systems change names or “fork” into several ones. An #ifdef MyOS will break over time.

If you use the feature of autoconf -- the Gnu auto-configuration utility -- wisely, you will help future porters automatically because your changes will test for features, not names of operating systems. A feature can be many things:

  • existence of a header file
  • existence of a library function
  • existence of libraries
  • bugs in header files, library functions, the compiler, ...

You will need GNU autoconf, which you can get from your friendly GNU mirror. This program takes Wine configure.ac file and produces a configure shell script that users use to configure Wine to their system.

There are exceptions to the “avoid #ifdef MyOS” rule. Wine, for example, needs the internals of the signal stack -- that cannot easily be described in terms of features. Moreover, you cannot use autoconf HAVE_* symbols in Wine headers, as these may be used by Winelib users who may not be using a configure script.

Let's now turn to specific porting problems and how to solve them.

MyOS doesn't have the foo.h header!

This first step is to make autoconf check for this header. In configure.ac you add a segment like this in the section that checks for header files (search for “header files”):

AC_CHECK_HEADER(foo.h, AC_DEFINE(HAVE_FOO_H))

If your operating system supports a header file with the same contents but a different name, say bar.h, add a check for that also.

Now you can change

#include <foo.h>

to

#ifdef HAVE_FOO_H
#include <foo.h>
#elif defined (HAVE_BAR_H)
#include <bar.h>
#endif

If your system doesn't have a corresponding header file even though it has the library functions being used, you might have to add an #else section to the conditional. Avoid this if you can.

You will also need to add #undef HAVE_FOO_H (etc.) to include/config.h.in.

Finish up with autoconf and ./configure.

MyOS doesn't have the bar function!

A typical example of this is the memmove function. To solve this problem you would add memmove to the list of functions that autoconf checks for. In configure.ac you search for AC_CHECK_FUNCS and add memmove (you will notice that someone already did this for this particular function).

Secondly, you will also need to add #undef HAVE_BAR to include/config.h.in.

The next step depends on the nature of the missing function.

Case 1:

It's easy to write a complete implementation of the function (memmove belongs to this case).

You add your implementation in misc/port.c surrounded by #ifndef HAVE_MEMMOVE and #endif.

You might have to add a prototype for your function. If so, include/miscemu.h might be the place. Don't forget to protect that definition by #ifndef HAVE_MEMMOVE and #endif also!

Case 2:

A general implementation is hard, but Wine is only using a special case.

An example is the various wait calls used in SIGNAL_child from loader/signal.c. Here we have a multi-branch case on features:

#ifdef HAVE_THIS
...
#elif defined (HAVE_THAT)
...
#elif defined (HAVE_SOMETHING_ELSE)
...
#endif

Note that this is very different from testing on operating systems. If a new version of your operating systems comes out and adds a new function, this code will magically start using it.

Finish up with autoconf and ./configure.

Adding New Languages

This section documents the procedure for adding a new language to the list of languages that Wine can display system menus and forms in. Adding new translations is not hard as it requires no programming knowledge or special skills.

First add the language ID (most often like xx, e.g. fr for French, or xx_YY for country-specific variations, e.g. pt_BR for Brazilian Portuguese ; look in tools/wmc/po.c for a list) in the LINGUAS section of configure.ac, and in po/LINGUAS.

Language dependent resources reside in .po files in the po/ directory. Simply create the language-specific .po file using the wine.pot template:

cp po/wine.pot po/xx.po

and start translating (note the file must use UTF-8 encoding).

When adding a new language, also make sure the parameters defined in dlls/kernel32/nls/*.nls fit your local habits and language.

This page was last edited on 8 July 2023, at 09:21.