2013年3月8日 星期五

順序很重要:gcc library參數的順序

今天呢,想說來看一下lua好了。Lua是一個在許多遊戲中當作scripting language的程式語言,為這些遊戲提供了不小的擴展性。首先,lua可以讓遊戲在不重新編譯的狀態下更有彈性的更改參數;其次,lua提供了一個讓玩者自訂遊戲的管道(像是製作新道具等)。

提供自訂能力的lua必須由另一隻程式來驅動。也就是,我可以做出一隻C語言的程式,讓該程式與lua程式庫連結,然後載入並執行lua的程式碼。

於是,我的第一隻lua相關的程式長這樣:

#include <lua.h>
#include <lualib.h>
#include <stdio.h>
#include <stdlib.h>

void* allocator(void* ud, void* ptr, size_t osize, size_t nsize)
{
  if (nsize == 0)
    {
      free(ptr);
      return NULL;
    }
  else
    {
      return realloc(ptr, nsize);
    }
}

int main()
{
  lua_State* state = lua_newstate(allocator, NULL);
  const lua_Number* version = lua_version(NULL);
  printf("Version: %f\n", *version);
  lua_close(state);
  return 0;
}

接著來編譯:

gcc -I${HOME}/applications/lua-5.2.1/include\
 -L${HOME}/applications/lua-5.2.1/lib/\
 -std=c99 -llua -lm a.c

Fedora 18只提供lua 5.1,而我想要使用傳說中的_ENV,所以只好自行製作lua 5.2囉。(據說有位人士自行製作了lua 5.2,把系統提供的lua 5.1,然後發生了慘不忍睹的事情...)

令人難過(且驚訝)的是編譯並不成功:

#錯誤訊息
/tmp/cc4PrIDU.o: In function `main':
a.c:(.text+0x5a): undefined reference to `lua_newstate'
a.c:(.text+0x68): undefined reference to `lua_version'
a.c:(.text+0x97): undefined reference to `lua_close'
collect2: error: ld returned 1 exit status

利用gcc -I${HOME}/applications/lua-5.2.1/include -L${HOME}/applications/lua-5.2.1/lib/ -std=c99 -llua -lm a.c -Wl,--verbose得知linker有找到我自製的liblua.a:

GNU ld version 2.23.51.0.1-3.fc18 20120806
  Supported emulations:
   elf_x86_64
   elf32_x86_64
   elf_i386
#中略
attempt to open /home/略/applications/lua-5.2.1/lib//liblua.so failed
attempt to open /home/略/applications/lua-5.2.1/lib//liblua.a succeeded
#後略
found ld-linux-x86-64.so.2 at /lib64/ld-linux-x86-64.so.2
/tmp/ccitISUF.o: In function `main':
a.c:(.text+0x5a): undefined reference to `lua_newstate'
a.c:(.text+0x68): undefined reference to `lua_version'
a.c:(.text+0x97): undefined reference to `lua_close'
collect2: error: ld returned 1 exit status

而且該liblua.a裡面也有這三個symbol:

$ objdump -x liblua.a | grep -P "(lua_newstate|lua_version|lua_close)"
0000000000000330 g     F .text  000000000000001e lua_version
00000000000002d0 g     F .text  00000000000002a0 lua_newstate
0000000000000000         *UND*  0000000000000000 lua_version
00000000000006a0 g     F .text  0000000000000010 lua_close
00000000000003d1 R_X86_64_32S      lua_newstate
0000000000000454 R_X86_64_PC32     lua_version-0x0000000000000004
0000000000000000         *UND*  0000000000000000 lua_newstate
0000000000000000         *UND*  0000000000000000 lua_version
0000000000001f09 R_X86_64_PC32     lua_newstate-0x0000000000000004
0000000000001f40 R_X86_64_PC32     lua_version-0x0000000000000004
0000000000001f4a R_X86_64_PC32     lua_version-0x0000000000000004
0000000000000000         *UND*  0000000000000000 lua_close
0000000000000184 R_X86_64_PC32     lua_close-0x0000000000000004

至少這個archive裡面有object提供這些symbol...那為什麼會找不到呢?順序嗎?有聽說過呢!試試看好了:

$ #之前:gcc -I${HOME}/applications/lua-5.2.1/include\
$ # -L${HOME}/applications/lua-5.2.1/lib/ -std=c99\
$ # -llua -lm a.c
$ gcc -I${HOME}/applications/lua-5.2.1/include\
> -L${HOME}/applications/lua-5.2.1/lib/\
> -std=c99 a.c -llua -lm
$ ls a.out
a.out
$ ./a.out
Version: 502.000000

算是誤打誤撞找到了解答。順序真的很重要呢!

沒有留言:

張貼留言