Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zig rc: Add COFF object file creation for CMake cross-compilation use case #22813

Merged
merged 1 commit into from
Feb 23, 2025

Conversation

squeek502
Copy link
Collaborator

@squeek502 squeek502 commented Feb 8, 2025

This is a fully optional PR that addresses a use case that will only be temporarily supported, since all resinator code and the zig rc subcommand is likely to be removed when Windows resource compilation becomes a build system thing (see #22522 for context).

Is what's described below worth the temporary addition of an extra thousand+ lines of code?

Note: This only touches files within lib/compiler/resinator


In #22522 I said:

RC="zig rc" will now work in combination with zig cc and CMake. Here's an example of cross-compiling a simple Windows GUI CMake project

$ RC="zig rc" CC="zig cc --target=x86_64-windows-gnu" cmake .. -DCMAKE_SYSTEM_NAME=Windows -G Ninja

However, I didn't realize at the time that this only works because of the -G Ninja part. When not using Ninja as the generator, CMake adds a workaround for 'very long lists of object files' where it takes all object files and runs them through ar to combine them into one archive:

https://github.com/Kitware/CMake/blob/4a11fd8dde745789f66d6500412d7f56607e9218/Modules/Platform/Windows-GNU.cmake#L141-L158

This is a problem for the Windows resource use-case, because ar doesn't know how to deal with .res files and so this object combining step fails with:

unknown file type: foo.rc.res

Only the linker knows what to do with .res files (since it has its own .res -> .obj ('cvtres') conversion mechanism). So, when using Ninja: this object file combining step is skipped, and the .res file gets passed to the linker and everyone is happy.


When CMake thinks that it's using windres as the Windows resource compiler, it will pass -O coff to windres which causes it to output a COFF object file instead of a .res file, which means that the ar step can succeed because it's only working on actual object files.

This commit gives zig rc the ability to output COFF object files directly whenever /:output-format coff is provided as an argument. This effectively matches what happens when CMake uses windres for resource compilation, but requires the argument to be provided explicitly.

So, after this change, the following CMake cross-compilation use case will work, even when not using Ninja as the generator:

RC="zig rc /:output-format coff" CC="zig cc --target=x86_64-windows-gnu" cmake .. -DCMAKE_SYSTEM_NAME=Windows

@alexrp alexrp added this to the 0.14.0 milestone Feb 8, 2025
… case

In ziglang#22522 I said:

> RC="zig rc" will now work in combination with zig cc and CMake. Here's an example of cross-compiling a simple Windows GUI CMake project
>
>    $ RC="zig rc" CC="zig cc --target=x86_64-windows-gnu" cmake .. -DCMAKE_SYSTEM_NAME=Windows -G Ninja

However, I didn't realize that the time that this only works because of the `-G Ninja` part. When not using Ninja as the build tool, CMake adds a workaround for 'very long lists of object files' where it takes all object files and runs them through `ar` to combine them into one archive:

https://github.com/Kitware/CMake/blob/4a11fd8dde745789f66d6500412d7f56607e9218/Modules/Platform/Windows-GNU.cmake#L141-L158

This is a problem for the Windows resource use-case, because `ar` doesn't know how to deal with `.res` files and so this object combining step fails with:

    unknown file type: foo.rc.res

Only the linker knows what to do with .res files (since it has its own `.res` -> `.obj` ('cvtres') conversion mechanism). So, when using Ninja, this object file combining step is skipped and the .res file gets passed to the linker and everyone is happy.

Note: When CMake thinks that its using `windres` as the Windows resource compiler, it will pass `-O coff` to windres which causes it to output a COFF object file instead of a `.res` file, which means that the `ar` step can succeed because it's only working on actual object files.

---

This commit gives `zig rc` the ability to output COFF object files directly when `/:output-format coff` is provided as an argument. This effectively matches what happens when CMake uses `windres` for resource compilation, but requires the argument to be provided explicitly.

So, after this change, the following CMake cross-compilation use case will work, even when not using Ninja as the generator:

    RC="zig rc /:output-format coff" CC="zig cc --target=x86_64-windows-gnu" cmake .. -DCMAKE_SYSTEM_NAME=Windows
@andrewrk
Copy link
Member

Sure, let's do it. Thanks for the writeup.

@andrewrk andrewrk merged commit a502301 into ziglang:master Feb 23, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants