빌드하기¶
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 빌드¶
-
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) -
소스 폴더에서
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 빌드¶
-
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 "") -
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) -
아래와 같이 빌드를 진행합니다.
$ 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! 버튼을 터치하여 생성된 캡춰 이미지입니다.
