Browse Source

CMake: Add an export_packages() function to export PKG::*

This is needed to support install(EXPORT)
Sam Edwards 7 years ago
parent
commit
b20c6e801c
1 changed files with 113 additions and 12 deletions
  1. 113 12
      cmake/macros/PackageConfig.cmake

+ 113 - 12
cmake/macros/PackageConfig.cmake

@@ -51,6 +51,8 @@
 #   calls to package_status above.
 #   calls to package_status above.
 #
 #
 
 
+set(_ALL_PACKAGE_OPTIONS CACHE INTERNAL "Internal variable")
+
 #
 #
 # package_option
 # package_option
 #
 #
@@ -146,11 +148,12 @@ function(package_option name)
 
 
   # Prevent the function from being called twice.
   # Prevent the function from being called twice.
   #   This would indicate a cmake error.
   #   This would indicate a cmake error.
-  if(PANDA_DID_SET_OPTION_${name})
+  if(";${_ALL_PACKAGE_OPTIONS};" MATCHES ";${name};")
     message(SEND_ERROR "package_option(${name}) was called twice.
     message(SEND_ERROR "package_option(${name}) was called twice.
                         This is a bug in the cmake build scripts.")
                         This is a bug in the cmake build scripts.")
   else()
   else()
-    set(PANDA_DID_SET_OPTION_${name} TRUE PARENT_SCOPE)
+    list(APPEND _ALL_PACKAGE_OPTIONS "${name}")
+    set(_ALL_PACKAGE_OPTIONS "${_ALL_PACKAGE_OPTIONS}" CACHE INTERNAL "Internal variable")
   endif()
   endif()
 
 
   set(PANDA_PACKAGE_DEFAULT_${name} "${default}" PARENT_SCOPE)
   set(PANDA_PACKAGE_DEFAULT_${name} "${default}" PARENT_SCOPE)
@@ -176,15 +179,23 @@ function(package_option name)
   if(HAVE_${name})
   if(HAVE_${name})
     set(use_variables ON)
     set(use_variables ON)
 
 
+    # 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(_is_not_interface_lib
+      "$<NOT:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,INTERFACE_LIBRARY>>")
+    set(_is_not_interrogate
+      "$<NOT:$<BOOL:$<${_is_not_interface_lib}:$<TARGET_PROPERTY:IS_INTERROGATE>>>>")
+
     foreach(implib ${imported_as})
     foreach(implib ${imported_as})
       if(TARGET ${implib})
       if(TARGET ${implib})
         # We found one of the implibs, so we don't need to use variables
         # We found one of the implibs, so we don't need to use variables
         # (below) anymore
         # (below) anymore
         set(use_variables OFF)
         set(use_variables OFF)
 
 
-        # Yes, this is ugly.  See below for an explanation.
+        # Hide it from Interrogate
         target_link_libraries(PKG::${name} INTERFACE
         target_link_libraries(PKG::${name} INTERFACE
-          "$<$<NOT:$<BOOL:$<TARGET_PROPERTY:IS_INTERROGATE>>>:${implib}>")
+          "$<${_is_not_interrogate}:$<TARGET_NAME:${implib}>>")
       endif()
       endif()
     endforeach(implib)
     endforeach(implib)
 
 
@@ -202,11 +213,9 @@ function(package_option name)
 
 
       target_link_libraries(PKG::${name} INTERFACE ${libs})
       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}>")
+      # Hide it from Interrogate
+      set_target_properties(PKG::${name} PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "$<${_is_not_interrogate}:${includes}>")
     endif()
     endif()
   endif()
   endif()
 endfunction(package_option)
 endfunction(package_option)
@@ -222,13 +231,13 @@ function(package_status name desc)
     set(note "${arg}")
     set(note "${arg}")
   endforeach()
   endforeach()
 
 
