Jump to content

Recommended Posts

Hello, I have problems making an extension in C for Arma in Linux (Ubuntu 16.04). For testing I just took the example from the wiki : 

#include <string.h>     // strcmp, strncpy

 
static char version[] = "1.0";
 
void RVExtension(char *output, int outputSize, const char *function)
{
    if (!strcmp(function, "version"))
    {
        strncpy(output, version, outputSize);
    }
    else
    {
        strncpy(output, function, outputSize);
    }
    output[outputSize-1]='\0';
 
    return;
}

 
After creating the .c file I use the command "gcc -shared -fPIC -o example.so example.c" without any errors. I place example.so in the root folder of my arma 3 server. I start the server but infortunately I have no confimation of the loading of the extension in the logs and in the game if i launch : "hint ("example" callExtension "version");" nothing happen.
 
I hope someone can help me with this. Thanks in advance.

Share this post


Link to post
Share on other sites

My first guess is you're using amd64 architecture, so abovementioned command creates x86-64 binary, whereas arma3server is 32-bit.

Try

gcc -shared -fPIC -m32 -o example.so example.c

UPD. This step may give you linker error, something like:

/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.9/libgcc.a when searching for -lgcc
/usr/bin/ld: cannot find -lgcc
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.9/libgcc_s.so when searching for -lgcc_s
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status

In this case install the package containing these files for 32bit architecture, most likely could be found with command apt-file search 32/libgcc.a

(lib32gcc-4.9-dev in my case)

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for the reply, the command you gave work perfectly but this is not working in the game and always no clue in the logs. I have done a ldd command 

ldd example.so

Here the output : 

linux-gate.so.1 =>  (0xb7759000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757e000)
/lib/ld-linux.so.2 (0xb775a000)

Share this post


Link to post
Share on other sites

I also run that command to check if it's actually loaded or not

lsof -p ...

and like I was thinking it's not.

Share this post


Link to post
Share on other sites

After some strace'ing I found that arma3server tries to open extension in that order:

1. In directories of all mods passed in command line (in reverse order), e.g. "/path/to/Steam/SteamApps/common/Arma 3 Server/mods/@allinarmaterrainpack/example.so"

2. In root directory, i.e. "/example.so"

3. In directories of stock addons installed, e.g. "/path/to/Steam/SteamApps/common/Arma 3 Server/{mark,heli,kart,curator}/example.so"

4. In root directory again. (why?)

5. In current working directory, that is "./example.so"

This order does not look like standard procedure for locating shared objects, so I guess having arma3server with RPATH set or not set to $ORIGIN does not make too much difference (and it is set anyway). Therefore I think it is not enough to just place the .so in the same directory as server executable. Make sure you also set cwd to that directory before launching server.

Extension is loaded on first use: file is opened, mmap'ed, then descriptor closed; that keeps file in process' list of open files (lsof); unmmap'ed on process exit.

 

So I had extension loaded, NO confirmation of that appeared in server logs, therefore I suggest adding some debug messages into extension's code:

/*
 * example.c
 *
 *   gcc -shared -fPIC -m32 -o example.so example.c
 */
#include <string.h>     // strcmp, strncpy
#include <stdio.h>      // fprintf

static char version[] = "1.0";

void RVExtension(char *output, int outputSize, const char *function)
{
    fprintf(stderr, "%s:%d: RVExtension: output: %p; outputSize: %d; function: \"%s\".\n", __FILE__, __LINE__, output, outputSize, function);
    if (!strcmp(function, "version"))
    {
        strncpy(output, version, outputSize);
    }
    else
    {
        strncpy(output, function, outputSize);
    }
    output[outputSize-1]='\0';

    return;
} 

I have these lines in mission's init.sqf:

ext_result = "example" callExtension "version";
diag_log format ["ext_result = ""example"" callExtension ""version""; ext_result == ""%1""", ext_result];

And I have this output in server log:

example.c:13: RVExtension: output: 0xfff166e0; outputSize: 10240; function: "version".
17:01:24 "ext_result = "example" callExtension "version"; ext_result == "1.0""

Further checking, I run this command from client's debug console while in-game:

["example", "foo"] remoteExec ["callExtension", 2]

Extension works only sever-side, therefore remoteExec with targets = 2. That causes following output:

example.c:13: RVExtension: output: 0xfffba6b0; outputSize: 10240; function: "foo".

Finally, when I stop the server, last lines I see are as follows:

18:16:57 Extensions:
18:16:57   example (./example.so) [] [] 

Seems like everything works as expected (except confirmation of load).

Tested on 1.54 legacy port server (for 1.54 legacy port clients), but I don't think things are broken in actual version.

  • Like 1

Share this post


Link to post
Share on other sites

Thank you a lot for your thorough research that resolved my problem. I'm very grateful.

 

 

 but I don't think things are broken in actual version.

 

You've right, It's working in 1.62.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×