[llvm] b663395 - [CMake] Installable find modules for terminfo and libffi

Jack Andersen via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 5 11:48:12 PST 2021


Author: Jack Andersen
Date: 2021-12-05T14:46:23-05:00
New Revision: b66339575a9b541e67ce5ad2ba7e88da07cf9305

URL: https://github.com/llvm/llvm-project/commit/b66339575a9b541e67ce5ad2ba7e88da07cf9305
DIFF: https://github.com/llvm/llvm-project/commit/b66339575a9b541e67ce5ad2ba7e88da07cf9305.diff

LOG: [CMake] Installable find modules for terminfo and libffi

Improves cross-distro portability of LLVM cmake package by resolving paths for
terminfo and libffi via import targets.

When LLVMExports.cmake is generated for installation, it contains absolute
library paths which are likely to be a common cause of portability issues. To
mitigate this, the discovery logic for these dependencies is refactored into
find modules which get installed alongside LLVMConfig.cmake. The result is
cleaner, cmake-friendly management of these dependencies that respect the
environment of the LLVM package importer.

Reviewed By: JDevlieghere

Differential Revision: https://reviews.llvm.org/D114327

Added: 
    llvm/cmake/modules/FindFFI.cmake
    llvm/cmake/modules/FindTerminfo.cmake

Modified: 
    llvm/cmake/config-ix.cmake
    llvm/cmake/modules/LLVMConfig.cmake.in
    llvm/lib/ExecutionEngine/Interpreter/CMakeLists.txt
    llvm/lib/Support/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake
index dd771ecee20b3..fabafe10f4f01 100644
--- a/llvm/cmake/config-ix.cmake
+++ b/llvm/cmake/config-ix.cmake
@@ -191,18 +191,13 @@ if(NOT LLVM_USE_SANITIZER MATCHES "Memory.*")
     else()
       set(HAVE_LIBEDIT 0)
     endif()
-    if(LLVM_ENABLE_TERMINFO STREQUAL FORCE_ON)
-      set(MAYBE_REQUIRED REQUIRED)
-    else()
-      set(MAYBE_REQUIRED)
-    endif()
     if(LLVM_ENABLE_TERMINFO)
-      find_library(TERMINFO_LIB NAMES terminfo tinfo curses ncurses ncursesw ${MAYBE_REQUIRED})
-    endif()
-    if(TERMINFO_LIB)
-      set(LLVM_ENABLE_TERMINFO 1)
-    else()
-      set(LLVM_ENABLE_TERMINFO 0)
+      if(LLVM_ENABLE_TERMINFO STREQUAL FORCE_ON)
+        find_package(Terminfo REQUIRED)
+      else()
+        find_package(Terminfo)
+      endif()
+      set(LLVM_ENABLE_TERMINFO "${Terminfo_FOUND}")
     endif()
   else()
     set(LLVM_ENABLE_TERMINFO 0)
@@ -354,38 +349,19 @@ if (LLVM_ENABLE_DOXYGEN)
   llvm_find_program(dot)
 endif ()
 
-if( LLVM_ENABLE_FFI )
-  find_path(FFI_INCLUDE_PATH ffi.h PATHS ${FFI_INCLUDE_DIR})
-  if( EXISTS "${FFI_INCLUDE_PATH}/ffi.h" )
-    set(FFI_HEADER ffi.h CACHE INTERNAL "")
-    set(HAVE_FFI_H 1 CACHE INTERNAL "")
+if(LLVM_ENABLE_FFI)
+  set(FFI_REQUIRE_INCLUDE On)
+  if(LLVM_ENABLE_FFI STREQUAL FORCE_ON)
+    find_package(FFI REQUIRED)
   else()
-    find_path(FFI_INCLUDE_PATH ffi/ffi.h PATHS ${FFI_INCLUDE_DIR})
-    if( EXISTS "${FFI_INCLUDE_PATH}/ffi/ffi.h" )
-      set(FFI_HEADER ffi/ffi.h CACHE INTERNAL "")
-      set(HAVE_FFI_FFI_H 1 CACHE INTERNAL "")
-    endif()
+    find_package(FFI)
   endif()
-
-  if( NOT FFI_HEADER )
-    message(FATAL_ERROR "libffi includes are not found.")
-  endif()
-
-  find_library(FFI_LIBRARY_PATH ffi PATHS ${FFI_LIBRARY_DIR})
-  if( NOT FFI_LIBRARY_PATH )
-    message(FATAL_ERROR "libffi is not found.")
-  endif()
-
-  list(APPEND CMAKE_REQUIRED_LIBRARIES ${FFI_LIBRARY_PATH})
-  list(APPEND CMAKE_REQUIRED_INCLUDES ${FFI_INCLUDE_PATH})
-  check_symbol_exists(ffi_call ${FFI_HEADER} HAVE_FFI_CALL)
-  list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES ${FFI_INCLUDE_PATH})
-  list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES ${FFI_LIBRARY_PATH})
+  set(LLVM_ENABLE_FFI "${FFI_FOUND}")
 else()
   unset(HAVE_FFI_FFI_H CACHE)
   unset(HAVE_FFI_H CACHE)
   unset(HAVE_FFI_CALL CACHE)
