2
0
mirror of https://github.com/FWGS/hlsdk-xash3d synced 2024-11-21 17:36:18 +01:00

waf: initial deploy

This commit is contained in:
Alibek Omarov 2019-05-03 19:19:39 +03:00
parent f7e51e2c20
commit 470a71540b
11 changed files with 1646 additions and 0 deletions

3
.gitignore vendored
View File

@ -17,3 +17,6 @@ cmake_install.cmake
*.vsxproj
*.vsproj
*.sln
.waf-*
.lock*
*.pyc

69
cl_dll/wscript Normal file
View File

@ -0,0 +1,69 @@
#! /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.GOLDSRC:
if conf.env.DEST_OS != 'win32':
conf.check_cc(lib='dl')
def build(bld):
source = bld.path.parent.ant_glob([
'pm_shared/*.c',
'dlls/crossbow.cpp', 'dlls/crowbar.cpp', 'dlls/egon.cpp', 'dlls/gauss.cpp', 'dlls/handgrenade.cpp',
'dlls/hornetgun.cpp', 'dlls/mp5.cpp', 'dlls/python.cpp', 'dlls/rpg.cpp', 'dlls/satchel.cpp',
'dlls/shotgun.cpp', 'dlls/squeakgrenade.cpp', 'dlls/tripmine.cpp', 'dlls/glock.cpp'
])
source += bld.path.ant_glob(['hl/*.cpp'])
source += [
'ev_hldm.cpp', 'ammo.cpp', 'ammo_secondary.cpp', 'ammohistory.cpp',
'battery.cpp', 'cdll_int.cpp', 'com_weapons.cpp', 'death.cpp',
'demo.cpp', 'entity.cpp', 'ev_common.cpp', 'events.cpp',
'flashlight.cpp', 'GameStudioModelRenderer.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',
'overview.cpp', 'parsemsg.cpp', 'saytext.cpp',
'status_icons.cpp', 'statusbar.cpp', 'studio_util.cpp',
'StudioModelRenderer.cpp', 'text_message.cpp', 'train.cpp',
'tri.cpp', 'util.cpp', 'view.cpp', 'scoreboard.cpp', 'MOTD.cpp'
]
includes = Utils.to_list('. hl/ ../dlls ../dlls/wpn_shared ../common ../engine ../pm_shared ../game_shared ../public ../utils/false_vgui/include')
defines = ['CLIENT_DLL']
if bld.env.GOLDSRC:
defines += ['GOLDSOURCE_SUPPORT']
libs = []
if bld.env.GOLDSRC:
libs += ['DL']
if bld.env.DEST_OS == 'win32':
libname = 'client.dll'
elif bld.env.DEST_OS == 'linux':
libname = 'client.so'
elif bld.env.DEST_OS == 'darwin':
libname = 'client.dylib'
else: libname = ''
bld.shlib(
source = source,
target = 'client',
features = 'c cxx',
includes = includes,
defines = defines,
use = libs,
install_path = os.path.join(bld.env.GAMEDIR, bld.env.CLIENT_DIR, libname),
subsystem = bld.env.MSVC_SUBSYSTEM,
idx = 1
)

75
dlls/wscript Normal file
View File

@ -0,0 +1,75 @@
#! /usr/bin/env python
# encoding: utf-8
# a1batross, mittorn, 2018
from waflib import Utils
import os
def options(opt):
# stub
return
def configure(conf):
# stub
return
def build(bld):
defines = []
source = bld.path.parent.ant_glob([
'pm_shared/*.c',
])
source += [
'agrunt.cpp', 'airtank.cpp', 'aflock.cpp', 'animating.cpp', 'animation.cpp', 'apache.cpp',
'barnacle.cpp', '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']
if bld.env.VOICEMGR:
source += bld.path.parent.ant_glob([
'game_shared/voice_gamemgr.cpp',
])
else:
defines += ['NO_VOICEGAMEMGR']
includes = Utils.to_list('. wpn_shared ../common ../engine ../pm_shared ../game_shared ../public')
libs = []
if bld.env.DEST_OS == 'win32':
libname = bld.env.SERVER_NAME + '.dll'
elif bld.env.DEST_OS == 'linux':
libname = bld.env.SERVER_NAME + '.so'
elif bld.env.DEST_OS == 'darwin':
libname = bld.env.SERVER_NAME + '.dylib'
else: libname = ''
bld.shlib(
source = source,
target = 'server',
features = 'c cxx',
includes = includes,
defines = defines,
use = libs,
install_path = os.path.join(bld.env.GAMEDIR, bld.env.SERVER_DIR, libname),
subsystem = bld.env.MSVC_SUBSYSTEM,
idx = 2
)

65
scripts/waflib/deps.py Normal file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Michel Mooij, michel.mooij7@gmail.com
from waflib import Utils
from waflib import Errors
def get_deps(bld, target):
'''Returns a list of (nested) targets on which this target depends.
:param bld: a *waf* build instance from the top level *wscript*
:type bld: waflib.Build.BuildContext
:param target: task name for which the dependencies should be returned
:type target: str
:returns: a list of task names on which the given target depends
'''
try:
tgen = bld.get_tgen_by_name(target)
except Errors.WafError:
return []
else:
uses = Utils.to_list(getattr(tgen, 'use', []))
deps = uses[:]
for use in uses:
deps += get_deps(bld, use)
return list(set(deps))
def get_tgens(bld, names):
'''Returns a list of task generators based on the given list of task
generator names.
:param bld: a *waf* build instance from the top level *wscript*
:type bld: waflib.Build.BuildContext
:param names: list of task generator names
:type names: list of str
:returns: list of task generators
'''
tgens=[]
for name in names:
try:
tgen = bld.get_tgen_by_name(name)
except Errors.WafError:
pass
else:
tgens.append(tgen)
return list(set(tgens))
def get_targets(bld):
'''Returns a list of user specified build targets or None if no specific
build targets has been selected using the *--targets=* command line option.
:param bld: a *waf* build instance from the top level *wscript*.
:type bld: waflib.Build.BuildContext
:returns: a list of user specified target names (using --targets=x,y,z) or None
'''
if bld.targets == '':
return None
targets = bld.targets.split(',')
for target in targets:
targets += get_deps(bld, target)
return targets

View File

@ -0,0 +1,56 @@
# encoding: utf-8
# force_32bit.py -- force compiler to create 32-bit code
# 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.
from fwgslib import get_flags_by_compiler
# Input:
# BIT32_MANDATORY(optional) -- fail if 32bit mode not available
# BIT32_ALLOW64(optional) -- ignore all checks, just set DEST_SIZEOF_VOID_P to 8
# Output:
# DEST_SIZEOF_VOID_P -- an integer, equals sizeof(void*) on target
def check_32bit(ctx, msg):
try:
ctx.check_cc(
fragment='''int main( void )
{
int check[sizeof(void*) == 4 ? 1: -1];
return 0;
}''',
msg = msg)
except ctx.errors.ConfigurationError:
return False
return True
def configure(conf):
if getattr(conf.env, 'BIT32_ALLOW64'):
conf.env.DEST_SIZEOF_VOID_P = 8
else:
if check_32bit(conf, 'Checking if \'{0}\' can target 32-bit'.format(conf.env.COMPILER_CC)):
conf.env.DEST_SIZEOF_VOID_P = 4
else:
flags = ['-m32']
# Think different.
if(conf.env.DEST_OS == 'darwin'):
flags = ['-arch', 'i386']
env_stash = conf.env
conf.env.append_value('LINKFLAGS', flags)
conf.env.append_value('CFLAGS', flags)
conf.env.append_value('CXXFLAGS', flags)
if check_32bit(conf, '...trying with additional flags'):
conf.env.DEST_SIZEOF_VOID_P = 4
else:
conf.env.DEST_SIZEOF_VOID_P = 8
conf.env = env_stash
if getattr(conf.env, 'BIT32_MANDATORY') and conf.env.DEST_SIZEOF_VOID_P == 8:
conf.fatal('Compiler can\'t create 32-bit code!')

30
scripts/waflib/fwgslib.py Normal file
View File

@ -0,0 +1,30 @@
# encoding: utf-8
# fwgslib.py -- utils for Waf build system by FWGS
# 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.
import os
def get_flags_by_compiler(flags, compiler):
out = []
if compiler in flags:
out += flags[compiler]
elif 'default' in flags:
out += flags['default']
return out
def get_flags_by_type(flags, type, compiler):
out = []
if 'common' in flags:
out += get_flags_by_compiler(flags['common'], compiler)
if type in flags:
out += get_flags_by_compiler(flags[type], compiler)
return out

774
scripts/waflib/msdev.py Normal file
View File

@ -0,0 +1,774 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Michel Mooij, michel.mooij7@gmail.com
# modified: Alibek Omarov, a1ba.omarov@gmail.com
'''
Summary
-------
Exports and converts *waf* project data, for C/C++ programs, static- and shared
libraries, into **Microsoft Visual Studio**, also known as **msdev**,
project files (.vcproj) and solution (.sln) files.
**Microsoft Visual Studio** is a mature and stable integrated development
environment for, amongst others, the C and C++ programming language. A free
version of this IDE, known as the *express* version can be obtained from Microsoft
at http://wwww.visualstudio.com.
Description
-----------
When exporting *waf* project data, a single **Visual Studio** solution will be
exported in the top level directory of your *WAF* build environment. This
solution file will contain references to all exported **Visual Studio**
projects and will include dependencies between those projects and will have the
same name as APPNAME variable from the top level *wscript* file.
For each single task generator (*waflib.TaskGenerator*), for instance a
*bld.program(...)* which has been defined within a *wscript* file somewhere in
the build environment, a single **Visual Studio** project file will be generated
in the same directory as where the task generator has been defined.
The name of this task generator will be used as name for the exported **Visual
Studio** project file. If for instance the name of the task generator is
*hello*, then a **Visual Studio** project file named *hello.vcproj* will be
exported.
Example below presents an overview of an environment in which **Visual Studio**
files already have been exported::
.
components
clib
program
cprogram.vcproj
wscript
shared
cshlib.vcproj
wscript
static
cstlib.vcproj
wscript
waf.vcproj
appname.sln
wscript
Projects will be exported such that they will use the same settings and
structure as has been defined for that build task within the *waf* build
environment as much as possible. Note that since cross compilation is not
really supported in this IDE, only the first environment encountered that
is targeted for **MS Windows** will be exported; i.e. an environment in
which::
bld.env.DEST_OS == 'win32'
is true.
Please note that in contrast to a *normal* IDE setup the exported projects
will contain either a *debug* **or** a *release* build target but not both at
the same time. By doing so exported projects will always use the same settings
(e.g. compiler options, installation paths) as when building the same task in
the *waf* build environment from command line.
Usage
-----
**Visual Studio** project and workspace files can be exported using the *msdev*
command, as shown in the example below::
$ waf msdev
When needed, exported **Visual Studio** project- and solution files can be
removed using the *clean* command, as shown in the example below::
$ waf msdev --clean
Once exported simply open the *appname.sln* using **Visual Studio**
this will automatically open all exported projects as well.
Tasks generators to be excluded can be marked with the *skipme* option
as shown below::
def build(bld):
bld.program(name='foo', src='foobar.c', msdev_skip=True)
'''
import os
import sys
import copy
import uuid
import shutil
import xml.etree.ElementTree as ElementTree
from xml.dom import minidom
from waflib import Utils, Logs, Errors, Context
from waflib.Build import BuildContext
# import waftools
# from waftools import deps
from deps import get_targets
from subproject import get_subproject_env
def options(opt):
'''Adds command line options to the *waf* build environment
:param opt: Options context from the *waf* build environment.
:type opt: waflib.Options.OptionsContext
'''
opt.add_option('--msdev', dest='msdev', default=False, action='store_true', help='select msdev for export/import actions')
opt.add_option('--clean', dest='clean', default=False, action='store_true', help='delete exported files')
def configure(conf):
'''Method that will be invoked by *waf* when configuring the build
environment.
:param conf: Configuration context from the *waf* build environment.
:type conf: waflib.Configure.ConfigurationContext
'''
pass
class MsDevContext(BuildContext):
'''export C/C++ tasks to MS Visual Studio projects and solutions.'''
cmd = 'msdev'
def execute(self):
'''Will be invoked when issuing the *msdev* command.'''
self.restore()
if not self.all_envs:
self.load_envs()
self.recurse([self.run_dir])
self.pre_build()
for group in self.groups:
for tgen in group:
try:
f = tgen.post
except AttributeError:
pass
else:
f()
try:
self.get_tgen_by_name('')
except Exception:
pass
self.msdev = True
if self.options.clean:
cleanup(self)
else:
export(self)
self.timer = Utils.Timer()
def export(bld):
'''Exports all C and C++ task generators as **Visual Studio** projects
and creates a **Visual Studio** solution containing references to
those project.
:param bld: a *waf* build instance from the top level *wscript*.
:type bld: waflib.Build.BuildContext
'''
if not bld.options.msdev and not hasattr(bld, 'msdev'):
return
Logs.pprint('RED', '''This tool is intended only to ease development for Windows-fags.
Don't use it for release builds, as it doesn't enables WinXP compatibility for now!''')
solution = MsDevSolution(bld)
targets = get_targets(bld)
saveenv = bld.env # root env
for tgen in bld.task_gen_cache_names.values():
if targets and tgen.get_name() not in targets:
continue
if getattr(tgen, 'msdev_skipme', False):
continue
try:
bld.env = get_subproject_env(bld, tgen.path, True)
except IndexError:
bld.env = saveenv
if set(('c', 'cxx')) & set(getattr(tgen, 'features', [])):
project = MsDevProject(bld, tgen)
project.export()
(name, fname, deps, pid) = project.get_metadata()
solution.add_project(name, fname, deps, pid)
solution.export()
def cleanup(bld):
'''Removes all **Visual Studio** projects and workspaces from the
*waf* build environment.
:param bld: a *waf* build instance from the top level *wscript*.
:type bld: waflib.Build.BuildContext
'''
if not bld.options.msdev and not hasattr(bld, 'msdev'):
return
targets = get_targets(bld)
saveenv = bld.env
for tgen in bld.task_gen_cache_names.values():
if targets and tgen.get_name() not in targets:
continue
if getattr(tgen, 'msdev_skipme', False):
continue
try:
bld.env = get_subproject_env(bld, tgen.path)
except IndexError:
bld.env = saveenv
if set(('c', 'cxx')) & set(getattr(tgen, 'features', [])):
project = MsDevProject(bld, tgen)
project.cleanup()
solution = MsDevSolution(bld)
solution.cleanup()
class MsDev(object):
'''Abstract base class used for exporting *waf* project data to
**Visual Studio** projects and solutions.
REMARK:
bld.objects() taks generators are treated as static libraries.
:param bld: Build context as used in *wscript* files of your *waf* build
environment.
:type bld: waflib.Build.BuildContext
'''
PROGRAM = '1'
'''Identifier for projects containing an executable'''
SHLIB = '2'
'''Identifier for projects containing a shared library'''
STLIB = '4'
'''Identifier for projects containing a static library'''
C = 'c'
'''Identifier for projects using C language'''
CXX = 'cxx'
'''Identifier for projects using C++ language'''
def __init__(self, bld):
self.bld = bld
def export(self):
'''Exports a **Visual Studio** solution or project.'''
content = self.get_content()
if not content:
return
if self.xml_clean:
content = self.xml_clean(content)
node = self.make_node()
if not node:
return
node.write(content)
Logs.pprint('YELLOW', 'exported: %s' % node.abspath())
def cleanup(self):
'''Deletes a **Visual Studio** solution or project file including
associated files (e.g. *.ncb*).
'''
cwd = self.get_cwd()
for node in cwd.ant_glob('*.user'):
node.delete()
Logs.pprint('YELLOW', 'removed: %s' % node.abspath())
for node in cwd.ant_glob('*.ncb'):
node.delete()
Logs.pprint('YELLOW', 'removed: %s' % node.abspath())
for node in cwd.ant_glob('*.suo'):
node.delete()
Logs.pprint('YELLOW', 'removed: %s' % node.abspath())
for node in cwd.ant_glob('*.sln'):
node.delete()
Logs.pprint('YELLOW', 'removed: %s' % node.abspath())
node = self.find_node()
if node:
node.delete()
Logs.pprint('YELLOW', 'removed: %s' % node.abspath())
def get_cwd(self):
cwd = os.path.dirname(self.get_fname())
if cwd == "":
cwd = "."
return self.bld.srcnode.find_node(cwd)
def find_node(self):
name = self.get_fname()
if not name:
return None
return self.bld.srcnode.find_node(name)
def make_node(self):
name = self.get_fname()
if not name:
return None
return self.bld.srcnode.make_node(name.lower())
def get_fname(self):
'''<abstract> Returns file name.'''
return None
def get_content(self):
'''<abstract> Returns file content.'''
return None
def xml_clean(self, content):
s = minidom.parseString(content).toprettyxml(indent="\t")
lines = [l for l in s.splitlines() if not l.isspace() and len(l)]
lines[0] = '<?xml version="1.0" encoding="UTF-8"?>'
return '\n'.join(lines)
class MsDevSolution(MsDev):
'''Class used for exporting *waf* project data to a **Visual Studio**
solution located in the lop level directory of the *waf* build
environment.
:param bld: Build context as used in *wscript* files of your *waf* build
environment.
:type bld: waflib.Build.BuildContext
'''
def __init__(self, bld):
super(MsDevSolution, self).__init__(bld)
self.projects = {}
self.xml_clean = None
def get_fname(self):
'''Returns the workspace's file name.'''
return '%s.sln' % getattr(Context.g_module, Context.APPNAME)
def export(self):
'''Exports a **Visual Studio** solution.'''
dst = self.get_fname()
s = MSDEV_SOLUTION
with open(dst, 'w') as f:
for line in s[0:3]:
f.write(line)
for name, (fname, deps, pid) in self.projects.items():
sid = str(uuid.uuid4()).upper()
f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' % (sid, name, fname, pid))
if len(deps):
f.write('\tProjectSection(ProjectDependencies) = postProject\n')
for d in deps:
try:
(_, _, pid) = self.projects[d]
except KeyError:
pass
else:
f.write('\t\t{%s} = {%s}\n' % (pid, pid))
f.write('\tEndProjectSection\n')
f.write('EndProject\n')
for line in s[3:8]:
f.write(line)
for _, (_, _, pid) in self.projects.items():
f.write('\t\t{%s}.Debug|Win32.ActiveCfg = Debug|Win32\n' % (pid))
f.write('\t\t{%s}.Debug|Win32.Build.0 = Debug|Win32\n' % (pid))
for line in s[8:]:
f.write(line)
Logs.pprint('YELLOW', 'exported: %s' % os.path.abspath(dst))
def add_project(self, name, fname, deps, pid):
'''Adds a project to the workspace.
:param name: Name of the project.
:type name: str
:param fname: Complete path to the project file
:type fname: str
:param deps: List of names on which this project depends
:type deps: list of str
'''
self.projects[name] = (fname, deps, pid)
class MsDevProject(MsDev):
'''Class used for exporting *waf* project data to **Visual Studio**
projects.
:param bld: Build context as used in *wscript* files of your *waf* build
environment.
:type bld: waflib.Build.BuildContext
:param gen: Task generator that contains all information of the task to be
converted and exported to the **Visual Studio** project.
:type gen: waflib.Task.TaskGen
'''
def __init__(self, bld, gen):
super(MsDevProject, self).__init__(bld)
self.gen = gen
self.id = str(uuid.uuid4()).upper()
self.type = self.get_type(gen)
self.language = self.get_language(gen)
self.buildpath = self.get_buildpath(bld, gen)
def get_type(self, gen):
if set(('cprogram', 'cxxprogram')) & set(gen.features):
return MsDev.PROGRAM
elif set(('cshlib', 'cxxshlib')) & set(gen.features):
return MsDev.SHLIB
else:
return MsDev.STLIB
def get_language(self, gen):
return MsDev.CXX if 'cxx' in gen.features else MsDev.C
def get_buildpath(self, bld, gen):
pth = '%s/%s' % (bld.path.get_bld().path_from(gen.path), gen.path.relpath())
return pth.replace('/', '\\')
def get_fname(self):
'''Returns the project's file name.'''
return '%s/%s.vcproj' % (self.gen.path.relpath().replace('\\', '/'), self.gen.get_name())
def get_root(self):
'''Returns a document root, either from an existing file, or from template.'''
fname = self.get_fname()
if os.path.exists(fname):
tree = ElementTree.parse(fname)
root = tree.getroot()
else:
root = ElementTree.fromstring(MSDEV_PROJECT)
return root
def get_content(self):
'''Returns the content of a project file.'''
root = self.get_root()
root.set('Name', self.gen.get_name())
root.set('ProjectGUID', '{%s}' % self.id)
configurations = root.find('Configurations')
for configuration in configurations.iter('Configuration'):
configuration.set('ConfigurationType', '%s' % self.type)
configuration.set('OutputDirectory', '%s\\msdev' % self.buildpath)
configuration.set('IntermediateDirectory', '%s\\msdev' % self.buildpath)
for tool in configuration.iter('Tool'):
name = tool.get('Name')
if name == 'VCCLCompilerTool':
tool.set('PreprocessorDefinitions', '%s' % self.get_compiler_defines(self.gen))
includes = []
for include in self.get_compiler_includes(self.bld, self.gen):
includes.append('%s' % include)
tool.set('AdditionalIncludeDirectories', ';'.join(includes))
if name == 'VCLinkerTool':
if self.type == MsDev.PROGRAM:
# Force Windows Subsystem
# TODO: this isn't enables Windows XP compatibility!
tool.set('SubSystem', '2')
self.update_link_deps(tool)
self.update_link_paths(tool)
files = root.find('Files')
self.update_includes(files)
self.update_sources(files)
return ElementTree.tostring(root)
def update_includes(self, files):
'''Add include files.'''
includes = []
for filtr in files.iter('Filter'):
if filtr.get('Name') == 'Header Files':
for include in filtr.iter('File'):
includes.append(include.get('RelativePath'))
break
if len(includes) == 0:
filtr = ElementTree.SubElement(files, 'Filter', attrib={'Name':'Header Files', 'Filter':'h;hpp;hxx;hm;inl;inc;xsd'})
filtr.set('UniqueIdentifier', '{%s}' % str(uuid.uuid4()).upper())
for include in self.get_include_files(self.bld, self.gen):
if include not in includes:
ElementTree.SubElement(filtr, 'File', attrib={'RelativePath':'%s' % include})
def update_sources(self, files):
'''Add source files.'''
sources = []
for filtr in files.iter('Filter'):
if filtr.get('Name') == 'Source Files':
for source in filtr.iter('File'):
sources.append(source.get('RelativePath'))
break
if len(sources) == 0:
filtr = ElementTree.SubElement(files, 'Filter', attrib={'Name':'Source Files', 'Filter':'cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx'})
filtr.set('UniqueIdentifier', '{%s}' % str(uuid.uuid4()).upper())
for source in self.get_genlist(self.gen, 'source'):
if source not in sources:
ElementTree.SubElement(filtr, 'File', attrib={'RelativePath':'%s' % source})
def update_link_deps(self, tool):
'''Add libraries on which this project depends.'''
deps = tool.get('AdditionalDependencies')
deps = [] # clean out deps everytime
libs = self.get_link_libs(self.bld, self.gen)
for lib in libs:
dep = '%s.lib' % lib
if dep not in deps:
deps.append(dep)
if len(deps):
add_deps = " ".join(deps) # work around when converting to vcxproj by inserting spaces
tool.set('AdditionalDependencies', add_deps)
def update_link_paths(self, tool):
deps = tool.get('AdditionalLibraryDirectories', '')
deps = []
dirs = self.get_link_paths(self.bld, self.gen)
for dep in dirs:
if dep not in deps:
deps.append(dep)
if len(deps):
tool.set('AdditionalLibraryDirectories', ';'.join(deps))
def get_metadata(self):
'''Returns a tuple containing project information (name, file name and
dependencies).
'''
name = self.gen.get_name()
fname = self.get_fname().replace('/', '\\')
deps = Utils.to_list(getattr(self.gen, 'use', []))
return (name, fname, deps, self.id)
def get_genlist(self, gen, name):
lst = Utils.to_list(getattr(gen, name, []))
lst = [str(l.path_from(gen.path)) if hasattr(l, 'path_from') else l for l in lst]
return [l.replace('/', '\\') for l in lst]
def get_compiler_options(self, bld, gen):
if self.language == MsDev.CXX:
flags = getattr(gen, 'cxxflags', []) + bld.env.CXXFLAGS
else:
flags = getattr(gen, 'cflags', []) + bld.env.CFLAGS
if self.type == MsDev.SHLIB:
if self.language == MsDev.CXX:
flags.extend(bld.env.CXXFLAGS_cxxshlib)
else:
flags.extend(bld.env.CFLAGS_cshlib)
return list(set(flags))
def get_compiler_includes(self, bld, gen):
includes = self.get_genlist(gen, 'includes')
for include in bld.env['INCLUDES']:
root = bld.path.abspath().replace('\\', '/')
pref = os.path.commonprefix([root, include])
if pref == root:
node = bld.root.find_dir(include)
if node:
includes.append(node.path_from(gen.path).replace('/', '\\'))
deps = Utils.to_list(getattr(gen, 'use', []))
for dep in deps:
uselib_incs = bld.env['INCLUDES_%s' % dep]
for uselib_inc in uselib_incs:
root = bld.root.abspath().replace('\\', '/')
pref = os.path.commonprefix([root, uselib_inc])
if pref == root:
node = bld.root.find_dir(uselib_inc)
if node:
inc = node.path_from(gen.path).replace('/', '\\')
includes.append(inc)
Logs.pprint('YELLOW', 'Added relative include: %s' % inc)
includes.append(uselib_inc)
return includes
def get_compiler_defines(self, gen):
defines = self.get_genlist(gen, 'defines') + gen.bld.env.DEFINES
if 'win32' in sys.platform:
defines = [d.replace('"', '\\"') for d in defines]
defines = ';'.join(defines)
return defines
def get_link_options(self, bld, gen):
flags = getattr(gen, 'linkflags', []) + bld.env.LINKFLAGS
if self.language == MsDev.CXX:
if self.type == MsDev.SHLIB:
flags.extend(bld.env.LINKFLAGS_cxxshlib)
else:
flags.extend(bld.env.LINKFLAGS_cshlib)
return list(set(flags))
def get_link_libs(self, bld, gen):
libs = Utils.to_list(getattr(gen, 'lib', []))
deps = Utils.to_list(getattr(gen, 'use', []))
for dep in deps:
try:
tgen = bld.get_tgen_by_name(dep)
except Errors.WafError:
uselib_libs = bld.env['LIB_%s' % dep]
for uselib_lib in uselib_libs:
libs.append(uselib_lib)
pass
else:
if self.type == MsDev.STLIB:
libs.append(dep)
return libs
def get_link_paths(self, bld, gen):
dirs = []
deps = Utils.to_list(getattr(gen, 'use', []))
for dep in deps:
try:
tgen = bld.get_tgen_by_name(dep)
except Errors.WafError:
uselib_paths = bld.env['LIBPATH_%s' % dep]
for uselib_path in uselib_paths:
root = bld.root.abspath().replace('\\', '/')
pref = os.path.commonprefix([root, uselib_path])
if pref == root:
node = bld.root.find_dir(uselib_path)
if node:
libpath = node.path_from(gen.path).replace('/', '\\')
dirs.append(libpath)
Logs.pprint('YELLOW', 'Added relative library path: %s' % libpath)
dirs.append(uselib_path)
pass
else:
if self.type in (MsDev.STLIB, MsDev.SHLIB):
directory = '%s\\msdev' % tgen.path.get_bld().path_from(gen.path)
if directory not in dirs:
dirs.append(directory.replace('/', '\\'))
elif self.type in (MsDev.PROGRAM):
for directory in tgen.lib_paths:
if directory not in dirs:
dirs.append(directory.replace('/', '\\'))
return dirs
def get_include_files(self, bld, gen):
includes = []
for include in self.get_genlist(gen, 'includes'):
node = gen.path.find_dir(include)
if node:
for header in node.ant_glob('*.h*'):
includes.append(header.path_from(gen.path).replace('/', '\\'))
for include in bld.env['INCLUDES']:
root = bld.path.abspath().replace('\\', '/')
pref = os.path.commonprefix([root, include])
if pref == root:
node = bld.root.find_dir(include)
if node:
for header in node.ant_glob('*.h*'):
includes.append(header.path_from(gen.path).replace('/', '\\'))
return includes
MSDEV_PROJECT = \
'''<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name=""
ProjectGUID=""
Keyword="Win32Proj"
TargetFrameworkVersion="0"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions=""
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
'''
MSDEV_SOLUTION = [
'Microsoft Visual Studio Solution File, Format Version 8.00\n',
'# Visual Studio 2005\n',
'Global\n',
'GlobalSection(SolutionConfigurationPlatforms) = preSolution\n',
'Debug|Win32 = Debug|Win32\n',
'EndGlobalSection\n',
'GlobalSection(ProjectConfigurationPlatforms) = postSolution\n',
'EndGlobalSection\n',
'GlobalSection(SolutionProperties) = preSolution\n',
'HideSolutionNode = FALSE\n',
'EndGlobalSection\n',
'EndGlobal\n',
'\n']

View File

@ -0,0 +1,47 @@
#!/usr/bin/env python
# encoding: utf-8
# Copyright (c) 2019 mittorn
'''
Reconfigure
Store/load configuration user input
Usage:
def options(opt):
opt.load('reconfigure')
def configure(conf):
conf.load('reconfigure')
./waf configure --reconfigure
'''
from waflib import Configure, Logs, Options, Utils, ConfigSet
import os
import optparse
STORE_PATH = 'build/configuration.py'
def options(opt):
opt.add_option('--rebuild-cache', dest='rebuild_cache', default=False, action='store_true', help='load previous configuration')
opt.add_option('--reconfigure', dest='reconfigure', default=False, action='store_true', help='load and update configuration')
def configure(conf):
store_data = ConfigSet.ConfigSet()
options = vars(conf.options)
environ = conf.environ
if conf.options.reconfigure or conf.options.rebuild_cache:
store_data.load(STORE_PATH)
if conf.options.reconfigure:
for o in options:
if options[o]: store_data['OPTIONS'][o] = options[o]
store_data['ENVIRON'].update(environ)
store_data.store(STORE_PATH)
conf.environ = store_data['ENVIRON']
conf.options = optparse.Values(store_data['OPTIONS'])
else:
store_data['OPTIONS'] = vars(conf.options)
store_data['ENVIRON'] = conf.environ
store_data.store(STORE_PATH)

