Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove cpp-optparse from the rest of our project #4072

Closed

Conversation

Sonicadvance1
Copy link
Member

Based on #4070

First step: add an argument parser that handles /only/ what FEX needs for its tools.
Second step: Move everything over to that.
Third step: Delete cpp-optparse.

FEXLoader using the generated loader still.

@Sonicadvance1 Sonicadvance1 force-pushed the remove_cpp_optparse_therest branch 4 times, most recently from 6d8a867 to 488a472 Compare September 16, 2024 04:49
Doesn't remove it from the full project since three tools still use it.

FEXLoader argument loader is fairly special since we have a generator
tied to it. This generator lets us have some niceties where everything
ends up being a string literal without any sort of dynamic requirements.

cpp-optparse has a systemic issue where it makes deep copies of
/everything/ all the time. This means it has huge runtime costs and huge
stack usage (4992 bytes). The new implementation uses 608 bytes of stack
space (plus 640 if it actually parses a strenum).

When profiling cpp-optparse with FEXLoader's argument it takes ~2,039,307 ns to parse the arguments!
As a direct comparison this new implementation takes ~56,885 ns.
Both sides not getting passed /any/ arguments, really shows how spicy
this library is.
Fits our needs and /only/ our needs.
Copy link
Member

@neobrain neobrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding more comments here, most of which I think already apply to 4070.

}
};

bool NeedsArg(const OptionDetails* Details) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global functions used only locally should be static.

};

void ParseArgument(std::string_view Arg, std::string_view SecondArg, const OptionDetails* Details) {
std::invoke(Parser[FEXCore::ToUnderlying(Details->ParseType)], this, Arg, SecondArg, Details);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just call the member pointer directly?

Suggested change
std::invoke(Parser[FEXCore::ToUnderlying(Details->ParseType)], this, Arg, SecondArg, Details);
(this->*Parser[FEXCore::ToUnderlying(Details->ParseType)])(Arg, SecondArg, Details);

_exit(1);
}

class ArgParser final {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs some documentation to explain why it exists and what's the difference from the confusingly similarly named ArgLoader.

}

void MicroArgParser::PrintHelp(char** argv, std::span<ParseMember> ParseList) {
fextl::fmt::print("Usage: {} [options]\n", argv[0]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to handle line wrapping, e.g. FEXpidof now prints very long lines

  -q                       Do not display matched PIDs to stdout. Simply exit with status of true or false if a PID was found
  -z                       Try to detect zombie processes - Usually zombie processes are skipped

instead of

  -q                    Do not display matched PIDs to stdout. Simply exit
                        with status of true or false if a PID was found
  -z                    Try to detect zombie processes - Usually zombie
                        processes are skipped

(Also note the extra spaces on the left. Not sure where those are coming from. Both versions seem overly padding-happy, not sure if there's some sort of standard that says there should be at least N characters of whitespace here. Conversely, FEXRootFSFetcher --help doesn't vertically align the option descriptions for the lengthy --force-ui=[default,tty,zenity], though that seems to be the only setting with that issue.)

{FEX::MicroArgParser::ParseMember::Type::Bool, {}, "--current-rootfs", "Print the directory that contains the FEX rootfs. Mounted in the case of squashfs", "0"},
{FEX::MicroArgParser::ParseMember::Type::Bool, {}, "--tso-emulation-info", "Print how FEX is emulating the x86-TSO memory model.", "0"},
// Defaults
{FEX::MicroArgParser::ParseMember::Type::Bool, "-v", "--version", "show program's verison number and exit", "0"},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verison is spelt wrong here and in a couple of other places.

{FEX::MicroArgParser::ParseMember::Type::StringArray, "-o", {}, "Ignore processes with matched pids", {}},

// Defaults
{FEX::MicroArgParser::ParseMember::Type::Bool, "-v", "--version", "show program's verison number and exit", "0"},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

show should be spelt Show for consistency with other descriptions.

}
}

ExitWithError(fextl::fmt::format("'{}' Not in list of choices '{}'\n", Arg, Member->Choices));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ExitWithError(fextl::fmt::format("'{}' Not in list of choices '{}'\n", Arg, Member->Choices));
ExitWithError(fextl::fmt::format("Invalid argument '{}'. Valid choices are '{}'\n", Arg, Member->Choices));

or better yet:

Suggested change
ExitWithError(fextl::fmt::format("'{}' Not in list of choices '{}'\n", Arg, Member->Choices));
ExitWithError(fextl::fmt::format("Invalid argument '{}' for --TODO. Valid choices are '{}'\n", Arg, Member->Choices));

ExitWithError(fextl::fmt::format("'{}' Not in list of choices '{}'\n", Arg, Member->Choices));
}

void MicroArgParser::Parse(int argc, char** argv) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invoking multiple short options at once seems broken now:

./Bin/FEXpidof -sq
Error: Unknown argument: -sq

}

private:
fextl::vector<std::string_view> _Value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identifiers starting with an underscore look out of place here.

Also, this can be an std::optional<vector<string_view>> instead to avoid having two variables to manage the same state.

{FEX::MicroArgParser::ParseMember::Type::StringArray, "-o", {}, "Ignore processes with matched pids", {}},

// Defaults
{FEX::MicroArgParser::ParseMember::Type::Bool, "-v", "--version", "show program's verison number and exit", "0"},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The apostrophe s isn't needed here (and actually sounds slightly wrong to me due to lack of preceding article):
program's version -> program version

Comment on lines +144 to +148
if (Arg == "--") {
// Special case break. Remaining arguments get passed to guest.
++ArgParsed;
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For tools other than FEXLoader, are we checking and failing if "--" is used by accident (e.g. by slipping in a space)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants