MongoDB 설치 및 C 개발 도구 설정

by digipine posted Sep 03, 2020
?

Shortcut

PrevPrev Article

NextNext Article

ESCClose

Larger Font Smaller Font Up Down Go comment Print

프로젝트에서 MongoDB를 사용해 보기로 했다.
아무래도 근래 제일 점유율이 높은 대세이기도 하고, 

무엇보다 C로 되어있는 점이 가장 마음에 들었다.

MongoDB 사용을 위해서는 먼저 MonngoDB 서버가 어딘가에 설치되어야 하고, 
여기에 접근하기 위한 플랫폼별 클라이언트 Driver를 통해 서버에 접속하게 된다.

헷갈리는 용어 덕분에 처음엔 Native 단의 Device Driver를 제공하는 것으로 착각했다.
알고보니 그냥 플랫폼별로 빌드된 라이브러리였다.
다음 페이지에서 플랫폼별 드라이버를 확인할 수 있다.

https://docs.mongodb.com/ecosystem/drivers/
 

 

서버 설치

 

먼저 MongoDB의 서버는 플랫폼 별로 설치 가이드가 잘 나와 있었다.
우분투의 경우 다음 페이지에 설치 방법이 있다. 

https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/

서버도 빌드해서 쓸까 했지만, 그냥 repo에 있는 것을 쓰기로 했다.
여기까진 전혀 문제없이 설치가 잘 되었고, 구동도 잘 되었다.

 


libmongoc

 

다음으로 클라이언트 드라이버를 찾아보았다.
내 경우에는 C/C++로 쓰여진 응용에서 MongoDB에 접근하게 되어 있었다.
C와 C++ 드라이버 중에 잠시 고민을 하다, C 드라이버를 선택했다.
MongoDB의 C 드라이버는 libmongoc라는 이름을 가지고 있으며, 

다음 페이지에 설명이 되어 있다.

http://mongoc.org/libmongoc/current/index.html

사실 libmongoc도 우분투 repo에 기본적으로 존재하고 있다.
apt로 설치하면 헤더와 빌드된 라이브러리들이 예쁘게 설치된다.

그러나 조금 살펴보던 도중 libmongoc가 libssl을 쓰고 있는 것을 발견했다.
내 경우에는 응용 내부에 특정 버전의 libssl을 static으로 쓰고 있어서,

이미 빌드된 버전을 쓰는데 약간 우려가 되었다.

그래서 소스코드에서 빌드를 하기로 했는데... 정말 잘못된 선택이었다.
웹사이트에 빌드 방법을 친절하게 안내하고 있는데다가, 

그래봐야 DB 서버에 연결해서 링크하는 정도의 라이브러리쯤이야 하는 생각이 있었다.

이 잘못된 결정 하나는 4시간을 넘기는 거대한 삽질로 귀결되었다.
그나마 다행인 점은 완공은 했다는 점이다.

혹시라도 이 글을 읽는 분들께 apt-get으로 설치하시라고 강력히 권장을 드린다.
다음 한 줄이면 번뇌없이 /usr/local에 예쁘게 정리된 header와 lib들을 얻을 수 있다.
 

$ apt-get install libmongoc-1.0-0 libbson-1.0 


그래도 소스코드에서 빌드를 시도할 특이점이 온 분들을 위해 삽질의 기록을 남겨본다.

 


libmongoc 드라이버 빌드

 

Documentation에 나온 설명에 따르면 MongoDB C Driver는 libmongoc와 libbson으로 구성된다.
전자가 후자에 의존성이 있으며, 후자는 MongoDB에서 사용하는 데이터 형식을 처리하기 위한 라이브러리이다.

Documentation에 나온 바에 따르면 libmongoc는 openssl과 cyrus-sasl에 의존성을 가지며, 
libbson은 cmake에 유일한 의존성을 갖는다.
openssl은 잘 알려진 라이브러리이고, cyrus-sasl은 인증관련 라이브러리이다.

하지만 Documentation은 대부분의 필요한 라이브러리들의 개발 버전이 이미 시스템에 있다는 가정을 하고있다.
그냥 쉽게 가고 싶다면 다음 명령으로 필요 라이브러리들을 설치하고 가면 된다.
 

$ apt-get install cmake libssl-dev libsasl2-dev


그러나 내 경우는 static으로 링크를 해야 하기에 의존성을 전부 클리어해야 했다.
검색으로는 한계가 있어 결국 cmakefile을 열어서 일일이 확인을 해야했다.


Cyrus-sasl

 

우선 문서에 공식적으로 언급된 Cyrus-sasl을 빌드해 보자.
GitHub 페이지는 다음과 같다.

https://github.com/cyrusimap/cyrus-sasl

최신 소스코드는 ftp서버에 있다.
다음 주소에서 가져올 수 있다.
 

ftp://ftp.cyrusimap.org/cyrus-sasl/ 


