Seamless 모드란?

: Seamless의 단어가 가지는 의미는 끊김이 없는, 매끄러운 등의 의미를 가지고 있습니다. 마치 두 물체를 이어 붙였을 때 두 물체 사이의 유격이 느껴지지 않는 상태를 의미합니다. 이러한 seamless mode를 VirtualBox에서는 다음의 그림과 같은 기능을 제공함으로써 얻을 수 있습니다. 마치 Host PC(Window) 에서 Guest PC(Linux)를 동시에 지원하고 있는 것 처럼 말이죠.

 

WSL(Window Subsystem for Linux)를 Window에서 지원하고는 있지만, 실제 Linux 환경을 운영하는 것 보다는 개인적으로 조금 불편한 느낌이 있어 VirtualBox를 사용하고 있습니다.
WSL과 Virtual Box를 동시에 사용하면 crash issue도 있더군요... 한 번 crash가 발생하니 되돌리기 쉽지않은..ㅠㅠ

 

Seamless 모드를 적용하는 방법

:다음의 사진과 같이 적용하면 됩니다.

 

1. Seamless 모드를 사용할 때 기본적으로 설정되어있는 비디오 메모리의 크기가 충분하지 않아 렌더링을 하지 못하고 Black window가 보이는 현상이 있습니다. 따라서 다음의 설정을 통해 이를 방지할 수 있습니다.

 

2. Seamless 모드의 사용은 `HostKey` + `L` 조합으로 전환할 수 있습니다. terminal 하나를 띄운 채 seamless mode에 진입하면 아래와 같이 보이게 됩니다.

다시 기본 모드로 돌아가려면 `Hostkey` + `C` 조합으로 돌아갈 수 있습니다.

 

3. 위의 사진에서 보면 terminal 주위에 margin이 생기는 걸 볼 수 있습니다. 테두리의 여백을 없애기 위해서는 다음과 같은 절차로 없앨 수 있습니다.

3-1. `~/.config/gtk-3.0/gtk.css` 파일 생성

3-1. 생성된 파일에 아래의 내용 입력

decoration, decoration:backdrop {
    border-radius: 0;
    border-width: 0;
    box-shadow: none;
    margin: 1px;
}

 

위 설정을 마치면 아래의 그림과 같이 여백이 제거된 상태의 seamless 모드를 즐길 수 있습니다.

 

4. seamless mode 상단에 도구모음 표시

아래의 그림에서와 같이 seamless 모드 상단에 도구모음을 표시하기 위해서는

 

다음의 설정을 수행하면 됩니다.

 

 

+ HostKey 확인 및 변경하는 방법

1. [VirtualBox] - [파일] - [환경설정] 진입

2. [입력] - [가상머신] - [호스트 키 조합] 을 선택 후 원하는 키 입력

LOG 출력 함수

: 프로젝트의 크기가 제법 되는 경우에는 개발과 추후 디버깅을 위해서 로그를 사용하는 일이 많다. 그렇지 않다면 개발 시 일일히 print 함수를 찍어보며 값을 확인하거나 GDB 툴을 이용해야만 한다. GDB를 이용하는 방법은 괜찮지만 printf 함수를 이용해 값을 일일히 찍어보는 것은 여간 귀찮은 일이 아닐 수 없다. 이러한 필요성에 따라 로그 함수를 작성하는 방법에 대해 알아보자.

자체 LOG 출력 함수 만들기

: 다음과 같이 LOG 출력 함수를 만들 수 있다.

#include <stdio.h>
#include <stdarg.h>

#define LOG(fmt, ...) print_log(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)

void print_log(const char *file, const char *func, int line, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);

    printf("%s/%s(%d): ", file, func, line);
    printf(fmt, ap);

    va_end(ap);

    printf("\\n");
}
int main() {
    LOG("Hello");

    return 0;
}

그리고 그 실행결과는 다음과 같다.

jay@ ~/Desktop/tutorial/log $ ./main 
main.cc/main(17): Hello

Inside LOG 출력 함수