208
scripts/waflib/xcompile.py Normal file
View File

@ -0,0 +1,208 @@
# 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.
from fwgslib import get_flags_by_compiler
import os
import sys
# Output:
# CROSSCOMPILING -- set to true, if crosscompiling is enabled
# DEST_OS2 -- as some operating systems is built on top of another, it's better to not change DEST_OS,
# instead of this DEST_OS2 is defined with target value
# For example: android is built on top of linux and have many things in common,
# but it can't be considered as default GNU/Linux.
# Possible values:
# DEST_OS2 DEST_OS
# 'android' 'linux'
class Android:
arch = None
toolchain = None
api = None
toolchain_path = None
ndk_home = None
# TODO: New Android NDK support?
# TODO: Crystax support?
# TODO: Support for everything else than linux-x86_64?
# TODO: Determine if I actually need to implement listed above
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.startswith('x86')
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.toolchain.startswith('clang')
def is_hardfp(self):
return self.arch.endswith('-hard')
def gen_toolchain_path(self):
path = 'toolchains'
if self.is_clang():
raise Exception('Clang is not supported yet')
else:
if self.is_x86():
toolchain_folder = self.arch + '-' + self.toolchain
elif self.is_arm():
toolchain_folder = 'arm-linux-androideabi-' + self.toolchain
else:
toolchain_folder = self.arch + '-linux-android-' + self.toolchain
if sys.platform.startswith('linux'):
toolchain_host = 'linux'
elif sys.platform.startswith('darwin'):
toolchain_host = 'darwin'
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
toolchain_host = 'windows'
else: raise Exception('Unsupported by NDK host platform')
toolchain_host += '-'
# Assuming we are building on x86
if sys.maxsize > 2**32:
toolchain_host += 'x86_64'
else: toolchain_host += 'x86'
if self.arch == 'x86':
triplet = 'i686-linux-android-'
elif self.is_arm():
triplet = 'arm-linux-androideabi-'
else:
triplet = self.arch + '-linux-android-'
return os.path.join(path, toolchain_folder, 'prebuilt', toolchain_host, 'bin', triplet)
def cc(self):
return os.path.abspath(os.path.join(self.ndk_home, self.toolchain_path + 'gcc'))
def cxx(self):
return os.path.abspath(os.path.join(self.ndk_home, self.toolchain_path + 'g++'))
def system_stl(self):
# TODO: proper STL support
return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'system', 'include'))
def sysroot(self):
arch = self.arch
if self.is_arm():
arch = 'arm'
elif self.is_arm64():
arch = 'arm64'
path = 'platforms/android-{0}/arch-{1}'.format(self.api, arch)
return os.path.abspath(os.path.join(self.ndk_home, path))
def cflags(self):
cflags = ['--sysroot={0}'.format(self.sysroot()), '-DANDROID', '-D__ANDROID__']
cflags += ['-I{0}'.format(self.system_stl())]
if self.is_arm():
if self.arch.startswith('armeabi-v7a'):
# ARMv7 support
cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9', '-mvectorize-with-neon-quad', '-DHAVE_EFFICIENT_UNALIGNED_ACCESS', '-DVECTORIZE_SINCOS']
if self.arch == 'armeabi-v7a-hard':
cflags += ['-D_NDK_MATH_NO_SOFTFP=1', '-mhard-float', '-mfloat-abi=hard', '-DLOAD_HARDFP', '-DSOFTFP_LINK']
else:
cflags += ['-mfloat-abi=softfp'] # Tegra 2 sucks
else:
# 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
def ldflags(self):
ldflags = ['--sysroot={0}'.format(self.sysroot())]
if self.is_arm():
if self.arch.startswith('armeabi-v7a'):
ldflags += ['-march=armv7-a', '-Wl,--fix-cortex-a8']
if self.arch == 'armeabi-v7a-hard':
ldflags += ['-Wl,--no-warn-mismatch', '-lm_hard']
else:
ldflags += ['-march=armv5te']
return ldflags
def __init__(self, ndk_home, arch, toolchain, api):
self.ndk_home = ndk_home
self.arch = arch
self.toolchain = toolchain
self.api = api
self.toolchain_path = self.gen_toolchain_path()
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:
for i in ['ANDROID_NDK_HOME', 'ANDROID_NDK']:
android_ndk_path = os.getenv(i)
if android_ndk_path != None:
break
if not android_ndk_path:
conf.fatal('Set ANDROID_NDK_HOME environment variable pointing to the root of Android NDK!')
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', 'mipsel', 'mips64el']
if values[0] not in valid_archs:
conf.fatal('Unknown arch: {0}. Supported: {1}'.format(values[0], ', '.join(valid_archs)))
android = Android(android_ndk_path, values[0], values[1], values[2])
conf.options.ALLOW64 = True # skip pointer length check
conf.options.NO_VGUI = True # skip vgui
conf.options.NANOGL = True
conf.options.GLWES = True
conf.options.GL = False
conf.environ['CC'] = android.cc()
conf.environ['CXX'] = android.cxx()
conf.env.CFLAGS += android.cflags()
conf.env.CXXFLAGS += android.cflags()
conf.env.LINKFLAGS += android.ldflags()
conf.env.HAVE_M = True
if android.is_hardfp():
conf.env.LIB_M = ['m_hard']
else: conf.env.LIB_M = ['m']
conf.msg('Selected Android NDK', android_ndk_path)
# 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_path, '$NDK'))
conf.msg('... linker flags', ' '.join(android.ldflags()).replace(android_ndk_path, '$NDK'))
# conf.env.ANDROID_OPTS = android
conf.env.DEST_OS2 = 'android'
# else:
# conf.load('compiler_c compiler_cxx') # Use host compiler :)

