Browse Source

Merge pull request #368 from FWGS/buildsystems-overhaul

Buildsystems overhaul
fix-cwd-path
nekonomicon 2 years ago committed by GitHub
parent
commit
9a4eddfba9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 109
      CMakeLists.txt
  2. 140
      cl_dll/wscript
  3. 131
      cmake/LibraryNaming.cmake
  4. 132
      dlls/wscript
  5. 16
      mod_options.txt
  6. 175
      public/build.h
  7. 11
      scripts/waifulib/compiler_optimizations.py
  8. 17
      scripts/waifulib/library_naming.py
  9. 79
      scripts/waifulib/vgui.py
  10. 14
      waf
  11. 12
      waf.bat
  12. 286
      wscript

109
CMakeLists.txt

@ -20,7 +20,8 @@
# SOFTWARE. # SOFTWARE.
# #
cmake_minimum_required(VERSION 2.8.12) # 3.9 added captures in if(MATCHES)
cmake_minimum_required(VERSION 3.9)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.15.0") if(NOT ${CMAKE_VERSION} VERSION_LESS "3.15.0")
cmake_policy(SET CMP0091 NEW) cmake_policy(SET CMP0091 NEW)
@ -58,28 +59,33 @@ else()
option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" OFF) option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" OFF)
endif() endif()
option(BARNACLE_FIX_VISIBILITY "Enable barnacle tongue length fix" OFF)
option(CLIENT_WEAPONS "Enable client local weapons prediction" ON)
option(CROWBAR_IDLE_ANIM "Enable crowbar idle animation" OFF)
option(CROWBAR_DELAY_FIX "Enable crowbar attack delay fix" OFF)
option(CROWBAR_FIX_RAPID_CROWBAR "Enable rapid crowbar fix" OFF)
option(GAUSS_OVERCHARGE_FIX "Enable gauss overcharge fix" OFF)
option(TRIPMINE_BEAM_DUPLICATION_FIX "Enable fix of tripmine beam duplication on level transition" OFF)
option(HANDGRENADE_DEPLOY_FIX "Enable handgrenade deploy animation fix after finishing a throw" OFF)
option(WEAPONS_ANIMATION_TIMES_FIX "Enable animation times fix for some weapons" OFF)
option(OEM_BUILD "Enable OEM Build" OFF)
option(HLDEMO_BUILD "Enable Demo Build" OFF)
set(GAMEDIR "valve" CACHE STRING "Gamedir path")
set(SERVER_INSTALL_DIR "dlls" CACHE STRING "Where put server dll")
set(CLIENT_INSTALL_DIR "cl_dlls" CACHE STRING "Where put client dll")
set(SERVER_LIBRARY_NAME "hl" CACHE STRING "Library name for PC platforms")
message(STATUS "Half-Life")
#----------------- #-----------------
# MAIN BUILD CODE \ # MAIN BUILD CODE \
###################\ ###################\
file(STRINGS "mod_options.txt" MOD_OPTIONS_STRINGS REGEX "^([A-Za-z0-9_]+)=([A-Za-z0-9_]+)\ \#\ (.*)$")
foreach(LINE IN LISTS MOD_OPTIONS_STRINGS)
# file() itself doesn't populate CMAKE_MATCH_<n>, so
# reparse the string
if(${LINE} MATCHES "^([A-Za-z0-9_]+)=([A-Za-z0-9_]+)\ \#\ (.*)$")
# detect boolean options
if(${CMAKE_MATCH_2} STREQUAL "ON" OR ${CMAKE_MATCH_2} STREQUAL "OFF")
option(${CMAKE_MATCH_1} "${CMAKE_MATCH_3}" ${CMAKE_MATCH_2})
# let's check it here as well
if(${CMAKE_MATCH_1})
message(STATUS ${CMAKE_MATCH_3} " is enabled")
add_definitions(-D${CMAKE_MATCH_1})
else()
message(STATUS ${CMAKE_MATCH_3} " is disabled")
endif()
else()
set(${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE STRING "${CMAKE_MATCH_3}")
endif()
endif()
endforeach()
if(HLDEMO_BUILD AND OEM_BUILD) if(HLDEMO_BUILD AND OEM_BUILD)
message(FATAL_ERROR "Don't mix Demo and OEM builds!") message(FATAL_ERROR "Don't mix Demo and OEM builds!")
endif() endif()
@ -109,76 +115,11 @@ else()
message(STATUS "Building for 32 Bit") message(STATUS "Building for 32 Bit")
endif() endif()
if(CLIENT_WEAPONS)
message(STATUS "Client weapons enabled.")
add_definitions(-DCLIENT_WEAPONS)
endif()
if(BARNACLE_FIX_VISIBILITY)
message(STATUS "Barnacle tongue fix enabled")
add_definitions(-DBARNACLE_FIX_VISIBILITY)
endif()
if(CROWBAR_IDLE_ANIM)
message(STATUS "Crowbar idle animation enabled")
add_definitions(-DCROWBAR_IDLE_ANIM)
endif()
if(CROWBAR_DELAY_FIX)
message(STATUS "Crowbar attack delay fix enabled")
add_definitions(-DCROWBAR_DELAY_FIX)
endif()
if(CROWBAR_FIX_RAPID_CROWBAR)
message(STATUS "Rapid crowbar fix enabled")
add_definitions(-DCROWBAR_FIX_RAPID_CROWBAR)
endif()
if(GAUSS_OVERCHARGE_FIX)
message(STATUS "Gauss overcharge fix enabled")
add_definitions(-DGAUSS_OVERCHARGE_FIX)
endif()
if(TRIPMINE_BEAM_DUPLICATION_FIX)
message(STATUS "Tripmine beam duplication fix enabled")
add_definitions(-DTRIPMINE_BEAM_DUPLICATION_FIX)
endif()
if(HANDGRENADE_DEPLOY_FIX)
message(STATUS "Handgrenade deploy animation fix enabled")
add_definitions(-DHANDGRENADE_DEPLOY_FIX)
endif()
if(WEAPONS_ANIMATION_TIMES_FIX)
message(STATUS "Weapons animation times fix enabled")
add_definitions(-DWEAPONS_ANIMATION_TIMES_FIX)
endif()
if(OEM_BUILD)
message(STATUS "OEM build enabled")
add_definitions(-DOEM_BUILD)
endif()
if(HLDEMO_BUILD)
message(STATUS "Demo build enabled")
add_definitions(-DHLDEMO_BUILD)
endif()
if (MINGW) if (MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--add-stdcall-alias") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--add-stdcall-alias")
endif() endif()
# add_compile_options for older cmake versions
if(${CMAKE_VERSION} VERSION_LESS "3.0.2")
macro(add_compile_options)
set(list_var "${ARGV}")
foreach(arg IN LISTS list_var)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${arg}")
endforeach()
endmacro()
endif()
if(NOT MSVC) if(NOT MSVC)
#add_compile_options(-Wempty-body) # GCC/Clang flag #add_compile_options(-Wempty-body) # GCC/Clang flag
add_compile_options(-Wreturn-type) # GCC/Clang flag add_compile_options(-Wreturn-type) # GCC/Clang flag

140
cl_dll/wscript

@ -6,27 +6,70 @@ from waflib import Utils
import os import os
def options(opt): def options(opt):
# stub grp = opt.add_option_group('Client options')
return
grp.add_option('--enable-vgui', action = 'store_true', dest = 'USE_VGUI', default = False,
help = 'Enable VGUI1')
grp.add_option('--enable-vgui2', action = 'store_true', dest = 'USE_VGUI2', default = False,
help = 'Enable VGUI2. UNDONE')
grp.add_option('--enable-novgui-motd', action = 'store_true', dest = 'USE_NOVGUI_MOTD', default = False,
help = 'Prefer non-VGUI MOTD when USE_VGUI is enabled')
grp.add_option('--enable-novgui-scoreboard', action = 'store_true', dest = 'USE_NOVGUI_SCOREBOARD', default = False,
help = 'Prefer non-VGUI Scoreboard when USE_VGUI is enabled')
grp.add_option('--disable-goldsrc-support', action = 'store_false', dest = 'GOLDSOURCE_SUPPORT',
default=True, help = 'disable GoldSource compatibility')
opt.load('vgui')
def configure(conf): def configure(conf):
if conf.env.DEST_OS == 'win32': conf.env.USE_VGUI = conf.options.USE_VGUI
conf.check_cxx(lib='user32') conf.env.USE_NOVGUI_MOTD = conf.options.USE_NOVGUI_MOTD
conf.env.USE_NOVGUI_SCOREBOARD = conf.options.USE_NOVGUI_SCOREBOARD
conf.env.USE_VOICEMGR = conf.options.USE_VOICEMGR
conf.env.GOLDSOURCE_SUPPORT = conf.options.GOLDSOURCE_SUPPORT
if conf.env.USE_VGUI:
conf.load('vgui')
if not conf.check_vgui():
conf.fatal('VGUI was enabled but VGUI cannot be used')
def build(bld):
libs = []
defines = ['CLIENT_DLL']
includes = ['.',
'../dlls',
'../common',
'../engine',
'../pm_shared',
'../game_shared',
'../public']
excluded_files = ['GameStudioModelRenderer_Sample.cpp',
'game_shared/voice_vgui_tweakdlg.cpp',
'game_shared/voice_gamemgr.cpp',
'game_shared/voice_status.cpp']
if conf.env.GOLDSRC: if bld.env.USE_VGUI:
if conf.env.DEST_OS == 'win32': defines += ['USE_VGUI']
conf.check_cxx(lib='winmm') libs += ['VGUI']
if bld.env.USE_NOVGUI_MOTD:
defines += ['USE_NOVGUI_MOTD']
else: else:
conf.check_cc(lib='dl') excluded_files += ['MOTD.cpp']
def build(bld): if bld.env.USE_NOVGUI_SCOREBOARD:
source = bld.path.parent.ant_glob([ defines += ['USE_NOVGUI_SCOREBOARD']
'pm_shared/*.c' else:
]) excluded_files += ['scoreboard.cpp']
source += bld.path.ant_glob([ else:
'hl/*.cpp' includes += ['../utils/fake_vgui/include']
]) excluded_files += ['voice_status.cpp',
'vgui_*.cpp',
'game_shared/vgui_*.cpp',
'game_shared/voice_banmgr.cpp']
source = bld.path.ant_glob('**/*.cpp', excl=excluded_files)
source += bld.path.parent.ant_glob('game_shared/*.cpp', excl=excluded_files)
source += bld.path.parent.ant_glob([ source += bld.path.parent.ant_glob([
'pm_shared/*.c',
'dlls/crossbow.cpp', 'dlls/crossbow.cpp',
'dlls/crowbar.cpp', 'dlls/crowbar.cpp',
'dlls/egon.cpp', 'dlls/egon.cpp',
@ -42,78 +85,21 @@ def build(bld):
'dlls/squeakgrenade.cpp', 'dlls/squeakgrenade.cpp',
'dlls/tripmine.cpp' 'dlls/tripmine.cpp'
]) ])
source += [
'GameStudioModelRenderer.cpp',
'MOTD.cpp',
'StudioModelRenderer.cpp',
'ammo.cpp',
'ammo_secondary.cpp',
'ammohistory.cpp',
'battery.cpp',
'cdll_int.cpp',
'com_weapons.cpp',
'death.cpp',
'demo.cpp',
'entity.cpp',
'ev_hldm.cpp',
'ev_common.cpp',
'events.cpp',
'flashlight.cpp',
'geiger.cpp',
'health.cpp',
'hud.cpp',
'hud_msg.cpp',
'hud_redraw.cpp',
'hud_spectator.cpp',
'hud_update.cpp',
'in_camera.cpp',
'input.cpp',
'input_goldsource.cpp',
'input_mouse.cpp',
'input_xash3d.cpp',
'menu.cpp',
'message.cpp',
'parsemsg.cpp',
'saytext.cpp',
'scoreboard.cpp',
'status_icons.cpp',
'statusbar.cpp',
'studio_util.cpp',
'text_message.cpp',
'train.cpp',
'tri.cpp',
'util.cpp',
'view.cpp'
]
includes = [
'.',
'hl/',
'../dlls',
'../common',
'../engine',
'../pm_shared',
'../game_shared',
'../public',
'../utils/fake_vgui/include'
]
defines = ['CLIENT_DLL']
if bld.env.GOLDSRC:
defines += ['GOLDSOURCE_SUPPORT']
libs = []
if bld.env.DEST_OS == 'win32': if bld.env.DEST_OS == 'win32':
libs += ["USER32"] libs += ['USER32']
if bld.env.GOLDSOURCE_SUPPORT:
defines += ['GOLDSOURCE_SUPPORT']
if bld.env.GOLDSRC:
if bld.env.DEST_OS == 'win32': if bld.env.DEST_OS == 'win32':
libs += ["WINMM"] libs += ["WINMM"]
else: else:
libs += ['DL'] libs += ['DL']
if bld.env.DEST_OS not in ['android', 'dos']: if bld.env.DEST_OS not in ['android', 'dos']:
install_path = os.path.join(bld.env.GAMEDIR, bld.env.CLIENT_DIR) install_path = os.path.join(bld.env.GAMEDIR, bld.env.CLIENT_INSTALL_DIR)
else: else:
install_path = bld.env.PREFIX install_path = bld.env.PREFIX

131
cmake/LibraryNaming.cmake

@ -1,54 +1,88 @@
include(CheckSymbolExists) include(CheckSymbolExists)
# generated(see comments in public/build.h) macro(check_build_target symbol)
# cat build.h | grep '^#undef XASH' | awk '{ print "check_symbol_exists(" $2 " \"build.h\" " $2 ")" }' check_symbol_exists(${symbol} "build.h" ${symbol})
endmacro()
macro(check_group_build_target symbol group)
if(NOT ${group})
check_build_target(${symbol})
if(${symbol})
set(${group} TRUE)
endif()
else()
set(${symbol} FALSE)
endif()
endmacro()
# So there is a problem:
# 1. Number of these symbols only grows, as we support more and more ports
# 2. CMake was written by morons and can't check these symbols in parallel
# 3. MSVC is very slow at everything (startup, parsing, generating error)
# Solution: group these symbols and set variable if one of them was found
# this way we can reorder to reorder them by most common configurations
# but we can't generate this list anymore! ... OR IS IT ???
# Well, after reordering positions in engine's buildenums.h, we can partially autogenerate this list!
# echo "check_build_target(XASH_64BIT)"
# grep "#define PLATFORM" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_PLATFORM)" }'
# grep "#define ARCHITECTURE" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_ARCHITECTURE)"
# grep "#define ENDIAN" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 "_ENDIAN XASH_ENDIANNESS)"}'
# echo "if(XASH_ARM)"
# grep '^#undef XASH' build.h | grep "XASH_ARM[v_]" | awk '{ print "check_build_target(" $2 ")"}'
# echo "endif()"
# echo "if(XASH_RISCV)"
# grep '^#undef XASH' build.h | grep "XASH_RISCV_" | awk '{ print "check_build_target(" $2 ")"}'
# echo "endif()"
set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/public/") set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/public/")
check_symbol_exists(XASH_64BIT "build.h" XASH_64BIT) check_build_target(XASH_64BIT)
check_symbol_exists(XASH_AMD64 "build.h" XASH_AMD64) check_group_build_target(XASH_WIN32 XASH_PLATFORM)
check_symbol_exists(XASH_ANDROID "build.h" XASH_ANDROID) check_group_build_target(XASH_LINUX XASH_PLATFORM)
check_symbol_exists(XASH_APPLE "build.h" XASH_APPLE) check_group_build_target(XASH_FREEBSD XASH_PLATFORM)
check_symbol_exists(XASH_ARM "build.h" XASH_ARM) check_group_build_target(XASH_ANDROID XASH_PLATFORM)
check_symbol_exists(XASH_ARM_HARDFP "build.h" XASH_ARM_HARDFP) check_group_build_target(XASH_APPLE XASH_PLATFORM)
check_symbol_exists(XASH_ARM_SOFTFP "build.h" XASH_ARM_SOFTFP) check_group_build_target(XASH_NETBSD XASH_PLATFORM)
check_symbol_exists(XASH_ARMv4 "build.h" XASH_ARMv4) check_group_build_target(XASH_OPENBSD XASH_PLATFORM)
check_symbol_exists(XASH_ARMv5 "build.h" XASH_ARMv5) check_group_build_target(XASH_EMSCRIPTEN XASH_PLATFORM)
check_symbol_exists(XASH_ARMv6 "build.h" XASH_ARMv6) check_group_build_target(XASH_DOS4GW XASH_PLATFORM)
check_symbol_exists(XASH_ARMv7 "build.h" XASH_ARMv7) check_group_build_target(XASH_HAIKU XASH_PLATFORM)
check_symbol_exists(XASH_ARMv8 "build.h" XASH_ARMv8) check_group_build_target(XASH_SERENITY XASH_PLATFORM)
check_symbol_exists(XASH_BIG_ENDIAN "build.h" XASH_BIG_ENDIAN) check_group_build_target(XASH_IRIX XASH_PLATFORM)
check_symbol_exists(XASH_BSD "build.h" XASH_BSD) check_group_build_target(XASH_NSWITCH XASH_PLATFORM)
check_symbol_exists(XASH_DOS4GW "build.h" XASH_DOS4GW) check_group_build_target(XASH_PSVITA XASH_PLATFORM)
check_symbol_exists(XASH_E2K "build.h" XASH_E2K) check_group_build_target(XASH_LINUX_UNKNOWN XASH_PLATFORM)
check_symbol_exists(XASH_EMSCRIPTEN "build.h" XASH_EMSCRIPTEN) check_group_build_target(XASH_X86 XASH_ARCHITECTURE)
check_symbol_exists(XASH_FREEBSD "build.h" XASH_FREEBSD) check_group_build_target(XASH_AMD64 XASH_ARCHITECTURE)
check_symbol_exists(XASH_HAIKU "build.h" XASH_HAIKU) check_group_build_target(XASH_ARM XASH_ARCHITECTURE)
check_symbol_exists(XASH_IOS "build.h" XASH_IOS) check_group_build_target(XASH_MIPS XASH_ARCHITECTURE)
check_symbol_exists(XASH_JS "build.h" XASH_JS) check_group_build_target(XASH_JS XASH_ARCHITECTURE)
check_symbol_exists(XASH_LINUX "build.h" XASH_LINUX) check_group_build_target(XASH_E2K XASH_ARCHITECTURE)
check_symbol_exists(XASH_LITTLE_ENDIAN "build.h" XASH_LITTLE_ENDIAN) check_group_build_target(XASH_RISCV XASH_ARCHITECTURE)
check_symbol_exists(XASH_MINGW "build.h" XASH_MINGW) check_group_build_target(XASH_LITTLE_ENDIAN XASH_ENDIANNESS)
check_symbol_exists(XASH_MIPS "build.h" XASH_MIPS) check_group_build_target(XASH_BIG_ENDIAN XASH_ENDIANNESS)
check_symbol_exists(XASH_PPC "build.h" XASH_PPC) if(XASH_ARM)
check_symbol_exists(XASH_MOBILE_PLATFORM "build.h" XASH_MOBILE_PLATFORM) check_build_target(XASH_ARM_HARDFP)
check_symbol_exists(XASH_MSVC "build.h" XASH_MSVC) check_build_target(XASH_ARM_SOFTFP)
check_symbol_exists(XASH_NETBSD "build.h" XASH_NETBSD) check_build_target(XASH_ARMv4)
check_symbol_exists(XASH_OPENBSD "build.h" XASH_OPENBSD) check_build_target(XASH_ARMv5)
check_symbol_exists(XASH_POSIX "build.h" XASH_POSIX) check_build_target(XASH_ARMv6)
check_symbol_exists(XASH_RISCV "build.h" XASH_RISCV) check_build_target(XASH_ARMv7)
check_symbol_exists(XASH_RISCV_DOUBLEFP "build.h" XASH_RISCV_DOUBLEFP) check_build_target(XASH_ARMv8)
check_symbol_exists(XASH_RISCV_SINGLEFP "build.h" XASH_RISCV_SINGLEFP) endif()
check_symbol_exists(XASH_RISCV_SOFTFP "build.h" XASH_RISCV_SOFTFP) if(XASH_RISCV)
check_symbol_exists(XASH_SERENITY "build.h" XASH_SERENITY) check_build_target(XASH_RISCV_DOUBLEFP)
check_symbol_exists(XASH_WIN32 "build.h" XASH_WIN32) check_build_target(XASH_RISCV_SINGLEFP)
check_symbol_exists(XASH_WIN64 "build.h" XASH_WIN64) check_build_target(XASH_RISCV_SOFTFP)
check_symbol_exists(XASH_X86 "build.h" XASH_X86) endif()
check_symbol_exists(XASH_NSWITCH "build.h" XASH_NSWITCH)
check_symbol_exists(XASH_PSVITA "build.h" XASH_PSVITA)
unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_INCLUDES)
# engine/common/build.c # engine/common/build.c
if(XASH_ANDROID) if(XASH_ANDROID)
set(BUILDOS "android") set(BUILDOS "android")
elseif(XASH_LINUX_UNKNOWN)
set(BUILDOS "linuxunkabi")
elseif(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE) elseif(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE)
set(BUILDOS "") # no prefix for default OS set(BUILDOS "") # no prefix for default OS
elseif(XASH_FREEBSD) elseif(XASH_FREEBSD)
@ -69,6 +103,8 @@ elseif(XASH_NSWITCH)
set(BUILDOS "nswitch") set(BUILDOS "nswitch")
elseif(XASH_PSVITA) elseif(XASH_PSVITA)
set(BUILDOS "psvita") set(BUILDOS "psvita")
elseif(XASH_IRIX)
set(BUILDOS "irix")
else() else()
message(SEND_ERROR "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug") message(SEND_ERROR "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug")
endif() endif()
@ -113,15 +149,6 @@ elseif(XASH_MIPS)
if(XASH_LITTLE_ENDIAN) if(XASH_LITTLE_ENDIAN)
set(BUILDARCH "${BUILDARCH}el") set(BUILDARCH "${BUILDARCH}el")
endif() endif()
elseif(XASH_PPC)
set(BUILDARCH "powerpc")
if(XASH_64BIT)
set(BUILDARCH "${BUILDARCH}64")
endif()
if(XASH_LITTLE_ENDIAN)
set(BUILDARCH "${BUILDARCH}le")
endif()
elseif(XASH_RISCV) elseif(XASH_RISCV)
set(BUILDARCH "riscv") set(BUILDARCH "riscv")
if(XASH_64BIT) if(XASH_64BIT)

