[MinGW ] 윈도우용 SQLCipher C에서 자바까지

2023. 3. 30. 19:04프로그래밍

728x90

 

 

[MinGW ] 윈도우용 SQLCipher C에서 자바까지

오늘은, Sqlite을 사용하여 프로젝트를 작성하기 위해서는 어떻게 해야 될지에 대해서 얘기를 해보도록 한...

blog.naver.com

 

오늘은, Sqlite을 사용하여 프로젝트를 작성하기 위해서는 어떻게 해야 될지에 대해서 얘기를 해보도록 한다.

SQLCipher를빌드하고 C로 예제를 만들고 난 다음 내가 젤 익숙한 자바를 사용하여 이 라이브러리를 사용하게 되면연동에 관련된 문제로 다음 번부터는 크게 씨름 할 것 같지 않아서 이렇게 적어 두도록 한다.

 

저번에 안드로이드 용으로 문서1를 만들어 보기는 했지만,

이는 sqlcipher 제작사가 이미 jdbc 드라이버도 만들어져 있고 빌드 시에도, 구글이 워낙 툴체인을 잘 만들어 놓은 관계로 몇몇 설정 만으로 라이브러리를빌드하고 설정하고 deploy 만 하면 되는 과정 이었지만, 이번의경우에는 약간 사정이 다르다고 할까?

 

우선, 윈도우용으로빌드하기가 까다롭다라는 것이 중론이고, mingw 환경에서 제대로 컴파일하고 빌드 하는 것이 가능한지여부도 참고 자료가 부족하였다. 아주 많은 시간을 투자 하였다고나 할까?

결과물이 나름 만족하기는 하지만 그렇다고, 정말 잘 만들어 진 것으로보이진 않는다. 제약 사항이 있다고나 할까?

 

SQLCipher MinGW gcc로 빌드하기

 

1. Openssl 빌드하기 - 정적 빌드하기

다음 문서 내용2에 따라서 Openssl 라이브러리를 빌드 하기로 한다. 이번 경우는 정적 빌드로 빌드하였다.

version: https://www.openssl.org/source/old/1.0.1/

/source/old/1.0.1/index.html

www.openssl.org

의 최신 버전을 사용 하였다.

 

-- openssl static build

./Configure --prefix=$PWD/dist no-shared no-asm mingw
make depend
make
make install
 

제대로 실행 되는 지 여부는 해당 디렉토리에서 openssl.exe 를실행시켜 다음과 같이 확인하였다.

 

1. Sqlcipher 빌드하기

Sqlcipher 소스 코드 다운 받기; github에서 다음과 같이 다운 받으면 되겠다.

git clone https://github.com/sqlcipher/sqlcipher
 

 빌드하기에 앞서서 다음의 문서를 한 번 읽어 볼 필요가 있을 듯 하다.

https://github.com/sqlcipher/android-database-sqlcipher/issues/298

Can we fix some SQLCipher for build flags? · Issue #298 · sqlcipher/android-database-sqlcipher · GitHub

github.com

주요 논점은 각 플래그를 설정 하는 것마다, 링크를 하는 함수의 내용이 약간씩 틀려 지는 것이 아닌가 하는 생각이 든다. 특히 각 플래그를 설정 했을 때 나타나는 함수를 나름 이 사람이 연구 한 것이 아닌가 한다.

There seem to be some irrelevant and duplicate SQLCIPHER_CFLAGS defined in the Makefile:
  • SQLITE_THREADSAFE
- appears twice (first time with correct [default] value, second time with no value specified)
  • SQLITE_ENABLE_MEMORY_MANAGEMENT - appears twice
  • SQLITE_ENABLE_FTS3_BACKWARDS - does not appear in https://www.sqlite.org/compile.html or sqlcipher source
  • SQLITE_ENABLE_LOAD_EXTENSION
- Is there any way a SQLCipher user
would actually load binary extensions on Android?
  • SQLITE_ENABLE_COLUMN_METADATA
- from https://www.sqlite.org/compile.html
the following functions do not seem to be used here:
sqlite3_column_database_name(),
sqlite3_column_database_name16(),
sqlite3_column_table_name(),
sqlite3_column_table_name16(),
sqlite3_column_origin_name(),
or sqlite3_column_origin_name16()
  • SQLITE_ENABLE_UNLOCK_NOTIFY
- sqlite3_unlock_notify() not used here
  • SQLITE_ENABLE_FTS4_UNICODE61 –
