Browse Source

Improve `odin help -foo` usage

gingerBill 9 months ago
parent
commit
3229f4668d
1 changed files with 380 additions and 351 deletions
  1. 380 351
      src/main.cpp

+ 380 - 351
src/main.cpp

@@ -2175,11 +2175,12 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
 }
 }
 
 
 
 
-gb_internal void print_show_help(String const arg0, String const &command) {
+gb_internal void print_show_help(String const arg0, String const &command, String optional_flag = {}) {
 	print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
 	print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
 	print_usage_line(0, "Usage:");
 	print_usage_line(0, "Usage:");
 	print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
 	print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
 	print_usage_line(0, "");
 	print_usage_line(0, "");
+	defer (print_usage_line(0, ""));
 
 
 	if (command == "build") {
 	if (command == "build") {
 		print_usage_line(1, "build   Compiles directory of .odin files as an executable.");
 		print_usage_line(1, "build   Compiles directory of .odin files as an executable.");
@@ -2225,532 +2226,560 @@ gb_internal void print_show_help(String const arg0, String const &command) {
 	bool check_only      = command == "check" || strip_semicolon;
 	bool check_only      = command == "check" || strip_semicolon;
 	bool check           = run_or_build || check_only;
 	bool check           = run_or_build || check_only;
 
 
+	if (command == "help") {
+		doc             = true;
+		build           = true;
+		run_or_build    = true;
+		test_only       = true;
+		strip_semicolon = true;
+		check_only      = true;
+		check           = true;
+	}
+
 	print_usage_line(0, "");
 	print_usage_line(0, "");
 	print_usage_line(1, "Flags");
 	print_usage_line(1, "Flags");
 	print_usage_line(0, "");
 	print_usage_line(0, "");
 
 
 
 
-	if (doc) {
-		print_usage_line(1, "-all-packages");
-		print_usage_line(2, "Generates documentation for all packages used in the current project.");
+
+	auto const print_flag = [&optional_flag](char const *flag) -> bool {
+		if (optional_flag.len != 0) {
+			String f = make_string_c(flag);
+			isize i = string_index_byte(f, ':');
+			if (i >= 0) {
+				f.len = i;
+			}
+			if (optional_flag != f) {
+				return false;
+			}
+		}
 		print_usage_line(0, "");
 		print_usage_line(0, "");
+		print_usage_line(1, flag);
+		return true;
+	};
+
+
+	if (doc) {
+		if (print_flag("-all-packages")) {
+			print_usage_line(2, "Generates documentation for all packages used in the current project.");
+		}
 	}
 	}
 	if (test_only) {
 	if (test_only) {
-		print_usage_line(1, "-all-packages");
-		print_usage_line(2, "Tests all packages imported into the given initial package.");
-		print_usage_line(0, "");
+		if (print_flag("-all-packages")) {
+			print_usage_line(2, "Tests all packages imported into the given initial package.");
+		}
 	}
 	}
 
 
 	if (build) {
 	if (build) {
-		print_usage_line(1, "-build-mode:<mode>");
-		print_usage_line(2, "Sets the build mode.");
-		print_usage_line(2, "Available options:");
-		print_usage_line(3, "-build-mode:exe         Builds as an executable.");
-		print_usage_line(3, "-build-mode:test        Builds as an executable that executes tests.");
-		print_usage_line(3, "-build-mode:dll         Builds as a dynamically linked library.");
-		print_usage_line(3, "-build-mode:shared      Builds as a dynamically linked library.");
-		print_usage_line(3, "-build-mode:dynamic     Builds as a dynamically linked library.");
-		print_usage_line(3, "-build-mode:lib         Builds as a statically linked library.");
-		print_usage_line(3, "-build-mode:static      Builds as a statically linked library.");
-		print_usage_line(3, "-build-mode:obj         Builds as an object file.");
-		print_usage_line(3, "-build-mode:object      Builds as an object file.");
-		print_usage_line(3, "-build-mode:assembly    Builds as an assembly file.");
-		print_usage_line(3, "-build-mode:assembler   Builds as an assembly file.");
-		print_usage_line(3, "-build-mode:asm         Builds as an assembly file.");
-		print_usage_line(3, "-build-mode:llvm-ir     Builds as an LLVM IR file.");
-		print_usage_line(3, "-build-mode:llvm        Builds as an LLVM IR file.");
-		print_usage_line(0, "");
+		if (print_flag("-build-mode:<mode>")) {
+			print_usage_line(2, "Sets the build mode.");
+			print_usage_line(2, "Available options:");
+			print_usage_line(3, "-build-mode:exe         Builds as an executable.");
+			print_usage_line(3, "-build-mode:test        Builds as an executable that executes tests.");
+			print_usage_line(3, "-build-mode:dll         Builds as a dynamically linked library.");
+			print_usage_line(3, "-build-mode:shared      Builds as a dynamically linked library.");
+			print_usage_line(3, "-build-mode:dynamic     Builds as a dynamically linked library.");
+			print_usage_line(3, "-build-mode:lib         Builds as a statically linked library.");
+			print_usage_line(3, "-build-mode:static      Builds as a statically linked library.");
+			print_usage_line(3, "-build-mode:obj         Builds as an object file.");
+			print_usage_line(3, "-build-mode:object      Builds as an object file.");
+			print_usage_line(3, "-build-mode:assembly    Builds as an assembly file.");
+			print_usage_line(3, "-build-mode:assembler   Builds as an assembly file.");
+			print_usage_line(3, "-build-mode:asm         Builds as an assembly file.");
+			print_usage_line(3, "-build-mode:llvm-ir     Builds as an LLVM IR file.");
+			print_usage_line(3, "-build-mode:llvm        Builds as an LLVM IR file.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-collection:<name>=<filepath>");
-		print_usage_line(2, "Defines a library collection used for imports.");
-		print_usage_line(2, "Example: -collection:shared=dir/to/shared");
-		print_usage_line(2, "Usage in Code:");
-		print_usage_line(3, "import \"shared:foo\"");
-		print_usage_line(0, "");
+		if (print_flag("-collection:<name>=<filepath>")) {
+			print_usage_line(2, "Defines a library collection used for imports.");
+			print_usage_line(2, "Example: -collection:shared=dir/to/shared");
+			print_usage_line(2, "Usage in Code:");
+			print_usage_line(3, "import \"shared:foo\"");
+		}
 
 
-		print_usage_line(1, "-custom-attribute:<string>");
-		print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown.");
-		print_usage_line(2, "This can be used with metaprogramming tools.");
-		print_usage_line(2, "Examples:");
-		print_usage_line(3, "-custom-attribute:my_tag");
-		print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
-		print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
-		print_usage_line(0, "");
+		if (print_flag("-custom-attribute:<string>")) {
+			print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown.");
+			print_usage_line(2, "This can be used with metaprogramming tools.");
+			print_usage_line(2, "Examples:");
+			print_usage_line(3, "-custom-attribute:my_tag");
+			print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
+			print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-debug");
-		print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
-		print_usage_line(0, "");
+		if (print_flag("-debug")) {
+			print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-default-to-nil-allocator");
-		print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
-		print_usage_line(0, "");
+		if (print_flag("-default-to-nil-allocator")) {
+			print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
+		}
 
 
-		print_usage_line(1, "-define:<name>=<value>");
-		print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
-		print_usage_line(2, "Example: -define:SPAM=123");
-		print_usage_line(2, "Usage in code:");
-		print_usage_line(3, "#config(SPAM, default_value)");
-		print_usage_line(0, "");
+		if (print_flag("-define:<name>=<value>")) {
+			print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
+			print_usage_line(2, "Example: -define:SPAM=123");
+			print_usage_line(2, "Usage in code:");
+			print_usage_line(3, "#config(SPAM, default_value)");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-disable-assert");
-		print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
-		print_usage_line(0, "");
+		if (print_flag("-disable-assert")) {
+			print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
+		}
 
 
-		print_usage_line(1, "-disable-red-zone");
-		print_usage_line(2, "Disables red zone on a supported freestanding target.");
-		print_usage_line(0, "");
+		if (print_flag("-disable-red-zone")) {
+			print_usage_line(2, "Disables red zone on a supported freestanding target.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-disallow-do");
-		print_usage_line(2, "Disallows the 'do' keyword in the project.");
-		print_usage_line(0, "");
+		if (print_flag("-disallow-do")) {
+			print_usage_line(2, "Disallows the 'do' keyword in the project.");
+		}
 	}
 	}
 
 
 	if (doc) {
 	if (doc) {
-		print_usage_line(1, "-doc-format");
-		print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
-		print_usage_line(0, "");
+		if (print_flag("-doc-format")) {
+			print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-dynamic-map-calls");
-		print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
-		print_usage_line(0, "");
+		if (print_flag("-dynamic-map-calls")) {
+			print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-error-pos-style:<string>");
-		print_usage_line(2, "Available options:");
-		print_usage_line(3, "-error-pos-style:unix      file/path:45:3:");
-		print_usage_line(3, "-error-pos-style:odin      file/path(45:3)");
-		print_usage_line(3, "-error-pos-style:default   (Defaults to 'odin'.)");
-		print_usage_line(0, "");
+		if (print_flag("-error-pos-style:<string>")) {
+			print_usage_line(2, "Available options:");
+			print_usage_line(3, "-error-pos-style:unix      file/path:45:3:");
+			print_usage_line(3, "-error-pos-style:odin      file/path(45:3)");
+			print_usage_line(3, "-error-pos-style:default   (Defaults to 'odin'.)");
+		}
 
 
-		print_usage_line(1, "-export-defineables:<filename>");
-		print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path.");
-		print_usage_line(2, "Example: -export-defineables:defineables.csv");
-		print_usage_line(0, "");
+		if (print_flag("-export-defineables:<filename>")) {
+			print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path.");
+			print_usage_line(2, "Example: -export-defineables:defineables.csv");
+		}
 
 
-		print_usage_line(1, "-export-dependencies:<format>");
-		print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`.");
-		print_usage_line(2, "Available options:");
-		print_usage_line(3, "-export-dependencies:make   Exports in Makefile format");
-		print_usage_line(3, "-export-dependencies:json   Exports in JSON format");
-		print_usage_line(0, "");
+		if (print_flag("-export-dependencies:<format>")) {
+			print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`.");
+			print_usage_line(2, "Available options:");
+			print_usage_line(3, "-export-dependencies:make   Exports in Makefile format");
+			print_usage_line(3, "-export-dependencies:json   Exports in JSON format");
+		}
 
 
-		print_usage_line(1, "-export-dependencies-file:<filename>");
-		print_usage_line(2, "Specifies the filename for `-export-dependencies`.");
-		print_usage_line(2, "Example: -export-dependencies-file:dependencies.d");
-		print_usage_line(0, "");
+		if (print_flag("-export-dependencies-file:<filename>")) {
+			print_usage_line(2, "Specifies the filename for `-export-dependencies`.");
+			print_usage_line(2, "Example: -export-dependencies-file:dependencies.d");
+		}
 
 
-		print_usage_line(1, "-export-timings:<format>");
-		print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
-		print_usage_line(2, "Available options:");
-		print_usage_line(3, "-export-timings:json   Exports compile time stats to JSON.");
-		print_usage_line(3, "-export-timings:csv    Exports compile time stats to CSV.");
-		print_usage_line(0, "");
+		if (print_flag("-export-timings:<format>")) {
+			print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
+			print_usage_line(2, "Available options:");
+			print_usage_line(3, "-export-timings:json   Exports compile time stats to JSON.");
+			print_usage_line(3, "-export-timings:csv    Exports compile time stats to CSV.");
+		}
 
 
-		print_usage_line(1, "-export-timings-file:<filename>");
-		print_usage_line(2, "Specifies the filename for `-export-timings`.");
-		print_usage_line(2, "Example: -export-timings-file:timings.json");
-		print_usage_line(0, "");
+		if (print_flag("-export-timings-file:<filename>")) {
+			print_usage_line(2, "Specifies the filename for `-export-timings`.");
+			print_usage_line(2, "Example: -export-timings-file:timings.json");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-extra-assembler-flags:<string>");
+		if (print_flag("-extra-assembler-flags:<string>")) {
 		print_usage_line(2, "Adds extra assembler specific flags in a string.");
 		print_usage_line(2, "Adds extra assembler specific flags in a string.");
-		print_usage_line(0, "");
+		}
 
 
-		print_usage_line(1, "-extra-linker-flags:<string>");
+		if (print_flag("-extra-linker-flags:<string>")) {
 		print_usage_line(2, "Adds extra linker specific flags in a string.");
 		print_usage_line(2, "Adds extra linker specific flags in a string.");
-		print_usage_line(0, "");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-file");
-		print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command));
-		print_usage_line(2, "This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.");
-		print_usage_line(0, "");
+		if (print_flag("-file")) {
+			print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command));
+			print_usage_line(2, "This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.");
+		}
 
 
-		print_usage_line(1, "-foreign-error-procedures");
-		print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
-		print_usage_line(0, "");
+		if (print_flag("-foreign-error-procedures")) {
+			print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
+		}
 
 
-		print_usage_line(1, "-ignore-unknown-attributes");
-		print_usage_line(2, "Ignores unknown attributes.");
-		print_usage_line(2, "This can be used with metaprogramming tools.");
-		print_usage_line(0, "");
+		if (print_flag("-ignore-unknown-attributes")) {
+			print_usage_line(2, "Ignores unknown attributes.");
+			print_usage_line(2, "This can be used with metaprogramming tools.");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
 	#if defined(GB_SYSTEM_WINDOWS)
 	#if defined(GB_SYSTEM_WINDOWS)
-		print_usage_line(1, "-ignore-vs-search");
-		print_usage_line(2, "[Windows only]");
-		print_usage_line(2, "Ignores the Visual Studio search for library paths.");
-		print_usage_line(0, "");
+		if (print_flag("-ignore-vs-search")) {
+			print_usage_line(2, "[Windows only]");
+			print_usage_line(2, "Ignores the Visual Studio search for library paths.");
+		}
 	#endif
 	#endif
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-ignore-warnings");
-		print_usage_line(2, "Ignores warning messages.");
-		print_usage_line(0, "");
+		if (print_flag("-ignore-warnings")) {
+			print_usage_line(2, "Ignores warning messages.");
+		}
 
 
-		print_usage_line(1, "-json-errors");
-		print_usage_line(2, "Prints the error messages as json to stderr.");
-		print_usage_line(0, "");
+		if (print_flag("-json-errors")) {
+			print_usage_line(2, "Prints the error messages as json to stderr.");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-keep-temp-files");
-		print_usage_line(2, "Keeps the temporary files generated during compilation.");
-		print_usage_line(0, "");
+		if (print_flag("-keep-temp-files")) {
+			print_usage_line(2, "Keeps the temporary files generated during compilation.");
+		}
 	} else if (strip_semicolon) {
 	} else if (strip_semicolon) {
-		print_usage_line(1, "-keep-temp-files");
-		print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
-		print_usage_line(0, "");
+		if (print_flag("-keep-temp-files")) {
+			print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-linker:<string>");
-		print_usage_line(2, "Specify the linker to use.");
-		print_usage_line(2, "Choices:");
-		for (i32 i = 0; i < Linker_COUNT; i++) {
-			print_usage_line(3, "%.*s", LIT(linker_choices[i]));
+		if (print_flag("-linker:<string>")) {
+			print_usage_line(2, "Specify the linker to use.");
+			print_usage_line(2, "Choices:");
+			for (i32 i = 0; i < Linker_COUNT; i++) {
+				print_usage_line(3, "%.*s", LIT(linker_choices[i]));
+			}
 		}
 		}
-		print_usage_line(0, "");
 
 
-		print_usage_line(1, "-lld");
-		print_usage_line(2, "Uses the LLD linker rather than the default.");
-		print_usage_line(0, "");
+		if (print_flag("-lld")) {
+			print_usage_line(2, "Uses the LLD linker rather than the default.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-max-error-count:<integer>");
-		print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
-		print_usage_line(2, "Must be an integer >0.");
-		print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
-		print_usage_line(0, "");
+		if (print_flag("-max-error-count:<integer>")) {
+			print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
+			print_usage_line(2, "Must be an integer >0.");
+			print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-microarch:<string>");
-		print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
-		print_usage_line(2, "Examples:");
-		print_usage_line(3, "-microarch:sandybridge");
-		print_usage_line(3, "-microarch:native");
-		print_usage_line(3, "-microarch:\"?\" for a list");
-		print_usage_line(0, "");
+		if (print_flag("-microarch:<string>")) {
+			print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
+			print_usage_line(2, "Examples:");
+			print_usage_line(3, "-microarch:sandybridge");
+			print_usage_line(3, "-microarch:native");
+			print_usage_line(3, "-microarch:\"?\" for a list");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-min-link-libs");
-		print_usage_line(2, "If set, the number of linked libraries will be minimized to prevent duplications.");
-		print_usage_line(2, "This is useful for so called \"dumb\" linkers compared to \"smart\" linkers.");
-		print_usage_line(0, "");
+		if (print_flag("-min-link-libs")) {
+			print_usage_line(2, "If set, the number of linked libraries will be minimized to prevent duplications.");
+			print_usage_line(2, "This is useful for so called \"dumb\" linkers compared to \"smart\" linkers.");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-minimum-os-version:<string>");
-		print_usage_line(2, "Sets the minimum OS version targeted by the application.");
-		print_usage_line(2, "Default: -minimum-os-version:11.0.0");
-		print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
-		print_usage_line(0, "");
+		if (print_flag("-minimum-os-version:<string>")) {
+			print_usage_line(2, "Sets the minimum OS version targeted by the application.");
+			print_usage_line(2, "Default: -minimum-os-version:11.0.0");
+			print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
+		}
 
 
-		print_usage_line(1, "-no-bounds-check");
-		print_usage_line(2, "Disables bounds checking program wide.");
-		print_usage_line(0, "");
+		if (print_flag("-no-bounds-check")) {
+			print_usage_line(2, "Disables bounds checking program wide.");
+		}
 
 
-		print_usage_line(1, "-no-crt");
-		print_usage_line(2, "Disables automatic linking with the C Run Time.");
-		print_usage_line(0, "");
+		if (print_flag("-no-crt")) {
+			print_usage_line(2, "Disables automatic linking with the C Run Time.");
+		}
 	}
 	}
 
 
 	if (check && command != "test") {
 	if (check && command != "test") {
-		print_usage_line(1, "-no-entry-point");
-		print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
-		print_usage_line(0, "");
+		if (print_flag("-no-entry-point")) {
+			print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-no-rpath");
-		print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory.");
-		print_usage_line(0, "");
+		if (print_flag("-no-rpath")) {
+			print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory.");
+		}
 
 
-		print_usage_line(1, "-no-thread-local");
-		print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
-		print_usage_line(0, "");
+		if (print_flag("-no-thread-local")) {
+			print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
+		}
 
 
-		print_usage_line(1, "-no-threaded-checker");
-		print_usage_line(2, "Disables multithreading in the semantic checker stage.");
-		print_usage_line(0, "");
+		if (print_flag("-no-threaded-checker")) {
+			print_usage_line(2, "Disables multithreading in the semantic checker stage.");
+		}
 
 
-		print_usage_line(1, "-no-type-assert");
-		print_usage_line(2, "Disables type assertion checking program wide.");
-		print_usage_line(0, "");
+		if (print_flag("-no-type-assert")) {
+			print_usage_line(2, "Disables type assertion checking program wide.");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-o:<string>");
-		print_usage_line(2, "Sets the optimization mode for compilation.");
-		print_usage_line(2, "Available options:");
-		print_usage_line(3, "-o:none");
-		print_usage_line(3, "-o:minimal");
-		print_usage_line(3, "-o:size");
-		print_usage_line(3, "-o:speed");
-		if (LB_USE_NEW_PASS_SYSTEM) {
-			print_usage_line(3, "-o:aggressive (use this with caution)");
-		}
-		print_usage_line(2, "The default is -o:minimal.");
-		print_usage_line(0, "");
+		if (print_flag("-o:<string>")) {
+			print_usage_line(2, "Sets the optimization mode for compilation.");
+			print_usage_line(2, "Available options:");
+			print_usage_line(3, "-o:none");
+			print_usage_line(3, "-o:minimal");
+			print_usage_line(3, "-o:size");
+			print_usage_line(3, "-o:speed");
+			if (LB_USE_NEW_PASS_SYSTEM) {
+				print_usage_line(3, "-o:aggressive (use this with caution)");
+			}
+			print_usage_line(2, "The default is -o:minimal.");
+		}
 
 
 
 
-		print_usage_line(1, "-obfuscate-source-code-locations");
-		print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
-		print_usage_line(0, "");
+		if (print_flag("-obfuscate-source-code-locations")) {
+			print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
+		}
 
 
 
 
-		print_usage_line(1, "-out:<filepath>");
-		print_usage_line(2, "Sets the file name of the outputted executable.");
-		print_usage_line(2, "Example: -out:foo.exe");
-		print_usage_line(0, "");
+		if (print_flag("-out:<filepath>")) {
+			print_usage_line(2, "Sets the file name of the outputted executable.");
+			print_usage_line(2, "Example: -out:foo.exe");
+		}
 	}
 	}
 
 
 	if (doc) {
 	if (doc) {
-		print_usage_line(1, "-out:<filepath>");
-		print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
-		print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'.");
-		print_usage_line(2, "Example: -out:foo");
-		print_usage_line(0, "");
+		if (print_flag("-out:<filepath>")) {
+			print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
+			print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'.");
+			print_usage_line(2, "Example: -out:foo");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
 	#if defined(GB_SYSTEM_WINDOWS)
 	#if defined(GB_SYSTEM_WINDOWS)
-		print_usage_line(1, "-pdb-name:<filepath>");
-		print_usage_line(2, "[Windows only]");
-		print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
-		print_usage_line(2, "Example: -pdb-name:different.pdb");
-		print_usage_line(0, "");
+		if (print_flag("-pdb-name:<filepath>")) {
+			print_usage_line(2, "[Windows only]");
+			print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
+			print_usage_line(2, "Example: -pdb-name:different.pdb");
+		}
 	#endif
 	#endif
 	}
 	}
 
 
 	if (build) {
 	if (build) {
-		print_usage_line(1, "-print-linker-flags");
-		print_usage_line(2, "Prints the all of the flags/arguments that will be passed to the linker.");
-		print_usage_line(0, "");
+		if (print_flag("-print-linker-flags")) {
+			print_usage_line(2, "Prints the all of the flags/arguments that will be passed to the linker.");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-radlink");
-		print_usage_line(2, "Uses the RAD linker rather than the default.");
-		print_usage_line(0, "");
+		if (print_flag("-radlink")) {
+			print_usage_line(2, "Uses the RAD linker rather than the default.");
+		}
 
 
-		print_usage_line(1, "-reloc-mode:<string>");
-		print_usage_line(2, "Specifies the reloc mode.");
-		print_usage_line(2, "Available options:");
-		print_usage_line(3, "-reloc-mode:default");
-		print_usage_line(3, "-reloc-mode:static");
-		print_usage_line(3, "-reloc-mode:pic");
-		print_usage_line(3, "-reloc-mode:dynamic-no-pic");
-		print_usage_line(0, "");
+		if (print_flag("-reloc-mode:<string>")) {
+			print_usage_line(2, "Specifies the reloc mode.");
+			print_usage_line(2, "Available options:");
+			print_usage_line(3, "-reloc-mode:default");
+			print_usage_line(3, "-reloc-mode:static");
+			print_usage_line(3, "-reloc-mode:pic");
+			print_usage_line(3, "-reloc-mode:dynamic-no-pic");
+		}
 
 
 	#if defined(GB_SYSTEM_WINDOWS)
 	#if defined(GB_SYSTEM_WINDOWS)
-		print_usage_line(1, "-resource:<filepath>");
-		print_usage_line(2, "[Windows only]");
-		print_usage_line(2, "Defines the resource file for the executable.");
-		print_usage_line(2, "Example: -resource:path/to/file.rc");
-		print_usage_line(2, "or:      -resource:path/to/file.res for a precompiled one.");
-		print_usage_line(0, "");
+		if (print_flag("-resource:<filepath>")) {
+			print_usage_line(2, "[Windows only]");
+			print_usage_line(2, "Defines the resource file for the executable.");
+			print_usage_line(2, "Example: -resource:path/to/file.rc");
+			print_usage_line(2, "or:      -resource:path/to/file.res for a precompiled one.");
+		}
 	#endif
 	#endif
 
 
-		print_usage_line(1, "-sanitize:<string>");
-		print_usage_line(2, "Enables sanitization analysis.");
-		print_usage_line(2, "Available options:");
-		print_usage_line(3, "-sanitize:address");
-		print_usage_line(3, "-sanitize:memory");
-		print_usage_line(3, "-sanitize:thread");
-		print_usage_line(2, "NOTE: This flag can be used multiple times.");
-		print_usage_line(0, "");
+		if (print_flag("-sanitize:<string>")) {
+			print_usage_line(2, "Enables sanitization analysis.");
+			print_usage_line(2, "Available options:");
+			print_usage_line(3, "-sanitize:address");
+			print_usage_line(3, "-sanitize:memory");
+			print_usage_line(3, "-sanitize:thread");
+			print_usage_line(2, "NOTE: This flag can be used multiple times.");
+		}
 	}
 	}
 
 
 	if (doc) {
 	if (doc) {
-		print_usage_line(1, "-short");
-		print_usage_line(2, "Shows shortened documentation for the packages.");
-		print_usage_line(0, "");
+		if (print_flag("-short")) {
+			print_usage_line(2, "Shows shortened documentation for the packages.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-show-defineables");
-		print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project.");
-		print_usage_line(0, "");
+		if (print_flag("-show-defineables")) {
+			print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project.");
+		}
 
 
-		print_usage_line(1, "-show-system-calls");
-		print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
-		print_usage_line(0, "");
+		if (print_flag("-show-system-calls")) {
+			print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
+		}
 
 
-		print_usage_line(1, "-show-timings");
-		print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
-		print_usage_line(0, "");
+		if (print_flag("-show-timings")) {
+			print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
+		}
 
 
-		print_usage_line(1, "-show-more-timings");
-		print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
-		print_usage_line(0, "");
+		if (print_flag("-show-more-timings")) {
+			print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
+		}
 	}
 	}
 
 
 	if (check_only) {
 	if (check_only) {
-		print_usage_line(1, "-show-unused");
-		print_usage_line(2, "Shows unused package declarations within the current project.");
-		print_usage_line(0, "");
-		print_usage_line(1, "-show-unused-with-location");
-		print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
-		print_usage_line(0, "");
+		if (print_flag("-show-unused")) {
+			print_usage_line(2, "Shows unused package declarations within the current project.");
+		}
+		if (print_flag("-show-unused-with-location")) {
+			print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-strict-style");
-		print_usage_line(2, "This enforces parts of same style as the Odin compiler, prefer '-vet-style -vet-semicolon' if you do not want to match it exactly.");
-		print_usage_line(2, "");
-		print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
-		print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
-		print_usage_line(2, "Errs on deprecated syntax.");
-		print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
-		print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
-		print_usage_line(0, "");
+		if (print_flag("-strict-style")) {
+			print_usage_line(2, "This enforces parts of same style as the Odin compiler, prefer '-vet-style -vet-semicolon' if you do not want to match it exactly.");
+			print_usage_line(2, "");
+			print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
+			print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
+			print_usage_line(2, "Errs on deprecated syntax.");
+			print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
+			print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-strict-target-features");
-		print_usage_line(2, "Makes @(enable_target_features=\"...\") behave the same way as @(require_target_features=\"...\").");
-		print_usage_line(2, "This enforces that all generated code uses features supported by the combination of -target, -microarch, and -target-features.");
-		print_usage_line(0, "");
+		if (print_flag("-strict-target-features")) {
+			print_usage_line(2, "Makes @(enable_target_features=\"...\") behave the same way as @(require_target_features=\"...\").");
+			print_usage_line(2, "This enforces that all generated code uses features supported by the combination of -target, -microarch, and -target-features.");
+		}
 
 
 	#if defined(GB_SYSTEM_WINDOWS)
 	#if defined(GB_SYSTEM_WINDOWS)
-		print_usage_line(1, "-subsystem:<option>");
-		print_usage_line(2, "[Windows only]");
-		print_usage_line(2, "Defines the subsystem for the application.");
-		print_usage_line(2, "Available options:");
+		if (print_flag("-subsystem:<option>")) {
+			print_usage_line(2, "[Windows only]");
+			print_usage_line(2, "Defines the subsystem for the application.");
+			print_usage_line(2, "Available options:");
 		print_usage_line(3, "-subsystem:console");
 		print_usage_line(3, "-subsystem:console");
 		print_usage_line(3, "-subsystem:windows");
 		print_usage_line(3, "-subsystem:windows");
-		print_usage_line(0, "");
+		}
 	#endif
 	#endif
 
 
-		print_usage_line(1, "-target-features:<string>");
-		print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch.");
-		print_usage_line(2, "Examples:");
-		print_usage_line(3, "-target-features:atomics");
-		print_usage_line(3, "-target-features:\"sse2,aes\"");
-		print_usage_line(3, "-target-features:\"?\" for a list");
-		print_usage_line(0, "");
+		if (print_flag("-target-features:<string>")) {
+			print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch.");
+			print_usage_line(2, "Examples:");
+			print_usage_line(3, "-target-features:atomics");
+			print_usage_line(3, "-target-features:\"sse2,aes\"");
+			print_usage_line(3, "-target-features:\"?\" for a list");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-target:<string>");
-		print_usage_line(2, "Sets the target for the executable to be built in.");
-		print_usage_line(0, "");
+		if (print_flag("-target:<string>")) {
+			print_usage_line(2, "Sets the target for the executable to be built in.");
+		}
 
 
-		print_usage_line(1, "-terse-errors");
-		print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
-		print_usage_line(0, "");
+		if (print_flag("-terse-errors")) {
+			print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
+		}
 
 
-		print_usage_line(1, "-thread-count:<integer>");
-		print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
-		print_usage_line(2, "Example: -thread-count:2");
-		print_usage_line(0, "");
+		if (print_flag("-thread-count:<integer>")) {
+			print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
+			print_usage_line(2, "Example: -thread-count:2");
+		}
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {
-		print_usage_line(1, "-use-separate-modules");
-		print_usage_line(2, "The backend generates multiple build units which are then linked together.");
-		print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
-		print_usage_line(2, "This is the default behaviour on Windows for '-o:none' and '-o:minimal' builds.");
-		print_usage_line(0, "");
+		if (print_flag("-use-separate-modules")) {
+			print_usage_line(2, "The backend generates multiple build units which are then linked together.");
+			print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
+			print_usage_line(2, "This is the default behaviour on Windows for '-o:none' and '-o:minimal' builds.");
+		}
 
 
 	}
 	}
 
 
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-vet");
-		print_usage_line(2, "Does extra checks on the code.");
-		print_usage_line(2, "Extra checks include:");
-		print_usage_line(3, "-vet-unused");
-		print_usage_line(3, "-vet-unused-variables");
-		print_usage_line(3, "-vet-unused-imports");
-		print_usage_line(3, "-vet-shadowing");
-		print_usage_line(3, "-vet-using-stmt");
-		print_usage_line(0, "");
+		if (print_flag("-vet")) {
+			print_usage_line(2, "Does extra checks on the code.");
+			print_usage_line(2, "Extra checks include:");
+			print_usage_line(3, "-vet-unused");
+			print_usage_line(3, "-vet-unused-variables");
+			print_usage_line(3, "-vet-unused-imports");
+			print_usage_line(3, "-vet-shadowing");
+			print_usage_line(3, "-vet-using-stmt");
+		}
 
 
-		print_usage_line(1, "-vet-cast");
-		print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-cast")) {
+			print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`.");
+		}
 
 
-		print_usage_line(1, "-vet-packages:<comma-separated-strings>");
-		print_usage_line(2, "Sets which packages by name will be vetted.");
-		print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-packages:<comma-separated-strings>")) {
+			print_usage_line(2, "Sets which packages by name will be vetted.");
+			print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set.");
+		}
 
 
-		print_usage_line(1, "-vet-semicolon");
-		print_usage_line(2, "Errs on unneeded semicolons.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-semicolon")) {
+			print_usage_line(2, "Errs on unneeded semicolons.");
+		}
 
 
 
 
-		print_usage_line(1, "-vet-shadowing");
-		print_usage_line(2, "Checks for variable shadowing within procedures.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-shadowing")) {
+			print_usage_line(2, "Checks for variable shadowing within procedures.");
+		}
 
 
-		print_usage_line(1, "-vet-style");
-		print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
-		print_usage_line(2, "Errs on deprecated syntax.");
-		print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
-		print_usage_line(0, "");
+		if (print_flag("-vet-style")) {
+			print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
+			print_usage_line(2, "Errs on deprecated syntax.");
+			print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
+		}
 
 
 
 
-		print_usage_line(1, "-vet-tabs");
-		print_usage_line(2, "Errs when the use of tabs has not been used for indentation.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-tabs")) {
+			print_usage_line(2, "Errs when the use of tabs has not been used for indentation.");
+		}
 
 
 
 
-		print_usage_line(1, "-vet-unused");
-		print_usage_line(2, "Checks for unused declarations (variables and imports).");
-		print_usage_line(0, "");
+		if (print_flag("-vet-unused")) {
+			print_usage_line(2, "Checks for unused declarations (variables and imports).");
+		}
 
 
-		print_usage_line(1, "-vet-unused-imports");
-		print_usage_line(2, "Checks for unused import declarations.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-unused-imports")) {
+			print_usage_line(2, "Checks for unused import declarations.");
+		}
 
 
-		print_usage_line(1, "-vet-unused-procedures");
-		print_usage_line(2, "Checks for unused procedures.");
-		print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-unused-procedures")) {
+			print_usage_line(2, "Checks for unused procedures.");
+			print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags.");
+		}
 
 
-		print_usage_line(1, "-vet-unused-variables");
-		print_usage_line(2, "Checks for unused variable declarations.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-unused-variables")) {
+			print_usage_line(2, "Checks for unused variable declarations.");
+		}
 
 
 
 
-		print_usage_line(1, "-vet-using-param");
-		print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
-		print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-using-param")) {
+			print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
+			print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
+		}
 
 
-		print_usage_line(1, "-vet-using-stmt");
-		print_usage_line(2, "Checks for the use of 'using' as a statement.");
-		print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
-		print_usage_line(0, "");
+		if (print_flag("-vet-using-stmt")) {
+			print_usage_line(2, "Checks for the use of 'using' as a statement.");
+			print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
+		}
 	}
 	}
 
 
 	if (check) {
 	if (check) {
-		print_usage_line(1, "-warnings-as-errors");
-		print_usage_line(2, "Treats warning messages as error messages.");
-		print_usage_line(0, "");
+		if (print_flag("-warnings-as-errors")) {
+			print_usage_line(2, "Treats warning messages as error messages.");
+		}
 	}
 	}
 }
 }
 
 
@@ -3239,7 +3268,7 @@ int main(int arg_count, char const **arg_ptr) {
 			usage(args[0]);
 			usage(args[0]);
 			return 1;
 			return 1;
 		} else {
 		} else {
-			print_show_help(args[0], args[2]);
+			print_show_help(args[0], args[1], args[2]);
 			return 0;
 			return 0;
 		}
 		}
 	} else if (command == "root") {
 	} else if (command == "root") {