Should find_package() skip empty PATH entries?

Summary

When the system PATH environment variable contains empty entries (e.g., ;; on Windows or :: on Unix), find_package() unexpectedly searches the current working directory. This happens because empty PATH entries are passed to path resolution functions that convert "" to CWD.

I’d like to discuss whether filtering empty PATH entries in find_package() would be a reasonable enhancement.

The Issue

On Windows, it’s common for the system PATH to contain empty entries:

  • Trailing semicolon: C:\bin;C:\tools;
  • Double semicolons: C:\bin;;C:\tools

These malformed entries often come from buggy installers and are difficult for users to notice.

When find_package() processes CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH, it iterates through PATH entries. Empty entries get passed to CollapseFullPath(""), which correctly resolves them to the current working directory (since "" is a valid relative path meaning “current directory”).

Reproduction

cmake_minimum_required(VERSION 3.20)
project(test)

# Simulate empty PATH entry
set(ENV{PATH} "C:/bin;;C:/tools")

# Create a config file in build directory
file(WRITE "${CMAKE_BINARY_DIR}/mylib-config.cmake" "set(mylib_FOUND TRUE)")

# This finds mylib because "" resolves to CMAKE_BINARY_DIR
find_package(mylib CONFIG QUIET)
if(mylib_FOUND)
    message(WARNING "mylib found unexpectedly in: ${mylib_DIR}")
endif()

Impact

This becomes problematic when:

  1. CMake runs with CWD set to the build directory (common in IDE integrations)
  2. The build directory contains *-config.cmake files from export(TARGETS ...)
  3. System PATH has empty entries

In this case, find_package(foo) may incorrectly find packages exported to the build tree, even when foo_ROOT or CMAKE_PREFIX_PATH isn’t set.

Proposal

Would it be reasonable for CMake to filter empty entries when processing PATH for find_package() searches? Something like:

// When iterating PATH entries for find_package search
if (pathEntry.empty()) {
    continue;  // Skip empty entries
}

This would be a defensive enhancement that prevents unexpected behavior from malformed PATH variables, which are unfortunately common on Windows systems.

Workaround

Currently, users can work around this by filtering PATH at the start of CMakeLists.txt:

if(WIN32)
  set(_path_sep ";")
else()
  set(_path_sep ":")
endif()
string(REPLACE "${_path_sep}" ";" _path_entries "$ENV{PATH}")
list(FILTER _path_entries EXCLUDE REGEX "^$")
list(JOIN _path_entries "${_path_sep}" _filtered_path)
set(ENV{PATH} "${_filtered_path}")

Questions

  1. Is this considered expected behavior, or would filtering empty PATH entries be a welcome enhancement?
  2. If this is worth pursuing, should I file a GitLab issue?

Thanks for any feedback!

Thanks for pointing this out. Yes, please open an issue.

Issue opened: https://gitlab.kitware.com/cmake/cmake/-/issues/27454

Hey!!!

This is a common problem with CMake PATH: find_package() isn’t really doing anything “wrong”; it just follows the rule that empty entries resolve to CWD.

In real life, it would be safer to filter out empty entries when going through PATH in find_package(), especially on Windows where installers like to leave trailing semicolons.

Adding a flag or policy might be a more subtle way to fix the problem without breaking projects that depend on CWD resolution.

However, for most workflows, it makes sense to skip empty entries and avoid accidentally picking files from the build directory.

Yes, a defensive enhancement would keep things from going wrong without breaking the main logic.

The behavior has changed since CMake 4.0 to remove empty PATH entries by default.

I was using CMake 3.31.6 and not noticing that change.

Therefore, the mentioned issue is closed now.