: 위의 LOG 출력 함수에 사용된 여러가지 사항들에 대해 알아보자.

  1. #define LOG(fmt, ...)... 이 가지는 의미
    • ...variadic function을 정의할 때 사용되는데, 이는 가변 갯수의 parameter가 들어올 수 있음을 의미한다.
    • 대표적인 variadic function이 printf로, printf("%d \\n", 1), printf("%d %d \\n", 1, 2)와 같이 함수의 parameter가 정해져 있지 않다.
  2. print_log(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)__FILE__, __FUNCTION__, __LINE__ 이 가지는 의미
    • FILE과 같이 두 개의 연속된 underscore로 시작하는 변수들은 대부분 컴파일러에 pre-define 되어있는 값들이다.
    • 여기서 FILE은 해당 명령어가 호출되고 있는 파일의 이름, FUNCTION은 해당 명령어가 속해있는 함수의 이름, LINE은 해당 명령어가 해당 파일의 몇 번째 라인에 위치해 있는지를 나타낸다.
  3. print_log(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)##__VA_ARGS__가 가지는 의미
    • __VA_ARGS는 앞의 define 문에서의 ...에 대치되는 문구이다.
    • 여기서 ##이 붙은 이유는, LOG("Hi %s", "Jay")가 아닌 LOG("Hi")를 호출하였을 때 ...에 해당하는 argument가 없기 때문에 컴파일 오류가 나는 것을 방지하기 위함이다.
  4. va_list, va_start, va_end 이란?
    • 위의 variadic function에서 parameter의 갯수는 제한이 없다. 따라서 parameter에 어떤 값들이 들어오는지는 미정인 상태이므로, parameter에 들어오는 값들을 순회하여야 할 필요가 있다.
    • 따라서 va_start를 이용해 순회하고자 하는 파라미터의 위치를 지정하고, va_start, va_end로 각각 순회 리스트를 생성, 종료시킨다.

Python2 에서 Python3로 변경시 유의해야 할 점

아래의 참고자료 중 Python2 to Python3 Porting Guide 를 보면 자세한 설명과 그 이유를 알 수 있으니 해당 문서를 참고하길 바랍니다.

C를 Python3로 포팅

: C에서 Python3로 포팅하는 절차는 크게 3가지로 구성된다.

  1. Modernization, 개발한 코드들이 Python2의 기능으로 마이그레이션 된다. 이 단계 이후에는 Python2.6 이상을 지원하게 된다.
  2. Porting, Python3도입 후 Python3 뿐만 아니라 Python2에 대한 호환성을 유지하도록 만든다.
  3. Cleanup, Python2에 대한 지원을 제거한다. 이 단계 후에는 Python3.3 이상의 버전만을 지원한다.

PyObject

: 모든 object 타입들은 이 PyObject 타입의 확장이라 할 수 있다. 이는 Python이 object를 다루기 위해 해당 object를 가리키는 포인터를 저장하는 구조라고 보면 된다. 이 PyObject는 원본 object의 reference count, 해당하는 object에 대한 type object에 대한 포인터를 가지고 있다.

Modernization

: PyObject의 멤버에 대한 사용에서 다음의 항목들의 사용에 주의하라.

From To 설명
obj->ob_type Py_YPE(obj)  
obj->ob_refcnt Py_REFCNT(obj)  
obj->ob_size Py_SIZE(obj)  
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0) type object의 초기화
PyClass_*, Py_Instance_* PyType_* 앞의 두 클래스는 Python3에서 삭제된 클래스, v2.2에서는 유효
PyCObject_* PyCapsule_* Python3.3에서 삭제된 타입

Porting

: modernize의 결과로 당신은 Python2의 가장 최신 feature를 사용하고 있을 것이다. 이제부터는 Python3를 동시에 지원할 수 있도록 할 것이다.

  1. #include <py3c.h>을 통해 헤더파일을 include하고 헤더 파일의 위치를 컴파일러에 알려줘라
  2. Python3에서의 특별한 점은 Python3에서는 human-readable한 string과 binary data를 나누어 놓았다는 점이다. 따라서 py3c 헤더파일을 이용할 때, native stringPyStr_* (PyStr_FromString, PyStr_Type, PyStr_Check 등)을 사용하고 binary dataPyBytes_* (PyBytes_FromString, PyBytes_Type, PyBytes_Check 등)을 사용해라.