I did not find it in https://www.sqlite.org/compile.html
or SQLCipher source
Looking through the generated amalgamation
it seems from one of the headers that NDEBUG
will be automatically defined or undefined opposite toSQLITE_DEBUG.
Also: looking at
https://www.sqlite.org/compile.html#recommended_compile_time_options
I was wondering if the following items should be defined:
  • SQLITE_OMIT_DECLTYPE (sqlite3_column_decltype() and
sqlite3_column_decltype16() do not seem to be used here)
  • SQLITE_OMIT_DEPRECATED - none of the reference functions (
sqlite3_aggregate_count(),
sqlite3_expired(),
sqlite3_transfer_bindings(),
sqlite3_global_recover(),
sqlite3_thread_cleanup(),
or sqlite3_memory_alarm()) seem to be used here
  • SQLITE_OMIT_PROGRESS_CALLBACK
(sqlite3_progress_handler() does not seem to be used here)
  • SQLITE_OMIT_SHARED_CACHE
(sqlite3_enable_shared_cache() does not seem to be used here)
In general I would like to get these
build settings consistent for Android, iOS, and
Windows in my Cordova plugin and would like
to avoid maintaining a custom Android build if possible.
Thanks for your consideration.
P.S. I would be happy to raise a pull request if desired.

그리고 다음과 같이 configure 및 컴파일 빌드를 수행 하여 준다.

더 자세한 내용은 컴파일 페이지3를 참조 해야 할 듯...

(https://www.sqlite.org/compile.html)

echo $PKG_CONFIG_PATH
export PKG_CONFIG_PATH=/home/tobee/openssl/lib/pkgconfig:$PKG_CONFIG_PATH

./configure --prefix=$PWD/dist \
--disable-editline --enable-tempstore=yes \
CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_CORE -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_STAT2 -DSQLITE_HAS_CODEC -I/home/tobee/openssl/include " \
LIBS="-lcrypto -L/mingw/lib -lgcc -lgdi32 -lopengl32" LDFLAGS="-L/home/tobee/openssl/lib"
make
make install
 

빌드를 진행하고 나면 dll 의존성이 있는 것들이 생기는 데.. 다 모아 보면 다음과 같이 파일이 존재 해야만 이 sqlcipher를 구동 할 수가 있다. 정적 빌드를해 보았으나, 능력이 안됨…

 

위의 내용은 앞으로 자바 JDBC 드라이버를 잡을 때도 유용하게 쓰이는 dll들이 될 것이다. 여하튼 sqlcipher.exe 실행 파일을 실행 해 주면 다음과 같이 명령어 프롬프트를 가지고 sqlcipher가 구동된다.

 

위의 부분이 약간 바뀌었음. 현재는 그냥 실행파일 실행으로 바뀌었으며, 위의 dll 파일들이 필요 없어 졌음. - 첨부파일 참고

 

명령어를 실행 해보면 될 것이다. 하지만 원래 툴을 만들것이 아니라 라이브러리를 만들어서 내가 원하는 곳 아무 곳에서 사용해 보는 것이 아니었는가?

테스트 프로그램을 만들기를 진행 하여보자.

 

1. 테스트 프로그램 만들기 - C

다음과 같이 간단한 프로그램으로 테스트를 진행 해보도록 한다. 간단히 버전 정보 만을 읽어서 콘솔에 표시하는 프로그램을 작성하였다.

 

테스트 프로그램 1:

#include <sqlite3.h>
#include <stdio.h>

int main(void) {
	printf("%s\n", sqlite3_libversion());
	return 0;
}
 

빌드는 정적라이브러리로 빌드하여 다음과 같이 사용한다.

gcc -static -std=gnu99 -Wall -I/home/tobee/sqlcipher/include/sqlcipher -I/home/tobee/openssl/include -c -o test_ver.o test_ver.c
gcc -static -std=gnu99 -Wall -I/home/tobee/sqlcipher/include/sqlcipher -I/home/tobee/openssl/include -o test.exe test_ver.o /home/tobee/sqlcipher/lib/libsqlcipher.a /home/tobee/openssl/lib/libcrypto.a -lgdi32
strip test.exe
 

제대로 빌드 되었다면 결과는 다음과 같이 나오면 된다.

[tests]./test
3.15.2

Sqlcipher 디렉토리 내부의test 디렉토리의 wordcount.c를 빌드하면 다음과 같은 로그가 나온다

gcc -static -std=gnu99 -Wall -I/home/tobee/sqlcipher/include/sqlcipher -I/home/tobee/openssl/include -c -o wordcount.o wordcount.c
wordcount.c: In function 'main':
wordcount.c:473:12: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("%s sum of cnt: %lld\n", zTag, sumCnt);
^
wordcount.c:473:12:
warning: too many arguments for format [-Wformat-extra-args]
wordcount.c:473:12:
warning: unknown conversion type character 'l' in format [-Wformat=]
wordcount.c:473:12:
warning: too many arguments for format [-Wformat-extra-args]
wordcount.c:477:14:
warning: unknown conversion type character 'l' in format [-Wformat=]
printf("%s double-check: %lld\n", zTag,
sqlite3_column_int64(pSelect, 0));
^
wordcount.c:477:14:
warning: too many arguments for format [-Wformat-extra-args]
wordcount.c:477:14:
warning: unknown conversion type character 'l' in format [-Wformat=]
wordcount.c:477:14:
warning: too many arguments for format [-Wformat-extra-args]
gcc -static -std=gnu99 -Wall -I/home/tobee/sqlcipher/include/sqlcipher -I/home/tobee/openssl/include -o wordcount.exe wordcount.o /home/tobee/sqlcipher/lib/libsqlcipher.a /home/tobee/openssl/lib/libcrypto.a -lgdi32
strip wordcount.exe

 Warning 메시지를 없애기 위해서 다음 사이트4를 참고 하였다.

예를 들면

printf("%s sum of cnt: %lld\n",zTag, sumCnt);
 

의 형태는 윈도우에서 제공하지 않는다고 하니, 내 경우에는 다음과같이 소스를 변경하여 주었다.

printf("%s sum of cnt:%I64d\n", zTag,sumCnt);
 
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>

static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
	/*feed this callback function to handle theresultset returned by the select statement*/
	int i;
	for (i = 0; i < argc; i++) { //loop over results
		printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); //gota love how human radable c is
	}
	printf("\n");
	return 0;
} /*end callback*/

int main(int argc, char** argv)
{
	sqlite3 *db;
	/*int ch;*/
	if (sqlite3_open("mydb.db", &db) == SQLITE_OK) {
		printf("DB file is open\n");
		
		if (sqlite3_exec(db, (const char*)"PRAGMA key ='password'", NULL, NULL, NULL) == SQLITE_OK){
			printf("Accepted Key\n");
		};
		if (sqlite3_exec(db, (const char*)"CREATE TABLE testtable (id int, name varchar(20));", NULL, NULL, NULL) == SQLITE_OK) {
			printf("Created Table\n");
		};

		if (sqlite3_exec(db, (const char*)"INSERT INTO testtable (id,name) values (0,'alice'), (1,'bob'), (2,'charlie');", NULL, NULL, NULL) == SQLITE_OK) {
			printf("Gave it some data\n");
		};

		if (sqlite3_exec(db, (const char*)"SELECT * FROM testtable;", callback, NULL, NULL) == SQLITE_OK) {
			printf("Sent Select\n");
		};
	}
	sqlite3_close(db); /*close it up properly*/

	/*ch = getch(); just a hack to keep the console open during debugging*/
	/*printf("%c\n", ch);*/
	return 0;

}/* end test_db.c*/
 

빌드하기

gcc -static -std=gnu99 -Wall -I/home/tobee/sqlcipher/include/sqlcipher -I/home/tobee/openssl/include -c -o test_db.o test_db.c
gcc -static -std=gnu99 -Wall -I/home/tobee/sqlcipher/include/sqlcipher -I/home/tobee/openssl/include -o test_db.exe test_db.o /home/tobee/sqlcipher/lib/libsqlcipher.a /home/tobee/openssl/lib/libcrypto.a -lgdi32
strip test_db.exe
 

결과물

[tests]$ ./test_db.exe
DB file is open
Accepted Key
Gave it some data
id = 0
name = alice
id = 1
name = bob
id = 2
name = charlie
id = 0
name = alice
id = 1
name = bob
id = 2
name = charlie
id = 0
name = alice
id = 1
name = bob
id = 2
name = charlie
id = 0
name = alice
id = 1
name = bob
id = 2
name = charlie
id = 0
name = alice
id = 1
name = bob
id = 2
name = charlie
Sent Select
 

​이로써 sqlcipher를 이용한 C 테스트 소스를 만들고 빌드하여 결과물을 확인 해 보는 단계까지 이르렀다. sqlbrowser 라는 툴이 있으므로 이 툴을 사용해서 데이터베이스를 열어보도록 한다.

 

Sqlbrowser의 사용

아래 그림과 같이 데이터베이스 파일을 열려면 암호를 입력하라는 메시지가 나온다. 위에 소스에서 만들어진 파일이므로 당연히 암호는 'password'이다.

데이터베이스를 확인해 보면, 콘솔 창에서 확인 한 내용과 똑 같음을 알 수가 있다.

 

 

여기까지가 sqlcipher 라이브러리를 윈도우용으로 포팅하고 테스트프로그램을 C로 작성하는 과정을 살펴 보았다.

다음에서는 jdbc 라이브러리를 가져와서 구동하고 자바에서 이를 접근 하는 방법을 알아보도록 하자.

 

첨부된 파일 sqlcipher-exe.zip 파일은 콘솔 커맨드라인 툴이다.

openssl-exe.zip은 openssl 실행 파일이다.

tests.zip 파일은 위의 테스트를 수행 했던 파일들이다(Makefile 확인).

 

 

이상.


 

728x90