The moon-run
lib is a command-line utility for building and running Haxe projects.
Like how LESS/SASS provides a nested way to do CSS, haxe.json
is a nested way to describe build.hxml
where compiler flags within JSON objects can "inherit" from its parent.
It mainly provides an alternate way of compiling your Haxe projects using settings stored in a haxe.json
file. It is useful for projects that has to compile to different targets with multiple different settings. You can organize your settings in a nested json structure.
It also supports retrieving settings from FlashDevelop's .hxproj
files. I mainly use this with FlashDevelop (see Using With FlashDevelop section at the bottom).
haxelib install moon-run
haxelib run moon-run setup # hx => haxelib run moon-run
After setup, instead of running haxelib run moon-run whatever
, you can instead use the shorter hx whatever
. If you don't want the shortcut to be named hx
, you can specify it like in the example below. You can also create shortcuts for other haxe libs.
haxelib run moon-run setup foo # foo => haxelib run moon-run
haxelib run moon-run setup foo bar # foo => haxelib run bar
haxelib run moon-run setup --remove # removes instead of creating shortcut
Requires haxe.json. See the sections below on how to use.
hx --help # shows command line help information
hx build foo # builds using `foo` configuration
hx build foo --debug # prints hxml output instead of building
hx run bar # run commands in `bar`
hx dev # haxelib dev $name $path
For hx dev
$name
is implied based on current directory name, or if haxe.json exist, will use the information defined inmeta.name
.$path
is the path of the current directory.
Comments in JSON are invalid according to specifications. However, the moon-run
lib allows comments and these are automatically stripped.
{
// Meta information about the project.
// This can also be used to generate haxelib.json when pushing to
// a haxelib repository. No need to add dependencies field here
// as it can be inferred from the build settings.
// If dependencies are listed here, then no inferrence is done.
"meta":
{
"name": "my-project",
"license": "2KILL",
"tags": ["cross", "utility"],
"description": "super cool project",
"contributors": ["somebody"],
"releasenote": "Update for haxe 3.2",
"version": "1.0.0",
"url": "https://github.com/somebody/my-project",
"classPath": "src/"
// leave out "dependencies" and moon-run will
// automatically fill it in based on all the -lib
// arguments in the build section below
},
// Build settings goes here.
"build":
{
// These are the common settings that will be inherited
// in all sub-settings.
"-main": "Test",
"-cp": ["src", "test"],
"-lib": ["tink_core"],
"-v": false,
// This is a group of settings
"release":
{
"-D": "hey"
},
"debug":
{
"-D": "yo"
},
// build with:
// hx build js
"js":
{
// This will override the parent -main setting.
"-main": "Foo",
// This will concatenate with the parent -lib resulting
// in ["tink_core", "nodejs", "expressjs"].
"-lib": ["nodejs", "expressjs"],
"-js": "bin/foo.js"
},
// hx build neko
"neko":
{
// This turns into a -main and the value is retrieved
// from myfile.hxproj.
"@hxproj-main": "run.hxproj",
// Paths can have spaces, no problem.
"-neko": "foo/bar baz/hey.n"
},
// hx build html
"html":
{
// When multiple targets are listed together, args
// --each and --next will be generated accordingly.
"-js": "bin/html/app.js",
"-as3": "bin/html/app_a.swf",
// nested config. build with:
// hx build html/as3
"as3":
{
// This overrides the parent's -as3
"-as3": "bin/html/app_c.swf",
"-D": "abc"
}
},
// hx build as3
"as3":
{
"-as3": "bin/html/app_b.swf",
"-D": "hi"
},
// hx build whatever
"whatever":
{
"-js": "bin/js/app.js",
// merges the settings in "release" and "debug"
// into this current object
"@merge": ["release", "debug"]
},
// used by run example below
"hello":
{
"-main": "Foo",
"-neko": "foo/bar baz/hello.n"
},
// hx build foo
// same as consecutive commands:
// hx build as3
// hx build whatever
// or in a single line:
// hx build as3 whatever
// and is also equivalent to:
// "foo": { "@multi": ["as3", "whatever"] }
"foo": ["as3", "whatever"]
},
// Run settings goes here.
"run":
{
// hx run message
"message": "This is a string",
// hx run greet something
"greet":
[
// [0] is the first argument passed to the greet function
["println", "hello", [0], "!"],
["println", ["message"]]
],
// hx run main
// or simply, hx run
"main":
[
["hx", "build", "hello"],
["cd", "foo", "bar baz"],
["neko", "hello", "how", "are you"],
["greet", "world"]
]
}
}
The following examples are based on haxe.json above.
hx build
generates the following hxml and runs it through haxe:
-main Test
-cp src
-cp test
-lib tink_core
hx build html
generates the following hxml and runs it through haxe:
-main Test
-cp src
-cp test
-lib tink_core
--each
-js bin/html/app.js
--next
-as3 bin/html/app_a.swf
hx build html as3
generates 2 hxml files and runs each of them through haxe:
-main Test
-cp src
-cp test
-lib tink_core
--each
-js bin/html/app.js
--next
-as3 bin/html/app_a.swf
-main Test
-cp src
-cp test
-lib tink_core
-D hi
-as3 bin/html/app_b.swf
hx build html/as3
builds the as3
config within html
, and not the other as3
config within root of build config:
-main Test
-cp src
-cp test
-lib tink_core
-D abc
--each
-js bin/html/app.js
--next
-as3 bin/html/app_c.swf
hx build whatever
generates:
-main Test
-cp src
-cp test
-lib tink_core
-D hey
-D yo
-js bin/js/app.js
hx build foo
builds as3
and whatever
separately, and generates:
-main Test
-cp src
-cp test
-lib tink_core
-D hi
-as3 bin/html/app_b.swf
-main Test
-cp src
-cp test
-lib tink_core
-D hey
-D yo
-js bin/js/app.js
The following examples are based on haxe.json above.
hx run main
Building... ok
Build completed with 1 successes and 0 failures.
Changed current directory to: C:\Path\To\MyProject\foo\bar baz/
Foo is running! The args are: [how,are you]
bye!
hello world !
This is a string
TODO: More examples.
There are 3 types of arguments in haxe compiler:
- singular-type: arg/value pair that can only appear once (-main, -dce, etc...)
- multi-type: arg/value pairs that can appear more than once (-lib, -D, etc...)
- bool-type: arg flag that doesn't need a value (-debug, -v, etc...)
Singular-types are represented in JSON as "-arg": "value"
.
Multi-types are represented in JSON as "-arg": ["value1", "value2", ...]
. If an argument is a known multi-type, you can also write it as a string, e.g. "-arg": "value"
. This lib will detect those and automatically wrap them in an Array.
Bool-types are represented in JSON as a Bool, e.g. "-arg": true
. Valid values are true
or false
. If it is a known bool-type, any truthy value can be used, which will be coerced into a Bool. Truthy values includes the String "true", "false", "yes", and integers. If Int is given, 0 is false, everything else is true. Null is false. If an object or array is there where a truthy is expected, an exception will be thrown.
Build settings can be nested! Settings of a child-object inherits from all its parent-objects, all the way to the root build object.
Settings in a child-object will shadow its parent's settings if the argument is a single-type or bool-type, and will concatenate with its parent's settings if the argument is a multi-type.
If you want a multi-type value to shadow instead of concatenate, put a null
as the first item in the array.
Fields that starts with -
are Haxe's command line arguments.
Fields that starts with @
are hx's special commands.
All other fields represents a group of settings.
List of special commands:
@merge: ["group1", "group2"]
Merges all the settings from group1 object and group2 object into current object. This will replace or concatenate the values of current object when the field names match.@multi: [{...}, {...}, ...]
Builds each object in the array separately. If you have a"groupX": ["groupA", "groupB"]
, and you build withhx build groupX
, it will automatically transform into a multi command, and is the same as runninghx build groupA
followed byhx build groupB
.@hxproj-main: "myfile.hxproj"
This will transform into a-main
argument. It opensmyfile.hxproj
and read themainClass
setting for its value. I sometimes switch main class often from within FlashDevelop to test and run different classes, but I require custom build settings. So this comes in handy.@hxproj: "myfile.hxproj"
(not implemented yet)
This is intended to read all the settings frommyfile.hxproj
and infer all the arguments. This might be useful to those using FlashDevelop as their Haxe IDE and wants to export their settings into a hxml file.
Some projects may have a number of bash/batch scripts to run some common tasks. For most of my projects, it's simply to run the compiled program from the bin directory.
You can add those commands within the JSON file as ["command", "arg1", "arg2", ...]
. This lib will run them as Sys.command()
calls.
Since they look like S-expressions, I couldn't resist and implemented a little simplified Lisp out of the JSON array syntax.
- All literals except arrays evaluates as themselves.
- Arrays become function calls.
env
is the current environment/scope. Ifenv
does not have variablefoo
, then do a Sys.command instead. - You can override function definitions with your own definitions.
- If there's a conflict between user-defined function name, and a system call,
you can prefix with a
#
to force a system call. - User-defined functions are case-insensitive, by turning it to lowercase.
JSON | Haxe |
---|---|
5 | 5 |
true | true |
"foo" | "foo" |
{ "key": "value" } | { "key": "value" } |
["foo"] | env.foo() or Sys.command("foo") |
["FoO"] | env.foo() or Sys.command("foo") |
["foo", "bar", "baz"] | env.foo("bar", "baz") or Sys.command("foo", ["bar", "baz"]) |
["array", "foo", "bar"] | ["foo", "bar"] |
["&foo"] | env["foo"] |
["#foo", "bar"] | Sys.command("foo", ["bar"]) |
[">foo", "bar"] | new Process("foo", ["bar"]) |
Currently, you can't do much with Process. This will be updated in future versions.
List of implemented functions:
begin
, var
, set
, if
, lambda
, define
, print
, println
, globals
,
field
, index
, array
, ==
, !=
, <
, >
, <=
, >=
, &&
, ||
, !
, +
, -
, *
, /
, %
- Create
haxe.json
with the build and run settings for the desired platforms. - Set
Project > Properties... > Build > Pre-Build Command Line
tohaxelib run moon-run build "$(TargetPlatform)"
- Set
Project > Properties... > Output > Test Project
to run custom commandhx run "$(TargetPlatform)" --pause
The --pause
argument prevents the command prompt window from immediately
closing after your program has ended.
I'm not sure why, but Pre-Build Command Line
does not seem to detect hx
, but
haxelib
works fine, even though they're on the same directory.
By nesting your configs appropriately, your build command can be something like
haxelib run moon-run build "$(TargetPlatform)/$(BuildConfig)"
or (TODO) merge them using
haxelib run moon-run build "$(TargetPlatform)+$(BuildConfig)"
Feel free to contribute.
MIT