CMake: Use packages by imported target where available

This is preferable because imported targets generally include
all of the relevant information specific to the particular
installation of each package, and without needing to hunt down
a bunch of variables to do it.

To do this, package_option() (which is starting to grow in scope
a little beyond just providing the package option, come to think
of it) is given a new IMPORTED_AS option, which tells the package
configuration system to look for one or more imported targets and
link against them instead.
This commit is contained in:
Sam Edwards 2018-09-21 16:24:48 -06:00
parent 1520d712d4
commit 968ca123d4
2 changed files with 64 additions and 27 deletions

View File

@ -15,6 +15,7 @@
# Usage:
# package_option(package_name package_doc_string
# [DEFAULT ON | OFF]
# [IMPORTED_AS CMake::Imported::Target [...]]
# [FOUND_AS find_name]
# [LICENSE license])
# Examples:
@ -28,6 +29,11 @@
# FOUND_AS indicates the name of the CMake find_package() module, which
# may differ from Panda3D's internal name for that package.
#
# IMPORTED_AS is used to indicate that the find_package() may have
# provided one or more IMPORTED targets, and that if at least one is
# found, the IMPORTED target(s) should be used instead of the
# variables provided by find_package()
#
#
# Function: config_package
# Usage:
@ -62,6 +68,7 @@ function(package_option name)
set(command)
set(default)
set(found_as "${name}")
set(imported_as)
set(license "")
set(cache_string)
@ -87,6 +94,12 @@ function(package_option name)
elseif(arg STREQUAL "LICENSE")
set(command "LICENSE")
elseif(arg STREQUAL "IMPORTED_AS")
set(command "IMPORTED_AS")
elseif(command STREQUAL "IMPORTED_AS")
list(APPEND imported_as "${arg}")
else()
# Yes, a list, because semicolons can be in there, and
# that gets split up into multiple args, so we have to
@ -96,8 +109,8 @@ function(package_option name)
endif()
endforeach()
if(command STREQUAL "DEFAULT")
message(SEND_ERROR "DEFAULT in package_option takes an argument")
if(command AND NOT command STREQUAL "IMPORTED_AS")
message(SEND_ERROR "${command} in package_option takes an argument")
endif()
# If the default is not set, we set it.
@ -142,31 +155,47 @@ function(package_option name)
set(PANDA_PACKAGE_DEFAULT_${name} "${default}" PARENT_SCOPE)
# Create the option.
option("HAVE_${name}" "${cache_string}" "${default}")
# Create the library if the package is available.
# Create the INTERFACE library used to depend on this package.
add_library(PKG::${name} INTERFACE IMPORTED GLOBAL)
# Create the option, and if it actually is enabled, populate the INTERFACE
# library created above
option("HAVE_${name}" "${cache_string}" "${default}")
if(HAVE_${name})
if(${found_as}_INCLUDE_DIRS)
set(includes ${${found_as}_INCLUDE_DIRS})
else()
set(includes "${${found_as}_INCLUDE_DIR}")
endif()
if(${found_as}_LIBRARIES)
set(libs ${${found_as}_LIBRARIES})
else()
set(libs "${${found_as}_LIBRARY}")
endif()
set(use_variables ON)
target_link_libraries(PKG::${name} INTERFACE ${libs})
foreach(implib ${imported_as})
if(TARGET ${implib})
# We found one of the implibs, so we don't need to use variables
# (below) anymore
set(use_variables OFF)
# This is gross, but we actually want to hide package include directories
# from Interrogate to make sure it relies on parser-inc instead, so we'll
# use some generator expressions to do that.
set_target_properties(PKG::${name} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"$<$<NOT:$<BOOL:$<TARGET_PROPERTY:IS_INTERROGATE>>>:${includes}>")
# Yes, this is ugly. See below for an explanation.
target_link_libraries(PKG::${name} INTERFACE
"$<$<NOT:$<BOOL:$<TARGET_PROPERTY:IS_INTERROGATE>>>:${implib}>")
endif()
endforeach(implib)
if(use_variables)
if(${found_as}_INCLUDE_DIRS)
set(includes ${${found_as}_INCLUDE_DIRS})
else()
set(includes "${${found_as}_INCLUDE_DIR}")
endif()
if(${found_as}_LIBRARIES)
set(libs ${${found_as}_LIBRARIES})
else()
set(libs "${${found_as}_LIBRARY}")
endif()
target_link_libraries(PKG::${name} INTERFACE ${libs})
# This is gross, but we actually want to hide package include directories
# from Interrogate to make sure it relies on parser-inc instead, so we'll
# use some generator expressions to do that.
set_target_properties(PKG::${name} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"$<$<NOT:$<BOOL:$<TARGET_PROPERTY:IS_INTERROGATE>>>:${includes}>")
endif()
endif()
endfunction(package_option)

View File

@ -88,8 +88,10 @@ endif()
#
find_package(OpenSSL COMPONENTS ssl crypto QUIET)
package_option(OPENSSL DEFAULT ON
"Enable OpenSSL support")
package_option(OPENSSL
DEFAULT ON
"Enable OpenSSL support"
IMPORTED_AS OpenSSL::SSL OpenSSL::Crypto)
option(REPORT_OPENSSL_ERRORS
"Define this true to include the OpenSSL code to report verbose
@ -112,7 +114,10 @@ config_package(JPEG "libjpeg")
# PNG:
find_package(PNG QUIET)
package_option(PNG DEFAULT ON "Enable support for loading .png images.")
package_option(PNG
DEFAULT ON
"Enable support for loading .png images."
IMPORTED_AS PNG::PNG)
config_package(PNG "libpng")
# TIFF:
@ -201,7 +206,8 @@ config_package(VRPN "VRPN")
find_package(zlib QUIET)
package_option(ZLIB
"Enables support for compression of Panda assets.")
"Enables support for compression of Panda assets."
IMPORTED_AS ZLIB::ZLIB)
config_package(ZLIB "zlib")
@ -260,6 +266,7 @@ package_option(OPENAL
"This enables support for audio output via OpenAL. Some platforms, such as
macOS, provide their own OpenAL implementation, which Panda3D can use. But,
on most platforms this will imply OpenAL Soft, which is LGPL licensed."
IMPORTED_AS OpenAL::OpenAL
LICENSE "LGPL")
config_package(OPENAL "OpenAL sound library")
@ -272,7 +279,8 @@ find_package(Freetype QUIET)
package_option(FREETYPE
"This enables support for the FreeType font-rendering library. If disabled,
Panda3D will only be able to read fonts specially made with egg-mkfont.")
Panda3D will only be able to read fonts specially made with egg-mkfont."
IMPORTED_AS freetype)
config_package(FREETYPE "FreeType")