mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Update to the new ninja-fied ab.
This commit is contained in:
		
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							| @@ -26,7 +26,8 @@ ifeq ($(BUILDTYPE),windows) | |||||||
| else | else | ||||||
| 	CC = gcc | 	CC = gcc | ||||||
| 	CXX = g++ -std=c++20 | 	CXX = g++ -std=c++20 | ||||||
| 	CFLAGS = -g -O3 \ | 	CFLAGS = -g -O3 | ||||||
|  | 	CXXFLAGS += \ | ||||||
| 		-Wno-deprecated-enum-float-conversion \ | 		-Wno-deprecated-enum-float-conversion \ | ||||||
| 		-Wno-deprecated-enum-enum-conversion | 		-Wno-deprecated-enum-enum-conversion | ||||||
| 	LDFLAGS = | 	LDFLAGS = | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								build.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								build.py
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ import config | |||||||
| import re | import re | ||||||
|  |  | ||||||
| # Hack for building on Fedora/WSL; executables get the .exe extension, | # Hack for building on Fedora/WSL; executables get the .exe extension, | ||||||
| # build the build system detects it as Linux. | # but the build system detects it as Linux. | ||||||
| import build.toolchain | import build.toolchain | ||||||
|  |  | ||||||
| toolchain.Toolchain.EXE = "$(EXT)" | toolchain.Toolchain.EXE = "$(EXT)" | ||||||
| @@ -93,7 +93,7 @@ else: | |||||||
|                     + c[1] |                     + c[1] | ||||||
|                     + "' '" |                     + "' '" | ||||||
|                     + c[2] |                     + c[2] | ||||||
|                     + "' $(dir $[outs[0]]) > /dev/null" |                     + "' $[dirname(filenameof(outs[0]))] > /dev/null" | ||||||
|                 ], |                 ], | ||||||
|                 label="CORPUSTEST", |                 label="CORPUSTEST", | ||||||
|             ) |             ) | ||||||
|   | |||||||
							
								
								
									
										69
									
								
								build/ab.mk
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								build/ab.mk
									
									
									
									
									
								
							| @@ -15,16 +15,17 @@ HOSTCC ?= gcc | |||||||
