Why am I getting OptiX_DIR-NOTFOUND?

I am trying to cmake Optix toolkit, owl and other optix related projects and I am getting:

CMake Warning at CMakeLists.txt:109 (find_package):
  By not providing "FindOptiX.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "OptiX", but
  CMake did not find one.

  Could not find a package configuration file provided by "OptiX" with any of
  the following names:

    OptiXConfig.cmake
    optix-config.cmake

  Add the installation prefix of "OptiX" to CMAKE_PREFIX_PATH or set
  "OptiX_DIR" to a directory containing one of the above files.  If "OptiX"
  provides a separate development package or SDK, be sure it has been
  installed.

Even if I insert

C:\ProgramData\NVIDIA Corporation\OptiX SDK 7.6.0
C:\ProgramData\NVIDIA Corporation\OptiX SDK 7.6.0\SDK

or any other directory in Optix 7.6 I still get the same error in cmake-gui. Why am I getting this error whereas my optix 7.6 build and run without any problem?

The CMAKE_INSTALL_PREFIX has nothing to do with that. That’s only controlling where built files are copied when building the INSTALL target inside the solution.

Let’s start with the very first message. If FindOptiX.cmake is not found by CMake inside your project when using find_package(OptiX REQUIRED), then you would first need to find where that FindOptiX.cmake file resides on your local computer (there should be one inside your OptiX SDK <version>\SDK\CMake folder of each OptiX SDK installation) and that folder needs to be made known to CMake by adding that path to the CMAKE_MODULE_PATH as the first sentence inside the error message says.

Inside the OptiX SDK example framework that happens inside the root CMakeLists.txt file (inside your OptiX SDK <version>\SDK\CMakeLists.txt) like this:

# Add paths to our CMake code to the module path, so they can be found automatically by
# CMake.
set(CMAKE_MODULE_PATH
  "${CMAKE_SOURCE_DIR}/../SDK/CMake"
  ${CMAKE_MODULE_PATH}
  )

Means all OptiX SDK examples only build when using that root CMakeLists.txt as input to the CMake build. The CMakeLists.txt inside the individual example folders don’t work standalone!

If you have built your own local CMakeLists.txt which should work standalone, that would need to contain all necessary CMake and project setup steps of that root CMakeLists.txt as well.

Similarly for other projects. OWL for example has its own FindOptiX.cmake script in its own cmake scripts folder which might set other project specific CMake variables. (Please raise any issue with OWL inside its github repository.)

This is similar in my OptiX examples:
I have my own FindOptiX*.cmake scripts per version in this folder: https://github.com/NVIDIA/OptiX_Apps/tree/master/3rdparty/CMake
The CMAKE_MODULE_PATH variable is set to that folder here: https://github.com/NVIDIA/OptiX_Apps/blob/master/CMakeLists.txt#L8
and then I look for all OptiX 7 and 8 SDK versions further down: https://github.com/NVIDIA/OptiX_Apps/blob/master/CMakeLists.txt#L81
and the OptiX*_FOUND results are used to configure the individual example.

My individual examples are built using the newest found OptiX SDK version but some examples need a minimal version and they aren’t built when that is not found. The examples themselves check the OPTIX_VERSION inside the source code in case the OptiX API changed among versions.

For the OptiX Toolkit build you must set the OptiX_INSTALL_DIR which defines which OptiX SDK to use for the build. That happens either via the CMake command line options or inside the CMake GUI application, whatever you use to configure and generate the solution. The OptiX Toolkit README.md explains that inside the Building the OptiX Toolkit section.

Thank you very much for your very informative answer :)
If I understand well, I have to help the FindOptiX.cmake of my Optix related project to find the 7.6 directory "C:/ProgramData/NVIDIA Corporation/OptiX SDK 7.6.0"

Is this what happens in your FindOptiX76.cmake ?

set(OPTIX76_PATH $ENV{OPTIX76_PATH})

if ("${OPTIX76_PATH}" STREQUAL "")
  if (WIN32)
    # Try finding it inside the default installation directory under Windows first.
    set(OPTIX76_PATH "C:/ProgramData/NVIDIA Corporation/OptiX SDK 7.6.0")
  else()
    # Adjust this if the OptiX SDK 7.6.0 installation is in a different location.
    set(OPTIX76_PATH "~/NVIDIA-OptiX-SDK-7.6.0-linux64")
  endif()
endif()

In my project, I have a FindOptiX.cmake in the cmake folder,

if (TARGET OptiX::OptiX)
  return()
endif()

