waf: add Waf build system

This commit is contained in:
Alibek Omarov 2020-08-31 20:01:38 +03:00
parent e11ac08f0c
commit b5b7697b33
9 changed files with 1169 additions and 0 deletions

65
cl_dll/wscript Normal file
View File

@ -0,0 +1,65 @@
#! /usr/bin/env python
# encoding: utf-8
# a1batross, mittorn, 2018
from waflib import Utils
import os
def options(opt):
# stub
return
def configure(conf):
if conf.env.DEST_OS != 'win32':
conf.check_cc(lib='dl')
else:
conf.check_cxx(lib='user32')
def build(bld):
source = bld.path.ant_glob([
'render/*.cpp',
'*.cpp'
])
source += bld.path.parent.ant_glob([
'game_shared/*.cpp',
'pm_shared/*.cpp'
])
includes = [
'.',
'hl/',
'../dlls',
'../common',
'../engine',
'../pm_shared',
'../game_shared',
'../public',
'../utils/vgui/include'
]
defines = ['CLIENT_DLL']
libs = []
if bld.env.DEST_OS != 'win32':
libs += ['DL']
else:
libs += ["USER32"]
if bld.env.DEST_OS not in ['android', 'dos']:
install_path = os.path.join(bld.env.GAMEDIR, bld.env.CLIENT_DIR)
else:
install_path = bld.env.PREFIX
bld.shlib(
source = source,
target = 'client' + bld.env.POSTFIX,
name = 'client',
features = 'c cxx',
includes = includes,
defines = defines,
use = libs,
install_path = install_path,
subsystem = bld.env.MSVC_SUBSYSTEM,
idx = bld.get_taskgen_count()
)

61
dlls/wscript Normal file
View File

@ -0,0 +1,61 @@
#! /usr/bin/env python
# encoding: utf-8
# a1batross, mittorn, 2018
from waflib import Utils
import os
def options(opt):
# stub
return
def configure(conf):
if conf.env.COMPILER_CC == 'msvc':
# hl.def removes MSVC function name decoration from GiveFnptrsToDll on Windows.
# Without this, the lookup for this function fails.
hlDefNode = conf.path.find_resource("./hl.def")
if hlDefNode is not None:
conf.env.append_unique('LINKFLAGS', '/def:%s' % hlDefNode.abspath())
else:
conf.fatal("Could not find hl.def")
def build(bld):
source = bld.path.parent.ant_glob([
'pm_shared/*.cpp',
'game_shared/*.cpp'
])
source += bld.path.ant_glob([
'*.cpp'
])
includes = [
'.',
'../common',
'../engine',
'../pm_shared',
'../game_shared',
'../public'
]
defines = []
libs = []
if bld.env.DEST_OS not in ['android', 'dos']:
install_path = os.path.join(bld.env.GAMEDIR, bld.env.SERVER_DIR)
else:
install_path = bld.env.PREFIX
bld.shlib(
source = source,
target = bld.env.SERVER_NAME + bld.env.POSTFIX,
name = 'server',
features = 'c cxx',
includes = includes,
defines = defines,
use = libs,
install_path = install_path,
subsystem = bld.env.MSVC_SUBSYSTEM,
idx = bld.get_taskgen_count()
)

View File

