Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
libraries:machine_code:mcl [2023-12-17 01:43] – Add example section w/ C++_with_new_delete geek | libraries:machine_code:mcl [2023-12-17 03:08] (current) – Fix broken markup geek | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== MCL [v1][v2] ====== | ====== MCL [v1][v2] ====== | ||
- | |||
- | A new kind of machine code library for AutoHotkey. | ||
THIS IS ALPHA SOFTWARE | THIS IS ALPHA SOFTWARE | ||
- | Currently only supports | + | MCL is a new kind of machine code library for AutoHotkey, which takes a no-nonsense approach to converting compiled code to AutoHotkey embedded machine code. It requires a GCC-based cross-compiler installed under PATH (named as gcc.exe/%%g++%%.exe or x86_64-w64-mingw32-gcc.exe/ |
+ | |||
+ | It was designed to work with mingw-w64 installed via [[https:// | ||
+ | |||
+ | Once your C or %%C++%% code has been compiled to a standalone function or class, that standalone class will have no dependency back to MCL. Scripts using your compiled code will need to include //just// the compiled code, and nothing else. You can check the releases of [[libraries: | ||
+ | |||
+ | MCL has a few extra features compared to other machine code tools, the big ones being: | ||
+ | |||
+ | * Support for both C and %%C++%% | ||
+ | * Includes some basic hand-written replacements for some of the most common standard headers | ||
+ | * Support for both 32 and 64 bit | ||
+ | * Allows very large constants (and Doubles, which GCC tends to promote to being a global constant, breaking code under other tools) | ||
+ | * Allows exporting one or more functions to AutoHotkey | ||
+ | * Allows exporting one or more global variables to AutoHotkey | ||
+ | * Generates a wrapper with all the DllCalls/ | ||
+ | * Allows importing functions from external DLLs into the C/%%C++%% code, such as from the Windows API or any other DLL you have laying around | ||
+ | * Generates standalone AutoHotkey code with the compiled machine code and wrappers, so you can include compiled code without including the MCL library. | ||
+ | |||
+ | Altogether, MCL has just enough features that a solid subset of standard C code can be compiled under it, and run (more or less) fine. | ||
+ | |||
+ | The primary goal of MCL is to enable much more complex machine code functions/ | ||
+ | |||
+ | MCL also supports a tiny subset of %%C++%% (no STL, exceptions, or RTTI). For example, see [[https:// | ||
+ | |||
+ | MCL also adds the ability for code to " | ||
+ | |||
+ | And a (low level) warning for this feature: There is a bug with mingw-w64 compilers which results in the stack being misaligned, which will cause a crash the next time a Windows API (or standard library) function is called from your C/%%C++%%. This bug can be tracked [[https:// | ||
+ | |||
+ | For an example of " | ||
+ | |||
+ | ---- | ||
- | Requires a gcc-based Windows %%C/C++%% compiler (for example, mingw-w64). MSVC is not supported. | + | If you have any questions about the library, please feel free to join [[https:// |
If you run into any problems, please report them as GitHub issues. | If you run into any problems, please report them as GitHub issues. | ||
Line 56: | Line 84: | ||
In AHK, MCL provides all functionality through the '' | In AHK, MCL provides all functionality through the '' | ||
- | Any method which is described as " | + | Any method which is described as " |
Now, for the API: | Now, for the API: | ||
Line 67: | Line 95: | ||
For any method which takes an '' | For any method which takes an '' | ||
- | * '' | + | * '' |
* '' | * '' | ||
* '' | * '' | ||
Line 157: | Line 185: | ||
</ | </ | ||
</ | </ | ||
+ | |||
+ | ==== C as Library ==== | ||
+ | |||
+ | <tabbox AutoHotkey v1> | ||
+ | <runner ahk> | ||
+ | #Include <MCL> | ||
+ | |||
+ | C = | ||
+ | ( % | ||
+ | |||
+ | #include < | ||
+ | |||
+ | MCL_EXPORT_INLINE(int, | ||
+ | return Left + Right; | ||
+ | } | ||
+ | |||
+ | MCL_EXPORT_INLINE(int, | ||
+ | return Left * Right; | ||
+ | } | ||
+ | |||
+ | int unused() { | ||
+ | return 20; | ||
+ | } | ||
+ | |||
+ | ) | ||
+ | |||
+ | Code := MCL.FromC(C) | ||
+ | |||
+ | Added := DllCall(Code.Add, | ||
+ | MsgBox, % Added | ||
+ | |||
+ | Multiplied := DllCall(Code.Multiply, | ||
+ | MsgBox, % Multiplied | ||
+ | </ | ||
+ | <tabbox AutoHotkey v2> | ||
+ | <runner ahk2> | ||
+ | #Include <MCL> | ||
+ | |||
+ | lib := MCL.FromC(" | ||
+ | ( | ||
+ | #include < | ||
+ | |||
+ | MCL_EXPORT(Add, | ||
+ | int Add(int left, int right) { | ||
+ | return left + right; | ||
+ | } | ||
+ | |||
+ | MCL_EXPORT(Multiply, | ||
+ | int Multiply(int left, int right) { | ||
+ | return left * right; | ||
+ | } | ||
+ | |||
+ | int unused() { | ||
+ | return 20; | ||
+ | } | ||
+ | )") | ||
+ | |||
+ | Added := lib.Add(300, | ||
+ | MsgBox Added | ||
+ | |||
+ | Multiplied := lib.Multiply(Added, | ||
+ | MsgBox Multiplied | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== C Return Struct to AHK ==== | ||
+ | |||
+ | <tabbox AutoHotkey v1> | ||
+ | <runner ahk> | ||
+ | #Include <MCL> | ||
+ | |||
+ | C = | ||
+ | ( % | ||
+ | |||
+ | #include < | ||
+ | |||
+ | typedef struct { | ||
+ | int X; | ||
+ | int Y; | ||
+ | } Point; | ||
+ | |||
+ | Point* __main(int a, int b) { | ||
+ | Point* P = malloc(sizeof(Point)); | ||
+ | |||
+ | P->X = a; | ||
+ | P->Y = b; | ||
+ | |||
+ | return P; | ||
+ | } | ||
+ | |||
+ | ) | ||
+ | |||
+ | Code := MCL.AHKFromC(C, | ||
+ | |||
+ | pCode := MCL.FromString(Code) | ||
+ | |||
+ | pPoint := DllCall(pCode, | ||
+ | |||
+ | MsgBox, % NumGet(pPoint+0, | ||
+ | </ | ||
+ | <tabbox AutoHotkey v2> | ||
+ | <runner ahk2> | ||
+ | #Include <MCL> | ||
+ | |||
+ | lib := MCL.FromC(" | ||
+ | ( | ||
+ | #include < | ||
+ | |||
+ | typedef struct { | ||
+ | int X; | ||
+ | int Y; | ||
+ | } Point; | ||
+ | |||
+ | MCL_EXPORT(Call, | ||
+ | Point* Call(int a, int b) { | ||
+ | Point* P = malloc(sizeof(Point)); | ||
+ | |||
+ | P->X = a; | ||
+ | P->Y = b; | ||
+ | |||
+ | return P; | ||
+ | } | ||
+ | )") | ||
+ | |||
+ | pPoint := lib(20, 30) | ||
+ | |||
+ | MsgBox NumGet(pPoint, | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== C Set Global from AHK ==== | ||
+ | |||
+ | <tabbox AutoHotkey v1> | ||
+ | <runner ahk> | ||
+ | #Include %A_ScriptDir%/ | ||
+ | #include MCL.ahk | ||
+ | |||
+ | C = | ||
+ | ( % | ||
+ | |||
+ | #include < | ||
+ | |||
+ | int SavedValue = 10; | ||
+ | MCL_EXPORT_GLOBAL(SavedValue); | ||
+ | |||
+ | int __main(int NewValue) { | ||
+ | int Result = SavedValue; | ||
+ | |||
+ | SavedValue = NewValue; | ||
+ | |||
+ | return Result; | ||
+ | } | ||
+ | |||
+ | ) | ||
+ | |||
+ | Code := MCL.FromC(C) | ||
+ | |||
+ | NumPut(20, Code.SavedValue, | ||
+ | MsgBox, % DllCall(Code.__main, | ||
+ | MsgBox, % DllCall(Code.__main, | ||
+ | MsgBox, % NumGet(Code.SavedValue, | ||
+ | </ | ||
+ | <tabbox AutoHotkey v2> | ||
+ | <runner ahk2> | ||
+ | #Include <MCL> | ||
+ | |||
+ | lib := MCL.FromC(" | ||
+ | ( | ||
+ | #include < | ||
+ | |||
+ | MCL_EXPORT_GLOBAL(savedValue, | ||
+ | int savedValue = 10; | ||
+ | |||
+ | MCL_EXPORT(Call, | ||
+ | int Call(int newValue) { | ||
+ | int result = savedValue; | ||
+ | savedValue = newValue; | ||
+ | return result; | ||
+ | } | ||
+ | )") | ||
+ | |||
+ | lib.savedValue := 20 | ||
+ | MsgBox lib(30) | ||
+ | MsgBox lib(40) | ||
+ | MsgBox lib.savedValue | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== C with Floats ==== | ||
+ | |||
+ | <tabbox AutoHotkey v1> | ||
+ | <runner ahk> | ||
+ | #Include <MCL> | ||
+ | |||
+ | C = | ||
+ | ( % | ||
+ | |||
+ | double __main(double In) { | ||
+ | return In * 2.5; | ||
+ | } | ||
+ | |||
+ | ) | ||
+ | |||
+ | pCode := MCL.FromC(C) | ||
+ | |||
+ | MsgBox, % DllCall(pCode, | ||
+ | </ | ||
+ | <tabbox AutoHotkey v2> | ||
+ | <runner ahk2> | ||
+ | #Include <MCL> | ||
+ | |||
+ | lib := MCL.FromC(" | ||
+ | ( | ||
+ | #include < | ||
+ | MCL_EXPORT(Call, | ||
+ | double Call(double in) { | ||
+ | return in * 2.5; | ||
+ | } | ||
+ | )") | ||
+ | |||
+ | MsgBox lib(11.7) | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== C Write to File ==== | ||
+ | |||
+ | <tabbox AutoHotkey v1> | ||
+ | <runner ahk> | ||
+ | #Include <MCL> | ||
+ | |||
+ | C = | ||
+ | ( % | ||
+ | |||
+ | #include < | ||
+ | |||
+ | void __main(int Value) { | ||
+ | FILE* f = fopen(" | ||
+ | |||
+ | fputs(" | ||
+ | fprintf(f, "The number is: %i\n", Value); | ||
+ | |||
+ | fclose(f); | ||
+ | } | ||
+ | |||
+ | ) | ||
+ | |||
+ | pCode := MCL.FromC(C) | ||
+ | |||
+ | DllCall(pCode, | ||
+ | |||
+ | MsgBox % FileOpen(" | ||
+ | </ | ||
+ | <tabbox AutoHotkey v2> | ||
+ | <runner ahk2> | ||
+ | #Include <MCL> | ||
+ | |||
+ | lib := MCL.FromC(" | ||
+ | ( | ||
+ | #include < | ||
+ | #include < | ||
+ | MCL_EXPORT(Call, | ||
+ | void Call(int value) { | ||
+ | FILE* f = fopen(" | ||
+ | |||
+ | fputs(" | ||
+ | fprintf(f, "The number is: %i\n", value); | ||
+ | |||
+ | fclose(f); | ||
+ | } | ||
+ | |||
+ | )") | ||
+ | |||
+ | lib(2931) | ||
+ | MsgBox FileRead(" | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== Import DLL with Headers (Lua) ==== | ||
+ | |||
+ | <runner ahk2> | ||
+ | #Requires AutoHotkey v2 | ||
+ | #DllLoad Z: | ||
+ | #Include <MCL> | ||
+ | FileCopy " | ||
+ | |||
+ | lib := MCL.FromC(" | ||
+ | ( | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | #include " | ||
+ | #include " | ||
+ | |||
+ | #define MCL_IMPORT_SOURCE lua54 | ||
+ | |||
+ | MCL_IMPORT_DECLARED_FROM(luaL_newstate); | ||
+ | MCL_IMPORT_DECLARED_FROM(luaL_openlibs); | ||
+ | MCL_IMPORT_DECLARED_FROM(luaL_loadstring); | ||
+ | MCL_IMPORT_DECLARED_FROM(lua_pcallk); | ||
+ | MCL_IMPORT_DECLARED_FROM(lua_close); | ||
+ | |||
+ | lua_State *L; | ||
+ | |||
+ | MCL_EXPORT(init, | ||
+ | void init() { | ||
+ | L = luaL_newstate(); | ||
+ | luaL_openlibs(L); | ||
+ | } | ||
+ | |||
+ | MCL_EXPORT(dostring, | ||
+ | int dostring(char* str) { | ||
+ | return luaL_loadstring(L, | ||
+ | } | ||
+ | |||
+ | MCL_EXPORT(close, | ||
+ | void close() { | ||
+ | lua_close(L); | ||
+ | } | ||
+ | )") | ||
+ | |||
+ | lib.init() | ||
+ | lib.dostring(' | ||
+ | lib.close() | ||
+ | </ |