Переглянути джерело

Fix inconsistencies with define flags (#10365)

* Fix inconsistency between - and _ in define.json

* Remove unnecessary dash conversion

define.json now already provides them with dashes so this manual
conversion is no longer necessary.

* Move `source-header` default value setting

* Split function with bool parameter

* Fix missing error when doing `-D haxe-ver`

* Use underscore defines internally

Move all define conversions to interfaces, and internally a flag is
represented using the underscore version only.

This prevents duplicate defines appearing in a bunch of places, and now
there are no longer tiny differences in the effects of `-D flag-a` and
`-D flag_a`. Same is true for macro functions for accessing defines.

* Use existing functions for accessing defines

* Remove duplicate definition of the `flash` define

This is already done for every target in `Common.init_platform`.

* Update documentation for `net-ver` compiler flag

* Remove `dump_context` made redundant in bef481f

* Clean up define outputs

All internal outputs of defines are now in alphabetical order

* Add tests for define flag conversions

* Add tests for `-D no-deprecation-warnings`

* Add tests for `-D source-header`

* Test for duplicate defines in `hlc.json` & `Options.txt`

* [hl] Fix `-D source-header` not working with hlc (#10376)

* Add tests for `source-header` on hlc

* Clean up

- Error for `-D haxe-ver` solved more generally
  - Add temporary function to be removed for #8690
- Minor refactoring

* Fix `--help-defines`
tobil4sk 3 роки тому
батько
коміт
0ef19b4e28
62 змінених файлів з 797 додано та 303 видалено
  1. 89 89
      src-json/define.json
  2. 12 12
      src/codegen/dotnet.ml
  3. 1 1
      src/codegen/gencommon/realTypeParams.ml
  4. 3 3
      src/codegen/java.ml
  5. 22 24
      src/compiler/haxe.ml
  6. 1 1
      src/compiler/server.ml
  7. 6 3
      src/compiler/serverMessage.ml
  8. 73 33
      src/context/common.ml
  9. 1 2
      src/context/display/diagnostics.ml
  10. 14 14
      src/core/define.ml
  11. 9 9
      src/core/globals.ml
  12. 14 14
      src/generators/gencpp.ml
  13. 12 6
      src/generators/genhl.ml
  14. 1 1
      src/generators/genjvm.ml
  15. 1 1
      src/generators/genlua.ml
  16. 15 10
      src/generators/hl2c.ml
  17. 8 5
      src/macro/macroApi.ml
  18. 7 7
      src/optimization/analyzerConfig.ml
  19. 1 0
      tests/misc/cpp/projects/.gitignore
  20. 28 0
      tests/misc/cpp/projects/Issue10184/CheckOptionsTxt.hx
  21. 5 0
      tests/misc/cpp/projects/Issue10184/options-txt.hxml
  22. 2 0
      tests/misc/cpp/run.hxml
  23. 1 0
      tests/misc/hl/projects/.gitignore
  24. 28 0
      tests/misc/hl/projects/Issue10184/CheckJson.hx
  25. 5 0
      tests/misc/hl/projects/Issue10184/hlc-json.hxml
  26. 56 0
      tests/misc/hl/projects/Issue10376/CheckSourceHeader.hx
  27. 5 0
      tests/misc/hl/projects/Issue10376/custom-header.hxml
  28. 5 0
      tests/misc/hl/projects/Issue10376/default-header.hxml
  29. 5 0
      tests/misc/hl/projects/Issue10376/no-header-dash.hxml
  30. 2 0
      tests/misc/hl/run.hxml
  31. 1 0
      tests/misc/js/projects/.gitignore
  32. 35 0
      tests/misc/js/projects/Issue10184/CheckSourceHeader.hx
  33. 3 0
      tests/misc/js/projects/Issue10184/Main.hx
  34. 12 0
      tests/misc/js/projects/Issue10184/Tools.hx
  35. 4 0
      tests/misc/js/projects/Issue10184/custom-header-dash.hxml
  36. 4 0
      tests/misc/js/projects/Issue10184/custom-header-underscore.hxml
  37. 4 0
      tests/misc/js/projects/Issue10184/default-header.hxml
  38. 4 0
      tests/misc/js/projects/Issue10184/no-header-dash.hxml
  39. 4 0
      tests/misc/js/projects/Issue10184/no-header-underscore.hxml
  40. 2 0
      tests/misc/js/run.hxml
  41. 12 0
      tests/misc/projects/Issue10184/BuiltIn.hx
  42. 4 0
      tests/misc/projects/Issue10184/Deprecated.hx
  43. 27 0
      tests/misc/projects/Issue10184/Flags.hx
  44. 27 0
      tests/misc/projects/Issue10184/GetDefines.hx
  45. 25 0
      tests/misc/projects/Issue10184/IfBlocks.hx
  46. 25 0
      tests/misc/projects/Issue10184/Repeated.hx
  47. 1 0
      tests/misc/projects/Issue10184/builtin.hxml
  48. 2 0
      tests/misc/projects/Issue10184/check-warning.hxml
  49. 1 0
      tests/misc/projects/Issue10184/check-warning.hxml.stderr
  50. 7 0
      tests/misc/projects/Issue10184/cli.hxml
  51. 18 0
      tests/misc/projects/Issue10184/get-defines.hxml
  52. 18 0
      tests/misc/projects/Issue10184/if-blocks.hxml
  53. 7 0
      tests/misc/projects/Issue10184/macro.hxml
  54. 3 0
      tests/misc/projects/Issue10184/no-warning-underscore.hxml
  55. 0 0
      tests/misc/projects/Issue10184/no-warning-underscore.hxml.stderr
  56. 3 0
      tests/misc/projects/Issue10184/no-warning.hxml
  57. 0 0
      tests/misc/projects/Issue10184/no-warning.hxml.stderr
  58. 18 0
      tests/misc/projects/Issue10184/repeated.hxml
  59. 9 0
      tests/runci/System.hx
  60. 4 0
      tests/runci/targets/Cpp.hx
  61. 75 67
      tests/runci/targets/Hl.hx
  62. 6 1
      tests/runci/targets/Js.hx

+ 89 - 89
src-json/define.json

@@ -1,7 +1,7 @@
 [
 	{
 		"name": "AbsolutePath",
-		"define": "absolute_path",
+		"define": "absolute-path",
 		"doc": "Print absolute file path in trace output."
 	},
 	{
@@ -12,28 +12,28 @@
 	},
 	{
 		"name": "AnalyzerOptimize",
-		"define": "analyzer_optimize",
+		"define": "analyzer-optimize",
 		"doc": "Perform advanced optimizations."
 	},
 	{
 		"name": "AnnotateSource",
-		"define": "annotate_source",
+		"define": "annotate-source",
 		"doc": "Add additional comments to generated source code.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "CheckXmlProxy",
-		"define": "check_xml_proxy",
+		"define": "check-xml-proxy",
 		"doc": "Check the used fields of the XML proxy."
 	},
 	{
 		"name": "CoreApi",
-		"define": "core_api",
+		"define": "core-api",
 		"doc": "Defined in the core API context."
 	},
 	{
 		"name": "CoreApiSerialize",
-		"define": "core_api_serialize",
+		"define": "core-api-serialize",
 		"doc": "Mark some generated core API classes with the `Serializable` attribute on C#.",
 		"platforms": ["cs"]
 	},
@@ -44,7 +44,7 @@
 	},
 	{
 		"name": "CsVer",
-		"define": "cs_ver",
+		"define": "cs-ver",
 		"doc": "The C# version to target.",
 		"platforms": ["cs"],
 		"params": ["version"]
@@ -63,7 +63,7 @@
 	},
 	{
 		"name": "DceDebug",
-		"define": "dce_debug",
+		"define": "dce-debug",
 		"doc": "Show DCE log.",
 		"links": ["https://haxe.org/manual/cr-dce.html"]
 	},
@@ -74,7 +74,7 @@
 	},
 	{
 		"name": "DisableUnicodeStrings",
-		"define": "disable_unicode_strings",
+		"define": "disable-unicode-strings",
 		"doc": "Disable Unicode support in `String` type.",
 		"platforms": ["cpp"]
 	},
@@ -86,24 +86,24 @@
 	},
 	{
 		"name": "DisplayStdin",
-		"define": "display_stdin",
+		"define": "display-stdin",
 		"doc": "Read the contents of a file specified in `--display` from standard input."
 	},
 	{
 		"name": "DllExport",
-		"define": "dll_export",
+		"define": "dll-export",
 		"doc": "GenCPP experimental linking.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "DllImport",
-		"define": "dll_import",
+		"define": "dll-import",
 		"doc": "Handle Haxe-generated .NET DLL imports.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "DocGen",
-		"define": "doc_gen",
+		"define": "doc-gen",
 		"doc": "Do not perform any removal/change in order to correctly generate documentation."
 	},
 	{
@@ -114,65 +114,65 @@
 	},
 	{
 		"name": "DumpPath",
-		"define": "dump_path",
+		"define": "dump-path",
 		"doc": "Path to generate dumps to (default: \"dump\").",
 		"params": ["path"]
 	},
 	{
 		"name": "DumpDependencies",
-		"define": "dump_dependencies",
+		"define": "dump-dependencies",
 		"doc": "Dump the classes dependencies in a dump subdirectory."
 	},
 	{
 		"name": "DumpIgnoreVarIds",
-		"define": "dump_ignore_var_ids",
+		"define": "dump-ignore-var-ids",
 		"doc": "Remove variable IDs from non-pretty dumps (helps with diff)."
 	},
 	{
 		"name": "DynamicInterfaceClosures",
-		"define": "dynamic_interface_closures",
+		"define": "dynamic-interface-closures",
 		"doc": "Use slow path for interface closures to save space.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "EraseGenerics",
-		"define": "erase_generics",
+		"define": "erase-generics",
 		"doc": "Erase generic classes on C#.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "EvalCallStackDepth",
-		"define": "eval_call_stack_depth",
+		"define": "eval-call-stack-depth",
 		"doc": "Set maximum call stack depth for eval. (default: 1000)",
 		"platforms": ["eval"],
 		"params": ["depth"]
 	},
 	{
 		"name": "EvalDebugger",
-		"define": "eval_debugger",
-		"doc": "Support debugger in macro/interp mode. Allows `host:port` value to open a socket. Implies eval_stack.",
+		"define": "eval-debugger",
+		"doc": "Support debugger in macro/interp mode. Allows `host:port` value to open a socket. Implies eval-stack.",
 		"platforms": ["eval"]
 	},
 	{
 		"name": "EvalStack",
-		"define": "eval_stack",
+		"define": "eval-stack",
 		"doc": "Record stack information in macro/interp mode.",
 		"platforms": ["eval"]
 	},
 	{
 		"name": "EvalTimes",
-		"define": "eval_times",
-		"doc": "Record per-method execution times in macro/interp mode. Implies eval_stack.",
+		"define": "eval-times",
+		"doc": "Record per-method execution times in macro/interp mode. Implies eval-stack.",
 		"platforms": ["eval"]
 	},
 	{
 		"name": "FilterTimes",
-		"define": "filter_times",
+		"define": "filter-times",
 		"doc": "Record per-filter execution times upon --times."
 	},
 	{
 		"name": "FastCast",
-		"define": "fast_cast",
+		"define": "fast-cast",
 		"doc": "Enables an experimental casts cleanup on C# and Java.",
 		"platforms": ["cs", "java"]
 	},