String 종류 Py2 Py3 사용처
PyStr_* PyString_* PyUnicode_* Human-readable 텍스트
PyBytes_* PyString_* PyBytes_* Binary data
PyUnicode_* PyUnicode_* PyUnicode_* Unicode strings
PyString_* PyString_* 사용불가 unported code
  1. String의 길이를 return하기 위해서는 PyStr_AsUTF8AndSize()를 사용해라. Python3에서는 PyUnicode_AsUTF8AndSize()가 사용됨에 유의하라.
  2. Python3에서 string이 2 종류(human-readable, binary data)로 분리되었다면, int와 long은 하나의 타입으로 합쳐졌다. 다시말해, PyInt_*은 제거되고 PyLong_*만이 남았다. 이를 py3c 헤더파일에서는 에일리어싱으로 정의해 놓았다.
  3. Python3에서 PyFloat_FromString 함수는 2번째 인자를 없앴다. 이를 py3c 헤더파일에서는 재정의함으로써 Python2와 동시에 지원하고 있다.
  4. 모듈 초기화시 Python2에서는 void init<module_name> 함수를 사용하였으나, Python3에서는 PyObject *PyInit_<module_name>함수를 사용한다. 이를 동시에 지원하기 위해서는 MODULE_INIT_FUNC 매크로를 사용하라.

Cleanup

: Porting의 결과로 Python2와 Python3를 동시에 지원하고 있는 코드를 얻을 수 있다. 여기서는 C에서 Python2와 관련된 문법을 더이상 사용하지 않도록 하는 것이다.

py3c.h 헤더파일이 포함되어있다면 이를 제거하라.

From To 설명
PyStr_* PyUnicode_* PyStr_으로 시작하는 함수는 더이상 사용되지 않음
PyInt_* PyLong_* 더 이상 사용되지 않음
MODULE_INIT_FUNC(module_name) PyMODINIT_FUNC Py_Init_<module_name>(void)  
Py_TPFLAGS_HAVE_WEAKREFS
Py_TPFLAGS_HAVE_ITER
  단순 제거
return PY3C_RICHCMP Py_RETURN_RICHCOMPARE() 링크 참조
capsulethunk.h   사용중이라면 제거하라
#if !IS_PY3 BLOCK   해당 블럭에 있는 코드 제거

참고자료 

[Ofiicial] Embedding Python Application
Python/C API Reference Manual
Python/C API Unicode Objects and Codecs
Python/C API List Objects
Python2 to Python3 Porting Guide
NLTK install guide
stackoverflow - No module name
stackoverflow - Python.h: No such file or directory

Python 모듈을 C에서 import 하기

: 이 내용은 Python으로 개발된 모듈들을 C에서 자유자재로 이용하기 위해서 사용해야할 API 들과 그 전반에 대한 개발 가이드이다.

파일의 구성

: 이 Sample App은 크게 3개의 함수들로 구성하였다.

첫 번째로는, string을 인자로 받아 string을 반환하는 make_string 함수.
두 번째로는, int를 인자로 받아 int를 반환하는 make_int 함수.
마지막으로는, list 타입을 반환하는 make_list 함수이다.

파일의 구조는 다음과 같이 구성하였다.

jay@ ~/Desktop/tutorial/embedded-python $ tree .
.
├── bin
├── scripts
│   ├── __init__.py
│   └── my_module.py
└── src
    └── main.cpp

my_module.py 파일은 다음의 함수들로 구성된다.

def make_string(param):
    return "my_string: " + param

def make_int(param):
    return (1 + param)

def make_list():
    return ["1", "2", "3"]

main.cpp 파일은 다음의 함수들로 구성된다.

#include <Python.h>

void initialize(char* module_name, PyObject **pModule)
{
    Py_Initialize();

    PyObject *pName = PyUnicode_DecodeFSDefault(module_name);
    *pModule = PyImport_Import(pName);

    Py_DECREF(pName);
}

void finalize(PyObject *pModule)
{
    Py_DECREF(pModule);
    Py_FinalizeEx();
}

void make_string(PyObject *pModule, char *arg)
{
    PyObject *pFunc, *pArgs, *pValue;

    pFunc = PyObject_GetAttrString(pModule, "make_string");
    pArgs = PyTuple_New(1);

    PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(arg));
    pValue = PyObject_CallObject(pFunc, pArgs);
    Py_DECREF(pArgs);

    printf("Result of call: %s \n", PyUnicode_AsUTF8(pValue));
    Py_DECREF(pValue);
    Py_DECREF(pFunc);
}


