Native extensions - kuimoani/defold GitHub Wiki

Native extensions

λ§Œμ•½ Luaλ‘œλŠ” μΆ©λΆ„ν•˜μ§€ λͺ»ν•œ μ™ΈλΆ€ μ†Œν”„νŠΈμ›¨μ–΄λ‚˜ ν•˜λ“œμ›¨μ–΄μ™€ 둜우 레벨둜 μ»€μŠ€ν…€ μƒν˜Έμž‘μš©μ΄ ν•„μš”ν•œ κ²½μš°μ—λŠ”, Defold SDKλŠ” C++둜 μ΅μŠ€ν…μ…˜μ„ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. λ„€μ΄ν‹°λΈŒ μ΅μŠ€ν…μ…˜μ˜ 일반적인 μ‚¬μš© μ‚¬λ‘€λ‘œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • 예λ₯Ό λ“€λ©΄ λͺ¨λ°”일 카메라 같은 νŠΉμ • ν•˜λ“œμ›¨μ–΄μ™€ μƒν˜Έμž‘μš© ν•˜κΈ°
  • κ΄‘κ³  λ„€νŠΈμ›Œν¬ APIλ‚˜ Luasocket을 μ‚¬μš©ν•  수 μžˆλŠ” λ„€νŠΈμ›Œν¬ API 같은 μ™ΈλΆ€ 둜우 레벨 API와 μƒν˜Έμž‘μš© ν•˜κΈ°
  • κ³ μ„±λŠ₯ 계산

The build platform

DefoldλŠ” ν΄λΌμš°λ“œ 기반 λΉŒλ“œ μ†”λ£¨μ…˜μ„ μ‚¬μš©ν•˜μ—¬ λ„€μ΄ν‹°λΈŒ μ΅μŠ€ν…μ…˜μ— λŒ€ν•œ 무섀정 μ§„μž… 지점(zero setup entry point)을 μ œκ³΅ν•©λ‹ˆλ‹€. κ²Œμž„ ν”„λ‘œμ νŠΈμ— μΆ”κ°€λœ λ„€μ΄ν‹°λΈŒ μ΅μŠ€ν…μ…˜μ€ 일반적인 ν”„λ‘œμ νŠΈ μ»¨ν…μΈ μ˜ 일뢀가 λ©λ‹ˆλ‹€. μ—”μ§„μ˜ νŠΉμ • λ²„μ „μœΌλ‘œ λΉŒλ“œν•˜κ±°λ‚˜ νŒ€μ›μ—κ²Œ 배포할 ν•„μš”λ„ μ—†μœΌλ©° 이 μž‘μ—…λ“€μ€ μžλ™μœΌλ‘œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€. ν”„λ‘œμ νŠΈλ₯Ό λΉŒλ“œν•˜κ±°λ‚˜ μ‹€ν–‰ν•˜λ €λŠ” λͺ¨λ“  νŒ€μ›λ“€μ€ λͺ¨λ“  λ„€μ΄ν‹°λΈŒ μ΅μŠ€ν…μ…˜κ³Ό ν•¨κ»˜ νŠΉμ • ν”„λ‘œμ νŠΈ μ—”μ§„ μ‹€ν–‰νŒŒμΌμ„ 받을 수 μžˆμŠ΅λ‹ˆλ‹€.

Cloud build

Project layout

μƒˆ μ΅μŠ€ν…μ…˜μ„ λ§Œλ“€κΈ° μœ„ν•΄μ„œλŠ” ν”„λ‘œμ νŠΈ λ£¨νŠΈμ— 폴더λ₯Ό ν•˜λ‚˜ λ§Œλ“€μ–΄μ•Ό ν•©λ‹ˆλ‹€. 이 ν΄λ”μ—λŠ” μ΅μŠ€ν…μ…˜κ³Ό κ΄€κ³„λœ λͺ¨λ“  μ…‹νŒ…, μ†ŒμŠ€μ½”λ“œ, 라이브러리, λ¦¬μ†ŒμŠ€λ“€μ„ ν¬ν•¨μ‹œμΌœμ•Ό ν•©λ‹ˆλ‹€. 이 μ΅μŠ€ν…μ…˜ λΉŒλ”λŠ” 폴더 ꡬ쑰λ₯Ό μΈμ‹ν•˜κ³  λͺ¨λ“  μ†ŒμŠ€νŒŒμΌκ³Ό 라이브러리λ₯Ό μˆ˜μ§‘ν•©λ‹ˆλ‹€.

Project layout

"ext.manifest"

