- C 80%
- Lua 15.1%
- PowerShell 2.5%
- Makefile 1.3%
- Shell 1.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .claude/skills/add-api-function | ||
| .forgejo/workflows | ||
| docs | ||
| include | ||
| src | ||
| tests | ||
| tools | ||
| .gitattributes | ||
| .gitignore | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
msimple
A cross-platform toolkit for building MSI installers that aims to be simpler than the current tools but just as expressive. As a bonus, it's far faster and leaner than other tools. Project elements are declared in a Lua script, which msimple runs to figure out what to put in the MSI.
The result is that the instructions you give are much closer to a description of what you want the installer to do. You aren't expected to understand how MSIs work in detail to create installers that are simple to moderately advanced in complexity.
Usage
Projects are declared in lua files, like project.lua. Here's an example:
local msimple = require("msimple")
local project = msimple.new_project("My Project", "1.3.6", "B. Corp")
project:set_platform(msimple.platform.x64)
project:set_upgrade_code("{<an-upgrade-code>}")
project:set_property(msimple.property.about_url, "https://example.com")
project:install_program("MainExe", "file.exe", project:dir().."file.exe", {
name = "My Project",
add_to_desktop = true,
add_to_start = true,
})
project:use_standard_ui()
project:build("installer.msi")
This script is invoked through the msimple CLI tool, which provides the
underlying C API and the convenience functions in msimple.lua:
./build/msimple project.lua # runs project.lua, which builds the .msi itself via project:build(...)
msimple will plainly log any error that occurs during the build, and will try to detect common programming mistakes that would result in weird MSI behaviour.
See docs/lua-api.md for the full Lua API reference (AI-generated, but mostly sane).
You can also run ./build/msimple dump to dump the contents of msimple.lua from
the CLI tool to the current directory, for code completion and type checking.
If you need more advanced functionality than the high-level functions, you can call the bound C API directly from your project script. See msimple.lua for examples on how this works. Unlike the convenience functions, it requires an understanding of how MSIs work. Because it's in a scripting language, there's nothing stopping you from writing your own API on top of msimple, or defining functions specific to your use-case.
Building
Requires a C11 compiler, make, and zlib. Lua 5.5 is embedded via
vendor/minilua.h, and the Lua bindings are embedded via tools/embed_lua.c.
make # builds libmsimple.a, cfbtool, msimple, and tests into ./build
make windows # cross-compiles from Linux to Windows
make test # builds and runs the test suite
The project is cross-platform, and should build as long as you have make and
POSIX utils. On Windows this requires MSYS2 or WSL (preferably MSYS2).
Architecture
msimple is (roughly speaking) composed of 4 layers:
| Language | Layer | Primary Source Files |
|---|---|---|
| C | CFB reader/writer | cfb.h/c |
| C | MSI database reader/writer | msidb.h/c |
| C | MSI schema reader/writer | msiauthor.h/c |
| Lua | Lua bindings | msimple_native.c / msimple.lua |
Each layer builds on/uses the last. The third layer is wrapped up in a convenient Lua library that can be used to produce an MSI by invoking the command-line tool.
Licensing Remarks
The vast majority of code here was generated by claude, so that's public domain. The parts that are human-authored (like this README) are licensed under MIT.
cfbtool
cfbtool is an independent tool to test reading/writing of the compound document file format the MSI database and embedded files use.
./build/cfbtool list <file.msi>
./build/cfbtool extract <file.msi> </Path/To/Stream> <outfile>
./build/cfbtool resave <file.msi> <outfile> [sector_size] # 512, 4096, or 0=auto