🌐 한국어

    빌드하기#

    Oasis 응용 프로그램 개발과 빌드는 주로 호스트 PC (x86_64 Ubuntu 등)에서 진행됩니다.

    Oasis는 컴포넌트 별로 구성되어 있어서 응용 프로그램이 사용하는 컴포넌트 라이브러리만 사용하여 빌드합니다.

    Oasis 응용 프로그램이 실행되는 타겟 장치의 프로세서가 호스트 PC의 프로세서와 다르거나 바이너리상 호환이 안 되는 경우, 크로스 컴파일을 합니다.

    여기서는 Makefile을 이용하여 빌드하는 방법CMake를 이용하여 빌드하는 방법을 설명합니다.

    타겟 장치 프로세서가 aarch64 이며 호스트 PC에 GCC 크로스툴 체인이 /opt/vtcs_toolchain/leipzig 에 설치되어 있다고 가정합니다.

    Oasis SDK는 호스트 PC의 아래 폴더에 있다고 가정합니다.

    • 라이브러리 /opt/oasis/sdk-4.3.29/lib
    • 헤더파일 /opt/oasis/sdk-4.3.29/include

    hello.cpp#

    아래 코드(hello.cpp)는 빌드 과정 설명을 위한 응용 프로그램 코드입니다.

    빌드를 마치면 hello 라는 Oasis 응용 프로그램이 생성됩니다.

    #include "OasisAPI.h"
    #include "OasisLog.h"
    #include "OasisUI.h"
    #include "OasisUtil.h"
    #include "OasisDisplay.h"
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <dirent.h>
    
    #include <thread>
    #include <mutex>
    #include <memory>
    #include <condition_variable>
    
    
    #undef DLOG_TAG
    #define DLOG_TAG "Hello"
    
    
    using namespace oasis;
    
    bool got_interrupt = false;
    
    #include <signal.h>
    
    //SIGINT 핸들러입니다. 프로그램을 종료합니다.
    void cancel_handler(int sig)
    {
      got_interrupt = true;
    }
    
    //Capture Me! 버튼이 클릭되었을 때 호출되는 함수입니다. 스크린을 캡춰하여 /tmp에 저장합니다.
    void captureMeClicked(ui::WidgetRef widget)
    {
      ui::ScreenRef screen = ui::getDefaultScreen();
    
      std::vector<uint8_t> png_data;
      char image_path[PATH_MAX];
      time_t t;
      struct tm tm_t;
      time(&t);
      localtime_r(&t, &tm_t);    
    
      sprintf(image_path, "/tmp/snapshot_%4d-%02d-%02d-%02d-%02d-%02d.png", tm_t.tm_year + 1900, tm_t.tm_mon + 1, tm_t.tm_mday, tm_t.tm_hour, tm_t.tm_min, tm_t.tm_sec);
      if(ui::takeScreenShot(screen, png_data) > 0) {
        printf("saved to %s\n", image_path);
        writeFile(png_data.data(), png_data.size(), image_path);
      }
    }
    
    //Goodbye! 버튼이 클릭되었을 때 호출되는 함수입니다. 프로그램을 종료합니다.
    void goodbyeClicked(ui::WidgetRef widget)
    {
      got_interrupt = true;
    }
    
    int main(int argc, char *argv[])
    {
      int32_t err;
    
      signal(SIGINT, cancel_handler);
    
      oasis::key_value_map_t parameters;
    
      //Oasis를 초기화합니다. Oasis 파일 시스템을 비활성화합니다.
      parameters["offs-disable"] = "1";
      if(oasis::initialize(parameters) < 0) {
        DLOG(DLOG_ERROR, "Oasis init failed\n");
        return -1;
      }
    
    
      //디스플레이 장치를 초기화합니다.
      parameters.clear();
    
      parameters["memory-type"] = "ion"; //cma
      parameters["screen-width"] = "480";
      parameters["screen-height"] = "320";
    
      display::setup(parameters);
    
      //GUI를 초기화합니다.
      parameters.clear();
    
      parameters["system-font-size"] = "11";
      parameters["system-font-path"] = "/mnt/sd/NanumGothicCoding.ttf";
      parameters["display-rotation"] = "0";
      parameters["enable-touch"] = "1";
      parameters["touch-cal-data-path"] = "/mnt/sd/cal.dat";
    
      err = ui::setup(parameters);
      if (err < 0) {
        DLOG(DLOG_ERROR, "Oasis ui::setup failed\n");
        oasis::finalize();
        return -1;
      }
    
      //디폴트 화면 객체를 얻습니다.
      ui::ScreenRef screen = ui::getDefaultScreen();
    
      //최상위 Window를 생성합니다. 생성시 보이지 않습니다.
      ui::WindowRef window = ui::createWindow("Hello");
    
      //최상위 Window에 세로 Box 레이아웃 객체를 생성합니다.
      ui::BoxRef vbox = ui::createBox(ui::kOrientationVertical, false, 6);
      //Box 레이아웃은 Window에 추가된 후 중앙에 배치되도록 합니다.
      ui::setVAlign(vbox, ui::kAlignCenter);
    
      //라벨1,2,3를 생성하고 각각 Box 레이아웃에 추가합니다.
      ui::LabelRef label = ui::createLabelWithText("Hello, World!");
      ui::setVAlign(label, ui::kAlignCenter);
      ui::setHAlign(label, ui::kAlignCenter);
      ui::setLabelHorzJustification(label, ui::kJustificationCenter);
      ui::setLabelVertJustification(label, ui::kJustificationCenter);
      ui::setLabelFontPointSize(label, 16);
    
      ui::boxPackStart(vbox, label, true, true, 0);
    
      ui::LabelRef label2 = ui::createLabelWithText("안녕하세요!");
      ui::setVAlign(label2, ui::kAlignCenter);
      ui::setHAlign(label2, ui::kAlignCenter);
      ui::setLabelHorzJustification(label2, ui::kJustificationCenter);
      ui::setLabelVertJustification(label2, ui::kJustificationCenter);
      ui::setLabelFontPointSize(label2, 13);
    
      ui::boxPackStart(vbox, label2, true, true, 0);
    
      ui::LabelRef label3 = ui::createLabelWithText("こんにちは!");
      ui::setVAlign(label3, ui::kAlignCenter);
      ui::setHAlign(label3, ui::kAlignCenter);
      ui::setLabelHorzJustification(label3, ui::kJustificationCenter);
      ui::setLabelVertJustification(label3, ui::kJustificationCenter);
      ui::setLabelFontPointSize(label3, 13);
    
      ui::boxPackStart(vbox, label3, true, true, 0);
    
      //Goodbye! 버튼을 생성하고 Box 레이아웃 끝쪽부터 추가합니다.
      ui::ButtonRef close_button = ui::createButtonWithLabel("Goodbye!", true);
      ui::setID(close_button, "close_button");
      ui::setLabelFontPointSize(ui::getButtonLabel(close_button), 13);
      ui::setLabelTextColor(ui::getButtonLabel(close_button), Color(255, COLOR_YELLOW));
      ui::setVAlign(close_button, ui::kAlignCenter);
      ui::setHAlign(close_button, ui::kAlignCenter);
      ui::boxPackEnd(vbox, close_button, false, true, 0);
    
      //Capture Me! 버튼을 생성하고 Box 레이아웃 끝쪽부터 추가합니다.
      ui::ButtonRef capture_button = ui::createButtonWithLabel("Capture Me!", true);
      ui::setID(capture_button, "capture_me_button");
      ui::setLabelFontPointSize(ui::getButtonLabel(capture_button), 13);
      ui::setLabelTextColor(ui::getButtonLabel(capture_button), Color(255, COLOR_YELLOW));
      ui::setVAlign(capture_button, ui::kAlignCenter);
      ui::setHAlign(capture_button, ui::kAlignCenter);
      ui::boxPackEnd(vbox, capture_button, false, true, 20);
    
      //Capture Me! 버튼 클릭 이벤트 호출 함수를 연결합니다.
      ui::connectSignal(capture_button, "clicked", clicked_slot_t(sig::ptr_fn(&captureMeClicked)), 0);
    
      //Goodbye! 버튼 클릭 이벤트 호출 함수를 연결합니다.
      ui::connectSignal(close_button, "clicked", clicked_slot_t(sig::ptr_fn(&goodbyeClicked)), 0);
    
      //최상위 Window에 Box 레이아웃을 추가합니다.
      ui::containerAdd(window, vbox);
      //화면에 Window를 추가합니다.
      ui::screenAdd(screen, window);
    
      //최상위 Window가 보이도록 합니다.
      ui::setVisible(window, true);
    
      //메인 쓰레드가 종료 신호를 받을 때까지 기다립니다.
      do {
        usleep(100000);
      } while(got_interrupt == false);
    
      //GUI를 해제합니다.
      err = ui::cleanup();
    
      //Oasis를 해제합니다.
      oasis::finalize();
    
      return 0;
    }
    

    Makefile 빌드#

    1. hello.cpp가 있는 소스 폴더에 Makefile 파일을 아래 내용으로 생성합니다.

      # 크로스 툴체인 환경을 설정합니다.
      CROSS_COMPILER_PREFIX = aarch64-linux-
      EXTERNAL_TOOLCHAIN_ROOT = /opt/vtcs_toolchain/leipzig/usr/
      EXTERNAL_TOOLCHAIN_PATH = $(EXTERNAL_TOOLCHAIN_ROOT)bin/
      SYSROOT = $(EXTERNAL_TOOLCHAIN_ROOT)/aarch64-buildroot-linux-gnu/sysroot
      
      CC = $(EXTERNAL_TOOLCHAIN_PATH)$(CROSS_COMPILER_PREFIX)gcc
      CXX = $(EXTERNAL_TOOLCHAIN_PATH)$(CROSS_COMPILER_PREFIX)g++
      LD = $(EXTERNAL_TOOLCHAIN_PATH)$(CROSS_COMPILER_PREFIX)ld
      AR = $(EXTERNAL_TOOLCHAIN_PATH)$(CROSS_COMPILER_PREFIX)ar
      
      # Oasis SDK 환경을 설정합니다.
      OASIS_SDK_ROOT = /opt/oasis/sdk-4.3.29/
      OASIS_INC_PATH = $(OASIS_SDK_ROOT)/include
      OASIS_LIB_PATH = $(OASIS_SDK_ROOT)/lib
      OASIS_LIBS = -loasis_codec -loasis_fs -loasis_pipe -loasis_media -loasis_ui -loasis_util -loasis_certs -loasis_disp -loasis
      OASIS_DEFS = -DOASIS_NO_NVWA
      
      # 타겟을 설정합니다.
      TARGET = hello
      SRCS = hello.cpp
      OBJS = $(SRCS:.cpp=.o)
      
      CXXFLAGS += -I$(OASIS_INC_PATH) --sysroot=$(SYSROOT)
      LDFLAGS += -s -L$(OASIS_LIB_PATH) $(OASIS_LIBS)
      
      CXXFLAGS += -std=c++17 -O2 -g $(OASIS_DEFS)
      
      # 기타 의존적인 라이브러리를 설정합니다.
      LIBS = -lexif -lpng16 -ljpeg -lfreetype -lz -ljsoncpp -lrt -lpthread -lcva -lvmf_nnm -lvmf -lvdec -lutil -liniparser
      
      .PHONY: all clean
      
      all: $(TARGET)
      
      $(TARGET): $(OBJS)
        $(CXX) $(LDFLAGS) $^ $(LIBS) -o $@
      
      %.o: %.cpp
        $(CXX) $(CXXFLAGS) -c $< -o $@
      
      clean:
        rm -f $(OBJS) $(TARGET)
      
    2. 소스 폴더에서 make 명령으로 응용 프로그램을 빌드합니다.

      $ make
      $ ls -l
      total 1144
      -rwxrwxr-x 1 cobenhan cobenhan  133176  3월 14 00:59 hello
      -rw-rw-r-- 1 cobenhan cobenhan    5121  3월 14 00:43 hello.cpp
      -rw-rw-r-- 1 cobenhan cobenhan 1023288  3월 14 00:59 hello.o
      -rw-rw-r-- 1 cobenhan cobenhan    1446  3월 14 00:59 Makefile
      

    CMake 빌드#

    1. hello.cpp가 있는 소스 폴더에 toolchain.cmake 파일을 아래 내용으로 생성합니다.

      # this one is important
      SET(CMAKE_SYSTEM_NAME Linux)
      #this one not so much
      SET(CMAKE_SYSTEM_VERSION 1)
      SET(CMAKE_SYSTEM_PROCESSOR aarch64)
      
      SET(EXTERNAL_TOOLCHAIN_ROOT /opt/vtcs_toolchain/leipzig/usr/)
      SET(EXTERNAL_TOOLCHAIN_PATH ${EXTERNAL_TOOLCHAIN_ROOT}/bin)
      SET(CROSS_COMPILER_PREFIX aarch64-linux-)
      
      # specify the cross compiler
      SET(CMAKE_C_COMPILER   /opt/vtcs_toolchain/leipzig/usr/bin/aarch64-linux-gcc)
      SET(CMAKE_CXX_COMPILER ${EXTERNAL_TOOLCHAIN_PATH}/aarch64-linux-g++)
      SET(CMAKE_AR_COMPILER ${EXTERNAL_TOOLCHAIN_PATH}/aarch64-linux-ar)
      SET(CMAKE_STRIP_COMPILER ${EXTERNAL_TOOLCHAIN_PATH}/aarch64-linux-strip)
      SET(CMAKE_SYSROOT ${EXTERNAL_TOOLCHAIN_ROOT}/aarch64-buildroot-linux-gnu/sysroot)
      
      # where is the target environment 
      SET(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${EXTERNAL_TOOLCHAIN_ROOT})
      SET(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${EXTERNAL_TOOLCHAIN_ROOT}/aarch64-buildroot-linux-gnu)
      SET(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${EXTERNAL_TOOLCHAIN_ROOT}/aarch64-buildroot-linux-gnu/sysroot/lib)
      
      # search for programs in the build host directories
      SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
      # for libraries and headers in the target directories
      SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
      SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
      
      # SET(TOOLSDIR /opt/vtcs_toolchain/leipzig)
      
      SET(CMAKE_ASM_COMPILER   ${EXTERNAL_TOOLCHAIN_PATH}/${CROSS_COMPILER_PREFIX}gcc)
      # Override ar and ranlib tools that CMake should use for linking lib
      SET(CMAKE_AR             ${EXTERNAL_TOOLCHAIN_PATH}/${CROSS_COMPILER_PREFIX}ar      CACHE STRING "")
      SET(CMAKE_RANLIB        ${EXTERNAL_TOOLCHAIN_PATH}/${CROSS_COMPILER_PREFIX}ranlib  CACHE STRING "")
      
    2. hello.cpp가 있는 소스 폴더에 CMakeLists.txt 파일을 아래 내용으로 생성합니다.

      cmake_minimum_required (VERSION 3.5.1)
      
      project (Hello)
      
      # Oasis SDK 환경을 설정합니다.
      include_directories(SYSTEM "/opt/oasis/sdk-4.3.29/include")
      #-Wl,-rpath,path1:path2:path3...
      link_directories(/opt/oasis/sdk-4.3.29/lib)
      add_definitions(-DOASIS_NO_NVWA -DOFFS_NO_NVWA)
      
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O2 -g")
      # strip
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s")
      
      # 타겟을 설정합니다.
      add_executable(hello hello.cpp)
      
      target_link_libraries(hello oasis_codec oasis_fs oasis_pipe oasis_media oasis_ui oasis_util oasis_certs oasis_disp oasis)
      
      target_link_libraries(hello cva vmf_nnm vmf vdec util iniparser)
      target_link_libraries(hello exif png16 jpeg freetype z jsoncpp)
      target_link_libraries(hello rt pthread)
      
    3. 아래와 같이 빌드를 진행합니다.

      $ mkdir build
      $ ls -l
      total 20
      drwxrwxr-x 3 cobenhan cobenhan 4096  3월 14 01:46 build
      -rw-rw-r-- 1 cobenhan cobenhan  751  3월 14 01:44 CMakeLists.txt
      -rw-rw-r-- 1 cobenhan cobenhan 5121  3월 14 00:43 hello.cpp
      -rwxrwxr-x 1 cobenhan cobenhan 1679 12월 11 16:27 toolchain.cmake
      $ cd build
      build$ cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake ..
      build$ make
      build$ ls -l
      total 164
      -rw-rw-r-- 1 cobenhan cobenhan  14549  3월 14 01:46 CMakeCache.txt
      drwxrwxr-x 6 cobenhan cobenhan   4096  3월 14 01:46 CMakeFiles
      -rw-rw-r-- 1 cobenhan cobenhan   1716  3월 14 01:46 cmake_install.cmake
      -rwxrwxr-x 1 cobenhan cobenhan 133176  3월 14 01:46 hello
      -rw-rw-r-- 1 cobenhan cobenhan   5246  3월 14 01:46 Makefile
      

    실행 결과#

    빌드 후 타겟 장치에 응용 프로그램을 설치하기 가이드에 따라 설치합니다.

    아래는 타겟 장치에서 실행 후 Capture Me! 버튼을 터치하여 생성된 캡춰 이미지입니다.

    Hello

    예제 다운로드