@ -0,0 +1,133 @@
#! /usr/bin/env python
# Copyright 2019 (C) a1batross
from waflib import Configure, Errors, Utils
# TODO: make generic
CHECK_SYMBOL_EXISTS_FRAGMENT = '''
#include "build.h"
int main(int argc, char** argv)
{
(void)argv;
#ifndef %s
return ((int*)(&%s))[argc];
#else
(void)argc;
return 0;
#endif
}
'''
DEFINES = [
'XASH_64BIT',
'XASH_AMD64',
'XASH_ANDROID',
'XASH_APPLE',
'XASH_ARM',
'XASH_ARM64',
'XASH_ARM_HARDFP',
'XASH_ARM_SOFTFP',
'XASH_ARMv4',
'XASH_ARMv5',
'XASH_ARMv6',
'XASH_ARMv7',
'XASH_BIG_ENDIAN',
'XASH_BSD',
'XASH_E2K',
'XASH_EMSCRIPTEN',
'XASH_FREEBSD',
'XASH_IOS',
'XASH_JS',
'XASH_LINUX',
'XASH_LITTLE_ENDIAN',
'XASH_MINGW',
'XASH_MIPS',
'XASH_MOBILE_PLATFORM',
'XASH_MSVC',
'XASH_NETBSD',
'XASH_OPENBSD',
'XASH_WIN32',
'XASH_WIN64',
'XASH_X86',
'XASH_DOS4GW',
'XASH_POSIX'
]
def configure(conf):
conf.env.stash()
conf.start_msg('Determining library postfix')
tests = map(lambda x: {
'fragment': CHECK_SYMBOL_EXISTS_FRAGMENT % (x, x),
'includes': [conf.path.find_node('public/').abspath()],
'define_name': x }, DEFINES )
conf.multicheck(*tests, msg = '', mandatory = False, quiet = True)
# engine/common/build.c
if conf.env.XASH_ANDROID:
buildos = "android"
elif conf.env.XASH_WIN32 or conf.env.XASH_LINUX or conf.env.XASH_APPLE:
buildos = "" # no prefix for default OS
elif conf.env.XASH_FREEBSD:
buildos = "freebsd"
elif conf.env.XASH_NETBSD:
buildos = "netbsd"
elif conf.env.XASH_OPENBSD:
buildos = "openbsd"
elif conf.env.XASH_EMSCRIPTEN:
buildos = "emscripten"
elif conf.env.XASH_DOS4GW:
buildos = "dos4gw" # unused, just in case
else:
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 conf.env.XASH_AMD64:
buildarch = "amd64"
elif conf.env.XASH_X86:
buildarch = ""
elif conf.env.XASH_ARM64:
buildarch = "arm64"
elif conf.env.XASH_ARM:
buildarch = "armv"
if conf.env.XASH_ARMv7:
buildarch += "7"
elif conf.env.XASH_ARMv6:
buildarch += "6"
elif conf.env.XASH_ARMv5:
buildarch += "5"
elif conf.env.XASH_ARMv4:
buildarch += "4"
else:
raise conf.fatal('Unknown ARM')
if conf.env.XASH_ARM_HARDFP:
buildarch += "hf"
else:
buildarch += "l"
elif conf.env.XASH_MIPS and conf.env.XASH_BIG_ENDIAN:
buildarch = "mips"
elif conf.env.XASH_MIPS and conf.env.XASH_LITTLE_ENDIAN:
buildarch = "mipsel"
elif conf.env.XASH_JS:
buildarch = "javascript"
elif conf.env.XASH_E2K:
buildarch = "e2k"
else:
raise conf.fatal("Place your architecture name in build.h and library_naming.py!\n"
"If this is a mistake, try to fix conditions above and report a bug")
conf.env.revert()
if buildos == 'android':
# force disable for Android, as Android ports aren't distributed in normal way and doesn't follow library naming
conf.env.POSTFIX = ''
elif buildos != '' and buildarch != '':
conf.env.POSTFIX = '_%s_%s' % (buildos,buildarch)
elif buildarch != '':
conf.env.POSTFIX = '_%s' % buildarch
else:
conf.env.POSTFIX = ''
conf.end_msg(conf.env.POSTFIX)

Binary file not shown.

View File