회사 등에서 ftp가 방화벽으로 막힌 경우에는 wget으로 가져올 수 있다.
 

$ wget https://github.com/cyrusimap/cyrus-sasl/releases/download/cyrus-sasl-2.1.27/cyrus-sasl-2.1.27.tar.gz 


빌드는 단순하다.
 

$ ./configure --prefix= <path to install>
$ ./make 
$ ./make install 


위와 같이 빌드하면 문제가 없이 빌드된다.
그러나 이렇게 하면 기본적으로 dynamic lib인 so만 생성된다.
static 빌드를 위해서는 --enable-static 옵션이 필요하다.
 

$ ./configure --enable-static --prefix=<path to install>


그런데 이렇게 하면 다음과 같이 없던 에러를 만날 수 있다.
 

CDPATH="${ZSH_VERSION+.}:" && cd . && /bin/bash /home/dev/cyrus-sasl-2.1.27/config/missing aclocal-1.15 -I m4 
/home/dev/cyrus-sasl-2.1.27/config/missing: line 81: aclocal-1.15: command not found 
WARNING: 'aclocal-1.15' is missing on your system. 
         You should only need it if you modified 'acinclude.m4' or 
         'configure.ac' or m4 files included by 'configure.ac'. 
         The 'aclocal' program is part of the GNU Automake package: 
         <http://www.gnu.org/software/automake> 
         It also requires GNU Autoconf, GNU m4 and Perl in order to run: 
         <http://www.gnu.org/software/autoconf> 
         <http://www.gnu.org/software/m4/> 
         <http://www.perl.org/> 


autoconf가 없기 때문인데, 이건 다음과 같이 설치해 준다.
 

$ apt-get install autoconf 


설치 후에는 다음 명령을 통해 재구성을 해준다.
 

$ autoreconf -f -i.


자 이제 준비가 되었으니 configure를 살행한다.
다음 에러를 만날 수 있다.
 

Can't exec "libtoolize": No such file or directory at /usr/share/autoconf/Autom4te/FileUtils.pm line 345,  line 6. 
autoreconf: failed to run libtoolize: No such file or directory


libtool이 없단다.
설치한다.
 

$ apt-get install libtool libtool-bin 


다시 configure를 실행하면 드디어 빌드가 정상적으로 된다.
Cyrus-sasl을 빌드했다!


OpenSSL

 

OpenSSL 빌드는 간단하고 잘 나와있는 글이 많으니 따라하면 금방 빌드가 가능하다.
Static 빌드를 하는 것만 잊지 않으면 되는데, 환경에 따라 최종 링크시 에러가 날 가능성이 있다.
여기에 대해서는 예전에 이 블로그의 다른 글에 언급해 두었다. 

귀찮다면 앞에 언급한 다음 명령으로 쉽게 설치가 가능하다.
 

$ apt-get install libssl-dev 


마침내 libmongoc를 빌드할 준비가 되었다.


libmongoc

 

드라이버의 소스코드는 다음과 같이 wget으로 얻을 수 있다.
x.y.z는 원하는 버전으로 치환하면 된다.
 

$ wget https://github.com/mongodb/mongo-c-driver/releases/download/x.y.z/mongo-c-driver-x.y.z.tar.gz


문서에 따르면 다음 명령으로 빌드가 된다.
 

$ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF 
$ make install 


그러나 다른 디펜던시 문제도 있는데다 부족한 설명이 너무 많다.

우선 cmake 옵션을 보면..
빌드 타입과 인스톨 위치는 일반적인 cmake 변수로 설정이 가능하다.
 

-DCMAKE_BUILD_TYPE=Release 
-DCMAKE_INSTALL_PREFIX= <path to install>


그리고 혹시라도 OpenSSL 위치가 정위치가 아니라면 다음 변수로 설정한다.

 

-DOPENSSL_ROOT_DIR=<path to openssl install>


물론 아까 공들여 빌드한 SASL을 라이브러리 링크도 잊으면 안된다.
 

-DCMAKE_INCLUDE_PATH=<path to sasl install>/include  
-DCMAKE_LIBRARY_PATH=<path to sasl install>/lib 


최종적으로 완성된 폼은 다음과 같다.
 

$ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=<path to install> -DOPENSSL_ROOT_DIR=<path to openssl install> -DCMAKE_INCLUDE_PATH=<path to sasl install>/include -DCMAKE_LIBRARY_PATH=<path to sasl install>/lib 
$ make install


자 그럼 이제 다 된걸까.
물론 그냥 넘어갈 수도 있지만, 여러 가지의 디펜던시를 더 넘어야 한다.


Other Dependencies

 

이 단계까지 와선 어쩐지 귀찮아져서 넘어갈 수 있는건 그냥 넘어갔다.