μ΅μŠ€ν…μ…˜ ν΄λ”μ—λŠ” "ext.manifest" 파일이 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. 이 νŒŒμΌμ€ μ΅μŠ€ν…μ…˜ λΉŒλ”μ— μ˜ν•΄ μ„ νƒλ˜λŠ” YAML ν˜•μ‹μ˜ νŒŒμΌμž…λ‹ˆλ‹€. λ©”λ‹ˆνŽ˜μŠ€νŠΈ νŒŒμΌμ—λŠ” μ΅œμ†Œν•œ μ΅μŠ€ν…μ…˜μ˜ 이름이 ν¬ν•¨λ˜μ–΄ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

src

이 ν΄λ”μ—λŠ” λͺ¨λ“  μ†ŒμŠ€μ½”λ“œ νŒŒμΌλ“€μ΄ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

include

이 선택적(optional) ν΄λ”μ—λŠ” λ‹€λ₯Έ 포함 파일(include files)듀이 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

lib

이 선택적 ν΄λ”μ—λŠ” μ΅μŠ€ν…μ…˜μ΄ μ˜μ‘΄ν•˜λŠ” λͺ¨λ“  컴파일된 λΌμ΄λΈŒλŸ¬λ¦¬λ“€μ΄ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. 라이브러리 νŒŒμΌλ“€μ€ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ§€μ›ν•˜λŠ” 아킀텍쳐가 무엇인지에 따라 ν”Œλž«νΌ λ˜λŠ” 아킀텍쳐-ν”Œλž«νΌ μ΄λ¦„μ˜ ν•˜μœ„ 폴더에 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. μ§€μ›λ˜λŠ” ν”Œλž«νΌμ€ ios, android, osx 이며 μ§€μ›λ˜λŠ” 아킀텍쳐-ν”Œλž«νΌ 쌍(arc-platform pairs)은 armv7-ios, arm64-ios, armv7-android, x86_64-osx μž…λ‹ˆλ‹€.

res

이 선택적 ν΄λ”μ—λŠ” μ΅μŠ€ν…μ…˜μ΄ μ˜μ‘΄ν•˜λŠ” λͺ¨λ“  μΆ”κ°€ λ¦¬μ†ŒμŠ€λ“€μ΄ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. λ¦¬μ†ŒμŠ€ νŒŒμΌλ“€μ€ "lib" ν•˜μœ„ ν΄λ”μ²˜λŸΌ ν”Œλž«νΌ λ˜λŠ” 아킀텍쳐-ν”Œλž«νΌ μ΄λ¦„μ˜ ν•˜μœ„ 폴더에 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. common μ΄λ¦„μ˜ ν•˜μœ„ν΄λ”μ—λŠ” λͺ¨λ“  ν”Œλž«νΌμ— 곡톡적인 λ¦¬μ†ŒμŠ€ νŒŒμΌλ“€μ„ ν¬ν•¨μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

A simple example extension

μ•„μ£Ό κ°„λ‹¨ν•œ μ΅μŠ€ν…μ…˜μ„ κ°œλ°œν•΄ λ΄…μ‹œλ‹€. μš°μ„ , "myextension" μ΄λΌλŠ” μƒˆ 루트 폴더λ₯Ό λ§Œλ“€κ³  μ΅μŠ€ν…μ…˜μ˜ 이름이 μžˆλŠ” "ext.manifest" νŒŒμΌμ„ μΆ”κ°€ν•΄ λ΄…μ‹œλ‹€.

Manifest

ext.manifest

name: "MyExtension"

μ΅μŠ€ν…μ…˜μ„ κ΅¬μ„±ν•˜λŠ” C++ 파일 ν•œ 개λ₯Ό "myextension.cpp" λΌλŠ” μ΄λ¦„μœΌλ‘œ "src" 폴더에 μƒμ„±ν•©λ‹ˆλ‹€.

Defold μ—λ””ν„°λŠ” 기본적으둜 .cpp νŒŒμΌμ„ μ—΄ 수 μ—†μœΌλ―€λ‘œ νŒŒμΌμ„ 더블 ν΄λ¦­ν•΄μ„œ ν•΄λ‹Ή 파일 νƒ€μž…μ— μ‚¬μš©λ˜λŠ” μ‹œμŠ€ν…œ 에디터λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. λ¬Όλ‘  ν•΄λ‹Ή νŒŒμΌμ— 마우슀 였λ₯Έμͺ½ ν΄λ¦­ν•΄μ„œ Open With β–Έ Text Editor 메뉴λ₯Ό 선택해 λ‚΄μž₯된 ν…μŠ€νŠΈ 에디터λ₯Ό μ‚¬μš©ν•΄λ„ λ˜μ§€λ§Œ, DefoldλŠ” C++ νŒŒμΌμ„ μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μ΅œμ†Œν•œμ˜ νŽΈμ§‘ κΈ°λŠ₯만 μ‚¬μš© κ°€λŠ₯ν•©λ‹ˆλ‹€.

C++ file

μ΅μŠ€ν…μ…˜ μ†ŒμŠ€ νŒŒμΌμ€ μ•„λž˜ μ½”λ“œλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.

myextension.cpp

// Extension lib defines
#define LIB_NAME "MyExtension"
#define MODULE_NAME "myextension"

// include the Defold SDK
#include <dmsdk/sdk.h>

static int Rot13(lua_State* L)
{
    int top = lua_gettop(L);

    // μŠ€νƒμ—μ„œ λ¬Έμžμ—΄ νŒŒλΌλ―Έν„° μ²΄ν¬ν•˜κ³  κ°€μ Έμ˜€κΈ°
    const char* str = luaL_checkstring(L, 1);

    // μƒˆ λ¬Έμžμ—΄ ν• λ‹Ή
    int len = strlen(str);
    char *rot = (char *) malloc(len + 1);

    // νŒŒλΌλ―Έν„° λ¬Έμžμ—΄μ„ λ°˜λ³΅ν•΄μ„œ rot13 λ¬Έμžμ—΄ μƒμ„±ν•˜κΈ°
    for(int i = 0; i <= len; i++) {
        const char c = str[i];
        if((c >= 'A' && c <= 'M') || (c >= 'a' && c <= 'm')) {
            // A~M μ‚¬μ΄μ˜ char에 13 λ”ν•˜κΈ°
            rot[i] = c + 13;
        } else if((c >= 'N' && c <= 'Z') || (c >= 'n' && c <= 'z')) {
            // N~Z μ‚¬μ΄μ˜ char에 13을 λΉΌκΈ°
            rot[i] = c - 13;
        } else {
            // 문자λ₯Ό κ·ΈλŒ€λ‘œ μœ μ§€ν•¨
            rot[i] = c;
        }
    }

    // νšŒμ „λœ λ¬Έμžμ—΄μ„ μŠ€νƒμ— λ„£μŒ
    lua_pushstring(L, rot);

    // λ¬Έμžμ—΄ λ©”λͺ¨λ¦¬ ν•΄μ œ. LuaλŠ” μ§€κΈˆ λ³΅μ œλ³Έμ„ κ°€μ§€κ³  있음
    free(rot);

    // μŠ€νƒμ— ν•˜λ‚˜μ˜ μ•„μ΄ν…œμ΄ μžˆμŒμ„ assert 함
    assert(top + 1 == lua_gettop(L));

    // 1 μ•„μ΄ν…œ λ°˜ν™˜
    return 1;
}

// Lua에 λ…ΈμΆœλœ ν•¨μˆ˜
static const luaL_reg Module_methods[] =
{
    {"rot13", Rot13},
    {0, 0}
};

static void LuaInit(lua_State* L)
{
    int top = lua_gettop(L);

    // lua 이름을 λ“±λ‘ν•˜κΈ°
    luaL_register(L, MODULE_NAME, Module_methods);

    lua_pop(L, 1);
    assert(top == lua_gettop(L));
}

dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params)
{
    return dmExtension::RESULT_OK;
}

dmExtension::Result InitializeMyExtension(dmExtension::Params* params)
{
    // Init Lua
    LuaInit(params->m_L);
    printf("Registered %s Extension\n", MODULE_NAME);
    return dmExtension::RESULT_OK;
}

dmExtension::Result AppFinalizeMyExtension(dmExtension::AppParams* params)
{
    return dmExtension::RESULT_OK;
}

dmExtension::Result FinalizeMyExtension(dmExtension::Params* params)
{
    return dmExtension::RESULT_OK;
}


// Defold SDKλŠ” μ΅μŠ€ν…μ…˜ μ§„μž…μ μ„ μ…‹νŒ…ν•˜κΈ° μœ„ν•΄ 맀크둜λ₯Ό μ‚¬μš©ν•¨
//
// DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)

DM_DECLARE_EXTENSION(MyExtension, LIB_NAME, AppInitializeMyExtension, AppFinalizeMyExtension, InitializeMyExtension, 0, 0, FinalizeMyExtension)

DM_DECLARE_EXTENSION λ§€ν¬λ‘œλŠ” μ΅μŠ€ν…μ…˜ μ½”λ“œμ— λ‹€μ–‘ν•œ μ§„μž…μ (entry points)을 μ„ μ–Έν•˜λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€. 이 κ°„λ‹¨ν•œ μ˜ˆμ œμ—μ„œλŠ”, "update"λ‚˜ "on_event" μ§„μž…μ μ΄ ν•„μš”ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ λŒ€μ‹  0 값을 맀크둜 μΈμžκ°’μœΌλ‘œ λ³΄λƒ…λ‹ˆλ‹€.

이제 ν”„λ‘œμ νŠΈλ₯Ό λΉŒλ“œ(Project β–Έ Build and Launch)ν•  μ°¨λ‘€μž…λ‹ˆλ‹€. 이것은 μ΅μŠ€ν…μ…˜μ„ μ΅μŠ€ν…μ…˜ λΉŒλ”μ— μ—…λ‘œλ“œν•΄μ„œ μƒˆ μ΅μŠ€ν…μ…˜μ΄ ν¬ν•¨λœ μ»€μŠ€ν…€ 엔진을 μƒμ„±ν•©λ‹ˆλ‹€. λ§Œμ•½ λΉŒλ”μ— μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ λΉŒλ“œ μ—λŸ¬κ°€ μžˆλŠ” λŒ€ν™”μ°½μ„ ν‘œμ‹œν•©λ‹ˆλ‹€.

μ΅μŠ€ν…μ…˜μ„ ν…ŒμŠ€νŠΈν•˜λ €λ©΄, κ²Œμž„ 였브젝트λ₯Ό μƒμ„±ν•΄μ„œ μ•„λž˜μ™€ 같은 ν…ŒμŠ€νŠΈ μ½”λ“œκ°€ μžˆλŠ” 슀크립트 μ»΄ν¬λ„ŒνŠΈλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
local rot_s = myextension.rot13(s)
print(rot_s) --> nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM

이제 λμž…λ‹ˆλ‹€! μš°λ¦¬λŠ” μ™„μ „νžˆ 잘 λ™μž‘ν•˜λŠ” λ„€μ΄ν‹°λΈŒ μ΅μŠ€ν…μ…˜μ„ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

The ext.manifest file

λ©”λ‹ˆνŽ˜μŠ€νŠΈ νŒŒμΌμ—λŠ” μ΅μŠ€ν…μ…˜μ˜ 이름 외에도 νŠΉμ • ν”Œλž«νΌμ˜ compile flags, link flags, libs, frameworks λ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ•„λž˜μ— μ˜ˆμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

ext.manifest

name: "AdExtension"

platforms:
    arm64-ios:
        context:
            frameworks: ["CoreGraphics", "CFNetwork", "GLKit", "CoreMotion", "MessageUI", "MediaPlayer", "StoreKit", "MobileCoreServices", "AdSupport", "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreMotion", "CoreTelephony", "CoreVideo", "Foundation", "GLKit", "JavaScriptCore", "MediaPlayer", "MessageUI", "MobileCoreServices", "OpenGLES", "SafariServices", "StoreKit", "SystemConfiguration", "UIKit", "WebKit"]
            flags:      ["-stdlib=libc++"]
            linkFlags:  ["-ObjC"]
            libs:       ["z", "c++", "sqlite3"]

    armv7-ios:
        context:
            frameworks: ["CoreGraphics", "CFNetwork", "GLKit", "CoreMotion", "MessageUI", "MediaPlayer", "StoreKit", "MobileCoreServices", "AdSupport", "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreMotion", "CoreTelephony", "CoreVideo", "Foundation", "GLKit", "JavaScriptCore", "MediaPlayer", "MessageUI", "MobileCoreServices", "OpenGLES", "SafariServices", "StoreKit", "SystemConfiguration", "UIKit", "WebKit"]
            flags:      ["-stdlib=libc++"]
            linkFlags:  ["-ObjC"]
            libs:       ["z", "c++", "sqlite3"]

Known issues

λ„€μ΄ν‹°λΈŒ μ΅μŠ€ν…μ…˜ κΈ°λŠ₯은 μ•ŒνŒŒ(alpha) μƒνƒœμ΄λ―€λ‘œ, 아직 λͺ¨λ“  κΈ°λŠ₯이 μ€€λΉ„λ˜μ§€λŠ” μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

  • Platforms: ν˜„μž¬λŠ” macOS, iOS, Android μ΅μŠ€ν…μ…˜ λΉŒλ“œλ§Œ μ§€μ›ν•©λ‹ˆλ‹€.
  • Android λŠ” .java 와 .jar archives 에 λŒ€ν•œ 지원이 λΆ€μ‘±ν•©λ‹ˆλ‹€.
  • Editor: 에디터 톡합(editor integration). λΉŒλ“œ ν”„λ‘œμ„ΈμŠ€κ°€ ν‘œμ‹œλ˜μ§€ μ•Šκ³  μ—λŸ¬ λ¦¬ν¬νŒ… κΈ°λŠ₯도 아직 λͺ‡λͺ‡ κΈ°λŠ₯만 μ§€μ›λ©λ‹ˆλ‹€.
  • Debugging: ν˜„μž¬, iOSμ—μ„œ λΉŒλ“œν•˜λŠ” 경우, .dSYM 파일이 κ²°κ³Ό λΉŒλ“œμ— ν¬ν•¨λ˜κ³  μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€.