利用 Tiny C compiler 編譯 Windows 10 64 位元 dll 動態連結庫, 並由 Python 程式呼叫執行.

利用 Tiny C 編譯 Tiny C

http://download.savannah.gnu.org/releases/tinycc/ 下載 Win64 C 程式編譯器, 並下載 Tiny C compiler 0.9.26 版程式原始碼. 利用下列批次檔案進行編譯.

compileTCC.bat 檔案內容:

echo Use TCC to compile TCC

echo Set CC=tcc

set CC=tcc
set target=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
set P=64

echo tools: tiny_impdef.exe, tiny_libmaker.exe

%CC% %target% win32/tools/tiny_impdef.c -o tiny_impdef.exe
%CC% %target% win32/tools/tiny_libmaker.c -o tiny_libmaker.exe

echo Compile libtcc.dll

if not exist libtcc\nul mkdir libtcc
%CC% %target% -w -shared -DLIBTCC_AS_DLL -DONE_SOURCE libtcc.c -o libtcc.dll
tiny_impdef libtcc.dll -o libtcc/libtcc.def

echo Compile tc.exe

%CC% %target% tcc.c -o tc.exe -ltcc -Llibtcc

echo Compile libcc1.a

%CC% %target% -c lib/libtcc1.c
%CC% %target% -c win32/lib/crt1.c
%CC% %target% -c win32/lib/wincrt1.c
%CC% %target% -c win32/lib/dllcrt1.c
%CC% %target% -c win32/lib/dllmain.c
%CC% %target% -c win32/lib/chkstk.S
%CC% %target% -c lib/alloca86_64.S
tiny_libmaker lib/libtcc1.a libtcc1.o alloca86_64.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o

編譯 dll 動態程式庫

首先, 建立一個 multiply.c 程式:

#include <stdio.h>

int multiply(int, int);

__declspec(dllexport) int
multiply(int num1, int num2)
{
return num1 * num2;
}

利用下列指令, 將 multiply.c 編譯為動態連結庫 myltiply.dll

tcc -w -shared -DLIBTCC_AS_DLL -DONE_SOURCE multiply.c -o multiply.dll

接著利用下列 Python3 程式, 透過 ctypes 模組導入 multiply.dll, 並且執行動態連結程式庫中的 multiply() 函式.

import ctypes

lib = ctypes.CDLL('multiply.dll')
result = lib.multiply(3, 2)
print(result)

因為 ctypes 內建傳回值為 int, 因此若 C 對應動態連結庫輸入或傳回值為浮點數, 就必須手動宣告.

例如, 將上述函式的輸入與輸出均由 int 改為 float 如下:

// multiply2.c
#include 

float multiply(float, float);

__declspec(dllexport) float
multiply(float num1, float num2)
{
return num1 * num2;
}

可利用下列指令, 將 multiply2.c 編譯為動態連結庫 myltiply2.dll

tcc -w -shared -DLIBTCC_AS_DLL -DONE_SOURCE multiply2.c -o multiply2.dll

但是 Python3 程式部份就必須改為:

import ctypes

lib = ctypes.CDLL('multiply2.dll')
# By default functions are assumed to return the C int type. Other return types can be specified by setting the restype attribute of the function object.
lib.multiply.restype = ctypes.c_float
result = lib.multiply(ctypes.c_float(3.0), ctypes.c_float(2.0))
print(result)