@ -0,0 +1,49 @@
#! /usr/bin/env python
# Modified: Alibek Omarov <a1ba.omarov@gmail.com>
# Originally taken from Thomas Nagy's blogpost
"""
Strip executables upon installation
"""
import shutil, os
from waflib import Build, Utils, Context, Errors, Logs
def options(opt):
grp = opt.option_groups['install/uninstall options']
grp.add_option('--no-strip', dest='no_strip', action='store_true', default=False,
help='don\'t strip binaries. You must pass this flag to install command(default: False)')
def configure(conf):
if conf.env.DEST_BINFMT in ['elf', 'mac-o']:
conf.find_program('strip', var='STRIP')
if not conf.env.STRIPFLAGS:
conf.env.STRIPFLAGS = os.environ['STRIPFLAGS'] if 'STRIPFLAGS' in os.environ else []
def copy_fun(self, src, tgt):
inst_copy_fun(self, src, tgt)
if self.generator.bld.options.no_strip:
return
if self.env.DEST_BINFMT not in ['elf', 'mac-o']: # don't strip unknown formats or PE
return
if getattr(self.generator, 'link_task', None) and self.generator.link_task.outputs[0] in self.inputs:
cmd = self.env.STRIP + self.env.STRIPFLAGS + [tgt]
try:
self.generator.bld.cmd_and_log(cmd, output=Context.BOTH, quiet=Context.BOTH)
if not self.generator.bld.progress_bar:
c1 = Logs.colors.NORMAL
c2 = Logs.colors.CYAN
f1 = os.path.getsize(src)
f2 = os.path.getsize(tgt)
Logs.info('%s+ strip %s%s%s (%d bytes change)', c1, c2, tgt, c1, f2 - f1)
except Errors.WafError as e:
print(e.stdout, e.stderr)
inst_copy_fun = Build.inst.copy_fun
Build.inst.copy_fun = copy_fun

View File

