2023-09-11 06:13:48 -04:00
This document details how to compile a basic plugin in Visual Studio, MinGW, or GCC/Clang.
2019-05-13 09:30:23 -04:00
2023-09-11 06:13:48 -04:00
To find the functions and variables available for use in plugins, look for `CC_API` /`CC_VAR` in the .h files.
2019-05-13 09:30:23 -04:00
2024-02-19 19:52:31 -05:00
[Source code of some actual plugins ](https://github.com/ClassiCube/ClassiCube-Plugins/ )
2019-05-13 09:30:23 -04:00
### Setup
2023-09-11 06:13:48 -04:00
You need to download and install either Visual Studio, MinGW, or GCC/Clang.
2019-05-13 09:30:23 -04:00
2023-09-11 06:13:48 -04:00
*Note: MinGW/GCC/Clang are relatively small, while Visual Studio is gigabytes in size.
2019-05-13 09:30:23 -04:00
If you're just trying to compile a plugin on Windows you might want to use MinGW. See main readme.*
I assume your directory is structured like this:
```
src/...
TestPlugin.c
```
2023-01-17 04:46:25 -05:00
Or in other words, in a directory somewhere, you have a file named `TestPlugin.c` , and then a sub-directory named `src` which contains the game's source code.
2019-05-13 09:30:23 -04:00
### Basic plugin
```C
#include "src/Chat.h"
2021-10-10 05:09:31 -04:00
#include "src/Game.h"
#include "src/String.h"
2019-05-13 09:30:23 -04:00
static void TestPlugin_Init(void) {
2020-10-17 23:51:13 -04:00
cc_string msg = String_FromConst("Hello world!");
2019-05-13 09:30:23 -04:00
Chat_Add(&msg);
}
int Plugin_ApiVersion = 1;
struct IGameComponent Plugin_Component = { TestPlugin_Init };
```
Here's the idea for a basic plugin that shows "Hello world" in chat when the game starts. Alas, this won't compile...
### Basic plugin boilerplate
```C
2021-10-10 05:09:31 -04:00
#ifdef _WIN32
2019-05-13 09:30:23 -04:00
#define CC_API __declspec(dllimport)
#define CC_VAR __declspec(dllimport)
#define EXPORT __declspec(dllexport)
#else
#define CC_API
#define CC_VAR
#define EXPORT __attribute__ ((visibility("default")))
#endif
2021-10-10 05:09:31 -04:00
#include "src/Chat.h"
#include "src/Game.h"
#include "src/String.h"
2019-05-13 09:30:23 -04:00
static void TestPlugin_Init(void) {
2023-01-17 04:46:25 -05:00
cc_string msg = String_FromConst("Hello world!");
Chat_Add(&msg);
2019-05-13 09:30:23 -04:00
}
EXPORT int Plugin_ApiVersion = 1;
EXPORT struct IGameComponent Plugin_Component = { TestPlugin_Init };
```
With this boilerplate, we're ready to compile the plugin.
All plugins require this boilerplate, so feel free to copy and paste it.
---
2021-01-22 05:27:54 -05:00
### Writing plugins in C++
2020-04-24 21:34:23 -04:00
2021-10-10 05:09:31 -04:00
Exported plugin functions **must** be surrounded with `extern "C"` , i.e.
2021-01-22 05:27:54 -05:00
```C
extern "C" {
EXPORT int Plugin_ApiVersion = 1;
EXPORT struct IGameComponent Plugin_Component = { TestPlugin_Init };
}
```
Otherwise your plugin will not load. (you'll see `error getting plugin version` in-game)
2020-04-24 21:34:23 -04:00
---
2022-08-12 09:01:21 -04:00
## Compiling
Plugin compilation instructions differs depending on the compiler and operating system
2019-05-13 09:30:23 -04:00
### Linux
2022-08-12 09:01:21 -04:00
[Compiling using gcc or clang ](plugin-dev.md#using-gcc-or-clang )
[Cross compiling for Windows 32-bit ](plugin-dev.md#cross-compiling-for-windows-32-bit-using-mingw-w64 )
[Cross compiling for Windows 64-bit ](plugin-dev.md#cross-compiling-for-windows-64-bit-using-mingw-w64 )
### macOS
[Compiling using gcc or clang ](plugin-dev.md#using-gcc-or-clang-1 )
### Windows
[Compiling using Visual Studio ](plugin-dev.md#using-visual-studio )
[Compiling using mingw-w64 ](plugin-dev.md#using-mingw-w64 )
---
## Compiling - Linux
### Using gcc or clang
2023-01-17 04:46:25 -05:00
2022-08-12 09:01:21 -04:00
#### Compiling
2023-01-17 04:46:25 -05:00
`cc TestPlugin.c -o TestPlugin.so -shared -fPIC`
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
Then put `TestPlugin.so` into your game's `plugins` folder. Done.
2019-05-13 09:30:23 -04:00
2022-08-12 09:01:21 -04:00
### Cross compiling for Windows 32 bit using mingw-w64
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
#### Setup
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
1) Create `ClassiCube.exe` by either:
1) Compiling the game, see `Cross compiling for windows (32 bit)` in [main readme ](/readme.md#cross-compiling-for-windows-32-bit )
2) Downloading 32 bit ClassiCube from https://www.classicube.net/download/#dl-win
2) Install the `mingw-w64-tools` package (if it isn't already)
3) Generate the list of exported symbols from `ClassiCube.exe` by running:
* `gendef ClassiCube.exe`
4) Create a linkable library from the exported symbols list by running:
* `i686-w64-mingw32-dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe`
2019-09-12 17:47:06 -04:00
TODO: also document alternate method of compiling the game using --out-implib
2022-08-12 09:01:21 -04:00
#### Compiling
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
`i686-w64-mingw32-gcc TestPlugin.c -o TestPlugin.dll -s -shared -L . -lClassiCube`
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
### Cross compiling for Windows 64 bit using mingw-w64
#### Setup
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
1) Create `ClassiCube.exe` by either:
1) Compiling the game, see `Cross compiling for windows (64 bit)` in [main readme ](/readme.md#cross-compiling-for-windows-64-bit )
2) Downloading 64 bit ClassiCube from https://www.classicube.net/download/#dl-win
2) Install the `mingw-w64-tools` package (if it isn't already)
3) Generate the list of exported symbols from `ClassiCube.exe` by running:
* `gendef ClassiCube.exe`
4) Create a linkable library from the exported symbols list by running:
* `x86_64-w64-mingw32-dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe`
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
TODO: also document alternate method of compiling the game using --out-implib
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
#### Compiling
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
`x86_64-w64-mingw32-gcc TestPlugin.c -o TestPlugin.dll -s -shared -L . -lClassiCube`
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
2019-05-13 09:30:23 -04:00
2022-08-12 09:01:21 -04:00
## Compiling - macOS
2019-05-13 09:30:23 -04:00
2022-08-12 09:01:21 -04:00
### Using gcc or clang
2023-01-17 04:46:25 -05:00
2022-08-12 09:01:21 -04:00
#### Compiling
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
`cc TestPlugin.c -o TestPlugin.dylib -undefined dynamic_lookup`
2019-05-13 09:30:23 -04:00
2023-01-17 04:46:25 -05:00
Then put `TestPlugin.dylib` into your game's `plugins` folder. Done.
2019-05-13 09:30:23 -04:00
2022-08-12 09:01:21 -04:00
## Compiling - Windows
### Using Visual Studio
TODO more detailed when I have some more time...
#### Setup
2019-09-12 17:47:06 -04:00
2023-03-25 09:18:13 -04:00
1) Compile the game, see `Compiling - Windows > using Visual Studio` in main readme
2019-09-12 17:47:06 -04:00
2) Find the `ClassiCube.lib` that was generated when compiling the game. Usually it is in either `src\x64\Debug` or `src\x86\Debug` .
3) Add a new `Empty Project` to the ClassiCube solution, then add the plugin .c files to it
Note: If the plugin provides a .vcxproj file, you can skip step 2 and just open that project file instead.
2022-08-12 09:01:21 -04:00
#### Configuration - alternative #1
The simplest way of linking to the `.lib` file is simply adding the following code to one of the plugin's `.c` files
2023-03-25 09:18:13 -04:00
```C
2022-08-12 09:01:21 -04:00
#ifdef _MSC_VER
#ifdef _WIN64
2023-01-17 04:46:25 -05:00
#pragma comment(lib, "[GAME SRC FOLDER]/x64/Debug/ClassiCube.lib")
2022-08-12 09:01:21 -04:00
#else
2023-01-17 04:46:25 -05:00
#pragma comment(lib, "[GAME SRC FOLDER]/x86/Debug/ClassiCube.lib")
2022-08-12 09:01:21 -04:00
#endif
#endif
2023-09-11 06:13:48 -04:00
```
2022-08-12 09:01:21 -04:00
2023-01-17 04:46:25 -05:00
replacing `[GAME SRC FOLDER]` with the full path of `src` folder (e.g. `C:/Dev/ClassiCube/src` )
2022-08-12 09:01:21 -04:00
#### Configuration - alternative #2
The more complicated way of linking to the `.lib` file is to add it to the plugin's project configuration file
2019-09-12 17:47:06 -04:00
Right click the plugin project in the `Solution Explorer` pane, then click `Properties`
TODO: add screenshots here
TODO: may need to configure include directories
1) In `Configuration properties` -> `General` , make sure `Configuration type` is set to `Dynamic library (.DLL)`
2) In `Configuration properties` -> `Linker` -> `Input` , click the dropdown button for `Additional Dependencies` , then click `Edit` . Add the full path to `ClassiCube.lib` , then click `OK`
2022-08-12 09:01:21 -04:00
#### Compiling
2019-09-12 17:47:06 -04:00
Build the project. There should be a line in the build output that tells you where you can find the .dll file like this:
2023-01-17 04:46:25 -05:00
`
2022-08-12 09:01:21 -04:00
Project1.vcxproj -> C:\classicube-dev\testplugin\src\x64\Debug\TestPlugin.dll
2023-01-17 04:46:25 -05:00
`
2022-08-12 09:01:21 -04:00
2023-01-17 04:46:25 -05:00
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
2022-08-12 09:01:21 -04:00
### Using mingw-w64
#### Setup
2023-01-17 04:46:25 -05:00
1) Create `ClassiCube.exe` by either:
1) Compiling the game, see `Compiling for windows (MinGW-w64)` in [main readme ](/readme.md#using-mingw-w64 )
2) Downloading ClassiCube from https://www.classicube.net/download/#dl-win
2) Generate the list of exported symbols in `ClassiCube.exe` by running:
* `gendef ClassiCube.exe`
3) Create a linkable library from the exported symbols list by running:
* `dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe`
2022-08-12 09:01:21 -04:00
#### Compiling
2023-01-17 04:46:25 -05:00
`gcc TestPlugin.c -o TestPlugin.dll -s -shared -L . -lClassiCube`
2022-08-12 09:01:21 -04:00
2023-01-17 04:46:25 -05:00
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
2022-08-12 09:01:21 -04:00
2023-09-11 06:13:48 -04:00
## Notes for compiling for Windows
### Ensuring your plugin works when the ClassiCube exe isn't named ClassiCube.exe
If you follow the prior compilation instructions, the compiled DLL will have a runtime dependancy on `ClassiCube.exe`
However, this means that if the executable is e.g. named `ClassiCube (2).exe` instead. the plugin DLL will fail to load
To avoid this problem, you must
1) Stop linking to `ClassiCube` (e.g. for `MinGW` , remove the ` -L . -lClassiCube` )
2) Load all functions and variables exported from ClassiCube via `GetProcAddress` instead
2024-02-19 19:52:31 -05:00
This is somewhat tedious to do - see [here ](https://github.com/ClassiCube/ClassiCube-Plugins/ ) for some examples of plugins which do this
2022-08-12 09:01:21 -04:00
2023-09-11 06:13:48 -04:00
#### Compiling ultra small plugin DLLs - MinGW
If you **ONLY** use code from the game (no external libraries and no C standard library functions):
* You can add `-nostartfiles -Wl,--entry=0` to the compile flags to reduce the DLL size (e.g from 11 to 4 kb)
2022-08-12 09:01:21 -04:00
2024-07-28 09:33:22 -04:00
This isn't necessary to do though, and plugin DLLs work completely fine without doing this.