-  if(NOT PANDA_DID_SET_OPTION_${name})
+  if(NOT ";${_ALL_PACKAGE_OPTIONS};" MATCHES ";${name};")
     message(SEND_ERROR "package_status(${name}) was called before package_option(${name}).
     message(SEND_ERROR "package_status(${name}) was called before package_option(${name}).
                         This is a bug in the cmake build scripts.")
                         This is a bug in the cmake build scripts.")
+    return()
   endif()
   endif()
 
 
-  list(FIND _ALL_CONFIG_PACKAGES "${name}" called_twice)
-  if(called_twice GREATER -1)
+  if(";${_ALL_CONFIG_PACKAGES};" MATCHES ";${name};")
     message(SEND_ERROR "package_status(${name}) was called twice.
     message(SEND_ERROR "package_status(${name}) was called twice.
                         This is a bug in the cmake build scripts.")
                         This is a bug in the cmake build scripts.")
   else()
   else()
@@ -269,6 +278,98 @@ function(show_packages)
   endforeach()
   endforeach()
 endfunction()
 endfunction()
 
 
+#
+# export_packages(filename)
+#
+# Generates an includable CMake file that contains definitions for every PKG::
+# package defined.
+#
+function(export_packages filename)
+  set(exports "# Exports for Panda3D PKG:: packages\n")
+
+  foreach(pkg ${_ALL_PACKAGE_OPTIONS})
+    set(exports "${exports}\n# Create imported target PKG::${pkg}\n")
+    set(exports "${exports}add_library(PKG::${pkg} INTERFACE IMPORTED)\n\n")
+
+    set(exports "${exports}set_target_properties(PKG::${pkg} PROPERTIES\n")
+    foreach(prop
+        INTERFACE_COMPILE_DEFINITIONS
+        INTERFACE_COMPILE_FEATURES
+        INTERFACE_COMPILE_OPTIONS
+        INTERFACE_INCLUDE_DIRECTORIES
+        INTERFACE_LINK_DEPENDS
+        INTERFACE_LINK_DIRECTORIES
+        INTERFACE_LINK_OPTIONS
+        INTERFACE_POSITION_INDEPENDENT_CODE
+       #INTERFACE_SYSTEM_INCLUDE_DIRECTORIES  # Let the consumer dictate this
+        INTERFACE_SOURCES)
+      set(prop_ex "$<TARGET_PROPERTY:PKG::${pkg},${prop}>")
+      set(exports "${exports}$<$<BOOL:${prop_ex}>:  ${prop} \"${prop_ex}\"\n>")
+    endforeach(prop)
+
+    # Ugh, INTERFACE_LINK_LIBRARIES isn't transitive.  Fine.  Take care of it
+    # by hand:
+    set(libraries)
+    set(stack "PKG::${pkg}")
+    set(history)
+    while(stack)
+      # Remove head item from stack
+      list(GET stack 0 head)
+      list(REMOVE_AT stack 0)
+
+      # Don't visit anything twice
+      list(FIND history "${head}" _index)
+      if(_index GREATER -1)
+        continue()
+      else()
+        list(APPEND history "${head}")
+      endif()
+
+      # If head isn't a target, add it to `libraries`, else recurse
+      if(TARGET "${head}")
+        get_target_property(link_libs "${head}" INTERFACE_LINK_LIBRARIES)
+        if(link_libs)
+          list(APPEND stack ${link_libs})
+        endif()
+
+        get_target_property(type "${head}" TYPE)
+        if(NOT type STREQUAL "INTERFACE_LIBRARY")
+          get_target_property(imported_location "${head}" IMPORTED_LOCATION)
+          if(imported_location)
+            list(APPEND libraries ${imported_location})
+          endif()
+
+          get_target_property(configs "${head}" IMPORTED_CONFIGURATIONS)
+          if(configs AND NOT imported_location)
+            foreach(config ${configs})
+              get_target_property(imported_location "${head}" IMPORTED_LOCATION_${config})
+              if(imported_location)
+                if(configs MATCHES ".*;.*")
+                  set(_bling "$<1:$>") # genex-escaped $
+                  list(APPEND libraries "${_bling}<${_bling}<CONFIG:${config}>:${imported_location}>")
+                else()
+                  list(APPEND libraries ${imported_location})
+                endif()
+              endif()
+            endforeach(config)
+          endif()
+        endif()
+      elseif("${head}" MATCHES "\\$<TARGET_NAME:\([^>]+\)>")
+        string(REGEX REPLACE ".*\\$<TARGET_NAME:\([^>]+\)>.*" "\\1" match "${head}")
+        list(APPEND stack "${match}")
+      else()
+        list(APPEND libraries "${head}")
+      endif()
+    endwhile(stack)
+
+    set(exports "${exports}  INTERFACE_LINK_LIBRARIES \"${libraries}\"\n")
+
+    set(exports "${exports})\n")
+  endforeach(pkg)
+
+  file(GENERATE OUTPUT "${filename}" CONTENT "${exports}")
+endfunction(export_packages)
+
 #
 #
 # find_package
 # find_package
 #
 #