-endif( LLVM_ENABLE_FFI )
+endif()
 
 check_symbol_exists(proc_pid_rusage "libproc.h" HAVE_PROC_PID_RUSAGE)
 

diff  --git a/llvm/cmake/modules/FindFFI.cmake b/llvm/cmake/modules/FindFFI.cmake
new file mode 100644
index 0000000000000..b0d859af89598
--- /dev/null
+++ b/llvm/cmake/modules/FindFFI.cmake
@@ -0,0 +1,81 @@
+# Attempts to discover ffi library with a linkable ffi_call function.
+#
+# Example usage:
+#
+# find_package(FFI)
+#
+# FFI_REQUIRE_INCLUDE may be set to consider ffi found if the includes
+# are present in addition to the library. This is useful to keep off
+# for the imported package on platforms that install the library but
+# not the headers.
+#
+# FFI_LIBRARY_DIR may be set to define search paths for the ffi library.
+#
+# If successful, the following variables will be defined:
+# FFI_FOUND
+# FFI_INCLUDE_DIRS
+# FFI_LIBRARIES
+# HAVE_FFI_CALL
+#
+# HAVE_FFI_H or HAVE_FFI_FFI_H is defined depending on the ffi.h include path.
+#
+# Additionally, the following import target will be defined:
+# FFI::ffi
+
+find_path(FFI_INCLUDE_DIRS ffi.h PATHS ${FFI_INCLUDE_DIR})
+if( EXISTS "${FFI_INCLUDE_DIRS}/ffi.h" )
+  set(FFI_HEADER ffi.h CACHE INTERNAL "")
+  set(HAVE_FFI_H 1 CACHE INTERNAL "")
+else()
+  find_path(FFI_INCLUDE_DIRS ffi/ffi.h PATHS ${FFI_INCLUDE_DIR})
+  if( EXISTS "${FFI_INCLUDE_DIRS}/ffi/ffi.h" )
+    set(FFI_HEADER ffi/ffi.h CACHE INTERNAL "")
+    set(HAVE_FFI_FFI_H 1 CACHE INTERNAL "")
+  endif()
+endif()
+
+find_library(FFI_LIBRARIES ffi PATHS ${FFI_LIBRARY_DIR})
+
+if(FFI_LIBRARIES)
+  include(CMakePushCheckState)
+  include(CheckCSourceCompiles)
+  cmake_push_check_state()
+  list(APPEND CMAKE_REQUIRED_LIBRARIES ${FFI_LIBRARIES})
+  check_c_source_compiles("
+    struct ffi_cif;
+    typedef struct ffi_cif ffi_cif;
+    void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
+    int main() { ffi_call(0, 0, 0, 0); }"
+    HAVE_FFI_CALL)
+  cmake_pop_check_state()
+endif()
+
+unset(required_includes)
+if(FFI_REQUIRE_INCLUDE)
+  set(required_includes FFI_INCLUDE_DIRS)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FFI
+                                  FOUND_VAR
+                                    FFI_FOUND
+                                  REQUIRED_VARS
+                                    FFI_LIBRARIES
+                                    ${required_includes}
+                                    HAVE_FFI_CALL)
+mark_as_advanced(FFI_LIBRARIES
+                 FFI_INCLUDE_DIRS
+                 HAVE_FFI_CALL
+                 FFI_HEADER
+                 HAVE_FFI_H
+                 HAVE_FFI_FFI_H)
+
+if(FFI_FOUND)
+  if(NOT TARGET FFI::ffi)
+    add_library(FFI::ffi UNKNOWN IMPORTED)
+    set_target_properties(FFI::ffi PROPERTIES IMPORTED_LOCATION "${FFI_LIBRARIES}")
+    if(FFI_INCLUDE_DIRS)
+      set_target_properties(FFI::ffi PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFI_INCLUDE_DIRS}")
+    endif()
+  endif()
+endif()

