Cygwin vs MinGW

|

개인용 노트 PC에 C++ 개발 환경을 설정하기 위해서 CygwinMinGW을 각각 설치해보면서 어떤 것이 더 좋을 지 테스트를 해보았습니다. 사실 Windows 환경에서는 Visual Studio 하나면 C++ 개발 환경은 거의 끝이지만, 최대한 Linux 환경과 비슷하게 만들기 위해서 MinGW와 Cygwin을 살펴보았습니다.


Cygwin vs MinGW

Cygwin과 MinGW는 둘 다 태생은 비슷합니다. Cygwin은 Windows에서 Linux 환경을 에뮬레이팅하기 위하여 Windows로 포팅된 UNIX 기반 소프트웨어입니다. 그리고, MinGW은 Cygwin 1.3.3 버전에서 분리되어져서 나왔습니다.

그 이후 Cygwin과 MinGW은 완전히 다른 노선을 걷기 시작합니다. Cygwin은 Windows 위에서 작동하는 Linux 호환 Layer를 구성하고 그 위에서 추가 에뮬레이션되어 동작하도록 구현되었습니다. 하지만 MinGW는 네이티브(Native) Windows 타켓으로 동작하도록 구현되었습니다. 그러다보니 아무래도 MinGW가 Cygwin보다 성능면에서 더 빠르게 동작하는 경우가 많습니다. 대신 Linux 호환성 면에서는 Cygwin이 MigGW보다 더 안정적으로 작동합니다.

MinGW의 목표는 Windows에서 GNU 툴을 사용하기 위한 최소한의 환경 설정 제공에 있습니다. 그래서 이름도 MinGW(Minimalist GNU for Windows)입니다.


MinGW의 C++11 thread 지원 문제

MinGW에서 C++11의 thread를 정식으로 지원하지 않는 문제점이 있습니다. 덕분에 MinGW에서 Thread 관련 요소를 사용하려고 하면(특히 Mutex) 컴파일조차 되지 않고 에러가 발생합니다. 구글링을 통해서 알아보니 mingw-std-threads와 같은 라이브러리를 이용하면 해결할 수 있다고 하네요. 헤더 파일만 적당히 교체하면 되는 라이브러리라 큰 불편 없이 사용할 수 있을 것 같지만, 그래도 편법으로 해결하는거라 개운하지는 않네요. 그래서 저는 Cygwin을 추가로 설치했습니다. Cygwin에서는 이런 문제가 전혀 발생하지 않습니다.


MSYS

MSYS는 MinGW에서 bash나 make 등의 명령어를 수행할 수 있게 해주는 커맨드 쉘(Command Shell)입니다. Cygwin의 경우는 UNIX 대부분의 환경을 에뮬레이팅해주고 있지만, MSYS는 개발에 필요한 최소한의 요소들만 지원을 해주고 있습니다.

MSYS는 Cygwin의 초기 버전에서 분리되어 개발되었으며, 최근에는 Cygwin 최신 버전 기반으로 한 MSYS2도 있습니다. Cygwin이나 MSYS나 간단히 개발용으로 사용하기에는 큰 차이 없는 것 같습니다.


설치 용량 차이

대부분 하드디스크의 용량은 넉넉하다보니 설치 용량 차이가 큰 의미는 없을 수 있는데, 그래도 살짝 언급해봅니다. C++ 개발을 위한 MinGW의 설치 용량은 350MB 수준입니다. Cygwin의 경우는 약 10GB 수준입니다. 이것도 Cygwin 항목중에 development 항목만 추가했을 때의 용량입니다. 제가 C++ 개발을 위한 최소한의 옵션만으로 설정하지는 않았지만 그래도 아주 큰 차이가 있네요. 덕분에 설치 시간도 엄청나게 차이가 납니다. 물론, 설치는 처음 한 번만 하면 되니깐 아주 큰 문제는 아닐 수 있겠네요.

결국 C++11 thread 지원 문제 때문에 저는 MinGW를 설치했다가 지금은 완전히 지우고 Cygwin으로 넘어갔습니다.

find 사용법 - 파일 검색

|

리눅스에서 파일을 찾는 방법은 find 명령어를 이용해서 찾을 수 있습니다. 그리고 -name 옵션을 이용해서 원하는 파일을 검색할 수 있습니다.

