Skip to content
Open
12 changes: 12 additions & 0 deletions AddOn.rc.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <Windows.h>

/* UTF-8 */
#pragma code_page(65001)


18000 STRS
BEGIN
3 + 1, /* VERSION_APPENDIX length */
0
"@addOnLanguage@" "\0" /* Version appendix for localized data */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
3 + 1, /* VERSION_APPENDIX length */
0
"@addOnLanguage@" "\0" /* Version appendix for localized data */
4,
0
"@addOnLanguage@\0"

Prefer 4 spaces to be in line with VersionInfo.rc.in.

That stray 0 looks odd. Doesn't look like anything in the documentation https://learn.microsoft.com/en-us/windows/win32/menurc/user-defined-resource

Prefer to do the length calculation for the string in CMake.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

END
4 changes: 3 additions & 1 deletion AddOnInfo.plist.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
<key>CFBundleExecutable</key>
<string>@addOnName@</string>
<key>GSAddOnDescription</key>
<string>@addOnDescription@</string>@privateBuild@
<string>@addOnDescription@</string>
<key>GSVersionAppendix</key>
<string>@languageCode@</string>@privateBuild@@autoupdate@
</dict>
</plist>
11 changes: 10 additions & 1 deletion BuildAddOn.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import zipfile
import tarfile

from LocalizationMappingTable import FillLocalizationMappingTable


def ParseArguments ():
parser = argparse.ArgumentParser ()
parser.add_argument ('-c', '--configFile', dest = 'configFile', required = True, help = 'JSON Configuration file')
Expand Down Expand Up @@ -206,16 +209,22 @@ def GetProjectGenerationParams (args, workspaceRootFolder, buildPath, platformNa
'-B', str (buildPath)
]

devkitDir = devKitFolder / "Support"
if platformName == 'WIN':
projGenParams.extend ([
'-G', GetInstalledVisualStudioGenerator (),
'-T', GetToolset (int (version)),
])
localizationMappingTable = FillLocalizationMappingTable (devkitDir)
winLangCharsetStr = '040904b0'
if languageCode != 'INT':
winLangCharsetStr = localizationMappingTable.get (languageCode, winLangCharsetStr)
projGenParams.append (f'-DAC_WIN_LANGCHARSET_STR={winLangCharsetStr}')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it comes from the header, but I don't like this *_STR/*Str suffix. Nothing else has this, so let's keep it that way.

elif platformName == 'MAC':
projGenParams.append ('-GXcode')

projGenParams.append (f'-DAC_VERSION={version}')
projGenParams.append (f'-DAC_API_DEVKIT_DIR={str (devKitFolder / "Support")}')
projGenParams.append (f'-DAC_API_DEVKIT_DIR={str (devkitDir)}')
projGenParams.append (f'-DAC_ADDON_LANGUAGE={languageCode}')

if release:
Expand Down
32 changes: 26 additions & 6 deletions CMakeCommon.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function (parse_version inValue outList)
endif ()
endfunction ()

