{"id":18427116,"url":"https://github.com/nowisesys/uup-build-system","last_synced_at":"2025-04-13T19:38:44.656Z","repository":{"id":57028813,"uuid":"440099057","full_name":"nowisesys/uup-build-system","owner":"nowisesys","description":"Target build system similar to make with complex dependency tree","archived":false,"fork":false,"pushed_at":"2022-02-21T18:16:03.000Z","size":255,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-16T08:27:29.038Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nowisesys.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-12-20T08:41:39.000Z","updated_at":"2022-01-11T00:16:03.000Z","dependencies_parsed_at":"2022-08-23T16:30:11.339Z","dependency_job_id":null,"html_url":"https://github.com/nowisesys/uup-build-system","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowisesys%2Fuup-build-system","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowisesys%2Fuup-build-system/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowisesys%2Fuup-build-system/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nowisesys%2Fuup-build-system/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nowisesys","download_url":"https://codeload.github.com/nowisesys/uup-build-system/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248769397,"owners_count":21158810,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T05:09:42.868Z","updated_at":"2025-04-13T19:38:44.617Z","avatar_url":"https://github.com/nowisesys.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"## UUP-BUILD-SYSTEM\n\nA build system similar to make with complex dependency tree. Declare goals (target and dependencies)\nand evaluate the dependency tree to rebuild targets in correct order.\n\nGoals are **either** defined _programmatically in code_ or declared in _one or more make-files_. The remaining job \nfor users are to implement the target interface with some concrete actions. Use the TargetBase class to simplify \nthat task.\n\n### GETTING STARTED:\n\nIt's recommended to work with files, even though this README tries to describe both modes as simple and complete as\npossible.\n\n#### GENERATE FILES\n\n* Generate one or more make files using the `generate` option.\n* Changing default namespace and add target classes.\n\n```shell\n./vendor/bin/pbsmake generate \u003e build.make\n```\n\nYou can then use the make command (pbsmake) to evaluate targets. Use type=json if you prefer to work with JSON-style\nfiles.\n\n```shell\n./vendor/bin/pbsmake generate=implicit type=json \u003e build.json\n./vendor/bin/pbsmake build.json\n```\n\n#### PROGRAMMATICALLY\n\n* Begin by creating a dependency tree.\n* Add one or more goal definitions. A goal definition consists of the target (code to run) and a list of dependencies.\n* Get the node evaluator for complete tree or a child node.\n* Call rebuild() to build that node, its dependencies and child nodes.\n\n***Hint:***\nThe dependency tree can be obtained from a (make/json) file reader.\n\n### TARGETS:\n\nA [target](docs/targets.md) has a unique name and description as properties. The class provides the `isUpdated()` for\nchecking if a target is up-to-date and `rebuild()` to build it. The name is used for other targets to express their\ndependency on this target.\n\n### GOALS:\n\nGoals are defined by its target and a list of zero or more dependencies. Dependencies are strings matching other\ntargets (goals) by their name. A goal is what's used for constructing the dependency tree.\n\n### DECLARATIONS:\n\nHow everything should be build can either be declared programmatically in code, static declared with files\nor a mixture of them.\n\n### NODES \u0026 TREES:\n\nThe dependency tree can be constructed manually by adding child nodes (dependencies) and then using the node evaluator\non the root node for rebuilding the manual crafted tree. More convenient is to use the dependency tree, adding nodes to\nit either as dependency nodes or using goal definitions.\n\n### FILES:\n\nDependencies can be declared in text files which are consumed by a file reader. The same reader can be used for reading\nrules from multiple input files:\n\n```php\n$reader = new MakeFileReader();\n\n$reader-\u003eaddDependencies(\"makefile1.txt\");\n$reader-\u003eaddDependencies(\"makefile2.txt\");\n\n$reader-\u003egetDependencyTree()\n       -\u003egetEvaluator()\n       -\u003erebuild();\n```\n\nCurrently, [GNU makefile](example/file/input.make) or [JSON](example/file/input.json) is the supported file formats.\n\n#### MAKEFILE\n\nAn example of makefile declaration using the test target class looks like this:\n\n```makefile\nVERBOSE\t:= true\nDEBUG \t:= true\n\nNAMESPACE := UUP\\BuildSystem\\Tests\n\nT1 :\n\tTarget(\"T1\")\nT2 : T1\n\tTarget(\"T2\")\nT3 : T1\n\tTarget(\"T3\")\nT4 : T2\n\tTarget(\"T4\")\nT5 : T2 T3\n\tTarget(\"T5\")\nT6 : T4\n\tTarget(\"T6\")\nT7 : T5\n\tTarget(\"T7\")\nT8 : T5\n\tTarget(\"T8\", 123, true)\n```\n\nFollowing conventions, the left-hand side is the rule target and right-hand side list dependencies. The Target class \nimplements the PHP code to execute for that rule target. The T5 target depends on T2 and T3, while T6 and T7 both \ndepends on T5.\n\nThe target class will be constructed with variadic number of arguments. It's thus possible to use the same target \nclass in multiple rules and define different behavior from arguments. \n\nTarget name and list of dependencies will be passed to the target class instance.\n\n```makefile\nT1 :\n\tTarget()            # Constructs new Target(), with name T1 derived from target name.\nT8 : T5\n\tTarget(123, true)   # Constructs new Target(123, true) named T8.\n```\n\nIn reality, the Target class will be replaced by different classes. This is just an example makefile purely for testing.\n\n#### OPTIONS\n\nOptional arguments are not limited to simple scalar values. Use standard JSON encoding for passing complex object\nstructures as optional arguments that will be decoded into standard associative arrays.\n\n```makefile\nT8 : T5\n\tTarget(123, true, [\"P1\", \"P2\"])\nT9 : T5\n\tTarget(123, true, {\"name\": \"Anders\", \"city\": \"Uppsala\", \"hobbies\": [\"playing guitar\", \"watching sci-fi\", \"programming\"]})\n```\n\n#### NAMESPACES\n\nThe default namespace is declared in the makefile. If classes is placed in multiple namespaces, either declare them\nfully qualified or split declarations in multiple file, each with their own default namespace.\n\n#### IMPLICIT\n\nTarget classes can be deduced from make rule (in Makefile or JSON file). In this case, the left-/right-hand target\nshould be a class. The example Makefile above then becomes:\n\n```makefile\nVERBOSE\t:= true\nDEBUG \t:= true\n\nNAMESPACE := UUP\\BuildSystem\\Tests\\Implicit\n\nT1 :\nT2 : T1\nT3 : T1\nT4 : T2\nT5 : T2 T3\nT6 : T4\nT7 : T5\nT8 : T5\n```\n\nEach T* class is present in this test namespace and can be tested with:\n\n```shell\n./vendor/bin/pbsmake example/file/implicit.make target=T3\n```\n\nIt's possible to mix rules with implicit/explicit target classes. Classes don't have to be defined in the namespace\ndeclared in the make file, use fully qualified class name if present in some other namespace.\n\n#### PROBING\n\nInvoking the pbsmake-command without a list of makefiles will cause script to probe current directory for some standard\nnamed files: `build.make`, `build.json`, `makefile`, `makefile.txt` and `*.pbs`. The default type is assumed to be\nmakefiles.\n\nPass recursive option (-r) to enable recursive scan for makefiles starting in current directory.\n\n#### VERBOSE \u0026 DEBUG\n\nThe superglobal environment (`$_ENV`) gets populated with DEBUG and VERBOSE values from make files.\n\n```php\nArray\n(\n    [PBS_MAKE_VERBOSE] =\u003e 1\n    [PBS_MAKE_DEBUG] =\u003e 1\n)\n```\n\nFor convenience, either true/false, yes/no, on/off and 0/1 are recognised as boolean value.\n\n#### PHONY TARGETS\n\nPhony target function as virtual dependencies for zero or more real targets. It's easiest to explain this with an simple\nexample.\n\nLet's say that we define this list of phony targets:\n\n```makefile\nPHONY := all clean dist-clean\n```\n\nWe can then i.e. set T1 and T2 to depend on the phony `all` target:\n\n```makefile\nT1 : all\nT2 : all\nT3 : T1\nT4 : T2\nT5 : T2 T3\n```\n\nEvaluate the dependency tree starting from the builtin root-node will list:\n\n```shell\n./vendor/bin/pbsmake example/file/implicit.make -d target=root\n  ...\nEvaluate node tree structure (graph):\n{\n    \"all\": {\n        \"T1\": {\n            \"T3\": {\n                \"T5\": []\n            }\n        },\n        \"T2\": {\n            \"T4\": [],\n            \"T5\": []\n        }\n    },\n    \"clean\": [],\n    \"dist-clean\": []\n}\n  ...\n```\n\nAs expected, both T1 and T2 are immediate child of the phony target `all`. Evaluating target all will rebuild both of\nthem along with their dependencies.\n\n```shell\n./vendor/bin/pbsmake example/file/implicit.make -v target=all\n  ...\nAdd dependencies from example/file/implicit.make\nMaking all (Phony target for all)\n  ...\n```\n\n**Notice:**\n\nIf `target` option isn't specified, then the builtin `root` target will be evaluated. In the example above, it will\ncause `clean` and `dist-clean` to be evaluated too.\n\n#### SPECIAL TARGETS\n\nOne common task is to execute shell commands. A builtin target exists for this:\n\n```makefile\nclean:\n    Shell(\"find -name *.tmp -type f | xargs rm -f\")\n```\n\nWrap commands within `@(...)` or `@@(...)` to suppress output.\n\n```makefile\nclean:\n    Shell(\"@(find -name *.tmp -type f | xargs rm -f)\")\n```\n\nAnother task is to run arbitrary PHP code. Supplied code will be executed using `eval()`, make sure to not use this\nfeature with external input.\n\n```makefile\nfinished:\n    Call(\"printf('Finished build at %s!\\n', strftime('%c'));\")\n```\n\nSee the unit tests for further examples.\n\n### EVALUATION:\n\nThe tree is usually completely rebuilt by evaluating its root node:\n\n```php \n$tree-\u003egetEvaluator()-\u003erebuild();\n```\n\nIt's also possible to obtain one of the tree nodes from the registry and evaluate it:\n\n```php\n$tree-\u003egetRegistry()-\u003egetNode(\"T5\")\n    -\u003egetEvaluator()\n    -\u003erebuild();\n```\n\n### EXAMPLES:\n\nThe example directory contains some script for constructing an example build tree. Evaluating the T5 node should rebuild\nT1, T2, T3, T5, T7 and T8 in that order (unless dependency node are already up-to-date).\n\n![](docs/dependency-tree.png)\n\nRun them from command line:\n\n```shell\nphp example/definition-tree.php\n```\n\n### EXCLUDE CHILD TARGETS:\n\nThe default is to build a target node with all its dependency and child nodes. For a\nmore [standard make mode](example/make-compat.php), building child nodes can be disabled:\n\n```php\n$tree-\u003egetEvaluator()\n    -\u003esetRebuildChildren(false)\n    -\u003erebuild();\n```\n\nThen the output will be:\n\n```text\n++ Rebuild node T5:\nCalled isUpdated() on T1 (updated=0)\nCalled rebuild() on T1 (updated=0)\nCalled isUpdated() on T2 (updated=0)\nCalled rebuild() on T2 (updated=0)\nCalled isUpdated() on T3 (updated=0)\nCalled rebuild() on T3 (updated=0)\nCalled isUpdated() on T5 (updated=0)\nCalled rebuild() on T5 (updated=0)\n++ Rebuild complete tree:\n```\n\n### MAKE COMMAND:\n\nThe make command [pbsmake](bin/pbsmake) can be used for executing makefiles and makes it easy to get started. Like\nstandard make, an optional target can be passed:\n\n```shell\n./vendor/bin/pbsmake example/file/input.make target=T8\nCalled isUpdated() on T1 (updated=0)\nCalled rebuild() on T1 (updated=0)\nCalled isUpdated() on T2 (updated=0)\nCalled rebuild() on T2 (updated=0)\nCalled isUpdated() on T3 (updated=0)\nCalled rebuild() on T3 (updated=0)\nCalled isUpdated() on T5 (updated=0)\nCalled rebuild() on T5 (updated=0)\nCalled isUpdated() on T7 (updated=0)\nCalled rebuild() on T7 (updated=0)\n```\n\nMultiple makefiles can be processed. Currently, a limitation is that all makefiles must be of same type.\n\n```shell\n./vendor/bin/pbsmake -h\nPHP make (build system command)\n\nUsage: pbsmake makefile1 [...makefiles] [target=name] [type=json]\n\nOptions:\n  target=name:      Make this target.\n  type=str:         The type of makefile (make/json).\n  compat[=bool]:    Enable make compatible mode.\n  generate[=mode]:  Output template makefile (explicit/implicit).\n  recursive:        Recursive scan for makefiles (-r).\n\nGeneric options:\n  help:     Show this casual help.\n  version:  Show version information.\n  verbose:  Run in verbose mode.\n  quiet:    Run in quiet mode.\n  debug:    Enable debug output.\n\nCopyright (C) 2021-2022 Nowise Systems\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnowisesys%2Fuup-build-system","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnowisesys%2Fuup-build-system","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnowisesys%2Fuup-build-system/lists"}