탐색 경로를 생략한 경우에는 현재 작업중인 폴더부터 검색을 시작합니다. 읽기 권한이 없는 폴더는 건너뜁니다.

find -name [파일명]

ex)
find -name snowdeer

권한이 없는 폴더까지 검색을 하고 싶으면 앞에 sudo로 루트 권한을 얻으면 가능합니다.

루트 폴더부터 모든 폴더의 파일을 다 검색하고 싶을 때는 /를 명시하면 됩니다.

sudo find / -name snowdeer

C++용 Log 클래스

|

C++ 에서 사용할 수 있는 Log 클래스입니다. 안드로이드 NDK 환경이나 Windows 환경 등에서도 사용할 수 있습니다. 사용법을 최대한 안드로이드 Java의 Log 클래스와 비슷하게 흉내냈습니다.


Log.h

#ifndef SNOWDEER_LOG_H
#define SNOWDEER_LOG_H

class Log {
 public:
  static void v(const char* format, ...);
  static void d(const char* format, ...);
  static void i(const char* format, ...);
  static void w(const char* format, ...);
  static void e(const char* format, ...);

 private:
  Log() {}
  virtual ~Log() {}
};

#endif //SNOWDEER_LOG_H


Log.cc

#include "Log.h"

#include <cstdio>
#ifdef __ANDROID__
#include <android/log.h>
#else
#include <stdarg.h>
#endif

const char* gLogTag = "SDLog";

#ifdef __ANDROID__
#define PLOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, gProseLogTag, __VA_ARGS__)
#define PLOGD(...) __android_log_print(ANDROID_LOG_DEBUG, gProseLogTag, __VA_ARGS__)
#define PLOGI(...) __android_log_print(ANDROID_LOG_INFO, gProseLogTag,__VA_ARGS__)
#define PLOGW(...) __android_log_print(ANDROID_LOG_WARN, gProseLogTag,__VA_ARGS__)
#define PLOGE(...) __android_log_print(ANDROID_LOG_ERROR, gProseLogTag, __VA_ARGS__)
#define PLOGF(...) __android_log_print(ANDROID_FATAL_ERROR, gProseLogTag,__VA_ARGS__)
#define PLOGS(...) __android_log_print(ANDROID_SILENT_ERROR, gProseLogTag,__VA_ARGS__)
#else
#define LOGV(...)
#define LOGD(...)
#define LOGI(...)
#define LOGW(...)
#define LOGE(...)
#define LOGF(...)
#define LOGS(...)
#endif

void Log::v(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf("[%s] %s\n", gLogTag, message);
  LOGV("%s", message);
}

void Log::d(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf("[%s] %s\n", gLogTag, message);
  LOGD("%s", message);
}

void Log::i(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf("[%s] %s\n", gLogTag, message);
  LOGI("%s", message);
}

void Log::w(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf("[%s] %s\n", gLogTag, message);
  LOGW("%s", message);
}

void Log::e(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf("[%s] %s\n", gLogTag, message);
  LOGE("%s", message);
}

사용자 계정 관리하기

|

계정 생성

리눅스에서 사용자 계정은 다음 명령어를 이용해서 생성할 수 있습니다. 기본적으로 -m 옵션을 붙여서 사용자의 홈 디렉토리(Home Directory)를 생성할 수 있습니다.

sudo useradd -m [사용자 ID]

ex) sudo useradd -m snowdeer

계정을 생성한 다음에는 ls /home 명령어를 이용해서 확인할 수 있습니다.


패스워드 설정

패스워드는 passwd 명령어를 이용해서 설정할 수 있습니다.

sudo passwd snowdeer

ex)
pi@snowdeer_raspberry:~ $ sudo passwd snowdeer
Enter new UNIX password: ********
Retype new UNIX password: ********
passwd: password updated successfully


패스워드 변경

현재 로그인해 있는 계정의 패스워드를 변경할 경우는 다음과 같이 passwd 명령어만 입력하면 됩니다.

sudo passwd


계정 삭제

계정 삭제는 userdel 명령어로 가능합니다.

sudo userdel snowdeer

