Skip to content

Libraries

Positron edited this page Aug 3, 2017 · 1 revision

Libraries

The library specified as an argument to the compiler is called the main library. First, the main library is preprocessed and parsed. Then, each library imported by the main library is preprocessed and parsed. The preprocessor starts afresh for every library, so macros defined in one library will not be available in another library. Macros defined on the command-line are only available during the preprocessing of the main library.


In an imported library, the predefined macro, __IMPORTED__, is available. It is defined as 1. This macro is useful for identifying the error where the user imports a library using #include instead of #import:

#library "somelib"

#ifndef __IMPORTED__
   #error you must #import this file
#endif

Private visibility

A library can have private objects, which can be variables, functions, and unnamed enumerations. Only the library can see its private objects. A library that imports another library will not be able to see the private objects of the imported library:

File: lib1.bcs
#library "lib1"

int a;

// The following variable, function, and unnamed enumeration are only visible
// inside "lib1":
private int b;
private void F() {}
private enum { C = 123 };
File: lib2.bcs
#library "lib2"

#import "lib1.bcs"

// This `b` is only visible inside "lib2":
private int b;

script "Main" open {
   ++a; // Will increment `a` in "lib1".
   ++b; // Will increment `b` in "lib2".
   F(); // Error: `F` not found. 
}

You can have as many private variables in your library as you like. When the maximum variable limit is about to be reached, the compiler will combine the remaining private variables into a single array.

External declarations

Variables can be declared extern. An external variable declaration is not actually a real variable. All it does is tell the compiler that such a variable exists in some library. The compiler will tell the game to import the variable when the game runs. Along with external variable declarations, external function declarations are also supported:

File: lib1.bcs
#library "lib1"

int v = 123;
void F() {}
File: lib2.bcs
#library "lib2"

extern int v;
extern void F();

script "Main" open {
   ++v;
   F();
}

The game cannot use an external variable unless it knows which library has the variable. To instruct the game to look in some library so it can find the external variable, use #linklibrary:

File: lib2.bcs (Fixed)
#library "lib2"

// The game will now load the "lib1" library. It will also look in the "lib1"
// library when it tries to find the `v` variable and the `F` function.
#linklibrary "lib1"

extern int v;
extern void F();

script "Main" open {
   ++v;
   F();
}

External declarations and the #linklibrary directive are probably not all that useful unless you plan to use header files.

Header files

The header file organization style of C/C++ is supported by BCS. To avoid conflicts with C/C++ header files, it is suggested you give your header files a .h.bcs file extension, although it is not mandatory to do so:

Header file: lib1.h.bcs
#ifndef LIB1_H_BCS
#define LIB1_H_BCS

#linklibrary "lib1"

extern int v;
extern void F();

#endif
Source (library) file: lib1.bcs
#library "lib1"

#include "lib1.h.bcs"

int v = 123;
void F() {}
File: main.bcs
#include "zcommon.h.bcs"
#include "lib1.h.bcs"

script "Main" open {
   v = INT_MAX;
   F();
}

If the name of your header file ends with .h.bcs, the .bcs extension does not need to be specified in an #include directive:

File: main.bcs (Now with shorter include paths)
#include "zcommon.h"
#include "lib1.h"

script "Main" open {
   v = INT_MAX;
   F();
}