@@ -184,38 +184,38 @@
 	},
 	{
 		"name": "FileExtension",
-		"define": "file_extension",
+		"define": "file-extension",
 		"doc": "Output filename extension for cpp source code.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "FlashStrict",
-		"define": "flash_strict",
+		"define": "flash-strict",
 		"doc": "More strict typing for flash target.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "FlashUseStage",
-		"define": "flash_use_stage",
+		"define": "flash-use-stage",
 		"doc": "Keep the SWF library initial stage.",
 		"platforms": ["flash"]
 	},
 	{
-		"devcomment": "force_lib_check is only here as a debug facility - compiler checking allows errors to be found more easily",
+		"devcomment": "force-lib-check is only here as a debug facility - compiler checking allows errors to be found more easily",
 		"name": "ForceLibCheck",
-		"define": "force_lib_check",
+		"define": "force-lib-check",
 		"doc": "Force the compiler to check `--net-lib` and `–-java-lib` added classes (internal).",
 		"platforms": ["cs", "java"]
 	},
 	{
 		"name": "ForceNativeProperty",
-		"define": "force_native_property",
+		"define": "force-native-property",
 		"doc": "Tag all properties with `:nativeProperty` metadata for 3.1 compatibility.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "GencommonDebug",
-		"define": "gencommon_debug",
+		"define": "gencommon-debug",
 		"doc": "GenCommon internal.",
 		"platforms": ["cs", "java"]
 	},
@@ -226,13 +226,13 @@
 	},
 	{
 		"name": "HaxeBoot",
-		"define": "haxe_boot",
+		"define": "haxe-boot",
 		"doc": "Give the name 'haxe' to the flash boot class instead of a generated name.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "HaxeVer",
-		"define": "haxe_ver",
+		"define": "haxe-ver",
 		"doc": "The current Haxe version value as decimal number. E.g. 3.407 for 3.4.7.",
 		"reserved": true
 	},
@@ -244,39 +244,39 @@
 	},
 	{
 		"name": "HlVer",
-		"define": "hl_ver",
+		"define": "hl-ver",
 		"doc": "The HashLink version to target. (default: 1.10.0)",
 		"platforms": ["hl"],
 		"params": ["version"]
 	},
 	{
 		"name": "HxcppApiLevel",
-		"define": "hxcpp_api_level",
+		"define": "hxcpp-api-level",
 		"doc": "Provided to allow compatibility between hxcpp versions.",
 		"platforms": ["cpp"],
 		"reserved": true
 	},
 	{
 		"name": "HxcppGcGenerational",
-		"define": "HXCPP_GC_GENERATIONAL",
+		"define": "HXCPP-GC-GENERATIONAL",
 		"doc": "Experimental Garbage Collector.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "HxcppDebugger",
-		"define": "HXCPP_DEBUGGER",
-		"doc": "Include additional information for hxcpp_debugger.",
+		"define": "HXCPP-DEBUGGER",
+		"doc": "Include additional information for hxcpp-debugger.",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "HxcppSmartStings",
-		"define": "hxcpp_smart_strings",
-		"doc": "Use wide strings in hxcpp. (Turned on by default unless `-D disable_unicode_strings` is specified.)",
+		"define": "hxcpp-smart-strings",
+		"doc": "Use wide strings in hxcpp. (Turned on by default unless `-D disable-unicode-strings` is specified.)",
 		"platforms": ["cpp"]
 	},
 	{
 		"name": "IncludePrefix",
-		"define": "include_prefix",
+		"define": "include-prefix",
 		"doc": "Prepend path to generated include files.",
 		"platforms": ["cpp"]
 	},
@@ -293,20 +293,20 @@
 	},
 	{
 		"name": "JavaVer",
-		"define": "java_ver",
+		"define": "java-ver",
 		"doc": "Sets the Java version to be targeted.",
 		"platforms": ["java"],
 		"params": ["version: 5-7"]
 	},
 	{
 		"name": "JsClassic",
-		"define": "js_classic",
+		"define": "js-classic",
 		"doc": "Don't use a function wrapper and strict mode in JS output.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "JsEs",
-		"define": "js_es",
+		"define": "js-es",
 		"doc": "Generate JS compliant with given ES standard version. (default: 5)",
 		"platforms": ["js"],
 		"params": ["version: 3 | 5 | 6"],
@@ -314,7 +314,7 @@
 	},
 	{
 		"name": "JsEnumsAsArrays",
-		"define": "js_enums_as_arrays",
+		"define": "js-enums-as-arrays",
 		"doc": "Generate enum representation as array instead of as object.",
 		"platforms": ["js"]
 	},
@@ -326,19 +326,19 @@
 	},
 	{
 		"name": "JsUnflatten",
-		"define": "js_unflatten",
+		"define": "js-unflatten",
 		"doc": "Generate nested objects for packages and types.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "JsSourceMap",
-		"define": "js_source_map",
-		"doc": "Generate JavaScript source map even in non-debug mode. Deprecated in favor of `-D source_map`.",
+		"define": "js-source-map",
+		"doc": "Generate JavaScript source map even in non-debug mode. Deprecated in favor of `-D source-map`.",
 		"platforms": ["js"]
 	},
 	{
 		"name": "SourceMap",
-		"define": "source_map",
+		"define": "source-map",
 		"doc": "Generate source map for compiled files.",
 		"platforms": ["php", "js"]
 	},
@@ -362,31 +362,31 @@
 	},
 	{
 		"name": "KeepOldOutput",
-		"define": "keep_old_output",
+		"define": "keep-old-output",
 		"doc": "Keep old source files in the output directory.",
 		"platforms": ["cs", "java"]
 	},
 	{
 		"name": "LoopUnrollMaxCost",
-		"define": "loop_unroll_max_cost",
+		"define": "loop-unroll-max-cost",
 		"doc": "Maximum cost (number of expressions * iterations) before loop unrolling is canceled. (default: 250)",
 		"params": ["cost"]
 	},
 	{
 		"name": "LuaJit",
-		"define": "lua_jit",
+		"define": "lua-jit",
 		"doc": "Enable the jit compiler for lua (version 5.2 only).",
 		"platforms": ["lua"]
 	},
 	{
 		"name": "LuaVanilla",
-		"define": "lua_vanilla",
+		"define": "lua-vanilla",
 		"doc": "Generate code lacking compiled extern lib support (e.g. utf8).",
 		"platforms": ["lua"]
 	},
 	{
 		"name": "LuaVer",
-		"define": "lua_ver",
+		"define": "lua-ver",
 		"doc": "The lua version to target.",
 		"platforms": ["lua"],
 		"params": ["version"]
@@ -400,39 +400,39 @@
 	},
 	{
 		"name": "MacroTimes",
-		"define": "macro_times",
+		"define": "macro-times",
 		"doc": "Display per-macro timing when used with `--times`."
 	},
 	{
 		"name": "NetVer",
-		"define": "net_ver",
+		"define": "net-ver",
 		"doc": "Sets the .NET version to be targeted.",
 		"platforms": ["cs"],
-		"params": ["version: 20-45"]
+		"params": ["version: 20-50"]
 	},
 	{
 		"name": "NetcoreVer",
-		"define": "netcore_ver",
+		"define": "netcore-ver",
 		"doc": "Sets the .NET core version to be targeted",
 		"platforms": ["cs"],
 		"params": ["version: x.x.x"]
 	},
 	{
 		"name": "NetTarget",
-		"define": "net_target",
+		"define": "net-target",
 		"doc": "Sets the .NET target. `netcore` (.NET core), `xbox`, `micro` (Micro Framework), `compact` (Compact Framework) are some valid values. (default: `net`)",
 		"platforms": ["cs"],
 		"params": ["name"]
 	},
 	{
 		"name": "NekoSource",
-		"define": "neko_source",
+		"define": "neko-source",
 		"doc": "Output neko source instead of bytecode.",
 		"platforms": ["neko"]
 	},
 	{
 		"name": "NekoV1",
-		"define": "neko_v1",
+		"define": "neko-v1",
 		"doc": "Keep Neko 1.x compatibility.",
 		"platforms": ["neko"]
 	},
@@ -450,7 +450,7 @@
 	},
 	{
 		"name": "NoDebug",
-		"define": "no_debug",
+		"define": "no-debug",
 		"doc": "Remove all debug macros from cpp output."
 	},
 	{
@@ -466,41 +466,41 @@
 	},
 	{
 		"name": "NoOpt",
-		"define": "no_opt",
+		"define": "no-opt",
 		"doc": "Disable optimizations."
 	},
 	{
 		"name": "NoInline",
-		"define": "no_inline",
+		"define": "no-inline",
 		"doc": "Disable inlining.",
 		"links": ["https://haxe.org/manual/class-field-inline.html"]
 	},
 	{
 		"name": "KeepInlinePositions",
-		"define": "keep_inline_positions",
+		"define": "keep-inline-positions",
 		"doc": "Don't substitute positions of inlined expressions with the position of the place of inlining.",
 		"links": ["https://haxe.org/manual/class-field-inline.html"]
 	},
 	{
 		"name": "NoRoot",
-		"define": "no_root",
+		"define": "no-root",
 		"doc": "Generate top-level types into the `haxe.root` namespace.",
 		"platforms": ["cs"]
 	},
 	{
 		"name": "NoMacroCache",
-		"define": "no_macro_cache",
+		"define": "no-macro-cache",
 		"doc": "Disable macro context caching."
 	},
 	{
 		"name": "NoSwfCompress",
-		"define": "no_swf_compress",
+		"define": "no-swf-compress",
 		"doc": "Disable SWF output compression.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "NoTraces",
-		"define": "no_traces",
+		"define": "no-traces",
 		"doc": "Disable all trace calls."
 	},
 	{
@@ -516,41 +516,41 @@
 	},
 	{
 		"name": "PhpPrefix",
-		"define": "php_prefix",
+		"define": "php-prefix",
 		"doc": "Root namespace for generated php classes. E.g. if compiled with`-D php-prefix=some.sub`, then all classes will be generated in `\\some\\sub` namespace.",
 		"platforms": ["php"],
 		"params": ["dot-separated namespace"]
 	},
 	{
 		"name": "PhpLib",
-		"define": "php_lib",
+		"define": "php-lib",
 		"doc": "Select the name for the php lib folder.",
 		"platforms": ["php"],
 		"params": ["folder name"]
 	},
 	{
 		"name": "PhpFront",
-		"define": "php_front",
+		"define": "php-front",
 		"doc": "Select the name for the php front file. (default: `index.php`)",
 		"platforms": ["php"],
 		"params": ["filename"]
 	},
 	{
 		"name": "PythonVersion",
-		"define": "python_version",
+		"define": "python-version",
 		"doc": "The python version to target. (default: 3.3)",
 		"platforms": ["python"],
 		"params": ["version"]
 	},
 	{
 		"name": "RealPosition",
-		"define": "real_position",
+		"define": "real-position",
 		"doc": "Disables Haxe source mapping when targetting C#, removes position comments in Java and Php output.",
 		"platforms": ["cs", "java", "php"]
 	},
 	{
 		"name": "ReplaceFiles",
-		"define": "replace_files",
+		"define": "replace-files",
 		"doc": "GenCommon internal.",
 		"platforms": ["cs", "java"]
 	},