계정을 삭제해도 /home 밑에 홈 디렉토리는 남아 있기 때문에 수작업으로 삭제를 해주시면 됩니다.

Eclipse에서 C++11 이상 지원하도록 설정하는 방법

|

C++11

C언어는 지금도 계속해서 발전하고 있습니다. 2011년 C++11 규격이 정해졌으며, 그 이후에도 계속하여 발전하고 있습니다. 지금은 현재 C++14, C++17 까지 나온 상태입니다. 개인적인 생각으로는 C++11에서 아주 큰 변화(스마트 포인터 지원 및 Thread 표준화)가 있었던 것 같습니다. 그래서 신규 프로젝트를 진행한다면 적어도 C++11 이상은 사용하는 것이 좋다고 생각합니다. 그 중에서도 스마트 포인터(Smart Pointer)는 메모리 릭(Memory Leak) 방지에 아주 큰 도움이 되며, 표준화가 된 쓰레드(Thread)는 멀티 플랫폼 지원에 유리할 것 같습니다.


Eclipse for C++11

Visual Studio나 CLion 등 좋은 C++ IDE가 많이 있지만, 회사에서는 아무래도 Eclipse를 많이 사용하게 되네요. 아마도 라이센스를 크게 신경쓸 필요가 없어서이지 않을까 싶습니다. 그래서 Eclipse에서 C++11 이상을 지원하는 방법을 포스팅해봅니다. 저는 현재 PC에 MinGW를 설치했기 때문에 포스팅을 MinGW 기준으로 설명을 하고 있지만, MinGW가 아니더라도 Cygwin 등 기타 다른 컴파일러에서도 거의 동일한 설정을 하면 됩니다.


image

일단 새로운 프로젝트를 시작하고 컴파일러를 MinGW를 선택합니다. (굳이 새로운 프로젝트를 시작할 필요없이 세팅에서 바로 설정을 할 수도 있지만, 여기서는 실제로 C++11 문법으로 잘 빌드가 되는지 확인하기 위해서 새로운 프로젝트를 만들어서 테스트를 합니다.)


image -fullwidth

Project > Properties > C/C++ Build / Settings > Tool Settings에서 [GCC C++ Compiler] 항목과 [GCC C Compiler] 항목에서 [Miscellaneous] 항목을 찾습니다. 그리고 [Other flags] 뒷 부분에 다음 옵션을 추가합니다.

-std=c++0x


이제 간단한 코드를 작성하여 테스트를 해봅니다. 코드 예제는 다음과 같습니다. 코드 작성 후 빌드를 실행해봅니다.


#include <cstdio>
#include <memory>
#include <string>
#include <thread>

using namespace std;

int main(void) {
  printf("Hello SnowDeer.\n");

  shared_ptr<string> a = make_shared<string>();

  return 0;
}


image -fullwidth


위 이미지와 같이 빌드가 잘 되는 것을 확인할 수 있습니다.

하지만 다음 이미지에 나온 것처럼 문제점이 하나 있습니다.


image -fullwidth

컴파일 및 빌드는 잘되지만, Eclipse의 에디터에서는 오류가 난 것처럼 표시되고 있습니다. 그냥 무시하고 개발을 진행해도 되지만, 시각적으로 상당히 불편합니다. 이럴거면 IDE를 사용하는 의미가 없을 것 같네요. 이를 해결하기 위해서는 IDE 내의 에디터키가 C++11 이상을 지원하도록 추가 설정을 해주어야 합니다. 앞서 설정한 내용은 컴파일러의 옵션만 설정한 것이기 때문에 추가 설정이 필요합니다.


image -fullwidth

Project > Properties > C/C++ General > Preprocessor Include Paths, Macros etc에서 [Providers] 탭을 선택한 다음 [CDT GCC Built-in Compiler Settings MinGW] 항목을 선택합니다. 그리고 아래쪽에 있는 Flag 설정 칸에 다음 옵션을 추가해줍니다.

-std=c++0x


image

그 이후 C/C++ Index Rebuild 를 수행해주면 Eclipse IDE가 C++11 문법을 정상적으로 인식하기 시작합니다.


image -fullwidth

이제 깔끔하게 Eclipse에서 C++11 이상의 문법들로 프로그램을 작성할 수 있습니다.