Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 116 additions & 133 deletions cmake/FindBrotli.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,191 +5,174 @@
# The targets will have the same names, but it will use the static libs.
#
# Valid find_package COMPONENTS names: "decoder", "encoder", and "common"
# Note that if you're requiring "decoder" or "encoder", then "common" will be automatically added as required.
#
# Defines the libraries (if found): Brotli::decoder, Brotli::encoder, Brotli::common
# and the includes path variable: Brotli_INCLUDE_DIR
#
# If it's failing to find the libraries, try setting BROTLI_ROOT_DIR to the folder containing your library & include dir.

function(brotli_err_msg _err_msg)
# If they asked for a specific version, warn/fail since we don't support it.
# TODO: if they start distributing the version somewhere, implement finding it.
# But currently there's a version header that doesn't seem to get installed.
if(Brotli_FIND_VERSION)
set(_brotli_version_error_msg "FindBrotli.cmake doesn't have version support!")
# If the package is required, throw a fatal error
# Otherwise, if not running quietly, we throw a warning
if(Brotli_FIND_REQUIRED)
message(FATAL_ERROR "${_err_msg}")
message(FATAL_ERROR "${_brotli_version_error_msg}")
elseif(NOT Brotli_FIND_QUIETLY)
message(WARNING "${_err_msg}")
message(WARNING "${_brotli_version_error_msg}")
endif()
endfunction()

# If they asked for a specific version, warn/fail since we don't support it.
if(Brotli_FIND_VERSION)
brotli_err_msg("FindBrotli.cmake doesn't have version support!")
endif()

# Since both decoder & encoder require the common lib (I think), force its requirement..
# Since both decoder & encoder require the common lib, force its requirement..
# if the user is requiring either of those other libs.
if(Brotli_FIND_REQUIRED_decoder OR Brotli_FIND_REQUIRED_encoder)
set(Brotli_FIND_REQUIRED_common TRUE)
endif()

# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
# Credit to FindOpenSSL.cmake for this
if(BROTLI_USE_STATIC_LIBS)
set(_brotli_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif()
endif()

# Make PkgConfig optional, since some users (mainly Windows) don't have it.
# But it's a lot more clean than manually using find_library.
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
if(BROTLI_USE_STATIC_LIBS)
# Have to use _STATIC to tell PkgConfig to find the static libs.
pkg_check_modules(Brotli_common_STATIC QUIET IMPORTED_TARGET libbrotlicommon)
pkg_check_modules(Brotli_decoder_STATIC QUIET IMPORTED_TARGET libbrotlidec)
pkg_check_modules(Brotli_encoder_STATIC QUIET IMPORTED_TARGET libbrotlienc)
else()
pkg_check_modules(Brotli_common QUIET IMPORTED_TARGET libbrotlicommon)
pkg_check_modules(Brotli_decoder QUIET IMPORTED_TARGET libbrotlidec)
pkg_check_modules(Brotli_encoder QUIET IMPORTED_TARGET libbrotlienc)
endif()
endif()

# Only used if the PkgConfig libraries aren't used.
find_path(Brotli_INCLUDE_DIR
NAMES "brotli/decode.h" "brotli/encode.h"
PATH_SUFFIXES "include" "includes"
NAMES
"brotli/decode.h"
"brotli/encode.h"
HINTS
${BROTLI_ROOT_DIR}
PATH_SUFFIXES
"include"
"includes"
DOC "The path to Brotli's include directory."
)
# Hides this var from the GUI
mark_as_advanced(Brotli_INCLUDE_DIR)

# Also check if Brotli_decoder was defined, as it can be passed by the end-user
if(NOT TARGET PkgConfig::Brotli_decoder AND NOT Brotli_decoder AND NOT TARGET PkgConfig::Brotli_decoder_STATIC)
if(BROTLI_USE_STATIC_LIBS)
list(APPEND _brotli_decoder_lib_names
"brotlidec-static"
"libbrotlidec-static"
)
else()
list(APPEND _brotli_decoder_lib_names
"brotlidec"
"libbrotlidec"
)
endif()
find_library(Brotli_decoder
NAMES ${_brotli_decoder_lib_names}
PATH_SUFFIXES
"lib"
"lib64"
"libs"
"libs64"
"lib/x86_64-linux-gnu"
)
# Just used for PkgConfig stuff in the loop below
set(_brotli_stat_str "")
if(BROTLI_USE_STATIC_LIBS)
set(_brotli_stat_str "_STATIC")
endif()

# Also check if Brotli_encoder was defined, as it can be passed by the end-user
if(NOT TARGET PkgConfig::Brotli_encoder AND NOT Brotli_encoder AND NOT TARGET PkgConfig::Brotli_encoder_STATIC)
if(BROTLI_USE_STATIC_LIBS)
list(APPEND _brotli_encoder_lib_names
"brotlienc-static"
"libbrotlienc-static"
)
else()
list(APPEND _brotli_encoder_lib_names
"brotlienc"
"libbrotlienc"
)
# Lets us know we are using the PkgConfig libraries
# Will be set false if any non-pkgconf vars are used
set(_brotli_using_pkgconf TRUE)

# Each string here is "ComponentName;LiteralName" (the semi-colon is a delimiter)
foreach(_listvar "common;common" "decoder;dec" "encoder;enc")
# Split the component name and literal library name from the listvar
list(GET _listvar 0 _component_name)
list(GET _listvar 1 _libname)

if(PKG_CONFIG_FOUND)
# These need to be GLOBAL for MinGW when making ALIAS libraries against them.
if(BROTLI_USE_STATIC_LIBS)
# Have to use _STATIC to tell PkgConfig to find the static libs.
pkg_check_modules(Brotli_${_component_name}_STATIC QUIET GLOBAL IMPORTED_TARGET libbrotli${_libname})
else()
pkg_check_modules(Brotli_${_component_name} QUIET GLOBAL IMPORTED_TARGET libbrotli${_libname})
endif()
endif()

# Check if the target was already found by Pkgconf
if(TARGET PkgConfig::Brotli_${_component_name} OR TARGET PkgConfig::Brotli_${_component_name}_STATIC)
# Can't use generators for ALIAS targets, so you get this jank
add_library(Brotli::${_component_name} ALIAS PkgConfig::Brotli_${_component_name}${_brotli_stat_str})

# Tells HANDLE_COMPONENTS we found the component
set(Brotli_${_component_name}_FOUND TRUE)
if(Brotli_FIND_REQUIRED_${_component_name})
# If the lib is required, we can add its literal path as a required var for FindPackageHandleStandardArgs
# Since it won't accept the PkgConfig targets
if(BROTLI_USE_STATIC_LIBS)
list(APPEND _brotli_req_vars "Brotli_${_component_name}_STATIC_LIBRARIES")
else()
list(APPEND _brotli_req_vars "Brotli_${_component_name}_LINK_LIBRARIES")
endif()
endif()

# Skip searching for the libs with find_library since it was already found by Pkgconf
continue()
endif()

# Lets us know we aren't using the PkgConfig libraries
set(_brotli_using_pkgconf FALSE)
if(Brotli_FIND_REQUIRED_${_component_name})
# If it's required, we can set the name used in find_library as a required var for FindPackageHandleStandardArgs
list(APPEND _brotli_req_vars "Brotli_${_component_name}")
endif()
find_library(Brotli_encoder
NAMES ${_brotli_encoder_lib_names}
PATH_SUFFIXES
"lib"
"lib64"
"libs"
"libs64"
"lib/x86_64-linux-gnu"
)
endif()

# Also check if Brotli_common was defined, as it can be passed by the end-user
if(NOT TARGET PkgConfig::Brotli_common AND NOT Brotli_common AND NOT TARGET PkgConfig::Brotli_common_STATIC)
if(BROTLI_USE_STATIC_LIBS)
list(APPEND _brotli_common_lib_names
"brotlicommon-static"
"libbrotlicommon-static"
list(APPEND _brotli_lib_names
"brotli${_libname}-static"
"libbrotli${_libname}-static"
)
else()
list(APPEND _brotli_common_lib_names
"brotlicommon"
"libbrotlicommon"
list(APPEND _brotli_lib_names
"brotli${_libname}"
"libbrotli${_libname}"
)
endif()
find_library(Brotli_common
NAMES ${_brotli_common_lib_names}

find_library(Brotli_${_component_name}
NAMES ${_brotli_lib_names}
HINTS ${BROTLI_ROOT_DIR}
PATH_SUFFIXES
"lib"
"lib64"
"libs"
"libs64"
"lib/x86_64-linux-gnu"
)
endif()
# Hide the library variable from the Cmake GUI
mark_as_advanced(Brotli_${_component_name})

set(_brotli_req_vars "")
# Generic loop to either create all the aliases for the end-user, or throw errors/warnings.
# Note that the case here needs to match the case we used elsewhere in this file.
foreach(_target_name "common" "decoder" "encoder")
# The PkgConfig IMPORTED_TARGET has PkgConfig:: prefixed to it.
if(TARGET PkgConfig::Brotli_${_target_name} OR TARGET PkgConfig::Brotli_${_target_name}_STATIC)
set(_stat_str "")
if(BROTLI_USE_STATIC_LIBS)
set(_stat_str "_STATIC")
endif()
# Can't use generators for ALIAS targets, so you get this jank
add_library(Brotli::${_target_name} ALIAS PkgConfig::Brotli_${_target_name}${_stat_str})
# Unset since otherwise it'll stick around for the next loop and break things
unset(_brotli_lib_names)

# The PkgConfig version of the library has a slightly different path to its lib.
if(Brotli_FIND_REQUIRED_${_target_name})
if(BROTLI_USE_STATIC_LIBS)
list(APPEND _brotli_req_vars "Brotli_${_target_name}_STATIC_LIBRARIES")
else()
list(APPEND _brotli_req_vars "Brotli_${_target_name}_LINK_LIBRARIES")
endif()
endif()
# This will only trigger for libraries we found using find_library
elseif(Brotli_${_target_name})
add_library("Brotli::${_target_name}" UNKNOWN IMPORTED)
# Safety-check the includes dir
if(NOT Brotli_INCLUDE_DIR)
brotli_err_msg("Failed to find Brotli's includes directory. Try manually defining \"Brotli_INCLUDE_DIR\" to Brotli's header path on your system.")
endif()
# Check if find_library found the library
if(Brotli_${_component_name})
# Tells HANDLE_COMPONENTS we found the component
set(Brotli_${_component_name}_FOUND TRUE)

add_library("Brotli::${_component_name}" UNKNOWN IMPORTED)
# Attach the literal library and include dir to the IMPORTED target for the end-user
set_target_properties("Brotli::${_target_name}" PROPERTIES
set_target_properties("Brotli::${_component_name}" PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Brotli_INCLUDE_DIR}"
IMPORTED_LOCATION "${Brotli_${_target_name}}"
IMPORTED_LOCATION "${Brotli_${_component_name}}"
)
# Attach the library from find_library to our required vars (if it's required)
if(Brotli_FIND_REQUIRED_${_target_name})
list(APPEND _brotli_req_vars "Brotli_${_target_name}")
endif()
# This will only happen if it's a required library but we didn't find it.
elseif(Brotli_FIND_REQUIRED_${_target_name})
# Only bother with an error/failure if they actually required the lib.
brotli_err_msg("Failed to find Brotli's ${_target_name} library. Try manually defining \"Brotli_${_target_name}\" to its path on your system.")
# If the compnent was required but not found, you set XXX_FOUND to false to signify failure to find component(s)
# This is used in find_package_handle_standard_args's HANDLE_COMPONENTS (I think)
set(Brotli_FOUND FALSE)
else()
# Tells HANDLE_COMPONENTS we found the component
set(Brotli_${_component_name}_FOUND FALSE)
endif()
endforeach()

include(FindPackageHandleStandardArgs)
# Sets Brotli_FOUND, and fails the find_package(Brotli) call if it was REQUIRED but missing libs.
find_package_handle_standard_args(Brotli
FOUND_VAR Brotli_FOUND
REQUIRED_VARS ${_brotli_req_vars}
FOUND_VAR
Brotli_FOUND
REQUIRED_VARS
Brotli_INCLUDE_DIR
${_brotli_required_targets}
HANDLE_COMPONENTS
)

if(Brotli_FOUND)
include(FindPackageMessage)
foreach(_lib_name ${_brotli_req_vars})
# TODO: remove this if/when The Cmake PkgConfig file fixes the non-quiet message about libbrotlicommon being found.
if(${_lib_name} MATCHES "common")
# This avoids a duplicate "Found Brotli: /usr/lib/libbrotlicommon.so" type message.
continue()
endif()
# Double-expand the var to get the actual path instead of the variable's name.
find_package_message(Brotli "Found Brotli: ${${_lib_name}}"
"[${${_lib_name}}][${Brotli_INCLUDE_DIR}]"
)
endforeach()
# Restore the original find library ordering
if(BROTLI_USE_STATIC_LIBS)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_brotli_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
endif()