1# Copyright Contributors to the OpenVDB Project
2# SPDX-License-Identifier: MPL-2.0
3#
4#[=======================================================================[.rst:
5
6FindOpenEXR
7-----------
8
9Find OpenEXR include dirs and libraries
10
11Use this module by invoking find_package with the form::
12
13  find_package(OpenEXR
14    [version] [EXACT]      # Minimum or EXACT version
15    [REQUIRED]             # Fail with error if OpenEXR is not found
16    [COMPONENTS <libs>...] # OpenEXR libraries by their canonical name
17                           # e.g. "IlmImf" for "libIlmImf"
18    )
19
20IMPORTED Targets
21^^^^^^^^^^^^^^^^
22
23``OpenEXR::IlmImf``
24  The IlmImf library target.
25``OpenEXR::IlmImfUtil``
26  The IlmImfUtil library target.
27
28Result Variables
29^^^^^^^^^^^^^^^^
30
31This will define the following variables:
32
33``OpenEXR_FOUND``
34  True if the system has the OpenEXR library.
35``OpenEXR_VERSION``
36  The version of the OpenEXR library which was found.
37``OpenEXR_INCLUDE_DIRS``
38  Include directories needed to use OpenEXR.
39``OpenEXR_RELEASE_LIBRARIES``
40  Libraries needed to link to the release version of OpenEXR.
41``OpenEXR_RELEASE_LIBRARY_DIRS``
42  OpenEXR release library directories.
43``OpenEXR_DEBUG_LIBRARIES``
44  Libraries needed to link to the debug version of OpenEXR.
45``OpenEXR_DEBUG_LIBRARY_DIRS``
46  OpenEXR debug library directories.
47``OpenEXR_DEFINITIONS``
48  Definitions to use when compiling code that uses OpenEXR.
49``OpenEXR_{COMPONENT}_FOUND``
50  True if the system has the named OpenEXR component.
51
52Deprecated - use [RELEASE|DEBUG] variants:
53
54``OpenEXR_LIBRARIES``
55  Libraries needed to link to OpenEXR.
56``OpenEXR_LIBRARY_DIRS``
57  OpenEXR library directories.
58
59Cache Variables
60^^^^^^^^^^^^^^^
61
62The following cache variables may also be set:
63
64``OpenEXR_INCLUDE_DIR``
65  The directory containing ``OpenEXR/config-auto.h``.
66``OpenEXR_{COMPONENT}_LIBRARY``
67  Individual component libraries for OpenEXR. may include target_link_libraries() debug/optimized keywords.
68``OpenEXR_{COMPONENT}_LIBRARY_RELEASE``
69  Individual component libraries for OpenEXR release
70``OpenEXR_{COMPONENT}_LIBRARY_DEBUG``
71  Individual component libraries for OpenEXR debug
72
73Hints
74^^^^^
75
76Instead of explicitly setting the cache variables, the following variables
77may be provided to tell this module where to look.
78
79``OpenEXR_ROOT``
80  Preferred installation prefix.
81``OPENEXR_INCLUDEDIR``
82  Preferred include directory e.g. <prefix>/include
83``OPENEXR_LIBRARYDIR``
84  Preferred library directory e.g. <prefix>/lib
85``OPENEXR_DEBUG_SUFFIX``
86  Suffix of the debug version of openexr libs. Defaults to "_d".
87``SYSTEM_LIBRARY_PATHS``
88  Global list of library paths intended to be searched by and find_xxx call
89``OPENEXR_USE_STATIC_LIBS``
90  Only search for static openexr libraries
91``DISABLE_CMAKE_SEARCH_PATHS``
92  Disable CMakes default search paths for find_xxx calls in this module
93
94#]=======================================================================]
95
96cmake_minimum_required(VERSION 3.15)
97include(GNUInstallDirs)
98
99
100mark_as_advanced(
101  OpenEXR_INCLUDE_DIR
102  OpenEXR_LIBRARY
103)
104
105set(_FIND_OPENEXR_ADDITIONAL_OPTIONS "")
106if(DISABLE_CMAKE_SEARCH_PATHS)
107  set(_FIND_OPENEXR_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
108endif()
109
110
111# Set _OPENEXR_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
112# are prioritised over the legacy capitalized XXX_ROOT variables for matching
113# CMake 3.12 behaviour
114# @todo  deprecate -D and ENV OPENEXR_ROOT from CMake 3.12
115if(OpenEXR_ROOT)
116  set(_OPENEXR_ROOT ${OpenEXR_ROOT})
117elseif(DEFINED ENV{OpenEXR_ROOT})
118  set(_OPENEXR_ROOT $ENV{OpenEXR_ROOT})
119elseif(OPENEXR_ROOT)
120  set(_OPENEXR_ROOT ${OPENEXR_ROOT})
121elseif(DEFINED ENV{OPENEXR_ROOT})
122  set(_OPENEXR_ROOT $ENV{OPENEXR_ROOT})
123endif()
124
125# Additionally try and use pkconfig to find OpenEXR
126if(USE_PKGCONFIG)
127  if(NOT DEFINED PKG_CONFIG_FOUND)
128    find_package(PkgConfig)
129  endif()
130  pkg_check_modules(PC_OpenEXR QUIET OpenEXR)
131endif()
132
133# ------------------------------------------------------------------------
134#  Search for OpenEXR include DIR
135# ------------------------------------------------------------------------
136
137set(_OPENEXR_INCLUDE_SEARCH_DIRS "")
138list(APPEND _OPENEXR_INCLUDE_SEARCH_DIRS
139  ${OPENEXR_INCLUDEDIR}
140  ${_OPENEXR_ROOT}
141  ${PC_OpenEXR_INCLUDEDIR}
142  ${SYSTEM_LIBRARY_PATHS}
143)
144
145# Look for a standard OpenEXR header file.
146find_path(OpenEXR_INCLUDE_DIR OpenEXRConfig.h
147  ${_FIND_OPENEXR_ADDITIONAL_OPTIONS}
148  PATHS ${_OPENEXR_INCLUDE_SEARCH_DIRS}
149  PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/OpenEXR include/OpenEXR OpenEXR
150)
151
152if(EXISTS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h")
153  # Get the EXR version information from the config header
154  file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h"
155    _openexr_version_major_string REGEX "#define OPENEXR_VERSION_MAJOR "
156  )
157  string(REGEX REPLACE "#define OPENEXR_VERSION_MAJOR" ""
158    _openexr_version_major_string "${_openexr_version_major_string}"
159  )
160  string(STRIP "${_openexr_version_major_string}" OpenEXR_VERSION_MAJOR)
161
162  file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h"
163     _openexr_version_minor_string REGEX "#define OPENEXR_VERSION_MINOR "
164  )
165  string(REGEX REPLACE "#define OPENEXR_VERSION_MINOR" ""
166    _openexr_version_minor_string "${_openexr_version_minor_string}"
167  )
168  string(STRIP "${_openexr_version_minor_string}" OpenEXR_VERSION_MINOR)
169
170  unset(_openexr_version_major_string)
171  unset(_openexr_version_minor_string)
172
173  set(OpenEXR_VERSION ${OpenEXR_VERSION_MAJOR}.${OpenEXR_VERSION_MINOR})
174endif()
175
176if(${OpenEXR_VERSION} VERSION_GREATER_EQUAL 3.0)
177  set(_OPENEXR_COMPONENT_LIST OpenEXR OpenEXRUtil Iex IlmThread)
178else()
179  set(_OPENEXR_COMPONENT_LIST IlmImf IlmImfUtil)
180endif()
181
182if(OpenEXR_FIND_COMPONENTS)
183  set(OPENEXR_COMPONENTS_PROVIDED TRUE)
184  set(_IGNORED_COMPONENTS "")
185  foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS})
186    if(NOT ${COMPONENT} IN_LIST _OPENEXR_COMPONENT_LIST)
187      list(APPEND _IGNORED_COMPONENTS ${COMPONENT})
188    endif()
189  endforeach()
190
191  if(_IGNORED_COMPONENTS)
192    message(STATUS "Ignoring unknown components of OpenEXR:")
193    foreach(COMPONENT ${_IGNORED_COMPONENTS})
194      message(STATUS "  ${COMPONENT}")
195    endforeach()
196    list(REMOVE_ITEM OpenEXR_FIND_COMPONENTS ${_IGNORED_COMPONENTS})
197  endif()
198else()
199  set(OPENEXR_COMPONENTS_PROVIDED FALSE)
200  set(OpenEXR_FIND_COMPONENTS ${_OPENEXR_COMPONENT_LIST})
201endif()
202
203
204# ------------------------------------------------------------------------
205#  Search for OPENEXR lib DIR
206# ------------------------------------------------------------------------
207
208if(NOT DEFINED OPENEXR_DEBUG_SUFFIX)
209  set(OPENEXR_DEBUG_SUFFIX _d)
210endif()
211
212set(_OPENEXR_LIBRARYDIR_SEARCH_DIRS "")
213
214# Append to _OPENEXR_LIBRARYDIR_SEARCH_DIRS in priority order
215
216list(APPEND _OPENEXR_LIBRARYDIR_SEARCH_DIRS
217  ${OPENEXR_LIBRARYDIR}
218  ${_OPENEXR_ROOT}
219  ${PC_OpenEXR_LIBDIR}
220  ${SYSTEM_LIBRARY_PATHS}
221)
222
223set(OpenEXR_LIB_COMPONENTS "")
224list(APPEND OPENEXR_BUILD_TYPES RELEASE DEBUG)
225
226foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS})
227  foreach(BUILD_TYPE ${OPENEXR_BUILD_TYPES})
228
229    set(_TMP_SUFFIX "")
230    if(BUILD_TYPE STREQUAL DEBUG)
231      set(_TMP_SUFFIX ${OPENEXR_DEBUG_SUFFIX})
232    endif()
233
234    set(_OpenEXR_Version_Suffix "-${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}")
235    set(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
236
237    if(WIN32)
238      if(OPENEXR_USE_STATIC_LIBS)
239        set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.lib")
240      endif()
241      list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.lib")
242    else()
243      if(OPENEXR_USE_STATIC_LIBS)
244        set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.a")
245      else()
246        if(APPLE)
247          list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.dylib")
248        else()
249          list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.so")
250        endif()
251      endif()
252      list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.a")
253    endif()
254
255    # Find the lib
256    find_library(OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE} ${COMPONENT}
257      ${_FIND_OPENEXR_ADDITIONAL_OPTIONS}
258      PATHS ${_OPENEXR_LIBRARYDIR_SEARCH_DIRS}
259      PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib
260    )
261
262    if(EXISTS ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
263      list(APPEND OpenEXR_LIB_COMPONENTS ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
264      list(APPEND OpenEXR_LIB_COMPONENTS_${BUILD_TYPE} ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
265    endif()
266
267    # Reset library suffix
268    set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
269    unset(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
270    unset(_OpenEXR_Version_Suffix)
271    unset(_TMP_SUFFIX)
272  endforeach()
273
274  if(OpenEXR_${COMPONENT}_LIBRARY_DEBUG AND OpenEXR_${COMPONENT}_LIBRARY_RELEASE)
275    # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
276    # single-config generators, set optimized and debug libraries
277    get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
278    if(_isMultiConfig OR CMAKE_BUILD_TYPE)
279      set(OpenEXR_${COMPONENT}_LIBRARY optimized ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} debug ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
280    else()
281      # For single-config generators where CMAKE_BUILD_TYPE has no value,
282      # just use the release libraries
283      set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
284    endif()
285    # FIXME: This probably should be set for both cases
286    set(OpenEXR_${COMPONENT}_LIBRARIES optimized ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} debug ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
287  endif()
288
289  # if only the release version was found, set the debug variable also to the release version
290  if(OpenEXR_${COMPONENT}_LIBRARY_RELEASE AND NOT OpenEXR_${COMPONENT}_LIBRARY_DEBUG)
291    set(OpenEXR_${COMPONENT}_LIBRARY_DEBUG ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
292    set(OpenEXR_${COMPONENT}_LIBRARY       ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
293    set(OpenEXR_${COMPONENT}_LIBRARIES     ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
294  endif()
295
296  # if only the debug version was found, set the release variable also to the debug version
297  if(OpenEXR_${COMPONENT}_LIBRARY_DEBUG AND NOT OpenEXR_${COMPONENT}_LIBRARY_RELEASE)
298    set(OpenEXR_${COMPONENT}_LIBRARY_RELEASE ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
299    set(OpenEXR_${COMPONENT}_LIBRARY         ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
300    set(OpenEXR_${COMPONENT}_LIBRARIES       ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
301  endif()
302
303  # If the debug & release library ends up being the same, omit the keywords
304  if("${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}" STREQUAL "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}")
305    set(OpenEXR_${COMPONENT}_LIBRARY   ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} )
306    set(OpenEXR_${COMPONENT}_LIBRARIES ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} )
307  endif()
308
309  if(OpenEXR_${COMPONENT}_LIBRARY)
310    set(OpenEXR_${COMPONENT}_FOUND TRUE)
311  else()
312    set(OpenEXR_${COMPONENT}_FOUND FALSE)
313  endif()
314endforeach()
315
316# ------------------------------------------------------------------------
317#  Cache and set OPENEXR_FOUND
318# ------------------------------------------------------------------------
319
320include(FindPackageHandleStandardArgs)
321find_package_handle_standard_args(OpenEXR
322  FOUND_VAR OpenEXR_FOUND
323  REQUIRED_VARS
324    OpenEXR_INCLUDE_DIR
325    OpenEXR_LIB_COMPONENTS
326  VERSION_VAR OpenEXR_VERSION
327  HANDLE_COMPONENTS
328)
329
330if(NOT OpenEXR_FOUND)
331  if(OpenEXR_FIND_REQUIRED)
332    message(FATAL_ERROR "Unable to find OpenEXR")
333  endif()
334  return()
335endif()
336
337# Partition release/debug lib vars
338
339set(OpenEXR_RELEASE_LIBRARIES "")
340set(OpenEXR_RELEASE_LIBRARY_DIRS "")
341set(OpenEXR_DEBUG_LIBRARIES "")
342set(OpenEXR_DEBUG_LIBRARY_DIRS "")
343foreach(LIB ${OpenEXR_LIB_COMPONENTS_RELEASE})
344  get_filename_component(_EXR_LIBDIR ${LIB} DIRECTORY)
345  list(APPEND OpenEXR_RELEASE_LIBRARIES ${LIB})
346  list(APPEND OpenEXR_RELEASE_LIBRARY_DIRS ${_EXR_LIBDIR})
347endforeach()
348
349foreach(LIB ${OpenEXR_LIB_COMPONENTS_DEBUG})
350  get_filename_component(_EXR_LIBDIR ${LIB} DIRECTORY)
351  list(APPEND OpenEXR_DEBUG_LIBRARIES ${LIB})
352  list(APPEND OpenEXR_DEBUG_LIBRARY_DIRS ${_EXR_LIBDIR})
353endforeach()
354
355list(REMOVE_DUPLICATES OpenEXR_RELEASE_LIBRARY_DIRS)
356list(REMOVE_DUPLICATES OpenEXR_DEBUG_LIBRARY_DIRS)
357
358set(OpenEXR_LIBRARIES ${OpenEXR_RELEASE_LIBRARIES})
359set(OpenEXR_LIBRARY_DIRS ${OpenEXR_RELEASE_LIBRARY_DIRS})
360
361# We have to add both include and include/OpenEXR to the include
362# path in case OpenEXR and IlmBase are installed separately.
363#
364# Make sure we get the absolute path to avoid issues where
365# /usr/include/OpenEXR/../ is picked up and passed to gcc from cmake
366# which won't correctly compute /usr/include as an implicit system
367# dir if the path is relative:
368#
369# https://github.com/AcademySoftwareFoundation/openvdb/issues/632
370# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129
371
372set(_OpenEXR_Parent_Dir "")
373get_filename_component(_OpenEXR_Parent_Dir
374  ${OpenEXR_INCLUDE_DIR}/../ ABSOLUTE)
375
376set(OpenEXR_INCLUDE_DIRS)
377list(APPEND OpenEXR_INCLUDE_DIRS
378  ${_OpenEXR_Parent_Dir}
379  ${OpenEXR_INCLUDE_DIR}
380)
381unset(_OpenEXR_Parent_Dir)
382
383# Configure imported target
384
385foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS})
386  # Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
387  # lib is in use. If win32, we can't mark the import .libs as shared, so
388  # these are always marked as UNKNOWN. Otherwise, infer from extension.
389  set(OpenEXR_${COMPONENT}_LIB_TYPE UNKNOWN)
390  if(OPENEXR_USE_STATIC_LIBS)
391    set(OpenEXR_${COMPONENT}_LIB_TYPE STATIC)
392  elseif(UNIX)
393    get_filename_component(_OpenEXR_${COMPONENT}_EXT ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} EXT)
394    if(${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".a")
395      set(OpenEXR_${COMPONENT}_LIB_TYPE STATIC)
396    elseif(${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".so" OR
397           ${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".dylib")
398      set(OpenEXR_${COMPONENT}_LIB_TYPE SHARED)
399    endif()
400  endif()
401
402  set(OpenEXR_${COMPONENT}_DEFINITIONS)
403
404  # Add the OPENEXR_DLL define if the library is not static on WIN32
405  if(WIN32)
406    if(NOT OpenEXR_${COMPONENT}_LIB_TYPE STREQUAL STATIC)
407      list(APPEND OpenEXR_${COMPONENT}_DEFINITIONS OPENEXR_DLL)
408    endif()
409  endif()
410
411  if(NOT TARGET OpenEXR::${COMPONENT})
412    add_library(OpenEXR::${COMPONENT} ${OpenEXR_${COMPONENT}_LIB_TYPE} IMPORTED)
413    set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
414      INTERFACE_COMPILE_OPTIONS "${PC_OpenEXR_CFLAGS_OTHER}"
415      INTERFACE_COMPILE_DEFINITIONS "${OpenEXR_${COMPONENT}_DEFINITIONS}"
416      INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIRS}")
417
418    # Standard location
419    set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
420      IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
421      IMPORTED_LOCATION "${OpenEXR_${COMPONENT}_LIBRARY}")
422
423    # Release location
424    if(EXISTS "${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}")
425      set_property(TARGET OpenEXR::${COMPONENT} APPEND PROPERTY
426        IMPORTED_CONFIGURATIONS RELEASE)
427      set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
428        IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
429        IMPORTED_LOCATION_RELEASE "${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}")
430    endif()
431
432    # Debug location
433    if(EXISTS "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}")
434      set_property(TARGET OpenEXR::${COMPONENT} APPEND PROPERTY
435        IMPORTED_CONFIGURATIONS DEBUG)
436      set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
437        IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
438        IMPORTED_LOCATION_DEBUG "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}")
439    endif()
440  endif()
441endforeach()
442
443