많이 쓰시는 분들은 무슨 의미인지 바로 파악이 가능하실 텐데 make를 하되 4개의 스레드를 만들어서 돌린다는 의미입니다. 여기서 -j4를 파라미터라고 합니다. 그런데 C프로그램에선 이것을 어떻게 파악을 할까요?
C/C++의 기본적인 main함수의 구조를 보면
int main(int argc, char[][] argv)
이런 구조가 있습니다.
(int 대신 void를 쓰기도 하지만 어찌됐든 보통은 int가 기본입니다.)
여기서는 argc라는 정수형 하나와 argv라는 이중 배열 문자 혹은 문자열의 배열을 의미합니다.
그 어떤 파라미터를 받지 않는 다면 뒷부분을 모두 생략 가능합니다만 CLI특성상 뒤에 파라미터를 받는 경우가 대부분입니다.
즉, argc는 파라미터의 갯수이고 argv는 파라미터의 갯수입니다.
다만 argv[0]에 들어가는 것은 무조건 실행되는 프로그램의 경로를 넣습니다.
그러니까
make -j4
이 명령을 넣었을 때 make의 main함수에서는
argc = 2
argv[0] = /bin/make
argv[1] = -j4
이렇식으로 들어간다는 의미입니다. 그러면 다시한번 vlmcsd의 함수를 뜯어볼까요. (이것이 본래 main함수라는건 잊지 않으셨죠?)
int argc와 함께 CARGV argv 변수를 받고 있습니다. CARGV는 define된 무언가일겁니다. (VSCode에서 저건 보통 define 된 이름입니다.) CARGV를 한번 검색해봅시다.
types.h에 보면 typedef로 처리되어 있군요. 구조체가 아니었네요. const char *const * 형태를 의미합니다. 즉, 이중포인터 = 이중배열 구조를 의미합니다.
argv구조와 같다는 것입니다.
이걸 말씀드리는 이유는 server_main함수를 안드로이드의 자바/코틀린에서 호출할 예정이기 때문입니다. 그러려면 함수의 구조를 그대로 만들어서 호출해야겠지요.
그리고 vlmcsd의 동작에 대해 말할 필요가 있습니다.
터미널에서 vlmcsd를 실행하면
그냥 이렇게 커서가 뚝 떨어집니다. 그래서 ps -A | grep vlmcsd를 해보면
이렇게 뒤에서 프로세스가 돌고 있는 것을 볼 수 있습니다.
이건 백그라운드에서 돌릴 수 있게끔 코드가 짜여져 있기 때문입니다. 그런데 우리는 vlmcsd를 따로 실행하는 것이 아니라 안드로이드 앱의 프로세스 내에서 이것을 돌려야 합니다. 미리 말씀드리자면 이 코드를 그대로 호출한 결과 안드로이드 프로세스가 같이 죽어버리는 결과가 나옵니다. 백그라운드 프로세스에 등록후에 자기 자신을 꺼버리게 때문입니다.
그래서 다른 서버프로그램 처럼 대몬으로 동작하는 것이 아니라 대기하게 하는 방식이 필요합니다. 그런데 코드를 뒤져보니 foreground에서 돌아가게 하는 코드가 존재하더군요.
사실 ./vlmcsd -h 만 해도 뜨는 파라미터입니다.
그러니까 ./vlmcsd -D 이렇게 명령을 주면
이렇게 커서가 떨어지지 않고 대기를 하게 됩니다.
이 이야기를 하는 이유는 눈치빠른 분이라면 아실거 같은데 server_main함수를 호출 할때 argv에 "-D"를 넣어야 한다는 겁니다.
그러니까 함수 호출 형태가
int argc = 2;
char[][] argv = {"./', "-D"};
server_main(argc, argv);
이렇게 되어야 한다는 겁니다. argc가 2인 이유는 1번째는 무조건 경로가 들어가야 하므로 추가 파라미터가 2번째부터 들어가야 하기 때문입니다. 아래 argv 보면 첫번째 배열에는 "./"가 들어가 있지요. 그냥 무엇이 들어가야 할지 몰라서 현위치를 지정했습니다.
재미없는 이론 시간은 이제 끝났습니다. 이제 진짜로 Android Studio에서 이 코드를 넣어봅시다. Android Studio의 세팅은 생략하겠습니다.
Android Studio에서 New Project를 해봅시다.
여기서 Native C++을 사용하겠습니다.
그리고 저는 낡은 인간(?)이므로 JAVA를 사용할 예정입니다. Kotlin이 익숙하신 분은 Kotlin을 쓰시면 됩니다.
그리고 컴파일러는 그냥 기본 툴체인을 사용합니다. 어차피 저희는 표준C를 사용하는 것이니 그냥 편한대로 하면 됩니다.
`
이제 기본적인 구조가 완성 되었습니다. 이 기본 구조도 분석해볼 필요는 있는데 굳이 따로 하지는 않겠습니다. 간단하게 C++에서 문자열을 리턴하는 함수를 native-lib.cpp에 만들고 MainActivity에서 native로 해당 함수(stringFromJNI() )를 선언한뒤 onCreate할때 해당 함수를 호출하는 방식입니다.
C/C++로 짜여진걸 안드로이드로 포팅하려면 우선 기본 프로그램을 so라이브러리 형태로 바꾼뒤 안드로이드의 JNI로 해당 라이브러리를 호출하는 방식으로 만들어집니다.
대신 생각해야하는게 몇 가지 있습니다.
1. 리눅스나 유닉스의 지원이 되는가 2. Xorg등 GUI툴킷에 종속되어있는가
1의 경우는 당연하게도 Windows/Dos만 되는건 애초에 ELF(*.so)형식으로 만들수가 없기 때문입니다. 이건 리눅스나 유닉스용 포팅이 우선되어야합니다.
2는 안드로이드에서는 Xorg나 Wayland가 안 돌아가기 때문입니다. GUI툴킷도 여러종류가 있지만 GTK에 종속된경우 포팅이 까다롭습니다. 그냥 새로짜는게 더 빠른편입니다. Qt의 경우 그나마 낫지만 역시 OS에서 제공하는 기능을 쓸 경우 그것도 대체할 궁리를 해야합니다.
그래서 생각해보다가 주로 CLI와 단일파일로 구성된 서버프로그램을 한번 포팅해보려고 합니다. 서버프로그램은 대부분 백그라운드 대몬형태로 돌아가며 추가입력을 받거나 하는 경우가 거의 없습니다. 한번 실행하면 계속 돌아가기 때문에 그 부분만 신경쓰면 될겁니다.
순수 C로 짜여져있고 빌드후에 단일파일로 나오게 되는 구조입니다. 그리고 vlmcs라는 클라이언트를 따로 제공하고 있어서 서버의 포팅이 정상적으로 되었는지 확인이 가능합니다.
무엇보다 안드로이드 지원이 이미 고려되어있어서 좀 더 수월 할것 같은것도 한 몫했습니다. 다만 여기서 기본적인 안드로이드 지원은 Termux같은 별도의 안드로이드 내부 터미널에서 쓰는걸 전제로 되어있어서 이래저래 삽질이 필요하긴합니다.
실제로 저장소에서 제공하는 바이너리를 adb shell로 실행하면(실행권한 문제로 /data/local/tmp로 밀어넣어야 합니다.) 실행이 되는걸 볼 수있긴한데 우린 이 방법대신 일반 안드로이드 앱형태로 포팅하는걸 목적으로 하겠습니다.
방법은 아마 이렇게 되겠지요. 1. 기본 프로그램의 main함수를 찾는다. 2. main함수의 이름을 바꾸고 JNI가 지원되도록 형태를 바꾼다.(JNIEXPORT로 시작하는 함수로) 3. 프로그램의 make를 고쳐서 so형태로 나오게 바꾼다. 4. 안드로이드 스튜디오에서 so를 NDK기반 프로젝트에 밀어넣고 위에서 바꾼 main함수를 native로 만든다. 5. 몇몇 부분은 필요에 따라 C구현을 일부고친다.
끝부분 장식이 있느냐(세리프, 부리, 명조 기타등등-이하 세리프) 끝부분 장식이 없느냐(산세리프, 민부리, 고딕 기타등등 - 이하 산세리프)
이건 로마자도 아랍어도 그렇고 심지어 한자도 그렇습니다.
끝에 장식이 있는건 사실 예쁘라고 만든게 아니지요. 묽은 잉크 펜이나 붓으로 글씨를 쓰면 필연적으로 끝부분에 덩어리?가 생기기 마련입니다. 세리프체는 인간이 글을 쓰다보니 자연스럽게 생긴 모양입니다. 그런데 이 장식이 획의 끝을 확실하게 나타내다보니 상대적으로 작은 글씨일때 효과적이라고 합니다. (어디까지나 종이에 표시할때 이야기지만요)
동양에서는 조금 다른데 목판인쇄술이 발전하면서 목판 특유의 결대로 찣어지는 현상을 줄이기위해 끝부분 장식을 새기게 되었습니다. 목판가로줄이 가늘면 목판이 결국 결대로 쭉 부러질수있으니까요. 이를 명나라 시대에 주로 쓰였다해서 명조라고 부르는 계기가 되었습니다. 그래서 요즘 명조라고 부르는 서체는 실제랑 결이 좀 다르긴합니다.
산세리프체는 장식을 최대한 줄이고 멀리서도 잘보이게 만드는것이 특징입니다. 그래서 큰 글씨에 잘 어울린다고 합니다. 표지판이나 알림, 제목등에서 그 특징이 보입니다. 사실 글씨가 크다보니 붓이나 펜으로 쓸때 깔끔하게 마무리가 가능했던것도 있겠지요.
한국에선 판본체라고 부르는게 얼추비슷한데 글씨가 직선과 원 위주인 한글에 잘 어울리는 구조입니다.
그런데 세상이 변하고 펜도 발전했으며 붓은 상대적으로 덜 쓰이게 되었습니다. 그리고 연필도 발전해서 펜보다 더 동글동글한 필기구도 많아졌습니다. 심지어 이러한 필기도구로 효율적으로 글씨를 쓰기위한 필기체도 개발되었지요.
그래서인지 최근에는 작은글씨에도 산세리프(민부리)를 쓰거나 책의 제목같이 큰글씨에 세리프(부리)를 쓰는 경우도 크게 늘었습니다. 그리고 모바일기기가 늘어나며 상대적으로 간단명료한 산세리프의 사용량이 늘어났습니다.
그래서인지 예전보다 폰트의 종류는 많아졌는데 어쩐지 쓰이는 폰트는 비슷하다는 느낌입니다. 왠지 그냥 그렇다고요.
10년전만해도 이게 뭔 뚱딴지같은 소리냐 했을텐데 2025년 지금은 AMD만큼 리눅스 지원이 잘 되는 제품이 없습니다.
과거엔 인텔이 최고였고 ClearLinux라는 인텔에서 직접 만든 배포판도 있을 정도였지만 지금 인텔의 상태가 말이아니기에 리눅스관련 직원들이 해고되었다는군요. 실제로 몇몇기능은 커널에 구현되다 말았고요. (이러다 제온이 리눅스 서버시장에서 조차 밀리는거 아닌가 싶습니다)
AMD는 이와 반대로 리눅스 지원이 좋아지다못해 최고의 성능을 발휘하는 OS와 CPU가 되었습니다. 특히 쓰레드리퍼나 에픽을 쓸때 윈도우에 비해 리눅스의 성능이 정말 굉장하지요.
거기다 스팀덱출시 이후 라데온에서 리눅스의 Vulkan성능이 대폭 좋아져서 윈도의 라데온과 비교해 성능을 더 뽑아내고 있습니다. 심지어 Nvidia의 DLSS와 다르게 AMD는 비슷한 기능인 FSR도 네이티브로 돌리지요.
10년전만 하더라도 리눅스 데스크탑은 인텔CPU에 인텔그래픽이 진리였습니다. 성능문제는 둘째치고 안정성면에서 문제가 심했거든요. 만약 3D를 원한다면 Nvidia카드를 박아서 Nvidia의 독점드라이버를 설치해야했고요. 물론 그래도 안정성은 충분했습니다. 커널버전에 따른 호환성은 있었을지언정 드라이버만 설치되면 쓰는데는 지장이 없었으니까요.
그런데 AI의 대두이후 Nvidia의 드라이버는 CUDA를 위시한 컴퓨트성능위주로 흘러가게 되었고 Vulkan과 OpenGL성능이 나락으로 가기 시작했습니다. 언제부터인가 Vulkan의 지원되는 수준이 떨어지고 강점이었던 OpenGL의 안정성조차 떨어지더군요.
인텔은... 그때나 지금이나 바탕화면 표시기...였지요.
그런데 스팀덱에 AMD칩셋이 쓰이고 AMD가 Vulkan에 투자하면서 이야기가 달라지기 시작했습니다. Doom Eternal만 해도 Vulkan버전으로 돌리면 AMD그래픽카드에서 성능이 배로 좋아진다고 하지요. DirectX나 OpenGL성능이 경쟁사에 비해 떨어지니 최신API인 Vulkan에 투자한듯합니다. 그런데 그게 스팀덱에서 꽃을 피운듯합니다.
그리고 AMD의 드라이버는 (완벽한건 아니지만)오픈소스입니다. amdgpu라는 이름으로 공개되어있습니다. 커널에 직접 반영도 되고 덕분에 Wayland지원도 빨랐습니다. 그러다보니 사용자가 늘어날 수록 안정성이 좋아지는 경향이 있는데(버그리포트가 그만큼 많아지므로 생각지못한 패닉이 줄어듭니다) 스팀덱으로 인해 AMD그래픽사용자가 늘어나자 안정성이 급격히 좋아지기 시작했습니다.
최근 제 Debian시스템을 기준으로 Nvidia 1660에서 돌아가지 않던 게임이 RX570에서 돌아가는것을 확인했습니다. 원인은 Vulkan드라이버였습니다. FSR이 켜지면서 프레임이 좋아진건 덤입니다.
보통 이쪽은 하나도 모르는 수많은 꼰대들이 이런식으로 이야기하곤 합니다. 대부분 이렇게 이야기하는 사람들은 돈만보고 살아왔거나 자기자신만 아는 경우가 많습니다.
그런데 다들 알다시피 오픈소스는 수많은 기여자들의 취미활동으로 많은 수가 굴러갑니다. 솔직히 저 사람들 입장에선 이해가 안 될겁니다. 그런데 "성취감"이라는게 뭐라 형용할 수없는 중독성을 지니고 있습니다.
특히 내가 기여한 무언가가 다른 누군가에게 유용하게 쓰이고 있을때의 그 기분이란...
거기다가 보통 오픈소스프로젝트에는 한줄이라도 코드에 기여했거나 그냥 UI용 아이콘 하나라도 만들어주면 Thanks To에 이름이 올라갑니다. 영화 끝날때 크레딧에 내 이름이 써있다고 생각해보세요. 그리고 심지어 사람들이 작품을 칭찬한다고 상상하면 난 거기에 모래알만큼 기여했지만 어찌됐건 기분이 좋습니다.
=================================
솔직히 오픈소스에 기여하는건 어렵지 않습니다. 심지어 프로그래밍을 못 해도 충분히 기여가 가능합니다. 많은 프로그램들은 전세계에서 만들어지다보니 수많은 언어지원이 어렵습니다.
프로젝트관리자가 기여자들이 가져다주는 코드들 중 제일 쌍심지켜고 환영하는게 번역물입니다. 왜냐하면 그 사람들은 최소 영어와 자국어외에는 모르거든요. 번역기를 쓰면 당연히 번역투로 나오기 때문에 엉망이라는건 본인들도 아주 잘 알고 있습니다.
그런데 갑자기 특정언어권 사용자가 직접 번역해서 가져다주면 그렇게 좋을 수가 없겠지요. 아마 바로 다음버전에 적용해줄 가능성이 높습니다. "사용자층 확대" "모국어 사용자라는 신뢰" "번역을 기여할 정도로 내 작품을 쓰는자의 물건"
이 세가지 측면에서 좋은 기여가 없습니다.
개발자들은 번역된걸 쓰는경우가 적은편입니다. 보통영문판을 선호하지요. 하지만 보통의 한국인은 다릅니다. 기왕이면 한글판을 선호합니다.
저부터도 첫 오픈소스 기여가 번역이었습니다. 20문장 남짓이었지만 다음날 바로 적용해서 업데이트까지 해주더군요. 그리고 몇년이 지난지금 그 프로그램사용자들이 제 번역을 기준으로 사용법을 공유하고 있습니다.