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

resinator: Sync with upstream #22522

Merged
merged 2 commits into from
Jan 21, 2025
Merged

Conversation

squeek502
Copy link
Collaborator

@squeek502 squeek502 commented Jan 18, 2025

The end result of this PR is somewhat boring--it's just some bug fixes, mostly for obscure edge cases--but the journey was not straightforward.

This PR has had 3 distinct versions:

The tightly integrated version

The original plan was to implement what's detailed here: make resinator compile directly to COFF object files, and then send those to the linker instead of .res files.

However, the plan (as I understand it) is now for resinator to become a build system thing rather than part of the compiler, following the lead of translate-c (relevant issue), so tight integration with the compiler would be wasted effort.

The drop-in windres version

The master version of resinator has support for outputting COFF object files, and one other potential use case that opens up is providing a windres-compatible CLI interface (since windres can also output COFF object files).

So, the second plan was to add a zig windres command (see #9564 (comment)). This could be useful, because CMake can use windres when cross-compiling, so being able to do something like RC="zig windres" CC="zig cc --target=x86_64-windows-gnu" cmake ... would be quite nice.

From my testing, however, CMake only recognizes the RC compiler as windres if "windres" is in the 'main' program name (i.e. zigwindres would work and CMake would give it windres-style arguments, but zig windres still gets rc.exe-style arguments). So, having a zig windres command wouldn't actually help that much to enable this use case without a wrapper script.

The bug fix version

So, ultimately, the windres subcommand and all COFF object file stuff was excluded from this update for the sake of simplicity. Instead, it's mostly just bug fixes.

However, the CMake cross-compiling use case is still addressed, because it turns out the only thing really blocking it before was CMake giving the RC compiler absolute paths, which resinator tried to interpret as flags, e.g. /home/foo/bar.rc would be interpreted as the flag /h which prints the help screen and exits. Note that this behavior is 'correct' in terms of rc.exe, since it is Windows-only and uses / as an option prefix.

To support the CMake use-case, resinator's CLI parser has been updated to infer when an argument might actually be an absolute filepath (see the looksLikeFilepath function in resinator/cli.zig).

So, 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
$ ninja dialogtest
[1/5] Building RC object dialog/CMakeFiles/dialogtest.dir/dialog.rc.res
<cli>: note: this argument was inferred to be a filepath, so argument parsing was terminated
 ... /home/ryan/Programming/misc/win32-resource-tests/dialog/dialog.rc
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[5/5] Linking C executable dialog/dialogtest.exe

Running the result with wine (the dialog, the button, and the label come from the .rc file):

image

Re-closes #9564 (cc @alexrp)

Note: This mostly matches resinator v0.1.0 rather than the latest master version, since the latest master version focuses on adding support for .res -> .obj conversion which is not necessary for the future planned relationship of zig and resinator (resinator will likely be moved out of the compiler and into the build system, a la translate-c).

So, ultimately the changes here consist mostly of bug fixes for obscure edge cases.
@andrewrk andrewrk merged commit 160445e into ziglang:master Jan 21, 2025
10 checks passed
@andrewrk
Copy link
Member

Thanks for the nice writeup as well as the sync.

github-actions bot pushed a commit to 5hes/zig that referenced this pull request Jan 22, 2025
squeek502 added a commit to squeek502/zig that referenced this pull request 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
squeek502 added a commit to squeek502/zig that referenced this pull request Feb 9, 2025
squeek502 added a commit that referenced this pull request Feb 10, 2025
Fixup for some of the changes in #22522
squeek502 added a commit to squeek502/zig that referenced this pull request Feb 10, 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 pushed a commit that referenced this pull request Feb 23, 2025
… case

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

zig windres
3 participants