zlib
대부분 zlib이 필요하지 않은 경우가 희귀할 정도이니 의존성이 있는건 당연하다.
필요한 zlib 버전이 따로 있다면 ZLIB_LIBRARY ZLIB_INCLUDE_DIR에 위치를 지정한다.
그러나 특별히 지정하지 않아도 내장 zlib을 사용하니 그냥 skip해도 된다.

PkgConfig
빌드시 라이브러리 의존성 순서에 따른 문제를 해결하기 위해 사용된다.
다른 곳에도 많이 쓰는 툴이므로 그냥 설치한다.

zstandard
페북에서 만든 프로토콜인 것 같고, 다음에서 정보를 찾을 수 있다.

https://facebook.github.io/zstd/

귀찮으니 스킵하기로 했다.

Snappy
정보는 다음 링크에 있다.

https://github.com/google/snappy

스킵.


Undefined Reference

 

무수한 삽질 끝에, 드디어 대망의 막바지 빌드를 진행했다.
빌드 성공!!!!
libmongoc와 libbson을 획득했다!!!!

부푼 꿈을 안고 드디어 진행 중인 프로젝트에 빌드 결과를 연동해본다.
프로젝트 빌드..
그런데 역시나 기대를 저버리지 않고.. 에러가 난다.
 

mongoc-client.c:(.text+0x17a): undefined reference to `__dn_expand' 
... 
mongoc-counters.c:(.text+0x164): undefined reference to `shm_unlink' 
... 


기본 함수인데, Shared memory 관련 함수 등등이 없다고 한다.
해결책은 gcc에 명시적으로 링크를 걸어줘야 한다.
 

-lresolv -lrt


최근 gcc는 순서대로 의존성 체크를 들어가므로 libmongoc 뒤에 놓는걸 권장한다.
드디어 길고 긴 삽질이 끝나고 정상적으로 libmongoc가 링크되었다.

 


사용예제

 

끝으로 작동 확인을 위해서는 mongoc 튜토리얼에 있는 예제를 실행하면 된다.
 

#include <bson/bson.h> 
#include <mongoc/mongoc.h> 
#include  

int main (int   argc, char *argv[]) 
{ 
    mongoc_client_t *client; 
    mongoc_collection_t *collection; 
    bson_error_t error; 
    bson_oid_t oid; 
    bson_t *doc; 

    mongoc_init (); 

    client = mongoc_client_new ("mongodb://localhost:27017/?appname=insert-example"); 
    collection = mongoc_client_get_collection (client, "mydb", "mycoll"); 

    doc = bson_new (); 
    bson_oid_init (&oid, NULL); 
    BSON_APPEND_OID (doc, "_id", &oid); 
    BSON_APPEND_UTF8 (doc, "hello", "world"); 

    if (!mongoc_collection_insert_one ( 
           collection, doc, NULL, NULL, &error)) { 
        fprintf (stderr, "%s\n", error.message); 
    } 

    bson_destroy (doc); 
    mongoc_collection_destroy (collection); 
    mongoc_client_destroy (client); 
    mongoc_cleanup (); 

    return 0; 
} 



 

Makefile 설정예제

-I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0/ -lmongoc-1.0 -lbson-1.0 를 추가 해주어야 정상적으로 빌드된다.

 

PROG = olive_server
MODULE_CFLAGS=-DMG_ENABLE_THREADS -DMG_ENABLE_HTTP_WEBSOCKET=0 
SSL_LIB ?= openssl
SOURCES = $(PROG).c ../mongoose.c api_server.c
CFLAGS = -g -W -Wall -Werror -I../ -Wno-unused-function -I/usr/local/include/libmongoc-1.0 -I/usr/local/include/libbson-1.0/ -lmongoc-1.0 -lbson-1.0 $(CFLAGS_EXTRA) $(MODULE_CFLAGS)

all: $(PROG)

ifeq ($(OS), Windows_NT)
# TODO(alashkin): enable SSL in Windows
CFLAGS += -lws2_32
CC = gcc
else
CFLAGS += -pthread
endif

ifeq ($(SSL_LIB),openssl)
CFLAGS += -DMG_ENABLE_SSL -lssl -lcrypto
endif
ifeq ($(SSL_LIB), krypton)
CFLAGS += -DMG_ENABLE_SSL ../../../krypton/krypton.c -I../../../krypton
endif
ifeq ($(SSL_LIB),mbedtls)
CFLAGS += -DMG_ENABLE_SSL -DMG_SSL_IF=MG_SSL_IF_MBEDTLS -DMG_SSL_MBED_DUMMY_RANDOM -lmbedcrypto -lmbedtls -lmbedx509
endif

ifdef ASAN
CC = clang
CFLAGS += -fsanitize=address
endif

$(PROG): $(SOURCES)
	$(CC) $(SOURCES) -o $@ $(CFLAGS)

$(PROG).exe: $(SOURCES)
	cl $(SOURCES) /I../.. /MD /Fe$@

clean:
	rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)