function (generate_add_on_version_info outSemver)
function (generate_add_on_version_info outSemver addOnLanguage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the function is internal I almost feel like this parameter can be omitted, since it's present in the calling context anyway.

Either that or move it before the out parameter.

parse_version ("${addOnVersion}" vers)
if (NOT DEFINED vers)
message (FATAL_ERROR "'${addOnVersion}' does not follow the '123' or '1.23' or '1.2.3' version format.")
Expand All @@ -149,9 +149,21 @@ function (generate_add_on_version_info outSemver)

string (REGEX REPLACE [[(\\|")]] [[\\\1]] addOnDescription "${addOnDescription}")

if (autoupdate STREQUAL "1")
set (autoupdate "\n\t\t\tVALUE \"Autoupdate\", \"1\"")
else ()
set (autoupdate "")
endif ()
Comment on lines +152 to +156
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (autoupdate STREQUAL "1")
set (autoupdate "\n\t\t\tVALUE \"Autoupdate\", \"1\"")
else ()
set (autoupdate "")
endif ()
set (autoupdate "")
if (autoupdate STREQUAL "1")
set (autoupdate "\n\t\t\tVALUE \"Autoupdate\", \"1\"")
endif ()

In the other places as well.


set (winLangCharsetStr "${AC_WIN_LANGCHARSET_STR}")

set (out "${CMAKE_CURRENT_BINARY_DIR}/${target}-VersionInfo.rc")
configure_file ("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/VersionInfo.rc.in" "${out}" @ONLY)
target_sources ("${target}" PRIVATE "${out}")

set (addOnRes "${CMAKE_CURRENT_BINARY_DIR}/${target}-AddOn.rc")
configure_file ("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/AddOn.rc.in" "${addOnRes}" @ONLY)

target_sources ("${target}" PRIVATE "${out}" "${addOnRes}")
Comment on lines 160 to +166
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turn this into a loop with foreach (res IN ITEMS VersionInfo AddOn).

else ()
# BE on the safe side; load the info from an existing framework
file (READ "${devKitDir}/Frameworks/GSRoot.framework/Versions/A/Resources/Info.plist" plist_content NEWLINE_CONSUME)
Expand All @@ -172,11 +184,19 @@ function (generate_add_on_version_info outSemver)
string (REPLACE ' &apos\; addOnDescription "${addOnDescription}")
string (REPLACE \" &quot\; addOnDescription "${addOnDescription}")

set (languageCode "${addOnLanguage}")

set (privateBuild "\n\t\t<key>GSPrivateBuild</key>\n\t\t<string>1</string>")
if (NOT AC_ADDON_FOR_DISTRIBUTION)
set (privateBuild "")
endif ()

if (autoupdate STREQUAL "1")
set (autoupdate "\n\t\t<key>autoupdate</key>\n\t\t<string>1</string>")
else ()
set (autoupdate "")
endif ()

string (TOLOWER "${addOnName}" lowerAddOnName)
string (REGEX REPLACE "[ _]" "-" addOnNameIdentifier "${lowerAddOnName}")
set (bundleIdentifier "com.graphisoft.${addOnNameIdentifier}")
Expand Down Expand Up @@ -347,7 +367,7 @@ function (GenerateAddOnProject target acVersion devKitDir addOnSourcesFolder add
)
endif ()
endif ()
generate_add_on_version_info (semver)
generate_add_on_version_info (semver ${addOnLanguage})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer "${...}" for things you intend to pass as a single argument and where you don't want list expansion.

target_compile_definitions (
"${target}" PRIVATE
"ADDON_VERSION=\"${semver}\""
Expand Down Expand Up @@ -416,9 +436,9 @@ function (ReadConfigJson)
set ("${out}" "${${out}}" PARENT_SCOPE)
endforeach ()

# optional members (macOS code signing for start)
set (optionalMembers codesignIdentity developmentTeamId)
set (returnAs codesignIdentity developmentTeamId)
# optional members (macOS code signing for start, autoupdate next)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the comment here and below for the language list.

set (optionalMembers codesignIdentity developmentTeamId autoupdate)
set (returnAs codesignIdentity developmentTeamId autoupdate)
foreach (out members IN ZIP_LISTS returnAs optionalMembers)
string (JSON "${out}" ERROR_VARIABLE error GET "${json}" ${members})
if (error)
Expand Down
16 changes: 11 additions & 5 deletions CompileResources.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
import json
import pathlib
from pathlib import Path
from LocalizationMappingTable import FillLocalizationMappingTable

from JsonToGrcConverter import JsonToGrcConverter
from JsonToGrcConverter import JsonTranslator

class ResourceCompiler (object):
def __init__ (self, devKitPath: Path, acVersion: str, buildNum: str, addonName: str, languageCode: str, defaultLanguageCode: str, sourcesPath: Path, resourcesPath: Path, resourceObjectsPath: Path, permissiveLocalization: bool):
def __init__ (self, devKitPath: Path, acVersion: str, buildNum: str, addonName: str, languageCode: str, defaultLanguageCode: str,
sourcesPath: Path, resourcesPath: Path, resourceObjectsPath: Path, permissiveLocalization: bool):
self.devKitPath = devKitPath
self.acVersion = acVersion
self.buildNum = buildNum
Expand All @@ -27,7 +29,8 @@ def __init__ (self, devKitPath: Path, acVersion: str, buildNum: str, addonName:
self.permissiveLocalization = permissiveLocalization
self.resConvPath = None
self.nativeResourceFileExtension = None

self.localizationMappingTable = FillLocalizationMappingTable (devKitPath)

def GetPlatformDevKitLinkKey (self) -> str:
return ""

Expand Down Expand Up @@ -255,7 +258,8 @@ def RunResConv (self, platformSign: str, codepage: str, inputFilePath: Path) ->

class WinResourceCompiler (ResourceCompiler):
def __init__ (self, devKitPath: Path, acVersion: str, buildNum: str, addonName: str, languageCode: str, defaultLanguageCode: str, sourcesPath: Path, resourcesPath: Path, resourceObjectsPath: Path, permissiveLocalization: bool):
super (WinResourceCompiler, self).__init__ (devKitPath, acVersion, buildNum, addonName, languageCode, defaultLanguageCode, sourcesPath, resourcesPath, resourceObjectsPath, permissiveLocalization)
super (WinResourceCompiler, self).__init__ (devKitPath, acVersion, buildNum, addonName, languageCode, defaultLanguageCode,
sourcesPath, resourcesPath, resourceObjectsPath, permissiveLocalization)
self.resConvPath = devKitPath / 'Tools' / 'Win' / 'ResConv.exe'
self.nativeResourceFileExtension = '.rc2'

Expand Down Expand Up @@ -327,7 +331,8 @@ def CompileNativeResource (self, resultResourcePath: Path) -> None:

class MacResourceCompiler (ResourceCompiler):
def __init__ (self, devKitPath: Path, acVersion: str, buildNum: str, addonName: str, languageCode: str, defaultLanguageCode: str, sourcesPath: Path, resourcesPath: Path, resourceObjectsPath: Path, permissiveLocalization: bool):
super (MacResourceCompiler, self).__init__ (devKitPath, acVersion, buildNum, addonName, languageCode, defaultLanguageCode, sourcesPath, resourcesPath, resourceObjectsPath, permissiveLocalization)
super (MacResourceCompiler, self).__init__ (devKitPath, acVersion, buildNum, addonName, languageCode, defaultLanguageCode,
sourcesPath, resourcesPath, resourceObjectsPath, permissiveLocalization)
self.resConvPath = devKitPath / 'Tools' / 'OSX' / 'ResConv'
self.nativeResourceFileExtension = '.ro'

Expand Down Expand Up @@ -360,7 +365,8 @@ def CompileGRCResourceFile (self, grcFilePath: Path) -> bool:
return self.RunResConv ('M', 'utf16', precompiledGrcFilePath)

def CompileNativeResource (self, resultResourcePath: Path) -> None:
resultLocalizedResourcePath = resultResourcePath / 'English.lproj'
region_name = self.localizationMappingTable.get (self.languageCode, 'English')
resultLocalizedResourcePath = resultResourcePath / f'{region_name}.lproj'
if not resultLocalizedResourcePath.exists ():
resultLocalizedResourcePath.mkdir (parents=True)
resultLocalizableStringsPath = resultLocalizedResourcePath / 'Localizable.strings'
Expand Down
24 changes: 24 additions & 0 deletions LocalizationMappingTable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import platform
import re


def FillLocalizationMappingTable (devKitPath) -> str:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns a dict[str, str], not a str. You can also type hint that the devKitPath is a Path (from pathlib).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

# Dynamically generate a mapping table from GSLocalization.h
pattern = None
system = platform.system ()
if system == 'Windows':
pattern = r'#define\s+VERSION_APPENDIX\s+"([A-Z]+)"[\s\S]*?#define\s+WIN_LANGCHARSET_STR\s+"([^"]+)"'
elif system == 'Darwin':
pattern = r'#define\s+VERSION_APPENDIX\s+"([A-Z]+)"[\s\S]*?#define\s+MAC_REGION_NAME\s+"([^"]+)"'

assert pattern, 'Platform is not supported'

gsLocalizationPath = devKitPath / 'Inc' / 'GSLocalization.h'
with open(gsLocalizationPath, 'r', encoding='utf-8') as f:
gsLocalizationContent = f.read ()

if not pattern:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines above you already assert that the pattern is not None.

return {}

patternRegex = re.compile (pattern, re.MULTILINE)
return { m.group(1): m.group(2) for m in patternRegex.finditer (gsLocalizationContent) }
4 changes: 2 additions & 2 deletions VersionInfo.rc.in
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ BEGIN
/* https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block */
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BLOCK "@winLangCharsetStr@"
BEGIN
VALUE "CompanyName", "@addOnCompanyName@"
VALUE "FileDescription", "@addOnDescription@"
Expand All @@ -43,7 +43,7 @@ BEGIN
VALUE "PrivateBuild", "Not for distribution"
#endif
VALUE "ProductName", "@addOnName@"
VALUE "ProductVersion", "@version@"
VALUE "ProductVersion", "@version@"@autoupdate@
END
END
/* https://learn.microsoft.com/en-us/windows/win32/menurc/varfileinfo-block */
Expand Down