I'm on your side, when times get rough.

2021-05-28

[C/C++] C Runtime Compile

Filed under: Programming — Peter_KIM @ 08:16
“C/C++ 프로그램에서 C 코드를 마치 스크립트처럼 입력의 값으로 사용할 수 있을까”에 대한 고찰은 몇 년 전에 해결된 과제였습니다.
이것을 해결하려고, 컴파일러의 구문 분석 등의 기초 공부를 다시 하기도 했습니다.

이론적으로는 입력된 코드를 라이브러리 형태의 모듈(LIB, DLL …)로 만들어서 동적으로 호출하면 될 것 같기도 합니다만, 이렇게 하는 것은 매우 복잡하고 실행 시간도 오래 걸리게 됩니다.
여러가지 해법을 고민한 결과 이런 과제를 수행하기에 매우 적당한 것을 찾았습니다.
Tiny C Compiler – C Scripting Everywhere – The Smallest ANSI C compiler
“Tiny CC” https://bellard.org/tcc/
이 작은 컴파일러는 라이브러리 형태로 만들어서 사용할 수 있으며, Compile 관련 함수를 제공합니다. 바로 이 기능을 이용한다면, C 코드를 문자열 형태로 입력하여 사용할 수 있습니다.

사이트에 접속하면, 원래의 저작자는 더 이상 이 컴파일러와 관련된 작업을 하지 않는다는 아쉬운 소식이 있습니다. 내려 받기를 수행하면 꽤 오래전에 올려놓은 바이너리와 코드를 얻을 수 있습니다.
소스 코드를 받을 수도 있지만 MSVC 컴파일러로 소스를 제어하기에는 설명서도 없고 너무 복잡합니다. 그냥 미리 만들어 놓은 바이너리와 헤더 파일이 있는, tcc-0.9.27-win64-bin.zip 파일을 내려 받았습니다.
압축을 해제하면, 아래와 같은 디렉터리를 볼 수 있습니다.
X:\TCC
├─doc
├─examples
├─include
│  ├─sec_api
│  │  └─sys
│  ├─sys
│  ├─tcc
│  └─winapi
├─lib
└─libtcc

VC/VC++ 프로젝트에서 이 코드를 사용하려면, *.LIB, *.DLL, *.H 파일이 필요합니다.
lib 디렉터리에서 찾아보니, 리눅스에서나 볼 수 있었던 *.a 파일이 있습니다. libtcc1-32.a, libtcc1-64.a 이름에서 보듯이 x86, x64 전용 파일입니다.
libtcc 디렉터리에 있는 *.def 파일과 *.h 파일을 프로젝트에 이용할 수 있을 것입니다. libtcc.def 파일을 이용하여, *.LIB 파일을 만듭니다.

X:\TCC\libtcc>LIB.EXE /DEF:libtcc.def /OUT:LIBTCC.LIB /MACHINE:X64
Microsoft (R) Library Manager Version 14.29.30037.0
Copyright (C) Microsoft Corporation. All rights reserved.

Creating library LIBTCC.LIB and object LIBTCC.exp

아래처럼 명령을 수행하고 만든 LIBTCC.LIB 파일과 헤더 파일을 복사하여 VC/VC++ 소스 코드에서 사용하면 됩니다.
……
#include “../include/libtcc.h”
#if defined (_MSC_VER)
#if defined _M_X64
#pragma comment (lib, “../lib/x64/libtcc.lib”)
#elif defined _M_IX86
#pragma comment (lib, “../lib/x86/libtcc.lib”)
#endif
#endif
……

헤더 파일(libtcc.h)을 보면, 컴파일에 관련된 함수들이 많이 보입니다. 여기서 주목해야할 함수는 아래와 같습니다.

– tcc_compile_string: 코드 문자열을 컴파일 합니다.
– tcc_relocate: 컴파일한 코드를 프로그램의 내부의 메모리에 배치합니다.
– tcc_get_symbol: 라이브러리에서 함수의 포인터를 동적으로 얻듯이 메모리에 배치한 함수의 포인터를 얻습니다.

이 세 함수를 적절히 사용하면, C 코드의 스크립트에서 작성된 함수를 동적으로 호출할 수 있습니다.

