ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] Native Application(C/C++), NDK build ๋ฐ CMake ๊ตฌ์„ฑ
    Android 2022. 2. 14. 23:01
    ๋ฐ˜์‘ํ˜•

    Native Application

      Android NDK๋Š” C ๋˜๋Š” C++๋ฅผ Android ์•ฑ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์€ ์ด์œ ๋กœ Android ํ”„๋กœ์ ํŠธ์— C ๋ฐ C++ ์ฝ”๋“œ ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€๊ฐ€ ํ•„์š”ํ•  ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

     

    • ํ”Œ๋žซํผ ๊ฐ„ ์•ฑ ํ˜ธํ™˜์„ฑ
    • ๊ธฐ์กด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์žฌ์‚ฌ์šฉ, ์žฌ์‚ฌ์šฉํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(.so) ์ œ๊ณต
    • ๊ฒŒ์ž„ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ๊ฐ™์€ ์•ฑ ์„ฑ๋Šฅ ํ–ฅ์ƒ

       Android Studio์—์„œ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ปดํŒŒ์ผ ๋„๊ตฌ๋กœ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ํ”„๋กœ์ ํŠธ์— ์ ํ•ฉํ•œ CMake์™€ CMake๋ณด๋‹ค ๋น ๋ฅด์ง€๋งŒ Android๋งŒ ์ง€์›ํ•˜๋Š” ndk-build๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ์— CMake์™€ ndk-build๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ˜„์žฌ ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ndk-build๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ CMake๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• 2๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

     

     

    ๊ธฐ๋ณธ ๊ตฌ์„ฑ์š”์†Œ

      ๋„ค์ดํ‹ฐ๋ธŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๊ธฐ ์ „์— ๊ฐ๊ฐ์˜ ๊ตฌ์„ฑ์š”์†Œ๋“ค์— ๋Œ€ํ•ด ํŒŒ์•…์„ ํ•˜๋ฉด ๋น ๋ฅด๊ฒŒ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    • Shared Library : ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” .so ํŒŒ์ผ์„ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.
    • Static Library : ์ •์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” .a ํŒŒ์ผ์„ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.
    • Java Native Interface(JNI) : ์ž๋ฐ”์™€ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ์™€ ์—ฐ๊ฒฐํ•ด ์ฃผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.
    • Application Binary Interface(ABI) : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋ฐ”์ด๋„ˆ๋ฆฌ(๊ธฐ๊ณ„์–ด)์™€ ์—ฐ๊ฒฐํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‹ค์–‘ํ•œ Android ๊ธฐ๊ธฐ๋Š” ๊ฐ๊ธฐ ๋‹ค๋ฅธ CPU๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์„œ๋กœ ๋‹ค๋ฅธ ๋ช…๋ น ์ง‘ํ•ฉ์„ ์ง€์›ํ•˜๊ธฐ์— ABI ๋ช…์‹œํ•˜์—ฌ ์‹œ์Šคํ…œ๊ณผ ์–ด๋–ป๊ฒŒ ์ƒํ˜ธ์ž‘์šฉํ• ์ง€ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • Manifest

     

        Android์šฉ ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ์ผ๋ฐ˜์ ์ธ ํ๋ฆ„์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

     

    1. ์•ฑ์˜ ์„ค๊ณ„์— ๋งž๊ฒŒ Java๋กœ ๊ตฌํ˜„ํ•  ๋ถ€๋ถ„๊ณผ ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ๊ตฌํ˜„ํ•  ๋ถ€๋ถ„์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
    2. Android ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    3. JNI ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ชจ๋“ˆ ์ด๋ฆ„, ์—ฐ๊ฒฐ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์ปดํŒŒ์ผํ•  ์†Œ์Šค ํŒŒ์ผ ๋“ฑ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ ๋นŒ๋“œ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•œ Android.mk ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    4. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ABI, STL ๋“ฑ์„ ๊ตฌ์„ฑํ•˜๋Š” Application.mk ํŒŒ์ผ๋„ ๋งŒ๋“ค์–ด JNI ํด๋” ์•„๋ž˜์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
    5. ndk-build๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋„ค์ดํ‹ฐ๋ธŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(.so, .a)๋ฅผ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค.
    6. ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ .dex ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ์ž๋ฐ” ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.
    7. ์•ฑ ์‹คํ–‰์— ํ•„์š”ํ•œ .so, .dex ๋ฐ ๊ธฐํƒ€ ๋ฆฌ์†Œ์Šค๋“ค์„ ๋น„๋กฏํ•˜์—ฌ ๋ชจ๋“  ํ•ญ๋ชฉ์„ APK ํŒŒ์ผ์— ํŒจํ‚ค์ง•ํ•ฉ๋‹ˆ๋‹ค.

     

    NDK build ๋กœ ๊ตฌ์„ฑ

      ndk-build ์Šคํฌ๋ฆฝํŠธ๋Š” NDK์˜ Make ๊ธฐ๋ฐ˜ ๋นŒ๋“œ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. ndk-build๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” jni ํด๋”  ์•„๋ž˜์— Android.mk ๋ฐ Application.mk ๊ฐ€ ๊ตฌ์„ฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ ndk-build๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์„ฑํ•˜๋Š” ๋ฒ•๊ณผ ndk-build ์ปค๋ฉ˜๋“œ๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•ด์„œ C ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์›Œ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

     

      NDK ์„ค์น˜๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ Tools > SDK Manager์—์„œ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. NDK๊ฐ€ ์„ค์น˜๋˜๋ฉด ๋‚ด๋ถ€์— ndk-build ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ndk-build๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” jni ํด๋” ์•„๋ž˜์— Android.mk, Application.mk๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

     

    Application.mk 

    APP_ABI := all
    APP_PLATFORM := android-16
    APP_STL := c++_static
    APP_ALLOW_MISSING_DEPS := true

     Application.mk๋Š” ndk-build์˜ ํ”„๋กœ์ ํŠธ ์ „์ฒด ์„ค์ •์„ ์ง€์ •ํ•˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ jni/Application.mk์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ ๋‚ด์— ์ •์˜ ๋˜์–ด ์žˆ๋Š” ๋ณ€์ˆ˜๋“ค์€ ๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ์ž์„ธํ•˜๊ฒŒ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

     

    Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := jnicalculator
    LOCAL_SRC_FILES := calculator.cpp
    
    include $(BUILD_SHARED_LIBRARY)

      ๋‹ค์Œ์€ jni ํด๋” ์•„๋ž˜์— ์ •์˜๋˜์–ด ์žˆ๋Š” Android.mk ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. Android.mk๋Š” ๋นŒ๋“œ ์‹œ์Šคํ…œ์˜ ์†Œ์Šค ํŒŒ์ผ ๋ฐ ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ์—ฌ๋Ÿฌ ์†Œ์ŠคํŒŒ์ผ์„ ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ๋กœ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ชจ๋“ˆ์ด๋ผ๋Š” ๊ฒƒ์€ ์ •์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(.a), ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(.so), ๋˜๋Š” ์‹คํ–‰ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œ ์‹œ์Šคํ…œ์—์„œ๋Š” ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํŒจํ‚ค์ง€์— ๋„ฃ์„ ๋ฟ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ํŒŒ์ผ์—์„œ๋Š” jnicalculator ๋ผ๋Š” ๋ชจ๋“ˆ์ด๋ฆ„์œผ๋กœ ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋นŒ๋“œ๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด libjnicalculator.so ํŒŒ์ผ์ด ์ƒ๊ฒจ๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.  ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ ๋ณ€์ˆ˜๋“ค์— ๋Œ€ํ•ด์„œ๋Š” ๊ณต์‹๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

     

      ndk-build ๊ฒฐ๊ณผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋นŒ๋“œ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

     

     

    Java Code ๊ตฌํ˜„

    ๋ช…๋ น์–ด๋กœ ์ง์ ‘ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    public class MainActivity extends AppCompatActivity {
    
        static {
            System.loadLibrary("jnicalculator");
        }
    
        public native int getSum(int num1, int num2);
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            int num1 = 10;
            int num2 = 20;
    
            int sum = getSum(10, 20);
            Toast.makeText(this, "sum : " + sum, Toast.LENGTH_LONG).show();
        }
    }

      ๋‹ค์Œ์€ ์ž๋ฐ” ์†Œ์Šค์ฝ”๋“œ๋กœ intํ˜• ์ˆซ์ž๋ฅผ ๋‘ ๊ฐœ๋ฅผ ๊ฐ€์ง€๊ณ  ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ณผ ๊ฐ’์„ ๋ฐ›์•„์„œ ํ† ์ŠคํŠธ ๋ฉ”์„ธ์ง€๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

     

        static {
            System.loadLibrary("jnicalculator");
        }

      ๋จผ์ € System.loadLibrary("jnicalculator") ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ .so ํŒŒ์ผ์ด ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค. ์œ„ ์ชฝ์—์„œ Android.mk์— ๋ชจ๋“ˆ ์ •์˜ํ•  ๋•Œ jnicalculator๋กœ ์„ค์ •ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— libjnicalculator.so๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๊ณ  System.loadLibrary ๋ฉ”์†Œ๋“œ์—๋Š” lib๊ณผ .so ๋ฅผ ์ƒ๋žตํ•˜๊ณ  ๋ชจ๋“ˆ๋ช…๋งŒ ์ž…๋ ฅํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. 

     

        public native int getSum(int num1, int num2);

        ์œ„ ๋ฉ”์„œ๋“œ ์„ ์–ธ์—์„œ native ํ‚ค์›Œ๋“œ๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ๋„ค์ดํ‹ฐ๋ธŒ ์ชฝ์— ๊ตฌํ˜„๋˜์–ด ์žˆ์Œ์„ JVM์—๊ฒŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

     

     

    C Code ๊ตฌํ˜„

    #include "calculator.h"
    
    JNIEXPORT jint JNICALL Java_com_example_ndkapplication_MainActivity_getSum(
            JNIEnv* env, jobject thiz, jint num1, jint num2){
        return num1+num2;
    }

      ์œ„ ์ฝ”๋“œ๋Š” ์ž๋ฐ” ์ฝ”๋“œ์—์„œ ๋‘ ๊ฐ€์ง€์˜ intํ˜• ์ˆซ์ž๋ฅผ ๋ฐ›์•„์„œ ๋ง์…ˆ์„ ๊ณ„์‚ฐํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ž๋ฐ” ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์„ ์–ธ๋œ ๋„ค์ดํ‹ฐ๋ธŒ ํ•จ์ˆ˜์™€ ์ƒ์‘ํ•˜๋ฉฐ ๋ฐ˜ํ™˜ ์œ ํ˜•์€ jint๋กœ ์ž๋ฐ” ๋„ค์ดํ‹ฐ๋ธŒ ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์–‘์— ์ •์˜๋œ ๋ฐ์ดํ„ฐ ์œ ํ˜•์ž…๋‹ˆ๋‹ค. jint ๋’ค์—๋Š” ํ•จ์ˆ˜ ์ด๋ฆ„์œผ๋กœ ํŒจํ‚ค์ง€ ๋ช… + ์ž๋ฐ” ํ•จ์ˆ˜ ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

     

    • ์•ž์— Java_๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    • ํŒจํ‚ค์ง€๋ช…(์ตœ์ƒ์œ„ ์†Œ์Šค ๋””๋ ‰ํ† ๋ฆฌ์˜ ์ƒ๋Œ€์ ์ธ ํŒŒ์ผ ๊ฒฝ๋กœ), .์€ _๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.
    • ์•กํ‹ฐ๋น„ํ‹ฐ ๋ช…์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    • ๋งˆ์ง€๋ง‰์—๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

    ์ด๋Ÿฌํ•œ ๊ทœ์น™์„ ํ†ตํ•ด์„œ ํ•จ์ˆ˜ ์ด๋ฆ„์ด Java_com_example_ndkapplication_MainActivity_getSum์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ์ด๋ฆ„์ด getSum() ์ด๋ผ๋Š” ์ž๋ฐ” ํ•จ์ˆ˜ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. 

     

     

    C header  ๊ตฌํ˜„

    #include <jni.h>
    /* Header for class com_example_ndkapplication_MainActivity */
    
    #ifndef _Included_com_example_ndkapplication_MainActivity
    #define _Included_com_example_ndkapplication_MainActivity
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_example_ndkapplication_MainActivity
     * Method:    getSum
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_com_example_ndkapplication_MainActivity_getSum
      (JNIEnv *, jobject, jint, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif

      header ์ถ”๊ฐ€๋Š” javah Tool์„ ์ •์˜ํ•˜์—ฌ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜ ๋ธ”๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    https://math-coding.tistory.com/177

     

    [Android] ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค NDK ์‚ฌ์šฉ๋ฒ•

    NDK๋ž€? ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ(C/C++)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž๋ฐ” ์ด์™ธ์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ(C/C++)์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” JNI(Java Native Interface)๋ผ๋Š” ์ธํ„ฐํŽ˜์ด

    math-coding.tistory.com

     

     

    Gradle ๊ตฌ์„ฑ

     ๋„ค์ดํ‹ฐ๋ธŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ”„๋กœ์ ํŠธ๋ฅผ Gradle ๋นŒ๋“œ ์ข…์† ํ•ญ๋ชฉ์œผ๋กœ ํฌํ•จํ•˜๋ ค๋ฉด Gradle์— CMake ๋˜๋Š” ndk-build ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•ฑ์„ ๋นŒ๋“œํ•˜๋ฉด  Gradle์€ CMake ๋˜๋Š” ndk-build๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์•ฑ์œผ๋กœ ํŒจํ‚ค์ง•ํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜๋™์œผ๋กœ Gradle์„ ๊ตฌ์„ฑํ•˜์—ฌ ๋„ค์ดํ‹ฐ๋ธŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ๋ชจ๋“ˆ ์ˆ˜์ค€ build.gralde ํŒŒ์ผ์— externalNativeBuild ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ cmake ๋˜๋Š” ndkBuild ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

        externalNativeBuild {
            ndkBuild {
                path file('src/main/jni/Android.mk')
            }
        }

      ์œ„ ์˜ˆ์‹œ์—์„œ๋Š” ndkBuild๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ์— Gradle์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑํ•˜๋ฉด ๋นŒ๋“œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๋ฐ˜์‘ํ˜•

     

    CMake ๋กœ ๊ตฌ์„ฑ

      CMake ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ๋Š” CMakeLists.txt๋กœ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์•ผ ํ•˜๋Š” ํ…์ŠคํŠธ ํŒŒ์ผ์ด๋ฉฐ ํฌ๋กœ์Šค ํ”Œ๋žซํผ์— ์ ํ•ฉํ•œ ๋นŒ๋“œ ํˆด์ž…๋‹ˆ๋‹ค. C/C++ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ช…๋ น์–ด๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ndk-build ๋กœ ๋นŒ๋“œ ์‹œ์—๋Š” Android.mk, Application.mk ๋“ฑ ๋งŽ์€ ๊ฒƒ์„ ์ง์ ‘ ์ถ”๊ฐ€๋ฅผ ํ•ด์•ผํ–ˆ์ง€๋งŒ, CMake ๋นŒ๋“œ๋Š” Project ์ƒ์„ฑ ์‹œ Native C++ Project๋กœ ์„ ํƒํ•˜๊ฒŒ ๋˜๋ฉด ์ž๋™์œผ๋กœ ๊ธฐ๋ณธ ๊ตฌ์„ฑ์ด ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

     

     

    CMakeLists.txt ์„ค์ •

    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    
    cmake_minimum_required(VERSION 3.10.2)
    
    # Declares and names the project.
    
    project("cmakeapplication")
    
    # Creates and names a library, sets it as either STATIC
    # or SHARED, and provides the relative paths to its source code.
    # You can define multiple libraries, and CMake builds them for you.
    # Gradle automatically packages shared libraries with your APK.
    
    add_library( # Sets the name of the library.
            cmakecalculator
    
            # Sets the library as a shared library.
            SHARED
    
            # Provides a relative path to your source file(s).
            calculator.cpp)
    
    # Searches for a specified prebuilt library and stores the path as a
    # variable. Because CMake includes system libraries in the search path by
    # default, you only need to specify the name of the public NDK library
    # you want to add. CMake verifies that the library exists before
    # completing its build.
    
    find_library( # Sets the name of the path variable.
            log-lib
    
            # Specifies the name of the NDK library that
            # you want CMake to locate.
            log)
    
    # Specifies libraries CMake should link to your target library. You
    # can link multiple libraries, such as libraries you define in this
    # build script, prebuilt third-party libraries, or system libraries.
    
    target_link_libraries( # Specifies the target library.
            cmakecalculator
    
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib})

     ๋‹ค์Œ์€ CMakeLists.txt์— ์ž‘์„ฑ๋œ ์Šคํฌ๋ฆฝํŠธ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

     

    • add_library : ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” ์ •์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฅผ ์ƒ์„ฑ, ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์†Œ์Šค์ฝ”๋“œ ์ž…๋ ฅ
    • find_library : ์ด๋ฏธ ๋นŒ๋“œ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ช… ์ง€์ •, log-lib(์•ˆ๋“œ๋กœ์ด๋“œ ๋กœ๊ทธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)
    • target_link_libraries : CMake์— ์–ด๋–ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ๋งํฌํ• ์ง€ ๋ช…์‹œ

    ์ด๋ณด๋‹ค ๋” ์ž์„ธํ•˜๊ณ  ์ƒ์„ธํ•œ ๋ช…๋ น์–ด๋“ค์€ ๊ณต์‹๋ฌธ์„œ ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

     

    Java Code ๊ตฌํ˜„

    public class MainActivity extends AppCompatActivity {
    
        // Used to load the 'cmakeapplication' library on application startup.
        static {
            System.loadLibrary("cmakecalculator");
        }
    
        private ActivityMainBinding binding;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            binding = ActivityMainBinding.inflate(getLayoutInflater());
            setContentView(binding.getRoot());
    
            // Example of a call to a native method
            TextView tv = binding.sampleText;
            tv.setText(String.valueOf(getSum(10,20)));
        }
    
        public native int getSum(int num1, int num2);
    }

      nkd-build์™€ ์ฐจ์ด๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์„ค๋ช…์€ ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•˜๊ฒŒ libcmakecalculator.so ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

     

    C Code ๊ตฌํ˜„

    #include <jni.h>
    
    extern "C" JNIEXPORT jint JNICALL
    Java_com_example_cmakeapplication_MainActivity_getSum(
            JNIEnv* env,
            jobject /* this */,
            jint num1,
            jint num2) {
        return num1 + num2;
    }

      C Code๋„ ndk-build ์‹œ์— ์„ค์ •ํ•œ ํ•จ์ˆ˜ ์ด๋ฆ„๊ณผ ๋™์ผํ•œ ๊ทœ์น™์ด ์ ์šฉ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

     

     

    Gradle ๊ตฌ์„ฑ

      Project ์„ค์ • ์‹œ Native C++ Project๋กœ ์ง€์ •ํ•˜๊ฒŒ ๋˜๋ฉด ์ž๋™์œผ๋กœ ๋ชจ๋“ˆ ์ˆ˜์ค€ build.gradle์— ํฌํ•จ์ด ๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด CMakeLists.txt ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๋ฉด ๋„ค์ดํ‹ฐ๋ธŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

        externalNativeBuild {
            cmake {
                path file('src/main/cpp/CMakeLists.txt')
                version '3.10.2'
            }
        }

     

     CMake๋กœ ๊ตฌ์„ฑ ์‹œ์— ABI ์ง€์ •์€ ndk-build์™€ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ndk-build๋Š” Application.mk์—์„œ APP_ABI ๋ณ€์ˆ˜๋กœ ์„ค์ •์„ ํ•˜์˜€๋‹ค๋ฉด CMake๋กœ ๊ตฌ์„ฑํ•˜๊ฒŒ ๋˜๋ฉด build.gradle์— ํฌํ•จ์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    android {
      ...
      defaultConfig {
        ...
        externalNativeBuild {
          cmake {...}
          // or ndkBuild {...}
        }
    
        // Similar to other properties in the defaultConfig block,
        // you can configure the ndk block for each product flavor
        // in your build configuration.
        ndk {
          // Specifies the ABI configurations of your native
          // libraries Gradle should build and package with your app.
          abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
                       'arm64-v8a'
        }
      }
      buildTypes {...}
      externalNativeBuild {...}
    }

     ์œ„์ฒ˜๋Ÿผ ndk.abiFilters ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ง€์ •์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์›ํ•˜๋Š” ABI๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ABI์— ๋Œ€ํ•ด์„œ ์ถ”๊ฐ€๋ฅผ ํ•˜๊ณ  ์‹ถ์œผ๋ฉด all๋กœ ์ง€์ •์„ ํ•ด๋„ ๋ฌด๋ฐฉํ•ฉ๋‹ˆ๋‹ค.

     

     

    ๋„ค์ดํ‹ฐ๋ธŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

      ๋Ÿฐํƒ€์ž„์— ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. RegisterNative ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ช…์‹œ์ ์œผ๋กœ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ๋ฅผ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ์œ„์—์„œ ํŠน์ • ์ด๋ฆ„ ๊ทœ์น™์œผ๋กœ ์ง€์ •ํ•˜๋Š” ๋ฐฉ์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค. RegisterNative์˜ ์žฅ์ ์€  ๋ฉ”์†Œ๋“œ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๋ฏธ๋ฆฌ ํ™•์ธํ•˜๊ณ  JNI_OnLoad ์ด์™ธ์˜ ๋ฉ”์†Œ๋“œ๋Š” ํ™•์ธํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋น ๋ฅธ ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

     

    • JNIEXPORT jint JNI_OnLoad(JavaVM* vm , void* reserved) ํ•จ์ˆ˜ ์ œ๊ณต
    • JNI_OnLoad ์—์„œ RegisterNatives ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ ๋“ฑ๋ก
    jint getSum(JNIEnv *env, jobject thiz, jint num1, jint num2) {
        return num1 + num2;
    }
    
    jint JNI_OnLoad(JavaVM *vm, void *reserved) {
        JNIEnv *env;
        if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
            return JNI_ERR;
        }
    
        jclass c = env->FindClass("com/example/cmakeapplication/MainActivity");
        if (c == nullptr) return JNI_ERR;
    
        static const JNINativeMethod methods[] = {
                {"getSum", "(II)I", (void*)getSum}
        };
    
        int rc = env->RegisterNatives(c, methods, sizeof(methods) / sizeof(JNINativeMethod));
        if (rc != JNI_OK) return rc;
    
        return JNI_VERSION_1_6;
    }

      JNI_OnLoad ์—์„œ FindClass ํ˜ธ์ถœ์„ ์‹คํ–‰ํ•˜๋ฉด ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋กœ๋“œํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ์ฐพ์€ ํ›„ JNINativeMethod์— ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. JNINativeMethod ๊ทœ์น™์€ name, signature, function name ์„ ์ž…๋ ฅํ•˜๊ฒŒ ๋˜๊ณ , signature์—๋Š” ๊ด„ํ˜ธ ์•ˆ์—๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ด„ํ˜ธ ๋ฐ–์€ ๋ฐ˜ํ™˜ ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ RegisterNatives ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค์˜ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก์„ ํ•˜๊ฒŒ ๋˜๋ฉด ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

     

     

    ์ฐธ๊ณ 

    https://developer.android.com/studio/projects/add-native-code?hl=ko 

     

    C ๋ฐ C++ ์ฝ”๋“œ๋ฅผ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€  |  Android ๊ฐœ๋ฐœ์ž  |  Android Developers

    C ๋ฐ C++ ์ฝ”๋“œ๋ฅผ Android ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์„ธ์š”.

    developer.android.com

    https://developer.android.com/ndk/samples/sample_hellojni?hl=ko 

     

    ์ƒ˜ํ”Œ: hello-jni  |  Android NDK  |  Android Developers

    ์ƒ˜ํ”Œ: hello-jni ์ด ์ƒ˜ํ”Œ์—์„œ๋Š” NDK๋กœ ๋นŒ๋“œํ•œ ์ž‘์€ C/C++ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ธ hello-jni๋ฅผ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค. ์ด ์ƒ˜ํ”Œ์€ android-mk ๋ถ„๊ธฐ ๋‚ด ndk-samples ์ €์žฅ์†Œ์˜ hello-jni ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์žˆ์Šต๋‹ˆ๋‹ค. Android.mk ๋‹ค์Œ ๋‘ ์ค„์€ ๋„ค์ด

    developer.android.com

    https://developer.android.com/training/articles/perf-jni#native-libraries

     

    JNI ๋„์›€๋ง  |  Android NDK  |  Android Developers

    JNI ๋„์›€๋ง JNI๋Š” Java Native Interface(์ž๋ฐ” ๋„ค์ดํ‹ฐ๋ธŒ ์ธํ„ฐํŽ˜์ด์Šค)์˜ ์•ฝ์–ด์ž…๋‹ˆ๋‹ค. JNI๋Š” Android๊ฐ€ ๊ด€๋ฆฌ ์ฝ”๋“œ์—์„œ ์ปดํŒŒ์ผํ•˜๋Š” ๋ฐ”์ดํŠธ ์ฝ”๋“œ(์ž๋ฐ” ๋˜๋Š” Kotlin ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋กœ ์ž‘์„ฑ๋จ)์™€ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ(C/C+

    developer.android.com

     

    ๋ฐ˜์‘ํ˜•
Designed by Tistory.