23.08.2017, 22:40
Choosing a compiler
Introduction
We'll start with basics. First of all, you need to know distinction between PAWNO, PAWN and pawncc.
What is PAWNO?
PAWNO is a text editor. Basically, Windows notepad, but with color highlighting of keywords, panel listing all native functions and convinient execution of the compiler from within the PAWNO. If you want more power, you can use more sophisticated text editor - Notepad++, VS Code, Atom, Sublime Text, and any editor for which community created PAWN syntax definitions. Some users even created full-fledged IDE's specifically for PAWN. I personally prefer Sublime Text, but have heard good things about each and every other editor I've listed.
What is PAWN?
It's a scripting language which compiles to machine readable bytecode (put in .amx file) which is then executed by your server. So, anything you will write for SAMP in your editor, be it PAWNO or any other editor - is in PAWN.
What is pawncc?
This is the proper compiler - this is where all the action happens. It takes a file (or stdin) written in PAWN, and churns out .amx file. It's important to know that this is one-way process - you can't get original file written in PAWN from .amx file.
You have to understand what compiler does exactly:
All lines starting with "#" are called preprocessor directives. The compiler scans the whole file looking for them (twice to be exact, that's why ALS hooks work at all). I won't go into detail about them, but just know that in this phase, the code goes through following transformation:
pawn Code:
// Before
#define HELLO_WORLD "I like PAWN"
print(HELLO_WORLD);
printf(HELLO_WORLD);
//After
print("I like PAWN");
print("I like PAWN");
That's why sometimes it's better to define your strings as "static const". Why?
In global scope, "static" keyword restricts the string to the file it's defined in, and "const" will trigger errors when you try to modify it somewhere by accident.
In function scope, "static" puts the string on the heap, so its value does not change between function calls.
So, the macro will allocate a new string each time it is used, while your const string will be allocated only once. Take a look at this:
pawn Code:
#include <a_samp>
static const str[] = "Hello world";
main() {
print(str);
print(str);
}
pawn Code:
CODE 0 ; 0
;program exit point
halt 0
DATA 0 ; 0
dump 48 65 6c 6c 6f 20 77 6f 72 6c 64 0
CODE 0 ; 8
proc ; main
; line 5
break ; c
; line 6
break ; 10
const.pri 0
push.pri
;$par
push.c 4
sysreq.c 0 ; print
stack 8
;$exp
; line 7
break ; 38
const.pri 0
push.pri
;$par
push.c 4
sysreq.c 0 ; print
stack 8
;$exp
zero.pri
retn
STKSIZE 1000
You can see what preprocessor does, by compiling with "-l" flag. It will generate .lst file, which is code after preprocesing.
Next, the preprocessed file is compiled to P-code bytecode - code readable by our amx virtual machine. You can see one step before that, compling with -a flag - it will generate .asm file (this is _not_ assembly). You can write P-Code directly using preprocessor directive #emit - using it is black magic, only reserved for people like Y_Less, Zeex and Slice. Can you believe that Y_Less created inline functions just by using #emit? (which create function at run-time, as I said, black magic).
The good stuff
There are 3 compilers. We'll start with
Standard compiler
When you download samp-server from official site, it comes with PAWNO editor, and pawncc modified by Kalcor. It is the easiest choice, as you don't have to do anything, just fire up PAWNO, write some stuff, hit F5 and you get nice AMX. However, it has some bugs, listed here. When I was a beginner PAWN scripter, I was bit by them often (especially sizeof second dimension, as well as ternary with strings) and didn't know what to do.
Pros
- No barrier to entry
- Supported by official SAMP team
- Has multiple bugs
- Too mainstream
Source not available
SA-MP team doesn't really respond to users requests for bugfixes (except for the critical ones, thank God), so there is this guy Zeex who (I guess) got fed up by it, and created...
Zeex's compiler
It fixes most of the issues with standard compiler, however: It is not a drop-in replacement for standard compiler, except in compatibility mode. If you want just the bugfixes, you need to specify compability mode (-Z+ flag).
For me, the most important bug fix was changing behaviour of the sizeof operator for second dimension. For example, here's code from standard compiler:
pawn Code:
#include <a_samp>
enum E_TEST {
E_TEST_WTF,
E_TEST_STR[32]
}
new Test[MAX_PLAYERS][E_TEST];
main() {
new abc[] = "Hello";
strcat(Test[0][E_TEST_STR], abc);
}
pawn Code:
strcat(Test[0][E_TEST_STR], abc, 32);
Now, what does it change? For one, in non-compat mode it removes the auto include guards. When you include a file in standard compiler, it creates something called include guard. It means that if file is included twice, the second include is not included. When using Zeex's compiler, this is no longer the case. And this can, and will bite you in the ass - all your dependencies have to create their own include guards, so for non-maintained includes you have to manually add them, or really watch out what includes what.
Another brilliant addition is nested ellipsis. Now you can do something standard compiler failed at:
pawn Code:
new Hello[][10] = { { 1, 2, ...}, ... };
Pros
- Opensource
- Multiple contributors (shoutout to VVWVV for taking up the torch lately)
- Fixes most of the bugs in standard compiler
- Adds some handy stuff
- Zeex is busy doing other stuff
- Not friendly to beginners
Download 2 for windows, in case source is ahead of releases
Source (github)
Zeex started doing his own thing, and some guy tried to get his attention via github and email, but failed, got fed up because of it, and created...
Some russian's guy compiler
A new compiler. I heard about it few days ago, and gave it a try. It cut down from my compile time of 180 seconds (yes, that's what using YSI and a few years of work does to your compilation) to 15 seconds. For 30 second compilation it took 3 seconds. That's simply amazing. Quoting author:
Quote:
this version based on c++14, I don't think Zeex will merge speed changed (...) it's compile as cpp not c unordered_map, unordered_set & std:tring @zeex didn't answer about optimise on email & for thread |
Oh, and there's a possibility there's a virus either embedded in the compiler's own .exe, or injected into .amx. Virustotal does not report anything in the binary (but it is trivial to create fully undetectable malware as far as I know). .amx's report differences, and you should be wary that it's quite easy to exploit virtual amx machine used by samp-server (see Zeex's amx_assembly - ShellExecute is arbitrary code execution). Given all that warnings:
Download link (warning, I don't know who controls it, and it might change at any time, so watch out)
Mirror (same warnings as above)
Source not available
Pros
- All of Zeex's compiler pros
- Extreme (>10x) times compilation speed improvement
- Some hidden warnings, which may cause some libraries to fail
- May contain harmful code
- One contributor
- No source available
How to install the compiler?
The standard one is bundled with PAWNO, nothing needs to be done. For Zeex's compiler follow download links I provided, then dump those files in yourserver/pawno folder. Same thing for russian compiler
Summary
Are you a beginner? Use default pawncc bundled with server
You were bitten by any of the bugs in standard compiler but are cautious? Zeex's compiler with compatibility mode
You know what you are doing? Russian compiler for development, Zeex's compiler for CI and production-ready code
Have fun, and be safe!
UPDATE: I asked the creator of the russian compiler about opensourcing it, and he responded with
Quote:
Zeex enabled autism mode and ignore me at all https://github.com/Zeex/pawn/issues/120 |