Skip to content

How Builds Work

Southclaws edited this page Mar 9, 2018 · 6 revisions

This is an overview of how sampctl invokes the compiler and how this works with packages.

How Includes Work

First, I should clarify how includes actually work in the Pawn language. They work in the same way that the C compilers do - there are quote includes and angle-bracket includes:

#include "file.inc"
#include <file>

Quote-includes take the string enclosed in the quotes as a path relative to the file that contains the directive. This means you can include a file in a subdirectory with #include "subdir/file.inc".

Angle-bracket-includes work differently, they take the path enclosed in the angle brackets and search through a list of directories for files matching the path relative to each directory. These directories will be referred to as "include paths".

Using the compiler distributed with the SA:MP server package, it has a single pre-defined include path: ./includes/ relative to the pawncc location. That's why a_samp.inc and all your other include files are located in pawno/include.

As far as I know, the modified compiler by Zeex doesn't include any hard-coded include paths.

You can read more about include paths and some of the more obscure quirks in the YSI include guard documentation.

Include Paths

When invoking the compiler, you can pass the flag -i to specify an additional include path - you can do this as many times as you want and add (as far as I know) infinite include paths.

If you add 3 directories via this flag, this means that angle-bracket-includes have 3 more directories to search for includes.

For example, given a file gm.pwn:

#include <anticheat>

Given the following directory structure:

/
├── afk
│   └── afk.inc
├── anticheat
│   └── anticheat.inc
└── velocity
    └── velocity.inc

Here we have three directories located at / (disk root) each with an include file inside.

If we invoke the compiler like this:

pawncc gm.pwn

We could get a fatal error 100: cannot read from file: "anticheat" because the compiler does not know where anticheat.inc is located.

So, to overcome this, the -i flag is used to specify a directory where .inc files reside:

pawncc -i /anticheat gm.pwn

Which now compiles correctly (given the contents of the files is all valid Pawn code!)

sampctl package build

Now you know how pawncc works with includes, you can get a good idea of how sampctl uses this to easily handle dependencies without the user needing to manually move .inc files around.

The old way of doing things was to manually place all your .inc files into a single folder. And that folder is implicitly added as an include directory when the compiler is executed.

For every "dependency" that a package declares, sampctl knows the exact location of it. Because of this fact, sampctl creates a list of -i flags when it invokes the compiler, each -i is simply the path to a dependency. These always reside in the dependencies/ directory located in the package directory.

For example, given the following package dependencies:

{
  "dependencies": ["sampctl/samp-stdlib", "Southclaws/samp-logger"]
}

After running sampctl package ensure the dependencies/ directory would look like this, with most files omitted for clarity:

dependencies/
├── samp-logger/
|   └── logger.inc
├── samp-plugin-crashdetect/
|   └── crashdetect.inc
└── samp-stdlib/
    ├── a_samp.inc
    ...

The compiler is then invoked like this, with some unrelated flags omitted:

pawncc -i./dependencies/samp-stdlib -i./dependencies/samp-logger -i./dependencies/samp-crashdetect gm.pwn

(In reality, the paths are absolute, not relative)

Conflicts

You might have wondered what happens if two include paths contain a file with the same name. You should read the YSI document on include guards to get an idea of how the compiler handles these cases.

If two dependencies contain conflicting .inc fies, such as Zeex/amx_assembly and Zeex/samp-plugin-profiler which both contain a file named profiler.inc - the Pawn compiler will just pick one (I'm not sure which, I assume it picks the first one it encounters).

Because this can introduce ambiguity in the compilation process, sampctl traverses each dependency directory searching for conflicting filenames and warns the user if there are.

Clone this wiki locally