diff  --git a/llvm/cmake/modules/FindTerminfo.cmake b/llvm/cmake/modules/FindTerminfo.cmake
new file mode 100644
index 0000000000000..65edb80fa69a8
--- /dev/null
+++ b/llvm/cmake/modules/FindTerminfo.cmake
@@ -0,0 +1,43 @@
+# Attempts to discover terminfo library with a linkable setupterm function.
+#
+# Example usage:
+#
+# find_package(Terminfo)
+#
+# If successful, the following variables will be defined:
+# Terminfo_FOUND
+# Terminfo_LIBRARIES
+#
+# Additionally, the following import target will be defined:
+# Terminfo::terminfo
+
+find_library(Terminfo_LIBRARIES NAMES terminfo tinfo curses ncurses ncursesw)
+
+if(Terminfo_LIBRARIES)
+  include(CMakePushCheckState)
+  include(CheckCSourceCompiles)
+  cmake_push_check_state()
+  list(APPEND CMAKE_REQUIRED_LIBRARIES ${Terminfo_LIBRARIES})
+  check_c_source_compiles("
+    int setupterm(char *term, int filedes, int *errret);
+    int main() { return setupterm(0, 0, 0); }"
+    Terminfo_LINKABLE)
+  cmake_pop_check_state()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Terminfo
+                                  FOUND_VAR
+                                    Terminfo_FOUND
+                                  REQUIRED_VARS
+                                    Terminfo_LIBRARIES
+                                    Terminfo_LINKABLE)
+mark_as_advanced(Terminfo_LIBRARIES
+                 Terminfo_LINKABLE)
+
+if(Terminfo_FOUND)
+  if(NOT TARGET Terminfo::terminfo)
+    add_library(Terminfo::terminfo UNKNOWN IMPORTED)
+    set_target_properties(Terminfo::terminfo PROPERTIES IMPORTED_LOCATION "${Terminfo_LIBRARIES}")
+  endif()
+endif()

diff  --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in
index 60b56b5152ea8..425d3edfcc3a4 100644
--- a/llvm/cmake/modules/LLVMConfig.cmake.in
+++ b/llvm/cmake/modules/LLVMConfig.cmake.in
@@ -2,6 +2,9 @@
 
 @LLVM_CONFIG_CODE@
 
+# For finding self-installed Find*.cmake packages.
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
+
 set(LLVM_VERSION_MAJOR @LLVM_VERSION_MAJOR@)
 set(LLVM_VERSION_MINOR @LLVM_VERSION_MINOR@)
 set(LLVM_VERSION_PATCH @LLVM_VERSION_PATCH@)
@@ -48,9 +51,17 @@ set(LLVM_ENABLE_ASSERTIONS @LLVM_ENABLE_ASSERTIONS@)
 
 set(LLVM_ENABLE_EH @LLVM_ENABLE_EH@)
 
+set(LLVM_ENABLE_FFI @LLVM_ENABLE_FFI@)
+if(LLVM_ENABLE_FFI)
+  find_package(FFI)
+endif()
+
 set(LLVM_ENABLE_RTTI @LLVM_ENABLE_RTTI@)
 
 set(LLVM_ENABLE_TERMINFO @LLVM_ENABLE_TERMINFO@)
+if(LLVM_ENABLE_TERMINFO)
+  find_package(Terminfo)
+endif()
 
 set(LLVM_ENABLE_THREADS @LLVM_ENABLE_THREADS@)
 

diff  --git a/llvm/lib/ExecutionEngine/Interpreter/CMakeLists.txt b/llvm/lib/ExecutionEngine/Interpreter/CMakeLists.txt
index 976219830d5ed..14522ba2a1bff 100644
--- a/llvm/lib/ExecutionEngine/Interpreter/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Interpreter/CMakeLists.txt
@@ -1,11 +1,3 @@
-# Make sure that the path to libffi headers is on the command
-# line. That path can be a compiler's non-default path even when
-# FFI_INCLUDE_DIR was not used, because cmake has its own paths for
-# searching for headers (CMAKE_SYSTEM_INCLUDE_PATH, for instance):
-if( FFI_INCLUDE_PATH )
-  include_directories( ${FFI_INCLUDE_PATH} )
-endif()
-
 add_llvm_component_library(LLVMInterpreter
   Execution.cpp
   ExternalFunctions.cpp
@@ -22,5 +14,5 @@ add_llvm_component_library(LLVMInterpreter
   )
 
 if( LLVM_ENABLE_FFI )
-  target_link_libraries( LLVMInterpreter PRIVATE ${FFI_LIBRARY_PATH} )
+  target_link_libraries( LLVMInterpreter PRIVATE FFI::ffi )
 endif()

diff  --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 6ce682d911771..7e9fdd047f65b 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -45,7 +45,7 @@ elseif( CMAKE_HOST_UNIX )
     set(system_libs ${system_libs} ${Backtrace_LIBFILE})
   endif()
   if( LLVM_ENABLE_TERMINFO )
-    set(imported_libs ${imported_libs} "${TERMINFO_LIB}")
+    set(imported_libs ${imported_libs} Terminfo::terminfo)
   endif()
   if( LLVM_ENABLE_THREADS AND (HAVE_LIBATOMIC OR HAVE_CXX_LIBATOMICS64) )
     set(system_libs ${system_libs} atomic)
@@ -287,7 +287,10 @@ if(LLVM_ENABLE_ZLIB)
 endif()
 
 if(LLVM_ENABLE_TERMINFO)
-  get_library_name(${TERMINFO_LIB} terminfo_library)
+  if(NOT terminfo_library)
+    get_property(terminfo_library TARGET Terminfo::terminfo PROPERTY LOCATION)
+  endif()
+  get_library_name(${terminfo_library} terminfo_library)
   set(llvm_system_libs ${llvm_system_libs} "${terminfo_library}")
 endif()
 


        


More information about the llvm-commits mailing list