Fix architecture detection on Windows in Makefile, bump SAVEGAMEVER

.. and use YQ2ARCH and YQ2OSTYPE instead of just ARCH and OSTYPE
for the defines, so it's consistent with the engine and xatrix+rogue.

$PROCESSOR_ARCHITECTURE seems to contain the architecture of the host,
but we need the architecture the current MinGW shell is targeting.
$MINGW_CHOST seems to be just that, and on my system it's either
i686-w64-mingw32 (mingw32.exe) or x86_64-w64-mingw32 (mingw64.exe)
(No idea what it looks like for Windows on ARM...)

As fixing this would otherwise break existing savegames, I bumped the
SAVEGAMEVER to "YQ2-4" and added a quirk for older savegameversions:
On Windows i386 savegames that contain "AMD64" instead of "i386" as
architecture are also accepted.
(For YQ2-1 this didn't seem necessary, apparently "i386" was hardcoded)
This commit is contained in:
Daniel Gibson 2021-01-14 03:53:47 +01:00
parent 40fb2366d1
commit 7275a593a6
3 changed files with 113 additions and 93 deletions

View file

@ -19,13 +19,13 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fno-strict-aliasing -fwrapv")
string(REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
# Operating system # Operating system
add_definitions(-DOSTYPE="${CMAKE_SYSTEM_NAME}") add_definitions(-DYQ2OSTYPE="${CMAKE_SYSTEM_NAME}")
# Architecture string # Architecture string
string(REGEX REPLACE "amd64" "x86_64" ARCH "${CMAKE_SYSTEM_PROCESSOR}") string(REGEX REPLACE "amd64" "x86_64" ARCH "${CMAKE_SYSTEM_PROCESSOR}")
string(REGEX REPLACE "i.86" "i386" ARCH "${ARCH}") string(REGEX REPLACE "i.86" "i386" ARCH "${ARCH}")
string(REGEX REPLACE "^arm.*" "arm" ARCH "${ARCH}") string(REGEX REPLACE "^arm.*" "arm" ARCH "${ARCH}")
add_definitions(-DARCH="${ARCH}") add_definitions(-DYQ2ARCH="${ARCH}")
# Linker Flags # Linker Flags
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")

View file

@ -16,28 +16,36 @@
# Detect the OS # Detect the OS
ifdef SystemRoot ifdef SystemRoot
OSTYPE := Windows YQ2_OSTYPE := Windows
else else
OSTYPE := $(shell uname -s) YQ2_OSTYPE := $(shell uname -s)
endif endif
# Special case for MinGW # Special case for MinGW
ifneq (,$(findstring MINGW,$(OSTYPE))) ifneq (,$(findstring MINGW,$(YQ2_OSTYPE)))
OSTYPE := Windows YQ2_OSTYPE := Windows
endif endif
# Detect the architecture # Detect the architecture
ifeq ($(OSTYPE), Windows) ifeq ($(YQ2_OSTYPE), Windows)
ifdef MINGW_CHOST
ifeq ($(MINGW_CHOST), x86_64-w64-mingw32)
YQ2_ARCH ?= x86_64
else # i686-w64-mingw32
YQ2_ARCH ?= i386
endif
else # windows, but MINGW_CHOST not defined
ifdef PROCESSOR_ARCHITEW6432 ifdef PROCESSOR_ARCHITEW6432
# 64 bit Windows # 64 bit Windows
ARCH := $(PROCESSOR_ARCHITEW6432) YQ2_ARCH ?= $(PROCESSOR_ARCHITEW6432)
else else
# 32 bit Windows # 32 bit Windows
ARCH := $(PROCESSOR_ARCHITECTURE) YQ2_ARCH ?= $(PROCESSOR_ARCHITECTURE)
endif endif
endif # windows but MINGW_CHOST not defined
else else
# Normalize some abiguous ARCH strings # Normalize some abiguous YQ2_ARCH strings
ARCH := $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/^arm.*/arm/') YQ2_ARCH ?= $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/^arm.*/arm/')
endif endif
# Detect the compiler # Detect the compiler
@ -71,7 +79,7 @@ endif
# -fPIC for position independend code. # -fPIC for position independend code.
# #
# -MMD to generate header dependencies. # -MMD to generate header dependencies.
ifeq ($(OSTYPE), Darwin) ifeq ($(YQ2_OSTYPE), Darwin)
CFLAGS := -O2 -fno-strict-aliasing -fomit-frame-pointer \ CFLAGS := -O2 -fno-strict-aliasing -fomit-frame-pointer \
-Wall -pipe -g -fwrapv -arch i386 -arch x86_64 -Wall -pipe -g -fwrapv -arch i386 -arch x86_64
else else
@ -97,13 +105,23 @@ endif
# ---------- # ----------
# Using the default x87 float math on 32bit x86 causes rounding trouble
# -ffloat-store could work around that, but the better solution is to
# just enforce SSE - every x86 CPU since Pentium3 supports that
# and this should even improve the performance on old CPUs
ifeq ($(YQ2_ARCH), i386)
override CFLAGS += -msse -mfpmath=sse
endif
# ----------
# Defines the operating system and architecture # Defines the operating system and architecture
CFLAGS += -DOSTYPE=\"$(OSTYPE)\" -DARCH=\"$(ARCH)\" CFLAGS += -DYQ2OSTYPE=\"$(YQ2_OSTYPE)\" -DYQ2ARCH=\"$(YQ2_ARCH)\"
# ---------- # ----------
# Base LDFLAGS. # Base LDFLAGS.
ifeq ($(OSTYPE), Darwin) ifeq ($(YQ2_OSTYPE), Darwin)
LDFLAGS := -shared -arch i386 -arch x86_64 LDFLAGS := -shared -arch i386 -arch x86_64
else else
LDFLAGS := -shared LDFLAGS := -shared
@ -140,7 +158,7 @@ clean:
# ---------- # ----------
# The zaero game # The zaero game
ifeq ($(OSTYPE), Windows) ifeq ($(YQ2_OSTYPE), Windows)
zaero: zaero:
@echo "===> Building game.dll" @echo "===> Building game.dll"
${Q}mkdir -p release ${Q}mkdir -p release
@ -246,7 +264,7 @@ ZAERO_DEPS= $(ZAERO_OBJS:.o=.d)
# ---------- # ----------
ifeq ($(OSTYPE), Windows) ifeq ($(YQ2_OSTYPE), Windows)
release/game.dll : $(ZAERO_OBJS) release/game.dll : $(ZAERO_OBJS)
@echo "===> LD $@" @echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) -o $@ $(ZAERO_OBJS) ${Q}$(CC) $(LDFLAGS) -o $@ $(ZAERO_OBJS)

View file

@ -54,19 +54,19 @@
* in tables/ are changed, otherwise * in tables/ are changed, otherwise
* strange things may happen. * strange things may happen.
*/ */
#define SAVEGAMEVER "YQ2-3" #define SAVEGAMEVER "YQ2-4"
/* /*
* This macros are used to prohibit loading of savegames * This macros are used to prohibit loading of savegames
* created on other systems or architectures. This will * created on other systems or architectures. This will
* crash q2 in spectacular ways * crash q2 in spectacular ways
*/ */
#ifndef OSTYPE #ifndef YQ2OSTYPE
#error OSTYPE should be defined by the build system #error YQ2OSTYPE should be defined by the build system
#endif #endif
#ifndef ARCH #ifndef YQ2ARCH
#error ARCH should be defined by the build system #error YQ2ARCH should be defined by the build system
#endif #endif
/* /*
@ -766,8 +766,8 @@ WriteGame(const char *filename, qboolean autosave)
strncpy(str_ver, SAVEGAMEVER, sizeof(str_ver)); strncpy(str_ver, SAVEGAMEVER, sizeof(str_ver));
strncpy(str_game, GAMEVERSION, sizeof(str_game)); strncpy(str_game, GAMEVERSION, sizeof(str_game));
strncpy(str_os, OSTYPE, sizeof(str_os) - 1); strncpy(str_os, YQ2OSTYPE, sizeof(str_os) - 1);
strncpy(str_arch, ARCH, sizeof(str_arch)); strncpy(str_arch, YQ2ARCH, sizeof(str_arch));
fwrite(str_ver, sizeof(str_ver), 1, f); fwrite(str_ver, sizeof(str_ver), 1, f);
fwrite(str_game, sizeof(str_game), 1, f); fwrite(str_game, sizeof(str_game), 1, f);
@ -817,85 +817,87 @@ ReadGame(const char *filename)
fread(str_os, sizeof(str_os), 1, f); fread(str_os, sizeof(str_os), 1, f);
fread(str_arch, sizeof(str_arch), 1, f); fread(str_arch, sizeof(str_arch), 1, f);
if (!strcmp(str_ver, SAVEGAMEVER)) static const struct {
{ const char* verstr;
save_ver = 3; int vernum;
} version_mappings[] = {
{"YQ2-1", 1},
{"YQ2-2", 2},
{"YQ2-3", 3},
{"YQ2-4", 4},
};
if (strcmp(str_game, GAMEVERSION)) for (i=0; i < sizeof(version_mappings)/sizeof(version_mappings[0]); ++i)
{
if (strcmp(version_mappings[i].verstr, str_ver) == 0)
{ {
fclose(f); save_ver = version_mappings[i].vernum;
gi.error("Savegame from an other game.so.\n"); break;
}
else if (strcmp(str_os, OSTYPE))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
else if (strcmp(str_arch, ARCH))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
} }
} }
else if (!strcmp(str_ver, "YQ2-2"))
{
save_ver = 2;
if (strcmp(str_game, GAMEVERSION)) if (save_ver == 0) // not found in mappings table
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
else if (strcmp(str_arch, ARCH))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
else if (!strcmp(str_ver, "YQ2-1"))
{
save_ver = 1;
if (strcmp(str_game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE_1))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
if (!strcmp(str_os, "Windows"))
{
/* Windows was forced to i386 */
if (strcmp(str_arch, "i386"))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
else
{
if (strcmp(str_arch, ARCH_1))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
}
else
{ {
fclose(f); fclose(f);
gi.error("Savegame from an incompatible version.\n"); gi.error("Savegame from an incompatible version.\n");
} }
if (save_ver == 1)
{
if (strcmp(str_game, GAMEVERSION) != 0)
{
fclose(f);
gi.error("Savegame from another game.so.\n");
}
else if (strcmp(str_os, OSTYPE_1) != 0)
{
fclose(f);
gi.error("Savegame from another os.\n");
}
#ifdef _WIN32
/* Windows was forced to i386 */
if (strcmp(str_arch, "i386") != 0)
{
fclose(f);
gi.error("Savegame from another architecture.\n");
}
#else
if (strcmp(str_arch, ARCH_1) != 0)
{
fclose(f);
gi.error("Savegame from another architecture.\n");
}
#endif
}
else // all newer savegame versions
{
if (strcmp(str_game, GAMEVERSION) != 0)
{
fclose(f);
gi.error("Savegame from another game.so.\n");
}
else if (strcmp(str_os, YQ2OSTYPE) != 0)
{
fclose(f);
gi.error("Savegame from another os.\n");
}
else if (strcmp(str_arch, YQ2ARCH) != 0)
{
#if defined(_WIN32) && (defined(__i386__) || defined(_M_IX86))
// before savegame version "YQ2-4" (and after version 1),
// the official Win32 binaries accidentally had the YQ2ARCH "AMD64"
// instead of "i386" set due to a bug in the Makefile.
// This quirk allows loading those savegames anyway
if (save_ver >= 4 || strcmp(str_arch, "AMD64") != 0)
#endif
{
fclose(f);
gi.error("Savegame from another architecture.\n");
}
}
}
g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME); g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
globals.edicts = g_edicts; globals.edicts = g_edicts;