1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5FindLua
6-------
7
8Locate Lua library.
9
10.. versionadded:: 3.18
11  Support for Lua 5.4.
12
13This module defines::
14
15::
16
17  LUA_FOUND          - if false, do not try to link to Lua
18  LUA_LIBRARIES      - both lua and lualib
19  LUA_INCLUDE_DIR    - where to find lua.h
20  LUA_VERSION_STRING - the version of Lua found
21  LUA_VERSION_MAJOR  - the major version of Lua
22  LUA_VERSION_MINOR  - the minor version of Lua
23  LUA_VERSION_PATCH  - the patch version of Lua
24
25
26
27Note that the expected include convention is
28
29::
30
31  #include "lua.h"
32
33and not
34
35::
36
37  #include <lua/lua.h>
38
39This is because, the lua location is not standardized and may exist in
40locations other than lua/
41#]=======================================================================]
42
43cmake_policy(PUSH)  # Policies apply to functions at definition-time
44cmake_policy(SET CMP0012 NEW)  # For while(TRUE)
45
46unset(_lua_include_subdirs)
47unset(_lua_library_names)
48unset(_lua_append_versions)
49
50# this is a function only to have all the variables inside go away automatically
51function(_lua_get_versions)
52    set(LUA_VERSIONS5 5.4 5.3 5.2 5.1 5.0)
53
54    if (Lua_FIND_VERSION_EXACT)
55        if (Lua_FIND_VERSION_COUNT GREATER 1)
56            set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR})
57        endif ()
58    elseif (Lua_FIND_VERSION)
59        # once there is a different major version supported this should become a loop
60        if (NOT Lua_FIND_VERSION_MAJOR GREATER 5)
61            if (Lua_FIND_VERSION_COUNT EQUAL 1)
62                set(_lua_append_versions ${LUA_VERSIONS5})
63            else ()
64                foreach (subver IN LISTS LUA_VERSIONS5)
65                    if (NOT subver VERSION_LESS ${Lua_FIND_VERSION})
66                        list(APPEND _lua_append_versions ${subver})
67                    endif ()
68                endforeach ()
69                # New version -> Search for it (heuristic only! Defines in include might have changed)
70                if (NOT _lua_append_versions)
71                    set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR})
72                endif()
73            endif ()
74        endif ()
75    else ()
76        # once there is a different major version supported this should become a loop
77        set(_lua_append_versions ${LUA_VERSIONS5})
78    endif ()
79
80    if (LUA_Debug)
81        message(STATUS "Considering following Lua versions: ${_lua_append_versions}")
82    endif()
83
84    set(_lua_append_versions "${_lua_append_versions}" PARENT_SCOPE)
85endfunction()
86
87function(_lua_set_version_vars)
88  set(_lua_include_subdirs_raw "lua")
89
90  foreach (ver IN LISTS _lua_append_versions)
91    string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}")
92    list(APPEND _lua_include_subdirs_raw
93        lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
94        lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
95        lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
96        )
97  endforeach ()
98
99  # Prepend "include/" to each path directly after the path
100  set(_lua_include_subdirs "include")
101  foreach (dir IN LISTS _lua_include_subdirs_raw)
102    list(APPEND _lua_include_subdirs "${dir}" "include/${dir}")
103  endforeach ()
104
105  set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
106endfunction(_lua_set_version_vars)
107
108function(_lua_get_header_version)
109  unset(LUA_VERSION_STRING PARENT_SCOPE)
110  set(_hdr_file "${LUA_INCLUDE_DIR}/lua.h")
111
112  if (NOT EXISTS "${_hdr_file}")
113    return()
114  endif ()
115
116  # At least 5.[012] have different ways to express the version
117  # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
118  # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
119  file(STRINGS "${_hdr_file}" lua_version_strings
120       REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
121
122  string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
123  if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
124    string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
125    string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
126    set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
127  else ()
128    string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
129    if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
130      string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
131    endif ()
132    string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
133    string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
134    string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
135  endif ()
136  foreach (ver IN LISTS _lua_append_versions)
137    if (ver STREQUAL "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
138      set(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR} PARENT_SCOPE)
139      set(LUA_VERSION_MINOR ${LUA_VERSION_MINOR} PARENT_SCOPE)
140      set(LUA_VERSION_PATCH ${LUA_VERSION_PATCH} PARENT_SCOPE)
141      set(LUA_VERSION_STRING ${LUA_VERSION_STRING} PARENT_SCOPE)
142      return()
143    endif ()
144  endforeach ()
145endfunction(_lua_get_header_version)
146
147function(_lua_find_header)
148  _lua_set_version_vars()
149
150  # Initialize as local variable
151  set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH})
152  while (TRUE)
153    # Find the next header to test. Check each possible subdir in order
154    # This prefers e.g. higher versions as they are earlier in the list
155    # It is also consistent with previous versions of FindLua
156    foreach (subdir IN LISTS _lua_include_subdirs)
157      find_path(LUA_INCLUDE_DIR lua.h
158        HINTS ENV LUA_DIR
159        PATH_SUFFIXES ${subdir}
160        )
161      if (LUA_INCLUDE_DIR)
162        break()
163      endif()
164    endforeach()
165    # Did not found header -> Fail
166    if (NOT LUA_INCLUDE_DIR)
167      return()
168    endif()
169    _lua_get_header_version()
170    # Found accepted version -> Ok
171    if (LUA_VERSION_STRING)
172      if (LUA_Debug)
173        message(STATUS "Found suitable version ${LUA_VERSION_STRING} in ${LUA_INCLUDE_DIR}/lua.h")
174      endif()
175      return()
176    endif()
177    # Found wrong version -> Ignore this path and retry
178    if (LUA_Debug)
179      message(STATUS "Ignoring unsuitable version in ${LUA_INCLUDE_DIR}")
180    endif()
181    list(APPEND CMAKE_IGNORE_PATH "${LUA_INCLUDE_DIR}")
182    unset(LUA_INCLUDE_DIR CACHE)
183    unset(LUA_INCLUDE_DIR)
184    unset(LUA_INCLUDE_DIR PARENT_SCOPE)
185  endwhile ()
186endfunction()
187
188_lua_get_versions()
189_lua_find_header()
190_lua_get_header_version()
191unset(_lua_append_versions)
192
193if (LUA_VERSION_STRING)
194  set(_lua_library_names
195    lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}
196    lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
197    lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
198    lua.${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
199    )
200endif ()
201
202find_library(LUA_LIBRARY
203  NAMES ${_lua_library_names} lua
204  NAMES_PER_DIR
205  HINTS
206    ENV LUA_DIR
207  PATH_SUFFIXES lib
208)
209unset(_lua_library_names)
210
211if (LUA_LIBRARY)
212  # include the math library for Unix
213  if (UNIX AND NOT APPLE AND NOT BEOS)
214    find_library(LUA_MATH_LIBRARY m)
215    mark_as_advanced(LUA_MATH_LIBRARY)
216    set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
217
218    # include dl library for statically-linked Lua library
219    get_filename_component(LUA_LIB_EXT ${LUA_LIBRARY} EXT)
220    if(LUA_LIB_EXT STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
221      list(APPEND LUA_LIBRARIES ${CMAKE_DL_LIBS})
222    endif()
223
224  # For Windows and Mac, don't need to explicitly include the math library
225  else ()
226    set(LUA_LIBRARIES "${LUA_LIBRARY}")
227  endif ()
228endif ()
229
230include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
231# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
232# all listed variables are TRUE
233FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
234                                  REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
235                                  VERSION_VAR LUA_VERSION_STRING)
236
237mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY)
238
239cmake_policy(POP)
240