132
dlls/wscript

@ -6,7 +6,6 @@ from waflib import Utils
import os import os
def options(opt): def options(opt):
# stub
return return
def configure(conf): def configure(conf):
@ -16,116 +15,21 @@ def configure(conf):
hlDefNode = conf.path.find_resource("./hl.def") hlDefNode = conf.path.find_resource("./hl.def")
if hlDefNode is not None: if hlDefNode is not None:
conf.env.append_unique('LINKFLAGS', '/def:%s' % hlDefNode.abspath()) conf.env.append_value('LINKFLAGS', '/def:%s' % hlDefNode.abspath())
else: else:
conf.fatal("Could not find hl.def") conf.fatal("Could not find hl.def")
def build(bld): def build(bld):
source = bld.path.parent.ant_glob([ excluded_files = ['mpstubb.cpp', 'stats.cpp', 'prop.cpp', 'Wxdebug.cpp']
'pm_shared/*.c',
])
source += [ source = bld.path.ant_glob('**/*.cpp', excl=excluded_files)
'agrunt.cpp', source += bld.path.parent.ant_glob('pm_shared/*.c')
'airtank.cpp',
'aflock.cpp', defines = []
'animating.cpp', if bld.env.USE_VOICEMGR:
'animation.cpp', source += bld.path.parent.ant_glob('game_shared/voice_gamemgr.cpp')
'apache.cpp', else:
'barnacle.cpp', defines += ['NO_VOICEGAMEMGR']
'barney.cpp',
'bigmomma.cpp',
'bloater.cpp',
'bmodels.cpp',
'bullsquid.cpp',
'buttons.cpp',
'cbase.cpp',
'client.cpp',
'combat.cpp',
'controller.cpp',
'crossbow.cpp',
'crowbar.cpp',
'defaultai.cpp',
'doors.cpp',
'effects.cpp',
'egon.cpp',
'explode.cpp',
'flyingmonster.cpp',
'func_break.cpp',
'func_tank.cpp',
'game.cpp',
'gamerules.cpp',
'gargantua.cpp',
'gauss.cpp',
'genericmonster.cpp',
'ggrenade.cpp',
'globals.cpp',
'glock.cpp',
'gman.cpp',
'h_ai.cpp',
'h_battery.cpp',
'h_cine.cpp',
'h_cycler.cpp',
'h_export.cpp',
'handgrenade.cpp',
'hassassin.cpp',
'headcrab.cpp',
'healthkit.cpp',
'hgrunt.cpp',
'hornet.cpp',
'hornetgun.cpp',
'houndeye.cpp',
'ichthyosaur.cpp',
'islave.cpp',
'items.cpp',
'leech.cpp',
'lights.cpp',
'maprules.cpp',
'monstermaker.cpp',
'monsters.cpp',
'monsterstate.cpp',
'mortar.cpp',
'mp5.cpp',
'multiplay_gamerules.cpp',
'nihilanth.cpp',
'nodes.cpp',
'observer.cpp',
'osprey.cpp',
'pathcorner.cpp',
'plane.cpp',
'plats.cpp',
'player.cpp',
'playermonster.cpp',
'python.cpp',
'rat.cpp',
'roach.cpp',
'rpg.cpp',
'satchel.cpp',
'schedule.cpp',
'scientist.cpp',
'scripted.cpp',
'shotgun.cpp',
'singleplay_gamerules.cpp',
'skill.cpp',
'sound.cpp',
'soundent.cpp',
'spectator.cpp',
'squadmonster.cpp',
'squeakgrenade.cpp',
'subs.cpp',
'talkmonster.cpp',
'teamplay_gamerules.cpp',
'tempmonster.cpp',
'tentacle.cpp',
'triggers.cpp',
'tripmine.cpp',
'turret.cpp',
'util.cpp',
'weapons.cpp',
'world.cpp',
'xen.cpp',
'zombie.cpp'
]
includes = [ includes = [
'.', '.',
@ -136,30 +40,18 @@ def build(bld):
'../public' '../public'
] ]
defines = []
if bld.env.VOICEMGR:
source += bld.path.parent.ant_glob([
'game_shared/voice_gamemgr.cpp',
])
else:
defines += ['NO_VOICEGAMEMGR']
libs = []
if bld.env.DEST_OS not in ['android', 'dos']: if bld.env.DEST_OS not in ['android', 'dos']:
install_path = os.path.join(bld.env.GAMEDIR, bld.env.SERVER_DIR) install_path = os.path.join(bld.env.GAMEDIR, bld.env.SERVER_INSTALL_DIR)
else: else:
install_path = bld.env.PREFIX install_path = bld.env.PREFIX
bld.shlib( bld.shlib(
source = source, source = source,
target = bld.env.SERVER_NAME + bld.env.POSTFIX, target = bld.env.SERVER_LIBRARY_NAME + bld.env.POSTFIX,
name = 'server', name = 'server',
features = 'c cxx', features = 'c cxx',
includes = includes, includes = includes,
defines = defines, defines = defines,
use = libs,
install_path = install_path, install_path = install_path,
subsystem = bld.env.MSVC_SUBSYSTEM, subsystem = bld.env.MSVC_SUBSYSTEM,
idx = bld.get_taskgen_count() idx = bld.get_taskgen_count()

16
mod_options.txt

@ -0,0 +1,16 @@
BARNACLE_FIX_VISIBILITY=OFF # Barnacle tongue length fix
CLIENT_WEAPONS=ON # Client local weapons prediction
CROWBAR_IDLE_ANIM=OFF # Crowbar idle animation
CROWBAR_DELAY_FIX=OFF # Crowbar attack delay fix
CROWBAR_FIX_RAPID_CROWBAR=OFF # Rapid crowbar fix
GAUSS_OVERCHARGE_FIX=OFF # Gauss overcharge fix
TRIPMINE_BEAM_DUPLICATION_FIX=OFF # Fix of tripmine beam duplication on level transition
HANDGRENADE_DEPLOY_FIX=OFF # Handgrenade deploy animation fix after finishing a throw
WEAPONS_ANIMATION_TIMES_FIX=OFF # Animation times fix for some weapons
OEM_BUILD=OFF # OEM Build
HLDEMO_BUILD=OFF # Demo Build
GAMEDIR=valve # Gamedir path
SERVER_INSTALL_DIR=dlls # Where put server dll
CLIENT_INSTALL_DIR=cl_dlls # Where put client dll
SERVER_LIBRARY_NAME=hl # Library name for PC platforms

175
public/build.h

@ -30,15 +30,22 @@ For more information, please refer to <http://unlicense.org/>
#ifndef BUILD_H #ifndef BUILD_H
#define BUILD_H #define BUILD_H
// All XASH_* macros set by this header are guaranteed to have positive value otherwise not defined /*
All XASH_* macros set by this header are guaranteed to have positive value
otherwise not defined.
// Any new define must be undefined at first Every macro is intended to be the unified interface for buildsystems that lack
// You can generate #undef list below with this oneliner: platform & CPU detection, and a neat quick way for checks in platform code
// $ cat build.h | sed 's/\t//g' | grep '^#define XASH' | awk '{ print $2 }' | sort | uniq | awk '{ print "#undef " $1 }' For Q_build* macros, refer to buildenums.h
//
// So in various buildscripts you can grep for ^#undef XASH and select only second word Any new define must be undefined at first
// or in another oneliner: You can generate #undef list below with this oneliner:
// $ cat build.h | grep '^#undef XASH' | awk '{ print $2 }' $ sed 's/\t//g' build.h | grep '^#define XASH' | awk '{ print $2 }' | \
sort | uniq | awk '{ print "#undef " $1 }'
Then you can use another oneliner to query all variables:
$ grep '^#undef XASH' build.h | awk '{ print $2 }'
*/
#undef XASH_64BIT #undef XASH_64BIT
#undef XASH_AMD64 #undef XASH_AMD64
@ -53,21 +60,19 @@ For more information, please refer to <http://unlicense.org/>
#undef XASH_ARMv7 #undef XASH_ARMv7
#undef XASH_ARMv8 #undef XASH_ARMv8
#undef XASH_BIG_ENDIAN #undef XASH_BIG_ENDIAN
#undef XASH_BSD
#undef XASH_DOS4GW #undef XASH_DOS4GW
#undef XASH_E2K #undef XASH_E2K
#undef XASH_EMSCRIPTEN #undef XASH_EMSCRIPTEN
#undef XASH_FREEBSD #undef XASH_FREEBSD
#undef XASH_HAIKU #undef XASH_HAIKU
#undef XASH_IOS #undef XASH_IOS
#undef XASH_IRIX
#undef XASH_JS #undef XASH_JS
#undef XASH_LINUX #undef XASH_LINUX
#undef XASH_LINUX_UNKNOWN
#undef XASH_LITTLE_ENDIAN #undef XASH_LITTLE_ENDIAN
#undef XASH_MINGW
#undef XASH_MIPS #undef XASH_MIPS
#undef XASH_PPC
#undef XASH_MOBILE_PLATFORM #undef XASH_MOBILE_PLATFORM
#undef XASH_MSVC
#undef XASH_NETBSD #undef XASH_NETBSD
#undef XASH_OPENBSD #undef XASH_OPENBSD
#undef XASH_POSIX #undef XASH_POSIX
@ -77,74 +82,63 @@ For more information, please refer to <http://unlicense.org/>
#undef XASH_RISCV_SOFTFP #undef XASH_RISCV_SOFTFP
#undef XASH_SERENITY #undef XASH_SERENITY
#undef XASH_WIN32 #undef XASH_WIN32
#undef XASH_WIN64
#undef XASH_X86 #undef XASH_X86
#undef XASH_NSWITCH #undef XASH_NSWITCH
#undef XASH_PSVITA #undef XASH_PSVITA
//================================================================ //================================================================
// //
// OPERATING SYSTEM DEFINES // PLATFORM DETECTION CODE
// //
//================================================================ //================================================================
#if defined(_WIN32) #if defined _WIN32
#define XASH_WIN32 1 #define XASH_WIN32 1
#if defined(__MINGW32__) #elif defined __EMSCRIPTEN__
#define XASH_MINGW 1 #define XASH_EMSCRIPTEN 1
#elif defined(_MSC_VER) #elif defined __WATCOMC__ && defined __DOS__
#define XASH_MSVC 1 #define XASH_DOS4GW 1
#else // POSIX compatible
#define XASH_POSIX 1
#if defined __linux__
#if defined __ANDROID__
#define XASH_ANDROID 1
#else
#include <features.h>
// if our system libc has features.h header
// try to detect it to not confuse other libcs with built with glibc game libraries
#if !defined __GLIBC__
#define XASH_LINUX_UNKNOWN 1
#endif #endif
#if defined(_WIN64)
#define XASH_WIN64 1
#endif #endif
#elif defined __SWITCH__
#define XASH_NSWITCH 1
#define XASH_LITTLE_ENDIAN 1
#define XASH_POSIX 1
#elif defined __vita__
#define XASH_PSVITA 1
#define XASH_LITTLE_ENDIAN 1
#define XASH_POSIX 1
#elif defined(__linux__)
#define XASH_LINUX 1 #define XASH_LINUX 1
#if defined(__ANDROID__) #elif defined __FreeBSD__
#define XASH_ANDROID 1 #define XASH_FREEBSD 1
#endif // defined(__ANDROID__) #elif defined __NetBSD__
#define XASH_POSIX 1 #define XASH_NETBSD 1
#elif defined(__APPLE__) #elif defined __OpenBSD__
#define XASH_OPENBSD 1
#elif defined __HAIKU__
#define XASH_HAIKU 1
#elif defined __serenity__
#define XASH_SERENITY 1
#elif defined __sgi
#define XASH_IRIX 1
#elif defined __APPLE__
#include <TargetConditionals.h> #include <TargetConditionals.h>
#define XASH_APPLE 1 #define XASH_APPLE 1
#if TARGET_OS_IOS #if TARGET_OS_IOS
#define XASH_IOS 1 #define XASH_IOS 1
#endif // TARGET_OS_IOS #endif // TARGET_OS_IOS
#define XASH_POSIX 1 #elif defined __SWITCH__
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #define XASH_NSWITCH 1
#define XASH_BSD 1 #elif defined __vita__
#if defined(__FreeBSD__) #define XASH_PSVITA 1
#define XASH_FREEBSD 1 #else
#elif defined(__NetBSD__) #error
#define XASH_NETBSD 1
#elif defined(__OpenBSD__)
#define XASH_OPENBSD 1
#endif #endif
#define XASH_POSIX 1
#elif defined __EMSCRIPTEN__
#define XASH_EMSCRIPTEN 1
#elif defined __WATCOMC__ && defined __DOS__
#define XASH_DOS4GW 1
#define XASH_LITTLE_ENDIAN 1
#elif defined __HAIKU__
#define XASH_HAIKU 1
#define XASH_POSIX 1
#elif defined __serenity__
#define XASH_SERENITY 1
#define XASH_POSIX 1
#else
#error "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug"
#endif #endif
#if defined XASH_ANDROID || defined XASH_IOS || defined XASH_NSWITCH || defined XASH_PSVITA #if XASH_ANDROID || defined XASH_IOS || defined XASH_NSWITCH || defined XASH_PSVITA
#define XASH_MOBILE_PLATFORM 1 #define XASH_MOBILE_PLATFORM 1
#endif #endif
@ -154,27 +148,17 @@ For more information, please refer to <http://unlicense.org/>
// //
//================================================================ //================================================================
#if defined(XASH_FORCE_LITTLE_ENDIAN) && defined(XASH_FORCE_BIG_ENDIAN) #if !defined XASH_ENDIANNESS
#error "Both XASH_FORCE_LITTLE_ENDIAN and XASH_FORCE_BIG_ENDIAN are defined" #if defined XASH_WIN32 || __LITTLE_ENDIAN__
#elif defined(XASH_FORCE_LITTLE_ENDIAN)
#define XASH_LITTLE_ENDIAN 1
#elif defined(XASH_FORCE_BIG_ENDIAN)
#define XASH_BIG_ENDIAN 1
#endif
#if !defined(XASH_LITTLE_ENDIAN) && !defined(XASH_BIG_ENDIAN)
#if defined XASH_MSVC || __LITTLE_ENDIAN__
//!!! Probably all WinNT installations runs in little endian //!!! Probably all WinNT installations runs in little endian
#define XASH_LITTLE_ENDIAN 1 #define XASH_LITTLE_ENDIAN 1
#elif __BIG_ENDIAN__ #elif __BIG_ENDIAN__
#define XASH_BIG_ENDIAN 1 #define XASH_BIG_ENDIAN 1
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && defined(__ORDER_LITTLE_ENDIAN__) // some compilers define this #elif defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ && defined __ORDER_LITTLE_ENDIAN__ // some compilers define this
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define XASH_BIG_ENDIAN 1 #define XASH_BIG_ENDIAN 1
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define XASH_LITTLE_ENDIAN 1 #define XASH_LITTLE_ENDIAN 1
#else
#error "Unknown endianness!"
#endif #endif
#else #else
#include <sys/param.h> #include <sys/param.h>
@ -182,8 +166,6 @@ For more information, please refer to <http://unlicense.org/>
#define XASH_BIG_ENDIAN 1 #define XASH_BIG_ENDIAN 1
#elif __BYTE_ORDER == __LITTLE_ENDIAN #elif __BYTE_ORDER == __LITTLE_ENDIAN
#define XASH_LITTLE_ENDIAN 1 #define XASH_LITTLE_ENDIAN 1
#else
#error "Unknown endianness!"
#endif #endif
#endif // !XASH_WIN32 #endif // !XASH_WIN32
#endif #endif
@ -193,18 +175,28 @@ For more information, please refer to <http://unlicense.org/>
// CPU ARCHITECTURE DEFINES // CPU ARCHITECTURE DEFINES
// //
//================================================================ //================================================================
#if defined(__x86_64__) || defined(_M_X64) #if defined __x86_64__ || defined _M_X64
#define XASH_64BIT 1 #define XASH_64BIT 1
#define XASH_AMD64 1 #define XASH_AMD64 1
#elif defined(__i386__) || defined(_X86_) || defined(_M_IX86) #elif defined __i386__ || defined _X86_ || defined _M_IX86
#define XASH_X86 1 #define XASH_X86 1
#elif defined __aarch64__ || defined _M_ARM64 #elif defined __aarch64__ || defined _M_ARM64
#define XASH_64BIT 1 #define XASH_64BIT 1
#define XASH_ARM 8 #define XASH_ARM 8
#elif defined __arm__ || defined _M_ARM #elif defined __mips__
#define XASH_MIPS 1
#elif defined __EMSCRIPTEN__
#define XASH_JS 1
#elif defined __e2k__
#define XASH_64BIT 1
#define XASH_E2K 1
#elif defined _M_ARM // msvc
#define XASH_ARM 7
#define XASH_ARM_HARDFP 1
#elif defined __arm__
#if __ARM_ARCH == 8 || __ARM_ARCH_8__ #if __ARM_ARCH == 8 || __ARM_ARCH_8__
#define XASH_ARM 8 #define XASH_ARM 8
#elif __ARM_ARCH == 7 || __ARM_ARCH_7__ || defined _M_ARM // msvc can only armv7 in 32 bit #elif __ARM_ARCH == 7 || __ARM_ARCH_7__
#define XASH_ARM 7 #define XASH_ARM 7
#elif __ARM_ARCH == 6 || __ARM_ARCH_6__ || __ARM_ARCH_6J__ #elif __ARM_ARCH == 6 || __ARM_ARCH_6__ || __ARM_ARCH_6J__
#define XASH_ARM 6 #define XASH_ARM 6
@ -216,34 +208,17 @@ For more information, please refer to <http://unlicense.org/>
#error "Unknown ARM" #error "Unknown ARM"
#endif #endif
#if defined _M_ARM
#error "No WinMobile port yet! Need to determine which ARM float ABI msvc uses if applicable"
#endif
#if defined __SOFTFP__ || __ARM_PCS_VFP == 0 #if defined __SOFTFP__ || __ARM_PCS_VFP == 0
#define XASH_ARM_SOFTFP 1 #define XASH_ARM_SOFTFP 1
#else // __SOFTFP__ #else // __SOFTFP__
#define XASH_ARM_HARDFP 1 #define XASH_ARM_HARDFP 1
#endif // __SOFTFP__ #endif // __SOFTFP__
#elif defined __mips__
#define XASH_MIPS 1
#elif defined __powerpc__
#define XASH_PPC 1
#if defined __powerpc64__
#define XASH_64BIT 1
#endif
#elif defined __EMSCRIPTEN__
#define XASH_JS 1
#elif defined __e2k__
#define XASH_64BIT 1
#define XASH_E2K 1
#elif defined __riscv #elif defined __riscv
#define XASH_RISCV 1 #define XASH_RISCV 1
#if __riscv_xlen == 64 #if __riscv_xlen == 64
#define XASH_64BIT 1 #define XASH_64BIT 1
#elif __riscv_xlen == 32 #elif __riscv_xlen != 32
// ...
#else
#error "Unknown RISC-V ABI" #error "Unknown RISC-V ABI"
#endif #endif
@ -260,10 +235,6 @@ For more information, please refer to <http://unlicense.org/>
#error "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug" #error "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug"
#endif #endif
#if defined(XASH_WAF_DETECTED_64BIT) && !defined(XASH_64BIT)
#define XASH_64BIT 1
#endif
#if XASH_ARM == 8 #if XASH_ARM == 8
#define XASH_ARMv8 1 #define XASH_ARMv8 1
#elif XASH_ARM == 7 #elif XASH_ARM == 7

11
scripts/waifulib/compiler_optimizations.py

@ -118,7 +118,7 @@ POLLY_CFLAGS = {
def options(opt): def options(opt):
grp = opt.add_option_group('Compiler optimization options') grp = opt.add_option_group('Compiler optimization options')
grp.add_option('-T', '--build-type', action='store', dest='BUILD_TYPE', default=None, grp.add_option('-T', '--build-type', action='store', dest='BUILD_TYPE', default='release',
help = 'build type: debug, release or none(custom flags)') help = 'build type: debug, release or none(custom flags)')
grp.add_option('--enable-lto', action = 'store_true', dest = 'LTO', default = False, grp.add_option('--enable-lto', action = 'store_true', dest = 'LTO', default = False,
@ -129,12 +129,11 @@ def options(opt):
def configure(conf): def configure(conf):
conf.start_msg('Build type') conf.start_msg('Build type')
if conf.options.BUILD_TYPE == None:
conf.end_msg('not set', color='RED') if not conf.options.BUILD_TYPE in VALID_BUILD_TYPES:
conf.fatal('Set a build type, for example "-T release"')
elif not conf.options.BUILD_TYPE in VALID_BUILD_TYPES:
conf.end_msg(conf.options.BUILD_TYPE, color='RED') conf.end_msg(conf.options.BUILD_TYPE, color='RED')
conf.fatal('Invalid build type. Valid are: %s' % ', '.join(VALID_BUILD_TYPES)) conf.fatal('Invalid build type. Valid are: %s' % ', '.join(VALID_BUILD_TYPES))
conf.end_msg(conf.options.BUILD_TYPE) conf.end_msg(conf.options.BUILD_TYPE)
conf.msg('LTO build', 'yes' if conf.options.LTO else 'no') conf.msg('LTO build', 'yes' if conf.options.LTO else 'no')
@ -175,5 +174,7 @@ def get_optimization_flags(conf):
elif conf.env.DEST_OS == 'psvita': elif conf.env.DEST_OS == 'psvita':
# this optimization is broken in vitasdk # this optimization is broken in vitasdk
cflags.append('-fno-optimize-sibling-calls') cflags.append('-fno-optimize-sibling-calls')
# remove fvisibility to allow everything to be exported by default
cflags.remove('-fvisibility=hidden')
return cflags, linkflags return cflags, linkflags

17
scripts/waifulib/library_naming.py

@ -35,21 +35,19 @@ DEFINES = [
'XASH_ARMv7', 'XASH_ARMv7',
'XASH_ARMv8', 'XASH_ARMv8',
'XASH_BIG_ENDIAN', 'XASH_BIG_ENDIAN',
'XASH_BSD',
'XASH_DOS4GW', 'XASH_DOS4GW',
'XASH_E2K', 'XASH_E2K',
'XASH_EMSCRIPTEN', 'XASH_EMSCRIPTEN',
'XASH_FREEBSD', 'XASH_FREEBSD',
'XASH_HAIKU', 'XASH_HAIKU',
'XASH_IOS', 'XASH_IOS',
'XASH_IRIX',
'XASH_JS', 'XASH_JS',
'XASH_LINUX', 'XASH_LINUX',
'XASH_LINUX_UNKNOWN',
'XASH_LITTLE_ENDIAN', 'XASH_LITTLE_ENDIAN',
'XASH_MINGW',
'XASH_MIPS', 'XASH_MIPS',
'XASH_PPC',
'XASH_MOBILE_PLATFORM', 'XASH_MOBILE_PLATFORM',
'XASH_MSVC',
'XASH_NETBSD', 'XASH_NETBSD',
'XASH_OPENBSD', 'XASH_OPENBSD',
'XASH_POSIX', 'XASH_POSIX',
@ -59,7 +57,6 @@ DEFINES = [
'XASH_RISCV_SOFTFP', 'XASH_RISCV_SOFTFP',
'XASH_SERENITY', 'XASH_SERENITY',
'XASH_WIN32', 'XASH_WIN32',
'XASH_WIN64',
'XASH_X86', 'XASH_X86',
'XASH_NSWITCH', 'XASH_NSWITCH',
'XASH_PSVITA', 'XASH_PSVITA',
@ -78,6 +75,8 @@ def configure(conf):
# engine/common/build.c # engine/common/build.c
if conf.env.XASH_ANDROID: if conf.env.XASH_ANDROID:
buildos = "android" buildos = "android"
elif conf.env.XASH_LINUX_UNKNOWN:
buildos = "linuxunkabi"
elif conf.env.XASH_WIN32 or conf.env.XASH_LINUX or conf.env.XASH_APPLE: elif conf.env.XASH_WIN32 or conf.env.XASH_LINUX or conf.env.XASH_APPLE:
buildos = "" # no prefix for default OS buildos = "" # no prefix for default OS
elif conf.env.XASH_FREEBSD: elif conf.env.XASH_FREEBSD:
@ -98,6 +97,8 @@ def configure(conf):
buildos = "nswitch" buildos = "nswitch"
elif conf.env.XASH_PSVITA: elif conf.env.XASH_PSVITA:
buildos = "psvita" buildos = "psvita"
elif conf.env.XASH_IRIX:
buildos = "irix"
else: else:
conf.fatal("Place your operating system name in build.h and library_naming.py!\n" conf.fatal("Place your operating system name in build.h and library_naming.py!\n"
"If this is a mistake, try to fix conditions above and report a bug") "If this is a mistake, try to fix conditions above and report a bug")
@ -136,12 +137,6 @@ def configure(conf):
buildarch += "64" buildarch += "64"
if conf.env.XASH_LITTLE_ENDIAN: if conf.env.XASH_LITTLE_ENDIAN:
buildarch += "el" buildarch += "el"
elif conf.env.XASH_PPC:
buildarch = "powerpc"
if conf.env.XASH_64BIT:
buildarch += "64"
if conf.env.XASH_LITTLE_ENDIAN:
buildarch += "le"
elif conf.env.XASH_RISCV: elif conf.env.XASH_RISCV:
buildarch = "riscv" buildarch = "riscv"
if conf.env.XASH_64BIT: if conf.env.XASH_64BIT:

79
scripts/waifulib/vgui.py

@ -0,0 +1,79 @@
#! /usr/bin/env python
# encoding: utf-8
# mittorn, 2018
from waflib.Configure import conf
import os
VGUI_SUPPORTED_OS = ['win32', 'darwin', 'linux']
VGUI_FRAGMENT = '''#include <VGUI.h>
int main() { return 0; }'''
def options(opt):
grp = opt.add_option_group('VGUI options')
vgui_dev_path = os.path.join(opt.path.path_from(opt.path), 'vgui_support', 'vgui-dev')
grp.add_option('--vgui', action = 'store', dest = 'VGUI_DEV', default=vgui_dev_path,
help = 'path to vgui-dev repo [default: %default]')
grp.add_option('--skip-vgui-sanity-check', action = 'store_false', dest = 'VGUI_SANITY_CHECK', default=True,
help = 'skip checking VGUI sanity [default: %default]' )
return
@conf
def check_vgui(conf):
conf.start_msg('Does this architecture support VGUI?')
if conf.env.DEST_CPU != 'x86' and not (conf.env.DEST_CPU == 'x86_64' and not conf.options.ALLOW64):
conf.end_msg('no')
Logs.warn('vgui is not supported on this CPU: ' + str(conf.env.DEST_CPU))
return False
else: conf.end_msg('yes')
conf.start_msg('Does this OS support VGUI?')
if conf.env.DEST_OS not in VGUI_SUPPORTED_OS:
conf.end_msg('no')
Logs.warn('vgui is not supported on this OS: ' + str(conf.env.DEST_OS))
return False
else: conf.end_msg('yes')
conf.start_msg('Does this toolchain able to link VGUI?')
if conf.env.DEST_OS == 'win32' and conf.env.COMPILER_CXX == 'g++':
conf.end_msg('no')
# we have ABI incompatibility ONLY on MinGW
Logs.warn('vgui can\'t be linked with MinGW')
return False
else: conf.end_msg('yes')
conf.start_msg('Configuring VGUI by provided path')
vgui_dev = conf.options.VGUI_DEV
if conf.env.DEST_OS == 'win32':
conf.env.LIB_VGUI = ['vgui']
conf.env.LIBPATH_VGUI = [os.path.abspath(os.path.join(vgui_dev, 'lib/win32_vc6/'))]
else:
libpath = os.path.abspath(os.path.join(vgui_dev, 'lib'))
if conf.env.DEST_OS == 'linux':
conf.env.LIB_VGUI = [':vgui.so']
conf.env.LIBPATH_VGUI = [libpath]
elif conf.env.DEST_OS == 'darwin':
conf.env.LDFLAGS_VGUI = [os.path.join(libpath, 'vgui.dylib')]
else:
conf.fatal('vgui is not supported on this OS: ' + conf.env.DEST_OS)
conf.env.INCLUDES_VGUI = [os.path.abspath(os.path.join(vgui_dev, 'include'))]
conf.env.HAVE_VGUI = 1
conf.end_msg('yes: {0}, {1}, {2}'.format(conf.env.LIB_VGUI, conf.env.LIBPATH_VGUI, conf.env.INCLUDES_VGUI))
if conf.env.HAVE_VGUI and conf.options.VGUI_SANITY_CHECK:
try:
conf.check_cxx(fragment=VGUI_FRAGMENT,
msg = 'Checking for library VGUI sanity',
use = 'VGUI',
execute = False)
except conf.errors.ConfigurationError:
conf.fatal("Can't compile simple program. Check your path to vgui-dev repository.")
return True

14
waf vendored

File diff suppressed because one or more lines are too long

12
waf.bat

@ -1,24 +1,20 @@
@echo off @echo off
rem try fix py2 build rem try fix py2 build
chcp 1252 chcp 65001
set PYTHONIOENCODING=UTF-8 set PYTHONIOENCODING=UTF-8
rem from issue #964 rem from issue #964
Setlocal EnableDelayedExpansion Setlocal EnableDelayedExpansion
rem Check Windows Version rem Check Windows Version
set TOKEN=tokens=3* set TOKEN=tokens=2*
ver | findstr /i "5\.0\." > nul ver | findstr /i "5\.0\." > nul
if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3* if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3*
ver | findstr /i "5\.1\." > nul ver | findstr /i "5\.1\." > nul
if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3* if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3*
ver | findstr /i "5\.2\." > nul ver | findstr /i "5\.2\." > nul
if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3* if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3*
ver | findstr /i "6\.0\." > nul
if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=2*
ver | findstr /i "6\.1\." > nul
if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=2*
rem Start calculating PYTHON and PYTHON_DIR rem Start calculating PYTHON and PYTHON_DIR
set PYTHON= set PYTHON=
@ -29,7 +25,7 @@ Setlocal EnableDelayedExpansion
set PYTHON_DIR_OK=FALSE set PYTHON_DIR_OK=FALSE
set REGPATH= set REGPATH=
for %%i in (3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0 2.7 2.6 2.5) do ( for %%i in (3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0 2.7 2.6 2.5) do (
for %%j in (HKCU HKLM) do ( for %%j in (HKCU HKLM) do (
for %%k in (SOFTWARE\Wow6432Node SOFTWARE) do ( for %%k in (SOFTWARE\Wow6432Node SOFTWARE) do (
for %%l in (Python\PythonCore IronPython) do ( for %%l in (Python\PythonCore IronPython) do (
@ -88,7 +84,7 @@ rem @echo %PYTHON_DIR%
if "%PYTHON%" == "" ( if "%PYTHON%" == "" (
rem @echo No Python rem @echo No Python
set PYTHON=python set PYTHON=py
goto running goto running
) )

286
wscript

@ -2,16 +2,16 @@
# encoding: utf-8 # encoding: utf-8
# a1batross, mittorn, 2018 # a1batross, mittorn, 2018
from __future__ import print_function from waflib import Build, Configure, Context, Logs
from waflib import Logs, Context, Configure
import sys import sys
import os import os
import re
VERSION = '2.4' VERSION = '2.4'
APPNAME = 'hlsdk-xash3d' APPNAME = 'hlsdk-portable'
top = '.' top = '.'
Context.Context.line_just = 55 # should fit for everything on 80x26 Context.Context.line_just = 60 # should fit for everything on 80x26
@Configure.conf @Configure.conf
def get_taskgen_count(self): def get_taskgen_count(self):
@ -20,46 +20,29 @@ def get_taskgen_count(self):
return idx return idx
def options(opt): def options(opt):
opt.load('reconfigure compiler_optimizations xcompile compiler_cxx compiler_c clang_compilation_database strip_on_install msdev msvs msvc subproject')
grp = opt.add_option_group('Common options') grp = opt.add_option_group('Common options')
grp.add_option('-8', '--64bits', action = 'store_true', dest = 'ALLOW64', default = False, grp.add_option('-8', '--64bits', action = 'store_true', dest = 'ALLOW64', default = False,
help = 'allow targetting 64-bit engine(Linux/Windows/OSX x86 only) [default: %default]') help = 'allow targetting 64-bit engine(Linux/Windows/OSX x86 only) [default: %default]')
grp.add_option('--disable-werror', action = 'store_true', dest = 'DISABLE_WERROR', default = False,
help = 'disable compilation abort on warning')
grp.add_option('--enable-voicemgr', action = 'store_true', dest = 'USE_VOICEMGR', default = False,
help = 'Enable VOICE MANAGER')
grp.add_option('--enable-voicemgr', action = 'store_true', dest = 'VOICEMGR', default = False, opt.add_subproject('dlls')
help = 'enable voice manager [default: %default]') opt.add_subproject('cl_dll')
grp.add_option('--disable-goldsrc-support', action = 'store_false', dest = 'GOLDSRC', default = True,
help = 'disable GoldSource engine support [default: %default]')
opt.load('compiler_optimizations subproject')
opt.add_subproject(['cl_dll', 'dlls'])
opt.load('xcompile compiler_cxx compiler_c clang_compilation_database strip_on_install msdev msvs')
if sys.platform == 'win32':
opt.load('msvc')
opt.load('reconfigure')
def configure(conf): def configure(conf):
# Configuration conf.load('fwgslib reconfigure compiler_optimizations')
conf.env.GAMEDIR = 'valve' conf.env.MSVC_TARGETS = ['x86' if not conf.options.ALLOW64 else 'x64']
conf.env.CLIENT_DIR = 'cl_dlls'
conf.env.SERVER_DIR = 'dlls'
conf.env.SERVER_NAME = 'hl'
conf.env.PREFIX = ''
conf.load('fwgslib reconfigure compiler_optimizations enforce_pic')
enforce_pic = True # modern defaults
conf.env.VOICEMGR = conf.options.VOICEMGR
conf.env.GOLDSRC = conf.options.GOLDSRC
# Force XP compability, all build targets should add # Force XP compatibility, all build targets should add subsystem=bld.env.MSVC_SUBSYSTEM
# subsystem=bld.env.MSVC_SUBSYSTEM if conf.env.MSVC_TARGETS[0] == 'x86':
# TODO: wrapper around bld.stlib, bld.shlib and so on?
conf.env.MSVC_SUBSYSTEM = 'WINDOWS,5.01' conf.env.MSVC_SUBSYSTEM = 'WINDOWS,5.01'
conf.env.MSVC_TARGETS = ['x86' if not conf.options.ALLOW64 else 'x64'] else:
conf.env.MSVC_SUBSYSTEM = 'WINDOWS'
# Load compilers early # Load compilers early
conf.load('xcompile compiler_c compiler_cxx') conf.load('xcompile compiler_c compiler_cxx')
@ -71,108 +54,138 @@ def configure(conf):
if conf.env.COMPILER_CC == 'msvc': if conf.env.COMPILER_CC == 'msvc':
conf.load('msvc_pdb') conf.load('msvc_pdb')
conf.load('msvs msdev strip_on_install') conf.load('msvs msdev subproject clang_compilation_database strip_on_install enforce_pic')
if conf.env.DEST_OS == 'android':
conf.options.GOLDSRC = conf.env.GOLDSRC = False
conf.env.SERVER_NAME = 'server' # can't be any other name, until specified
elif conf.env.DEST_OS in ['nswitch', 'psvita']:
conf.options.GOLDSRC = conf.env.GOLDSRC = False
if conf.env.MAGX:
enforce_pic = False
enforce_pic = True # modern defaults
conf.check_pic(enforce_pic) conf.check_pic(enforce_pic)
# We restrict 64-bit builds ONLY for Win/Linux/OSX running on Intel architecture # We restrict 64-bit builds ONLY for Win/Linux/OSX running on Intel architecture
# Because compatibility with original GoldSrc # Because compatibility with original GoldSrc
if conf.env.DEST_OS in ['win32', 'linux', 'darwin'] and conf.env.DEST_CPU in ['x86_64']: if conf.env.DEST_OS in ['win32', 'linux', 'darwin'] and conf.env.DEST_CPU == 'x86_64':
conf.env.BIT32_ALLOW64 = conf.options.ALLOW64 conf.env.BIT32_MANDATORY = not conf.options.ALLOW64
if not conf.env.BIT32_ALLOW64: if conf.env.BIT32_MANDATORY:
Logs.info('WARNING: will build engine for 32-bit target') Logs.info('WARNING: will build game for 32-bit target')
else: else:
conf.env.BIT32_ALLOW64 = True conf.env.BIT32_MANDATORY = False
conf.env.BIT32_MANDATORY = not conf.env.BIT32_ALLOW64
conf.load('force_32bit library_naming')
compiler_optional_flags = [
'-fdiagnostics-color=always',
'-Werror=return-type',
'-Werror=parentheses',
'-Werror=vla',
'-Werror=tautological-compare',
'-Werror=duplicated-cond',
'-Werror=bool-compare',
'-Werror=bool-operation',
'-Wstrict-aliasing',
]
c_compiler_optional_flags = [ conf.load('force_32bit')
'-Werror=implicit-function-declaration',
'-Werror=int-conversion',
'-Werror=implicit-int',
'-Werror=declaration-after-statement'
]
cflags, linkflags = conf.get_optimization_flags() cflags, linkflags = conf.get_optimization_flags()
cxxflags = list(cflags) # optimization flags are common between C and C++ but we need a copy
# Here we don't differentiate C or C++ flags # on the Switch, allow undefined symbols by default, which is needed for libsolder to work
if conf.options.LTO: # we'll specifically disallow them for the engine executable
lto_cflags = { # additionally, shared libs are linked without standard libs, we'll add those back in the engine wscript
'msvc': ['/GL'],
'gcc': ['-flto'],
'clang': ['-flto']
}
lto_linkflags = {
'msvc': ['/LTCG'],
'gcc': ['-flto'],
'clang': ['-flto']
}
cflags += conf.get_flags_by_compiler(lto_cflags, conf.env.COMPILER_CC)
linkflags += conf.get_flags_by_compiler(lto_linkflags, conf.env.COMPILER_CC)
if conf.options.POLLY:
polly_cflags = {
'gcc': ['-fgraphite-identity'],
'clang': ['-mllvm', '-polly']
# msvc sosat :(
}
cflags += conf.get_flags_by_compiler(polly_cflags, conf.env.COMPILER_CC)
# And here C++ flags starts to be treated separately
cxxflags = list(cflags)
if conf.env.COMPILER_CC != 'msvc':
conf.check_cc(cflags=cflags, msg= 'Checking for required C flags')
conf.check_cxx(cxxflags=cflags, msg= 'Checking for required C++ flags')
cflags += conf.filter_cflags(compiler_optional_flags + c_compiler_optional_flags, cflags)
cxxflags += conf.filter_cxxflags(compiler_optional_flags, cflags)
# on the Switch and the PSVita, allow undefined symbols by default,
# which is needed for the dynamic loaders to work
# additionally, shared libs are linked without libc
if conf.env.DEST_OS == 'nswitch': if conf.env.DEST_OS == 'nswitch':
linkflags.remove('-Wl,--no-undefined') linkflags.remove('-Wl,--no-undefined')
conf.env.append_unique('LINKFLAGS_cshlib', ['-nostdlib', '-nostartfiles']) conf.env.append_unique('LINKFLAGS_cshlib', ['-nostdlib', '-nostartfiles'])
conf.env.append_unique('LINKFLAGS_cxxshlib', ['-nostdlib', '-nostartfiles']) conf.env.append_unique('LINKFLAGS_cxxshlib', ['-nostdlib', '-nostartfiles'])
# same on the vita
elif conf.env.DEST_OS == 'psvita': elif conf.env.DEST_OS == 'psvita':
linkflags.remove('-Wl,--no-undefined')
conf.env.append_unique('CFLAGS_cshlib', ['-fPIC']) conf.env.append_unique('CFLAGS_cshlib', ['-fPIC'])
conf.env.append_unique('CXXFLAGS_cxxshlib', ['-fPIC', '-fno-use-cxa-atexit']) conf.env.append_unique('CXXFLAGS_cxxshlib', ['-fPIC', '-fno-use-cxa-atexit'])
conf.env.append_unique('LINKFLAGS_cshlib', ['-nostdlib', '-Wl,--unresolved-symbols=ignore-all']) conf.env.append_unique('LINKFLAGS_cshlib', ['-nostdlib', '-Wl,--unresolved-symbols=ignore-all'])
conf.env.append_unique('LINKFLAGS_cxxshlib', ['-nostdlib', '-Wl,--unresolved-symbols=ignore-all']) conf.env.append_unique('LINKFLAGS_cxxshlib', ['-nostdlib', '-Wl,--unresolved-symbols=ignore-all'])
# check if we need to use irix linkflags
elif conf.env.DEST_OS == 'irix' and conf.env.COMPILER_CC == 'gcc':
linkflags.remove('-Wl,--no-undefined')
linkflags.append('-Wl,--unresolved-symbols=ignore-all')
# check if we're in a sgug environment
if 'sgug' in os.environ['LD_LIBRARYN32_PATH']:
linkflags.append('-lc')
conf.check_cc(cflags=cflags, linkflags=linkflags, msg='Checking for required C flags')
conf.check_cxx(cxxflags=cxxflags, linkflags=linkflags, msg='Checking for required C++ flags')
conf.env.append_unique('CFLAGS', cflags) conf.env.append_unique('CFLAGS', cflags)
conf.env.append_unique('CXXFLAGS', cxxflags) conf.env.append_unique('CXXFLAGS', cxxflags)
conf.env.append_unique('LINKFLAGS', linkflags) conf.env.append_unique('LINKFLAGS', linkflags)
if conf.env.COMPILER_CC != 'msvc' and not conf.options.DISABLE_WERROR:
opt_flags = [
# '-Wall', '-Wextra', '-Wpedantic',
'-fdiagnostics-color=always',
# stable diagnostics, forced to error, sorted
'-Werror=bool-compare',
'-Werror=bool-operation',
'-Werror=cast-align=strict',
'-Werror=duplicated-cond',
# '-Werror=format=2',
'-Werror=implicit-fallthrough=2',
# '-Werror=logical-op',
'-Werror=packed',
'-Werror=packed-not-aligned',
'-Werror=parentheses',
'-Werror=return-type',
'-Werror=sequence-point',
'-Werror=sizeof-pointer-memaccess',
'-Werror=sizeof-array-div',
'-Werror=sizeof-pointer-div',
# '-Werror=strict-aliasing',
'-Werror=string-compare',
'-Werror=tautological-compare',
'-Werror=use-after-free=3',
'-Werror=vla',
'-Werror=write-strings',
# unstable diagnostics, may cause false positives
'-Winit-self',
'-Wmisleading-indentation',
'-Wunintialized',
# disabled, flood
# '-Wdouble-promotion',
]
opt_cflags = [
'-Werror=declaration-after-statement',
'-Werror=enum-conversion',
'-Werror=implicit-int',
'-Werror=implicit-function-declaration',
'-Werror=incompatible-pointer-types',
'-Werror=int-conversion',
'-Werror=jump-misses-init',
# '-Werror=old-style-declaration',
# '-Werror=old-style-definition',
# '-Werror=strict-prototypes',
'-fnonconst-initializers' # owcc
]
opt_cxxflags = [] # TODO:
cflags = conf.filter_cflags(opt_flags + opt_cflags, cflags)
cxxflags = conf.filter_cxxflags(opt_flags + opt_cxxflags, cxxflags)
conf.env.append_unique('CFLAGS', cflags)
conf.env.append_unique('CXXFLAGS', cxxflags)
if conf.env.DEST_OS == 'android':
# LIB_M added in xcompile!
pass
elif conf.env.DEST_OS == 'win32':
a = [ 'user32', 'winmm' ]
if conf.env.COMPILER_CC == 'msvc':
for i in a:
conf.start_msg('Checking for MSVC library')
conf.check_lib_msvc(i)
conf.end_msg(i)
else:
for i in a:
conf.check_cc(lib = i)
else:
if conf.env.GOLDSOURCE_SUPPORT:
conf.check_cc(lib='dl')
conf.check_cc(lib='m')
# check if we can use C99 tgmath # check if we can use C99 tgmath
if conf.check_cc(header_name='tgmath.h', mandatory=False): if conf.check_cc(header_name='tgmath.h', mandatory=False):
if conf.env.COMPILER_CC == 'msvc':
conf.define('_CRT_SILENCE_NONCONFORMING_TGMATH_H', 1)
tgmath_usable = conf.check_cc(fragment='''#include<tgmath.h> tgmath_usable = conf.check_cc(fragment='''#include<tgmath.h>
int main(void){ return (int)sin(2.0f); }''', const float val = 2, val2 = 3;
msg='Checking if tgmath.h is usable', mandatory=False) int main(void){ return (int)(-asin(val) + cos(val2)); }''',
msg='Checking if tgmath.h is usable', mandatory=False, use='M')
conf.define_cond('HAVE_TGMATH_H', tgmath_usable) conf.define_cond('HAVE_TGMATH_H', tgmath_usable)
else: else:
conf.undefine('HAVE_TGMATH_H') conf.undefine('HAVE_TGMATH_H')
@ -187,29 +200,48 @@ def configure(conf):
elif conf.env.COMPILER_CC == 'owcc': elif conf.env.COMPILER_CC == 'owcc':
pass pass
else: else:
conf.env.append_unique('DEFINES', ['stricmp=strcasecmp', 'strnicmp=strncasecmp', '_snprintf=snprintf', '_vsnprintf=vsnprintf', '_LINUX', 'LINUX']) conf.env.append_unique('CXXFLAGS', ['-Wno-invalid-offsetof', '-fno-exceptions'])
conf.env.append_unique('CXXFLAGS', ['-Wno-invalid-offsetof', '-fno-rtti', '-fno-exceptions']) conf.define('stricmp', 'strcasecmp', quote=False)
conf.define('strnicmp', 'strncasecmp', quote=False)
conf.define('_snprintf', 'snprintf', quote=False)
conf.define('_vsnprintf', 'vsnprintf', quote=False)
conf.define('_LINUX', True)
conf.define('LINUX', True)
conf.msg(msg='-> processing mod options', result='...', color='BLUE')
regex = re.compile('^([A-Za-z0-9_]+)=([A-Za-z0-9_]+)\ \#\ (.*)$')
with open('mod_options.txt') as fd:
lines = fd.readlines()
for line in lines:
p = regex.match(line.strip())
if p:
conf.start_msg("* " + p[3])
if p[2] == 'ON':
conf.env[p[1]] = True
conf.define(p[1], 1)
elif p[2] == 'OFF':
conf.env[p[1]] = False
conf.undefine(p[1])
else:
conf.env[p[1]] = p[2]
conf.end_msg(p[2])
if conf.env.HLDEMO_BUILD and conf.env.OEM_BUILD:
conf.fatal('Don\'t mix Demo and OEM builds!')
# strip lib from pattern # strip lib from pattern
if conf.env.DEST_OS not in ['android']: if conf.env.DEST_OS not in ['android']:
if conf.env.cshlib_PATTERN.startswith('lib'):
conf.env.cshlib_PATTERN = conf.env.cshlib_PATTERN[3:]
if conf.env.cxxshlib_PATTERN.startswith('lib'): if conf.env.cxxshlib_PATTERN.startswith('lib'):
conf.env.cxxshlib_PATTERN = conf.env.cxxshlib_PATTERN[3:] conf.env.cxxshlib_PATTERN = conf.env.cxxshlib_PATTERN[3:]
conf.define('BARNACLE_FIX_VISIBILITY', False) conf.load('library_naming')
conf.define('CLIENT_WEAPONS', True) conf.add_subproject('dlls')
conf.define('CROWBAR_IDLE_ANIM', False) conf.add_subproject('cl_dll')
conf.define('CROWBAR_DELAY_FIX', False)
conf.define('CROWBAR_FIX_RAPID_CROWBAR', False)
conf.define('GAUSS_OVERCHARGE_FIX', False)
conf.define('OEM_BUILD', False)
conf.define('HLDEMO_BUILD', False)
conf.add_subproject(["cl_dll", "dlls"])
def build(bld): def build(bld):
bld.add_subproject(["cl_dll", "dlls"]) # don't clean QtCreator files and reconfigure saved options
bld.clean_files = bld.bldnode.ant_glob('**',
excl='*.user configuration.py .lock* *conf_check_*/** config.log %s/*' % Build.CACHE_DIR,
quiet=True, generator=True)
bld.add_subproject('dlls')
bld.add_subproject('cl_dll')

Loading…
Cancel
Save