find_program without knowing specific directory structure

I need to find an executable in an SDK where the structure can vary (including the names of intermediary folders). I just know that the executable will be under some root folder, but I don’t know at which level exactly. In a unix shell, I could just invoke:

cd <path_to_sdk>/root_folder/
find . -name "<program_name>"

The problem I am encountering is that find_program does not seem to work that way

  find_program(
      RE_2D_RENDER_EXECUTABLE RE2DRender
      PATHS "${ARG_RE_2D_RENDER_ROOT}"
      NO_DEFAULT_PATH
  )

will not find the program unless ARG_RE_2D_RENDER_ROOT is the exact folder in which RE2DRender is actually located. I know that I can provide multiple paths to find_program but my issue is that I just don’t know the names of those paths, I only know the top one

Or in other words, it doesn’t seem to check in all folder recursively down.

Is there another flavor of find_program that would behave like unix find?

I solve this kind of issue in my “FindOctave.cmake”, where GNU Octave install folder has the version number in it. I use find(GLOB) then find_program() https://github.com/scivision/octave-cmake-mex/blob/main/cmake/FindOctave.cmake#L66

Correct, find_program() doesn’t search recursively. That could be arbitrarily expensive. Instead, it searches well-defined sets of locations, suffixes and subdirectories, as described in the find_program() docs. If you need to recurse to arbitrary directory levels, you would have to implement that yourself with your own logic.

This is typically handled by something like (I’m making up versions since I don’t interact with Octave):

set(FindOctave_VERSIONS
  ${Octave_EXTRA_VERSIONS} # forward compat that users can use
  11.0 10.0 9.1 9.0)
set(paths)
foreach (version IN LISTS FindOctave_VERSIONS)
  list(APPEND paths foo-${version} foo/${version})
endforeach ()
# use ${paths} in `find_*` calls.

There should really just be some finite set of possible subpaths to search; in that case PATH_SUFFIXES is probably the way to go here.

yes I agree, instead of file(GLOB) which may not have a stopping condition, a finite list should be searched.

In my FindOctave.cmake, because I don’t use it that much and didn’t want to have to maintain it frequently, I did leave a single file(GLOB) just for Windows, though it could have no stopping condition, I feel that would be a rare case for a script I don’t want to maintain that much.

I wasn’t suggesting changing the default behavior of find_program. That being said adding a RECURSE option to find_program, that would then search recursively, would help in not having to reimplement the wheel every time this feature is required.

For the record, I ended up implementing it (note that I am not passing all find_param args because I don’t use them, so this implementation is somewhat simplified). It is not easy code to write, so that is why I think it would benefit CMake to have it built-in (optional of course…)

Note that since find_program sets a CACHE variable, then it is only “expensive” the first time it runs…

IIRC, it’s only expensive after the first time it succeeds.