if (OptiX_INSTALL_DIR)
  message(STATUS "Detected the OptiX_INSTALL_DIR variable (pointing to ${OptiX_INSTALL_DIR}; going to use this for finding optix.h")
  find_path(OptiX_ROOT_DIR NAMES include/optix.h PATHS ${OptiX_INSTALL_DIR})
elseif (DEFINED ENV{OptiX_INSTALL_DIR})
  message(STATUS "Detected the OptiX_INSTALL_DIR env variable (pointing to $ENV{OptiX_INSTALL_DIR}; going to use this for finding optix.h")
  find_path(OptiX_ROOT_DIR NAMES include/optix.h PATHS $ENV{OptiX_INSTALL_DIR})
else()
  find_path(OptiX_ROOT_DIR NAMES include/optix.h)
endif()

but I cannot make it see my optix installation directory.

I have tried setting directly the path before if (TARGET OptiX::OptiX)
set(OptiX_INSTALL_DIR "C:\ProgramData\NVIDIA Corporation\OptiX SDK 7.6.0")
I have tried setting an environmental variable to ${OptiX_INSTALL_DIR}
(should’t this be caught at elseif (DEFINED ENV{OptiX_INSTALL_DIR}) ?)

It seems that any changes in FindOptiX.cmake are ignored.
In addition, I have tried to set the OptiX_DIR in the cmake-gui but I always get the same error.

I am sure I am missing something, could you please help on that?
Thanks!

PS: At the beginning of the cmake output I get ( I am not sure if I should take care of this warning at first):

-- Building for: Visual Studio 17 2022
CMake Warning (dev) in CMakeLists.txt:
  No project() command is present.  The top-level CMakeLists.txt file must
  contain a literal, direct call to the project() command.  Add a line of
  code such as

    project(ProjectName)

  near the top of the file, but after cmake_minimum_required().

  CMake is pretending there is a "project(Project)" command on the first
  line.
This warning is for project developers.  Use -Wno-dev to suppress it.

I don’t know what projects you’re building and why this is not working for you.
With CMake script excerpts we won’t get anywhere. Just provide the whole thing.

Everything you take from some github.com repository should just build when following the respective build instructions by the letter.

Again, as said before, the OptiX Toolkit for example requires that you manually set the OptiX_INSTALL_DIR CMake variable either on the command line or inside the CMake GUI app after you pressed configure and got the respective message to set that.
I can’t explain it simpler than already done inside the OptiX Toolkit README.md:
https://github.com/NVIDIA/optix-toolkit?tab=readme-ov-file#building-the-optix-toolkit

If you’re not sure what happens inside your CMake scripts (*.cmake and CMakeLists.txt files), add message() calls to all your steps which set some CMake variable.
I’m using these as well when building Find*.cmake scripts or CMake functions to see what is going on:
https://github.com/NVIDIA/OptiX_Apps/blob/master/3rdparty/CMake/FindOptiX80.cmake#L23
https://github.com/NVIDIA/OptiX_Apps/blob/master/3rdparty/CMake/nvcuda_compile_module.cmake#L45
So if something is not working as you need it, check the contents of the CMake variables you source.

At the beginning of the cmake output I get ( I am not sure if I should take care of this warning at first):

Yes, if you don’t want your application to be called “Project” you should of course fix that and CMake’s warning message literally tells you what to do.

If you want to build a CMake project for OptiX from scratch, I would recommend the following:
Sync my OptiX Advanced Examples linked here https://forums.developer.nvidia.com/t/optix-advanced-samples-on-github/48410/4
You only need the 3rdparty/CMake folder and two CMakeLists.txt files from that.

Then to build a standalone OptiX project, you need to merge two CMakeLists.txt files:
1.) The root CMakeLists.txt file which sets up all things like the CMAKE_MODULE_PATH to find the CMake scripts without the final add_subdirectory(apps) and
2) The contents of one CMakeLists.txt of one individual example (the intro_runtime one when you want to use the CUDA Runtime API and any of the others when using the CUDA Driver API. The difference is just CUDA::cudart inside thetarget_link_library() ).
3.) Then you adjust the project name everywhere, change all the find_package() statements to what you need inside your project, and replace all source code filenames with your own and that’s about it.

I’ve also experimented with some CMake native CUDA language feature and there is a way to setup native CUDA projects where all *.cu files are compiled to objects and still have OptiX device code only translated to *.ptx or *.optixir. That requires a so called CMake Object Library.

Such a CMakeLists.txt looks like this and only works with CMake 3.27 or newer.
(Note that this is also using a root level CMakeLists.txt to setup the CMake and compiler environment and finds all installed OptiX versions upfront. Not shown here. It’s the same as in my github examples.)