void make_int(PyObject *pModule, int arg)
{
    PyObject *pFunc, *pArgs, *pValue;

    pFunc = PyObject_GetAttrString(pModule, "make_int");
    pArgs = PyTuple_New(1);

    PyTuple_SetItem(pArgs, 0, PyLong_FromLong(arg));
    pValue = PyObject_CallObject(pFunc, pArgs);
    Py_DECREF(pArgs);

    printf("Result of call: %d \n", PyLong_AsLong(pValue));
    Py_DECREF(pValue);
    Py_DECREF(pFunc);

}

void make_list(PyObject *pModule)
{
    PyObject *pFunc, *pArgs, *pValue;

    pFunc = PyObject_GetAttrString(pModule, "make_list");

    pValue = PyObject_CallObject(pFunc, NULL);

    printf("Result of call: \n");
    for (int i = 0; i < PyList_Size(pValue); ++i)
    {
        printf("\t%dst item: %s \n", i, PyUnicode_AsUTF8(PyList_GetItem(pValue, i)));
    }
    Py_DECREF(pValue);
    Py_DECREF(pFunc);
}

int main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pFunc;
    PyObject *pArgs, *pValue;
    int i;

    initialize(argv[1], &pModule);

    make_string(pModule, "Hello World!");
    make_int(pModule, 99);
    make_list(pModule);

    finalize(pModule);

    return 0;
}

여기서 __init__.py 파일은 아무런 내용을 기입하지 않아도 상관없으므로, 실행을 위해서 단순히 파일만 만들어 놓자.

빌드 및 실행

: 빌드는 다음과 같은 명령어로 빌드할 수 있다.

jay@ ~/Desktop/tutorial/embedded-python $ gcc -o ./bin/main -I/usr/local/include/python3.7m ./src/main.cpp -L/usr/local/lib -lpython3.7m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic

빌드 후 산출물을 가지고 실행하면 아래의 결과를 얻을 수 있을 것이다.


jay@ ~/Desktop/tutorial/embedded-python $ PYTHONPATH=. ./bin/main scripts.my_module

Result of call: my_string: Hello World! 

Result of call: 100 

Result of call: 

    0st item: 1 

    1st item: 2 

    2st item: 3

실행 중 발생되는 오류

  1. No module named pyfunction

ImportError: No module named pyfunction
  • $ PYTHONPATH=. ./main blah blah 을 통해 모듈의 위치를 찾는 경로에 현재 위치를 추가해 준다.
  1. reference undefined to "Py_Initialize", undefined referecne to 'log'

reference undefined to "Py_Initialize"

reference undefined to "PyRun_SimpleStringFlags"

reference undefined to "Py_Finalize"

collect2: error: ld returned 1 exit status





/Python-3.7.0/Objects/longobject.c:2287: undefined reference to `log'

/Python-3.7.0/Objects/floatobject.c:788: undefined reference to `pow'

/Python-3.7.0/Objects/floatobject.c:753: undefined reference to `floor'

/Python-3.7.0/Objects/floatobject.c:764: undefined reference to `fmod'

collect2: error: ld returned 1 exit status


  • $ python3-config --ldflags 수행 후 나타나는 결과를 gcc 옵션에 넣어준다.

  • 위의 해결방법으로 되지 않는다면, $ pkg-config --cflags --libs python3 수행 후 나타나는 결과를 gcc 옵션에 넣어준다. 본인은 위 방법으로 해결되었음.

  1. Python.h: No such file or directory

fatal error: Python.h: No such file or directory

compilation terminated.
  • $ sudo apt install libpython3-dev를 통해 Python 개발 관련 헤더파일을 설치해 준다.
  1. No module named 'BlahBlah'

ModuleNotFoundError: No module named 'BlahBlah'
  • module의 이름을 지정할 때 경로와 함께 지정해 준다.

  • 만일 ./module/my_module.py의 경로라면, module.my_module을 LOAD 하여야 한다.

Python2 에서 Python3로 변경시 유의해야 할 점

아래의 참고자료 중 Python2 to Python3 Porting Guide 를 보면 자세한 설명과 그 이유를 알 수 있으니 해당 문서를 참고하길 바랍니다.

: 추후 업데이트 예정

 

 

참고자료

[Ofiicial] Embedding Python Application

Python/C API Reference Manual

Python/C API Unicode Objects and Codecs

Python/C API List Objects

Python2 to Python3 Porting Guide

NLTK install guide

stackoverflow - No module name

stackoverflow - Python.h: No such file or directory

일반적인 라이센스