| HOSTCXX ?= g++ | HOSTCXX ?= g++ | ||||||
| HOSTAR ?= ar | HOSTAR ?= ar | ||||||
| HOSTCFLAGS ?= -g -Og | HOSTCFLAGS ?= -g -Og | ||||||
|  | HOSTCXXFLAGS ?= $(HOSTCFLAGS) | ||||||
| HOSTLDFLAGS ?= -g | HOSTLDFLAGS ?= -g | ||||||
|  |  | ||||||
| CC ?= $(HOSTCC) | CC ?= $(HOSTCC) | ||||||
| CXX ?= $(HOSTCXX) | CXX ?= $(HOSTCXX) | ||||||
| AR ?= $(HOSTAR) | AR ?= $(HOSTAR) | ||||||
| CFLAGS ?= $(HOSTCFLAGS) | CFLAGS ?= $(HOSTCFLAGS) | ||||||
|  | CXXFLAGS ?= $(CFLAGS) | ||||||
| LDFLAGS ?= $(HOSTLDFLAGS) | LDFLAGS ?= $(HOSTLDFLAGS) | ||||||
|  |  | ||||||
| export PKG_CONFIG | NINJA ?= ninja | ||||||
| export HOST_PKG_CONFIG |  | ||||||
|  |  | ||||||
| ifdef VERBOSE | ifdef VERBOSE | ||||||
| 	hide = | 	hide = | ||||||
| @@ -63,37 +64,33 @@ EXT ?= | |||||||
|  |  | ||||||
| CWD=$(shell pwd) | CWD=$(shell pwd) | ||||||
|  |  | ||||||
| ifeq ($(AB_ENABLE_PROGRESS_INFO),true) | define newline | ||||||
| 	ifeq ($(PROGRESSINFO),) |  | ||||||
| 	# The first make invocation here has to have its output discarded or else it |  | ||||||
| 	# produces spurious 'Leaving directory' messages... don't know why. |  | ||||||
| 	rulecount := $(strip $(shell $(MAKE) --no-print-directory -q $(OBJ)/build.mk PROGRESSINFO=1 > /dev/null \ |  | ||||||
| 		&& $(MAKE) --no-print-directory -n $(MAKECMDGOALS) PROGRESSINFO=XXXPROGRESSINFOXXX | grep XXXPROGRESSINFOXXX | wc -l)) |  | ||||||
| 	ruleindex := 1 |  | ||||||
| 	PROGRESSINFO = "[$(ruleindex)/$(rulecount)]$(eval ruleindex := $(shell expr $(ruleindex) + 1)) " |  | ||||||
| 	endif |  | ||||||
| else |  | ||||||
| 	PROGRESSINFO = "" |  | ||||||
| endif |  | ||||||
|  |  | ||||||
| PKG_CONFIG_HASHES = $(OBJ)/.pkg-config-hashes/target-$(word 1, $(shell $(PKG_CONFIG) --list-all | md5sum)) |  | ||||||
| HOST_PKG_CONFIG_HASHES = $(OBJ)/.pkg-config-hashes/host-$(word 1, $(shell $(HOST_PKG_CONFIG) --list-all | md5sum)) |  | ||||||
|  |  | ||||||
| $(OBJ)/build.mk : $(PKG_CONFIG_HASHES) $(HOST_PKG_CONFIG_HASHES) | endef | ||||||
| $(PKG_CONFIG_HASHES) $(HOST_PKG_CONFIG_HASHES) &: |  | ||||||
| 	$(hide) rm -rf $(OBJ)/.pkg-config-hashes |  | ||||||
| 	$(hide) mkdir -p $(OBJ)/.pkg-config-hashes |  | ||||||
| 	$(hide) touch $(PKG_CONFIG_HASHES) $(HOST_PKG_CONFIG_HASHES) |  | ||||||
|  |  | ||||||
| include $(OBJ)/build.mk | define check_for_command | ||||||
|  |   $(shell command -v $1 >/dev/null || (echo "Required command '$1' missing" >/dev/stderr && kill $$PPID)) | ||||||
|  | endef | ||||||
|  |  | ||||||
| ifeq ($(OSX),yes) | $(call check_for_command,ninja) | ||||||
| 	MAKEFLAGS += -r -j$(shell sysctl -n hw.logicalcpu) | $(call check_for_command,cmp) | ||||||
| else | $(call check_for_command,$(PYTHON)) | ||||||
| 	MAKEFLAGS += -r -j$(shell nproc) |  | ||||||
| endif |  | ||||||
|  |  | ||||||
| .DELETE_ON_ERROR: | pkg-config-hash = $(shell ($(PKG_CONFIG) --list-all && $(HOST_PKG_CONFIG) --list-all) | md5sum) | ||||||
|  | build-files = $(shell find . -name .obj -prune -o \( -name 'build.py' -a -type f \) -print) $(wildcard build/*.py) $(wildcard config.py) | ||||||
|  | build-file-timestamps = $(shell ls -l $(build-files) | md5sum) | ||||||
|  |  | ||||||
|  | # Wipe the build file (forcing a regeneration) if the make environment is different. | ||||||
|  | # (Conveniently, this includes the pkg-config hash calculated above.) | ||||||
|  |  | ||||||
|  | ignored-variables = MAKE_RESTARTS .VARIABLES MAKECMDGOALS MAKEFLAGS MFLAGS | ||||||
|  | $(shell mkdir -p $(OBJ)) | ||||||
|  | $(file >$(OBJ)/newvars.txt,$(foreach v,$(filter-out $(ignored-variables),$(.VARIABLES)),$(v)=$($(v))$(newline))) | ||||||
|  | $(shell touch $(OBJ)/vars.txt) | ||||||
|  | #$(shell diff -u $(OBJ)/vars.txt $(OBJ)/newvars.txt > /dev/stderr) | ||||||
|  | $(shell cmp -s $(OBJ)/newvars.txt $(OBJ)/vars.txt || (rm -f $(OBJ)/build.ninja && echo "Environment changed --- regenerating" > /dev/stderr)) | ||||||
|  | $(shell mv $(OBJ)/newvars.txt $(OBJ)/vars.txt) | ||||||
|  |  | ||||||
| .PHONY: update-ab | .PHONY: update-ab | ||||||
| update-ab: | update-ab: | ||||||
| @@ -108,9 +105,15 @@ clean:: | |||||||
| 	$(hide) rm -rf $(OBJ) | 	$(hide) rm -rf $(OBJ) | ||||||
|  |  | ||||||
| export PYTHONHASHSEED = 1 | export PYTHONHASHSEED = 1 | ||||||
| build-files = $(shell find . -name 'build.py') $(wildcard build/*.py) $(wildcard config.py) | $(OBJ)/build.ninja $(OBJ)/build.targets &: | ||||||
| $(OBJ)/build.mk: Makefile $(build-files) build/ab.mk |  | ||||||
| 	@echo "AB" | 	@echo "AB" | ||||||
| 	@mkdir -p $(OBJ) | 	$(hide) $(PYTHON) -X pycache_prefix=$(OBJ)/__pycache__ build/ab.py \ | ||||||
| 	$(hide) $(PYTHON) -X pycache_prefix=$(OBJ)/__pycache__ build/ab.py -o $@ build.py \ | 		-o $(OBJ) build.py \ | ||||||
| 		|| rm -f $@ | 		-v $(OBJ)/vars.txt \ | ||||||
|  | 		|| (rm -f $@ && false) | ||||||
|  |  | ||||||
|  | include $(OBJ)/build.targets | ||||||
|  | .PHONY: $(ninja-targets) | ||||||
|  | $(ninja-targets) &: $(OBJ)/build.ninja | ||||||
|  | 	@echo "NINJA" | ||||||
|  | 	+$(hide) $(NINJA) -f $(OBJ)/build.ninja $@ | ||||||
|   | |||||||
							
								
								
									
										244
									
								
								build/ab.py
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								build/ab.py
									
									
									
									
									
								
							| @@ -1,36 +1,32 @@ | |||||||
|  | from collections import namedtuple | ||||||
|  | from copy import copy | ||||||
|  | from importlib.machinery import SourceFileLoader, PathFinder, ModuleSpec | ||||||
| from os.path import * | from os.path import * | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from typing import Iterable | from typing import Iterable | ||||||
| import argparse | import argparse | ||||||
|  | import ast | ||||||
| import builtins | import builtins | ||||||
| from copy import copy |  | ||||||
| import functools | import functools | ||||||
|  | import hashlib | ||||||
| import importlib | import importlib | ||||||
| import importlib.util | import importlib.util | ||||||
| from importlib.machinery import ( |  | ||||||
|     SourceFileLoader, |  | ||||||
|     PathFinder, |  | ||||||
|     ModuleSpec, |  | ||||||
| ) |  | ||||||
| import inspect | import inspect | ||||||
|  | import os | ||||||
|  | import re | ||||||
| import string | import string | ||||||
| import sys | import sys | ||||||
| import hashlib | import types | ||||||
| import re |  | ||||||
| import ast |  | ||||||
| from collections import namedtuple |  | ||||||
|  |  | ||||||
| VERBOSE_MK_FILE = False | VERBOSE_NINJA_FILE = False | ||||||
|  |  | ||||||
| verbose = False |  | ||||||
| quiet = False | quiet = False | ||||||
| cwdStack = [""] | cwdStack = [""] | ||||||
| targets = {} | targets = {} | ||||||
| unmaterialisedTargets = {}  # dict, not set, to get consistent ordering | unmaterialisedTargets = {}  # dict, not set, to get consistent ordering | ||||||
| materialisingStack = [] | materialisingStack = [] | ||||||
| defaultGlobals = {} | defaultGlobals = {} | ||||||
| globalId = 1 | outputTargets = set() | ||||||
| wordCache = {} |  | ||||||
|  |  | ||||||
| RE_FORMAT_SPEC = re.compile( | RE_FORMAT_SPEC = re.compile( | ||||||
|     r"(?:(?P<fill>[\s\S])?(?P<align>[<>=^]))?" |     r"(?:(?P<fill>[\s\S])?(?P<align>[<>=^]))?" | ||||||
| @@ -52,6 +48,15 @@ sys.path += ["."] | |||||||
| old_import = builtins.__import__ | old_import = builtins.__import__ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Environment(types.SimpleNamespace): | ||||||
|  |     def setdefault(self, name, value): | ||||||
|  |         if not hasattr(self, name): | ||||||
|  |             setattr(self, name, value) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | G = Environment() | ||||||
|  |  | ||||||
|  |  | ||||||
| class PathFinderImpl(PathFinder): | class PathFinderImpl(PathFinder): | ||||||
|     def find_spec(self, fullname, path, target=None): |     def find_spec(self, fullname, path, target=None): | ||||||
|         # The second test here is needed for Python 3.9. |         # The second test here is needed for Python 3.9. | ||||||
| @@ -103,26 +108,71 @@ def error(message): | |||||||
|  |  | ||||||
|  |  | ||||||
| class BracketedFormatter(string.Formatter): | class BracketedFormatter(string.Formatter): | ||||||
|  |     def __init__(self, op, cl): | ||||||
|  |         self.op = op | ||||||
|  |         self.cl = cl | ||||||
|  |  | ||||||
|  |     def _undo_escaped_dollar(self, s): | ||||||
|  |         return s.replace(f"$${self.op}", f"${self.op}") | ||||||
|  |  | ||||||
|     def parse(self, format_string): |     def parse(self, format_string): | ||||||
|         while format_string: |         while format_string: | ||||||
|             left, *right = format_string.split("$[", 1) |             m = re.search(f"(?:[^$]|^)()\\$\\{self.op}()", format_string) | ||||||
|             if not right: |             if not m: | ||||||
|                 yield (left, None, None, None) |                 yield ( | ||||||
|  |                     self._undo_escaped_dollar(format_string), | ||||||
|  |                     None, | ||||||
|  |                     None, | ||||||
|  |                     None, | ||||||
|  |                 ) | ||||||
|                 break |                 break | ||||||
|             right = right[0] |             left = format_string[: m.start(1)] | ||||||
|  |             right = format_string[m.end(2) :] | ||||||
|  |  | ||||||
|             offset = len(right) + 1 |             offset = len(right) + 1 | ||||||
|             try: |             try: | ||||||
|                 ast.parse(right) |                 ast.parse(right) | ||||||
|             except SyntaxError as e: |             except SyntaxError as e: | ||||||
|                 if not str(e).startswith("unmatched ']'"): |                 if not str(e).startswith(f"unmatched '{self.cl}'"): | ||||||
|                     raise e |                     raise e | ||||||
|                 offset = e.offset |                 offset = e.offset | ||||||
|  |  | ||||||
|             expr = right[0 : offset - 1] |             expr = right[0 : offset - 1] | ||||||
|             format_string = right[offset:] |             format_string = right[offset:] | ||||||
|  |  | ||||||
|             yield (left if left else None, expr, None, None) |             yield ( | ||||||
|  |                 self._undo_escaped_dollar(left) if left else None, | ||||||
|  |                 expr, | ||||||
|  |                 None, | ||||||
|  |                 None, | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class GlobalFormatter(BracketedFormatter): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__("(", ")") | ||||||
|  |  | ||||||
|  |     def get_field(self, name, a1, a2): | ||||||
|  |         return ( | ||||||
|  |             getattr(G, name), | ||||||
|  |             False, | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     def format_field(self, value, format_spec): | ||||||
|  |         if not value: | ||||||
|  |             return "" | ||||||
|  |         return str(value) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | globalFormatter = GlobalFormatter() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def substituteGlobalVariables(value): | ||||||
|  |     while True: | ||||||
|  |         oldValue = value | ||||||
|  |         value = globalFormatter.format(value) | ||||||
|  |         if value == oldValue: | ||||||
|  |             return value | ||||||
|  |  | ||||||
|  |  | ||||||
| def Rule(func): | def Rule(func): | ||||||
| @@ -187,12 +237,10 @@ def _isiterable(xs): | |||||||
|  |  | ||||||
| class Target: | class Target: | ||||||
|     def __init__(self, cwd, name): |     def __init__(self, cwd, name): | ||||||
|         if verbose: |  | ||||||
|             print("rule('%s', cwd='%s'" % (name, cwd)) |  | ||||||
|         self.name = name |         self.name = name | ||||||
|         self.localname = self.name.rsplit("+")[-1] |         self.localname = self.name.rsplit("+")[-1] | ||||||
|         self.traits = set() |         self.traits = set() | ||||||
|         self.dir = join("$(OBJ)", name) |         self.dir = join(G.OBJ, name) | ||||||
|         self.ins = [] |         self.ins = [] | ||||||
|         self.outs = [] |         self.outs = [] | ||||||
|         self.deps = [] |         self.deps = [] | ||||||
| @@ -213,6 +261,9 @@ class Target: | |||||||
|  |  | ||||||
|     def templateexpand(selfi, s): |     def templateexpand(selfi, s): | ||||||
|         class Formatter(BracketedFormatter): |         class Formatter(BracketedFormatter): | ||||||
|  |             def __init__(self): | ||||||
|  |                 super().__init__("[", "]") | ||||||
|  |  | ||||||
|             def get_field(self, name, a1, a2): |             def get_field(self, name, a1, a2): | ||||||
|                 return ( |                 return ( | ||||||
|                     eval(name, selfi.callback.__globals__, selfi.args), |                     eval(name, selfi.callback.__globals__, selfi.args), | ||||||
| @@ -232,7 +283,8 @@ class Target: | |||||||
|                     [selfi.templateexpand(f) for f in filenamesof(value)] |                     [selfi.templateexpand(f) for f in filenamesof(value)] | ||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|         return Formatter().format(s) |         s = Formatter().format(s) | ||||||
|  |         return substituteGlobalVariables(s) | ||||||
|  |  | ||||||
|     def materialise(self, replacing=False): |     def materialise(self, replacing=False): | ||||||
|         if self not in unmaterialisedTargets: |         if self not in unmaterialisedTargets: | ||||||
| @@ -341,10 +393,10 @@ def targetof(value, cwd=None): | |||||||
|             elif value.startswith("./"): |             elif value.startswith("./"): | ||||||
|                 value = normpath(join(cwd, value)) |                 value = normpath(join(cwd, value)) | ||||||
|         # Explicit directories are always raw files. |         # Explicit directories are always raw files. | ||||||
|         elif value.endswith("/"): |         if value.endswith("/"): | ||||||
|             return _filetarget(value, cwd) |             return _filetarget(value, cwd) | ||||||
|         # Anything starting with a variable expansion is always a raw file. |         # Anything in .obj is a raw file. | ||||||
|         elif value.startswith("$"): |         elif value.startswith(outputdir) or value.startswith(G.OBJ): | ||||||
|             return _filetarget(value, cwd) |             return _filetarget(value, cwd) | ||||||
|  |  | ||||||
|         # If this is not a rule lookup... |         # If this is not a rule lookup... | ||||||
| @@ -467,78 +519,67 @@ def emit(*args, into=None): | |||||||
|     if into is not None: |     if into is not None: | ||||||
|         into += [s] |         into += [s] | ||||||
|     else: |     else: | ||||||
|         outputFp.write(s) |         ninjaFp.write(s) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def shell(*args): | ||||||
|  |     s = "".join(args) + "\n" | ||||||
|  |     shellFp.write(s) | ||||||
|  |  | ||||||
|  |  | ||||||
| def emit_rule(self, ins, outs, cmds=[], label=None): | def emit_rule(self, ins, outs, cmds=[], label=None): | ||||||
|     name = self.name |     name = self.name | ||||||
|     fins_list = filenamesof(ins) |     fins = [self.templateexpand(f) for f in set(filenamesof(ins))] | ||||||
|     fins = set(fins_list) |     fouts = [self.templateexpand(f) for f in filenamesof(outs)] | ||||||
|     fouts = filenamesof(outs) |  | ||||||
|     nonobjs = [f for f in fouts if not f.startswith("$(OBJ)")] |     global outputTargets | ||||||
|  |     outputTargets.update(fouts) | ||||||
|  |     outputTargets.add(name) | ||||||
|  |  | ||||||
|     emit("") |     emit("") | ||||||
|     if VERBOSE_MK_FILE: |     if VERBOSE_NINJA_FILE: | ||||||
|         for k, v in self.args.items(): |         for k, v in self.args.items(): | ||||||
|             emit(f"# {k} = {v}") |             emit(f"# {k} = {v}") | ||||||
|  |  | ||||||
|     lines = [] |  | ||||||
|     if nonobjs: |  | ||||||
|         emit("clean::", into=lines) |  | ||||||
|         emit("\t$(hide) rm -f", *nonobjs, into=lines) |  | ||||||
|  |  | ||||||
|     hashable = cmds + fins_list + fouts |  | ||||||
|     hash = hashlib.sha1(bytes("\n".join(hashable), "utf-8")).hexdigest() |  | ||||||
|     hashfile = join(self.dir, f"hash_{hash}") |  | ||||||
|  |  | ||||||
|     global globalId |  | ||||||
|     emit(".PHONY:", name, into=lines) |  | ||||||
|     if outs: |     if outs: | ||||||
|         outsn = globalId |         os.makedirs(self.dir, exist_ok=True) | ||||||
|         globalId = globalId + 1 |         rule = [] | ||||||
|         insn = globalId |  | ||||||
|         globalId = globalId + 1 |  | ||||||
|  |  | ||||||
|         emit(f"OUTS_{outsn}", "=", *fouts, into=lines) |  | ||||||
|         emit(f"INS_{insn}", "=", *fins, into=lines) |  | ||||||
|         emit(name, ":", f"$(OUTS_{outsn})", into=lines) |  | ||||||
|         emit(hashfile, ":", into=lines) |  | ||||||
|         emit(f"\t@mkdir -p {self.dir}", into=lines) |  | ||||||
|         emit(f"\t@touch {hashfile}", into=lines) |  | ||||||
|         emit( |  | ||||||
|             f"$(OUTS_{outsn})", |  | ||||||
|             "&:" if len(fouts) > 1 else ":", |  | ||||||
|             f"$(INS_{insn})", |  | ||||||
|             hashfile, |  | ||||||
|             into=lines, |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         if label: |  | ||||||
|             emit("\t$(hide)", "$(ECHO) $(PROGRESSINFO)" + label, into=lines) |  | ||||||
|  |  | ||||||
|         sandbox = join(self.dir, "sandbox") |         sandbox = join(self.dir, "sandbox") | ||||||
|         emit("\t$(hide)", f"rm -rf {sandbox}", into=lines) |         emit(f"rm -rf {sandbox}", into=rule) | ||||||
|         emit( |         emit( | ||||||
|             "\t$(hide)", |             f"{G.PYTHON} build/_sandbox.py --link -s", sandbox, *fins, into=rule | ||||||
|             "$(PYTHON) build/_sandbox.py --link -s", |  | ||||||
|             sandbox, |  | ||||||
|             f"$(INS_{insn})", |  | ||||||
|             into=lines, |  | ||||||
|         ) |         ) | ||||||
|         for c in cmds: |         for c in cmds: | ||||||
|             emit(f"\t$(hide) cd {sandbox} && (", c, ")", into=lines) |             emit(f"(cd {sandbox} &&", c, ")", into=rule) | ||||||
|         emit( |         emit( | ||||||
|             "\t$(hide)", |             f"{G.PYTHON} build/_sandbox.py --export -s", | ||||||
|             "$(PYTHON) build/_sandbox.py --export -s", |  | ||||||
|             sandbox, |             sandbox, | ||||||
|             f"$(OUTS_{outsn})", |             *fouts, | ||||||
|             into=lines, |             into=rule, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |         ruletext = "".join(rule) | ||||||
|  |         if len(ruletext) > 7000: | ||||||
|  |             rulehash = hashlib.sha1(ruletext.encode()).hexdigest() | ||||||
|  |  | ||||||
|  |             rulef = join(self.dir, f"rule-{rulehash}.sh") | ||||||
|  |             with open(rulef, "wt") as fp: | ||||||
|  |                 fp.write(ruletext) | ||||||
|  |  | ||||||
|  |             emit("build", *fouts, ":rule", *fins, rulef) | ||||||
|  |             emit(" command=sh", rulef) | ||||||
|  |         else: | ||||||
|  |             emit("build", *fouts, ":rule", *fins) | ||||||
|  |             emit(" command=", "&&".join([s.strip() for s in rule])) | ||||||
|  |         if label: | ||||||
|  |             emit(" description=", label) | ||||||
|  |         emit("build", name, ":phony", *fouts) | ||||||
|  |  | ||||||
|     else: |     else: | ||||||
|         assert len(cmds) == 0, "rules with no outputs cannot have commands" |         assert len(cmds) == 0, "rules with no outputs cannot have commands" | ||||||
|         emit(name, ":", *fins, into=lines) |         emit("build", name, ":phony", *fins) | ||||||
|  |  | ||||||
|     outputFp.write("".join(lines)) |  | ||||||
|     emit("") |     emit("") | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -585,47 +626,65 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []): | |||||||
|         dest = self.targetof(dest) |         dest = self.targetof(dest) | ||||||
|         outs += [dest] |         outs += [dest] | ||||||
|  |  | ||||||
|         destf = filenameof(dest) |         destf = self.templateexpand(filenameof(dest)) | ||||||
|  |         outputTargets.update([destf]) | ||||||
|  |  | ||||||
|         srcs = filenamesof([src]) |         srcs = filenamesof([src]) | ||||||
|         assert ( |         assert ( | ||||||
|             len(srcs) == 1 |             len(srcs) == 1 | ||||||
|         ), "a dependency of an exported file must have exactly one output file" |         ), "a dependency of an exported file must have exactly one output file" | ||||||
|  |         srcf = self.templateexpand(srcs[0]) | ||||||
|  |  | ||||||
|         subrule = simplerule( |         subrule = simplerule( | ||||||
|             name=f"{self.localname}/{destf}", |             name=f"{self.localname}/{destf}", | ||||||
|             cwd=self.cwd, |             cwd=self.cwd, | ||||||
|             ins=[srcs[0]], |             ins=[srcs[0]], | ||||||
|             outs=[destf], |             outs=[destf], | ||||||
|             commands=["$(CP) -H %s %s" % (srcs[0], destf)], |             commands=["$(CP) -H %s %s" % (srcf, destf)], | ||||||
|             label="", |             label="EXPORT", | ||||||
|         ) |         ) | ||||||
|         subrule.materialise() |         subrule.materialise() | ||||||
|  |  | ||||||
|     self.ins = [] |     self.ins = [] | ||||||
|     self.outs = deps + outs |     self.outs = deps + outs | ||||||
|  |     outputTargets.add(name) | ||||||
|  |  | ||||||
|     emit("") |     emit("") | ||||||
|     emit(".PHONY:", name) |     emit( | ||||||
|     emit(name, ":", *filenamesof(outs + deps)) |         "build", | ||||||
|  |         name, | ||||||
|  |         ":phony", | ||||||
|  |         *[self.templateexpand(f) for f in filenamesof(outs + deps)], | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def main(): | def main(): | ||||||
|     parser = argparse.ArgumentParser() |     parser = argparse.ArgumentParser() | ||||||
|     parser.add_argument("-v", "--verbose", action="store_true") |  | ||||||
|     parser.add_argument("-q", "--quiet", action="store_true") |     parser.add_argument("-q", "--quiet", action="store_true") | ||||||
|     parser.add_argument("-o", "--output") |     parser.add_argument("-v", "--varfile") | ||||||
|  |     parser.add_argument("-o", "--outputdir") | ||||||
|  |     parser.add_argument("-D", "--define", action="append", default=[]) | ||||||
|     parser.add_argument("files", nargs="+") |     parser.add_argument("files", nargs="+") | ||||||
|     args = parser.parse_args() |     args = parser.parse_args() | ||||||
|  |  | ||||||
|     global verbose |  | ||||||
|     verbose = args.verbose |  | ||||||
|  |  | ||||||
|     global quiet |     global quiet | ||||||
|     quiet = args.quiet |     quiet = args.quiet | ||||||
|  |  | ||||||
|     global outputFp |     vardefs = args.define | ||||||
|     outputFp = open(args.output, "wt") |     if args.varfile: | ||||||
|  |         with open(args.varfile, "rt") as fp: | ||||||
|  |             vardefs = vardefs + list(fp) | ||||||
|  |  | ||||||
|  |     for line in vardefs: | ||||||
|  |         if "=" in line: | ||||||
|  |             name, value = line.split("=", 1) | ||||||
|  |             G.setdefault(name.strip(), value.strip()) | ||||||
|  |  | ||||||
|  |     global ninjaFp, shellFp, outputdir | ||||||
|  |     outputdir = args.outputdir | ||||||
|  |     G.setdefault("OBJ", outputdir) | ||||||
|  |     ninjaFp = open(outputdir + "/build.ninja", "wt") | ||||||
|  |     ninjaFp.write(f"include build/ab.ninja\n") | ||||||
|  |  | ||||||
|     for k in ["Rule"]: |     for k in ["Rule"]: | ||||||
|         defaultGlobals[k] = globals()[k] |         defaultGlobals[k] = globals()[k] | ||||||
| @@ -640,7 +699,10 @@ def main(): | |||||||
|     while unmaterialisedTargets: |     while unmaterialisedTargets: | ||||||
|         t = next(iter(unmaterialisedTargets)) |         t = next(iter(unmaterialisedTargets)) | ||||||
|         t.materialise() |         t.materialise() | ||||||
|     emit("AB_LOADED = 1\n") |  | ||||||
|  |     with open(outputdir + "/build.targets", "wt") as fp: | ||||||
|  |         fp.write("ninja-targets =") | ||||||
|  |         fp.write(substituteGlobalVariables(" ".join(outputTargets))) | ||||||
|  |  | ||||||
|  |  | ||||||
| main() | main() | ||||||
|   | |||||||
							
								
								
									
										55
									
								
								build/c.py
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								build/c.py
									
									
									
									
									
								
							| @@ -7,23 +7,22 @@ from build.ab import ( | |||||||
|     flatten, |     flatten, | ||||||
|     simplerule, |     simplerule, | ||||||
|     emit, |     emit, | ||||||
|  |     G, | ||||||
| ) | ) | ||||||
| from build.utils import filenamesmatchingof, stripext, collectattrs | from build.utils import stripext, collectattrs | ||||||
| from build.toolchain import Toolchain, HostToolchain | from build.toolchain import Toolchain, HostToolchain | ||||||
| from os.path import * | from os.path import * | ||||||
|  |  | ||||||
| emit( | if G.OSX != "yes": | ||||||
|     """ |     G.STARTGROUP = "-Wl,--start-group" | ||||||
| ifeq ($(OSX),no) |     G.ENDGROUP = "-Wl,--end-group" | ||||||
| STARTGROUP ?= -Wl,--start-group | else: | ||||||
| ENDGROUP ?= -Wl,--end-group |     G.STARTGROUP = "" | ||||||
| endif |     G.ENDGROUP = "" | ||||||
| """ |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| Toolchain.CC = ["$(CC) -c -o $[outs[0]] $[ins[0]] $(CFLAGS) $[cflags]"] | Toolchain.CC = ["$(CC) -c -o $[outs[0]] $[ins[0]] $(CFLAGS) $[cflags]"] | ||||||
| Toolchain.CPP = ["$(CC) -E -P -o $[outs] $[cflags] -x c $[ins]"] | Toolchain.CPP = ["$(CC) -E -P -o $[outs] $[cflags] -x c $[ins]"] | ||||||
| Toolchain.CXX = ["$(CXX) -c -o $[outs[0]] $[ins[0]] $(CFLAGS) $[cflags]"] | Toolchain.CXX = ["$(CXX) -c -o $[outs[0]] $[ins[0]] $(CXXFLAGS) $[cflags]"] | ||||||
| Toolchain.AR = ["$(AR) cqs $[outs[0]] $[ins]"] | Toolchain.AR = ["$(AR) cqs $[outs[0]] $[ins]"] | ||||||
| Toolchain.ARXX = ["$(AR) cqs $[outs[0]] $[ins]"] | Toolchain.ARXX = ["$(AR) cqs $[outs[0]] $[ins]"] | ||||||
| Toolchain.CLINK = [ | Toolchain.CLINK = [ | ||||||
| @@ -70,13 +69,9 @@ def _toolchain_find_header_targets(deps, initial=[]): | |||||||
| Toolchain.find_c_header_targets = _toolchain_find_header_targets | Toolchain.find_c_header_targets = _toolchain_find_header_targets | ||||||
|  |  | ||||||
|  |  | ||||||
| HostToolchain.CC = [ | HostToolchain.CC = ["$(HOSTCC) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]"] | ||||||
|     "$(HOSTCC) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]" |  | ||||||
| ] |  | ||||||
| HostToolchain.CPP = ["$(HOSTCC) -E -P -o $[outs] $[cflags] -x c $[ins]"] | HostToolchain.CPP = ["$(HOSTCC) -E -P -o $[outs] $[cflags] -x c $[ins]"] | ||||||
| HostToolchain.CXX = [ | HostToolchain.CXX = ["$(HOSTCXX) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]"] | ||||||
|     "$(HOSTCXX) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]" |  | ||||||
| ] |  | ||||||
| HostToolchain.AR = ["$(HOSTAR) cqs $[outs[0]] $[ins]"] | HostToolchain.AR = ["$(HOSTAR) cqs $[outs[0]] $[ins]"] | ||||||
| HostToolchain.ARXX = ["$(HOSTAR) cqs $[outs[0]] $[ins]"] | HostToolchain.ARXX = ["$(HOSTAR) cqs $[outs[0]] $[ins]"] | ||||||
| HostToolchain.CLINK = [ | HostToolchain.CLINK = [ | ||||||
| @@ -102,9 +97,7 @@ def _indirect(deps, name): | |||||||
|     return r |     return r | ||||||
|  |  | ||||||
|  |  | ||||||
| def cfileimpl( | def cfileimpl(self, name, srcs, deps, suffix, commands, label, toolchain, cflags): | ||||||
|     self, name, srcs, deps, suffix, commands, label, toolchain, cflags |  | ||||||
| ): |  | ||||||
|     outleaf = "=" + stripext(basename(filenameof(srcs[0]))) + suffix |     outleaf = "=" + stripext(basename(filenameof(srcs[0]))) + suffix | ||||||
|  |  | ||||||
|     hdr_deps = toolchain.find_c_header_targets(deps) |     hdr_deps = toolchain.find_c_header_targets(deps) | ||||||
| @@ -114,9 +107,7 @@ def cfileimpl( | |||||||
|         if ("cheader_deps" not in d.args) and ("clibrary_deps" not in d.args) |         if ("cheader_deps" not in d.args) and ("clibrary_deps" not in d.args) | ||||||
|     ] |     ] | ||||||
|     hdr_files = collectattrs(targets=hdr_deps, name="cheader_files") |     hdr_files = collectattrs(targets=hdr_deps, name="cheader_files") | ||||||
|     cflags = collectattrs( |     cflags = collectattrs(targets=hdr_deps, name="caller_cflags", initial=cflags) | ||||||
|         targets=hdr_deps, name="caller_cflags", initial=cflags |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     t = simplerule( |     t = simplerule( | ||||||
|         replaces=self, |         replaces=self, | ||||||
| @@ -194,7 +185,7 @@ def findsources(self, srcs, deps, cflags, filerule, toolchain, cwd): | |||||||
|     for s in flatten(srcs): |     for s in flatten(srcs): | ||||||
|         objs += [ |         objs += [ | ||||||
|             filerule( |             filerule( | ||||||
|                 name=join(self.localname, _removeprefix(f, "$(OBJ)/")), |                 name=join(self.localname, _removeprefix(f, G.OBJ + "/")), | ||||||
|                 srcs=[f], |                 srcs=[f], | ||||||
|                 deps=deps, |                 deps=deps, | ||||||
|                 cflags=sorted(set(cflags)), |                 cflags=sorted(set(cflags)), | ||||||
| @@ -239,9 +230,7 @@ def libraryimpl( | |||||||
|         i = 0 |         i = 0 | ||||||
|         for dest, src in hdrs.items(): |         for dest, src in hdrs.items(): | ||||||
|             s = filenamesof([src]) |             s = filenamesof([src]) | ||||||
|             assert ( |             assert len(s) == 1, "the target of a header must return exactly one file" | ||||||
|                 len(s) == 1 |  | ||||||
|             ), "the target of a header must return exactly one file" |  | ||||||
|  |  | ||||||
|             cs += [f"$(CP) $[ins[{i}]] $[outs[{i}]]"] |             cs += [f"$(CP) $[ins[{i}]] $[outs[{i}]]"] | ||||||
|             outs += ["=" + dest] |             outs += ["=" + dest] | ||||||
| @@ -431,20 +420,16 @@ def programimpl( | |||||||
|     label, |     label, | ||||||
|     filerule, |     filerule, | ||||||
| ): | ): | ||||||
|     cfiles = findsources( |     cfiles = findsources(self, srcs, deps, cflags, filerule, toolchain, self.cwd) | ||||||
|         self, srcs, deps, cflags, filerule, toolchain, self.cwd |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     lib_deps = toolchain.find_c_library_targets(deps) |     lib_deps = toolchain.find_c_library_targets(deps) | ||||||
|     libs = collectattrs(targets=lib_deps, name="clibrary_files") |     libs = collectattrs(targets=lib_deps, name="clibrary_files") | ||||||
|     ldflags = collectattrs( |     ldflags = collectattrs(targets=lib_deps, name="caller_ldflags", initial=ldflags) | ||||||
|         targets=lib_deps, name="caller_ldflags", initial=ldflags |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     simplerule( |     simplerule( | ||||||
|         replaces=self, |         replaces=self, | ||||||
|         ins=cfiles + libs, |         ins=cfiles + libs, | ||||||
|         outs=[f"={self.localname}{toolchain.EXE}"], |         outs=[f"={self.localname}$(EXT)"], | ||||||
|         deps=deps, |         deps=deps, | ||||||
|         label=label, |         label=label, | ||||||
|         commands=commands, |         commands=commands, | ||||||
| @@ -558,9 +543,7 @@ def hostcxxprogram( | |||||||
|  |  | ||||||
| def _cppfileimpl(self, name, srcs, deps, cflags, toolchain): | def _cppfileimpl(self, name, srcs, deps, cflags, toolchain): | ||||||
|     hdr_deps = _indirect(deps, "cheader_deps") |     hdr_deps = _indirect(deps, "cheader_deps") | ||||||
|     cflags = collectattrs( |     cflags = collectattrs(targets=hdr_deps, name="caller_cflags", initial=cflags) | ||||||
|         targets=hdr_deps, name="caller_cflags", initial=cflags |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     simplerule( |     simplerule( | ||||||
|         replaces=self, |         replaces=self, | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								build/pkg.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								build/pkg.py
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| from build.ab import Rule, Target | from build.ab import Rule, Target, G | ||||||
| import os | import os | ||||||
| import subprocess | import subprocess | ||||||
|  |  | ||||||
| @@ -31,8 +31,8 @@ class _PkgConfig: | |||||||
|         return self.package_properties[p] |         return self.package_properties[p] | ||||||
|  |  | ||||||
|  |  | ||||||
| TargetPkgConfig = _PkgConfig(os.getenv("PKG_CONFIG")) | TargetPkgConfig = _PkgConfig(G.PKG_CONFIG) | ||||||
| HostPkgConfig = _PkgConfig(os.getenv("HOST_PKG_CONFIG")) | HostPkgConfig = _PkgConfig(G.HOST_PKG_CONFIG) | ||||||
|  |  | ||||||
|  |  | ||||||
| def _package(self, name, package, fallback, pkgconfig): | def _package(self, name, package, fallback, pkgconfig): | ||||||
| @@ -49,9 +49,7 @@ def _package(self, name, package, fallback, pkgconfig): | |||||||
|         self.traits.update({"clibrary", "cxxlibrary"}) |         self.traits.update({"clibrary", "cxxlibrary"}) | ||||||
|         return |         return | ||||||
|  |  | ||||||
|     assert ( |     assert fallback, f"Required package '{package}' not installed" | ||||||
|         fallback |  | ||||||
|     ), f"Required package '{package}' not installed when materialising target '$[name]'" |  | ||||||
|  |  | ||||||
|     if "cheader_deps" in fallback.args: |     if "cheader_deps" in fallback.args: | ||||||
|         self.args["cheader_deps"] = fallback.args["cheader_deps"] |         self.args["cheader_deps"] = fallback.args["cheader_deps"] | ||||||
|   | |||||||
| @@ -1,14 +1,10 @@ | |||||||
| from build.ab import Rule, Targets, emit, simplerule, filenamesof | from build.ab import Rule, Targets, emit, simplerule, filenamesof, G | ||||||
| from build.utils import filenamesmatchingof, collectattrs | from build.utils import filenamesmatchingof, collectattrs | ||||||
| from os.path import join, abspath, dirname, relpath | from os.path import join, abspath, dirname, relpath | ||||||
| from build.pkg import has_package | from build.pkg import has_package | ||||||
|  |  | ||||||
| emit( | G.setdefault("PROTOC", "protoc") | ||||||
|     """ | G.setdefault("HOSTPROTOC", "hostprotoc") | ||||||
| PROTOC ?= protoc |  | ||||||
| HOSTPROTOC ?= protoc |  | ||||||
| """ |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| assert has_package("protobuf"), "required package 'protobuf' not installed" | assert has_package("protobuf"), "required package 'protobuf' not installed" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,10 +1,5 @@ | |||||||
| import platform |  | ||||||
|  |  | ||||||
| _is_windows = (platform.system() == "Windows") |  | ||||||
|  |  | ||||||
| class Toolchain: | class Toolchain: | ||||||
|     PREFIX = "" |     PREFIX = "" | ||||||
|     EXE = ".exe" if _is_windows else "" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HostToolchain(Toolchain): | class HostToolchain(Toolchain): | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ from build.ab import ( | |||||||
| from os.path import relpath, splitext, join, basename, isfile | from os.path import relpath, splitext, join, basename, isfile | ||||||
| from glob import iglob | from glob import iglob | ||||||
| import fnmatch | import fnmatch | ||||||
|  | import subprocess | ||||||
|  |  | ||||||
|  |  | ||||||
| def filenamesmatchingof(xs, pattern): | def filenamesmatchingof(xs, pattern): | ||||||
| @@ -51,6 +52,11 @@ def itemsof(pattern, root=None, cwd=None): | |||||||
|     return result |     return result | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def shell(args): | ||||||
|  |     r = subprocess.check_output(args) | ||||||
|  |     return r.decode("utf-8").strip() | ||||||
|  |  | ||||||
|  |  | ||||||
| @Rule | @Rule | ||||||
| def objectify(self, name, src: Target, symbol): | def objectify(self, name, src: Target, symbol): | ||||||
|     simplerule( |     simplerule( | ||||||
|   | |||||||
| @@ -7,9 +7,7 @@ from build.ab import ( | |||||||
|  |  | ||||||
|  |  | ||||||
| @Rule | @Rule | ||||||
| def zip( | def zip(self, name, flags="", items: TargetsMap = {}, extension="zip", label="ZIP"): | ||||||
|     self, name, flags="", items: TargetsMap = {}, extension="zip", label="ZIP" |  | ||||||
| ): |  | ||||||
|     cs = ["$(PYTHON) build/_zip.py -z $[outs]"] |     cs = ["$(PYTHON) build/_zip.py -z $[outs]"] | ||||||
|  |  | ||||||
|     ins = [] |     ins = [] | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ from build.c import clibrary | |||||||
| from build.zip import zip | from build.zip import zip | ||||||
| from glob import glob | from glob import glob | ||||||
| from os.path import * | from os.path import * | ||||||
|  | import config | ||||||
|  |  | ||||||
| icons = ["fluxfile", "hardware", "icon", "imagefile"] | icons = ["fluxfile", "hardware", "icon", "imagefile"] | ||||||
|  |  | ||||||
| @@ -17,37 +18,37 @@ clibrary( | |||||||
|     }, |     }, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| simplerule( | if config.osx: | ||||||
|     name="fluxengine_icns", |     simplerule( | ||||||
|     ins=["./icon.png"], |         name="fluxengine_icns", | ||||||
|     outs=["=fluxengine.icns"], |         ins=["./icon.png"], | ||||||
|     commands=[ |         outs=["=fluxengine.icns"], | ||||||
|         "mkdir -p fluxengine.iconset", |         commands=[ | ||||||
|         "sips -z 64 64 $[ins[0]] --out fluxengine.iconset/icon_32x32@2x.png > /dev/null", |             "mkdir -p fluxengine.iconset", | ||||||
|         "iconutil -c icns -o $[outs[0]] fluxengine.iconset", |             "sips -z 64 64 $[ins[0]] --out fluxengine.iconset/icon_32x32@2x.png > /dev/null", | ||||||
|     ], |             "iconutil -c icns -o $[outs[0]] fluxengine.iconset", | ||||||
|     label="ICONSET", |         ], | ||||||
| ) |         label="ICONSET", | ||||||
|  |     ) | ||||||
| simplerule( |  | ||||||
|     name="fluxengine_ico", |     template_files = [ | ||||||
|     ins=["./icon.png"], |         f | ||||||
|     outs=["=fluxengine.ico"], |         for f in glob("**", recursive=True, root_dir="extras/FluxEngine.app.template") | ||||||
|     commands=["png2ico $[outs[0]] $[ins[0]]"], |         if isfile(join("extras/FluxEngine.app.template", f)) | ||||||
|     label="MAKEICON", |     ] | ||||||
| ) |     zip( | ||||||
|  |         name="fluxengine_template", | ||||||
| template_files = [ |         items={ | ||||||
|     f |             join("FluxEngine.app", k): join("extras/FluxEngine.app.template", k) | ||||||
|     for f in glob( |             for k in template_files | ||||||
|         "**", recursive=True, root_dir="extras/FluxEngine.app.template" |         }, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  | if config.windows: | ||||||
|  |     simplerule( | ||||||
|  |         name="fluxengine_ico", | ||||||
|  |         ins=["./icon.png"], | ||||||
|  |         outs=["=fluxengine.ico"], | ||||||
|  |         commands=["png2ico $[outs[0]] $[ins[0]]"], | ||||||
|  |         label="MAKEICON", | ||||||
|     ) |     ) | ||||||
|     if isfile(join("extras/FluxEngine.app.template", f)) |  | ||||||
| ] |  | ||||||
| zip( |  | ||||||
|     name="fluxengine_template", |  | ||||||
|     items={ |  | ||||||
|         join("FluxEngine.app", k): join("extras/FluxEngine.app.template", k) |  | ||||||
|         for k in template_files |  | ||||||
|     }, |  | ||||||
| ) |  | ||||||
|   | |||||||
| @@ -1,19 +1,25 @@ | |||||||
| from build.ab import emit, simplerule | from build.ab import simplerule, G | ||||||
| from build.c import cxxprogram | from build.c import cxxprogram | ||||||
|  | from build.utils import shell | ||||||
| from glob import glob | from glob import glob | ||||||
| import config | import config | ||||||
|  | import shutil | ||||||
|  | import subprocess | ||||||
|  |  | ||||||
| emit( | G.setdefault("WX_CONFIG", "wx-config") | ||||||
|     """ | assert shutil.which(G.WX_CONFIG), "Required binary 'wx-config' not found" | ||||||
| WX_CONFIG ?= wx-config |  | ||||||
| ifneq ($(strip $(shell command -v $(WX_CONFIG) >/dev/null 2>&1; echo $$?)),0) | G.setdefault( | ||||||
| WX_CFLAGS = $(error Required binary 'wx-config' not found.) |     "WX_CFLAGS", | ||||||
| WX_LDFLAGS = $(error Required binary 'wx-config' not found.) |     shell( | ||||||
| else |         [G.WX_CONFIG, "--cxxflags", "base", "adv", "aui", "richtext", "core"] | ||||||
| WX_CFLAGS := $(shell $(WX_CONFIG) --cxxflags base adv aui richtext core) |     ), | ||||||
| WX_LDFLAGS := $(shell $(WX_CONFIG) --libs base adv aui richtext core) | ) | ||||||
| endif | G.setdefault( | ||||||
| """ |     "WX_LDFLAGS", | ||||||
|  |     shell( | ||||||
|  |         [G.WX_CONFIG, "--libs", "base", "adv", "aui", "richtext", "core"] | ||||||
|  |     ) | ||||||
| ) | ) | ||||||
|  |  | ||||||
| extrasrcs = ["./layout.cpp"] | extrasrcs = ["./layout.cpp"] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user