Skip to content

Instantly share code, notes, and snippets.

@gvanem
Created December 30, 2025 13:01
Show Gist options
  • Select an option

  • Save gvanem/73b34157e2ce74cd2a1fc41f107bbd57 to your computer and use it in GitHub Desktop.

Select an option

Save gvanem/73b34157e2ce74cd2a1fc41f107bbd57 to your computer and use it in GitHub Desktop.
GNU-makefile for MG-LUA
#
# MG-Lua for MSVC / clang-cl
#
THIS_FILE := Makefile.Windows
TODAY := $(shell date +%d-%B-%Y)
PYTHON := py.exe -3
MAKEFLAGS += --warn-undefined-variables
USE_ASTYLE ?= 1
USE_LUAJIT ?= 1
USE_MG_OFFICIAL ?= 1
USE_MP_COMPILE ?= 1
USE_WSOCK_TRACE ?= 1
#
# Change to suite:
#
LUA55_ROOT ?= f:/MinGW32/src/LUA/Lua-5.5
LUAJIT_ROOT ?= f:/MinGW32/src/LUA/LuaJIT
MONGOOSE_ROOT ?= f:/MinGW32/src/inet/Web/Mongoose
define Usage
Usage: "make -f $(THIS_FILE) [CC=cl | clang-cl] [all | clean | vclean | install]")
Specify CC=cl - build with MSVC
Specify CC=clang-cl - build with clang-cl
endef
ifneq ($(CC),cl)
ifneq ($(CC),clang-cl)
$(error $(Usage))
endif
endif
ifeq ($(USE_MG_OFFICIAL),1)
MG_DIR = $(MONGOOSE_ROOT)
else
MG_DIR = ./libmongoose/src
endif
#
# From 'src/CMakeLists.txt':
# set(VERSION_MAJ 7)
# set(VERSION_MIN 2)
#
VER_MAJOR = 7
VER_MINOR = 2
VER_MICRO = 0
VERSION = $(VER_MAJOR).$(VER_MINOR).$(VER_MICRO)
#
# Undefine any '%CL%' env-var
#
export CL=
OBJ_DIR = objects
c_to_obj = $(addprefix $(OBJ_DIR)/, $(notdir $(1:.c=.obj)))
#
# What to build:
#
MG_LUA_DLL = bin/mg_lua-$(CPU).dll
MG_LUA_IMP_LIB = lib/mg_lua_imp-$(CPU).lib
MQTT_SERVER_DLL = bin/mqtt-server-$(CPU).dll
MQTT_SERVER_IMP_LIB = lib/mqtt-server_imp-$(CPU).lib
CFLAGS = -nologo -MD -O2 -W4 -Zi \
-I. \
-I./src \
-I$(MG_DIR) \
-Fd./$(OBJ_DIR)/vc14x.pdb \
-FI./$(OBJ_DIR)/mg-lua-hacks.h
LDFLAGS = -nologo -debug -verbose -incremental:no \
-machine:$(CPU) -nodefaultlib:uuid.lib \
-subsystem:console
RCFLAGS = -nologo
ifeq ($(CC),clang-cl)
CFLAGS += -fms-compatibility \
-ferror-limit=5
RCFLAGS += -D__clang__
else
RCFLAGS += -D_MSC_VER
endif
ifeq ($(USE_LUAJIT),1)
CFLAGS += -I$(LUAJIT_ROOT)/src -DUSE_LUAJIT
LUA_EXE = $(LUAJIT_ROOT)/bin/luajit.exe
LUA_LIB = $(LUAJIT_ROOT)/lib/luajit_static-$(CPU).lib
LUA_LIB = $(LUAJIT_ROOT)/lib/luajit-$(CPU).lib
else
CFLAGS += -I$(LUA55_ROOT) -DLUA_COMPAT_APIINTCASTS
LUA_EXE = $(LUA55_ROOT)/bin/lua.exe
LUA_LIB = $(LUA55_ROOT)/lib/lua55-$(CPU).lib
endif
ifeq ($(USE_WSOCK_TRACE),1)
WS2_32_LIB = wsock_trace-$(CPU).lib
LDFLAGS += -nodefaultlib:ws2_32.lib
else
WS2_32_LIB = ws2_32.lib
endif
vpath %.c src
LIB_SRC = $(addprefix src/, \
mg_addr.c \
mg_connection.c \
mg_dns.c \
mg_fd.c \
mg_fs.c \
mg_fs_file.c \
mg_http.c \
mg_http_header.c \
mg_http_message.c \
mg_http_part.c \
mg_http_serve_opts.c \
mg_iobuf.c \
mg_json.c \
mg_logging.c \
mg_lua.c \
mg_lua_cb.c \
mg_mgr.c \
mg_mqtt.c \
mg_mqtt_message.c \
mg_mqtt_opts.c \
mg_queue.c \
mg_rpc.c \
mg_rpc_req.c \
mg_sntp.c \
mg_str.c \
mg_string.c \
mg_time.c \
mg_timer.c \
mg_tls.c \
mg_tls_opts.c \
mg_trace.c \
mg_url.c \
mg_utility.c \
mg_ws.c \
mg_ws_message.c)
vpath %.c $(MG_DIR)
LIB_SRC += $(MG_DIR)/mongoose.c
LIB_OBJ = $(call c_to_obj, $(LIB_SRC))
#
# For '$(MQTT_SERVER_DLL)'
#
vpath %.c src/examples/mqtt/server
GENERATED = $(OBJ_DIR)/mg-lua-hacks.h
TARGETS = $(MG_LUA_IMP_LIB) \
$(MG_LUA_DLL) \
$(MQTT_SERVER_DLL) \
$(MQTT_SERVER_IMP_LIB) \
bin/mqtt_server-$(CPU).dll
all: check_lua_exe $(GENERATED) $(TARGETS)
check_lua_exe:
ifneq ($(shell $(LUA_EXE) -v 1>/dev/null 2>/dev/null; echo $$?), 0)
$(error "$(LUA_EXE) executable not found")
endif
bin lib \
$(OBJ_DIR):
mkdir --parents $@
$(OBJ_DIR)/mg-lua-hacks.h: $(THIS_FILE) | $(OBJ_DIR)
$(call generate_c, $@, $(MG_LUA_HACKS_H))
bin/%.exe: $(OBJ_DIR)/%.obj $(MG_LUA_IMP_LIB) $(LUA_LIB) | bin
$(call link_EXE, $@, $^ $(WS2_32_LIB))
#
# Exports from '$(MG_LUA_DLL)':
#
MG_LUA_EXPORTS = -export:luaopen_mg_lua \
-export:mg_open_mg_ws \
-export:mg_open_mg_mqtt \
-export:mg_str_s
#
# Exports from '$(MQTT_SERVER_DLL)':
#
MQTT_SERVER_EXPORTS = -export:luaopen_mqtt_server
$(MG_LUA_IMP_LIB): $(MG_LUA_DLL)
$(MQTT_SERVER_IMP_LIB): $(MQTT_SERVER_DLL)
.DELETE_ON_ERROR: $(MG_LUA_DLL) $(MG_LUA_IMP_LIB)
$(MG_LUA_DLL): $(LIB_OBJ) $(LUA_LIB) $(OBJ_DIR)/mg_lua.res | bin lib
$(call link_DLL, $@, $(MG_LUA_EXPORTS) $^ $(WS2_32_LIB), $(MG_LUA_IMP_LIB))
.DELETE_ON_ERROR: $(MQTT_SERVER_DLL) $(MQTT_SERVER_IMP_LIB)
$(MQTT_SERVER_DLL): $(OBJ_DIR)/mqtt-server.obj $(OBJ_DIR)/mqtt-server.res $(MG_LUA_IMP_LIB) $(LUA_LIB) | bin lib
$(call link_DLL, $@, $(MQTT_SERVER_EXPORTS) $^, $(MQTT_SERVER_IMP_LIB))
bin/mqtt_server-$(CPU).dll: $(MQTT_SERVER_DLL)
cp $(MQTT_SERVER_DLL) $@
@echo
ifeq ($(CC)-$(USE_MP_COMPILE),cl-1)
$(LIB_OBJ): $(LIB_SRC) | $(CC).args $(OBJ_DIR)
$(call C_compile_MP, $(OBJ_DIR), $(LIB_SRC), LIB_SRC)
endif
$(OBJ_DIR)/%.obj: %.c | $(CC).args $(OBJ_DIR)
$(call C_compile, $@, $<)
$(OBJ_DIR)/%.res: $(OBJ_DIR)/%.rc
$(call RC_compile, $@, $<)
$(OBJ_DIR)/mg_lua.rc: $(THIS_FILE) | $(OBJ_DIR)
$(call create_rc_file, $@, "$(notdir $(MG_LUA_DLL))", "Mongoose-Lua shared library")
$(OBJ_DIR)/mqtt-server.rc: $(THIS_FILE) | $(OBJ_DIR)
$(call create_rc_file, $@, "$(notdir $(MQTT_SERVER_DLL))", "MQTT server")
$(CC).args: $(THIS_FILE)
$(call green_msg, All CFLAGS are in $(BRIGHT_WHITE)$@)
$(call create_resp_file, $@, $(CFLAGS))
install: # todo
clean:
rm -f cl.args clang-cl.args link.args link.tmp
rm -rf $(OBJ_DIR)
vclean realclean: clean
rm -fr bin lib
%.i: %.c $(OBJ_DIR)/cpp-filter.py $(CC).args $(GENERATED) FORCE
$(call C_preprocess, $@, $<)
FORCE:
$(OBJ_DIR)/cpp-filter.py: $(THIS_FILE) | $(OBJ_DIR)
$(call generate, $@, #)
$(file >> $@,if 1:)
$(file >> $@,$(CPP_FILTER_PY))
run_http_client: src/examples/http-client/http-client.lua $(MG_LUA_DLL)
$(call run_lua, $<, 0)
run_huge_resp: src/examples/huge-response/huge-resp.lua $(MG_LUA_DLL)
$(call run_lua, $<, 0)
run_mqtt_dashboard: src/examples/mqtt/dashboard/main.lua $(MG_LUA_DLL)
$(call run_lua, $<, 0)
run_mqtt_server: src/examples/mqtt/server/mqtt-server.lua $(MG_LUA_DLL) $(MQTT_SERVER_DLL) bin/mqtt_server-$(CPU).dll
$(call run_lua, $<, 0)
run_json_test: src/examples/json/json-test.lua $(MG_LUA_DLL)
$(call run_lua, $<, 0)
#
# GNU-make macros:
#
# This assumes you have an MSys/Cygwin 'echo.exe' with colour support.
#
BRIGHT_GREEN = \e[1;32m
BRIGHT_WHITE = \e[1;37m
green_msg = @echo -e "$(BRIGHT_GREEN)$(strip $(1))\e[0m"
#
# A "require('mg_lua')" will match "?" here:
# "?-$(CPU).dll"
# ^
# |__ "mg_lua"
#
define run_lua
$(call green_msg, Running $(BRIGHT_WHITE)$(strip $(LUA_EXE) $(1)))
$(strip export LUA_CPATH=bin/?-$(CPU).dll ; \
export LUA_PATH=src/?.lua ; \
export LUA_TRACE=0 ; \
export MG_LUA_TRACE=0 ; \
export WSOCK_TRACE_LEVEL=$(strip $(2)) ; \
$(LUA_EXE) $(1) )
@echo
endef
define C_compile
$(CC) -c @$(CC).args -Fo./$(strip $(1) $(2))
@echo
endef
define C_compile_MP
$(call green_msg, Compiling $(words $(2)) .c-files for $(BRIGHT_WHITE)$(strip $(3)))
$(call C_compile, $(1)\\, -MP $(2))
endef
define RC_compile
rc $(RCFLAGS) -Fo./$(strip $(1) $(2))
@echo
endef
define create_rc_file
$(call generate, $(1), //)
$(file >> $(1), #define RC_INTERNAL_NAME $(2))
$(file >> $(1), #define RC_DESCRIPTION $(3))
$(file >> $(1),$(RC_COMMON))
endef
ifeq ($(USE_ASTYLE),1)
PP_FILTER = | astyle
pp_comment = The preprocessed and astyled output of '$(strip $(1))'
else
PP_FILTER =
pp_comment = The raw preprocessed output of '$(strip $(1))'
endif
define C_preprocess
$(file > $(1),/* $(call pp_comment, $(2)):)
$(file >> $(1), * $(CC) -E)
$(foreach f, $(CFLAGS), $(file >> $(1), * $(f)))
$(file >> $(1), *---------------------------------------------------------)
$(file >> $(1), */)
$(strip $(CC) -E @$(CC).args $(2) | $(PYTHON) $(OBJ_DIR)/cpp-filter.py $(PP_FILTER) >> $(1))
endef
define create_resp_file
$(file > $(1))
$(foreach f, $(2), $(file >> $(1),$(strip $(f))) )
endef
define link_EXE
$(call green_msg, Linking $(BRIGHT_WHITE)$(strip $(1)))
$(call create_resp_file, link.args, $(LDFLAGS) $(2))
$(file > $(OBJ_DIR)/check-for-unused-libs.py,if 1:)
$(file >> $(OBJ_DIR)/check-for-unused-libs.py,$(CHECK_FOR_UNUSED_LIBS_PY))
link -out:$(strip $(1)) @link.args > link.tmp
@rm -f $(1:.exe=.exp)
@$(PYTHON) $(OBJ_DIR)/check-for-unused-libs.py link.tmp
endef
define link_DLL
$(call green_msg, Linking $(BRIGHT_WHITE)$(strip $(1)))
$(call create_resp_file, link.args, -dll $(LDFLAGS) -implib:$(strip $(3)) $(2))
$(file > $(OBJ_DIR)/check-for-unused-libs.py,if 1:)
$(file >> $(OBJ_DIR)/check-for-unused-libs.py,$(CHECK_FOR_UNUSED_LIBS_PY))
link -out:$(strip $(1)) @link.args > link.tmp
@rm -f $(3:.lib=.exp)
@$(PYTHON) $(OBJ_DIR)/check-for-unused-libs.py link.tmp
endef
define Warning
$(1)
$(1) DO NOT EDIT! This file was automatically generated
$(1) from $(realpath $(THIS_FILE)) at $(TODAY).
$(1) Edit that file instead.
$(1)
endef
define generate
$(call green_msg, Generating $(BRIGHT_WHITE)$(strip $(1)))
$(file > $(1),$(call Warning,$(strip $(2))))
endef
define generate_c
$(call generate,$(1),//)
$(file >> $(1),$(2))
endef
#
# Force included as '-FI./$(OBJ_DIR)/mg-lua-hacks.h'
# with LUA to LuaJIT hacks etc.
#
define MG_LUA_HACKS_H
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_NONSTDC_NO_WARNINGS
#define _CRT_OBSOLETE_NO_WARNINGS
#define MG_TLS MG_TLS_BUILTIN
#define MG_ENABLE_LINES 1
#define MG_ENABLE_MBEDTLS 1
#define MG_ENABLE_DIRLIST 1
#define MG_ENABLE_IPV6 1
#define MG_ENABLE_MD5 1
#define MG_ENABLE_PACKED_FS 0
#define MG_ENABLE_POLL 1
#define MG_ENABLE_SSI 1
#define MG_ENABLE_WINSOCK 1
#define MG_MAX_HTTP_HEADERS 7
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wunused-function"
#elif defined(_MSC_VER)
#pragma warning (disable: 4244 4267 4310)
#endif
#if defined(USE_LUAJIT)
#define LUA_BUILD_AS_DLL /* Use the LuaJIT .DLL */
#endif
#include <lua.h>
#include <lauxlib.h>
#include <mg_trace.h>
#ifndef luaL_reg
#define luaL_reg luaL_Reg
#endif
#ifndef luaL_checklong
#define luaL_checklong(L, narg) ((long)luaL_checkinteger (L, narg))
#endif
#ifndef luaL_checkint32
#define luaL_checkint32(L, narg) ((int)luaL_checkinteger (L, narg))
#endif
#ifndef luaL_optlong
#define luaL_optlong(L, n, d) ((long)luaL_optinteger (L, n, d))
#endif
#if !defined(USE_LUAJIT) && (LUA_VERSION_NUM > 502)
static __inline void luaL_openlib (lua_State *L, const char *libname, const luaL_Reg *reg, int nup)
{
if (libname)
{
const luaL_Reg *r_save;
int size = 0;
for (r_save = reg; r_save && r_save->name; r_save++)
size++;
//luaL_pushmodule (L, libname, size);
(void) size;
lua_insert (L, -(nup + 1)); /* Move module table below upvalues. */
}
if (reg)
luaL_setfuncs (L, reg, nup);
else lua_pop (L, nup); /* Remove upvalues. */
}
static __inline void luaL_register (lua_State *L, const char *libname, const luaL_Reg *reg)
{
luaL_openlib (L, libname, reg, 0);
}
#endif
endef
ifeq ($(USER),gv)
BUILT_BY = " by <[email protected]>"
else
BUILT_BY =
endif
#
# Common .rc contents for '$(MG_LUA_DLL)' + '$(MQTT_SERVER_DLL)'.
#
define RC_COMMON
#include <winver.h>
#define RC_VERSION $(VER_MAJOR),$(VER_MINOR),$(VER_MICRO),0
#if defined(__clang__)
#define RC_COMPILER "Clang"
#elif defined(_MSC_VER)
#define RC_COMPILER "MSVC"
#else
#error "Unsupported compiler"
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION RC_VERSION
PRODUCTVERSION RC_VERSION
FILEFLAGSMASK 0x3fL
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0
FILEFLAGS 0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "MG-Lua, https://github.com/TheRootED24/mg_lua.git"
VALUE "FileDescription", RC_DESCRIPTION " (" RC_COMPILER ", $(CPU))"
VALUE "FileVersion", "$(VERSION)"
VALUE "InternalName", RC_INTERNAL_NAME
VALUE "LegalCopyright", "Apache-2.0 license"
VALUE "Comments", "Built on $(TODAY)" $(BUILT_BY)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
endef
define CPP_FILTER_PY
import sys
empty_lines = 0
while True:
line = sys.stdin.readline()
if not line:
break
line = line.rstrip()
if line == "":
empty_lines += 1
continue
#
# MSVC or clang-cl 'line' directive
#
l = line.lstrip()
if l.startswith("#line") or l.startswith("# "):
line = line.replace (r"\\", "/")
print (line)
#
# Print a newline after a functions or structs
#
if l == "}" or l == "};":
print ("")
print ("Removed %d empty lines." % empty_lines, file=sys.stderr)
endef
define CHECK_FOR_UNUSED_LIBS_PY
import os, sys, colorama
map_file = sys.argv [1]
ignore_libs = [ "oldnames.lib" ]
class State:
IDLE = 0
UNUSED = 1
colorama.init()
class Colour:
RED = colorama.Fore.RED + colorama.Style.BRIGHT
WHITE = colorama.Fore.WHITE + colorama.Style.BRIGHT
RESET = colorama.Style.RESET_ALL
def cprint (color, s):
print ("%s%s%s" % (color, s, Colour.RESET))
def report (unused):
num = len(unused)
if num > 0:
cprint (Colour.RED, "%d unused librar%s in %s:" % (num, ["y", "ies"][num > 1], map_file))
for u in unused:
print (" " + u)
cprint (Colour.WHITE, "Done.\n")
def process_map (state):
unused_libs = []
f = open (map_file, "rt")
lines = f.readlines()
f.close()
for l in lines:
l = l.strip()
if l == "Unused libraries:":
state = State.UNUSED
continue
if state == State.UNUSED:
if l == "":
break
if os.path.basename (l).lower() not in ignore_libs:
unused_libs.append (l)
return unused_libs
report (process_map(State.IDLE))
endef
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment