Weird variable behaviour with find_package

Hello there,
I have already posted for help on Reddit (here), but I believe I might get more insightful help here.

My environment: Windows 10, latest MSYS2/MinGW64, CMake 3.20.2, Intel IPP 2021.2.0
My objective: include IPP libraries for use in my project.
My issue: when using find_package with Intel-provided ipp-config.cmake, some variables are set while others aren’t, even though they should.

I have installed Intel IPP using the official installer, which includes a CMake package config file in C:\Program Files (x86)\Intel\oneAPI\ipp\2021.2.0\lib\cmake\ipp\ipp-config.cmake. You can find its paste here: pastebin .com/j3r67M1N

This is my CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(MyProject)
find_package(IPP REQUIRED)
message("${IPP_FOUND} | ${IPP_SHARED} | ${IPP_ARCH} | ${IPP_TL_VARIANT} | ${IPP_LIBRARIES} | ${WIN32} | ${IPP_ippcore_FOUND}")
add_executable(MyExec src/main.cpp)
target_link_libraries(MyExec ${IPP_LIBRARIES})

This is the output in a MinGW64 bash shell:

$ /c/Program\ Files/CMake/bin/cmake.exe .. -G "MinGW Makefiles"
-- The C compiler identification is GNU 10.3.0
-- The CXX compiler identification is GNU 10.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/msys64/mingw64/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
1 |  | intel64 | OpenMP |  | 1 |
-- Configuring done
-- Generating done
-- Build files have been written to: C:/REDACTED/build

Minor doubt: how does CMake know to use ipp-config.cmake when there is neither a built-in nor user-provided FindIPP? All I can see is an environment variable called ONEAPI_ROOT, which points to C:\Program Files (x86)\Intel\oneAPI; is this enough for CMake to do its thing?

Actual issue: take a look at the output of the message() command; as you can see IPP_FOUND, IPP_ARCH and IPP_TL_VARIANT are correctly set as expected (to their defaults), while IPP_LIBRARIES and IPP_ippcore_FOUND aren’t.
I can confidently say that they are being set by IPP’s config, because when I added a variable_watch(IPP_LIBRARIES), this was the output (full paste here: pastebin .com/gz2V5Ajh ), includes also a set(IPP_LIBRARIES "WTF") to make the issue more evident):

CMake Debug Log at C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake:128 (list):
  Variable "IPP_LIBRARIES" was accessed using MODIFIED_ACCESS with value
  "IPP::ipp_iw".

...

CMake Debug Log at C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake:128 (list):
  Variable "IPP_LIBRARIES" was accessed using READ_ACCESS with value "".

...

CMake Debug Log at C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake:128 (list):
  Variable "IPP_LIBRARIES" was accessed using MODIFIED_ACCESS with value
  "IPP::ippcore".

I then tried with target_link_libraries(MyExec IPP::ippcore) and guess what, that worked. But IPP_LIBRARIES is still empty. What the hell?

Does anyone have any clue why the list(APPEND IPP_LIBRARIES ...) in IPP’s config is always appending to an empty/reset variable?

Thanks in advance

The documentation for find_package describes this.

It might only be used inside of functions in the ipp-config.cmake call. I don’t think variables which go out of scope have variable_watch triggers called on them. I would recommend reading ipp-config.cmake yourself. It might have comments for usage and available libraries or targets at the top. Additionally, cmake --trace-expand can show the lines being executed and you can search it for IPP_LIBRARIES to trace its fate.

Thank you Ben.

It still is not clear to me, the closest thing I found was the ONEAPI_ROOT environment variable, but I believe that would only work for find_package(ONEAPI). Not even an entry in the Windows registry. Is there any debug/trace switch that logs the searched directories? Anyway, it’s not a big deal.

ipp-config.cmake explicitly says in its header (full paste here):

# To use it, add the lines below to your CMakeLists.txt:
# ~~~
#     find_package(IPP REQUIRED)
#     target_link_libraries(mytarget ${IPP_LIBRARIES})
# ~~~
#
# List of the variables defined in this file:
#
# * IPP_FOUND
# * IPP_LIBRARIES - list of all imported targets

I ran CMake with --trace-expand, here are all relevant lines where IPP_LIBRARIES is involved:

C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(52):  if(NOT IPP_LIBRARIES )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(53):  set(IPP_LIBRARIES  )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ipp_iw )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippcore )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippcc )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippdc )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippch )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippcv )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippe )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippi )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ipps )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippvm )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippcore_tl )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippcc_tl )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippcv_tl )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(128):  list(APPEND IPP_LIBRARIES IPP::ippi_tl )
C:/Program Files (x86)/Intel/oneAPI/ipp/2021.2.0/lib/cmake/ipp/ipp-config.cmake(222):  list(REMOVE_DUPLICATES IPP_LIBRARIES )

I don’t see anything particularly telling… the variable is set in the “global scope” (i.e. not inside any macro or function), all the script does is set its default value, append multiple times and then remove duplicates.

Thank you very much for the help

CMake 3.19+ has --debug-find which should help out with this.

Thanks. The problem is that list(APPEND) is in a function. This means that modifications don’t escape the function scope. I recommend filing an issue with IPP upstream to fix this problem.

Concrete suggestions:

  • rename add_imported_library_target to be IPP-specific to avoid conflicts with other packages (such as ipp_add_imported_library_target)
    • add_ipp_iw_include_directory should be mangled too for completeness
  • either:
    • use PARENT_SCOPE at the end of the function to “return” modified values to the caller
    • make it a macro (though it’d be nice to also unset lots of those local variables)
  • suppress all of those message() calls if QUIET is provided

Thank you very much Ben!
I will file an issue upstream.

Meanwhile, I will just link to the IPP:: exported targets I need.

Thank you again!