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

Introduce a new tool: ninja -t compdb-targets #2497

Merged
merged 2 commits into from
Nov 12, 2024

Conversation

JamesWidman
Copy link
Contributor

@JamesWidman JamesWidman commented Sep 20, 2024

This fixes #1544.

Here we use the same commit as in #2319, plus one more commit so that the option is spelled --targets.

Many thanks to @lk-chen for the original work in #1546, and to @csmoe for carrying it forward in #2319!


update 2024-10-04:

The most recent push implements the new tool, ninja -t compdb-targets.

todo:

  • add unit tests
  • update manual to mention the new tool (next to the entry for compdb)
  • review coding-style guidelines & fix any violations

@jhasse jhasse added this to the 1.13.0 milestone Sep 20, 2024
@mcprat
Copy link
Contributor

mcprat commented Sep 20, 2024

squash to 1 commit to get rid of the merge commits and combine the original with your rename, add yourself to the tags at the end of the original commit

it would be nice if we can find a way to get rid of stringstream (for lower binary size?)

I still think the remaining arguments should not require a long option at all or otherwise -- if its not possible to avoid long opts. Isn't it safe to assume everything after -t compdb will be a target? if not then whatever else can be after that should be the type of argument with it's own unique long option

@JamesWidman
Copy link
Contributor Author

@mcprat Agreed on squashing/rebasing, and i will look into the stringstream thing.

as for the command-line syntax: i wrote about this in #2319 (though i forgot to tag you there; sorry!), but it would be good to have it inline here too:

You wrote:

Would it be better to shift out arguments so that no flag is required for the targets list?

so instead of

-t compdb --target foo,bar

you would have

-t compdb foo bar

Prior to the commits in this PR, the output of ninja -t compdb -h is:

usage: ninja -t compdb [options] [rules]

options:
  -x     expand @rspfile style response file invocations

so ninja -t compdb foo bar already means "emit every compile command that uses rule foo or rule bar", and we probably don't want to break that.

or if a flag is really necessary to break out of flag-only parsing, use syntax like in git

-t compdb -- foo bar

so they can be space separated instead of comma separated

but that means the syntax would become:

ninja -t compdb [options] [rules] -- [targets]

...which means that users will need to remember that -t compdb foo -- bar means "rule foo and target bar", as opposed to "target foo and rule bar".

How would you feel about a short option instead of a long option? (meaning: -t TARGETS instead of --targets TARGETS)

Also: if we go with an option, are you ok with making the target names comma-delimited? (i think the main reason to use commas is so that we stick to the format expected by getopt()/getopt_long(), where the set of all targets would be returned via optarg.)

Fwiw, in bash 4.2 and later, you can join an array with commas using the printf builtin like so:

echo $(printf "%s," ${targets[*]})

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 20, 2024

@mcprat oh wait, when you wrote:

if not then whatever else can be after that should be the type of argument with it's own unique long option

are you proposing something like:

ninja -t compdb --target t1 --target t2 --target tN rule1 rule2 ruleN

...or maybe:

ninja -t compdb -t t1 -t t2 -t tN rule1 rule2 ruleN

...?

@JamesWidman
Copy link
Contributor Author

@mcprat btw, i assumed that we don't want to break the pre-existing [rules] interface because i assume that someone, somewhere, depends on that in a script or something, but personally i can't see much of a use for it if we can specify targets.

Do we want to make the breaking change of removing the [rules] syntax (or replacing it with an option that allows something like -r rule1 -r rule2 [...])?

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 21, 2024

@mcprat i just thought of another way we could do this:

up until now, i've been stuck thinking that --targets is an option that must have an argument, but we could alternatively tell getopt()/getopt_long() that --targets (or -t) doesn't take an argument. Then we could change the form of the command, in a non-breaking way, to this:

ninja -t compdb [options] [items]

...where the [items] are interpreted as rules unless one of the [options] is -t/--targets, in which case the [items] are interpreted as targets. So in effect, we would have two alternative forms:

ninja -t compdb --targets [other_options]  target1 target2 [...] targetN
ninja -t compdb [other_options] rule1 rule2 [...] ruleN

...which, although it would add an option, it would at least mean that targets are separated by spaces as you requested.

