https://wiki.alliedmods.net/api.php?action=feedcontributions&user=WildCard65&feedformat=atomAlliedModders Wiki - User contributions [en]2024-03-28T18:58:48ZUser contributionsMediaWiki 1.31.6https://wiki.alliedmods.net/index.php?title=Building_SourceMod&diff=11036Building SourceMod2020-08-04T01:39:38Z<p>WildCard65: Modernized the dependencies stuff for newer SourceMods/AMBuild</p>
<hr />
<div>Compiling SourceMod is not difficult, but requires a number of prerequisites. This article details the requirements and steps to being able to build working SourceMod binaries.<br />
<br />
Note that specific compiler versions are required to maintain ABI compatibility with Source engine binaries.<br />
<br />
=Requirements=<br />
<br />
==Windows==<br />
<ol><br />
<li>Install Visual Studio or Visual C++. VS/VC 2010 or above is required for SourceMod 1.6.x and earlier. VS/VC 2013 Update 2 or above is required for SourceMod 1.7.x and later (Express editions should work fine). VS/VC 2015 is required for SourceMod 1.10.x or later. If you use 2013 or higher, make sure to get the "Desktop" version: [http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop Visual Studio Express 2013 for Desktop].</li><br />
<ul><br />
<li>With VS/VC 2017, you may use [https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2017 the build tools installer] to install the minimal set of packages. You will want to install the following: .NET 4.6.1 SDK and corrresponding targeting pack, C++/CLI support, VC++2015.3 v14.00 toolset for desktop, Visual C++ Build Tools core features, Windows 8.1 SDK, and Windows Universal C Runtime. When attempting to configure and build, use the "VS2015 x86 Native Tools Command Prompt" Start Menu option to have the build tools available in the current Command Prompt's PATH.<br />
</li><br />
<li>With Build Tools for Visual Studio 2019, you can install the following individual components: MSVC v140 - VS 2015 C++ build tools (v14.00), Windows Universal CRT SDK, and Windows 10 SDK.</li><br />
</ul><br />
<li>Install [http://git-scm.com/ Git]. Make sure that you select the option that adds Git to PATH.</li><br />
<li>Next, you will need to start an environment capable of running Python and interacting with the Visual Studio compiler.<br />
<ul><br />
<li>Install [http://python.org/ Python] 2.7. It will install to C:\Python27 by default. (Version 3.4 will work, but is not recommended for compatibility with other tools).</li><br />
<li>Add Python to your <tt>PATH</tt> variable. Go to Control Panel, System, Advanced, Environment Variables. Add <tt>C:\Python27;C:\Python27\Scripts</tt> to <tt>PATH</tt> (or wherever your Python install is).</li><br />
<li>Under Start, Programs, Microsoft Visual Studio, select the "Visual Studio Tools" folder and run "Visual Studio Command Prompt". Alternately, open a normal command prompt and run <tt>"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\vcvars.bat"</tt>. Substitute your Visual Studio version if needed.</li><br />
</li><br />
</ul><br />
</ol><br />
<br />
==Linux==<br />
<ol><br />
<li>Install Git, via either system packages or from the [http://git-scm.com/ Git] distribution.</li><br />
<li>Install a C++ compiler and dependencies. SourceMod officially supports clang. For example, on Ubuntu/Debian:<br />
<pre><br />
sudo apt-get install clang lib32stdc++-7-dev lib32z1-dev libc6-dev-i386<br />
</pre><br />
</ol><br />
<br />
==Archlinux==<br />
<br />
# Enable multilib repository as described in the [https://wiki.archlinux.org/index.php/multilib Archlinux wiki page].<br />
# Install the following packages:<br />
#:<pre>pacman -S git python2 gcc-multilib lib32-glibc lib32-libstdc++5 lib32-zlib</pre><br />
<br />
==Mac OS X==<br />
Mac OS X 10.7 or higher is required to build, however, SourceMod will work on 10.5. SourceMod will neither build nor run on older PPC Macs.<br />
<br />
<ol><br />
<li>Install the Xcode Command Line Tools.<br />
<ul><br />
<li>For OS X 10.9 or higher, run the command below in Terminal and click the Install button in the window that appears.<br />
<pre><br />
xcode-select --install<br />
</pre><br />
</li><br />
<li>For earlier versions of OS X, download and install Xcode from the App Store. Launch Xcode and then navigate to Preferences -> Downloads -> Components -> Command Line Tools -> Install. If you have recently upgraded Xcode, you will need to perform this step again. SourceMod cannot build without Xcode's command line tools.</li><br />
</ul><br />
</ol><br />
<br />
=Downloading Source and Dependencies=<br />
<br />
First, grab the SourceMod source tree. We recommend placing it inside its own folder, since we'll also need to download its dependencies.<br />
<br />
'''You should do a recursive checkout of the git repo since the sourcepawn repo is a submodule of sourcemod now, see https://stackoverflow.com/questions/3796927/how-to-git-clone-including-submodules to do that.'''<br />
<pre><br />
mkdir -p alliedmodders<br />
cd alliedmodders<br />
git clone --recursive https://github.com/alliedmodders/sourcemod<br />
</pre><br />
<br />
Next, run the <tt>checkout-deps.sh</tt> script. This will download all dependencies and attempt to install AMBuild. If you are using Linux or OS X, it may prompt you for your sudo password at the very end. If you want to skip this and install AMBuild manually, just Ctrl+C. (Do not run the checkout script with sudo.)<br />
<pre><br />
bash sourcemod/tools/checkout-deps.sh<br />
</pre><br />
<br />
After it's done, you should see a large number of hl2sdk folders and other assorted dependencies, like MySQL, Metamod:Source, and AMBuild.<br />
<br />
If you are on Windows, you can use 'checkout-deps' PowerShell script (if it exists), you just may need to swap ExecutionPolicy to a less restrictive one. (See: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies).<br />
<br />
Otherwise, you can manually download the dependencies with the commands below:<br />
<pre><br />
git clone --mirror https://github.com/alliedmodders/hl2sdk hl2sdk-proxy-repo<br />
# For each SDK you want to build with:<br />
# git clone hl2sdk-proxy-repo hl2sdk-<SDK> -b <SDK><br />
# e.g. git clone hl2sdk-proxy-repo hl2sdk-csgo -b csgo<br />
<br />
git clone https://github.com/alliedmodders/metamod-source mmsource-1.10 -b 1.10-dev<br />
<br />
# If building version 1.10 of SourceMod, use MySQL 5.5<br />
wget https://cdn.mysql.com/archives/mysql-5.5/mysql-5.5.54-win32.zip mysql-5.5<br />
<br />
# If building < version 1.10 of SourceMod, use MySQL 5.0<br />
wget https://cdn.mysql.com/archives/mysql-5.0/mysql-noinstall-5.0.24a-win32.zip mysql-5.0<br />
<br />
# Install AMBuild<br />
git clone https://github.com/alliedmodders/ambuild<br />
pip install ./ambuild<br />
</pre><br />
<br />
Note that you can skip MySQL and SDK versions you don't plan to build.<br />
<br />
=Configuring=<br />
<br />
The first time you are building a SourceMod tree, you must ''configure'' the build. This step initializes some basic information and allows some customization around how things get compiled.<br />
<br />
First create a build folder within your sourcemod folder, and then run <tt>configure.py</tt>. For example:<br />
<pre><br />
cd sourcemod<br />
mkdir build<br />
cd build<br />
python ../configure.py<br />
</pre><br />
<br />
It is safe to reconfigure over an old build. However, it's probably a bad idea to configure inside a random, non-empty folder.<br />
<br />
There are a few extra options you can pass to <tt>configure</tt>:<br />
*--enable-debug - Compile with symbols and debug checks/assertions.<br />
*--enable-optimize - Compile with optimizations.<br />
*--no-sse - Disable floating point optimizations (if you have a very, very old CPU).<br />
*--no-mysql - Don't build the MySQL database module.<br />
*--sdks css - Only build css.<br />
<br />
See configure.py for all the options.<br />
<br />
=Building=<br />
<br />
To build SourceMod, simply type:<br />
<pre><br />
ambuild<br />
</pre><br />
<br />
In your build folder. Alternately, you can specify the path of the build folder:<br />
<pre><br />
ambuild debug-build<br />
</pre><br />
<br />
The full package layout that would be shipped for release is in the <tt>package</tt> folder of the build.<br />
<br />
=Deprecated Tools=<br />
==Visual Studio Project Files==<br />
In the future, we will use AMBuild to automatically generate project files, and the existing project files will be removed from the SourceMod tree. In the meantime however, it is possible to use these files. Unfortunately, they require a bit of extra work to use.<br />
<br />
First, make sure you've downloaded all necessary dependencies (SDKs, Metamod:Source source code, and MySQL) via the <tt>checkout-windows-deps.bat</tt> script. Next,<br />
#Open the Control Panel (for example, via Start -> Settings).<br />
#Open the System control. If you don't see it, you may need to switch to "Classic view" (either via the left-hand pane or by going to Tools -> Folder Options).<br />
#Click the Advanced tab.<br />
#Click the Environment Variables button.<br />
<br />
Now, add your environment variables to either your User settings or your System settings. Create a new variable for each item in the list below. You may omit SDKs that you do not plan to build against. The item names are in <tt>fixed-width font</tt> and their value descriptions follow.<br />
*<tt>MMSOURCE19</tt> - Path to Metamod:Source 1.10+<br />
*<tt>MMSOURCE18</tt> - Path to Metamod:Source 1.10+<br />
*<tt>HL2SDK</tt> - Path to HL2SDK Ep1/Original<br />
*<tt>HL2SDKOB</tt> - Path to HL2SDK Ep2/OrangeBox for mods<br />
*<tt>HL2SDKOBVALVE</tt> - Path to HL2SDK Source 2009 (HL2:DM, DoD:S, TF2)<br />
*<tt>HL2SDK-SWARM</tt> - Path to HL2SDK Alien Swarm<br />
*<tt>HL2SDK-BGT</tt> - Path to HL2SDK for Bloody Good Time<br />
*<tt>HL2SDKCSGO</tt> - Path to HL2SDK CS:GO<br />
*<tt>HL2SDKCSS</tt> - Path to HL2SDK CS:S<br />
*<tt>HL2SDK-DARKM</tt> - Path to HL2SDK Dark Messiah<br />
*<tt>HL2SDK-EYE</tt> - Path to HL2SDK E.Y.E.: Divine Cybermancy<br />
*<tt>HL2SDKL4D</tt> - Path to HL2SDK L4D1<br />
*<tt>HL2SDKL4D2</tt> - Path to HL2SDK L4D2<br />
*<tt>HL2SDK-DOTA</tt> - Path to HL2SDK DOTA 2<br />
*<tt>MYSQL5</tt> - Path to the folder that contains MySQL's <tt>include</tt> and <tt>lib</tt> folders.<br />
<br />
==Makefiles==<br />
Makefiles are deprecated and will be removed from the tree soon.<br />
<br />
[[Category:SourceMod Documentation]]<br />
[[Category:SourceMod Development]]</div>WildCard65https://wiki.alliedmods.net/index.php?title=AMBuild&diff=11035AMBuild2020-07-31T23:50:11Z<p>WildCard65: </p>
<hr />
<div>AMBuild is a tool for building software projects and creating release packages. It is targeted at C++ projects, though it can be used for anything. It has been tailored to solve three major problems that most build tools do not address:<br />
*'''Accuracy'''. You should *never* need to clean a build. Clean rebuilds are unnecessary and a waste of your time. AMBuild always computes minimal rebuilds accurately - any failure to do so is considered a bug.<br />
*'''Speed'''. Most build systems need to traverse the entire dependency graph for changes. AMBuild only needs to look at the set of changed files on the filesystem.<br />
*'''Flexibility'''. Build scripts are written in Python, so they're very easy to write and provide full programmatic control.<br />
<br />
Keep in mind, AMBuild is neither widely used nor has it been used on a wide variety of systems. AlliedModders has used it successfully for small to medium-sized C++ projects on Linux, Mac, and Windows. Our largest project, SourceMod, has 700 C++ files and over 200,000 lines of code. We're happy to receive feedback (see the bottom of this page) if you use it in your own projects.<br />
<br />
=Motivation=<br />
<br />
AlliedModders C++ projects require a lot of customization. The set of flags passed to the compiler, their order, how things get linked, is all delicate and complicated. In addition, each Source game requires different linkage, so our C++ files usually get compiled multiple times, over and over again, into separate binaries. Lastly, our projects are large, and minimizing build time through correct dependency computation and parallelization is important. Very few build systems can handle any of these scenarios well, much less all of them, so we sought to make a new build system.<br />
<br />
The initial version of AMBuild only solved flexibility problems. By controlling the build pipeline through Python, we were able to generate 15+ different binaries from the same source files without any code duplication. Over time the AMBuild script syntax has become very simple; you no longer need a complex project to justify AMBuild.<br />
<br />
The modern version of AMBuild (also known as AMBuild 2), is modeled after [http://gittup.org/tup/ Tup]. Tup is a huge advance forward in build systems, and it is likely that one day AMBuild will simply use Tup as a backend. If you are looking at AMBuild as a build platform for your projects, you may want to see whether Tup meets your needs instead.<br />
<br />
=Requirements=<br />
<br />
Python 2.6 or higher is required. If using Python 3, then 3.1 or higher is required. On systems where it is not provided by default (such as FreeBSD), you will also need to install the SQLite module for Python ("py-sqlite").<br />
<br />
PIP and Setuptools are also required, these two packages are technically optional in the Python universe and '''''MAY''''' require manual installation. Some Linux (example: Ubuntu/Debian) platforms provide packages to install pip and setuptools while the Windows Python installer bundles a copy of PIP & Setuptools, otherwise, the generic way is via [https://bootstrap.pypa.io/get-pip.py get-pip.py] with no arguments.<br />
<br />
AMBuild has been tested to work on the following platforms. Although builds of Python for specific architectures were tested, we expect that other architectures will work as well.<br />
* Windows (7 x86 and x64, XP x86)<br />
* Linux (x86 and x64)<br />
* OS X (10.7-10.9)<br />
* FreeBSD (9.2-x64)<br />
* OpenBSD (5.4 amd64, i386)<br />
* Solaris (11, x64)<br />
* Cygwin (x64)<br />
<br />
It has also been tested to work with the following compilers:<br />
* Visual Studio 2010+<br />
* GCC 4+<br />
* Clang 3+<br />
* Emscripten 1.25+ (JS output mode only, lib deps do not work)<br />
<br />
=Installation=<br />
<br />
AMBuild can be downloaded via GitHub at [https://github.com/alliedmodders/ambuild https://github.com/alliedmodders/ambuild].<br />
<br />
<pre><br />
$ git clone https://github.com/alliedmodders/ambuild<br />
$ pip install ./ambuild<br />
</pre><br />
<br />
Note: Administrator privileges are required to install AMBuild for '''''ALL USERS''''', otherwise, pip will install AMBuild at the user level.<br />
<br />
=Tutorial=<br />
<br />
See the [[AMBuild Tutorial]] for more information.<br />
<br />
=API=<br />
<br />
See the [[AMBuild API]] article for more information.<br />
<br />
=Technical Overview=<br />
<br />
AMBuild is separated into a ''frontend'' and a ''backend''. The frontend is responsible for parsing build scripts (this is known as the ''configure'' step). The backend is responsible for actually performing builds. The frontend and backend are separate, and it is possible to use a different backend other than AMBuild. For example, there are plans for the configure step to be able to produce Visual Studio project files.<br />
<br />
== Configuring ==<br />
<br />
Build scripts are written in Python, and they are parsed whenever you configure the build. If a build script changes, it will automatically re-trigger the configure process on the next build. When a configure takes place, any files left by an old build are removed if they are modified or removed in the new dependency graph.<br />
<br />
The details of the generated dependency graph are stored in an SQLite database, which is located in a hidden <tt>.ambuild2</tt> folder inside the build path.<br />
<br />
== Building ==<br />
<br />
The build process involves a few important steps that are executed every time you use the <tt>ambuild</tt> command:<br />
<ol><br />
<li>'''Damage Computation'''. Builds a list of all files that have changed since the last build. This is based on filesystem timestamps, and either a forward or backward time change is enough to be considered "damaged" (or dirty). For example:<br />
<pre><br />
$ ambuild --show-changed<br />
/home/dvander/alliedmodders/mmsource-central/loader/loader.cpp<br />
</pre><br />
</li><br />
<li>'''Partial DAG Construction'''. A partial dependency graph is built based on the list of damaged files. This is the entire set of nodes in the graph which need to be recomputed. The output of this step can be seen with <tt>--show-damage</tt>. For example:<br />
<pre><br />
$ ambuild --show-damage<br />
- package/addons/metamod/bin/server_i486.so<br />
- cp "../loader/server_i486/server_i486.so" "package/addons/metamod/bin/server_i486.so"<br />
- loader/server_i486/server_i486.so<br />
- c++ loader.o gamedll.o serverplugin.o utility.o -m32 -static-libgcc -shared -o server_i486.so<br />
- loader/server_i486/loader.o<br />
- [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
- /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp<br />
</pre><br />
</li><br />
<li>'''Task Construction'''. The partial DAG is simplified into a tree of commands to run. The output of this step can be seen with <tt>--show-commands</tt>. For example:<br />
<pre><br />
$ ambuild --show-commands<br />
- cp "../loader/server_i486/server_i486.so" "package/addons/metamod/bin/server_i486.so"<br />
- c++ loader.o gamedll.o serverplugin.o utility.o -shared -o server_i486.so<br />
- [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
</pre><br />
</li><br />
<li>'''Updating'''. Each task in the task tree is executed and the results are processed to either reject the build, or update the state of the dependency graph. At this phase, tasks are executed in parallel based on the number of CPU cores available. The task graph is also shared to maximize throughput. You can see the sequential build steps with <tt>--show-steps</tt>:<br />
<pre><br />
$ ambuild --show-steps<br />
task 0: [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
-> loader/server/loader.o<br />
task 1: c++ loader.o gamedll.o serverplugin.o utility.o -m32 -static-libgcc -shared -o server.so<br />
-> loader/server/server.so<br />
task 2: cp "../loader/server/server.so" "package/addons/metamod/bin/server.so"<br />
-> package/addons/metamod/bin/server.so<br />
</pre><br />
Maximizing throughput in Python is tricky since it has limited capability for IPC and multithreading. AMBuild spawns worker processes based on the number of CPUs available, which run task jobs and return the results.<br />
</li><br />
</ol><br />
<br />
=Comparisons=<br />
==Make, Speed==<br />
Make uses a recursive update scheme. Starting with the top-level rule, Make will recursively search all dependencies to find outdated rules, and it will update all rules as it unwinds. This usually involves touching way more rules than are necessary. Consider the following dependency graph:<br />
<br />
[[Image:RecursiveDepGraph.png]]<br />
<br />
In this graph, <tt>stdint.h</tt> has been modified. Even though it's the only rule that has been changed, Make must visit every single node in the graph to discover that it has changed. Furthermore, it has to visit it multiple times: once for <tt>main.o</tt>, and another time for <tt>helpers.o</tt>. In a large dependency graph, this is very expensive.<br />
<br />
In AMBuild, the direction of the graph is reversed:<br />
<br />
[[Image:AMDepGraph.png]]<br />
<br />
With this graph, it is possible to visit every node once. Once we know that <tt>stdint.h</tt> has changed, we can follow the edges upward and ignore everything in the graph that is unaffected:<br />
<br />
[[Image:AMPartialDepGraph.png]]<br />
<br />
==Make, Accuracy==<br />
AMBuild strives to be accurate by design, in two ways:<br />
* Computation of dependencies should be as minimally accurate as possible. Changing a build script should not result in a complete rebuild.<br />
* An incremental build should be exactly the same as a fresh build.<br />
<br />
It is difficult to achieve very accurate rebuilds in Make. For example, consider a Makefile that lists source files and CFLAGS, and invokes the C++ compiler to build and link them:<br />
<pre><br />
# Makefile<br />
CFLAGS = -Wall<br />
<br />
helpers.o: helpers.cpp<br />
$(CC) $(CFLAGS) helpers.cpp -c -o helpers.o<br />
main.o: main.cpp<br />
$(CC) $(CFLAGS) main.cpp -c -o main.o<br />
<br />
main: main.o helpers.o<br />
$(CC) main.o helpers.o -o main<br />
</pre><br />
<br />
If you change <tt>helpers.cpp</tt>, you will get a minimal rebuild. If you add a new source file, you will likely get a minimal rebuild. However, if you ''remove the <tt>helpers</tt> rule completely'', the build will be incorrect, because <tt>Make</tt> cannot tell that <tt>main</tt> needs to be relinked.<br />
<br />
One way to solve this is to have certain rules, like the link rule, have a dependency on <tt>Makefile</tt> itself. But then if you change <tt>CFLAGS</tt>, it will trigger a relink, even though that rule does not depend on <tt>CFLAGS</tt>. You would need to break the Makefile down into many smaller Makefiles.<br />
<br />
AMBuild mitigates these problems by intelligently updating the dependency graph. If a reparse of the build scripts produces identical nodes, it will not consider those nodes as stale.<br />
<br />
Furthermore, when deleting rules, Make will leave their outputs behind. The author is not aware of an easy way to solve this. Leaving old outputs behind is undesirable for a number of reasons. Stale outputs might fool a user or developer tool into thinking the build has succeeded, when in fact it has failed. Stale outputs might be loaded accidentally, i.e. <tt>LD_LIBRARY_PATH</tt> picking up a library that should not exist. Tests that developers forgot to update might pass locally because of a stale output.<br />
<br />
In AMBuild, leaving stale files behind is an error, since they would not be produced by a fresh build.<br />
<br />
==Tup==<br />
AMBuild is designed to be, essentially, a miniature clone of Tup written entirely in Python. In particular it closely follows concepts in [http://gittup.org/tup/build_system_rules_and_algorithms.pdf the Tup whitepaper]. However there are a few differences that may make one more desirable over the other:<br />
* Tup has been around longer than AMBuild 2, and has been more thoroughly tested. <br />
* Tup uses complex file system features to optimize updates. Algorithms that are O(n) in AMBuild tend to be O(1) in Tup.<br />
* AMBuild only requires a default Python installation to work. Tup, due to being written in C and using very platform specific file system features, may not be as accessible.<br />
* Tup has more features for speeding up very large projects. It can do minimal reparsing and it can reduce the number of links in large graphs.<br />
* AMBuild is designed to be a front-end in addition to a back-end. It has a simple API and script syntax, and is designed to support multiple output formats. For example, it could conceivably generate Visual Studio or XCode project files.<br />
<br />
Since AMBuild is also a frontend, AMBuild may one day eliminate its backend in favor of emitting Tupfiles instead.<br />
<br />
AMBuild's IPC implementation is very low-level, and it has not yet been ported beyond Windows, Mac/BSD, or Linux. However it's not difficult to port to Unix-like systems, and if needed a generic (albeit suboptimal) cross-platform implementation could be provided.</div>WildCard65https://wiki.alliedmods.net/index.php?title=AMBuild&diff=11034AMBuild2020-07-31T23:49:28Z<p>WildCard65: </p>
<hr />
<div>AMBuild is a tool for building software projects and creating release packages. It is targeted at C++ projects, though it can be used for anything. It has been tailored to solve three major problems that most build tools do not address:<br />
*'''Accuracy'''. You should *never* need to clean a build. Clean rebuilds are unnecessary and a waste of your time. AMBuild always computes minimal rebuilds accurately - any failure to do so is considered a bug.<br />
*'''Speed'''. Most build systems need to traverse the entire dependency graph for changes. AMBuild only needs to look at the set of changed files on the filesystem.<br />
*'''Flexibility'''. Build scripts are written in Python, so they're very easy to write and provide full programmatic control.<br />
<br />
Keep in mind, AMBuild is neither widely used nor has it been used on a wide variety of systems. AlliedModders has used it successfully for small to medium-sized C++ projects on Linux, Mac, and Windows. Our largest project, SourceMod, has 700 C++ files and over 200,000 lines of code. We're happy to receive feedback (see the bottom of this page) if you use it in your own projects.<br />
<br />
=Motivation=<br />
<br />
AlliedModders C++ projects require a lot of customization. The set of flags passed to the compiler, their order, how things get linked, is all delicate and complicated. In addition, each Source game requires different linkage, so our C++ files usually get compiled multiple times, over and over again, into separate binaries. Lastly, our projects are large, and minimizing build time through correct dependency computation and parallelization is important. Very few build systems can handle any of these scenarios well, much less all of them, so we sought to make a new build system.<br />
<br />
The initial version of AMBuild only solved flexibility problems. By controlling the build pipeline through Python, we were able to generate 15+ different binaries from the same source files without any code duplication. Over time the AMBuild script syntax has become very simple; you no longer need a complex project to justify AMBuild.<br />
<br />
The modern version of AMBuild (also known as AMBuild 2), is modeled after [http://gittup.org/tup/ Tup]. Tup is a huge advance forward in build systems, and it is likely that one day AMBuild will simply use Tup as a backend. If you are looking at AMBuild as a build platform for your projects, you may want to see whether Tup meets your needs instead.<br />
<br />
=Requirements=<br />
<br />
Python 2.6 or higher is required. If using Python 3, then 3.1 or higher is required. On systems where it is not provided by default (such as FreeBSD), you will also need to install the SQLite module for Python ("py-sqlite").<br />
<br />
PIP and Setuptools are also required, these two packages are technically optional in the Python universe and '''''MAY''''' require manual installation. Some Linux (example: Ubuntu/Debian) platforms provide packages to install pip and setuptools while the Windows installer bundles a copy of PIP, otherwise, the generic way is via [https://bootstrap.pypa.io/get-pip.py get-pip.py] with no arguments.<br />
<br />
AMBuild has been tested to work on the following platforms. Although builds of Python for specific architectures were tested, we expect that other architectures will work as well.<br />
* Windows (7 x86 and x64, XP x86)<br />
* Linux (x86 and x64)<br />
* OS X (10.7-10.9)<br />
* FreeBSD (9.2-x64)<br />
* OpenBSD (5.4 amd64, i386)<br />
* Solaris (11, x64)<br />
* Cygwin (x64)<br />
<br />
It has also been tested to work with the following compilers:<br />
* Visual Studio 2010+<br />
* GCC 4+<br />
* Clang 3+<br />
* Emscripten 1.25+ (JS output mode only, lib deps do not work)<br />
<br />
=Installation=<br />
<br />
AMBuild can be downloaded via GitHub at [https://github.com/alliedmodders/ambuild https://github.com/alliedmodders/ambuild].<br />
<br />
<pre><br />
$ git clone https://github.com/alliedmodders/ambuild<br />
$ pip install ./ambuild<br />
</pre><br />
<br />
Note: Administrator privileges are required to install AMBuild for '''''ALL USERS''''', otherwise, pip will install AMBuild at the user level.<br />
<br />
=Tutorial=<br />
<br />
See the [[AMBuild Tutorial]] for more information.<br />
<br />
=API=<br />
<br />
See the [[AMBuild API]] article for more information.<br />
<br />
=Technical Overview=<br />
<br />
AMBuild is separated into a ''frontend'' and a ''backend''. The frontend is responsible for parsing build scripts (this is known as the ''configure'' step). The backend is responsible for actually performing builds. The frontend and backend are separate, and it is possible to use a different backend other than AMBuild. For example, there are plans for the configure step to be able to produce Visual Studio project files.<br />
<br />
== Configuring ==<br />
<br />
Build scripts are written in Python, and they are parsed whenever you configure the build. If a build script changes, it will automatically re-trigger the configure process on the next build. When a configure takes place, any files left by an old build are removed if they are modified or removed in the new dependency graph.<br />
<br />
The details of the generated dependency graph are stored in an SQLite database, which is located in a hidden <tt>.ambuild2</tt> folder inside the build path.<br />
<br />
== Building ==<br />
<br />
The build process involves a few important steps that are executed every time you use the <tt>ambuild</tt> command:<br />
<ol><br />
<li>'''Damage Computation'''. Builds a list of all files that have changed since the last build. This is based on filesystem timestamps, and either a forward or backward time change is enough to be considered "damaged" (or dirty). For example:<br />
<pre><br />
$ ambuild --show-changed<br />
/home/dvander/alliedmodders/mmsource-central/loader/loader.cpp<br />
</pre><br />
</li><br />
<li>'''Partial DAG Construction'''. A partial dependency graph is built based on the list of damaged files. This is the entire set of nodes in the graph which need to be recomputed. The output of this step can be seen with <tt>--show-damage</tt>. For example:<br />
<pre><br />
$ ambuild --show-damage<br />
- package/addons/metamod/bin/server_i486.so<br />
- cp "../loader/server_i486/server_i486.so" "package/addons/metamod/bin/server_i486.so"<br />
- loader/server_i486/server_i486.so<br />
- c++ loader.o gamedll.o serverplugin.o utility.o -m32 -static-libgcc -shared -o server_i486.so<br />
- loader/server_i486/loader.o<br />
- [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
- /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp<br />
</pre><br />
</li><br />
<li>'''Task Construction'''. The partial DAG is simplified into a tree of commands to run. The output of this step can be seen with <tt>--show-commands</tt>. For example:<br />
<pre><br />
$ ambuild --show-commands<br />
- cp "../loader/server_i486/server_i486.so" "package/addons/metamod/bin/server_i486.so"<br />
- c++ loader.o gamedll.o serverplugin.o utility.o -shared -o server_i486.so<br />
- [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
</pre><br />
</li><br />
<li>'''Updating'''. Each task in the task tree is executed and the results are processed to either reject the build, or update the state of the dependency graph. At this phase, tasks are executed in parallel based on the number of CPU cores available. The task graph is also shared to maximize throughput. You can see the sequential build steps with <tt>--show-steps</tt>:<br />
<pre><br />
$ ambuild --show-steps<br />
task 0: [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
-> loader/server/loader.o<br />
task 1: c++ loader.o gamedll.o serverplugin.o utility.o -m32 -static-libgcc -shared -o server.so<br />
-> loader/server/server.so<br />
task 2: cp "../loader/server/server.so" "package/addons/metamod/bin/server.so"<br />
-> package/addons/metamod/bin/server.so<br />
</pre><br />
Maximizing throughput in Python is tricky since it has limited capability for IPC and multithreading. AMBuild spawns worker processes based on the number of CPUs available, which run task jobs and return the results.<br />
</li><br />
</ol><br />
<br />
=Comparisons=<br />
==Make, Speed==<br />
Make uses a recursive update scheme. Starting with the top-level rule, Make will recursively search all dependencies to find outdated rules, and it will update all rules as it unwinds. This usually involves touching way more rules than are necessary. Consider the following dependency graph:<br />
<br />
[[Image:RecursiveDepGraph.png]]<br />
<br />
In this graph, <tt>stdint.h</tt> has been modified. Even though it's the only rule that has been changed, Make must visit every single node in the graph to discover that it has changed. Furthermore, it has to visit it multiple times: once for <tt>main.o</tt>, and another time for <tt>helpers.o</tt>. In a large dependency graph, this is very expensive.<br />
<br />
In AMBuild, the direction of the graph is reversed:<br />
<br />
[[Image:AMDepGraph.png]]<br />
<br />
With this graph, it is possible to visit every node once. Once we know that <tt>stdint.h</tt> has changed, we can follow the edges upward and ignore everything in the graph that is unaffected:<br />
<br />
[[Image:AMPartialDepGraph.png]]<br />
<br />
==Make, Accuracy==<br />
AMBuild strives to be accurate by design, in two ways:<br />
* Computation of dependencies should be as minimally accurate as possible. Changing a build script should not result in a complete rebuild.<br />
* An incremental build should be exactly the same as a fresh build.<br />
<br />
It is difficult to achieve very accurate rebuilds in Make. For example, consider a Makefile that lists source files and CFLAGS, and invokes the C++ compiler to build and link them:<br />
<pre><br />
# Makefile<br />
CFLAGS = -Wall<br />
<br />
helpers.o: helpers.cpp<br />
$(CC) $(CFLAGS) helpers.cpp -c -o helpers.o<br />
main.o: main.cpp<br />
$(CC) $(CFLAGS) main.cpp -c -o main.o<br />
<br />
main: main.o helpers.o<br />
$(CC) main.o helpers.o -o main<br />
</pre><br />
<br />
If you change <tt>helpers.cpp</tt>, you will get a minimal rebuild. If you add a new source file, you will likely get a minimal rebuild. However, if you ''remove the <tt>helpers</tt> rule completely'', the build will be incorrect, because <tt>Make</tt> cannot tell that <tt>main</tt> needs to be relinked.<br />
<br />
One way to solve this is to have certain rules, like the link rule, have a dependency on <tt>Makefile</tt> itself. But then if you change <tt>CFLAGS</tt>, it will trigger a relink, even though that rule does not depend on <tt>CFLAGS</tt>. You would need to break the Makefile down into many smaller Makefiles.<br />
<br />
AMBuild mitigates these problems by intelligently updating the dependency graph. If a reparse of the build scripts produces identical nodes, it will not consider those nodes as stale.<br />
<br />
Furthermore, when deleting rules, Make will leave their outputs behind. The author is not aware of an easy way to solve this. Leaving old outputs behind is undesirable for a number of reasons. Stale outputs might fool a user or developer tool into thinking the build has succeeded, when in fact it has failed. Stale outputs might be loaded accidentally, i.e. <tt>LD_LIBRARY_PATH</tt> picking up a library that should not exist. Tests that developers forgot to update might pass locally because of a stale output.<br />
<br />
In AMBuild, leaving stale files behind is an error, since they would not be produced by a fresh build.<br />
<br />
==Tup==<br />
AMBuild is designed to be, essentially, a miniature clone of Tup written entirely in Python. In particular it closely follows concepts in [http://gittup.org/tup/build_system_rules_and_algorithms.pdf the Tup whitepaper]. However there are a few differences that may make one more desirable over the other:<br />
* Tup has been around longer than AMBuild 2, and has been more thoroughly tested. <br />
* Tup uses complex file system features to optimize updates. Algorithms that are O(n) in AMBuild tend to be O(1) in Tup.<br />
* AMBuild only requires a default Python installation to work. Tup, due to being written in C and using very platform specific file system features, may not be as accessible.<br />
* Tup has more features for speeding up very large projects. It can do minimal reparsing and it can reduce the number of links in large graphs.<br />
* AMBuild is designed to be a front-end in addition to a back-end. It has a simple API and script syntax, and is designed to support multiple output formats. For example, it could conceivably generate Visual Studio or XCode project files.<br />
<br />
Since AMBuild is also a frontend, AMBuild may one day eliminate its backend in favor of emitting Tupfiles instead.<br />
<br />
AMBuild's IPC implementation is very low-level, and it has not yet been ported beyond Windows, Mac/BSD, or Linux. However it's not difficult to port to Unix-like systems, and if needed a generic (albeit suboptimal) cross-platform implementation could be provided.</div>WildCard65https://wiki.alliedmods.net/index.php?title=SDKHooks&diff=11033SDKHooks2020-07-31T23:47:22Z<p>WildCard65: </p>
<hr />
<div>==Introduction==<br />
SDKHooks was previously an external extension to Sourcemod. It was rolled in [https://wiki.alliedmods.net/Sourcemod_1.5.0_API_Changes#SDKHooks Sourcemod 1.5] and it does not need to be manually installed anymore.<br />
<br />
==Hooks==<br />
Some information on various hooks below.<br />
<br />
===SDKHook_OnTakeDamage===<br />
inflictor (3rd argument) is the entity that inflicts the damage. If a player directly damages another, inflictor should be equal to the attacking player id. An example of an indirect damage would be a grenade.<br />
<br />
===SDKHook_OnTakeDamageAlive===<br />
This hook works in a similar way to SDKHook_OnTakeDamage but it gives the [https://bugs.alliedmods.net/show_bug.cgi?id=6249#c7 actual, calculated damage amount done to the player. The pre-hook will fire after an OnTakeDamage pre-hook, and the post-hook will fire before an OnTakeDamage post-hook. The health is subtracted in between pre and post unless the hook is blocked.] {{pr|149}}<br />
<br />
[https://forums.alliedmods.net/showthread.php?p=2309798#post2309798 OnTakeDamageAlive is also only called for players.]<br />
<br />
==Under CSS==<br />
===Non-regular cases for SDKHook_OnTakeDamage===<br />
In the scenario where a player throw a grenade to another player then quickly disconnect, the attacker (2nd argument) will become the inflictor (3rd argument). <br />
<br />
In the scenario where a player fall; the attacker, which is also the inflictor, will be 0 (the world).<br />
<br />
In the scenario where a terrorist plants the bomb, when the bomb explodes, the attacker (2nd argument) will be the same as the inflictor (3rd argument) which will have the Classname "planted_c4".<br />
<br />
===Some damage types===<br />
A normal HEGrenade and the C4 inflict damage of type DMG_BLAST.<br />
<br />
A fall inflicts damage of type DMG_FALL.<br />
<br />
A grenade impact (for instance a flash hitting a teammate) will inflict damage of type DMG_CLUB.<br />
<br />
A normal gun bullet and the knife will inflict damage of type (DMG_BULLET | DMG_NEVERGIB) (non-headshot) or (DMG_BULLET | DMG_NEVERGIB | (1 << 30) ) (headshot).<br />
<br />
A single attack can trigger many SDKHook_OnTakeDamage; when a gun throws pullets for instance (shotgun and glock in burst-mode notably).<br />
<br />
<br />
(Regarding SM/Admin damaged; maybe place this is another section if someone can be sure that this would occur on all mods)<br />
<br />
sm_slap does not trigger SDKHook_OnTakeDamage.<br />
<br />
sm_burn will trigger two different callback : an entity with the classname "entityflame" will deal once 0 damage of type DMG_BURN and once 1 damage of type (DMG_BURN | DMG_DIRECT) every tick.<br />
<br />
===Regarding SDKHook_OnTakeDamage and SDKHook_OnTakeDamageAlive===<br />
<br />
SDKHook_OnTakeDamage/Post is triggered when hitting a teammate with mp_friendlyfire 0 (except in TF2), but not SDKHook_OnTakeDamageAlive.<br />
<br />
==Under TF2==<br />
Under TF2, the SDKHook_OnTakeDamage hook isn't 100% accurate, it's damage parameter is the weapon's base damage. the DMG_CRIT flag is for both crits and minicrits. Weapon spread and minicrit/crit damage is calculated after this call (in SDKHook_OnTakeDamageAlive/Post).<br />
<br />
===Some damage types===<br />
Shotgun = DMG_BUCKSHOT | DMG_SLOWBURN<br />
<br />
Rocket Launcher = DMG_SLOWBURN | DMG_RADIATION | DMG_BLAST<br />
<br />
If a crit, |= DMG_CRIT</div>WildCard65https://wiki.alliedmods.net/index.php?title=SDKHooks&diff=11032SDKHooks2020-07-31T23:46:27Z<p>WildCard65: </p>
<hr />
<div>==Introduction==<br />
SDKHooks was previously an external extension to Sourcemod. It was rolled in [https://wiki.alliedmods.net/Sourcemod_1.5.0_API_Changes#SDKHooks Sourcemod 1.5] and it does not need to be manually installed anymore.<br />
<br />
==Hooks==<br />
Some information on various hooks below.<br />
<br />
===SDKHook_OnTakeDamage===<br />
inflictor (3rd argument) is the entity that inflicts the damage. If a player directly damages another, inflictor should be equal to the attacking player id. An example of an indirect damage would be a grenade.<br />
<br />
===SDKHook_OnTakeDamageAlive===<br />
This hook works in a similar way to SDKHook_OnTakeDamage but it gives the [https://bugs.alliedmods.net/show_bug.cgi?id=6249#c7 actual, calculated damage amount done to the player. The pre-hook will fire after an OnTakeDamage pre-hook, and the post-hook will fire before an OnTakeDamage post-hook. The health is subtracted in between pre and post unless the hook is blocked.] {{pr|149}}<br />
<br />
[https://forums.alliedmods.net/showthread.php?p=2309798#post2309798 OnTakeDamageAlive is also only called for players.]<br />
<br />
==Under CSS==<br />
===Non-regular cases for SDKHook_OnTakeDamage===<br />
In the scenario where a player throw a grenade to another player then quickly disconnect, the attacker (2nd argument) will become the inflictor (3rd argument). <br />
<br />
In the scenario where a player fall; the attacker, which is also the inflictor, will be 0 (the world).<br />
<br />
In the scenario where a terrorist plants the bomb, when the bomb explodes, the attacker (2nd argument) will be the same as the inflictor (3rd argument) which will have the Classname "planted_c4".<br />
<br />
===Some damage types===<br />
A normal HEGrenade and the C4 inflict damage of type DMG_BLAST.<br />
<br />
A fall inflicts damage of type DMG_FALL.<br />
<br />
A grenade impact (for instance a flash hitting a teammate) will inflict damage of type DMG_CLUB.<br />
<br />
A normal gun bullet and the knife will inflict damage of type (DMG_BULLET | DMG_NEVERGIB) (non-headshot) or (DMG_BULLET | DMG_NEVERGIB | (1 << 30) ) (headshot).<br />
<br />
A single attack can trigger many SDKHook_OnTakeDamage; when a gun throws pullets for instance (shotgun and glock in burst-mode notably).<br />
<br />
<br />
(Regarding SM/Admin damaged; maybe place this is another section if someone can be sure that this would occur on all mods)<br />
<br />
sm_slap does not trigger SDKHook_OnTakeDamage.<br />
<br />
sm_burn will trigger two different callback : an entity with the classname "entityflame" will deal once 0 damage of type DMG_BURN and once 1 damage of type (DMG_BURN | DMG_DIRECT) every tick.<br />
<br />
===Regarding SDKHook_OnTakeDamage and SDKHook_OnTakeDamageAlive===<br />
<br />
SDKHook_OnTakeDamage/Post is triggered when hitting a teammate with mp_friendlyfire 0 (except in TF2), but not SDKHook_OnTakeDamageAlive.<br />
<br />
==Under TF2==<br />
Under TF2, the SDKHook_OnTakeDamage hook isn't 100% accurate, it's damage parameter is the weapon's base damage. the DMG_CRIT flag is for both crit and minicrit, spread and minicrit/crit damage is calculated after this call (in SDKHook_OnTakeDamageAlive/Post).<br />
<br />
===Some damage types===<br />
Shotgun = DMG_BUCKSHOT | DMG_SLOWBURN<br />
<br />
Rocket Launcher = DMG_SLOWBURN | DMG_RADIATION | DMG_BLAST<br />
<br />
If a crit, |= DMG_CRIT</div>WildCard65https://wiki.alliedmods.net/index.php?title=AMBuild&diff=11031AMBuild2020-07-31T23:33:46Z<p>WildCard65: Added some more clarifications regarding pip.</p>
<hr />
<div>AMBuild is a tool for building software projects and creating release packages. It is targeted at C++ projects, though it can be used for anything. It has been tailored to solve three major problems that most build tools do not address:<br />
*'''Accuracy'''. You should *never* need to clean a build. Clean rebuilds are unnecessary and a waste of your time. AMBuild always computes minimal rebuilds accurately - any failure to do so is considered a bug.<br />
*'''Speed'''. Most build systems need to traverse the entire dependency graph for changes. AMBuild only needs to look at the set of changed files on the filesystem.<br />
*'''Flexibility'''. Build scripts are written in Python, so they're very easy to write and provide full programmatic control.<br />
<br />
Keep in mind, AMBuild is neither widely used nor has it been used on a wide variety of systems. AlliedModders has used it successfully for small to medium-sized C++ projects on Linux, Mac, and Windows. Our largest project, SourceMod, has 700 C++ files and over 200,000 lines of code. We're happy to receive feedback (see the bottom of this page) if you use it in your own projects.<br />
<br />
=Motivation=<br />
<br />
AlliedModders C++ projects require a lot of customization. The set of flags passed to the compiler, their order, how things get linked, is all delicate and complicated. In addition, each Source game requires different linkage, so our C++ files usually get compiled multiple times, over and over again, into separate binaries. Lastly, our projects are large, and minimizing build time through correct dependency computation and parallelization is important. Very few build systems can handle any of these scenarios well, much less all of them, so we sought to make a new build system.<br />
<br />
The initial version of AMBuild only solved flexibility problems. By controlling the build pipeline through Python, we were able to generate 15+ different binaries from the same source files without any code duplication. Over time the AMBuild script syntax has become very simple; you no longer need a complex project to justify AMBuild.<br />
<br />
The modern version of AMBuild (also known as AMBuild 2), is modeled after [http://gittup.org/tup/ Tup]. Tup is a huge advance forward in build systems, and it is likely that one day AMBuild will simply use Tup as a backend. If you are looking at AMBuild as a build platform for your projects, you may want to see whether Tup meets your needs instead.<br />
<br />
=Requirements=<br />
<br />
Python 2.6 or higher is required. If using Python 3, then 3.1 or higher is required. On systems where it is not provided by default (such as FreeBSD), you will also need to install the SQLite module for Python ("py-sqlite").<br />
<br />
PIP and Setuptools are also required, these two packages are technically optional in the Python universe and '''''MAY''''' require manual installation. Some Linux (example: Ubuntu/Debian) platforms provide packages to install pip and setuptools, otherwise, the generic way is via [https://bootstrap.pypa.io/get-pip.py get-pip.py] with no arguments.<br />
<br />
AMBuild has been tested to work on the following platforms. Although builds of Python for specific architectures were tested, we expect that other architectures will work as well.<br />
* Windows (7 x86 and x64, XP x86)<br />
* Linux (x86 and x64)<br />
* OS X (10.7-10.9)<br />
* FreeBSD (9.2-x64)<br />
* OpenBSD (5.4 amd64, i386)<br />
* Solaris (11, x64)<br />
* Cygwin (x64)<br />
<br />
It has also been tested to work with the following compilers:<br />
* Visual Studio 2010+<br />
* GCC 4+<br />
* Clang 3+<br />
* Emscripten 1.25+ (JS output mode only, lib deps do not work)<br />
<br />
=Installation=<br />
<br />
AMBuild can be downloaded via GitHub at [https://github.com/alliedmodders/ambuild https://github.com/alliedmodders/ambuild].<br />
<br />
<pre><br />
$ git clone https://github.com/alliedmodders/ambuild<br />
$ pip install ./ambuild<br />
</pre><br />
<br />
Note: Administrator privileges are required to install AMBuild for '''''ALL USERS''''', otherwise, pip will install AMBuild at the user level.<br />
<br />
=Tutorial=<br />
<br />
See the [[AMBuild Tutorial]] for more information.<br />
<br />
=API=<br />
<br />
See the [[AMBuild API]] article for more information.<br />
<br />
=Technical Overview=<br />
<br />
AMBuild is separated into a ''frontend'' and a ''backend''. The frontend is responsible for parsing build scripts (this is known as the ''configure'' step). The backend is responsible for actually performing builds. The frontend and backend are separate, and it is possible to use a different backend other than AMBuild. For example, there are plans for the configure step to be able to produce Visual Studio project files.<br />
<br />
== Configuring ==<br />
<br />
Build scripts are written in Python, and they are parsed whenever you configure the build. If a build script changes, it will automatically re-trigger the configure process on the next build. When a configure takes place, any files left by an old build are removed if they are modified or removed in the new dependency graph.<br />
<br />
The details of the generated dependency graph are stored in an SQLite database, which is located in a hidden <tt>.ambuild2</tt> folder inside the build path.<br />
<br />
== Building ==<br />
<br />
The build process involves a few important steps that are executed every time you use the <tt>ambuild</tt> command:<br />
<ol><br />
<li>'''Damage Computation'''. Builds a list of all files that have changed since the last build. This is based on filesystem timestamps, and either a forward or backward time change is enough to be considered "damaged" (or dirty). For example:<br />
<pre><br />
$ ambuild --show-changed<br />
/home/dvander/alliedmodders/mmsource-central/loader/loader.cpp<br />
</pre><br />
</li><br />
<li>'''Partial DAG Construction'''. A partial dependency graph is built based on the list of damaged files. This is the entire set of nodes in the graph which need to be recomputed. The output of this step can be seen with <tt>--show-damage</tt>. For example:<br />
<pre><br />
$ ambuild --show-damage<br />
- package/addons/metamod/bin/server_i486.so<br />
- cp "../loader/server_i486/server_i486.so" "package/addons/metamod/bin/server_i486.so"<br />
- loader/server_i486/server_i486.so<br />
- c++ loader.o gamedll.o serverplugin.o utility.o -m32 -static-libgcc -shared -o server_i486.so<br />
- loader/server_i486/loader.o<br />
- [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
- /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp<br />
</pre><br />
</li><br />
<li>'''Task Construction'''. The partial DAG is simplified into a tree of commands to run. The output of this step can be seen with <tt>--show-commands</tt>. For example:<br />
<pre><br />
$ ambuild --show-commands<br />
- cp "../loader/server_i486/server_i486.so" "package/addons/metamod/bin/server_i486.so"<br />
- c++ loader.o gamedll.o serverplugin.o utility.o -shared -o server_i486.so<br />
- [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
</pre><br />
</li><br />
<li>'''Updating'''. Each task in the task tree is executed and the results are processed to either reject the build, or update the state of the dependency graph. At this phase, tasks are executed in parallel based on the number of CPU cores available. The task graph is also shared to maximize throughput. You can see the sequential build steps with <tt>--show-steps</tt>:<br />
<pre><br />
$ ambuild --show-steps<br />
task 0: [gcc] -> c++ -Wall -Werror -H -c /home/dvander/alliedmodders/mmsource-central/loader/loader.cpp -o loader.o<br />
-> loader/server/loader.o<br />
task 1: c++ loader.o gamedll.o serverplugin.o utility.o -m32 -static-libgcc -shared -o server.so<br />
-> loader/server/server.so<br />
task 2: cp "../loader/server/server.so" "package/addons/metamod/bin/server.so"<br />
-> package/addons/metamod/bin/server.so<br />
</pre><br />
Maximizing throughput in Python is tricky since it has limited capability for IPC and multithreading. AMBuild spawns worker processes based on the number of CPUs available, which run task jobs and return the results.<br />
</li><br />
</ol><br />
<br />
=Comparisons=<br />
==Make, Speed==<br />
Make uses a recursive update scheme. Starting with the top-level rule, Make will recursively search all dependencies to find outdated rules, and it will update all rules as it unwinds. This usually involves touching way more rules than are necessary. Consider the following dependency graph:<br />
<br />
[[Image:RecursiveDepGraph.png]]<br />
<br />
In this graph, <tt>stdint.h</tt> has been modified. Even though it's the only rule that has been changed, Make must visit every single node in the graph to discover that it has changed. Furthermore, it has to visit it multiple times: once for <tt>main.o</tt>, and another time for <tt>helpers.o</tt>. In a large dependency graph, this is very expensive.<br />
<br />
In AMBuild, the direction of the graph is reversed:<br />
<br />
[[Image:AMDepGraph.png]]<br />
<br />
With this graph, it is possible to visit every node once. Once we know that <tt>stdint.h</tt> has changed, we can follow the edges upward and ignore everything in the graph that is unaffected:<br />
<br />
[[Image:AMPartialDepGraph.png]]<br />
<br />
==Make, Accuracy==<br />
AMBuild strives to be accurate by design, in two ways:<br />
* Computation of dependencies should be as minimally accurate as possible. Changing a build script should not result in a complete rebuild.<br />
* An incremental build should be exactly the same as a fresh build.<br />
<br />
It is difficult to achieve very accurate rebuilds in Make. For example, consider a Makefile that lists source files and CFLAGS, and invokes the C++ compiler to build and link them:<br />
<pre><br />
# Makefile<br />
CFLAGS = -Wall<br />
<br />
helpers.o: helpers.cpp<br />
$(CC) $(CFLAGS) helpers.cpp -c -o helpers.o<br />
main.o: main.cpp<br />
$(CC) $(CFLAGS) main.cpp -c -o main.o<br />
<br />
main: main.o helpers.o<br />
$(CC) main.o helpers.o -o main<br />
</pre><br />
<br />
If you change <tt>helpers.cpp</tt>, you will get a minimal rebuild. If you add a new source file, you will likely get a minimal rebuild. However, if you ''remove the <tt>helpers</tt> rule completely'', the build will be incorrect, because <tt>Make</tt> cannot tell that <tt>main</tt> needs to be relinked.<br />
<br />
One way to solve this is to have certain rules, like the link rule, have a dependency on <tt>Makefile</tt> itself. But then if you change <tt>CFLAGS</tt>, it will trigger a relink, even though that rule does not depend on <tt>CFLAGS</tt>. You would need to break the Makefile down into many smaller Makefiles.<br />
<br />
AMBuild mitigates these problems by intelligently updating the dependency graph. If a reparse of the build scripts produces identical nodes, it will not consider those nodes as stale.<br />
<br />
Furthermore, when deleting rules, Make will leave their outputs behind. The author is not aware of an easy way to solve this. Leaving old outputs behind is undesirable for a number of reasons. Stale outputs might fool a user or developer tool into thinking the build has succeeded, when in fact it has failed. Stale outputs might be loaded accidentally, i.e. <tt>LD_LIBRARY_PATH</tt> picking up a library that should not exist. Tests that developers forgot to update might pass locally because of a stale output.<br />
<br />
In AMBuild, leaving stale files behind is an error, since they would not be produced by a fresh build.<br />
<br />
==Tup==<br />
AMBuild is designed to be, essentially, a miniature clone of Tup written entirely in Python. In particular it closely follows concepts in [http://gittup.org/tup/build_system_rules_and_algorithms.pdf the Tup whitepaper]. However there are a few differences that may make one more desirable over the other:<br />
* Tup has been around longer than AMBuild 2, and has been more thoroughly tested. <br />
* Tup uses complex file system features to optimize updates. Algorithms that are O(n) in AMBuild tend to be O(1) in Tup.<br />
* AMBuild only requires a default Python installation to work. Tup, due to being written in C and using very platform specific file system features, may not be as accessible.<br />
* Tup has more features for speeding up very large projects. It can do minimal reparsing and it can reduce the number of links in large graphs.<br />
* AMBuild is designed to be a front-end in addition to a back-end. It has a simple API and script syntax, and is designed to support multiple output formats. For example, it could conceivably generate Visual Studio or XCode project files.<br />
<br />
Since AMBuild is also a frontend, AMBuild may one day eliminate its backend in favor of emitting Tupfiles instead.<br />
<br />
AMBuild's IPC implementation is very low-level, and it has not yet been ported beyond Windows, Mac/BSD, or Linux. However it's not difficult to port to Unix-like systems, and if needed a generic (albeit suboptimal) cross-platform implementation could be provided.</div>WildCard65https://wiki.alliedmods.net/index.php?title=SDKHooks&diff=9882SDKHooks2015-03-24T18:49:26Z<p>WildCard65: </p>
<hr />
<div>==Introduction==<br />
SDKHooks was previously an external extension to Sourcemod. It was rolled in [https://wiki.alliedmods.net/Sourcemod_1.5.0_API_Changes#SDKHooks Sourcemod 1.5] and it does not need to be manually installed anymore.<br />
<br />
==Hooks==<br />
Some information on various hooks below.<br />
<br />
===SDKHook_OnTakeDamage===<br />
inflictor (3rd argument) is the entity that inflicts the damage. If a player directly damages another, inflictor should be equal to the attacking player id. An example of an indirect damage would be a grenade.<br />
<br />
==Under CSS==<br />
===Non-regular cases for SDKHook_OnTakeDamage===<br />
In the scenario where a player throw a grenade to another player then quickly disconnect, the attacker (2nd argument) will become the inflictor (3rd argument). <br />
<br />
In the scenario where a player fall; the attacker, which is also the inflictor, will be 0 (the world).<br />
<br />
In the scenario where a terrorist plants the bomb, when the bomb explodes, the attacker (2nd argument) will be the same as the inflictor (3rd argument) which will have the Classname "planted_c4".<br />
<br />
===Some damage types===<br />
A normal HEGrenade and the C4 inflict damage of type DMG_BLAST.<br />
<br />
A fall inflicts damage of type DMG_FALL.<br />
<br />
A grenade impact (for instance a flash hitting a teammate) will inflict damage of type DMG_CLUB.<br />
<br />
A normal gun bullet and the knife will inflict damage of type (DMG_BULLET | DMG_NEVERGIB) (non-headshot) or (DMG_BULLET | DMG_NEVERGIB | (1 << 30) ) (headshot).<br />
<br />
A single attack can trigger many SDKHook_OnTakeDamage; when a gun throws pullets for instance (shotgun and glock in burst-mode notably).<br />
<br />
<br />
(Regarding SM/Admin damaged; maybe place this is another section if someone can be sure that this would occur on all mods)<br />
<br />
sm_slap does not trigger SDKHook_OnTakeDamage.<br />
<br />
sm_burn will trigger two different callback : an entity with the classname "entityflame" will deal once 0 damage of type DMG_BURN and once 1 damage of type (DMG_BURN | DMG_DIRECT) every tick.<br />
==Under TF2==<br />
Under tf2, the takedamage hook isn't 100% accurate, it's damage param is the weapon's base damage. the DMG_CRIT flag is for both crit and minicrit, spread and minicrit/crit damage is done after this call.</div>WildCard65