이런 과정이 필요했던 이유는 통신 프로그램을 작성하는데에 있어서 어떤 함수에서 필요한 인자가 구조체로 정의한 객체의 포인터이고, 해당 구조체를 프로그램의 외부에서 정의하는 것이 필요했기 때문입니다.
즉, 구조체의 정의를 바꾸더라도 프로그램 전체를 다시 작성하는 일을 줄이는게 그 목적이었습니다.

예제로 매우 간단한 프로그램을 만들어 보겠습니다.

#include <stdio.h>
#include "../Include/libtcc.h"
 
#pragma comment(lib, "../Lib/X64/LIBTCC.LIB")
 
int main()
{
    const char* lpszSource = 
        "int printf(char const* const _Format, ...);"
        "int AddTwoNumber(int n1, int n2) {"
        "	printf(\"TinyCC: %d \\n\", n1 + n2);"
        "	return n1 + n2;"
        "}";
    int nResult = 0;
    TCCState* pTcc = tcc_new();
    if (!pTcc)
        return -1;
 
    tcc_set_output_type(pTcc, TCC_OUTPUT_MEMORY);
 
    if (tcc_compile_string(pTcc, lpszSource) > 0) 
        return -1;
 
    tcc_relocate(pTcc, TCC_RELOCATE_AUTO);
 
    int (*AddTwoNumber)(int n1, int n2) = tcc_get_symbol(pTcc, "AddTwoNumber");
    nResult = AddTwoNumber(1, 2);
 
    printf("Result: %d", nResult);
 
    tcc_delete(pTcc);
    return 0;
}
주의할 점은 C 런타임 함수를 선언한 것입니다.
함수 선언 대신에 #Include <stdio.h> 코드를 써도 됩니다. 그러나 반드시 아래와 같이 코드를 추가해야 합니다, 이때에는 ANSI C 모든 헤더 파일을 디렉터리에 복사해두는 것이 좋습니다.
tcc_add_include_path(pTcc, “../Include”);

코드를 작성하고 컴파일과 링크 과정을 거치면 실행 파일이 만들어집니다.
libtcc.dll 파일을 실행 파일이 있는 곳에 복사하고, 실행합니다.
tcc: error: library ‘libtcc1-64.a’ not found
*.a 파일을 찾는 오류가 나타납니다. 이 파일의 위치는 DLL 파일이 있는 디렉터리의 아래에 있는 “LIB” 디렉터리 입니다.

실행을 하면 아래의 결과를 확인할 수 있습니다.
TinyCC: 3
Result: 3

몇 년이 흘렀지만, 이렇게 접근할 일도 이런 방법을 안내하는 일도 거의 없었습니다.
그러나, 이런 방법이 꼭 필요한 일도 있습니다.

2021-05-26

[Windows 10] Cannot play audio with “LG Sound Bar”

Filed under: ect. — Peter_KIM @ 11:06

모처럼 Windows 10 운영 체제를 21H1 버전으로 업데이트 했습니다.

음악을 좀 더 좋은 소리로 들으려고 사운드 바에 연결했습니다. 그런데, 소리가 노트북에서 나고 있습니다.

Windows 10 블루투스 설정화면으로 갔습니다. 연결되었다는 표시가 있었습니다.

사운드 설정에서 보니 기본 스피커만 보일 뿐 사운드 바는 표시되지 않았습니다.

난감한 상황이 되었습니다. 제어판에서 사운드 설정을 보니 아래의 그림과 같이 설정되어 있길래, 마우스 오른쪽 버튼으로 선택하고 “연결” 메뉴를 아무리 눌러도, 연결이 되지 않습니다.

삼성의 갤럭시 폰으로 LG 사운드 바에 연결하고 음악을 틀었는데, 잘 들립니다. Windows 10 업데이트에 오류가 있는 것은 아닌지 의심이 들기 시작했습니다.

여러 자료를 찾아본 결과, Windows 10 버그가 맞습니다.

이 문제를 해결하려면, 레지스트리 편집기에서 설정을 바꾸어야 합니다. 그리고 컴퓨터를 다시 시작하고 연결했더니 잘 작동합니다. 괜히, 좋은 사운드 바를 원망했습니다. MS 윈도우가 원인이었다니……

경로: \HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Bluetooth\Audio\AVRCP\CT

키: DisableAbsoluteVolume

값: 1

Blog at WordPress.com.