├── CHANGELOG.md ├── LICENSE ├── README.md ├── rtc.png └── src ├── gui.lua ├── img ├── exec.ico ├── open.ico └── rtc.ico └── rtc.lua /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # rtc Changelog 2 | 3 | ## rtc v1.6.0 (Nov 26 2023) 4 | 5 | ### General 6 | - Updated rtc with LuaRT toolchain to v1.6.0 7 | 8 | ### rtc 9 | - Fixed: `rtc` compiled executables with embedded modules can have now multiple running instances 10 | 11 | 12 | ## rtc v1.5.2 (Sept 17 2023) 13 | 14 | ### General 15 | - Updated rtc with LuaRT toolchain to v1.5.2 16 | - Updated Lua VM to 5.4.6 17 | - Release package now compiled using Visual C++ 18 | 19 | ### rtc 20 | - New: -l option to embed binary modules in the executable. Modules should be put in the `modules\` subfolder where `rtc.exe` is. 21 | - Updated: the main Lua file is now precompiled to bytecode 22 | 23 | ### wrtc GUI frontend 24 | - Updated : `wrtc` has a new field to embed modules (just type the name of the modules without the .DLL extension, separated by spaces) 25 | 26 | 27 | ## rtc v1.3.1 (Feb 04 2023) 28 | 29 | ### General 30 | - Updated rtc with LuaRT toolchain to v1.3.1 31 | - Updated to LuaRT UTF8 functions 32 | - Updated `rtc.lua` for new LuaRT `compression` module 33 | 34 | ### wrtc GUI frontend 35 | - Fixed the compilation of only console executable (Fixes #3) 36 | - Removed the message box after compilation succeeded 37 | - Fixed widget disposition with new Segoe UI default font 38 | - Display a warning when generated executable will overwrite a preexisting file 39 | - Explorer window don't show up anymore upon compilation 40 | - Fixed empty icon when cancelling icon selection -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Samir Tine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![rtc][title] 4 | 5 | [![Made with LuaRT](https://badgen.net/badge/Made%20with/LuaRT/yellow)](https://www.luart.org/) 6 | ![Windows Vista+](https://badgen.net/badge/Windows/Vista%20and%20later/blue?icon=windows) 7 | [![MIT License](https://badgen.net/badge/License/MIT/green)](#) 8 | 9 | Build standalone Windows executables from your Lua scripts. 10 | 11 | [Features](#features) | 12 | [Installation](#installation) | 13 | [Usage](#usage) | 14 | [Documentation](https://www.luart.org/doc/toolchain/rtc.html) | 15 | [Links](#links) | 16 | [License](#license) 17 |
18 | 19 | ## Features 20 | 21 | - Standalone tool : no Makefile, no C compiler needed 22 | - Compile from command line or using a GUI frontend 23 | - Build Windows native executable (.exe) from your Lua 5.4.6 scripts 24 | - Windows desktop or console applications 25 | - Static executables (without `lua54.dll` dependency) 26 | - Dynamic executables (with `lua54.dll` dependency) 27 | - Embed any files with your executable, even Lua binary modules with seamless loading using `require()` 28 | - Access embedded files seamlessly from your Lua scripts 29 | - Deploy your applications easily without the need to install Lua 30 | 31 | ## Installation 32 | 33 | #### Using latest release package 34 | 35 | The easiest way to install is to download the latest binary release from the Github repository. 36 | Just add the directory where you have unpacked the release package to your Windows system PATH variable. 37 | 38 | If you use the release package, you don't need any other dependencies to compile Lua scripts. 39 | 40 | #### Build rtc 41 | 42 | To build **rtc**, you will need to install the LuaRT programming framework sources before to proceed. 43 | Go to the ```src\``` directory in the LuaRT folder and type "**make rtc**" in a command prompt. 44 | It should produce a "**rtc.exe**" and "**wrtc.exe**"executable. 45 | 46 | ## Usage 47 | 48 | #### rtc command line options 49 | 50 | ``` 51 | usage: rtc.exe [-s][-c][-w][-i icon][-o output] [-lmodname] [directory] main.lua 52 | -s create static executable (without LUA54.DLL dependency) 53 | -c create executable for console (default) 54 | -w create executable for Windows desktop 55 | -i icon set executable icon (expects an .ico file) 56 | -o output set executable name to 'output' 57 | -lmodname link the LuaRT binary module 'modname.dll' 58 | directory the content of the directory to be embedded in the executable 59 | main.lua the Lua script to be executed 60 | ``` 61 | 62 | The specified optional directory will then be embedded within the executable with all its content archived in the ZIP format, bundled with the generated executable. 63 | As an alternative, you can use **wrtc.exe**, the GUI frontend which is more usert friendly. 64 | 65 | > **Warning** 66 | > Compiled dynamic executable depends on the provided `lua54.dll` library. Do not use any other library or your application will throw an error or may crash. 67 | 68 | #### Accessing embedded files from your LuaRT application 69 | 70 | To access embedded files from your LuaRT application, just use the global "**embed**" module. It will return a Zip instance, already open for read access, that contains the directory content provided on the command line during compilation with rtc : 71 | 72 | ```lua 73 | -- extract all the embedded content 74 | embed:extractall("c:/installdir/") 75 | ``` 76 | 77 | If no embedded content exists, "**embed**" will be set to a **nil** value. You should check that the current script is compiled embed table before using it. 78 | See the [LuaRT Zip object documentation](https://www.luart.org/doc/compression/Zip.html) for more information. 79 | 80 | #### Requiring Lua modules from embedded files 81 | 82 | To require a LuaRT script file in the embedded files, use **require** with the name of the module. You can require Lua modules, and binary modules (DLL) without the need to extract first (please note that in-memory binary modules loading works only with dynamic executables and may not work for some modules). 83 | 84 | ```lua 85 | -- require for the english.lua module, that must have been previously embedded with rtc 86 | local english = require "english" 87 | print(english.hello) 88 | ``` 89 | 90 | ## Links 91 | 92 | - [rtc Documentation](https://www.luart.org/doc/toolchain/rtc.html) 93 | - [rtc Tutorial](https://www.luart.org/doc/tutorial/rtc.html) 94 | - [LuaRT Homepage](https://www.luart.org/) 95 | - [LuaRT Community](https://community.luart.org/) 96 | 97 | ## License 98 | 99 | LuaRT and rtc are copyright (c) 2023 Samir Tine. 100 | rtc is open source, released under the MIT License. 101 | See full copyright notice in the LICENSE file. 102 | 103 | [title]: rtc.png 104 | -------------------------------------------------------------------------------- /rtc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samyeyo/rtc/d2b908d8c10930f1714f4edb98b818fe734a3089/rtc.png -------------------------------------------------------------------------------- /src/gui.lua: -------------------------------------------------------------------------------- 1 | local File = embed == nil and sys.File or embed.File 2 | local icon 3 | 4 | local win = ui.Window("rtc - Lua script to executable compiler", "fixed", 400, 300, "fixed") 5 | win:loadicon(File("img/rtc.ico")) 6 | 7 | local function setLabelBtn(widget, text, x, y, icon, tooltip, nobtn, delta) 8 | widget.label = ui.Label(win, text, x, y) 9 | widget.x = nobtn and (widget.label.x + widget.label.width + delta) or 106 10 | widget.y = widget.label.y - 3 11 | if not nobtn then 12 | widget.chooseBtn = ui.Button(win, "", widget.x + widget.width + 1, widget.y-2, 24, 24) 13 | widget.chooseBtn:loadicon(icon) 14 | widget.chooseBtn.hastext = false 15 | end 16 | widget.tooltip = tooltip 17 | return widget 18 | end 19 | 20 | local script = setLabelBtn(ui.Entry(win, "", 10, 10, win.width-142), "Main Lua script : ", 10, 26, File("img/open.ico"), "The Lua script to be run when the generated executable starts") 21 | local embed = setLabelBtn(ui.Entry(win, "", 10, 10, win.width-142), "Embed directory: ", 10, 52, File("img/open.ico"), "The content of the directory will be embedded in the generated executable") 22 | local modules = setLabelBtn(ui.Entry(win, "", 10, 10, win.width-142), "Embed modules: ", 10, 78, nil, "modules to be embedded, by name, separated with a space", true, 0) 23 | local output = setLabelBtn(ui.Entry(win, "", 10, 10, win.width-142), "Executable : ", 10, 104, nil, "The generated executable name", true, 26) 24 | 25 | local group = ui.Groupbox(win, "Windows subsystem", 10, 142, 130, 90) 26 | local radioconsole= ui.Radiobutton(group, "Console", 10, 26) 27 | radioconsole.checked = true 28 | local radiodesktop = ui.Radiobutton(group, "Windows desktop", 10, 50) 29 | 30 | local group = ui.Groupbox(win, "Runtime library", 150, 142, 130, 90) 31 | local radiodynamic = ui.Radiobutton(group, "Dynamic", 26, 26) 32 | radiodynamic.checked = true 33 | local radiostatic = ui.Radiobutton(group, "Static", 26, 50) 34 | 35 | local lbl = ui.Label(win, "Executable icon", 300, 162) 36 | local iconBtn = ui.Button(win, "", math.floor(300+lbl.width/2-16), lbl.y + lbl.height+4, 32, 32) 37 | iconBtn.hastext = false 38 | 39 | local execBtn = ui.Button(win, "Generate executable", 142, 256) 40 | execBtn:loadicon(File("img/exec.ico")) 41 | 42 | function iconBtn:onClick() 43 | local f = ui.opendialog("Select an icon", false, "ICO files (*.ico)|*.ico") 44 | if f ~= nil then 45 | icon = f.fullpath 46 | iconBtn:loadicon(f) 47 | else 48 | icon = nil 49 | end 50 | end 51 | 52 | function update_icon() 53 | target = radioconsole.checked and "luart" or "wluart" 54 | if icon == nil then 55 | iconBtn:loadicon(File(target..".exe")) 56 | end 57 | end 58 | 59 | radioconsole.onClick = update_icon 60 | radiodesktop.onClick = update_icon 61 | 62 | if #arg >= 1 and arg[1]:sub(1,1) ~= '-' then 63 | script.text = sys.File(arg[1]).fullpath 64 | if arg[2] ~= nil and arg[2]:sub(1,1) ~= '-' then 65 | embed.text = arg[2] 66 | end 67 | end 68 | 69 | function script:onChange() 70 | radioconsole.checked = script.text:match("(%.%w+)$") ~= ".wlua" 71 | radiodesktop.checked = not radioconsole.checked 72 | update_icon() 73 | output.text = script.text:gsub("(%.%w+)$", ".exe") 74 | end 75 | 76 | function script.chooseBtn:onClick() 77 | local file = ui.opendialog("Open main Lua script...", false, "Lua script (*.lua, *.wlua)|*.lua;*.wlua|Lua desktop script (*.wlua)|*.wlua|All files (*.*)|*.*") 78 | if file ~= nil then 79 | script.text = file.fullpath 80 | end 81 | end 82 | 83 | function embed.chooseBtn:onClick() 84 | local dir = ui.dirdialog("Select a directory...") 85 | if dir ~= nil then 86 | embed.text = dir.fullpath 87 | end 88 | end 89 | 90 | function radiodynamic:onClick() 91 | modules.enabled = radiodynamic.checked; 92 | end 93 | 94 | 95 | function radiostatic:onClick() 96 | if self.checked and ui.confirm( "It is strongly discouraged to use the static runtime library if you are using Lua binary modules.\nThis can lead to bugs and crashes of your application.\n\nPlease confirm that you want to use the static runtime library.", "Using static LuaRT runtime") == "cancel" then 97 | self.checked = false 98 | radiodynamic.checked = true 99 | end 100 | modules.enabled = radiodynamic.checked; 101 | end 102 | 103 | function win:onClose() 104 | sys.exit() 105 | end 106 | 107 | function execBtn:onClick() 108 | if #embed.text > 0 and not sys.Directory(embed.text).exists then 109 | ui.error("Embedded directory does not exists") 110 | else 111 | local f = sys.File(output.text) 112 | if f.exists and ui.confirm(f.name.." already exist.\nDo you want to proceed and replace the existing file ?") ~= "yes" then 113 | return 114 | end 115 | win:hide() 116 | end 117 | end 118 | 119 | update_icon() 120 | win:center() 121 | win:show() 122 | 123 | while win.visible do 124 | ui.update() 125 | end 126 | 127 | local directory = #embed.text > 0 and sys.Directory(embed.text) or nil 128 | 129 | if radiodesktop.checked then 130 | target = "wluart" 131 | else 132 | target = "luart" 133 | end 134 | 135 | if radiostatic.checked then 136 | target = target.."-static" 137 | end 138 | 139 | local libs = {} 140 | for mod in modules.text:gmatch("(%w+)") do 141 | libs[#libs+1] = mod 142 | end 143 | 144 | return { 145 | sys.File(script.text), 146 | directory, 147 | target..".exe", 148 | output.text, 149 | icon, 150 | libs 151 | } 152 | -------------------------------------------------------------------------------- /src/img/exec.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samyeyo/rtc/d2b908d8c10930f1714f4edb98b818fe734a3089/src/img/exec.ico -------------------------------------------------------------------------------- /src/img/open.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samyeyo/rtc/d2b908d8c10930f1714f4edb98b818fe734a3089/src/img/open.ico -------------------------------------------------------------------------------- /src/img/rtc.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samyeyo/rtc/d2b908d8c10930f1714f4edb98b818fe734a3089/src/img/rtc.ico -------------------------------------------------------------------------------- /src/rtc.lua: -------------------------------------------------------------------------------- 1 | -- | RTc - Lua script to executable compiler 2 | -- | Luart.org, Copyright (c) Tine Samir 2023 3 | -- | See Copyright Notice in LICENSE.TXT 4 | -- |--------------------------------------------------- 5 | -- | RTc.lua | LuaRT executable compiler 6 | 7 | local zip = require "compression" 8 | 9 | local output -- output executable filename 10 | local icon -- executable icon 11 | local directory -- Directory to be embedded in the executable 12 | local file -- main Lua File to be executed when running the executable 13 | local target = "luart.exe" -- target interpreter for console or window subsystem 14 | local setoutput, set_icon, static, forceconsole = false, false, false, false 15 | local console, gui 16 | 17 | ui = false 18 | local libs = {} 19 | 20 | if arg[0]:find("wrtc%.exe") == nil then 21 | console = require "console" 22 | local idx = (package.loaded["embed"] == nil) and 1 or 0 23 | if #arg == idx then 24 | console.writecolor("lightblue", "rt") 25 | console.writecolor('yellow', "c ") 26 | print(_VERSION:match(" (.*)$")..[[ - Lua script to executable compiler. 27 | Copyright (c) 2023, Samir Tine. 28 | 29 | usage: rtc.exe [-s][-c][-w][-i icon][-o output] [-lmodname] [directory] main.lua 30 | 31 | -s create static executable (without LUA54.DLL dependency) 32 | -c create executable for console (default) 33 | -w create executable for Windows desktop 34 | -i icon set executable icon (expects an .ico file) 35 | -o output set executable name to 'output' 36 | -lmodname link the LuaRT binary module 'modname.dll' 37 | directory the content of the directory to be embedded in the executable 38 | main.lua the Lua script to be executed]]) 39 | sys.exit() 40 | end 41 | 42 | ------------------------------------| Parse commande line 43 | for i, option in ipairs(arg) do 44 | if setoutput then 45 | output = option 46 | setoutput = false 47 | elseif set_icon then 48 | icon = option 49 | set_icon = false 50 | elseif option == "-i" then 51 | set_icon = true 52 | elseif option == "-c" then 53 | forceconsole = true 54 | target = "luart.exe" 55 | elseif option == "-w" then 56 | target = "wluart.exe" 57 | elseif option == "-o" then 58 | setoutput = true 59 | elseif option == "-s" then 60 | static = true 61 | elseif option:find("-l") == 1 then 62 | libs[#libs+1] = option:match("%-l(%w+)") 63 | elseif option:usub(1,1) == "-" then 64 | print("invalid option "..option) 65 | sys.exit(-1) 66 | elseif directory == nil and not sys.File(option).exists then 67 | directory = sys.Directory(option) 68 | if not directory.exists then 69 | error("cannot find file "..option) 70 | end 71 | else 72 | file = sys.File(option) 73 | if not file.exists then 74 | error("cannot find file "..option) 75 | end 76 | end 77 | end 78 | else 79 | ui = require "ui" 80 | local result = require("gui") 81 | file, directory, target, output, icon, libs = table.unpack(result) 82 | end 83 | 84 | if #libs > 0 and static then 85 | error("could not link modules in static mode") 86 | end 87 | 88 | if file == nil then 89 | error("no input file") 90 | end 91 | 92 | if file.extension == ".wlua" and target == "luart.exe" and not forceconsole then 93 | target = "wluart.exe" 94 | end 95 | 96 | if static then 97 | if target == "luart.exe" then 98 | target = "luart-static.exe" 99 | else 100 | target = "wluart-static.exe" 101 | end 102 | end 103 | 104 | result, err = load(file:open():read()) 105 | if result == nil then 106 | error(err) 107 | end 108 | 109 | if embed == nil then 110 | target = sys.File(sys.File(arg[0]).path..target) 111 | else 112 | target = embed.File(target) 113 | end 114 | 115 | if not target.exists then 116 | error("Fatal error: compilation failed, check your LuaRT installation") 117 | end 118 | 119 | local fs = sys.tempfile("luartc_") 120 | local fname = sys.tempfile("luartc_main_") 121 | 122 | fname:open("write", "binary") 123 | fname:write(string.dump(result, true)) 124 | fname:close() 125 | 126 | local z = zip.Zip(fs.fullpath, "write") 127 | z:write(fname, "__mainLuaRTStartup__.lua") 128 | 129 | for lib in each(libs) do 130 | local libpath = sys.Directory(sys.File(arg[0]).path.."/../modules/").exists and sys.File(arg[0]).path.."/../modules/" or sys.File(arg[0]).path.."/modules/" 131 | local libfile = sys.File(libpath..lib.."/"..lib..".dll") 132 | if not libfile.exists then 133 | libfile = sys.File(libpath.."/"..lib..".dll") 134 | end 135 | if libfile.exists then 136 | z:write(libfile) 137 | else 138 | error("module '"..lib.."' not found") 139 | end 140 | end 141 | 142 | if directory ~= nil then 143 | z:write(directory) 144 | end 145 | z:close() 146 | 147 | output = sys.File(output or file.name:gusub("(%w+)$", "exe")) 148 | output:remove() 149 | target:copy(output.fullpath) 150 | target:remove() 151 | 152 | if icon ~= nil then 153 | seticon(output.fullpath, icon) 154 | end 155 | 156 | if link(fs.fullpath, output.fullpath) == false then 157 | error('Cannot write "'..output.fullpath..'" to disk') 158 | end 159 | 160 | if ui then 161 | print("Successfully compiled "..output.name.." ("..math.floor(output.size/1024).."Kb)") 162 | else 163 | print(output.name) 164 | end 165 | fs:close() 166 | fs:remove() 167 | fname:remove() --------------------------------------------------------------------------------