2026-11-04 15:03:18 +01:00 | | | """Build the single-file MQL5 Market versions and compile them on a testing install.
|
| | |
|
| | | usage: build_market.py
|
| | | market/Tick_Forge.mq5 Expert (the utility product), TF_Gui / TF_Engine / TF_Expr inlined
|
| | | market/Tick_Forge_Indicator.mq5 indicator build of the same window (alternate)
|
| | | Each is compiled; errors / warnings are printed. The Market compiles the uploaded source server-side, so it
|
| | | must be ONE file with no custom includes (standard library includes are fine).
|
| | | Set TF_DATA / TF_EDITOR for your own install.
|
2026-11-04 07:30:30 +01:00 | | | """
|
| | | import os, re, shutil, subprocess, sys
|
| | | from pathlib import Path
|
| | |
|
| | | HERE = Path(__file__).resolve().parent.parent
|
| | | D = Path(os.environ.get("TF_DATA", r"C:\Users\gebruiker\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075"))
|
| | | EDIT = os.environ.get("TF_EDITOR", r"C:\Program Files\MetaTrader 5\metaeditor64.exe")
|
| | |
|
2026-11-04 15:03:18 +01:00 | | | # (source in repo, output name in market/, MQL5 sub-folder it compiles in, file name there)
|
| | | BUILDS = (("Tick_Forge.mq5", "Tick_Forge.mq5", "Experts", "Tick_Forge_Market"),
|
| | | ("variants/Tick_Forge_Indicator.mq5", "Tick_Forge_Indicator.mq5", "Indicators", "Tick_Forge_Market"))
|
| | |
|
2026-11-04 07:30:30 +01:00 | | |
|
| | | def body(name):
|
2026-11-04 15:03:18 +01:00 | | | return (HERE / name).read_text(encoding="utf-8")
|
2026-11-04 07:30:30 +01:00 | | |
|
| | |
|
| | | def inline(text):
|
| | | def sub(m):
|
| | | inc = m.group(1)
|
| | | return "// ---- inlined from %s ----\n%s\n// ---- end %s ----" % (inc, inline(body(inc)), inc)
|
2026-11-04 15:03:18 +01:00 | | | return re.sub(r'^#include "([^"]+)"[ \t]*$', sub, text, flags=re.M)
|
2026-11-04 07:30:30 +01:00 | | |
|
| | |
|
| | | out = HERE / "market"
|
| | | out.mkdir(exist_ok=True)
|
2026-11-04 15:03:18 +01:00 | | | (HERE / "release").mkdir(exist_ok=True)
|
| | | status = 0
|
| | | for src_rel, out_name, kind, folder in BUILDS:
|
| | | src = inline(body(src_rel))
|
| | | first = src.find("#property strict")
|
| | | if first >= 0: # inlined headers may repeat it; keep the first
|
| | | src = src[:first + 17] + src[first + 17:].replace("#property strict\n", "")
|
| | | (out / out_name).write_text(src, encoding="utf-8", newline="\n")
|
| | | left = re.findall(r'^#include "[^"]+"', src, flags=re.M)
|
| | | if left:
|
| | | sys.exit("custom includes left in %s: %s" % (out_name, left))
|
| | | dst = D / "MQL5" / kind / folder
|
| | | dst.mkdir(parents=True, exist_ok=True)
|
| | | shutil.copy2(out / out_name, dst / out_name)
|
| | | ex = dst / out_name.replace(".mq5", ".ex5")
|
| | | if ex.exists():
|
| | | ex.unlink()
|
| | | log = dst / (out_name + ".log")
|
| | | subprocess.run([EDIT, "/compile:%s" % (dst / out_name), "/log:%s" % log], capture_output=True)
|
| | | txt = log.read_bytes().decode("utf-16", "ignore") if log.exists() else ""
|
| | | res = [l.strip() for l in txt.splitlines() if re.search(r"error|warning|Result", l, re.I)]
|
| | | print("%s (%d lines): %s | ex5 %s" % (out_name, len(src.splitlines()), res[-1] if res else "?", ex.exists()))
|
| | | if ex.exists():
|
| | | shutil.copy2(ex, HERE / "release" / ex.name)
|
| | | else:
|
| | | status = 1
|
| | | sys.exit(status)
|