170
waf vendored Executable file

File diff suppressed because one or more lines are too long

149
wscript Normal file
View File

@ -0,0 +1,149 @@
#! /usr/bin/env python
# encoding: utf-8
# a1batross, mittorn, 2018
from __future__ import print_function
from waflib import Logs
import sys
import os
sys.path.append(os.path.realpath('scripts/waflib'))
import fwgslib
VERSION = '2.4'
APPNAME = 'hlsdk-xash3d'
top = '.'
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 game dlls')
grp.add_option('--enable-voicemgr', action = 'store_true', dest = 'VOICEMGR', default = False,
help = 'enable voice manager')
grp.add_option('--enable-goldsrc-support', action = 'store_true', dest = 'GOLDSRC', default = False,
help = 'enable GoldSource engine support')
opt.recurse('cl_dll dlls')
opt.load('xcompile compiler_cxx compiler_c')
if sys.platform == 'win32':
opt.load('msvc msdev')
opt.load('reconfigure')
def configure(conf):
# Configuration
conf.env.GAMEDIR = 'valve'
conf.env.CLIENT_DIR = 'cl_dlls'
conf.env.SERVER_DIR = 'dlls'
conf.env.SERVER_NAME = 'hl'
conf.env.PREFIX = ''
conf.load('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 ['fast', 'release', 'debug', 'nooptimize', 'sanitize', 'none']:
conf.end_msg(conf.options.BUILD_TYPE, color='RED')
conf.fatal('Invalid build type. Valid are "debug", "release" or "none"')
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')
conf.env.VOICEMGR = conf.options.VOICEMGR
conf.env.GOLDSRC = conf.options.GOLDSRC
# 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')
# print(conf.options.ALLOW64)
conf.env.BIT32_MANDATORY = not conf.options.ALLOW64
conf.env.BIT32_ALLOW64 = conf.options.ALLOW64
conf.load('force_32bit')
if conf.env.DEST_SIZEOF_VOID_P == 4:
Logs.info('NOTE: will build game dlls for 32-bit target')
else:
Logs.warn('WARNING: 64-bit game dlls may be unstable')
linker_flags = {
'common': {
'msvc': ['/DEBUG'], # always create PDB, doesn't affect result binaries
'gcc': ['-Wl,--no-undefined']
},
'sanitize': {
'gcc': ['-fsanitize=undefined', '-fsanitize=address'],
}
}
compiler_c_cxx_flags = {
'common': {
'msvc': ['/D_USING_V110_SDK71_', '/Zi', '/FS'],
'clang': ['-g', '-gdwarf-2'],
'gcc': ['-g', '-Werror=implicit-function-declaration', '-fdiagnostics-color=always']
},
'fast': {
'msvc': ['/O2', '/Oy'], #todo: check /GL /LTCG
'gcc': ['-Ofast', '-march=native', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer'],
'default': ['-O3']
},
'release': {
'msvc': ['/O2'],
'default': ['-O3']
},
'debug': {
'msvc': ['/O1'],
'gcc': ['-Og'],
'default': ['-O1']
},
'sanitize': {
'msvc': ['/Od', '/RTC1'],
'gcc': ['-Og', '-fsanitize=undefined', '-fsanitize=address'],
'default': ['-O1']
},
'nooptimize': {
'msvc': ['/Od'],
'default': ['-O0']
}
}
conf.env.append_unique('CFLAGS', fwgslib.get_flags_by_type(
compiler_c_cxx_flags, conf.options.BUILD_TYPE, conf.env.COMPILER_CC))
conf.env.append_unique('CXXFLAGS', fwgslib.get_flags_by_type(
compiler_c_cxx_flags, conf.options.BUILD_TYPE, conf.env.COMPILER_CC))
conf.env.append_unique('LINKFLAGS', fwgslib.get_flags_by_type(
linker_flags, conf.options.BUILD_TYPE, conf.env.COMPILER_CC))
if conf.env.COMPILER_CC == 'msvc':
conf.env.append_unique('DEFINES', ['_CRT_SECURE_NO_WARNINGS','_CRT_NONSTDC_NO_DEPRECATE'])
else:
conf.env.append_unique('DEFINES', ['stricmp=strcasecmp','strnicmp=strncasecmp','_LINUX','LINUX','_snprintf=snprintf','_vsnprintf=vsnprintf'])
cflags = ['-fvisibility=hidden','-Wno-write-strings','-fno-exceptions']
conf.env.append_unique('CFLAGS', cflags)
conf.env.append_unique('CXXFLAGS', cflags + ['-Wno-invalid-offsetof'])
conf.env.append_unique('DEFINES', 'CLIENT_WEAPONS')
conf.recurse('cl_dll dlls')
def build(bld):
bld.recurse('cl_dll dlls')