Page MenuHomePhabricator

Embed Windows version resource information into our exe and dll files
ClosedPublic

Authored by gbedwell on Feb 23 2015, 5:59 AM.

Details

Summary

As part of the PlayStation(R)4 SDK we have a requirement to embed Windows version information into executables/DLLs that we ship. I'd like to upstream our local change to enable this for the LLVM and related tools. Assuming that the basic idea is acceptable I'm expecting that we might need to go through a few iterations on this but hopefully the attached patch can serve as a basis for any related discussions.

The most visible place that you can find Windows version information is by looking at the file properties in Windows Explorer under the details tab. It's also embedded into dmp files (a subsequent change that I plan to submit will add the capability of automatically generating these files in the case of crashes on Windows)

The basis of the patch is the addition of the new file 'windows_version_resource.rc'. This is a resource script as described here:
http://msdn.microsoft.com/en-gb/library/windows/desktop/aa380599(v=vs.85).aspx

It defines a VERSIONINFO resource as defined here:
https://msdn.microsoft.com/en-gb/library/windows/desktop/aa381058(v=vs.85).aspx

There is a new CMake function 'add_version_info_on_windows' which is called from add_llvm_executable and llvm_add_library in the case of DLLs. This will add the resource script to these projects setting the values based on the LLVM_VERSION_* CMake values. Note that this function is a no-op except for MSVC builds. It should be possible, in theory, to also enable it for MinGW builds using windres.exe but the MinGW CMake generator doesn't seem to support it out of the box as the Visual Studio one does so in the interest of simplicity I've left it as MSVC only.

I've had to make small change to HandleLLVMOptions.cmake to support the CMake Ninja generator. Previously the MSVC-specific warning flags were being added from add_llvm_definitions. The Visual Studio generators use a filter to make sure that only valid flags are passed through to the resource compiler, however the Ninja generator expects that this will only ever contain definitions and passes everything through unfiltered leading to errors from the resource compiler when given invalid flags. I've changed the behaviour so these warning flags are now added to CMAKE_C_FLAGS and CMAKE_CXX_FLAGS directly.

A few points I'd like to draw attention to:

  • the location of windows_version_resource.rc: Currently it's at the root llvm directory level but I'm not sure if this is appropriate. Non of the existing directories seem to apply (possibly 'cmake' at a stretch?). Should I instead make a new one? If so, would 'resource' be a reasonable name?
  • Testing: We test this in our internal test suite using a Python script. The script itself is simple enough but requires the use of the win32api module which is an extension. Although it comes with some Python distributions on Windows by default, this is not guaranteed. Any thoughts on how best to test this would be greatly appreciated.
  • The Windows FILEVERSION format: This is made of four 16-bit integers x,y,z,w. I think it makes sense for x,y and z to be major, minor and patchlevel numbers respectively, but there is a question over w. Many software projects on Windows will use a unique build number here, so using the SVN revision would make sense in this case but one issue is that LLVM SVN revision numbers are way larger than can be represented in a 16-bit number so get truncated. The attached patch will embed the revision number if available, so we end up with a situation where, for example the file properties in Windows explorer show "Product Version" (a string) as "3.7.0svn-r230211" and "File Version" (a number) as "3.7.0.33603". The alternative would be for "File Version" to be set to "3.7.0.0" (major, minor, patch, zero). I don't have a strong preference either way, as internally we'll override all these numbers with our own PS4 SDK version number, so I'm happy to go with the consensus.

Apologies for the long description above. As it's a fairly non-standard change I wanted to explain all my reasoning for the changes made in detail.

Thanks!

Greg Bedwell
SN Systems - Sony Computer Entertainment Group

Diff Detail

Repository
rL LLVM

Event Timeline

gbedwell updated this revision to Diff 20507.Feb 23 2015, 5:59 AM
gbedwell retitled this revision from to Embed Windows version resource information into our exe and dll files.
gbedwell updated this object.
gbedwell edited the test plan for this revision. (Show Details)
gbedwell added a subscriber: Unknown Object (MLST).
gbedwell updated this revision to Diff 24644.Apr 29 2015, 10:22 AM
gbedwell added a subscriber: Unknown Object (MLST).

New patch attached. Apologies for the delay. I had to work on something else temporarily but am now free to hack on compilers once more - hooray!.

For the benefit of cfe-commits who I've just added, this patch adds a VERSIONINFO resource to .exe and .dll files when we build LLVM with MSVC. The most visible place that you can find Windows version information is by looking at the file properties in Windows Explorer under the details tab. It's also embedded into minidump .dmp files (a subsequent change that I plan to submit will add the capability of automatically generating these files in the case of crashes on Windows).

As suggested I separated the part that fixed an issue with the Ninja builder into another patch which was committed at r232727.

I've split the CMake function from the original patch into 2 functions now. The first just adds the resource script file to the current project if we're building with MSVC. The second checks whether the resource script exists in the current project and sets preprocessor macros for that file containing the version information to embed if it does. There are a couple of reasons for splitting it. Firstly, we need to add the resource script file to the project sources before the target has been created, but in order to populate the 'OriginalFilename' field we need the target location which only exists once the target has been created. Secondly, it means that we can call the 'set_windows_version_resource_properties' function from specific subproject CMakelists files to override the default values if necessary.

By default we're setting the FILEVERSION field with the following values from CMake:

LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH, 0

The "FileVersion" and "ProductVersion" fields which are strings get set to the value of PACKAGE_VERSION.
The "OriginalFilename" field gets set with the name of the exe or DLL file that the project creates. Note that this means that files such as clang++.exe or clang-cl.exe will still get the string 'clang.exe' in this field as they are just copies of clang.exe. "InternalName" as per the Microsoft documentation suggestion gets set to the filename string without the extension (so 'clang' in the above cases). I've set 'ProductName' to 'LLVM' by default.

I'll followup with a separate clang patch very shortly that overrides the LLVM version numbers with the clang equivalent ones and sets 'ProductName' to 'clang' when building projects that come from tools/clang. I'm happy to bikeshed on the strings that particular fields should get as long as the general approach is considered acceptable.

Thanks,
Greg

This revision was automatically updated to reflect the committed changes.