@@ -598,59 +598,59 @@
 	},
 	{
 		"name": "SwfCompressLevel",
-		"define": "swf_compress_level",
+		"define": "swf-compress-level",
 		"doc": "Set the amount of compression for the SWF output.",
 		"platforms": ["flash"],
 		"params": ["level: 1-9"]
 	},
 	{
 		"name": "SwfDebugPassword",
-		"define": "swf_debug_password",
+		"define": "swf-debug-password",
 		"doc": "Set a password for debugging.",
 		"platforms": ["flash"],
 		"params": ["password"]
 	},
 	{
 		"name": "SwfDirectBlit",
-		"define": "swf_direct_blit",
+		"define": "swf-direct-blit",
 		"doc": "Use hardware acceleration to blit graphics.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfGpu",
-		"define": "swf_gpu",
+		"define": "swf-gpu",
 		"doc": "Use GPU compositing features when drawing graphics.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfMetadata",
-		"define": "swf_metadata",
+		"define": "swf-metadata",
 		"doc": "Include contents of the given file as metadata in the SWF.",
 		"platforms": ["flash"],
 		"params": ["file"]
 	},
 	{
 		"name": "SwfPreloaderFrame",
-		"define": "swf_preloader_frame",
+		"define": "swf-preloader-frame",
 		"doc": "Insert empty first frame in SWF.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfProtected",
-		"define": "swf_protected",
+		"define": "swf-protected",
 		"doc": "Compile Haxe `private` as `protected` in the SWF instead of `public`.",
 		"platforms": ["flash"]
 	},
 	{
 		"name": "SwfScriptTimeout",
-		"define": "swf_script_timeout",
+		"define": "swf-script-timeout",
 		"doc": "Maximum ActionScript processing time before script stuck dialog box displays.",
 		"platforms": ["flash"],
 		"params": ["time in seconds"]
 	},
 	{
 		"name": "SwfUseDoAbc",
-		"define": "swf_use_doabc",
+		"define": "swf-use-doabc",
 		"doc": "Use `DoAbc` SWF-tag instead of `DoAbcDefine`.",
 		"platforms": ["flash"]
 	},
@@ -668,7 +668,7 @@
 	},
 	{
 		"name": "UseNekoc",
-		"define": "use_nekoc",
+		"define": "use-nekoc",
 		"doc": "Use `nekoc` compiler instead of the internal one.",
 		"platforms": ["neko"]
 	},
@@ -686,12 +686,12 @@
 	},
 	{
 		"name": "WarnVarShadowing",
-		"define": "warn_var_shadowing",
+		"define": "warn-var-shadowing",
 		"doc": "Warn about shadowing variable declarations."
 	},
 	{
 		"name": "NoTre",
-		"define": "no_tre",
+		"define": "no-tre",
 		"doc": "Disable tail recursion elimination."
 	}
 ]

+ 12 - 12
src/codegen/dotnet.ml

@@ -323,7 +323,7 @@ let convert_ilfield ctx p field =
 		| CInitOnly | CLiteral -> true, acc
 		| _ -> readonly,acc
 	) (false,[cff_access]) field.fflags.ff_contract in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
+	if Common.raw_defined ctx.ncom "net_loader_debug" then
 		Printf.printf "\t%sfield %s : %s\n" (if List.mem_assoc AStatic acc then "static " else "") cff_name (IlMetaDebug.ilsig_s field.fsig.ssig);
 	let kind = match readonly with
 		| true ->
@@ -363,7 +363,7 @@ let convert_ilevent ctx p ev =
 			else
 				acc
 	in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
+	if Common.raw_defined ctx.ncom "net_loader_debug" then
 		Printf.printf "\tevent %s : %s\n" name (IlMetaDebug.ilsig_s ev.esig.ssig);
 	let acc = add_m acc ev.eadd in
 	let acc = add_m acc ev.eremove in
@@ -400,7 +400,7 @@ let convert_ilmethod ctx p is_interface m is_explicit_impl =
 			(APrivate,null_pos), ((Meta.Protected, [], p) :: meta)
 		| FAPublic -> (APublic,null_pos), meta
 		| _ ->
-			if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
+			if Common.raw_defined ctx.ncom "net_loader_debug" then
 				Printf.printf "\tmethod %s (skipped) : %s\n" cff_name (IlMetaDebug.ilsig_s m.msig.ssig);
 			raise Exit
 	in
@@ -412,7 +412,7 @@ let convert_ilmethod ctx p is_interface m is_explicit_impl =
 		| _ -> acc, is_final
 	) ([acc],None) m.mflags.mf_contract in
 	let acc = (AOverload,p) :: acc in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
+	if Common.raw_defined ctx.ncom "net_loader_debug" then
 		Printf.printf "\t%smethod %s : %s\n" (if !is_static then "static " else "") cff_name (IlMetaDebug.ilsig_s m.msig.ssig);
 
 	let acc = match is_final with
@@ -551,7 +551,7 @@ let convert_ilprop ctx p prop is_explicit_impl =
 			| _ -> "never");
 		| Some _ -> "set"
 	in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
+	if Common.raw_defined ctx.ncom "net_loader_debug" then
 		Printf.printf "\tproperty %s (%s,%s) : %s\n" prop.pname get set (IlMetaDebug.ilsig_s prop.psig.ssig);
 	let ilsig = match prop.psig.snorm with
 		| LMethod (_,ret,[]) -> ret
@@ -717,7 +717,7 @@ let convert_ilclass ctx p ?(delegate=false) ilcls = match ilcls.csuper with
 	| _ ->
 		let flags = ref [HExtern] in
 		(* todo: instead of CsNative, use more specific definitions *)
-		if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then begin
+		if Common.raw_defined ctx.ncom "net_loader_debug" then begin
 			let sup = match ilcls.csuper with | None -> [] | Some c -> [IlMetaDebug.ilsig_s c.ssig] in
 			let sup = sup @ List.map (fun i -> IlMetaDebug.ilsig_s i.ssig) ilcls.cimplements in
 			print_endline ("converting " ^ ilpath_s ilcls.cpath ^ " : " ^ (String.concat ", " sup))
@@ -1141,14 +1141,14 @@ class net_library com name file_path std = object(self)
 		let cache = IlMetaReader.create_cache () in
 		let meta = IlMetaReader.read_meta_tables ctx clr_header cache in
 		close_in (r.PeReader.ch);
