Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| libraries:machine_code:mcl [2023-12-16 23:51] – created 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 22: | Line 50: | ||
| The header '' | The header '' | ||
| - | However, this header is not needed. By default, the '' | + | However, this header is not needed. By default, the '' |
| These macros are as follows: | These macros are as follows: | ||
| 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 88: | Line 116: | ||
| Generally, any language feature supported by standard C should work. If you find something that doesn' | Generally, any language feature supported by standard C should work. If you find something that doesn' | ||
| + | ===== Examples ===== | ||
| + | |||
| + | ==== CPlusPlus with New and Delete ==== | ||
| + | |||
| + | <tabbox AutoHotkey v1> | ||
| + | <runner ahk> | ||
| + | #Include <MCL> | ||
| + | |||
| + | CPP = | ||
| + | ( % | ||
| + | |||
| + | #include < | ||
| + | |||
| + | class Point { | ||
| + | public: | ||
| + | Point(int NX, int NY) { | ||
| + | X = NX; | ||
| + | Y = NY; | ||
| + | } | ||
| + | |||
| + | private: | ||
| + | int X; | ||
| + | int Y; | ||
| + | }; | ||
| + | |||
| + | Point* __main(int X, int Y) { | ||
| + | return new Point(X, Y); | ||
| + | } | ||
| + | |||
| + | ) | ||
| + | |||
| + | pCode := MCL.FromCPP(CPP) | ||
| + | |||
| + | pPoint := DllCall(pCode, | ||
| + | |||
| + | MsgBox, % NumGet(pPoint+0, | ||
| + | </ | ||
| + | <tabbox AutoHotkey v2> | ||
| + | <runner ahk2> | ||
| + | #Requires AutoHotkey v2.0 | ||
| + | #include <MCL> | ||
| + | |||
| + | lib := MCL.FromCPP(" | ||
| + | ( | ||
| + | #include < | ||
| + | |||
| + | class Point { | ||
| + | public: | ||
| + | Point(int NX, int NY) { | ||
| + | X = NX; | ||
| + | Y = NY; | ||
| + | } | ||
| + | |||
| + | private: | ||
| + | int X; | ||
| + | int Y; | ||
| + | }; | ||
| + | |||
| + | MCL_EXPORT(Call, | ||
| + | Point* Call(int X, int Y) { | ||
| + | return new Point(X, Y); | ||
| + | } | ||
| + | )") | ||
| + | |||
| + | pPoint := lib(20, 30) | ||
| + | |||
| + | MsgBox NumGet(pPoint, | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ==== 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() | ||
| + | </ | ||