(In this case, i would have a weak preference for the long form (--targets rather than -t), just because it follows another -t option that means something completely different (the "tool" option). It's not a deal-breaker for me if we go with the single-letter spelling, though.)

@mcprat
Copy link
Contributor

mcprat commented Sep 21, 2024

@JamesWidman I'm aware of your replies in the other PR. I was reiterating, but also clarifying that neither a short or long option would be the ideal (closer to POSIX-like behavior), because it seems like what I said previously was interpreted as only preferring short option or -- over long option.

All of this definitely clears things up, it is more complicated than I thought...

Here's an idea... what's stopping the parsing stage from checking both the list of targets and list of rules for each argument? Without having looked into it, there's probably different functions used depending on whether the argument is a rule or a target. Maybe each argument can be passed to both, a failure can be caught, and if only one has a problem that's expected, but both failing (or even if neither are failing) would indicate an actual problem.

@mcprat
Copy link
Contributor

mcprat commented Sep 21, 2024

or rather, since this is a printing-only tool, it can just ignore any errors...

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 21, 2024

I was reiterating, but also clarifying that neither a short or long option would be the ideal (closer to POSIX-like behavior),

@mcprat I am trying to understand:

  1. why is it desirable to avoid the introduction of a new option (like --targets or -t)?
  2. how does POSIX enter into it?

(I do plan on getting to your other points, but first, i really want to understand the answers to these questions.)

@mcprat
Copy link
Contributor

mcprat commented Sep 21, 2024

  1. why is it desirable to avoid the introduction of a new option (like --targets or -t)?

it's not really an option but rather more input, as it doesn't adjust existing outputs but rather just adds to it. consider the way the manual is written right now

given a list of rules, each of which is expected to be a C family language compiler rule whose first input is the name of the source file, prints on standard output a compilation database...

instead of now having to describe that there's different ways that one adds a rule to the list vs how one adds a target to the list, it would be nice if the manual can just say:

given a list of rules and/or targets...

  1. how does POSIX enter into it?

I consider the design of make as a general guide. even though most consider it a product of GNU, it is in fact defined by POSIX as well, and they try to mostly stay conformant. even though Ninja may not explicitly claim to be POSIX conforming we ought to follow it when possible.

POSIX has a section called "Utility Syntax Guidelines" that's used to form the standard syntax for make. there is mention there about the usage of -- and how the order of arguments can affect the output, and that there should be only one argument to each option. I don't see much about how the definition of an option differs from the definition of a normal operand however...

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 23, 2024

@mcprat First: i think my confusion might be shrinking; thank you!

i didn't quite understand what you meant here:

  1. why is it desirable to avoid the introduction of a new option (like --targets or -t)?

it's not really an option but rather more input, as it doesn't adjust existing outputs but rather just adds to it.

...but i think i understand this part:

consider the way the manual is written right now

given a list of rules, each of which is expected to be a C family language compiler rule whose first input is the name of the source file, prints on standard output a compilation database...

instead of now having to describe that there's different ways that one adds a rule to the list vs how one adds a target to the list, it would be nice if the manual can just say:

given a list of rules and/or targets...

so... if i understand you correctly, it sounds like you're saying something like:
"The user interface for producing a compilation database for a given set of ninja rules ought to be consistent with the user interface for producing a compilation database for a given set of ninja targets."

Is that about right?

(If so: i see that the consistency that you're asking for could make it easier for a user to transition from using rules to using targets or vice-versa, and that would end the confusion that prompted my first question above.)

Second:

POSIX has a section called "Utility Syntax Guidelines"

i started reading Issue 8 (IEEE Std 1003.1™-2024 Edition) as well as a draft from 1991, and i just realized that you might be targeting some other version in between (one that is old enough that it is implemented by all the platforms the ninja project wants to run on, but new enough that it specifies all the OS features that the project wants ninja to depend on).

i checked CONTRIBUTING.md, the wiki, and the ninja manual, but i didn't see any mention of POSIX.

so: what version of POSIX should we be reading/targeting?

Also: would it make sense to add a mention of that version of POSIX to the wiki and/or CONTRIBUTING.md to mention that version? (I can see how POSIX compliance is another way to support consistency of user interfaces (in this case, consistency of syntax between ninja and POSIX utilities), and also helps us avoid breaking the rule-of-least-surprise. Thank you for the pointer!)

src/ninja.cc Outdated
@@ -945,6 +948,32 @@ void printCompdb(const char* const directory, const Edge* const edge,
printf("\"\n }");
}

struct DependentEdgeCollector {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please move this class definition to src/graph.h and provide proper documentation + unit-tests for it. See InputsCollector there for inspiration.

I also recommend to make depend_edges a member of the class, and add a method like TakeResult() to move the final result out of the instance one all root targets have been visited.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please move this class definition to src/graph.h

is it ok if i move it to a new header file instead? It's very compdb-specific, and only used by ninja.cc and graph_test.cc, so it would be nice if changing it didn't cause a lot of unrelated source files to be recompiled

src/ninja.cc Outdated
std::vector<Edge*> user_interested_edges;
DependentEdgeCollector deps_edge_collector;

while (std::getline(iss, target, ',')) {
Copy link
Contributor

@digit-google digit-google Sep 23, 2024

Choose a reason for hiding this comment

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

Use SplitStringPiece() from string_piece_util.h instead for simpler and smaller generated code. Use std:: prefixes for all standard types, as we are trying to move away from using namespace std. E.g.:

for (StringPiece target_piece : SplitStringPiece(optarg, ',')) {
  std::string err;
  std::string target = target_piece.AsString();
  Node* node = CollectTarget(target.c_str(), &err);
  ...
}

src/ninja.cc Outdated
return 1;
}
if (!deps_edge_collector.CollectFrom(node, &user_interested_edges)) {
return 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Silent failure without a message explaning what's going on is a bad user experience :-/
Besides, it looks like your CollectFrom() implementation cannot return false, so get rid of the return value and the condition check here.

src/ninja.cc Outdated
@@ -945,6 +948,32 @@ void printCompdb(const char* const directory, const Edge* const edge,
printf("\"\n }");
}

struct DependentEdgeCollector {
bool CollectFrom(Node* node, std::vector<Edge*>* depend_edges) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: use const Node* for the first argument :-)

@digit-google
Copy link
Contributor

We do really not care about following POSIX guidelines or imitating the GNU Make design.
On the other hand we do care about developer workflows not breaking when introducing changes.

As such, changing how non-option arguments to -t compdb are interpreted is a strict no-go.

It is ok to introduce new options, even if they change the tool's behavior, as long as everything is properly documented, and there is no place for ambiguity. If this is not possible, or makes the UI too cluncky, introducing a new tool might be the better option.

@digit-google
Copy link
Contributor

In this specific case, using --targets as a separator between rules and targets seems ok, and no one likes commas on the command-line. What I mean is something like -t compdb [-x] [rule]... --targets [target]..., but I am not sure that getopt supports this here.

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 23, 2024

We do really not care about following POSIX guidelines or imitating the GNU Make design.

@digit-google Works for me, but is there consensus among maintainers on this point? (I got the sense from @mcprat that some POSIX-ness and Make-ness was desired. I don't feel a strong preference either way, but it would help to have unambiguous direction.)

On the other hand we do care about developer workflows not breaking when introducing changes.

[thumbs up]

As such, changing how non-option arguments to -t compdb are interpreted is a strict no-go.

So for example (and please correct me if i'm wrong):

  1. in ninja -t compdb item1 item2, we will continue to interpret the two items as rules only (and not as targets);
  2. likewise, we will NOT introduce a form like ninja -t compdb --targets item1 item2 where the two items are interpreted as targets

[edit: ...or would item (2) here be viable because it uses a new option that changes the tool's behavior?]

It is ok to introduce new options, even if they change the tool's behavior, as long as everything is properly documented, and there is no place for ambiguity.

Sounds good to me!

If this is not possible, or makes the UI too cluncky, introducing a new tool might be the better option.

... and by "tool" you mean a new sub-command, right? For example, maybe like:

ninja -t compdb-targets [options] [targets...]

@digit-google
Copy link
Contributor

Yes, except for 2, since -t comptb --targets item1 item2 would not break existing workflows, since --targets was not supported before this change.

Personally, I do not care about sticking to Posix guidelines. Ninja is supposed to be cross-platform anyway, and there are plenty of command-line parsers (like python argparse or Golang's flags) which do not follow them, and end up perfectly ok (or even great in the case of argparse, imho). I prefer ensuring that command-line options are simple to understand, provide correct and reproducible outputs, and are well documented in --help and other docs (Ninja had issues with all these in the past, but the situation is slowly improving).

I also forgot to ask for a regression test for the tool in output_test.py to be added. One that experiments all modes (rules, targets, and rules + targets) preferrably. This is also important to avoid breaking stuff unexpectedly.

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 26, 2024

@digit-google btw, what's our C++ version for compiling ninja? (i grepped for CXX_STANDARD in the cmake files but found nothing.)

i see uses of auto and range-based for loops, so that means we require at least C++11.

i ask because i wanted to use a structured binding in a place where i thought it would help to add clarity, but that's a C++17 feature, which would require setting CXX_STANDARD and CXX_STANDARD_REQUIRED.

Note, according to the clang website:

By default, Clang 16 or later builds C++ code according to the C++17 standard.

...and likewise, GCC 11 defaults to C++17.

So if we're not going to depend on C++14 or C++17 features, we may want to set CXX_STANDARD to 11 so that we get the desired compile errors in the event where people unwittingly uses more recent features.

@digit-google
Copy link
Contributor

IIRC, the goal is to have the core Ninja sources building with C++11 support only, in order to allow building the tool on older systems (in particular with ./configure.py --bootstrap rather than CMake).

However, the tests now rely on GTest which mandates C++14 though (and soon C++17), which is why CXX_STANDARD is not applied to them in our CMakeList.txt file.

I think these requirements were in the top-level CONTRIBUTING.md file, but no longer are there.

I wouldn't mind switching to C++17 personally, but @jhasse is the authority on this specific issue (and this may require updating some of our CI recipes).

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 27, 2024

@digit-google @jhasse this is a little off-topic for this PR, but: what's our policy on GNU core-language extensions)?

some pros/cons (in case this hasn't come up before):

pros:

con:

  • Allowing GNU extensions would rule out the use of MSVC to compile ninja. (i don't know whether that would be a deal-breaker for the ninja project, but given that speed is one of the top priorities, i can see why you'd want to keep MSVC compatibility in case the code that MSVC generates is ever faster for use-cases that ninja users care about).

@digit-google
Copy link
Contributor

I believe right now we absolutely want to build with the MSVC toolchain, and support non-GNU and non-Clang toolchains, so these are a deal breakers.

@JamesWidman JamesWidman marked this pull request as draft September 27, 2024 13:41
@JamesWidman
Copy link
Contributor Author

JamesWidman commented Sep 27, 2024

@digit-google

In this specific case, using --targets as a separator between rules and targets seems ok, and no one likes commas on the command-line. What I mean is something like -t compdb [-x] [rule]... --targets [target]..., but I am not sure that getopt supports this here.

so it turns out that this is doable, but it requires using getopt_long() in a way that is different from the normal usage pattern for getopt()/getopt_long(). To simplify things for NinjaMain::ToolCompilationDatabase(), it seems best to move argument parsing for compdb into a separate routine that (1) parses all arguments and (2) returns a structure that's easier to act on.

at the moment i'm working on regression tests and documentation, but here's a preview of the argument parsing routine (for early feedback on the general shape of this approach):

(Before my next push, i will review the coding style guidelines, so hopefully that push will not contain e.g. any naming style violations that might appear below.)

Compdb parseCompdbArguments(int argc, char* argv[]) {
  Compdb ret;
  //
  // grammar:
  //     ninja -t compdb [-hx] [rules] [--targets targets]
  //
  // in phase 1 of argument parsing, we process [-hx] and "--targets". The
  // pseudo-option "--targets" is conceptually more like "--" than an option.
  // Traditionally, "--" means "every argument that follows is an operand [i.e.,
  // a non-option argument]". Here, "--targets" means "every argument that
  // follows is grammatically an operand, and semantically a target. Also, rule
  // operands may precede this argument."
  //
  // If getopt_long returns an instance of "--targets", we store its `optind`
  // (see `man 3 getopt`) as the starting index for the list of targets, and we
  // store the previous `optind` as the starting index for the list of rules.
  //
  // in phase 2 of argument parsing, we process the list of rules (if any) and
  // the list of targets (if any).

  /* [...] */

  return ret;
}

...where Compdb is:

struct Compdb {
  enum class Action {
    display_help_and_exit,
    emit_all_commands,
    emit_userSpecified_commands
  };

  Action action;
  EvaluateCommandMode eval_mode = ECM_NORMAL;

  typedef std::vector<StringPiece> ArgList;
  ArgList targets;
  ArgList rules;
};

...and the usage looks like this:

int NinjaMain::ToolCompilationDatabase(const Options* options, int argc,
                                       char* argv[]) {
  Compdb compdb = parseCompdbArguments(argc, argv);

  switch (compdb.action) {
  /* [...] */
  }

  return 0;
}

Feedback welcome!

(Note: the comment about "storing optind" above is only an implementation detail of parseCompdbArguments(); it is not visible to the caller, who will not have to think about optind, getopt(), or argc/argv.)

@mcprat
Copy link
Contributor

mcprat commented Sep 28, 2024

POSIX has a section called "Utility Syntax Guidelines"

i started reading Issue 8 (IEEE Std 1003.1™-2024 Edition)...

I did originally read the section from Issue 7, but I don't see anything different from Issue 8
It's base definitions section 12.2
https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html

We do really not care about following POSIX guidelines or imitating the GNU Make design.

Works for me, but is there consensus among maintainers on this point? (I got the sense from @mcprat that some POSIX-ness and Make-ness was desired.

I'm not bringing up POSIX-ness or Make functionality to make things harder for us, it should actually make things easier. I understand Ninja does not have POSIX-compliance as a major goal, but I believe it should be done whenever it is easy to do so. POSIX likely recommends against an option having multiple arguments because it's simply not efficient, and doesn't match what most consider to be an "option" compared to what one would define as "input". I personally don't see why we need the secondary stage of getopt processing or similar alternatives at all...

imagine instead of

ninja -t compdb [-x] [RULES...] [--targets TARGETS...]

or

ninja -t compdb [-x] [--targets TARGETS...] [RULES...]

we can just have

ninja -t compdb [-x] [TARGETS...] [RULES...]
or just writing it the other way around...
ninja -t compdb [-x] [RULES...] [TARGETS...]

where the order of operands affects the order of output, but not the actual total content (amount of JSON elements).

Then in the manual you don't have to explain a new "option", rather it can simply read:
"given a list of rules and/or targets ... prints on standard output a compilation database ..."

I'm going to try to get that method to work myself, to make sure I'm not preaching for something that isn't possible to begin with... I wanted to have it done already but I've been busy...

@jhasse jhasse marked this pull request as ready for review September 28, 2024 07:25
@jhasse
Copy link
Collaborator

jhasse commented Sep 28, 2024

Sry misclicked.

Regarding C++ standard: I'm okay with everything that works relativly easy on the oldest supported RHEL version (8 currently).

I think it would be best to stick with a command line way that would also work easily with other command line parsers.

@digit-google
Copy link
Contributor

@mcprat , what you propose is ambiguous, and I assure you that someone, somewhere is going to have a rule and a target with the same name, and won´t understand why they cannot use the tool as expected. There needs to be a explicit separation in the parsing format. Or simply introduce a new tool name for targets, nobody will ever get confused.

@digit-google
Copy link
Contributor

Regarding C++, it looks like we should be able to switch to C++17 (to be performed in a separate CL of course).

this page says RHEL ships with GCC 8.x or 9.x, and that page says that all C++17 features are supported starting with GCC 8 (and even GCC 7 if you don't care about full support of template deductions).

Similarly, this page shows that VS 2019, which we currently use in CI, supports C++17 (unlike VS 2017 which still lacks some features).

src/ninja.cc Outdated
if (!success) {
Error("cannot determine working directory: %s", strerror(errno));
return 1;
}

putchar('[');
for (vector<Edge*>::iterator e = state_.edges_.begin();
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we're touching this part of the code, can I ask you to change this to use a for-range based loop:

for (const Edge* edge : state_.edges_) {
  ...
}

src/ninja.cc Outdated
case 'h':
default:
ret.action = Compdb_Targets::Action::display_help_and_exit;
goto fin;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Just return ret here.

@JamesWidman
Copy link
Contributor Author

(note, CommandCollector (formerly known as InEdge_Collector) moved from src/graph.h to src/command_collector.h)

@@ -12,14 +12,50 @@
import tempfile
import unittest
from textwrap import dedent
from typing import Dict
from typing import Dict, Optional
from collections.abc import Callable
Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops; i forgot to remove the import of Callable; this will be gone in the next push.

Choose a reason for hiding this comment

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

Superior style for avoiding this:

import os
import sys
import tempfile
import foobar
import typing as T

def func(args: T.Optional[T.Dict[str, str]]) -> T.Callable[........]:
    pass

A commonly used module where the symbols in use are regularly in flux is a strange time to spend most of your time micromanaging which symbols are currently in scope. But everyone does it. I'm always baffled.

The semantic difference between the two is trivial:

  • from x import y fills up the local namespace and in return accessing the "y" symbol avoids having to do a name lookup inside "x"

The effects on code readability are considerable:

  • with from x import y you lose the ability to clearly reason at a glance, that many symbols are part of the same logical context

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done and pushed; thank you!

(as i mentioned upthread, i have not touched python in years, so i'm grateful for any python help!)

Choose a reason for hiding this comment

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

Well, like I said an awful lot of people seem to do it so you're not exactly in bad company. :P

Probably the rationale is that from imports contribute less to line max width. That is the usual reason to use from imports for meaningful runtime code.

And if the alternative was truly

import typing 

def func(args: typing.Optional[typing.Dict[str, str]]) -> typing.Callable[........]:
    pass

I'd perhaps concede. That's a 7 char cost per symbol and typing symbols always appear on a line where something else is already present. But T is quite distinctive and makes sense to reserve for a language level feature in a way that frobnicator.core.utils as U doesn't really make sense. 🤷 I wish they'd named it "T" all along.

@JamesWidman
Copy link
Contributor Author

is there a recommended way to use clang-tidy? (Apparently it ships with a configuration that matches google's style guidelines.)


default_env = dict(os.environ)
default_env.pop('NINJA_STATUS', None)
default_env.pop('CLICOLOR_FORCE', None)
default_env['TERM'] = ''
NINJA_PATH = os.path.abspath('./ninja')

def cook(raw_output: bytes) -> str:
Copy link
Contributor

Choose a reason for hiding this comment

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

may I suggest a more meaningful name, e.g. remove_non_visible_lines here?

src/ninja.cc Outdated
// Phase 1: parse options:
optind = 1; // see `man 3 getopt` for documentation on optind
int opt;
while ((opt = getopt(argc, argv, "hx")) != -1) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I get a warning when cross-compiling locally for Windows:

/work2/github-ninja/src/ninja.cc: In static member function ‘static {anonymous}::CompdbTargets {anonymous}::CompdbTargets::CreateFromArgs(int, char**)’:
/work2/github-ninja/src/ninja.cc:1106:38: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
 1106 |     while ((opt = getopt(argc, argv, "hx")) != -1) {
      |                                      ^~~~

You may want to use a const_cast<char*>("hx") here like the rest of the code does for other getopt() calls. :-/

@digit-google
Copy link
Contributor

Thank you, the last PR looks good apart from minor nits. @jhasse, could you mark this PR as ready for review so that CI builders start building them. I compiled it locally for Linux and Windows only (cross-compiled with mingw64 only).

@JamesWidman JamesWidman marked this pull request as ready for review October 7, 2024 13:10
@JamesWidman
Copy link
Contributor Author

JamesWidman commented Oct 7, 2024

i finally looked at the job logs (:
(fixed errors from codespell about misspelled instances of "message", and a missing #include of <direct.h> for the MSVC build (so that it has a declaration of getcwd()))

@JamesWidman
Copy link
Contributor Author

Thank you, the last PR looks good apart from minor nits. @jhasse, could you mark this PR as ready for review so that CI builders start building them. I compiled it locally for Linux and Windows only (cross-compiled with mingw64 only).

@digit-google @jhasse yeah; in the workflow for windows, i see that it successfully builds with MSVC, and that the unit tests completed successfully, but it looks like we don't run output_test.py there, so it would be good to know whether an MSVC-built ninja actually produces the desired output for -t compdb-targets.

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Oct 8, 2024

it would be good to know whether an MSVC-built ninja actually produces the desired output for -t compdb-targets.

on the other hand, compdb-targets isn't doing anything OS-specific that compdb wasn't already doing, and compdb presumably works on windows, so...

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Oct 9, 2024

side note: when i try to build the documentation on macOS, using the version of xsltproc that ships with macOS (/usr/bin/xsltproc), i get:

% which xsltproc
/usr/bin/xsltproc
% ./configure.py
wrote build.ninja.
% ninja manual
[1/1] XSLTPROC doc/manual.html
FAILED: doc/manual.html
xsltproc --nonet doc/docbook.xsl build/manual.xml > doc/manual.html
I/O error : Attempt to load network entity http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl
warning: failed to load external entity "http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"
compilation error: file doc/docbook.xsl line 8 element import
xsl:import : unable to load http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl
ninja: build stopped: subcommand failed.
%

...but if i use the version of libxslt provided by Homebrew (after installing XSLT 1.0 Stylesheets for DocBook with brew install docbook-xsl), everything works:

% export PATH="$(brew --prefix libxslt)/bin:$PATH"
% ninja manual
[1/1] XSLTPROC doc/manual.html
%

i'm guessing that the homebrew version is checking homebrew-standard paths to find the docbook stuff, whereas the macOS version doesn't...

should we mention something about this in README.md? E.g. words to the effect of:

to build documentation on macOS, first run:

brew install libxslt docbook-xsl
export PATH="$(brew --prefix libxslt)/bin:$PATH"

(this would be in a separate PR, of course)

@digit-google
Copy link
Contributor

Mentioning it in the README.md would be nice. Detecting the version of xslt at configure time and warning about it would be nicer, imho, but I don't know enough about this library and its dependencies to know if this is simple enough to implement.

JamesWidman and others added 2 commits October 13, 2024 01:31
Fixes ninja-build#1544

Co-authored-by: Linkun Chen <lkchen@google.com>
Co-authored-by: csmoe <csmoe@msn.com>
Co-authored-by: James Widman <james.widman@gmail.com>
The introduction of the entry for `compdb-targets` in the `[horizontal]`
labeled list in doc/manual.asciidoc revealed some display issues in the
left column:

First, the web browser would insert a line break in the middle of the
label `compdb-targets`, so that it looked like this:

       compdb-
       targets

We fix this by applying the `white-space: nowrap` attribute to the left
column.

After this is fixed, we see practically no space between the end of the
longest label and the beginning of the text in the second column; we fix
this with the `padding-right` attribute.

Finally, we align all labels to the right side of the column so that
there is a consistent amount of horizontal space between the end of each
label and the beginning of the text in the second column.
@JamesWidman
Copy link
Contributor Author

is it normal for workflows to be re-executed when the content of the most recent push is identical to the previous push?

@mcprat
Copy link
Contributor

mcprat commented Oct 13, 2024

is it normal for workflows to be re-executed when the content is identical to the previous push?

unfortunately yes, the CI is not that smart, it operates on whether the commit hash has changed not the content. however, GitHub remembers which hashes passed or not so it can display that when a bad commit is placed on top

@eli-schwartz
Copy link

is it normal for workflows to be re-executed when the content of the most recent push is identical to the previous push?

https://github.com/orgs/community/discussions/64405

I fear you will be waiting quite long for a resolution but fortunately the CI here doesn't take 2 hours on each run.

@JamesWidman
Copy link
Contributor Author

JamesWidman commented Nov 12, 2024

@jhasse @digit-google is there anything else i need to do for this PR? (I thought I fixed or addressed everything, but please let me know if I missed anything!)

@digit-google
Copy link
Contributor

This looks good to me, it's up to @jhasse now to accept it.

@jhasse jhasse merged commit a3fda2b into ninja-build:master Nov 12, 2024
11 checks passed
@JamesWidman
Copy link
Contributor Author

thank you both!

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.

[Feature Request] Allow 'ninja -t compdb' accept one target
5 participants