Poorly-explained cmake_path() subcommands (CMake 3.19)

I was reading through the documentation for the upcoming cmake_path() command that will replace most of the file(foo_PATH ...) subcommands in the next release, and I’m finding some of them… both non-obvious, and unhelpfully documented.

IS_RELATIVE and IS_ABSOLUTE, those make sense to me, their workings are obvious. Many of the rest, though…

cmake_path(HAS_ROOT_NAME <path> <output>)

Checks if <path> has root-name .

cmake_path(HAS_ROOT_DIRECTORY <path> <output>)

Checks if <path> has root-directory .

Since these aren’t documented as taking inputs for root-name and root-directory, I have no real idea what they’re supposed to do.

cmake_path(HAS_ROOT_PATH <path> <output>)

Checks if <path> has root path.

Effectively, checks the following: root-name / root-directory .

Given the above, this one is even more confusing.

cmake_path(HAS_FILENAME <path> <output>)

Checks if <path> has file-name .

Again, since file-name isn’t an input, I’m confused. I’d assume this checks whether the path has any filename — meaning, it doesn’t end in a slash. But then file-name should just be “a filename component” or something like that.

cmake_path(HAS_EXTENSION <path> <output>)

Checks if <path> has an <extension. If the first character in the filename is a period, it is not treated as an extension (for example “.profile”).

This makes me even more convinced I’m correct about the previous one, since they would be complementary.

cmake_path(HAS_STEM <path> <output>)

Checks if <path> has stem.

Aaaand, we’re back to “I have no idea what this means”.

cmake_path(HAS_RELATIVE_PATH <path> <output>)

Checks if <path> has relative path.

How is this different from “IS_RELATIVE”? They sound redundant.

cmake_path(HAS_PARENT_PATH <path> <output>)

Checks if <path> has parent path.

Yup, again, no clue what that means. How can a path “have” a parent path — and not even a specific one, just any arbitrary parent path?

A pair of commands like…

cmake_path(IS_PARENT_OF <path> <child> <output>)
cmake_path(IS_CHILD_OF <path> <parent> <output>)

that would make sense to me. I could totally see the utility in that. And, actually, I guess that first one is cmake_path(IS_PREFIX_OF <path> <input>), so that’s cool. And I suppose you could just reverse <path> and <input> to get the other operation. So that only leaves me, again, even more confused about what all those other commands are supposed to be doing.

I just can’t figure out how, when, or why most of these would be used. And the current documentation only makes it less clear.

OK, the introduction waaay at the top makes some of this clearer. And makes other parts of it appear to be downright wrong.

The path name has the following syntax:

  1. root-name (optional): identifies the root on a filesystem with multiple roots (such as "C:" or "//myserver" ).
  2. root-directory (optional): a directory separator that, if present, marks this path as absolute. If it is missing (and the first element other than the root name is a file name), then the path is relative.

…Okay, but if root-directory is the directory separator, then “Effectively, checks the following: root-name / root-directory.” seems patently false. It checks that the path starts with root-name root-directory. (Where root-name will always be empty on Linux.)

Also, “and the first element other than the root name is a file name” should surely say “…is a file name or directory name”. Actually, even that’s not right. The first element could also be . or ...

Thanks for your remarks.

A less aggressive and more constructive tone would have been welcome …

My apologies.

Constructively, I would strongly recommend against adopting this definition:

Zero or more of the following:

  1. file-name : sequence of characters that aren’t directory separators. This name may identify a file, a hard link, a symbolic link, or a directory. Two special file-names are recognized:
  • dot : the file name consisting of a single dot character . is a directory name that refers to the current directory.
  • dot-dot : the file name consisting of two dot characters .. is a directory name that refers to the parent directory.
  1. directory-separator : the forward slash character / . If this character is repeated, it is treated as a single directory separator: /usr///////lib is the same as /usr/lib .

It would be better to describe that as a path-component or a name-string than as a file-name, as defining a “filename” as "the name of a file, or a directory, or . or .." only confuses things mightily.

A file-name can have an extension. By default, the extension is defined as the sub-string beginning at the leftmost period (including the period) and until the end of the pathname. When the option LAST_ONLY is specified, the extension is the sub-string beginning at the rightmost period.

This definition should also be expanded: An extension is a substring only of the last path-component (the one following the rightmost directory-separator) — other path-components cannot have extensions, even if they contain a period.

And as is mentioned later in the docs, the extension can’t start at the first character of the path-component. If the final path-component is .profile, it has no extension. If the final path-component is .config.txt, its extension is just .txt with or without LAST_ONLY.

file-name can be confusing, I agree, but path-component is ambiguous as well because root-name or root-directory are also components of the path.

FYI, cmake_path command is translation in CMake environment of std::filesystem::path STL class so I try to keep the same semantic and wording… And the documentation use the term file-name.

I’m happy to rework the docs during this 3.19 release cycle to improve their clarity, but first I’d like to see discussion of some concerns I’ve just raised in another post run its course.

Thanks for your proposition. FYI, I reply to your previous post.

Please see related discussions in this issue in the issue tracker.

@ferdnyc I’ve added a proposed revised version of the API for discussion in the associated issue. We would appreciate it if you could take a look and perhaps provide feedback in that issue with your thoughts.

@ferdnyc I finally got a chance to rework the docs for cmake_path(). Would appreciate your feedback on the changes (I expect there will be more reworking to do after review).

https://gitlab.kitware.com/cmake/cmake/-/merge_requests/5682

@craig.scott I’ll take a look, thanks!

Apologies for not responding to your previous request. To be honest I’d sort of checked out of this one, it’s been months since I last looked at this topic. I’d clearly made a poor first impression, and the whole interaction felt tainted, so the only thing that seemed likely to come out of pressing the issue further was digging myself an even deeper hole.

(Or, in its more recognizable form, “Better to remain silent and be thought a fool than to speak and to remove all doubt.”)