Files
mtgodot-poc/extension/src/port/CMakeLists.txt
T

243 lines
14 KiB
CMake

# port_logic — mirror of the 40250 client logic (extension/src/port/<Lib>/<File>.{h,cpp}).
# No godot-cpp dependency: libmtgodot links it, and it also builds on its own (top-level
# -DMTGODOT_BUILD_EXTENSION=OFF -DMTGODOT_BUILD_PORT=ON) for targets without an extension build.
# See docs/PORT-PLAN.md batch 2A.
file(GLOB_RECURSE MT_PORT_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE MT_PORT_HEADERS CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
if(WIN32)
# Stand-ins for Windows SDK headers; on Windows the real ones are used.
list(FILTER MT_PORT_HEADERS EXCLUDE REGEX "/common/shim/win32/")
endif()
# The script layer needs the embedded interpreter (mt3p::python), which has no Windows build yet
# (PORT-PLAN 批次 2P step 4). Without it, ScriptLib and its <Python-2.7/*> shims are left out.
# The units outside ScriptLib that reach it: UserInterface/StdAfx.h includes ScriptLib/StdAfx.h (as the
# original PCH does), and PythonPackModule.cpp is a Python module. Both go with it.
set(MT_PORT_NEEDS_PYTHON "/ScriptLib/|/UserInterface/StdAfx\\.h|/UserInterface/PythonPackModule\\.cpp")
if(NOT TARGET mtpython)
list(FILTER MT_PORT_SOURCES EXCLUDE REGEX "${MT_PORT_NEEDS_PYTHON}")
list(FILTER MT_PORT_HEADERS EXCLUDE REGEX "${MT_PORT_NEEDS_PYTHON}|/common/shim/sdk/Python-2\\.7/")
endif()
add_library(port_logic STATIC ${MT_PORT_SOURCES})
target_include_directories(port_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
# 40250 system headers the ported sources keep including verbatim: D3D8/D3DX/Miles SDK types everywhere,
# Windows/CRT ones only where the platform has none.
set(MT_PORT_SHIMS ${CMAKE_CURRENT_SOURCE_DIR}/common/shim/sdk)
if(NOT WIN32)
list(APPEND MT_PORT_SHIMS ${CMAKE_CURRENT_SOURCE_DIR}/common/shim/win32)
endif()
target_include_directories(port_logic PUBLIC ${MT_PORT_SHIMS})
# Libraries 40250 links that are vendored as-is: <lzo/lzo1x.h> (EterBase/lzo.h), <cryptopp/*>
# (EterBase/cipher.h), <Python-2.7/*> (ScriptLib).
target_link_libraries(port_logic PUBLIC mt3p::minilzo mt3p::cryptopp)
# common/Win32Crt.cpp converts non-UTF-8 code pages with iconv. macOS ships it as a separate library;
# extension/CMakeLists.txt finds it for mtnet, but the port-only build (script/port_gate.sh) never reads that file.
find_library(MT_ICONV_LIBRARY NAMES iconv)
if(MT_ICONV_LIBRARY)
target_link_libraries(port_logic PUBLIC ${MT_ICONV_LIBRARY})
endif()
if(TARGET mtpython)
target_link_libraries(port_logic PUBLIC mt3p::python)
endif()
# 40250 sources carry MSVC `#pragma warning(...)` lines verbatim, and non-literal printf formats
# (EterImageLib/StdAfx.h) that the Android toolchain turns into errors.
set(MT_PORT_WARNING_FLAGS)
if(NOT MSVC)
set(MT_PORT_WARNING_FLAGS -Wno-unknown-pragmas -Wno-format-security)
endif()
target_compile_options(port_logic PUBLIC ${MT_PORT_WARNING_FLAGS})
target_compile_features(port_logic PUBLIC cxx_std_20)
# Armadillo nanomite markers (StdAfx.h `__asm _emit` jumps over a signature): x86-32 MSVC inline asm that no
# target here accepts, and a no-op without the Armadillo wrapper, so they expand to nothing.
target_compile_definitions(port_logic PUBLIC "NANOBEGIN=" "NANOEND=")
if(MINGW)
target_compile_options(port_logic PUBLIC -include ${CMAKE_CURRENT_SOURCE_DIR}/common/Win32MinMax.h)
endif()
# EterPack/EterPack.cpp includes EterPackKeys.generated.h in place of the two TEA key arrays: the keys are
# read from the reference EterPack.cpp at configure time and written into the build tree, never the repository.
# Without the reference the arrays are zero and every COMPRESS/SECURITY entry fails to decode.
set(MT_40250_SOURCE "$ENV{MT_40250_SOURCE}" CACHE PATH "40250 ClientVS22/source reference root")
if(NOT MT_40250_SOURCE)
set(MT_40250_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/../../../../40250/Server Client TMP4/ClientVS22/source")
endif()
set(MT_PORT_GENERATED ${CMAKE_CURRENT_BINARY_DIR}/generated)
set(mt_eterpack_ref "${MT_40250_SOURCE}/EterPack/EterPack.cpp")
set(mt_eterpack_keys "")
if(EXISTS "${mt_eterpack_ref}")
file(READ "${mt_eterpack_ref}" mt_ref_text)
foreach(arr s_adwEterPackKey s_adwEterPackSecurityKey)
string(REGEX MATCH "static DWORD ${arr}\\[\\][ \t\r\n]*=[ \t\r\n]*{[^}]*}" block "${mt_ref_text}")
string(REGEX MATCHALL "[0-9]+" values "${block}")
list(LENGTH values n)
if(NOT n EQUAL 4)
message(FATAL_ERROR "port: ${arr} not found in ${mt_eterpack_ref}")
endif()
list(JOIN values ", " values)
string(APPEND mt_eterpack_keys "static DWORD ${arr}[] = { ${values} };\n")
endforeach()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${mt_eterpack_ref}")
else()
message(WARNING "port: ${mt_eterpack_ref} not found (set MT_40250_SOURCE); EterPack keys are zero")
string(APPEND mt_eterpack_keys "static DWORD s_adwEterPackKey[] = { 0, 0, 0, 0 };\n"
"static DWORD s_adwEterPackSecurityKey[] = { 0, 0, 0, 0 };\n")
endif()
file(CONFIGURE OUTPUT ${MT_PORT_GENERATED}/EterPackKeys.generated.h
CONTENT "// Generated from the 40250 reference EterPack.cpp by port/CMakeLists.txt; do not commit.\n#pragma once\n${mt_eterpack_keys}")
target_include_directories(port_logic PRIVATE ${MT_PORT_GENERATED})
if(WIN32)
target_link_libraries(port_logic PUBLIC winmm)
endif()
# 40250 Distribute|Win32 preprocessor definitions per library (vs_files/<Lib>/<Lib>.vcxproj),
# minus WIN32/_WINDOWS/_LIB/_CRT_SECURE_NO_WARNINGS: Windows-only branches go through platform/,
# never through ported logic. UserInterface/Locale_inc.h feature macros come with that header.
set(MT_PORT_DEFINES_default NDEBUG)
set(MT_PORT_DEFINES_GameLib NDEBUG USE_LOD)
set(MT_PORT_DEFINES_UserInterface NDEBUG USE_LOD _DISTRIBUTE)
function(mt_port_apply_defines file)
file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${file})
string(REGEX REPLACE "/.*" "" lib "${rel}")
if(DEFINED MT_PORT_DEFINES_${lib})
set(defs ${MT_PORT_DEFINES_${lib}})
else()
set(defs ${MT_PORT_DEFINES_default})
endif()
set_property(SOURCE ${file} APPEND PROPERTY COMPILE_DEFINITIONS ${defs})
endfunction()
foreach(src IN LISTS MT_PORT_SOURCES)
mt_port_apply_defines(${src})
endforeach()
# Gate: every header under port/ compiles on its own (and twice, for its include guard), with its
# library's definitions. As in 40250, where each library's StdAfx.h is the precompiled header of
# every translation unit, the library's StdAfx.h comes first. Built by default, so every platform
# build enforces it.
set(MT_PORT_GATE_SOURCES)
foreach(hdr IN LISTS MT_PORT_HEADERS)
file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${hdr})
string(MAKE_C_IDENTIFIER "${rel}" id)
set(tu ${CMAKE_CURRENT_BINARY_DIR}/header_gate/${id}.cpp)
string(REGEX REPLACE "/.*" "" lib "${rel}")
set(pch "")
# 40250 spells it StdAfx.h or Stdafx.h; use the on-disk name for case-sensitive hosts.
file(GLOB stdafx RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${lib}/[Ss]td[Aa]fx.h)
if(NOT lib STREQUAL "common" AND stdafx)
set(pch "#include \"${stdafx}\"\n")
endif()
file(CONFIGURE OUTPUT ${tu} CONTENT "${pch}#include \"${rel}\"\n#include \"${rel}\"\n")
set_property(SOURCE ${tu} APPEND PROPERTY OBJECT_DEPENDS ${hdr})
list(APPEND MT_PORT_GATE_SOURCES ${tu})
# Definitions follow the header's library, not the generated file's location.
if(DEFINED MT_PORT_DEFINES_${lib})
set_property(SOURCE ${tu} APPEND PROPERTY COMPILE_DEFINITIONS ${MT_PORT_DEFINES_${lib}})
else()
set_property(SOURCE ${tu} APPEND PROPERTY COMPILE_DEFINITIONS ${MT_PORT_DEFINES_default})
endif()
endforeach()
add_library(port_header_gate OBJECT ${MT_PORT_GATE_SOURCES})
target_include_directories(port_header_gate PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${MT_PORT_SHIMS})
target_link_libraries(port_header_gate PRIVATE mt3p::minilzo mt3p::cryptopp)
if(TARGET mtpython)
target_link_libraries(port_header_gate PRIVATE mt3p::python)
endif()
target_compile_features(port_header_gate PRIVATE cxx_std_20)
target_compile_definitions(port_header_gate PRIVATE "NANOBEGIN=" "NANOEND=")
if(MINGW)
target_compile_options(port_header_gate PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/common/Win32MinMax.h)
endif()
target_compile_options(port_header_gate PRIVATE ${MT_PORT_WARNING_FLAGS})
add_dependencies(port_logic port_header_gate)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../platform ${CMAKE_CURRENT_BINARY_DIR}/../platform)
if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
add_executable(port_utils_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_utils_test.cpp)
target_link_libraries(port_utils_test PRIVATE port_platform)
add_test(NAME port.utils COMMAND $<TARGET_FILE:port_utils_test>)
add_executable(port_common_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_common_test.cpp)
target_link_libraries(port_common_test PRIVATE port_logic)
add_test(NAME port.common COMMAND $<TARGET_FILE:port_common_test>)
# Against the real 40250 Client/pack next to the reference source; skipped (77) when it is missing,
# failed instead under MT_ASSETS_STRICT=1.
set(MT_40250_CLIENT "$ENV{MT_40250_CLIENT}" CACHE PATH "40250 Client directory (pack/, Eternexus/)")
if(NOT MT_40250_CLIENT)
set(MT_40250_CLIENT "${MT_40250_SOURCE}/../../Client")
endif()
add_executable(port_eterpack_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_eterpack_test.cpp)
target_link_libraries(port_eterpack_test PRIVATE port_platform)
add_test(NAME port.eterpack COMMAND $<TARGET_FILE:port_eterpack_test> ${MT_40250_CLIENT})
set_tests_properties(port.eterpack PROPERTIES SKIP_RETURN_CODE 77)
# 批次 2V0-g: the 40250 font path over the FreeType GDI emulation; needs a system Tahoma.
add_executable(port_text_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_text_test.cpp)
target_link_libraries(port_text_test PRIVATE port_platform)
add_test(NAME port.text COMMAND $<TARGET_FILE:port_text_test>)
set_tests_properties(port.text PROPERTIES SKIP_RETURN_CODE 77)
# 批次 2V1: Packet.h struct sizes against the classic wire layouts.
add_executable(port_packet_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_packet_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_packet_test_wire.cpp)
target_link_libraries(port_packet_test PRIVATE port_logic)
add_test(NAME port.packet COMMAND $<TARGET_FILE:port_packet_test>)
add_executable(port_net_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_net_test.cpp)
target_link_libraries(port_net_test PRIVATE port_platform)
add_test(NAME port.net COMMAND $<TARGET_FILE:port_net_test>)
if(TARGET mtpython)
add_executable(port_python_launcher_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_python_launcher_test.cpp)
target_link_libraries(port_python_launcher_test PRIVATE port_platform)
add_dependencies(port_python_launcher_test mtpython_stdlib)
add_test(NAME port.python_launcher
COMMAND $<TARGET_FILE:port_python_launcher_test> ${MT_40250_CLIENT} ${MT_PYTHON_STDLIB_ZIP})
set_tests_properties(port.python_launcher PROPERTIES SKIP_RETURN_CODE 77)
# EterPythonLib 的窗口树(批次 2V0-b)。需要解释器(CWindowManager 的构造函数就调 Python),
# 但不需要 40250 的 Client/pack —— 布局/命中/事件都不读资源。
add_executable(port_window_tree_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_window_tree_test.cpp)
target_link_libraries(port_window_tree_test PRIVATE port_platform)
add_dependencies(port_window_tree_test mtpython_stdlib)
add_test(NAME port.window_tree
COMMAND $<TARGET_FILE:port_window_tree_test> ${MT_PYTHON_STDLIB_ZIP})
set_tests_properties(port.window_tree PROPERTIES SKIP_RETURN_CODE 77)
# 批次 2V0-f: the real system.py through app.Loop() on PythonBoot's script thread; needs the pack.
add_executable(port_app_loop_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_app_loop_test.cpp)
target_link_libraries(port_app_loop_test PRIVATE port_platform)
add_dependencies(port_app_loop_test mtpython_stdlib)
add_test(NAME port.app_loop
COMMAND $<TARGET_FILE:port_app_loop_test> ${MT_40250_CLIENT} ${MT_PYTHON_STDLIB_ZIP})
set_tests_properties(port.app_loop PROPERTIES SKIP_RETURN_CODE 77)
add_executable(port_login_flow_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_login_flow_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_login_flow_server.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../net/classic/classic_cipher.cpp)
target_link_libraries(port_login_flow_test PRIVATE port_platform)
add_dependencies(port_login_flow_test mtpython_stdlib)
add_test(NAME port.login_flow
COMMAND $<TARGET_FILE:port_login_flow_test> ${MT_40250_CLIENT} ${MT_PYTHON_STDLIB_ZIP})
set_tests_properties(port.login_flow PROPERTIES SKIP_RETURN_CODE 77)
# 2V2-e: the same fake server as a process, for the Godot-driven render run
# (script/python_game_render_test.sh).
add_executable(port_fake_login_server ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_fake_login_server_main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_login_flow_server.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../net/classic/classic_cipher.cpp)
target_link_libraries(port_fake_login_server PRIVATE port_platform)
# 2V1-e: the same path against a live 40250 server; skipped unless MT_LIVE_* is set (see the test).
add_test(NAME port.login_live
COMMAND $<TARGET_FILE:port_login_flow_test> ${MT_40250_CLIENT} ${MT_PYTHON_STDLIB_ZIP} live)
set_tests_properties(port.login_live PROPERTIES SKIP_RETURN_CODE 77 RUN_SERIAL TRUE)
add_executable(port_python_ui_modules_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_python_ui_modules_test.cpp)
target_link_libraries(port_python_ui_modules_test PRIVATE port_platform)
add_dependencies(port_python_ui_modules_test mtpython_stdlib)
add_test(NAME port.python_ui_modules
COMMAND $<TARGET_FILE:port_python_ui_modules_test> ${MT_PYTHON_STDLIB_ZIP})
endif()
endif()