| cmake_policy(SET CMP0222 NEW) | |
| cmake_policy(SET CMP0223 NEW) | |
| # The operator is an if() spelling of cmake_path(IS_PREFIX), so assert that | |
| # the two agree rather than repeating a table of expected values here. What | |
| # each input should evaluate to is pinned by the cmake_path(IS_PREFIX) test; | |
| # this asserts only that the two surfaces cannot drift apart. Neither | |
| # normalizes, so the comparison is against the plain form of the command. | |
| # | |
| # Because nothing below states an expected value, the host path model needs | |
| # no branching: parity has to hold on every platform whatever the answer is. | |
| function(assert_parity prefix path) | |
| set(prefix_var "${prefix}") | |
| cmake_path(IS_PREFIX prefix_var "${path}" expected) | |
| if(expected) | |
| set(expected TRUE) | |
| else() | |
| set(expected FALSE) | |
| endif() | |
| if(prefix PATH_IS_PREFIX path) | |
| set(actual TRUE) | |
| else() | |
| set(actual FALSE) | |
| endif() | |
| if(NOT actual STREQUAL expected) | |
| message(SEND_ERROR | |
| "if('${prefix}' PATH_IS_PREFIX '${path}') is ${actual}, but " | |
| "cmake_path(IS_PREFIX) says ${expected}") | |
| endif() | |
| endfunction() | |
| # Each pair appears in both roles, so a reversed call cannot pass. | |
| assert_parity("/a/b" "/a/b/c") | |
| assert_parity("/a/b/c" "/a/b") | |
| assert_parity("/a/b" "/a/b") | |
| # Trailing separators, which are significant and asymmetric. | |
| assert_parity("/a/b" "/a/b/") | |
| assert_parity("/a/b/" "/a/b") | |
| assert_parity("/a/b/" "/a/b/c") | |
| # Without NORMALIZE, '.' and '..' are ordinary components. | |
| assert_parity("/a/b" "/a/b/../../etc") | |
| assert_parity("/a/b" "/a/./b//c") | |
| assert_parity("." "./a/b") | |
| assert_parity("." "a/b") | |
| # Duplicate separators are not components. | |
| assert_parity("a/b" "a///b") | |
| # Sibling sharing a textual prefix. | |
| assert_parity("/a/b" "/a/bc") | |
| # Relative and absolute paths are not reconciled. | |
| assert_parity("/a" "b/c") | |
| assert_parity("b" "b/c") | |
| assert_parity("/" "b/c") | |
| assert_parity("/" "/a/b") | |
| # Empty operands in each position. | |
| assert_parity("" "/a/b") | |
| assert_parity("/a" "") | |
| assert_parity("" "") | |
| # Host path model: backslashes, case, drive-relative paths, UNC root-names. | |
| assert_parity("C:\\a" "C:\\a\\b") | |
| assert_parity("c:/a" "C:/A/b") | |
| assert_parity("C:/" "C:foo") | |
| assert_parity("//host/share" "//host/share/a") | |
| assert_parity("/a" "//a/b") | |
| # Literal operands, not just variables. | |
| if(NOT "/a/b" PATH_IS_PREFIX "/a/b/c") | |
| message(SEND_ERROR "if(PATH_IS_PREFIX): literal operands rejected") | |
| endif() | |
| # NOT composes with the operator, which is the motivating guard idiom. | |
| set(guard_ok FALSE) | |
| if(NOT "/a/b" PATH_IS_PREFIX "/a/bc") | |
| set(guard_ok TRUE) | |
| endif() | |
| if(NOT guard_ok) | |
| message(SEND_ERROR "if(NOT <prefix> PATH_IS_PREFIX <path>) did not compose") | |
| endif() | |
| # Works in an elseif() chain, which a helper function could not. | |
| if("/a" PATH_IS_PREFIX "/x/y") | |
| message(SEND_ERROR "if(PATH_IS_PREFIX): '/a' matched '/x/y'") | |
| elseif("/a/b" PATH_IS_PREFIX "/a/b/c") | |
| else() | |
| message(SEND_ERROR "elseif(<prefix> PATH_IS_PREFIX <path>) did not match") | |
| endif() | |
| # The motivating case: a prefix that if(MATCHES) cannot express. | |
| set(prefix "/proj/lib+ssl(v2)/inc.d") | |
| if(NOT "${prefix}" PATH_IS_PREFIX "${prefix}/f.h") | |
| message(SEND_ERROR "if(PATH_IS_PREFIX): regex metacharacters in prefix") | |
| endif() | |
| # The keyword is consumed as an operator only with both a preceding and a | |
| # following token, so it stays usable as a variable otherwise. Neither | |
| # condition may be written with a leading NOT: that would put the keyword in | |
| # the operator slot and make these a hard error. | |
| set(PATH_IS_PREFIX "yes") | |
| if(PATH_IS_PREFIX) | |
| else() | |
| message(SEND_ERROR "if(PATH_IS_PREFIX): unary use broken") | |
| endif() | |
| if(PATH_IS_PREFIX STREQUAL "yes") | |
| else() | |
| message(SEND_ERROR "if(PATH_IS_PREFIX STREQUAL ...): left-operand use broken") | |
| endif() |