-		if PMap.mem "net_loader_debug" com.defines.Define.values then
+		if Common.raw_defined com "net_loader_debug" then
 			print_endline ("for lib " ^ file_path);
 		let il_typedefs = Hashtbl.copy meta.il_typedefs in
 		Hashtbl.clear meta.il_typedefs;
 
 		Hashtbl.iter (fun _ td ->
 			let path = IlMetaTools.get_path (TypeDef td) in
-			if PMap.mem "net_loader_debug" com.defines.Define.values then
+			if Common.raw_defined com "net_loader_debug" then
 				Printf.printf "found %s\n" (s_type_path (self#netpath_to_hx path));
 			Hashtbl.replace com.net_path_map (self#netpath_to_hx path) path;
 			Hashtbl.replace meta.il_typedefs path td
@@ -1190,7 +1190,7 @@ class net_library com name file_path std = object(self)
 		let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
 		let cp = ref [] in
 		let rec build path = try
-			if PMap.mem "net_loader_debug" com.defines.Define.values then
+			if Common.raw_defined com "net_loader_debug" then
 				Printf.printf "looking up %s\n" (s_type_path path);
 			match self#lookup path with
 			| Some({csuper = Some{snorm = LClass( (["System"],[],("Delegate"|"MulticastDelegate")),_)}} as cls)
@@ -1241,12 +1241,12 @@ let add_net_lib com file std extern =
 
 let before_generate com =
 	(* netcore version *)
-	let netcore_ver = try Some(PMap.find "netcore_ver" com.defines.Define.values) with Not_found -> None in
+	let netcore_ver = try Some(Common.defined_value com Define.NetcoreVer) with Not_found -> None in
 
 	(* net version *)
 	let net_ver =
 		try
-			let ver = PMap.find "net_ver" com.defines.Define.values in
+			let ver = Common.defined_value com Define.NetVer in
 			try int_of_string ver with Failure _ -> raise (Arg.Bad "Invalid value for -D net-ver. Expected format: xx (e.g. 20, 35, 40, 45, 50)")
 		with Not_found when netcore_ver != None ->
 			(* 4.7 was released around .NET core 2.1 *)
@@ -1274,7 +1274,7 @@ let before_generate com =
 
 	(* net target *)
 	let net_target = try
-			String.lowercase (PMap.find "net_target" com.defines.Define.values)
+			String.lowercase (Common.defined_value com Define.NetTarget)
 		with | Not_found ->
 			"net"
 	in

+ 1 - 1
src/codegen/gencommon/realTypeParams.ml

@@ -766,7 +766,7 @@ let default_implementation gen (dyn_tparam_cast:texpr->t->texpr) ifaces =
 							false)
 						| _ -> false
 					in
-					let unifies = unifies && not (PMap.mem "cs_safe_casts" gen.gcon.defines.Define.values) in
+					let unifies = unifies && not (Common.raw_defined gen.gcon "cs_safe_casts") in
 					(match follow t with
 						| TInst(cl, p1 :: pl) when is_hxgeneric (TClassDecl cl) && not unifies && not (Meta.has Meta.Enum cl.cl_meta) ->
 							let iface = Hashtbl.find ifaces cl.cl_path in

+ 3 - 3
src/codegen/java.ml

@@ -411,7 +411,7 @@ let convert_java_enum ctx p pe =
 							String.concat "_" parts,
 							(Meta.Native, [EConst (String (cff_name,SDoubleQuotes) ), cff_pos], cff_pos) :: !cff_meta
 		in
-		if PMap.mem "java_loader_debug" ctx.jcom.defines.Define.values then
+		if Common.raw_defined ctx.jcom "java_loader_debug" then
 			Printf.printf "\t%s%sfield %s : %s\n" (if List.mem_assoc AStatic !cff_access then "static " else "") (if List.mem_assoc AOverride !cff_access then "override " else "") cff_name (s_sig field.jf_signature);
 
 		{
@@ -453,7 +453,7 @@ let convert_java_enum ctx p pe =
 				[convert_java_enum ctx p jc]
 		| false ->
 			let flags = ref [HExtern] in
-			if PMap.mem "java_loader_debug" ctx.jcom.defines.Define.values then begin
+			if Common.raw_defined ctx.jcom "java_loader_debug" then begin
 				let sup = jc.csuper :: jc.cinterfaces in
 				print_endline ("converting " ^ (if List.mem JAbstract jc.cflags then "abstract " else "") ^ JData.path_s jc.cpath ^ " : " ^ (String.concat ", " (List.map s_sig sup)));
 			end;
@@ -1262,7 +1262,7 @@ let add_java_lib com name std extern modern =
 
 let before_generate con =
 	let java_ver = try
-			int_of_string (PMap.find "java_ver" con.defines.Define.values)
+			int_of_string (Common.defined_value con Define.JavaVer)
 		with | Not_found ->
 			Common.define_value con Define.JavaVer "7";
 			7

+ 22 - 24
src/compiler/haxe.ml

@@ -80,13 +80,6 @@ let error ctx msg p =
 	message ctx (CMError(msg,p));
 	ctx.has_error <- true
 
-let reserved_flags = [
-	"true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
-	"swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver"
-	]
-
-let reserved_flag_namespaces = ["target"]
-
 let delete_file f = try Sys.remove f with _ -> ()
 
 let expand_env ?(h=None) path  =
@@ -196,7 +189,10 @@ module Initialize = struct
 		if com.platform <> Cross then failwith "Multiple targets";
 		Common.init_platform com pf;
 		com.file <- file;
-		if (pf = Flash) && file_extension file = "swc" then Common.define com Define.Swc
+		if (pf = Flash) && file_extension file = "swc" then Common.define com Define.Swc;
+		(* Set the source header, unless the user has set one already or the platform sets a custom one *)
+		if not (Common.defined com Define.SourceHeader) && (pf <> Hl) then
+			Common.define_value com Define.SourceHeader ("Generated by Haxe " ^ s_version_full)
 
 	let initialize_target ctx com classes =
 		let add_std dir =
@@ -216,7 +212,6 @@ module Initialize = struct
 						loop l
 				in
 				loop Common.flash_versions;
-				Common.raw_define com "flash";
 				com.package_rules <- PMap.remove "flash" com.package_rules;
 				add_std "flash";
 				"swf"
@@ -237,7 +232,7 @@ module Initialize = struct
 				if es_version < 3 || es_version = 4 then (* we don't support ancient and there's no 4th *)
 					failwith "Invalid -D js-es value";
 
-				if es_version >= 5 then Common.raw_define com "js-es5"; (* backward-compatibility *)
+				if es_version >= 5 then Common.raw_define com "js_es5"; (* backward-compatibility *)
 
 				add_std "js";
 				"js"
@@ -392,7 +387,8 @@ let setup_common_context ctx com =
 	Common.define_value com Define.HaxeVer (Printf.sprintf "%.3f" (float_of_int Globals.version /. 1000.));
 	Common.raw_define com "haxe3";
 	Common.raw_define com "haxe4";
-	Common.define_value com Define.Haxe (s_version false);
+	Common.define_value com Define.Haxe s_version;
+	Common.raw_define com "true";
 	Common.define_value com Define.Dce "std";
 	com.info <- (fun msg p -> message ctx (CMInfo(msg,p)));
 	com.warning <- (fun msg p -> message ctx (CMWarning(msg,p)));
@@ -491,7 +487,14 @@ let create_typer_context ctx native_libs =
 	let com = ctx.com in
 	ctx.setup();
 	Common.log com ("Classpath: " ^ (String.concat ";" com.class_path));
-	Common.log com ("Defines: " ^ (String.concat ";" (PMap.foldi (fun k v acc -> (match v with "1" -> k | _ -> k ^ "=" ^ v) :: acc) com.defines.Define.values [])));
+	let buffer = Buffer.create 64 in
+	Buffer.add_string buffer "Defines: ";
+	PMap.iter (fun k v -> match v with
+		| "1" -> Printf.bprintf buffer "%s;" k
+		| _ -> Printf.bprintf buffer "%s=%s;" k v
+	) com.defines.values;
+	Buffer.truncate buffer (Buffer.length buffer - 1);
+	Common.log com (Buffer.contents buffer);
 	Typecore.type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> Typer.type_expr ~mode ctx e with_type);
 	List.iter (fun f -> f ()) (List.rev com.callbacks#get_before_typer_create);
 	(* Native lib pass 1: Register *)
@@ -688,7 +691,7 @@ let rec process_params create pl =
 and init ctx =
 	let usage = Printf.sprintf
 		"Haxe Compiler %s - (C)2005-2020 Haxe Foundation\nUsage: haxe%s <target> [options] [hxml files and dot paths...]\n"
-		(s_version true) (if Sys.os_type = "Win32" then ".exe" else "")
+		s_version_full (if Sys.os_type = "Win32" then ".exe" else "")
 	in
 	let com = ctx.com in
 	let classes = ref [([],"Std")] in
@@ -790,18 +793,13 @@ try
 		),"<class>","select startup class");
 		("Compilation",["-L";"--library"],["-lib"],Arg.String (fun l ->
 			cp_libs := l :: !cp_libs;
-			Common.raw_define com l;
+			Common.external_define com l;
 		),"<name[:ver]>","use a haxelib library");
 		("Compilation",["-D";"--define"],[],Arg.String (fun var ->
-			let flag = try fst (ExtString.String.split var "=") with _ -> var in
-			let raise_reserved description =
-				raise (Arg.Bad (description ^ " and cannot be defined from the command line"))
-			in
-			if List.mem flag reserved_flags then raise_reserved (Printf.sprintf "`%s` is a reserved compiler flag" flag);
-			List.iter (fun ns ->
-				if ExtString.String.starts_with flag (ns ^ ".") then raise_reserved (Printf.sprintf "`%s` uses the reserved compiler flag namespace `%s.*`" flag ns)
-			) reserved_flag_namespaces;
-			Common.raw_define com var;
+			let flag, value = try let split = ExtString.String.split var "=" in (fst split, Some (snd split)) with _ -> var, None in
+			match value with
+				| Some value -> Common.external_define_value com flag value
+				| None -> Common.external_define com flag;
 		),"<var[=value]>","define a conditional compilation flag");
 		("Debug",["-v";"--verbose"],[],Arg.Unit (fun () ->
 			com.verbose <- true
@@ -811,7 +809,7 @@ try
 			com.debug <- true;
 		),"","add debug information to the compiled code");
 		("Miscellaneous",["--version"],["-version"],Arg.Unit (fun() ->
-			com.info (s_version true) null_pos;
+			com.info s_version_full null_pos;
 			did_something := true;
 		),"","print version and exit");
 		("Miscellaneous", ["-h";"--help"], ["-help"], Arg.Unit (fun () ->

+ 1 - 1
src/compiler/server.ml

@@ -76,7 +76,7 @@ let default_flush ctx =
 
 let create_context params =
 	let ctx = {
-		com = Common.create version (s_version true) params;
+		com = Common.create version params;
 		flush = (fun()->());
 		setup = (fun()->());
 		messages = [];

+ 6 - 3
src/compiler/serverMessage.ml

@@ -105,8 +105,11 @@ let completion str =
 
 let defines com tabs =
 	if config.print_defines then begin
-		let defines = PMap.foldi (fun k v acc -> (k ^ "=" ^ v) :: acc) com.defines.Define.values [] in
-		print_endline ("Defines " ^ (String.concat "," (List.sort compare defines)))
+		let buffer = Buffer.create 64 in
+		Buffer.add_string buffer "Defines ";
+		PMap.iter (Printf.bprintf buffer "%s=%s,") com.defines.values;
+		Buffer.truncate buffer (Buffer.length buffer - 1);
+		print_endline (Buffer.contents buffer)
 	end
 
 let signature com tabs sign =
@@ -187,4 +190,4 @@ let set_by_name name value = match name with
 	| "socketMessage" -> config.print_socket_message <- value;
 	| "uncaughtError" -> config.print_uncaught_error <- value;
 	| "newContext" -> config.print_new_context <- value;
-	| _ -> raise Not_found
+	| _ -> raise Not_found

+ 73 - 33
src/context/common.ml

@@ -370,8 +370,56 @@ let raw_define com v =
 let define_value com k v =
 	Define.define_value com.defines k v
 
-let raw_defined_value com k =
-	Define.raw_defined_value com.defines k
+let convert_define k =
+	String.concat "_" (ExtString.String.nsplit k "-")
+
+let external_defined ctx k =
+	Define.raw_defined ctx.defines (convert_define k)
+
+let external_defined_value ctx k =
+	Define.raw_defined_value ctx.defines (convert_define k)
+
+let reserved_flags = [
+	"true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
+	"swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver"
+	]
+
+let reserved_flag_namespaces = ["target"]
+
+let convert_and_validate k =
+	let converted_flag = convert_define k in
+	let raise_reserved description =
+		raise (Arg.Bad (description ^ " and cannot be defined from the command line"))
+	in
+	if List.mem converted_flag reserved_flags then
+		raise_reserved (Printf.sprintf "`%s` is a reserved compiler flag" k);
+	List.iter (fun ns ->
+		if ExtString.String.starts_with converted_flag (ns ^ ".") then
+			raise_reserved (Printf.sprintf "`%s` uses the reserved compiler flag namespace `%s.*`" k ns)
+	) reserved_flag_namespaces;
+	converted_flag
+
+let external_define_value ctx k v =
+	raw_define_value ctx.defines (convert_and_validate k) v
+
+(* TODO: Temporary function until #8690, remove after *)
+let external_define_value_no_check ctx k v =
+	Define.raw_define_value ctx.defines (convert_define k) v
+
+let external_define ctx k =
+	Define.raw_define ctx.defines (convert_and_validate k)
+
+(* TODO: Temporary function until #8690, remove after *)
+let external_define_no_check ctx k =
+	Define.raw_define ctx.defines (convert_define k)
+
+let defines_for_external ctx =
+	PMap.foldi (fun k v acc ->
+		let added_underscore = PMap.add k v acc in
+		match ExtString.String.nsplit k "_" with
+			| [_] -> added_underscore
+			| split -> PMap.add (String.concat "-" split) v added_underscore;
+	) ctx.defines.values PMap.empty
 
 let get_es_version com =
 	try int_of_string (defined_value com Define.JsEs) with _ -> 0
@@ -640,13 +688,8 @@ let get_config com =
 
 let memory_marker = [|Unix.time()|]
 
-let create version s_version args =
+let create version args =
 	let m = Type.mk_mono() in
-	let defines =
-		PMap.add "true" "1" (
-			PMap.add "source_header" ("Generated by Haxe " ^ s_version) PMap.empty
-		)
-	in
 	{
 		cache = None;
 		stage = CCreated;
@@ -693,7 +736,7 @@ let create version s_version args =
 		load_extern_type = [];
 		defines = {
 			defines_signature = None;
-			values = defines;
+			values = PMap.empty;
 		};
 		get_macros = (fun() -> None);
 		info = (fun _ _ -> die "" __LOC__);
@@ -792,23 +835,23 @@ let init_platform com pf =
 	com.package_rules <- List.fold_left forbid com.package_rules ("jvm" :: (List.map platform_name platforms));
 	com.config <- get_config com;
 	if com.config.pf_static then begin
-		raw_define_value com.defines "target.static" "true";
+		raw_define com "target.static";
 		define com Define.Static;
 	end;
 	if com.config.pf_sys then begin
-		raw_define_value com.defines "target.sys" "true";
+		raw_define com "target.sys";
 		define com Define.Sys
 	end else
 		com.package_rules <- PMap.add "sys" Forbidden com.package_rules;
 	if com.config.pf_uses_utf16 then begin
-		raw_define_value com.defines "target.utf16" "true";
+		raw_define com "target.utf16";
 		define com Define.Utf16;
 	end;
 	if com.config.pf_supports_threads then begin
-		raw_define_value com.defines "target.threaded" "true";
+		raw_define com "target.threaded";
 	end;
 	if com.config.pf_supports_unicode then begin
-		raw_define_value com.defines "target.unicode" "true";
+		raw_define com "target.unicode";
 	end;
 	raw_define_value com.defines "target.name" name;
 	raw_define com name
@@ -1073,29 +1116,26 @@ let add_diagnostics_message com s p kind sev =
 
 open Printer
 
-let dump_context com = s_record_fields "" [
-	"version",string_of_int com.version;
-	"args",s_list ", " (fun s -> s) com.args;
-	"debug",string_of_bool com.debug;
-	"platform",platform_name com.platform;
-	"std_path",s_list ", " (fun s -> s) com.std_path;
-	"class_path",s_list ", " (fun s -> s) com.class_path;
-	"defines",s_pmap (fun s -> s) (fun s -> s) com.defines.values;
-	"defines_signature",s_opt (fun s -> Digest.to_hex s) com.defines.defines_signature;
-]
-
 let dump_path com =
 	Define.defined_value_safe ~default:"dump" com.defines Define.DumpPath
 
 let adapt_defines_to_macro_context defines =
-	let values = ref defines.values in
-	List.iter (fun p -> values := PMap.remove (Globals.platform_name p) !values) Globals.platforms;
-	let to_remove = List.map (fun d -> fst (Define.infos d)) [Define.NoTraces] in
-	let to_remove = to_remove @ List.map (fun (_,d) -> "flash" ^ d) flash_versions in
-	values := PMap.foldi (fun k v acc -> if List.mem k to_remove then acc else PMap.add k v acc) !values PMap.empty;
-	values := PMap.add "macro" "1" !values;
-	values := PMap.add (platform_name !Globals.macro_platform) "1" !values;
-	{values = !values; defines_signature = None }
+	let to_remove = List.map Globals.platform_name Globals.platforms in
+	let to_remove = List.fold_left (fun acc d -> Define.get_define_key d :: acc) to_remove [Define.NoTraces] in
+	let to_remove = List.fold_left (fun acc (_, d) -> ("flash" ^ d) :: acc) to_remove flash_versions in
+	let macro_defines = {
+		values = PMap.foldi (fun k v acc ->
+			if List.mem k to_remove then acc else PMap.add k v acc) defines.values PMap.empty;
+		defines_signature = None
+	} in
+	Define.define macro_defines Define.Macro;
+	Define.raw_define macro_defines (platform_name !Globals.macro_platform);
+	macro_defines
+
+let adapt_defines_to_display_context defines =
+	let defines = adapt_defines_to_macro_context defines in
+	Define.define defines Define.Display;
+	defines
 
 let is_legacy_completion com = match com.json_out with
 	| None -> true

+ 1 - 2
src/context/display/diagnostics.ml

@@ -108,8 +108,7 @@ let collect_diagnostics dctx com =
 	) com.types;
 	let handle_dead_blocks com = match com.cache with
 		| Some cc ->
-			let macro_defines = adapt_defines_to_macro_context com.defines in
-			let display_defines = {macro_defines with values = PMap.add "display" "1" macro_defines.values} in
+			let display_defines = adapt_defines_to_display_context com.defines in
 			let is_true defines e =
 				ParserEntry.is_true (ParserEntry.eval defines e)
 			in

+ 14 - 14
src/core/define.ml

@@ -6,6 +6,9 @@ type define = {
 	mutable defines_signature : string option;
 }
 
+let get_define_key d =
+	fst (infos d)
+
 let get_documentation_list() =
 	let m = ref 0 in
 	let rec loop i =
@@ -24,18 +27,18 @@ let get_documentation_list() =
 			) in
 			let pfs = platform_list_help (List.rev !pfs) in
 			if String.length t > !m then m := String.length t;
-			((String.concat "-" (ExtString.String.nsplit t "_")),params ^ doc ^ pfs) :: (loop (i + 1))
+			((String.concat "-" (ExtString.String.nsplit t "_")), params ^ doc ^ pfs) :: (loop (i + 1))
 		end else
 			[]
 	in
 	let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
 	all,!m
 
-let raw_defined ctx v =
-	PMap.mem v ctx.values
+let raw_defined ctx k =
+	PMap.mem k ctx.values
 
-let defined ctx v =
-	raw_defined ctx (fst (infos v))
+let defined ctx k =
+	raw_defined ctx (get_define_key k)
 
 let raw_defined_value ctx k =
 	PMap.find k ctx.values
@@ -48,20 +51,17 @@ let defined_value_safe ?default ctx v =
 	with Not_found -> match default with Some s -> s | None -> ""
 
 let raw_define_value ctx k v =
-	ctx.values <- PMap.add k v ctx.values;
-	let k = String.concat "_" (ExtString.String.nsplit k "-") in
 	ctx.values <- PMap.add k v ctx.values;
 	ctx.defines_signature <- None
 
-let raw_define ctx v =
-	let k,v = try ExtString.String.split v "=" with _ -> v,"1" in
-	raw_define_value ctx k v
-
 let define_value ctx k v =
-	raw_define ctx (fst (infos k) ^ "=" ^ v)
+	raw_define_value ctx (get_define_key k) v
+
+let raw_define ctx k =
+	raw_define_value ctx k "1"
 
-let define ctx v =
-	raw_define ctx (fst (infos v))
+let define ctx k =
+	raw_define_value ctx (get_define_key k) "1"
 
 let get_signature def =
 	match def.defines_signature with

+ 9 - 9
src/core/globals.ml

@@ -82,14 +82,14 @@ let get_error_pos_ref : ((string -> int -> string) -> pos -> string) ref = ref (
 	Printf.sprintf "%s: characters %d-%d" p.pfile p.pmin p.pmax
 )
 
-let s_version with_build =
+let s_version =
 	let pre = Option.map_default (fun pre -> "-" ^ pre) "" version_pre in
-	let build =
-		match with_build, Version.version_extra with
-			| true, Some (_,build) -> "+" ^ build
-			| _, _ -> ""
-	in
-	Printf.sprintf "%d.%d.%d%s%s" version_major version_minor version_revision pre build
+	Printf.sprintf "%d.%d.%d%s" version_major version_minor version_revision pre
+
+let s_version_full =
+	match Version.version_extra with
+		| Some (_,build) -> s_version ^ "+" ^ build
+		| _ -> s_version
 
 (**
 	Terminates compiler process and prints user-friendly instructions about filing an issue.
@@ -111,7 +111,7 @@ let die ?p msg ml_loc =
 		try snd (ExtString.String.split backtrace "\n")
 		with ExtString.Invalid_string -> backtrace
 	in
-	let ver = s_version true
+	let ver = s_version_full
 	and os_type = if Sys.unix then "unix" else "windows" in
 	Printf.eprintf "%s\nHaxe: %s; OS type: %s;\n%s\n%s" msg ver os_type ml_loc backtrace;
-	assert false
+	assert false

+ 14 - 14
src/generators/gencpp.ml

@@ -6942,9 +6942,9 @@ let write_build_options common_ctx filename defines =
    let writer = cached_source_writer common_ctx filename in
    PMap.iter ( fun name value -> match name with
       | "true" | "sys" | "dce" | "cpp" | "debug" -> ()
-      | _ ->  writer#write (name ^ "="^(escape_command value)^ "\n" ) ) defines;
+      | _ ->  writer#write (Printf.sprintf "%s=%s\n" name (escape_command value))) defines;
    let cmd = Unix.open_process_in "haxelib path hxcpp" in
-   writer#write ("hxcpp=" ^ (Pervasives.input_line cmd));
+   writer#write (Printf.sprintf "hxcpp=%s\n" (Pervasives.input_line cmd));
    Pervasives.ignore (Unix.close_process_in cmd);
    writer#close;;
 
@@ -8553,21 +8553,23 @@ let generate_source ctx =
    | _ -> "output" in
 
    write_build_data common_ctx (common_ctx.file ^ "/Build.xml") !exe_classes !main_deps (!boot_enums@ !boot_classes) !build_xml !extern_src output_name;
-   let cmd_defines = ref "" in
-   PMap.iter ( fun name value -> match name with
-      | "true" | "sys" | "dce" | "cpp" | "debug" -> ()
-      | _ -> cmd_defines := !cmd_defines ^ " -D" ^ name ^ "=\"" ^ (escape_command value) ^ "\"" ) common_ctx.defines.Define.values;
    write_build_options common_ctx (common_ctx.file ^ "/Options.txt") common_ctx.defines.Define.values;
    if ( not (Common.defined common_ctx Define.NoCompilation) ) then begin
       let t = Timer.timer ["generate";"cpp";"native compilation"] in
       let old_dir = Sys.getcwd() in
       Sys.chdir common_ctx.file;
-      let cmd = ref "haxelib run hxcpp Build.xml haxe" in
-      if (common_ctx.debug) then cmd := !cmd ^ " -Ddebug";
-      cmd := !cmd ^ !cmd_defines;
-      cmd := List.fold_left (fun cmd path -> cmd ^ " -I\"" ^ (escape_command path) ^ "\"" ) !cmd common_ctx.class_path;
-      common_ctx.print (!cmd ^ "\n");
-      if common_ctx.run_command !cmd <> 0 then failwith "Build failed";
+      let cmd_buffer = Buffer.create 128 in
+      Buffer.add_string cmd_buffer "haxelib run hxcpp Build.xml haxe";
+      if (common_ctx.debug) then Buffer.add_string cmd_buffer " -Ddebug";
+      PMap.iter ( fun name value -> match name with
+         | "true" | "sys" | "dce" | "cpp" | "debug" -> ();
+         | _ -> Printf.bprintf cmd_buffer " -D%s=\"%s\"" name (escape_command value);
+      ) common_ctx.defines.values;
+      List.iter (fun path -> Printf.bprintf cmd_buffer " -I\"%s\"" (escape_command path)) common_ctx.class_path;
+      Buffer.add_char cmd_buffer '\n';
+      let cmd = Buffer.contents cmd_buffer in
+      common_ctx.print cmd;
+      if common_ctx.run_command cmd <> 0 then failwith "Build failed";
       Sys.chdir old_dir;
       t()
    end
@@ -8583,5 +8585,3 @@ let generate common_ctx =
       generate_source ctx
    end
 ;;
-
-

+ 12 - 6
src/generators/genhl.ml

@@ -2646,8 +2646,8 @@ and eval_expr ctx e =
 		ctx.m.mloop_trys <- oldtrys;
 		alloc_tmp ctx HVoid
 	| TCast ({ eexpr = TCast (v,None) },None) when not (is_number (to_type ctx e.etype)) ->
-        (* coalesce double casts into a single runtime check - temp fix for Map accesses *)
-        eval_expr ctx { e with eexpr = TCast(v,None) }
+		(* coalesce double casts into a single runtime check - temp fix for Map accesses *)
+		eval_expr ctx { e with eexpr = TCast(v,None) }
 	| TCast (v,None) ->
 		let t = to_type ctx e.etype in
 		let rv = eval_expr ctx v in
@@ -3969,7 +3969,7 @@ let create_context com is_macro dump =
 	let ctx = {
 		com = com;
 		is_macro = is_macro;
-		optimize = not (Common.raw_defined com "hl-no-opt");
+		optimize = not (Common.raw_defined com "hl_no_opt");
 		dump_out = if dump then Some (IO.output_channel (open_out_bin "dump/hlopt.txt")) else None;
 		m = method_context 0 HVoid null_capture false;
 		cints = new_lookup();
@@ -4089,7 +4089,7 @@ let prev_sign = ref "" and prev_data = ref ""
 
 let generate com =
 	let dump = Common.defined com Define.Dump in
-	let hl_check = Common.raw_defined com "hl-check" in
+	let hl_check = Common.raw_defined com "hl_check" in
 
 	let sign = make_context_sign com in
 	if sign = !prev_sign && not dump && not hl_check then begin
@@ -4109,7 +4109,7 @@ let generate com =
 		Hlcode.dump (fun s -> output_string ch (s ^ "\n")) code;
 		close_out ch;
 	end;
-	(*if Common.raw_defined com "hl-dump-spec" then begin
+	(*if Common.raw_defined com "hl_dump_spec" then begin
 		let ch = open_out_bin "dump/hlspec.txt" in
 		let write s = output_string ch (s ^ "\n") in
 		Array.iter (fun f ->
@@ -4135,13 +4135,19 @@ let generate com =
 	if file_extension com.file = "c" then begin
 		let gnames = Array.create (Array.length code.globals) "" in
 		PMap.iter (fun n i -> gnames.(i) <- n) ctx.cglobals.map;
+		if not (Common.defined com Define.SourceHeader) then begin
+			let version_major = com.version / 1000 in
+			let version_minor = (com.version mod 1000) / 100 in
+			let version_revision = (com.version mod 100) in
+			Common.define_value com Define.SourceHeader (Printf.sprintf "Generated by HLC %d.%d.%d (HL v%d)" version_major version_minor version_revision code.version);
+		end;
 		Hl2c.write_c com com.file code gnames;
 		let t = Timer.timer ["nativecompile";"hl"] in
 		if not (Common.defined com Define.NoCompilation) && com.run_command ("haxelib run hashlink build " ^ escape_command com.file) <> 0 then failwith "Build failed";
 		t();
 	end else begin
 		let ch = IO.output_string() in
-		write_code ch code (not (Common.raw_defined com "hl-no-debug"));
+		write_code ch code (not (Common.raw_defined com "hl_no_debug"));
 		let str = IO.close_out ch in
 		let ch = open_out_bin com.file in
 		output_string ch str;

+ 1 - 1
src/generators/genjvm.ml

@@ -2926,7 +2926,7 @@ let generate jvm_flag com =
 		default_export_config = {
 			export_debug = true;
 		};
-		detail_times = Common.Define.raw_defined com.defines "jvm-times";
+		detail_times = Common.raw_defined com "jvm_times";
 		timer = new Timer.timer ["generate";"java"];
 		jar_compression_level = compression_level;
 		dynamic_level = dynamic_level;

+ 1 - 1
src/generators/genlua.ml

@@ -1852,7 +1852,7 @@ let alloc_ctx com =
         lua_jit = Common.defined com Define.LuaJit;
         lua_vanilla = Common.defined com Define.LuaVanilla;
         lua_ver = try
-                float_of_string (PMap.find "lua_ver" com.defines.Define.values)
+                float_of_string (Common.defined_value com Define.LuaVer)
             with | Not_found -> 5.2;
     } in
     ctx.type_accessor <- (fun t ->

+ 15 - 10
src/generators/hl2c.ml

@@ -78,6 +78,7 @@ type context = {
 	mutable file_prefix : string;
 	mutable fun_index : int;
 	mutable type_module : (ttype, code_module) PMap.t;
+	gcon : Common.context;
 }
 
 let sprintf = Printf.sprintf
@@ -291,10 +292,13 @@ let unamed_field fid = "f$" ^ string_of_int fid
 let obj_field fid name =
 	if name = "" then unamed_field fid else ident name
 
+let bom = "\xEF\xBB\xBF"
+
 let close_file ctx =
-	let str = Buffer.contents ctx.out in
+	let out = Buffer.contents ctx.out in
 	let defines = List.rev ctx.defines in
-	let str = (match defines with [] -> str | l -> String.concat "\n" l ^ "\n\n" ^ str) in
+	let content = (match defines with [] -> out | l -> String.concat "\n" l ^ "\n\n" ^ out) in
+	let str = if ctx.curfile = "hlc.json" then content else bom ^ content in
 	ctx.defines <- [];
 	ctx.defined_types <- PMap.empty;
 	Hashtbl.clear ctx.hdefines;
@@ -311,8 +315,6 @@ let close_file ctx =
 		close_out ch;
 	end
 
-let bom = "\xEF\xBB\xBF"
-
 let define_global ctx g =
 	let t = ctx.hlcode.globals.(g) in
 	define_type ctx t;
@@ -337,10 +339,8 @@ let short_digest str =
 
 let open_file ctx file =
 	if ctx.curfile <> "" then close_file ctx;
-	let version_major = ctx.version / 1000 in
-	let version_minor = (ctx.version mod 1000) / 100 in
-	let version_revision = (ctx.version mod 100) in
-	if file <> "hlc.json" then define ctx (sprintf "%s// Generated by HLC %d.%d.%d (HL v%d)" bom version_major version_minor version_revision ctx.hlcode.version);
+	if file <> "hlc.json" then
+		Codegen.map_source_header ctx.gcon (fun s -> define ctx (sprintf "// %s" s));
 	ctx.curfile <- file;
 	ctx.fun_index <- 0;
 	ctx.file_prefix <- (short_digest file) ^ "_"
@@ -1430,6 +1430,7 @@ let write_c com file (code:code) gnames =
 		file_prefix = "";
 		fun_index = 0;
 		type_module = PMap.empty;
+		gcon = com;
 	} in
 	let modules = make_modules ctx all_types in
 
@@ -1780,10 +1781,14 @@ let write_c com file (code:code) gnames =
 	block ctx;
 	sline "\"version\" : %d," ctx.version;
 	sline "\"libs\" : [%s]," (String.concat "," (Hashtbl.fold (fun k _ acc -> sprintf "\"%s\"" k :: acc) native_libs []));
-	sline "\"defines\" : {%s\n\t}," (String.concat "," (PMap.foldi (fun k v acc -> sprintf "\n\t\t\"%s\" : \"%s\"" (String.escaped k) (String.escaped v) :: acc) com.Common.defines.Define.values []));
+	let defines = Buffer.create 64 in
+	PMap.iter (fun key value ->
+		Printf.bprintf defines "\n\t\t\"%s\" : \"%s\"," (String.escaped key) (String.escaped value);
+	) com.defines.values;
+	Buffer.truncate defines (Buffer.length defines - 1);
+	sline "\"defines\" : {%s\n\t}," (Buffer.contents defines);
 	sline "\"files\" : [%s\n\t]" (String.concat "," (List.map (sprintf "\n\t\t\"%s\"") ctx.cfiles));
 	unblock ctx;
 	line "}";
 
 	close_file ctx
-

+ 8 - 5
src/macro/macroApi.ml

@@ -1610,18 +1610,21 @@ let macro_api ccom get_api =
 				let v = if v = vnull then "" else ", " ^ (decode_string v) in
 				com.warning ("Should be used in initialization macros only: haxe.macro.Compiler.define(" ^ s ^ v ^ ")") Globals.null_pos;
 			end;
-			let v = if v = vnull then "" else "=" ^ (decode_string v) in
-			Common.raw_define com (s ^ v);
+			(* TODO: use external_define and external_define_value for #8690 *)
+			if v = vnull then
+				Common.external_define_no_check com s
+			else
+				Common.external_define_value_no_check com s (decode_string v);
 			vnull
 		);
 		"defined", vfun1 (fun s ->
-			vbool (Common.raw_defined (ccom()) (decode_string s))
+			vbool (Common.external_defined (ccom()) (decode_string s))
 		);
 		"defined_value", vfun1 (fun s ->
-			try encode_string (Common.raw_defined_value (ccom()) (decode_string s)) with Not_found -> vnull
+			try encode_string (Common.external_defined_value (ccom()) (decode_string s)) with Not_found -> vnull
 		);
 		"get_defines", vfun0 (fun() ->
-			encode_string_map encode_string (ccom()).defines.Define.values
+			encode_string_map encode_string (Common.defines_for_external (ccom()))
 		);
 		"get_type", vfun1 (fun s ->
 			let tname = decode_string s in

+ 7 - 7
src/optimization/analyzerConfig.ml

@@ -65,14 +65,14 @@ let is_ignored meta =
 let get_base_config com =
 	{
 		optimize = Common.defined com Define.AnalyzerOptimize;
-		const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation");
-		copy_propagation = not (Common.raw_defined com "analyzer-no-copy-propagation");
-		local_dce = not (Common.raw_defined com "analyzer-no-local-dce");
-		fusion = not (Common.raw_defined com "analyzer-no-fusion");
-		purity_inference = not (Common.raw_defined com "analyzer-no-purity-inference");
+		const_propagation = not (Common.raw_defined com "analyzer_no_const_propagation");
+		copy_propagation = not (Common.raw_defined com "analyzer_no_copy_propagation");
+		local_dce = not (Common.raw_defined com "analyzer_no_local_dce");
+		fusion = not (Common.raw_defined com "analyzer_no_fusion");
+		purity_inference = not (Common.raw_defined com "analyzer_no_purity_inference");
 		debug_kind = DebugNone;
-		detail_times = Common.raw_defined com "analyzer-times";
-		user_var_fusion = (match com.platform with Flash | Java -> false | _ -> true) && (Common.raw_defined com "analyzer-user-var-fusion" || (not com.debug && not (Common.raw_defined com "analyzer-no-user-var-fusion")));
+		detail_times = Common.raw_defined com "analyzer_times";
+		user_var_fusion = (match com.platform with Flash | Java -> false | _ -> true) && (Common.raw_defined com "analyzer_user_var_fusion" || (not com.debug && not (Common.raw_defined com "analyzer_no_user_var_fusion")));
 		fusion_debug = false;
 	}
 

+ 1 - 0
tests/misc/cpp/projects/.gitignore

@@ -0,0 +1 @@
+out/

+ 28 - 0
tests/misc/cpp/projects/Issue10184/CheckOptionsTxt.hx

@@ -0,0 +1,28 @@
+import sys.FileSystem;
+
+function deleteDirectory(path:String) {
+	if (!FileSystem.isDirectory(path))
+		return FileSystem.deleteFile(path);
+
+	for (item in FileSystem.readDirectory(path))
+		deleteDirectory('$path/$item');
+
+	FileSystem.deleteDirectory(path);
+}
+
+function main() {
+	final definePairs = sys.io.File.getContent("out/Options.txt").split("\n");
+
+	for (definePair in definePairs)
+		for (index in 0...definePair.length) {
+			final char = definePair.charAt(index);
+			if (char == "=") break;
+			if (char == "-"){
+				deleteDirectory("out");
+				Sys.stderr().writeString("Generated `Options.txt` contains raw version of define flag: " + definePair + "\n");
+				Sys.exit(1);
+			}
+		}
+	deleteDirectory("out");
+	Sys.exit(0);
+}

+ 5 - 0
tests/misc/cpp/projects/Issue10184/options-txt.hxml

@@ -0,0 +1,5 @@
+# test Options.txt defines
+--main CheckOptionsTxt
+--cpp out
+-D no-compilation
+--cmd haxe --run CheckOptionsTxt

+ 2 - 0
tests/misc/cpp/run.hxml

@@ -0,0 +1,2 @@
+-cp ../src
+--run Main

+ 1 - 0
tests/misc/hl/projects/.gitignore

@@ -0,0 +1 @@
+out/

+ 28 - 0
tests/misc/hl/projects/Issue10184/CheckJson.hx

@@ -0,0 +1,28 @@
+import sys.FileSystem;
+
+function deleteDirectory(path:String) {
+	if (!FileSystem.isDirectory(path))
+		return FileSystem.deleteFile(path);
+
+	for (item in FileSystem.readDirectory(path))
+		deleteDirectory('$path/$item');
+
+	FileSystem.deleteDirectory(path);
+}
+
+function main() {
+	final json = haxe.Json.parse(sys.io.File.getContent("out/hlc.json"));
+
+	final defines:haxe.DynamicAccess<String> = json.defines;
+
+	final success = Lambda.foreach(defines.keys(), function(define:String) {
+		if (!StringTools.contains(define, "-"))
+			return true;
+
+		Sys.stderr().writeString("Generated `hlc.json` contains raw version of define flag: " + define + "\n");
+		return false;
+	});
+
+	deleteDirectory("out");
+	Sys.exit(if (success) 0 else 1);
+}

+ 5 - 0
tests/misc/hl/projects/Issue10184/hlc-json.hxml

@@ -0,0 +1,5 @@
+# test hlc.json defines
+--main CheckJson
+--hl out/main.c
+-D no-compilation
+--cmd haxe --run CheckJson

+ 56 - 0
tests/misc/hl/projects/Issue10376/CheckSourceHeader.hx

@@ -0,0 +1,56 @@
+import sys.FileSystem;
+
+final FILE = "out/main.c";
+
+function deleteDirectory(path:String) {
+	if (!FileSystem.isDirectory(path))
+		return FileSystem.deleteFile(path);
+
+	for (item in FileSystem.readDirectory(path))
+		deleteDirectory('$path/$item');
+
+	FileSystem.deleteDirectory(path);
+}
+
+function main() {
+	final args = Sys.args();
+
+	final code =
+		try {
+			switch args {
+				case [""]:
+					checkForEmptySourceHeader(FILE);
+				case [expected]:
+					checkSourceHeader(FILE, expected);
+				case _:
+					throw "Incorrect number of arguments to script.";
+			}
+			0;
+		} catch (e){
+			Sys.stderr().writeString(e + "\n");
+			1;
+		}
+
+	deleteDirectory("out");
+	Sys.exit(code);
+}
+
+function checkForEmptySourceHeader(path:String) {
+	final content = getCSourceContent(path);
+
+	if (StringTools.startsWith(content, "// "))
+		throw "File has a source header when none was expected: " + content.split("\n")[0];
+}
+
+function checkSourceHeader(path:String, expected:String) {
+	final content = getCSourceContent(path);
+
+	if (!StringTools.startsWith(content, "// " + expected))
+		throw "File source header does not start with expected: // " + expected +
+			"\nSource header: " + content.split("\n")[0];
+}
+
+function getCSourceContent(path:String) {
+	// have to skip the BOM character
+	return sys.io.File.getContent(path).substr(1);
+}

+ 5 - 0
tests/misc/hl/projects/Issue10376/custom-header.hxml

@@ -0,0 +1,5 @@
+--main CheckSourceHeader
+--hl out/main.c
+-D no-compilation
+-D source-header=custom
+--cmd haxe --run CheckSourceHeader custom

+ 5 - 0
tests/misc/hl/projects/Issue10376/default-header.hxml

@@ -0,0 +1,5 @@
+--main CheckSourceHeader
+--hl out/main.c
+-D no-compilation
+
+--cmd haxe --run CheckSourceHeader "Generated by HLC"

+ 5 - 0
tests/misc/hl/projects/Issue10376/no-header-dash.hxml

@@ -0,0 +1,5 @@
+--main CheckSourceHeader
+--hl out/main.c
+-D no-compilation
+-D source-header=
+--cmd haxe --run CheckSourceHeader ""

+ 2 - 0
tests/misc/hl/run.hxml

@@ -0,0 +1,2 @@
+-cp ../src
+--run Main

+ 1 - 0
tests/misc/js/projects/.gitignore

@@ -0,0 +1 @@
+main.js

+ 35 - 0
tests/misc/js/projects/Issue10184/CheckSourceHeader.hx

@@ -0,0 +1,35 @@
+final FILE = "main.js";
+
+function main() {
+	final args = Sys.args();
+
+	switch args {
+		case [""]:
+			checkForEmptySourceHeader(FILE);
+		case [expected]:
+			checkSourceHeader(FILE, expected);
+		case _:
+			Tools.exitWithError("Incorrect number of arguments to script.");
+	}
+
+	Tools.exit(0);
+}
+
+function checkForEmptySourceHeader(path:String) {
+	final content = getJsSourceContent(path);
+
+	if (StringTools.startsWith(content, "// "))
+		Tools.exitWithError("File has a source header when none was expected: " + content.split("\n")[0]);
+}
+
+function checkSourceHeader(path:String, expected:String) {
+	final content = getJsSourceContent(path);
+
+	if (!StringTools.startsWith(content, "// " + expected))
+		Tools.exitWithError("File source header does not start with expected: // " + expected +
+			"\nSource header: " + content.split("\n")[0]);
+}
+
+function getJsSourceContent(path:String) {
+	return sys.io.File.getContent(path);
+}

+ 3 - 0
tests/misc/js/projects/Issue10184/Main.hx

@@ -0,0 +1,3 @@
+function main() {
+	js.Browser.console.log("Hello, World!");
+}

+ 12 - 0
tests/misc/js/projects/Issue10184/Tools.hx

@@ -0,0 +1,12 @@
+import sys.FileSystem;
+
+function exit(code:Int) {
+	FileSystem.deleteFile("main.js");
+	Sys.exit(code);
+}
+
+function exitWithError(msg:String, code:Int = 1) {
+	FileSystem.deleteFile("main.js");
+	Sys.stderr().writeString(msg + "\n");
+	Sys.exit(code);
+}

+ 4 - 0
tests/misc/js/projects/Issue10184/custom-header-dash.hxml

@@ -0,0 +1,4 @@
+--main Main
+--js main.js
+-D source-header=custom
+--cmd haxe --run CheckSourceHeader custom

+ 4 - 0
tests/misc/js/projects/Issue10184/custom-header-underscore.hxml

@@ -0,0 +1,4 @@
+--main Main
+--js main.js
+-D source_header=custom
+--cmd haxe --run CheckSourceHeader custom

+ 4 - 0
tests/misc/js/projects/Issue10184/default-header.hxml

@@ -0,0 +1,4 @@
+# test source headers
+--main Main
+--js main.js
+--cmd haxe --run CheckSourceHeader "Generated by Haxe"

+ 4 - 0
tests/misc/js/projects/Issue10184/no-header-dash.hxml

@@ -0,0 +1,4 @@
+--main Main
+--js main.js
+-D source-header=
+--cmd haxe --run CheckSourceHeader ""

+ 4 - 0
tests/misc/js/projects/Issue10184/no-header-underscore.hxml

@@ -0,0 +1,4 @@
+--main Main
+--js main.js
+-D source_header=
+--cmd haxe --run CheckSourceHeader ""

+ 2 - 0
tests/misc/js/run.hxml

@@ -0,0 +1,2 @@
+-cp ../src
+--run Main

+ 12 - 0
tests/misc/projects/Issue10184/BuiltIn.hx

@@ -0,0 +1,12 @@
+import haxe.macro.Context;
+
+function main() {
+	// test that built in defines can be accessed by macros
+	// either with a dash or underscore
+
+	if (!Context.defined("haxe-ver"))
+		throw "`haxe-ver` flag is missing";
+
+	if (!Context.defined("haxe_ver"))
+		throw "`haxe_ver` flag is missing";
+}

+ 4 - 0
tests/misc/projects/Issue10184/Deprecated.hx

@@ -0,0 +1,4 @@
+function main() {
+	// usage of a deprecated function to generate warning
+	Std.is("string", String);
+}

+ 27 - 0
tests/misc/projects/Issue10184/Flags.hx

@@ -0,0 +1,27 @@
+import haxe.macro.Context;
+
+function main() {
+	// set with dash
+	if (!Context.defined("f-dash"))
+		throw "`f-dash` flag is missing";
+	if (!Context.defined("f_dash"))
+		throw "`f_dash` flag is missing";
+
+	// set with underscore
+	if (!Context.defined("f-underscore"))
+		throw "`f-underscore` flag is missing";
+	if (!Context.defined("f_underscore"))
+		throw "`f_underscore` flag is missing";
+
+	// value set with dash
+	if (Context.definedValue("v-dash") != "value")
+		throw "`v-dash` flag has incorrect value: " + Context.definedValue("v-dash");
+	if (Context.definedValue("v_dash") != "value")
+		throw "`v_dash` flag has incorrect value" + Context.definedValue("v_dash");
+
+	// value set with underscore
+	if (Context.definedValue("v-underscore") != "value")
+		throw "`v-underscore` flag has incorrect value" + Context.definedValue("v-underscore");
+	if (Context.definedValue("v_underscore") != "value")
+		throw "`v_underscore` flag has incorrect value" + Context.definedValue("v-underscore");
+}

+ 27 - 0
tests/misc/projects/Issue10184/GetDefines.hx

@@ -0,0 +1,27 @@
+function main() {
+	final defines = haxe.macro.Context.getDefines();
+
+	// -D f-dash
+	if (!defines.exists("f-dash"))
+		throw "`f-dash` flag is missing";
+	if (!defines.exists("f_dash"))
+		throw "`f_dash` flag is missing";
+
+	// -D f_underscore
+	if (!defines.exists("f-underscore"))
+		throw "`f-underscore` flag is missing";
+	if (!defines.exists("f_underscore"))
+		throw "`f_underscore` flag is missing";
+
+	// -D v-dash=value
+	if (defines["v-dash"] != "value")
+		throw "`v-dash` flag value is incorrect: " + defines["v-dash"];
+	if (defines["v_dash"] != "value")
+		throw "`v_dash` flag value is incorrect: " + defines["v_dash"];
+
+	// -D v_underscore=value
+	if (defines["v-underscore"] != "value")
+		throw "`v-underscore` flag value is incorrect: " + defines["v-underscore"];
+	if (defines["v_underscore"] != "value")
+		throw "`v_underscore` flag value is incorrect: " + defines["v_underscore"];
+}

+ 25 - 0
tests/misc/projects/Issue10184/IfBlocks.hx

@@ -0,0 +1,25 @@
+function throwInactive(flag:String) {
+	throw '`$flag` block is not active';
+}
+
+function throwInactiveValue(flag:String, expected:String, value:String) {
+	throw '`$flag` block is not active, as flag has value `$value` instead of `$expected`';
+}
+
+function main() {
+	#if !f_dash
+	throwInactive("f_dash");
+	#end
+
+	#if !f_underscore
+	throwInactive("f_underscore");
+	#end
+
+	#if (v_dash!="value")
+	throwInactiveValue("v_dash", "value", haxe.macro.Context.definedValue("v_dash"));
+	#end
+
+	#if (v_underscore!="value")
+	throwInactiveValue("v_underscore", "value", haxe.macro.Context.definedValue("v_underscore"));
+	#end
+}

+ 25 - 0
tests/misc/projects/Issue10184/Repeated.hx

@@ -0,0 +1,25 @@
+import haxe.macro.Context;
+
+function main() {
+	// dash set then underscore
+	if (Context.definedValue("value-a") != "new value")
+		throw '`value-a` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-a")}`';
+	if (Context.definedValue("value_a") != "new value")
+		throw '`value_a` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_a")}`';
+
+	if (Context.definedValue("value-b") != "new value")
+		throw '`value-b` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-b")}`';
+	if (Context.definedValue("value_b") != "new value")
+		throw '`value_b` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_b")}`';
+
+	// underscore set then dash
+	if (Context.definedValue("value-c") != "new value")
+		throw '`value-c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-c")}`';
+	if (Context.definedValue("value_c") != "new value")
+		throw '`value_c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_c")}`';
+
+	if (Context.definedValue("value-d") != "new value")
+		throw '`value-c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-d")}`';
+	if (Context.definedValue("value_d") != "new value")
+		throw '`value_c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_d")}`';
+}

+ 1 - 0
tests/misc/projects/Issue10184/builtin.hxml

@@ -0,0 +1 @@
+--run BuiltIn

+ 2 - 0
tests/misc/projects/Issue10184/check-warning.hxml

@@ -0,0 +1,2 @@
+# deprecation warnings should show
+--run Deprecated

+ 1 - 0
tests/misc/projects/Issue10184/check-warning.hxml.stderr

@@ -0,0 +1 @@
+Deprecated.hx:3: characters 2-8 : Warning : Std.is is deprecated. Use Std.isOfType instead.

+ 7 - 0
tests/misc/projects/Issue10184/cli.hxml

@@ -0,0 +1,7 @@
+# test defines set via -D
+-D f-dash
+-D f_underscore
+-D v-dash=value
+-D v_underscore=value
+
+--run Flags

+ 18 - 0
tests/misc/projects/Issue10184/get-defines.hxml

@@ -0,0 +1,18 @@
+# test that Context.getDefines works correctly
+
+--main GetDefines
+--interp
+
+--each
+
+-D f-dash
+-D f_underscore
+-D v-dash=value
+-D v_underscore=value
+
+--next
+
+--macro define("f-dash")
+--macro define("f_underscore")
+--macro define("v-dash", "value")
+--macro define("v_underscore", "value")

+ 18 - 0
tests/misc/projects/Issue10184/if-blocks.hxml

@@ -0,0 +1,18 @@
+# test using if blocks
+
+--main IfBlocks
+--interp
+
+--each
+
+-D f-dash
+-D f_underscore
+-D v-dash=value
+-D v_underscore=value
+
+--next
+
+--macro define("f-dash")
+--macro define("f_underscore")
+--macro define("v-dash", "value")
+--macro define("v_underscore", "value")

+ 7 - 0
tests/misc/projects/Issue10184/macro.hxml

@@ -0,0 +1,7 @@
+# test defines set via define macro function
+--macro define("f-dash")
+--macro define("f_underscore")
+--macro define("v-dash", "value")
+--macro define("v_underscore", "value")
+
+--run Flags

+ 3 - 0
tests/misc/projects/Issue10184/no-warning-underscore.hxml

@@ -0,0 +1,3 @@
+# should have no deprecation warnings
+-D no_deprecation_warnings
+--run Deprecated

+ 0 - 0
tests/misc/projects/Issue10184/no-warning-underscore.hxml.stderr


+ 3 - 0
tests/misc/projects/Issue10184/no-warning.hxml

@@ -0,0 +1,3 @@
+# should have no deprecation warnings
+-D no-deprecation-warnings
+--run Deprecated

+ 0 - 0
tests/misc/projects/Issue10184/no-warning.hxml.stderr


+ 18 - 0
tests/misc/projects/Issue10184/repeated.hxml

@@ -0,0 +1,18 @@
+# test defining the same define twice sets it to the most recent value,
+# regardless of if it uses a dash or underscore.
+
+# dash first, then underscore
+-D value-a=old value
+-D value_a=new value
+
+--macro define("value-b", "old value")
+--macro define("value_b", "new value")
+
+# underscore first, then dash
+-D value_c=old value
+-D value-c=new value
+
+--macro define("value_d", "old value")
+--macro define("value-d", "new value")
+
+--run Repeated

+ 9 - 0
tests/runci/System.hx

@@ -138,6 +138,15 @@ class System {
 		}
 	}
 
+	static public function haxelibDev(library:String, path:String):Void {
+		try {
+			getHaxelibPath(library);
+			infoMsg('$library has already been installed.');
+		} catch (e:Dynamic) {
+			runCommand("haxelib", ["dev", library, path]);
+		}
+	}
+
 	static public function haxelibRun(args:Array<String>, useRetry:Bool = false):Void {
 		runCommand("haxelib", ["run"].concat(args), useRetry);
 	}

+ 4 - 0
tests/runci/targets/Cpp.hx

@@ -6,6 +6,7 @@ import runci.Config.*;
 
 class Cpp {
 	static public var gotCppDependencies = false;
+	static final miscCppDir = miscDir + 'cpp/';
 
 	static public function getCppDependencies() {
 		if (gotCppDependencies) return;
@@ -71,5 +72,8 @@ class Cpp {
 		// 	runCommand("haxe", ["build.hxml"]);
 		// 	runCpp("bin/TestObjc-debug");
 		// }
+
+		changeDirectory(miscCppDir);
+		runCommand("haxe", ["run.hxml"]);
 	}
 }

+ 75 - 67
tests/runci/targets/Hl.hx

@@ -6,78 +6,86 @@ import runci.System.*;
 import runci.Config.*;
 
 class Hl {
-    static var hlSrc = switch [ci, systemName] {
-      case [GithubActions, "Windows"]: "C:\\hashlink";
-      case _: Path.join([Sys.getEnv("HOME"), "hashlink"]);
-    };
-    static var hlBuild = switch [ci, systemName] {
-      case [GithubActions, "Windows"]: "C:\\hashlink_build";
-      case _: Path.join([Sys.getEnv("HOME"), "hashlink_build"]);
-    };
-    static var hlBinDir = switch [ci, systemName] {
-      case [GithubActions, "Windows"]: "C:\\hashlink_build\\bin";
-      case _: Path.join([Sys.getEnv("HOME"), "hashlink_build", "bin"]);
-    };
-    static var hlBinary = switch [ci, systemName] {
-      case [GithubActions, "Windows"]: "C:\\hashlink_build\\bin\\hl.exe";
-      case _: Path.join([Sys.getEnv("HOME"), "hashlink_build", "bin", "hl"]);
-    };
+	static var hlSrc = switch [ci, systemName] {
+	  case [GithubActions, "Windows"]: "C:\\hashlink";
+	  case _: Path.join([Sys.getEnv("HOME"), "hashlink"]);
+	};
+	static var hlBuild = switch [ci, systemName] {
+	  case [GithubActions, "Windows"]: "C:\\hashlink_build";
+	  case _: Path.join([Sys.getEnv("HOME"), "hashlink_build"]);
+	};
+	static var hlBinDir = switch [ci, systemName] {
+	  case [GithubActions, "Windows"]: "C:\\hashlink_build\\bin";
+	  case _: Path.join([Sys.getEnv("HOME"), "hashlink_build", "bin"]);
+	};
+	static var hlBinary = switch [ci, systemName] {
+	  case [GithubActions, "Windows"]: "C:\\hashlink_build\\bin\\hl.exe";
+	  case _: Path.join([Sys.getEnv("HOME"), "hashlink_build", "bin", "hl"]);
+	};
 
-    static public function getHlDependencies() {
-        if (commandSucceed("hl", ["--version"])) {
-            infoMsg('hl has already been installed.');
-            return;
-        }
-        if (!FileSystem.exists(hlSrc)) {
-            runCommand("git", ["clone", "https://github.com/HaxeFoundation/hashlink.git", hlSrc]);
-        } else infoMsg("Reusing hashlink repository");
+	static final miscHlDir = miscDir + 'hl/';
 
-        switch (systemName) {
-            case "Linux":
-                Linux.requireAptPackages(["libpng-dev", "libjpeg-turbo8-dev", "libturbojpeg", "zlib1g-dev", "libvorbis-dev"]);
-            case "Mac":
-                runCommand("brew", ["update", '--preinstall'], true);
-                runCommand("brew", ["bundle", '--file=${hlSrc}/Brewfile'], true);
-            case "Windows":
-                //pass
-        }
+	static public function getHlDependencies() {
+		if (commandSucceed("hl", ["--version"])) {
+			infoMsg('hl has already been installed.');
+			return;
+		}
+		if (!FileSystem.exists(hlSrc))
+			runCommand("git", ["clone", "https://github.com/HaxeFoundation/hashlink.git", hlSrc]);
+		else
+			infoMsg("Reusing hashlink repository");
 
-        FileSystem.createDirectory(hlBuild);
-        var generator = systemName == "Windows" ? ["-DCMAKE_SYSTEM_VERSION=10.0.19041.0"] : ["-GNinja"];
-        runCommand("cmake", generator.concat([
-            "-DBUILD_TESTING=OFF",
-            "-DWITH_BULLET=OFF",
-            "-DWITH_DIRECTX=OFF",
-            "-DWITH_FMT=ON",
-            "-DWITH_OPENAL=OFF",
-            "-DWITH_SDL=OFF",
-            "-DWITH_SQLITE=OFF",
-            "-DWITH_SSL=OFF",
-            "-DWITH_UI=OFF",
-            "-DWITH_UV=OFF",
-            "-DWITH_VIDEO=OFF",
-            "-B" + hlBuild,
-            "-H" + hlSrc
-        ]));
-        runCommand("cmake", [
-            "--build", hlBuild
-        ]);
+		switch (systemName) {
+			case "Linux":
+				Linux.requireAptPackages(["libpng-dev", "libjpeg-turbo8-dev", "libturbojpeg", "zlib1g-dev", "libvorbis-dev"]);
+			case "Mac":
+				runCommand("brew", ["update", '--preinstall'], true);
+				runCommand("brew", ["bundle", '--file=${hlSrc}/Brewfile'], true);
+			case "Windows":
+				//pass
+		}
 
-        runCommand(hlBinary, ["--version"]);
-        addToPATH(hlBinDir);
-    }
+		FileSystem.createDirectory(hlBuild);
+		var generator = systemName == "Windows" ? ["-DCMAKE_SYSTEM_VERSION=10.0.19041.0"] : ["-GNinja"];
+		runCommand("cmake", generator.concat([
+			"-DBUILD_TESTING=OFF",
+			"-DWITH_BULLET=OFF",
+			"-DWITH_DIRECTX=OFF",
+			"-DWITH_FMT=ON",
+			"-DWITH_OPENAL=OFF",
+			"-DWITH_SDL=OFF",
+			"-DWITH_SQLITE=OFF",
+			"-DWITH_SSL=OFF",
+			"-DWITH_UI=OFF",
+			"-DWITH_UV=OFF",
+			"-DWITH_VIDEO=OFF",
+			"-B" + hlBuild,
+			"-H" + hlSrc
+		]));
+		runCommand("cmake", [
+			"--build", hlBuild
+		]);
 
-    static public function run(args:Array<String>) {
-        getHlDependencies();
-        runCommand("haxe", ["compile-hl.hxml"].concat(args));
-        runCommand(hlBinary, ["bin/unit.hl"]);
+		runCommand(hlBinary, ["--version"]);
+		addToPATH(hlBinDir);
 
-        changeDirectory(threadsDir);
-        runCommand("haxe", ["build.hxml", "-hl", "export/threads.hl"]);
-        runCommand("hl", ["export/threads.hl"]);
+		haxelibDev("hashlink", '$hlSrc/other/haxelib/');
+	}
 
-        changeDirectory(sysDir);
-        runCommand("haxe", ["compile-hl.hxml"].concat(args));
-        runCommand(hlBinary, ["bin/hl/sys.hl"]);
-    }
+	static public function run(args:Array<String>) {
+		getHlDependencies();
+		runCommand("haxe", ["compile-hl.hxml"].concat(args));
+		runCommand(hlBinary, ["bin/unit.hl"]);
+
+		changeDirectory(threadsDir);
+		runCommand("haxe", ["build.hxml", "-hl", "export/threads.hl"]);
+		runCommand(hlBinary, ["export/threads.hl"]);
+
+		changeDirectory(sysDir);
+		runCommand("haxe", ["compile-hl.hxml"].concat(args));
+		runCommand(hlBinary, ["bin/hl/sys.hl"]);
+
+		changeDirectory(miscHlDir);
+		runCommand("haxe", ["run.hxml"]);
+	}
 }

+ 6 - 1
tests/runci/targets/Js.hx

@@ -9,6 +9,8 @@ import sys.io.Process;
 using StringTools;
 
 class Js {
+	static final miscJsDir = miscDir + 'js/';
+
 	static public function getJSDependencies() {
 		switch [ci, systemName] {
 			case [_, "Linux"]:
@@ -107,5 +109,8 @@ class Js {
 		changeDirectory(serverDir);
 		runCommand("haxe", ["build.hxml"]);
 		runCommand("node", ["test.js"]);
+
+		changeDirectory(miscJsDir);
+		runCommand("haxe", ["run.hxml"]);
 	}
-}
+}