BSD

  • 소스코드를 공개하지 않아도 되는 대표적 라이센스
  • 저작권 명시
  • Nginx(BSD 2-Clause License)

MIT

  • MIT에서 해당 대학의 SW 공학도를 위해 개발한 라이센스
  • 라이센스 및 저작권 명시
  • Bootstrap, Angular.js, Backbone.js, jQuery

Apache

  • 아파치 재단의 모든 SW에 적용
  • BSD 의무사항 + 특허권
  • GPL2.0으로 배포되는 코드와 동시 적용 불가능
  • Android v2.0, Hadoop v2.0

주의해야할 라이센스

LGPL

  • 수정한 소스코드 LGPL로 공개 (Static Linking 시 전체 코드 공개)
  • 라이센스 및 저작권 명시
  • Mozilla Firefox v2.1

GPL

  • GPL 소스코드를 이용한 소프트웨어 전체 GPL로 공개
  • 라이센스 및 저작권 명시
  • Linux Kernel v2.0

AGPL

  • AGPL 소스코드를 이용한 소프트웨어 전체 AGPL로 공개
  • 라이센스 및 저작권 명시
  • MongoDB v3.0

라이센스 적용 범위

(외부 배포)

바이너리, 3rd-party, 소스코드, public, 판매, 웹서비스(AGPL 한정)

GPL License

GPL 사용시

: GPL을 사용한 프로젝트를 배포한 경우, 그 프로젝트 전체 소스코드를 공개해야 함.

GPL2.0 + Apache2.0

: GPL2.0과 Apache2.0은 특허 보복 조항에 있어 양립할 수 없기에 배포가 불가능하다.

: Apache2.0 - 특허 보복 조항 허용

: GPL2.0 - 특허 보복 조항 보장하지 않음.

LGPL2.1 + Apache2.0

: 이 또한 위와 같이 특허 보복조항에 있어 양립할 수 없기에 경우에 따라 배포가 불가능 하다.

: LGPL2.1 - 특허 보복 조항 보장하지 않음.

: LGPL2.1을 사용한 코드가 Apache2.0을 이용한 코드와 독립적으로 사용(Dynamic Linking)되는 경우 배포 가능

주요 공개SW 라이센스 의무사항

주요 라이센스 의무사항 MIT BSD Apache License 2.0 GPL 2.0 GPL 3.0 AGPL 3.0 GPL 2.1 EPL MPL
복제, 배포, 수정의 권한 허용 있음 있음 있음 있음 있음 있음 있음 있음 있음
배포 시 라이선스 사본 첨부 있음   있음 있음 있음 있음 있음 있음 있음
저작권 고지 사항 유지 있음 있음 있음 있음 있음 있음 있음 있음 있음
배포 시 소스코드 제공의무 (Reciprocity)와 범위       All All Include network Object code & Static link Module File
수정 시 수정내용 고지     있음 있음 있음 있음 있음 있음 있음
명시적 특허라이선스의 허용     있음   있음 있음   있음 있음
라이선시가 특허소송 제기 시 라이선스/특허 종료(특허 보복 조항)     Patent   있음 있음   있음 있음
이름, 상표, 상호에 대한 사용제한   있음 있음           있음
보증의 부인 있음 있음 있음 있음 있음 있음 있음 있음 있음
책임의 제한 있음 있음 있음 있음 있음 있음 있음 있음 있음

 

 

Reference

자료 참고
GPL의 재배포 이슈: 링크 32pg

Intro

개발을 하며 git branch -a를 이용해 현재 branch는 무엇인지 확인할 일이 많다.

하지만 이렇게 매번 branch name을 확인하기 위해 동일한 명령어를 반복적으로 쓰는것은 매우 번거로운 일이 아닐 수 없다.

따라서 다음의 과정을 통해 Shell 내에서 branch name을 자동으로 표시할 수 있도록 하자.

How to

아래 명령어는 Ubuntu 20.04를 기준으로 수행되었습니다.

  1. gedit ~/.bashrc

  2. 스크롤을 내려 가장 아래에

    parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
    }
    export PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\]$(parse_git_branch)\[\033[00m\]\$ '

    입력

  3. terminal 재 시작

Result

그러면 아래의 사진과 같이 Linux shell에 branch name이 표시된 것을 볼 수 있다.

Reference
ask ubuntu - How do I show the git branch with colours in Bash prompt?

+ Recent posts