cmake_minimum_required(VERSION 3.27 FATAL_ERROR)

project(CUDAOptiX LANGUAGES CXX CUDA)
message("PROJECT_NAME = " "${PROJECT_NAME}")

# Find the CUDA Toolkit 12.0 or newer.
# This legacy script is used to explicitly set the CUDA::cudart and CUDA::cuda_driver libraries inside target_link_libraries()
find_package(CUDAToolkit 12.0 REQUIRED)

# OptiX SDK 7.x and 8.x versions are searched inside the top-level CMakeLists.txt.

# Just use the OptiX SDK 8.0.0 here.
if(OptiX80_FOUND)
  set(OPTIX_INCLUDE_DIR "${OPTIX80_INCLUDE_DIR}")
else()
  message(FATAL_ERROR "No OptiX SDK 8.x found.")
endif()
message("OPTIX_INCLUDE_DIR = " "${OPTIX_INCLUDE_DIR}")

# OptiX SDK 7.5.0 and CUDA 11.7 added support for a new OptiX IR target, which is a binary intermediate format for the module input.
# The default module build target is PTX.
set(USE_OPTIX_IR FALSE)

if (OptiX80_FOUND)
  # Define USE_OPTIX_IR and change the target to OptiX IR if the combination of OptiX SDK and CUDA Toolkit versions supports this mode.
  if ((${CUDAToolkit_VERSION_MAJOR} GREATER 11) OR ((${CUDAToolkit_VERSION_MAJOR} EQUAL 11) AND (${CUDAToolkit_VERSION_MINOR} GREATER_EQUAL 7)))
    set(USE_OPTIX_IR TRUE)
  endif()
endif()
message("USE_OPTIX_IR = " "${USE_OPTIX_IR}")

if (USE_OPTIX_IR)
  # This define switches the OptiX program module filenames to either *.ptx or *.optixir extensions at compile time.
  add_definitions("-DUSE_OPTIX_IR")
endif()

# Set the install directory in the project directory
#set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/install" CACHE PATH "folder in which INSTALL will put everything needed to run the binaries" FORCE)

set(HEADERS_HOST
  CheckMacros.h
  MyAssert.h
  Options.h
)

set(SOURCES_HOST
  main.cpp
  Options.cpp
)

set(HEADERS_CUDA
  config.h
  half_common.h
  functions.h
  system_data.h
  vector_math.h
)

set(SOURCES_CUDA
  cuda_kernel_code.cu
)

set(HEADERS_OPTIX
  system_data.h
  vector_math.h
)

set(SOURCES_OPTIX
  raygeneration.cu
)

source_group("host"  FILES ${HEADERS_HOST}  ${SOURCES_HOST})
source_group("cuda"  FILES ${HEADERS_CUDA}  ${SOURCES_CUDA})
source_group("optix" FILES ${HEADERS_OPTIX} ${SOURCES_OPTIX})

#if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
  # SM versions to GPU architectures:
  # 60 61 62 Pascal
  # 70       Volta
  # 75       Turing
  # 80 86    Ampere
  # 89       Ada
  # 90       Hopper
  #
  # This generates PTX and cubins for all of these SMs:
  #set(CMAKE_CUDA_ARCHITECTURES 60 70 75 80 86 89)
  #
  # It results in these arguments on the nvcc.exe command line:
  # --generate-code=arch=compute_60,code=[compute_60,sm_60]
  # --generate-code=arch=compute_70,code=[compute_70,sm_70]
  # --generate-code=arch=compute_75,code=[compute_75,sm_75]
  # --generate-code=arch=compute_80,code=[compute_80,sm_80]
  # --generate-code=arch=compute_86,code=[compute_86,sm_86]
  # --generate-code=arch=compute_89,code=[compute_89,sm_89]
  #
  # HACK Save compilation time during development and only support Ada.
  set(CMAKE_CUDA_ARCHITECTURES 89)
  #
  # CMAKE_CUDA_ARCHITECTURES "native" should only compile for the GPU vesion installed inside the system. 
  # What is that selecting when there are multiple GPU installed with different SM versions? The GPU device ordinal zero?
  # set(CMAKE_CUDA_ARCHITECTURES native)
#endif()
message("CMAKE_CUDA_ARCHITECTURES = " "${CMAKE_CUDA_ARCHITECTURES}")


# This section builds OptiX device program code with the CMake LANGUAGES CUDA feature!
# Set library name to compile all OptiX device programs.
set(OPTIX_LIB ${PROJECT_NAME}_OptiX_Lib)

