How to inject the right version information into t

2019-07-16 05:58发布

问题:

I was surprised to discover that apparently it is not possible to import C predefined macros inside the resource files (.rc) because Resource Compiler is not able to deal with them.

I was trying to put the version information inside a version.h that would be generated / updated by the build system. This file was supposed to be included from the resource.rc so when you build the resources you will always get the same versions across all the built files.

It seems that this has something to do with RC_INVOKED and this bug http://connect.microsoft.com/VisualStudio/feedback/details/532929/rc4011-warnings-from-vc10-rc -- which is closed as "as-designed".

How can I solve this problem?

Is the only option to patch the final exe in order to update the version information? ... I would prefer not do to this and use a more standard way for this.

回答1:

The resource compiler deals just fine with includes and preprocessor definitions. It just does not deal well with including Windows.h for instance. But I cannot think of any good reason why you'd need that in a file that gets consumed by the resource compiler. Just use a header file that does not include anything causing the warning, and just define what you need. As an example the typical versioning we use here does this and works great: there's a single master .rc file with that looks something like this:

#include <winver.h>

#define stringize( x )        stringizei( x )
#define stringizei( x )       #x

#ifdef VRC_INCLUDE
  #include stringize( VRC_INCLUDE )
#endif

#ifdef _WIN32
  LANGUAGE 0x9,0x1
  #pragma code_page( 1252 )
#endif

1 VERSIONINFO
 FILEVERSION    VRC_FILEVERSION
 PRODUCTVERSION VRC_PRODUCTVERSION
 FILEFLAGSMASK  0x1L
 FILEFLAGS      VS_FF_DEBUG
 FILEOS         VOS__WINDOWS32
 FILETYPE       VRC_FILETYPE
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904E4"
    BEGIN
      VALUE "CompanyName",      stringize( VRC_COMPANYNAME )
      VALUE "FileDescription",  stringize( VRC_FILEDESCRIPTION )
      VALUE "FileVersion",      stringize( VRC_FILEVERSION )
      VALUE "LegalCopyright",   stringize( VRC_COPYRIGHT )
      VALUE "InternalName",     stringize( VRC_ORIGINALFILENAME )
      VALUE "OriginalFilename", stringize( VRC_ORIGINALFILENAME )
      VALUE "ProductName",      stringize( VRC_PRODUCTNAME )
      VALUE "ProductVersion",   stringize( VRC_PRODUCTVERSION )
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x409, 1200
  END
END

From here on the possibilities are pretty much unlimited. Either define VRC_INCLUDE to the full path of an include file containing all the VRC_... definitions:

rc /d VRC_INCLUDE=$(VersionMainInclude) ... version.rc

or supply all definitions

rc /d VRC_COMPANYNAME=mycompany ... version.rc

or a combination of both.

To show you the possibilities, here's what I'm currently doing for all projects versioned with git:

  • every project has a version.h #defining just a short VRC_FILEDESCRIPTION and VRC_FILEVERSION
  • there's a master version.h #defining VRC_COMPANYNAME/VRC_COPYRIGHT/...
  • the project includes a .targets file that creates a version.res in a prebuild event
  • the msbuild prebuild event takes care of the interesting stuff: it creates a new temporary header file combining the other two, takes the short git SHA and the current data and appends that to the file description string so it ends up looking like

    Foo Dll [12e454re 30/07/2013]