Build Windows Resources with x86_64-w64-mingw32-windres
You will turn a Windows resource script into a COFF object that the MinGW-w64 linker can include in a Windows executable. The workflow also shows how to inspect the generated resource, pass preprocessor definitions, and avoid the format guesses that cause most confusing failures.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes for a first resource. You need the binutils-mingw-w64-x86-64 package, a shell, and a working MinGW-w64 build directory. The commands below do not need elevated privileges. Do not use sudo unless your own input or output directory is deliberately protected.
The installed command is GNU Binutils 2.41.90.20240122, from package version 2.41.90.20240122-1ubuntu1+11.4 on this machine. The UCRT alias uses the same installed manual and canonical command behaviour.
1. Check the installed command
Start with the version and help output. This is read-only and confirms that the cross-tool is the one in your path:
$ command -v x86_64-w64-mingw32-windres
/usr/bin/x86_64-w64-mingw32-windres
$ x86_64-w64-mingw32-windres --version
GNU windres (GNU Binutils) 2.41.90.20240122
$ x86_64-w64-mingw32-windres --help
Usage: x86_64-w64-mingw32-windres [option(s)] [input-file] [output-file]
Checkpoint: the command name should be the x86_64 MinGW-w64 variant, not a native Linux windres installed by another toolchain.
2. Write a small resource script
A resource script is text in rc format. This example embeds a version resource with a preprocessor-controlled product name. Create app.rc in your build directory:
#ifndef PRODUCT_NAME
#define PRODUCT_NAME "Example application"
#endif
1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", PRODUCT_NAME
VALUE "ProductName", PRODUCT_NAME
VALUE "FileVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1200
END
END
The identifiers and structure belong to the Windows resource format. windres preprocesses an rc input with gcc by default, so ordinary C preprocessor directives work here. Keep the file in a directory you control and review included files before building; the preprocessor can read more than the resource declarations shown above.
3. Convert the script to a COFF object
Run the conversion with formats stated explicitly:
$ x86_64-w64-mingw32-windres \
--input-format=rc \
--output-format=coff \
--target=pe-x86-64 \
--input=app.rc \
--output=app-res.o
A successful run normally prints nothing and returns status zero. Check the result before linking:
$ printf 'windres status: %s\n' "$?"
windres status: 0
$ file app-res.o
app-res.o: Intel amd64 COFF object file, not stripped, 4 sections, symbol table
The exact file description can vary with its version, but it should identify a 64-bit Intel or PE COFF object. The output file is a build artefact, not a Windows executable and not a Linux ELF object.
Warning: the output option replaces an existing file. If app-res.o is valuable, copy it to a reviewed backup first. If the conversion fails, rebuild it under a new name and only replace the old object after checking the new one.
4. Link the object into the application
Pass the generated object to the same x86_64 MinGW-w64 linker used for the rest of the Windows program. For a program whose source has already been compiled to main.o:
$ x86_64-w64-mingw32-gcc main.o app-res.o -o example.exe
Resource objects are ordinary link inputs at this stage. The resource data becomes available to Windows when the executable is built. Do not feed app.rc directly to a Linux linker, and do not use a 32-bit target for one object and a 64-bit target for the other.
5. Use a definition and an include directory
For a build-specific value, pass a preprocessor definition with --define. The value below includes spaces, so quote the entire argument:
$ x86_64-w64-mingw32-windres \
--input-format=rc --output-format=coff --target=pe-x86-64 \
--define='PRODUCT_NAME="Nightly build"' \
--input=app.rc --output=app-res-nightly.o
For shared headers or external resource files, use --include-dir:
$ x86_64-w64-mingw32-windres \
--include-dir=./resources \
--input-format=rc --output-format=coff --target=pe-x86-64 \
app.rc app-res.o
--include-dir is passed to the preprocessor and is also searched for files named by the resource script. Do not rely on the current directory by accident. Make the include directory explicit in a repeatable build command.
6. Inspect or convert an existing resource
The three formats are rc text, res binary resource data, and coff object or executable data. To inspect an existing object as resource text, state both formats:
$ x86_64-w64-mingw32-windres \
--input-format=coff --output-format=rc \
--target=pe-x86-64 \
--input=app-res.o --output=app-res.rc
The generated rc is similar to an input script, but it is not guaranteed to be identical. External files referenced by an input script are emitted as contents in generated rc output. Treat that output as an inspection or migration aid and review it before reusing it.
If you omit the output filename, windres writes rc text to standard output. It cannot read a COFF file from standard input or write a COFF file to standard output, so explicit filenames are the safer choice for object conversion.
7. Diagnose format and target errors
Filename extensions drive automatic guessing: .rc means rc, .res means res, and .o or .exe means coff. A renamed file, a missing extension, or a pipeline can defeat that guess. Add --input-format and --output-format whenever the file name does not make the intended formats obvious.
The --target value is a BFD target. The installed help output lists pe-x86-64 and pei-x86-64, among others. Use the target expected by the rest of your toolchain; if you are unsure, inspect the help output rather than copying a target from a different architecture.
For preprocessor failures, use --verbose to see which preprocessor is selected. You can choose another program with --preprocessor, or add repeated --preprocessor-arg options. The default arguments include -E, -xc-header and -DRC_INVOKED; a custom preprocessor may need equivalent handling.
Done means
- The installed x86_64 MinGW-w64
windresand package version are confirmed. - Your
.rcscript preprocesses and converts with an explicit 64-bit COFF target. fileidentifies the result as an Intel amd64 or PE COFF object.- The resource object is passed to the matching MinGW-w64 linker.
- Format guesses, include paths and preprocessor definitions are explicit in the build command.
- You kept any previous output until the replacement was successfully converted and checked.