# Create a CMake object library for OptiX compilation.
# This will just be a list of files which are not compiled as native CUDA kernels but as *.ptx or *.optixir OptiX module input code.
add_library(${OPTIX_LIB} OBJECT
  ${HEADERS_OPTIX}
  ${SOURCES_OPTIX}
)

# Set CUDA_OPTIX_COMPILATION property on the object library.
if (USE_OPTIX_IR)
  set_property(TARGET ${OPTIX_LIB} PROPERTY CUDA_OPTIX_COMPILATION ON) # -optix-ir
else()
  set_property(TARGET ${OPTIX_LIB} PROPERTY CUDA_PTX_COMPILATION ON)   # -ptx
endif()

set_property(TARGET ${OPTIX_LIB} PROPERTY CUDA_SEPARABLE_COMPILATION ON) # -rdc=true (--relocatable-device-code=true)
set_property(TARGET ${OPTIX_LIB} PROPERTY CUDA_ARCHITECTURES 50)         # --generate-code=arch=compute_50,code=[compute_50,sm_50]
# set_property(TARGET ${OPTIX_LIB} PROPERTY CUDA_ARCHITECTURES native)

# CUDA default compile options for the OptiX device programs.
target_compile_options(${OPTIX_LIB} PRIVATE 
  $<$<COMPILE_LANGUAGE:CUDA>:
    # --machine=64                   # => Implicit for x64 build targets.
    # --gpu-architecture=compute_50  # => set_property(TARGET ${OPTIX_LIB} PROPERTY CUDA_ARCHITECTURES 50)
    # --relocatable-device-code=true # => set_property(TARGET ${OPTIX_LIB} PROPERTY CUDA_SEPARABLE_COMPILATION ON)
    --use_fast_math
    --generate-line-info
    -Wno-deprecated-gpu-targets
  >
  # You can also set different nvcc command line options per configuration:
  # $<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:CUDA>>:-lineinfo> # This is no affecting performance and can always be set.
  # $<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:CUDA>>:-G>          # WARNING! Debug device code is abysmally slow.
)

target_include_directories(${OPTIX_LIB} PRIVATE
  "${CMAKE_CURRENT_SOURCE_DIR}"
  "${OPTIX_INCLUDE_DIR}"
)
# End of the OptiX device programs object library.


# Create an executable for the main project.
add_executable(${PROJECT_NAME} 
  ${HEADERS_HOST}
  ${SOURCES_HOST}
  ${HEADERS_CUDA}
  ${SOURCES_CUDA}
)

# CPP compiler properties
# This is already set inside the root CMakeLists.txt
# set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
# set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)

if(MSVC)
  target_compile_options(${PROJECT_NAME} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/W3>") # Warning level 3 only for the C++ language code.
endif()

target_include_directories(${PROJECT_NAME} PRIVATE
   "${CMAKE_CURRENT_SOURCE_DIR}"
   "${OPTIX_INCLUDE_DIR}"
)

# Disable the automatic addition of the cudadevrt.lib and cudart_static.lib.
set(CMAKE_CUDA_RUNTIME_LIBRARY None)

# Link the object library with the executable
target_link_libraries(${PROJECT_NAME} PRIVATE
  # Link against the shared CUDA runtime library explicitly.
  CUDA::cudart      # CUDA runtime link library. DLL ships with the CUDA toolkit.
  # CUDA::cuda_driver # CUDA driver link library. DLL ships with the display driver.
  # Optionally link against different libraries for release and debug configurations.
  # optimized ${LIBRARIES_OPTIMIZED}
  # debug ${LIBRARIES_DEBUG}
  # Add additional link libraries for the application here.
  # ${PLATFORM_LIBRARIES}
)

# Making sure the OptiX object library is always compiled before the main project.
add_dependencies(${PROJECT_NAME} ${OPTIX_LIB})

set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "apps")
set_property(TARGET ${OPTIX_LIB}    PROPERTY FOLDER "apps")

# Add a custom command to copy all OptiX TARGET_OBJECTS to a folder next to the executable where I want them.
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${PROJECT_NAME}>/${PROJECT_NAME}_core"
  COMMAND ${CMAKE_COMMAND} -E copy_if_different "\"$<JOIN:$<TARGET_OBJECTS:${OPTIX_LIB}>,\" \">\"" "$<TARGET_FILE_DIR:${PROJECT_NAME}>/${PROJECT_NAME}_core"
  COMMENT "Copying TARGET_OBJECTS to $<TARGET_FILE_DIR:${PROJECT_NAME}>/${PROJECT_NAME}_core"
)