@ -0,0 +1,418 @@
# encoding: utf-8
# xcompile.py -- crosscompiling utils
# Copyright (C) 2018 a1batross
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
try: from fwgslib import get_flags_by_compiler
except: from waflib.extras.fwgslib import get_flags_by_compiler
from waflib import Logs, TaskGen
from waflib.Tools import c_config
from collections import OrderedDict
import os
import sys
ANDROID_NDK_ENVVARS = ['ANDROID_NDK_HOME', 'ANDROID_NDK']
ANDROID_NDK_SUPPORTED = [10, 19, 20]
ANDROID_NDK_HARDFP_MAX = 11 # latest version that supports hardfp
ANDROID_NDK_GCC_MAX = 17 # latest NDK that ships with GCC
ANDROID_NDK_UNIFIED_SYSROOT_MIN = 15
ANDROID_NDK_SYSROOT_FLAG_MAX = 19 # latest NDK that need --sysroot flag
ANDROID_NDK_API_MIN = { 10: 3, 19: 16, 20: 16 } # minimal API level ndk revision supports
ANDROID_64BIT_API_MIN = 21 # minimal API level that supports 64-bit targets
# This class does support ONLY r10e and r19c/r20 NDK
class Android:
ctx = None # waf context
arch = None
toolchain = None
api = None
ndk_home = None
ndk_rev = 0
is_hardfloat = False
clang = False
def __init__(self, ctx, arch, toolchain, api):
self.ctx = ctx
self.api = api
self.toolchain = toolchain
self.arch = arch
for i in ANDROID_NDK_ENVVARS:
self.ndk_home = os.getenv(i)
if self.ndk_home != None:
break
else:
ctx.fatal('Set %s environment variable pointing to the root of Android NDK!' %
' or '.join(ANDROID_NDK_ENVVARS))
# TODO: this were added at some point of NDK development
# but I don't know at which version
# r10e don't have it
source_prop = os.path.join(self.ndk_home, 'source.properties')
if os.path.exists(source_prop):
with open(source_prop) as ndk_props_file:
for line in ndk_props_file.readlines():
tokens = line.split('=')
trimed_tokens = [token.strip() for token in tokens]
if 'Pkg.Revision' in trimed_tokens:
self.ndk_rev = int(trimed_tokens[1].split('.')[0])
if self.ndk_rev not in ANDROID_NDK_SUPPORTED:
ctx.fatal('Unknown NDK revision: %d' % (self.ndk_rev))
else:
self.ndk_rev = ANDROID_NDK_SUPPORTED[0]
if 'clang' in self.toolchain or self.ndk_rev > ANDROID_NDK_GCC_MAX:
self.clang = True
if self.arch == 'armeabi-v7a-hard':
if self.ndk_rev <= ANDROID_NDK_HARDFP_MAX:
self.arch = 'armeabi-v7a' # Only armeabi-v7a have hard float ABI
self.is_hardfloat = True
else:
ctx.fatal('NDK does not support hardfloat ABI')
if self.api < ANDROID_NDK_API_MIN[self.ndk_rev]:
self.api = ANDROID_NDK_API_MIN[self.ndk_rev]
Logs.warn('API level automatically was set to %d due to NDK support' % self.api)
if self.is_arm64() or self.is_amd64() and self.api < ANDROID_64BIT_API_MIN:
self.api = ANDROID_64BIT_API_MIN
Logs.warn('API level for 64-bit target automatically was set to %d' % self.api)
def is_host(self):
'''
Checks if we using host compiler(implies clang)
'''
return self.toolchain == 'host'
def is_arm(self):
'''
Checks if selected architecture is **32-bit** ARM
'''
return self.arch.startswith('armeabi')
def is_x86(self):
'''
Checks if selected architecture is **32-bit** or **64-bit** x86
'''
return self.arch == 'x86'
def is_amd64(self):
'''
Checks if selected architecture is **64-bit** x86
'''
return self.arch == 'x86_64'
def is_arm64(self):
'''
Checks if selected architecture is AArch64
'''
return self.arch == 'aarch64'
def is_clang(self):
'''
Checks if selected toolchain is Clang (TODO)
'''
return self.clang
def is_hardfp(self):
return self.is_hardfloat
def ndk_triplet(self, llvm_toolchain = False, toolchain_folder = False):
if self.is_x86():
if toolchain_folder:
return 'x86'
else:
return 'i686-linux-android'
elif self.is_arm():
if llvm_toolchain:
return 'armv7a-linux-androideabi'
else:
return 'arm-linux-androideabi'
elif self.is_amd64() and toolchain_folder:
return 'x86_64'
else:
return self.arch + '-linux-android'
def apk_arch(self):
if self.is_arm64():
return 'arm64-v8a'
return self.arch
def gen_host_toolchain(self):
# With host toolchain we don't care about OS
# so just download NDK for Linux x86_64
if self.is_host():
return 'linux-x86_64'
if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
osname = 'windows'
elif sys.platform.startswith('darwin'):
osname = 'darwin'
elif sys.platform.startswith('linux'):
osname = 'linux'
else:
self.ctx.fatal('Unsupported by NDK host platform')
if sys.maxsize > 2**32:
arch = 'x86_64'
else: arch = 'x86'
return '%s-%s' % (osname, arch)
def gen_gcc_toolchain_path(self):
path = 'toolchains'
toolchain_host = self.gen_host_toolchain()
if self.is_clang():
toolchain_folder = 'llvm'
else:
if self.is_host():
toolchain = '4.9'
else:
toolchain = self.toolchain
toolchain_folder = '%s-%s' % (self.ndk_triplet(toolchain_folder = True), toolchain)
return os.path.abspath(os.path.join(self.ndk_home, path, toolchain_folder, 'prebuilt', toolchain_host))
def gen_toolchain_path(self):
if self.is_clang():
triplet = '%s%d-' % (self.ndk_triplet(llvm_toolchain = True), self.api)
else:
triplet = self.ndk_triplet() + '-'
return os.path.join(self.gen_gcc_toolchain_path(), 'bin', triplet)
def gen_binutils_path(self):
return os.path.join(self.gen_gcc_toolchain_path(), self.ndk_triplet(), 'bin')
def cc(self):
if self.is_host():
return 'clang --target=%s%d' % (self.ndk_triplet(), self.api)
return self.gen_toolchain_path() + ('clang' if self.is_clang() else 'gcc')
def cxx(self):
if self.is_host():
return 'clang++ --target=%s%d' % (self.ndk_triplet(), self.api)
return self.gen_toolchain_path() + ('clang++' if self.is_clang() else 'g++')
def strip(self):
if self.is_host():
return 'llvm-strip'
return os.path.join(self.gen_binutils_path(), 'strip')
def system_stl(self):
# TODO: proper STL support
return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'system', 'include'))
def libsysroot(self):
arch = self.arch
if self.is_arm():
arch = 'arm'
elif self.is_arm64():
arch = 'arm64'
path = 'platforms/android-%s/arch-%s' % (self.api, arch)
return os.path.abspath(os.path.join(self.ndk_home, path))
def sysroot(self):
if self.ndk_rev >= ANDROID_NDK_UNIFIED_SYSROOT_MIN:
return os.path.abspath(os.path.join(self.ndk_home, 'sysroot'))
else:
return self.libsysroot()
def cflags(self, cxx = False):
cflags = []
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX:
cflags += ['--sysroot=%s' % (self.sysroot())]
else:
if self.is_host():
cflags += [
'--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path()),
'-isystem', '%s/usr/include/' % (self.sysroot())
]
cflags += ['-I%s' % (self.system_stl()), '-DANDROID', '-D__ANDROID__']
if cxx and not self.is_clang() and self.toolchain not in ['4.8','4.9']:
cflags += ['-fno-sized-deallocation']
def fixup_host_clang_with_old_ndk():
cflags = []
# Clang builtin redefine w/ different calling convention bug
# NOTE: I did not added complex.h functions here, despite
# that NDK devs forgot to put __NDK_FPABI_MATH__ for complex
# math functions
# I personally don't need complex numbers support, but if you want it
# just run sed to patch header
for f in ['strtod', 'strtof', 'strtold']:
cflags += ['-fno-builtin-%s' % f]
return cflags
if self.is_arm():
if self.arch == 'armeabi-v7a':
# ARMv7 support
cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9', '-DHAVE_EFFICIENT_UNALIGNED_ACCESS', '-DVECTORIZE_SINCOS']
if not self.is_clang() and not self.is_host():
cflags += [ '-mvectorize-with-neon-quad' ]
if self.is_host() and self.ndk_rev <= ANDROID_NDK_HARDFP_MAX:
cflags += fixup_host_clang_with_old_ndk()
if self.is_hardfp():
cflags += ['-D_NDK_MATH_NO_SOFTFP=1', '-mfloat-abi=hard', '-DLOAD_HARDFP', '-DSOFTFP_LINK']
else:
cflags += ['-mfloat-abi=softfp']
else:
if self.is_host() and self.ndk_rev <= ANDROID_NDK_HARDFP_MAX:
cflags += fixup_host_clang_with_old_ndk()
# ARMv5 support
cflags += ['-march=armv5te', '-mtune=xscale', '-msoft-float']
elif self.is_x86():
cflags += ['-mtune=atom', '-march=atom', '-mssse3', '-mfpmath=sse', '-DVECTORIZE_SINCOS', '-DHAVE_EFFICIENT_UNALIGNED_ACCESS']
return cflags
# they go before object list
def linkflags(self):
linkflags = []
if self.is_host():
linkflags += ['--gcc-toolchain=%s' % self.gen_gcc_toolchain_path()]
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX:
linkflags += ['--sysroot=%s' % (self.sysroot())]
elif self.is_host():
linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())]
if self.is_clang() or self.is_host():
linkflags += ['-fuse-ld=lld']
linkflags += ['-Wl,--hash-style=both','-Wl,--no-undefined']
return linkflags
def ldflags(self):
ldflags = ['-lgcc', '-no-canonical-prefixes']
if self.is_clang() or self.is_host():
ldflags += ['-stdlib=libstdc++']
if self.is_arm():
if self.arch == 'armeabi-v7a':
ldflags += ['-march=armv7-a', '-mthumb']
if not self.is_clang() and not self.is_host(): # lld only
ldflags += ['-Wl,--fix-cortex-a8']
if self.is_hardfp():
ldflags += ['-Wl,--no-warn-mismatch', '-lm_hard']
else:
ldflags += ['-march=armv5te']
return ldflags
def options(opt):
android = opt.add_option_group('Android options')
android.add_option('--android', action='store', dest='ANDROID_OPTS', default=None,
help='enable building for android, format: --android=<arch>,<toolchain>,<api>, example: --android=armeabi-v7a-hard,4.9,9')
def configure(conf):
if conf.options.ANDROID_OPTS:
values = conf.options.ANDROID_OPTS.split(',')
if len(values) != 3:
conf.fatal('Invalid --android paramater value!')
valid_archs = ['x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'armeabi-v7a-hard', 'aarch64']
if values[0] not in valid_archs:
conf.fatal('Unknown arch: %s. Supported: %r' % (values[0], ', '.join(valid_archs)))
conf.android = android = Android(conf, values[0], values[1], int(values[2]))
conf.environ['CC'] = android.cc()
conf.environ['CXX'] = android.cxx()
conf.environ['STRIP'] = android.strip()
conf.env.CFLAGS += android.cflags()
conf.env.CXXFLAGS += android.cflags(True)
conf.env.LINKFLAGS += android.linkflags()
conf.env.LDFLAGS += android.ldflags()
conf.env.HAVE_M = True
if android.is_hardfp():
conf.env.LIB_M = ['m_hard']
else: conf.env.LIB_M = ['m']
conf.env.PREFIX = '/lib/%s' % android.apk_arch()
conf.msg('Selected Android NDK', '%s, version: %d' % (android.ndk_home, android.ndk_rev))
# no need to print C/C++ compiler, as it would be printed by compiler_c/cxx
conf.msg('... C/C++ flags', ' '.join(android.cflags()).replace(android.ndk_home, '$NDK/'))
conf.msg('... link flags', ' '.join(android.linkflags()).replace(android.ndk_home, '$NDK/'))
conf.msg('... ld flags', ' '.join(android.ldflags()).replace(android.ndk_home, '$NDK/'))
# conf.env.ANDROID_OPTS = android
conf.env.DEST_OS2 = 'android'
MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android' })
for k in c_config.MACRO_TO_DESTOS:
MACRO_TO_DESTOS[k] = c_config.MACRO_TO_DESTOS[k] # ordering is important
c_config.MACRO_TO_DESTOS = MACRO_TO_DESTOS
def post_compiler_cxx_configure(conf):
conf.msg('Target OS', conf.env.DEST_OS)
conf.msg('Target CPU', conf.env.DEST_CPU)
conf.msg('Target binfmt', conf.env.DEST_BINFMT)
if conf.options.ANDROID_OPTS:
if conf.android.ndk_rev == 19:
conf.env.CXXFLAGS_cxxshlib += ['-static-libstdc++']
conf.env.LDFLAGS_cxxshlib += ['-static-libstdc++']
return
def post_compiler_c_configure(conf):
conf.msg('Target OS', conf.env.DEST_OS)
conf.msg('Target CPU', conf.env.DEST_CPU)
conf.msg('Target binfmt', conf.env.DEST_BINFMT)
return
from waflib.Tools import compiler_cxx, compiler_c
compiler_cxx_configure = getattr(compiler_cxx, 'configure')
compiler_c_configure = getattr(compiler_c, 'configure')
def patch_compiler_cxx_configure(conf):
compiler_cxx_configure(conf)
post_compiler_cxx_configure(conf)
def patch_compiler_c_configure(conf):
compiler_c_configure(conf)
post_compiler_c_configure(conf)
setattr(compiler_cxx, 'configure', patch_compiler_cxx_configure)
setattr(compiler_c, 'configure', patch_compiler_c_configure)
@TaskGen.feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')
@TaskGen.after_method('apply_link', 'propagate_uselib_vars')
@TaskGen.before_method('apply_vnum')
def apply_android_soname(self):
"""
Enforce SONAME on Android
"""
if self.env.DEST_OS != 'android':
return
setattr(self, 'vnum', None) # remove vnum, so SONAME would not be overwritten
link = self.link_task
node = link.outputs[0]
libname = node.name
v = self.env.SONAME_ST % libname
self.env.append_value('LINKFLAGS', v.split())

Binary file not shown.

175
waf vendored Executable file

File diff suppressed because one or more lines are too long

268
wscript Normal file
View File

@ -0,0 +1,268 @@
#! /usr/bin/env python
# encoding: utf-8
# a1batross, mittorn, 2018
from __future__ import print_function
from waflib import Logs, Context, Configure
import sys
import os
VERSION = '1.51'
APPNAME = 'Paranoia2'
top = '.'
Context.Context.line_just = 55 # should fit for everything on 80x26
@Configure.conf
def get_taskgen_count(self):
try: idx = self.tg_idx_count
except: idx = 0 # don't set tg_idx_count to not increase counter
return idx
def options(opt):
grp = opt.add_option_group('Common options')
grp.add_option('-T', '--build-type', action='store', dest='BUILD_TYPE', default = None,
help = 'build type: debug, release or none(custom flags)')
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]')
grp.add_option('--enable-lto', action = 'store_true', dest = 'LTO', default = False,
help = 'enable Link Time Optimization [default: %default]')
grp.add_option('--enable-poly-opt', action = 'store_true', dest = 'POLLY', default = False,
help = 'enable polyhedral optimization if possible [default: %default]')
grp.add_option('--enable-magx', action = 'store_true', dest = 'MAGX', default = False,
help = 'enable targetting for MotoMAGX phones [default: %default]')
opt.load('xcompile compiler_cxx compiler_c clang_compilation_database strip_on_install')
if sys.platform == 'win32':
opt.load('msvc msdev msvs')
opt.load('reconfigure subproject')
opt.add_subproject(["cl_dll", "dlls"])
def configure(conf):
# Configuration
conf.env.GAMEDIR = 'base' # it was base or p2 or paranoia2???
conf.env.CLIENT_DIR = 'bin'
conf.env.SERVER_DIR = 'bin'
conf.env.SERVER_NAME = 'spirit'
conf.env.PREFIX = ''
conf.load('fwgslib reconfigure')
enforce_pic = True # modern defaults
valid_build_types = ['fastnative', 'fast', 'release', 'debug', 'nooptimize', 'sanitize', 'none']
conf.load('fwgslib reconfigure')
conf.start_msg('Build type')
if conf.options.BUILD_TYPE == None:
conf.end_msg('not set', color='RED')
conf.fatal('Please 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.fatal('Invalid build type. Valid are: %s' % ', '.join(valid_build_types))
conf.end_msg(conf.options.BUILD_TYPE)
# -march=native should not be used
if conf.options.BUILD_TYPE == 'fast':
Logs.warn('WARNING: \'fast\' build type should not be used in release builds')
# Force XP compability, all build targets should add
# subsystem=bld.env.MSVC_SUBSYSTEM
# TODO: wrapper around bld.stlib, bld.shlib and so on?
conf.env.MSVC_SUBSYSTEM = 'WINDOWS,5.01'
conf.env.MSVC_TARGETS = ['x86'] # explicitly request x86 target for MSVC
if sys.platform == 'win32':
conf.load('msvc msdev')
conf.load('xcompile compiler_c compiler_cxx strip_on_install')
try:
conf.env.CC_VERSION[0]
except IndexError:
conf.env.CC_VERSION = (0, )
if conf.env.DEST_OS == 'android':
conf.options.GOLDSRC = False
conf.env.SERVER_NAME = 'server' # can't be any other name, until specified
conf.env.MAGX = conf.options.MAGX
if conf.options.MAGX:
enforce_pic = False
if enforce_pic:
# Every static library must have fPIC
if conf.env.DEST_OS != 'win32' and '-fPIC' in conf.env.CFLAGS_cshlib:
conf.env.append_unique('CFLAGS_cstlib', '-fPIC')
conf.env.append_unique('CXXFLAGS_cxxstlib', '-fPIC')
else:
conf.env.CFLAGS_cshlib.remove('-fPIC')
conf.env.CXXFLAGS_cxxshlib.remove('-fPIC')
conf.env.CFLAGS_MACBUNDLE.remove('-fPIC')
conf.env.CXXFLAGS_MACBUNDLE.remove('-fPIC')
# We restrict 64-bit builds ONLY for Win/Linux/OSX running on Intel architecture
# Because compatibility with original GoldSrc
if conf.env.DEST_OS in ['win32', 'linux', 'darwin'] and conf.env.DEST_CPU in ['x86_64']:
conf.env.BIT32_ALLOW64 = conf.options.ALLOW64
if not conf.env.BIT32_ALLOW64:
Logs.info('WARNING: will build engine for 32-bit target')
else:
conf.env.BIT32_ALLOW64 = True
conf.env.BIT32_MANDATORY = not conf.env.BIT32_ALLOW64
conf.load('force_32bit library_naming')
linker_flags = {
'common': {
'msvc': ['/DEBUG'], # always create PDB, doesn't affect result binaries
'gcc': ['-Wl,--no-undefined']
},
'sanitize': {
'clang': ['-fsanitize=undefined', '-fsanitize=address'],
'gcc': ['-fsanitize=undefined', '-fsanitize=address'],
}
}
compiler_c_cxx_flags = {
'common': {
# disable thread-safe local static initialization for C++11 code, as it cause crashes on Windows XP
'msvc': ['/D_USING_V110_SDK71_', '/Zi', '/FS', '/Zc:threadSafeInit-', '/MT'],
'clang': ['-g', '-gdwarf-2', '-fvisibility=hidden'],
'gcc': ['-g']
},
'fast': {
'msvc': ['/O2', '/Oy'],
'gcc': {
'3': ['-O3', '-Os', '-funsafe-math-optimizations', '-fomit-frame-pointer'],
'default': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer']
},
'clang': ['-Ofast'],
'default': ['-O3']
},
'fastnative': {
'msvc': ['/O2', '/Oy'],
'gcc': ['-Ofast', '-march=native', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer'],
'clang': ['-Ofast', '-march=native'],
'default': ['-O3']
},
'release': {
'msvc': ['/O2'],
'default': ['-O3']
},
'debug': {
'msvc': ['/O1'],
'gcc': ['-Og'],
'default': ['-O1']
},
'sanitize': {
'msvc': ['/Od', '/RTC1'],
'gcc': ['-Og', '-fsanitize=undefined', '-fsanitize=address'],
'clang': ['-O0', '-fsanitize=undefined', '-fsanitize=address'],
'default': ['-O0']
},
'nooptimize': {
'msvc': ['/Od'],
'default': ['-O0']
}
}
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 = [
'-Werror=implicit-function-declaration',
'-Werror=int-conversion',
'-Werror=implicit-int',
'-Werror=declaration-after-statement'
]
linkflags = conf.get_flags_by_type(linker_flags, conf.options.BUILD_TYPE, conf.env.COMPILER_CC, conf.env.CC_VERSION[0])
cflags = conf.get_flags_by_type(compiler_c_cxx_flags, conf.options.BUILD_TYPE, conf.env.COMPILER_CC, conf.env.CC_VERSION[0])
# Here we don't differentiate C or C++ flags
if conf.options.LTO:
lto_cflags = {
'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)
conf.env.append_unique('CFLAGS', cflags)
conf.env.append_unique('CXXFLAGS', cxxflags)
conf.env.append_unique('LINKFLAGS', linkflags)
# check if we can use C99 tgmath
if conf.check_cc(header_name='tgmath.h', mandatory=False):
tgmath_usable = conf.check_cc(fragment='''#include<tgmath.h>
int main(void){ return (int)sin(2.0f); }''',
msg='Checking if tgmath.h is usable', mandatory=False)
conf.define_cond('HAVE_TGMATH_H', tgmath_usable)
else:
conf.undefine('HAVE_TGMATH_H')
cmath_usable = conf.check_cxx(fragment='''#include<cmath>
int main(void){ return (int)sqrt(2.0f); }''',
msg='Checking if cmath is usable', mandatory = False)
conf.define_cond('HAVE_CMATH', cmath_usable)
if conf.env.COMPILER_CC == 'msvc':
conf.define('_CRT_SECURE_NO_WARNINGS', 1)
conf.define('_CRT_NONSTDC_NO_DEPRECATE', 1)
elif conf.env.COMPILER_CC == 'owcc':
pass
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-rtti', '-fno-exceptions'])
# strip lib from pattern
if conf.env.DEST_OS in ['linux', 'darwin']:
if conf.env.cshlib_PATTERN.startswith('lib'):
conf.env.cshlib_PATTERN = conf.env.cshlib_PATTERN[3:]
if conf.env.cxxshlib_PATTERN.startswith('lib'):
conf.env.cxxshlib_PATTERN = conf.env.cxxshlib_PATTERN[3:]
conf.define('CLIENT_WEAPONS', '1')
conf.add_subproject(["cl_dll", "dlls"])
def build(bld):
bld.add_subproject(["cl_dll", "dlls"])